1. cvičení 5.3.2009
- O Prologu (miniopakování z přednášky)
- Syntaxe: jednoduché a složené termy, proměnné, atomy, čísla, řetězce, struktury
- Program v Prologu: klauzule, fakta, pravidla, procedury, komentáře
- Práce s interpretem Prologu: načtení souboru do paměti pomocí consult('mujprogram.pl'), halt (konec práce), ?- (prompt)
- Mechanismus kladení dotazů, operátory ',' a ';'
- Anonymní proměnná, "vstupní"/"výstupní" proměnné
- Backtracking: jak se vyhodnocují dotazy (na příkladech)
- Jednoduché predikáty o rodinných vztazích
- popis databáze rodinných vztahů pomoci predikátů rodice(On,Ona,Dite), muz(On), zena(Ona)
- manzele(On,Ona) + reflexivita
- další predikáty o rodinných vztazích - např. bratranec(Bratranec,Koho), prababickazotcovystrany(Ona,Pravnouce)
- Na rozmyšlenou: tchan(Tchan,Koho), snacha(Snacha,Koho), prastryc(Prastryc,Koho) a podobně
- Obarveni mapy čtyřmi barvami
- je dána následující mapa:
- pro tuto mapu jsme definovali predikát obarvi(A,B,C,D,E,F), kde A,...,F jsou barvy (cervena, modra, zelena, zluta) a sousedni staty nesmi byt obarveny stejně
- dvě různá řešení (jde to i bez negace)
- Strom
- je dán následující graf:
- popis grafu fakty hrana(Od,Do)
- rekurzivni predikát cesta(Od,Do) - různé varianty procedury a nebezpečí zacyklení
2. cvičení 12.3.2009
- Hrátky s unifikací
- Uvažujeme následující program:
t(a,b).
t(a,c).
g(t(A,_),t(A,_)).
gh(gh(X,_),X).
- Jaké budou odpovědi interpretu Prologu na následující dotazy?
?- g(X,Y).
X = t(_023,_024) , Y = t(_023,_025)
?- g(t(X,Y),Z).
X = _ , Y = _ , Z = t(X,_026)
?- g(t(a,b),Z).
Z = t(a,_027)
?- gh(X,Y).
X = gh(Y,_028) , Y = _
?- gh(X,c).
X = gh(c,_029)
?- gh(X,X).
Error 7, System Stack Full, Trying vars/2
- Modelování aritmetiky
- reprezentace přirozených čísel pomocí termů 0, s(0), s(s(0)),...
natural(0).
natural(s(X)) :- natural(X).
- nad přirozenými čísli jsme definovali predikáty even(X), odd(X) - X je sudé/liché přirozené číslo
- leq(X,Y) - přirozené číslo X je menší nebo rovno přirozenému číslu Y, různá řešení
- Je možné modifikovat leq/2 tak, aby volání leq(-X,-Y) vrátilo v konečném počtu kroků libovolnou dvojici přirozených čísel menších než n?
- lt(X,Y) - přirozené číslo X je menší než přirozené číslo Y, různá řešení
- add(X,Y,Z) - Z je součet přirozených čísel X a Y, různá řešení
- mul(X,Y,Z) - Z je součin přirozených čísel X a Y
- pow(X,Y,Z) - Z = X^Y
- Jednoduché predikáty pro práci se seznamy:
- member(X,S), je_seznam(S)
- sudy(S), lichy(S) - uspěje, je-li S seznam sudé délky / liché délky
- pridejnazacatek(Seznam,Prvek,Vysledny), pridejnakonec(Seznam,Prvek,Vysledny), smazprvni(Seznam,Vysledny), smazposledni(Seznam,Vysledny)
- prefix(Seznam,Prefix), suffix(Seznam,Suffix)
- usek(Seznam, Usek) - pomoci prefixu a suffixu
3. cvičení 19.3.2009
- Na příštím cvičení budeme psát test!
- Řešení minulého domácího úkolu - mladsisestra/2, starsibratr/2, nejmladsisestra/2, nejstarsibratr/2
- Další predikáty pro práci se seznamy
- podseznam(+S,?PodS) - seznam PodS je podseznamem seznamu S (ve smyslu podmnožiny). Predikát postupně generuje všechny podseznamy seznamu. Například pro S=[a,b,c,d] generuje podseznamy [a,b,c,d], [b,c,d], [c,d], [d],[], [a,c,d], [a,d] atd.
- prostredni(S,X) - X je prostředním prvkem seznamu S. Řešení trikem:
prostredni(+S,-X):- prostredni(+S,+S,-X).
prostredni([_],[X|_],X).
prostredni([_,_],[X|_],X).
prostredni([_,_|T1],[_|T2],X):- prostredni(T1,T2,X).
- spoj(S1,S2,S) - seznam S je konkatenací seznamů S1 a S2
- reversespoj(S1,S2,S) - seznam S je konkatenací obráceného seznamu S1 a seznamu S2. Řešení pomocí akumulátoru.
- reverse(?S,?OS) - seznam OS vznikne otočením seznamu S. Různá řešení - elegantně pomocí reversespoj/3.
- rotace(?S,?RS) - rotace seznamu o jeden prvek. Například, je-li S=[a,b,c,d], bude RS = [b,c,d,a]. Různá řešení - elegantně pomocí reverse/2
- Aritmetika v Prologu
- Úvod do aritmetiky - operátor is, relační operátory
- min(+X,+Y,?Min) - Min je minimum čísel X a Y
- minseznam(+S,?Min) - Min je minimální prvek seznamu S. Různá řešení - rekurzivně / iterativně za využití akumulátoru.
- minsort(+T,-ST) - T je seznam, ST je setříděný seznam T metodou přímého výběru minima. Řešení pomocí minseznam/2 a vhodného delete/3.
- mezi(+X,+Y,-Z) - Generuje postupně všechna čísla Z taková, že X <= Z <= Y
- mezi1(+X,+Y,-S) - S je seznam všech čísel takových, že X <= Z <= Y
4. cvičení 26.3.2009
- Myšlenka řešení minulého domácího úkolu - napoloviny/3, natretiny/4, polovinymuzu/3, tretinymuzu/4,
- Aritmetika v Prologu - pokračování
- soucet(+S1,+S2,-S) - Sečte seznamy čísel S1 a S2 prvek po prvku, výsledek je v seznamu S. Uspěje jen za předpokladu, že S1 a S2 jsou stejně dlouhé
- mensi(+S1,+N,-S) - Vybere ze seznamu (kladných čísel) S1 prvky menší než je N do seznamu S.
- vyber(+S1,+N,-S) - Vybere ze seznamu (kladných čísel) S1 prvky se součtem N do seznamu S. Funguje opakovaně díky backtrackingu. Našli jsme různá řešení.
- kombinace(+S1,+K,-S) - Postupně backtrackingem ze seznamu S1 generuje všechny K-prvkové kombinace (podmnožiny) prvků.
- Na rozmyšlenou: variace(+S1,+K,-S) - Postupně ze seznamu S1 generuje všechny K-prvkové variace prvků. Dal by se přitom využít predikát permutace(+S,-T)?
- Operátor řezu !
- Rozdíl mezi =, ==, =:=, \=, \==, =\=
- Máme program p(1). p(2):-!. p(3). Jak bude vypadat odpověř programu na následující dotazy?
?-p(X).
?-p(X),p(Y).
?-p(X),!,p(Y).
?-p(X).
X=1;X=2
?-p(X),p(Y).
X=Y=1;
X=1,Y=2;
X=2,Y=1;
X=Y=2
?-p(X),!,p(Y).
X=Y=1;
X=1,Y=2 - Negace v Prologu pomocí operátoru řezu:
notmember(X,S):-member(X,S),!,fail.
notmember(_,_).
not(X):- X,!,fail.
not(X).
- Na rozmyšlenou: V čem spočívá problém s negací v Prologu? Není zde jistá souvislost s problémem zastavení Turingova stroje?
- Modelování if-then-else v Prologu pomocí operátoru řezu (if b then c else d):
a(X):-b(X),!,d(X).
a(X):-c(X).
- Další užitečné predikáty pro práci se seznamy
- substituce(+X,+S,+Y,-T) - Za každý prvek X v seznamu S substituuj prvek Y. Výsledek je seznam T. Různá řešení - využití operátoru řezu.
- multijoin2(+S,-T) - Prvky seznamu S jsou buď atomy nebo seznamy. Seznam T vznikne "rozbalením" těchto seznamů. Pokud je prvkem S seznam, je nahrazen výčtem svých prvků. Například pro S=[a,b,[c,d],e,[],f] je T=[a,b,c,d,e,f]. Pro S=[a,b,[[e],[]],f,[],g] je T=[a,b,[e],[],f,g].
- Unární aritmetika
- [] reprezentuje 0, [1] reprezentuje 1, [1,1,1,1,1] reprezentuje 5, atd.
- soucet(+X,+Y,-S) - Sčítání v unární aritmetice pomocí konkatenace seznamů.
- soucin(+X,+Y,-S) - Násobení v unární aritmetice. Různá řešení. Hezký trik:
nasob(A,B,C):-substituce(1,A,B,S),multijoin2(S,C). - Na rozmyšlenou: predikáty pro odčítání a dělení v unární aritmetice.
- Matice
- Matice reprezentujeme jako seznamy řádků.
- prvekMatice(+M,?X) - X je prvkem matice M. Různá řešení. Hezký trik pomocí multijoin2.
- Na rozmyšlenou: transpozice(+M,-TM) - transpozice matice M.
5. cvičení 2.4.2009
- Rozbor testíku z minulého cvičení, správné řešení, bodování, nejčastější chyby
- POZOR: Protože testík dopadl pro řadu studentů dost katastrofálně, rozhodla jsem se lehce pozměnit podmínky na zápočet. Další podmínkou získání zápočtu bude získání nadpolovičního počtu bodů z alespoň jedné písemky. Testíky se budou psát do konce semestru asi ještě dva. Kdo má z prvního testíku více než 3 body, má tuto podmínku už splněnou. Pro podrobnosti o možnosti převodu bodů za testík na body za domácí úkoly či prezenci si přečtěte Podmínky.
- permutace(+S1,+S2)
- kazdyNty(+S1,+N,-S)
- Myšlenka řešení minulého domácího úkolu - multijoin/2, nasob/3
- POZOR: Bohužel se našli takoví studenti, co mi poslali naprosto identická řešení domácí úlohy. Přípomínám, že pokud něco takového odhalím příště, nebudu zjišťovat, kdo od koho kopíroval, a ani jednomu úkol neuznám! "Recidivisté" pak ať nepočítají s tím, že ode mě dostanou zápočet!
- Součtové seznamy
- Pro jaké operace se tato datová struktura hodí?
- Základní operace nad součtovými seznamy: přidej prvek na začátek, přidej prvek na konec, smazání prvku ze začátku, smazání prvku z konce, otočení, převod mezi obyčejným a součtovým seznamem
- Rozdílové seznamy
- Popis. Pro jaké operace se tato datová struktura hodí?
- concat(A-B,B-C,A-C) - vysvětlení, jak to vlastně funguje.
- quicksort(+Seznam,-RozdilovySeznam) - další využití rozdílového seznamu pro snížení časové složitosti.
- Některé standardní predikáty
- atom(X). X je atom
atomic(X). X je atom nebo číslo
number(X). X je číslo
var(X). X je nekonkretizovaná proměnná
nonvar(X). - Sčítání, kde libovolný argument může být proměnná
scit(A, B, C) :- number(A), number(B), C is A + B.
scit(A, B, C) :- number(A), var(B), number(C), B is C - A.
scit(A, B, C) :- var(A), number(B), number(C), A is C - B. - Další využití např. při vyhodnocování aritmetických výrazů (bude na příštím cvičení).
- Matice - pokračování
- transpozice(+M,-TM) - převod matice na transponovanou matici. Řešení pomocí prvnisloupec(+Matice,-PrvniSloupec,-Zbytek).
- otoc(+M,-OM) - otočení matice o 90 stupňů doprava. Různá řešení - např. pomocí transpozice a otočení seznamu.
6. cvičení 9.4.2009
- Na příštím cvičení si popovídáme o zápočtových programech. Pokud zbyde čas, začneme cvičit SCHEME.
- Rozbor řešení minulého domácího úkolu - nextPerm (v lineárním čase), nthPerm (s kvadratickou časovou složitostí). Predikát nthPerm zůstal jako domácí úkol na příště (teď už jsme si řekli, jak na to).
- Matice - hrátky se spirálou.
- rozbal(+M,-S) - Do seznamu S vkládá prvky matice M tak, jak leží na spirále. Různá řešení - a) 4 predikáty, b) pomocí otočení o 90 stupňů, c) pomocí inverzní operace.
- zabal(+M,+N,+S,-Mat) - Inverzni predikat k predikatu rozbal/2. Prvky seznamu S posklada po spirale do matice Mat tvaru MxN. Řešení pomocí inverzní operace.
zabal(+M,+N,+Vektor,-Matice):-generujMatici(M,N,MP), rozbal(MP,VP), Vektor=VP, Matice=MP.
% generujVektor(+N,-V) vygeneruje vektor volných proměnných délky N. generujVektor(0,[]).
generujVektor(X,[_|T]):-Y>0, Y is X-1,generujVektor(Y,T).
% generujMatici(+M,+N,-Mat) vygeneruje matici volných proměnných tvaru MxN. generujMatici(1,N,[V]):-generujVektor(N,V).
generujMatici(M,N,[V|Zb]):-M>1,M1 is M-1, generujVektor(N,V),generujMatici(M1,N,Zb).
- Operátor =..
- Přístup k parametrům struktury, konstrukce struktury z parametrů.
- Term =.. Seznam % Seznam = [Funktor|Argumenty]
- maplist(+Predikát,+Seznam,-Výsledek) Aplikuje Predikát/2 na každý prvek seznamu Seznam. Výsledek je výsledný seznam.
- Na rozmyšlenou Definujte predikát substituce(+Term, +Co, +Cim, -VyslTerm), který provede v termu Term substituci všech podtermů Co za termy Cim. Výsledný term je VyslTerm.
- Operátor name
- name(?Atom,?Seznam) Převod atomu na řetězec a nebo zpět. Řetězec v Prologu je reprezentován jako seznam ASCII kódů písmen.
- lexik(+Atom1,+Atom2) Lexikografické uspořádání dvou atomů.
- Operátory, které sesbírají všechny termy s nějakou vlastností
- bagof(+Term,+Cíl,-Seznam) Seznam je seznam všech instancí Termu, které splňují Cíl.
- setof(+Term,+Cíl,-Seznam) Totéž, ale Seznam je uspořádaný, bez duplicit.
- findall(+Term,+Cíl,-Seznam)
Shromáždí všechna řešení bez ohledu na volné proměnné,vždy uspěje.
hrana(a,b).
hrana(a,c).
hrana(a,d).
hrana(b,c).
?-bagof(X,trida(X,c),S). % odkud vede hrana do c?
X=_,S=[a,b].
?- bagof(op(c,X),hrana(X,c),S). % mohu vytvářet strukturu
X=_,S = [op(c,a),op(c,b)]
?- bagof(X,hrana(X,a),S). % Nesplnění cíle - neúspěch.
no
?-bagof(X,hrana(X,Y),S). % odkud vede hrana?
X = _ , Y = b ,S = [a] ;
X = _ , Y = c ,S = [a,b] ;
X = _ , Y = d , S = [a] ;
?- findall(X,hrana(X,Y),S). % odkud vede hrana?
X = _ , Y = _ , S = [a,a,b,a]
- Práce se vstupem a výstupem
- Konečný a nekonečný cyklus.
- Interakce programu s uživatelem.
- Operátory
- Definice operátorů pomocí predikátu op
:-op(+Priorita,+Asociativita,+Atom). - Stromy
- Různé reprezentace. Binární stromy (z přednášky). Binární vyhledávací stromy.
- Reprezentace obecného stromu pomocí binárního.
- Reprezentace binárního vyhledávacího stromu seznamem seznamů. Uzel je seznam [H,L,P]. List je seznam [H,_,_]. Definovali jsme predikát insert(+X,+Strom,-VyslednyStrom).
- Definice stromu pomocí operátoru + (např. T=(a+b)+(c+(d+e))). Prvky jsou uloženy v uzlech stromu. Definovali jsme predikát member(+X,+Strom).
- Aritmetické výrazy
- Symbolické derivování.
- Zjednodušení aritmetického výrazu.
7. cvičení 16.4.2009
- Povídání o zápočtových programech
- Různé návrhy témat. Náčrt témat navrhnutých na cvičení.
- Další zdroje možných témat: Hric, Dvořák, Barták.
- Téma zápočtového programu byste si měli vybrat do příště. Poté, co se na tématu dohodneme, mi pošlete specifikaci (podrobnější zadání) programu. Termín na odeslání specifikace je 30.duben.
- Příště budeme psát testík! Budou tam 1-2 příklady na Prolog (nejspíše tam budou operátory, =.., matice nebo stromy) a 1-2 jednoduché příkládky na SCHEME (např. jednoduché výpočty či operace se seznamy).
- Lisp - SCHEME
- Syntaxe LISPu. Základní formy ve SCHEME. Definice funkcí.
- Definovali jsme jednoduché funkce:
- Výpočet faktroriálu.
- Výpočet n-tého fibonacciho čísla. Více variant.
- Výpočet délky seznamu.
- Konkatenace dvou seznamů.
- Na rozmyšlenou: Otočení seznamu pomocí akumulátoru.
- Na rozmyšlenou (budeme cvičit příště, nebude v testíku): Závěsný prostorový mobil (zadání z přednášky).
- Na rozmyšlenou (budeme cvičit příště, nebude v testíku): Binární stromy v LISPU.
8. cvičení 23.4.2009
- Zápočtové programy
- Připomínám, že termín na výběr tématu zápočtového programu a poslání specifikace (podrobného zadání) je 30. duben!!!
- Náhrada testíku Kdo nebyl na cvičení 23.4. a chtěl by si napsat testík, náhradní termín je na příštím cvičení (popř. ihned po něm). Nabídka samozřejmě platí i pro ty, kteří testík sice psali, ale chtěli by si ho radši napsat ještě jednou :-).
- SCHEME - pokračování
- Definovali jsme funkci (map f s), která má jako parametry funkci f (f je funkce s jedním parametrem) a seznam s. Funkce map aplikuje funkci f na každý prvek seznamu s a vrátí výsledný seznam.
( define (map f s) ( if (= s nil ) nil ( cons (f ( car s)) (map f (cdr s))))) - Definovali jsme funkci (app s f g), která má jako parametry seznam s, funkci g (g je funkce s jedním parametrem) a funkci f (f je funkce se dvěma parametry). Funkce app aplikuje funkci f na poslední prvek seznamu s a funkci g rekurzivně na další prvek seznamu a zbytek ("to, co přišlo z rekurze"). Například pro seznam (list 1 2) funkce app spočte ( f 1 (g 2)), pro seznam (list 1 2 3 4) funkce app spočte ( f 1 ( f 2 ( f 3 (g 4)))). ( define (app s f g) ( if (= (cdr s) nil ) ( g (car s) ) ( f (car s) ( app (cdr s) f g ))))
- Vynásobení všech prvků seznamu dvěma pomocí funkce map.
- Výpočet délky seznamu, součinu prvků v seznamu a minimálního prvku seznamu pomocí funkce app.
- Binární stromy v LISPu:
( define (tree V L R) (list V L R)) ( define (emptyT) nil) ( define (value s) (car s)) ( define (left s) (cadr s)) ( define (right s) (caddr s)) - Prvek binárního stromu.
- Insert do binárního vyhledávacího stromu.
- Delete z binárního vyhledávacího stromu.
- Prostorový mobil
- Funkce, která zjistí, zda je mobil vyvážený.
- Funkce, která mobil vyváží.
- Funkce, která zjistí, zda mobil cinká.
- Na rozmyšlenou: Na cvičení jsme nastínili myšlenku řešení. Samotná implementace funkcí v Lispu / Prologu / Haskellu je na vás :-).
9. cvičení 30.4.2009
- HASKELL - úvod
- Definice funkcí (včetně typů), curryfikace, anonymní funkce, chybové hlášky (definice vlastních), anonymní proměnné
- Jednoduché funkce - součet pětkrát jinak. Výpočet faktoriálu.
- Základní vzory (patterns) na jednoduchých příkladech - stráže, let, where, if, case, @
- Jednoduché funkce - signum třikrát jinak, výpočet největšího společného dělitele, krácení čísel,...
- Seznamy vs. ntice, řetězce jako seznamy, ++, head, tail, fst, snd
- Rozsahy, generování (nekonečných) seznamů
- Jednoduché funkce - kartézský součin seznamů, nekoněčný seznam přirozených čísel, nekonečný seznam nul.
- Definovali jsme základní funkce nad seznamy - take (vezme prvních n prvků seznamu), map, takemap.
10. cvičení 7.5.2009
- HASKELL - pokračování - definice infixových operátorů, deklarace priority a asociativity, operátor skládání funkcí (.), výpis typu výrazu (:t vyraz), booleovské operace, ==, /=,...
- Seznamy - pokračování
- Standardní funkce nad seznamy v souboru standard.pre (Prelude.hs): head, tail, null, length, ++, !!, take, map, drop (viz. minule)
- Definovali jsme funkci splitAt f s, která rozdělí seznam na pozici f s (použili jsme standartní funkce take a drop).
splitAt:: ([a]-> Integer) -> [a] -> ([a],[a])
- Definovali jsme standartní funkci takeWhile, která je obdobou while cyklu (dokud prvky splňují podmínku, dávej je do výsledného seznamu).
takeWhile :: (a -> Bool) -> [a] -> [a] - Pomocí takeWhile jsme definovali funkci kladny, která vrátí kladný prefix seznamu.
kladny :: [Int] -> [Int]
kladny = takeWhile (>0)
- Definovali jsme standartní funkci filter, která vloží do výsledného seznamu jen ty prvky původního seznamu, které splňují podmínku.
filter :: (a -> Bool) -> [a] -> [a] - Pomocí filter jsme definovali funkci kladny1, která vrátí všechny kladné prvky seznamu.
kladny1 :: [Int] -> [Int]
kladny1 = filter (>0)
- Pomocí filter jsme definovali třídící funkci quicksort.
qsort :: [Int] -> [Int]
qsort [] = []
qsort (x:xs) = qsort (filter (< x) xs) ++ x: qsort (filter (>= x) xs)
- Definovali jsme standartní funkci zip, která má na vstupu dva seznamy a vloží do výsledného seznamu dvojice prvků (zbytek delšího ze seznamů zahodí).
zip :: [a] -> [b] -> [(a,b)] - Nekonečné seznamy, rozdíl mezi [(x,y) | (x,y) <- zip s t ] a [(x,y) | x <-s, y <-t ], nuly, přirozená čísla pětkrát jinak, mocniny,...
- Pomocí zip jsme definovali Fibonacciho posloupnost.
fibon :: [Integer]
fibon = 0:1: [x+y | (x,y) <- zip fibon (tail fibon) ] - Definovali jsme standartní funkci zipWith, která funguje jako zip, ale aplikuje funkci na výslednou dvojici.
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] - Pomocí zipWith jsme definovali funkci soucetVektoru, která sečte dva celočíselné seznamy.
soucetVektoru :: [Integer] -> [Integer] -> [Integer]
soucetVektoru = zipWith (+) - Definovali jsme standartní funkci flip, která prohodí parametry funkce.
flip :: (a -> b -> c) -> b -> a -> c
flip f y x = f x y
> zipWith (flip' div) [2,2..] [10,8,6,4,2]
[5,4,3,2,1] - Definovali jsme funkce merge, split a následně i mergesort.
merge :: ([Int],[Int]) -> [Int] split :: [Int] -> ([Int],[Int])
11. cvičení 14.5.2009
- Seznamy - pokračování
- Standardní funkce foldl a foldr
- Pomocí funkcí foldl/foldr jsme definovali funkce pro součet prvků seznamu, skalární součin prvků seznamu a otočení seznamu.
- Matice jako seznamy seznamů
- Definovali jsme funkci unitMat, která vytvoří jednotkovou matici jako nekonečnou datovou strukturu. unitMat :: [[Int]]
- Definovali jsme funkci dMat, která vytvoří (potenciálně nekonečnou) matici s danou diagonálou. dMat :: Int -> [[Int]]
- Definovali jsme funkci soucetMatic, která sečte dvě matice stejných rozměrů. soucetMatic :: Num a => [[a]] -> [[a]] -> [[a]] soucetMatic = zipWith (zipWith (+))
- Definovali jsme funkci transponuj, která transponuje matici (pomocí zipWith). transponuj :: [[a]] -> [[a]]
- Definovali jsme funkci podmatice x1 x2 y1 y2, která z matice vybere podmatici s danými souřadnicemi levého horního a pravého dolního rohu (pomocí map, take a drop).