1 / 46

Logick é programovanie 4

Logick é programovanie 4. backtracking a logické hádanky “ zebra problem ” alias kto chová rybičky ? cesta v grafe - prehľadávanie stavového priestor hanojské veže i n é g rafov é algoritmy jednoťažky farbenie grafu prehľadávanie grafu do šírky druhorádové predikáty Cvičenie

ellema
Download Presentation

Logick é programovanie 4

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Logické programovanie 4 • backtracking a logické hádanky • “zebra problem” alias kto chová rybičky ? • cesta v grafe - prehľadávanie stavového priestor • hanojské veže • iné grafové algoritmy • jednoťažky • farbenie grafu • prehľadávanie grafu do šírky • druhorádové predikáty Cvičenie • grafové algoritmy • most, artikulácia grafu, súvislé komponenty, ...

  2. Tento kvíz údane vymyslel Albert Einstein a údajne ho 98% ľudí vôbec nevyrieši. Susedia(zebra problem) Je rada piatich domov, pričom každý má inú farbu. V týchto domoch žije päť ľudí rôznych národností. Každý z nich chová iné zviera, rád pije iný nápoj a fajčí iné cigarety. • Brit býva v červenom dome. • Švéd chová psa. • Dán pije čaj. • Zelený dom stojí hneď naľavo od bieleho. • Majiteľ zeleného domu pije kávu. • Ten, kto fajčí Pall Mall, chová vtáka. • Majiteľ žltého domu fajčí Dunhill. • Človek z prostredného domu pije mlieko. • Nór býva v prvom dome. • Ten, kto fajčí Blend, býva vedľa toho, kto chová mačku. • Ten, kto chová kone, býva vedľa toho, kto fajčí Dunhill. • Ten, kto fajčí Blue Master, pije pivo. • Nemec fajčí Prince. • Nór býva vedľa modrého domu. • Ten, kto fajčí Blend, má suseda, ktorý pije vodu. Kto chová rybičky? (patríte medzi tie 2%) ?

  3. Susedia - 1 domy sú v rade indexované 1..5 % dom 1 2 3 4 5 % narod N1 N2 N3 N4 N5 % zviera Z1 Z2 Z3 Z4 Z5 % napoj P1 P2 P3 P4 P5 % fajci F1 F2 F3 F4 F5 % farba C1 C2 C3 C4 C5 susedia(N,Z,P,F,C) :- N=[N1,N2,N3,N4,N5], perm([brit,sved,dan,nor,nemec],N), N1=nor, %- Nór býva v prvom dome P=[P1,P2,P3,P4,P5], perm([caj,voda,pivo,kava,mlieko],P), P3=mlieko, ...%- Človek z prostredného domu pije mlieko

  4. Susedia - 2 z minulej prednášky: predikát index(X,Xs,I), ktorý platí, ak Xsi = X index(X,[X|_],1). index(X,[_|Ys],I):-index(X,Ys,I1),I is I1+1. • Dán pije čaj. index(dan,N,I2), index(caj,P,I2), • Brit býva v červenom dome. C=[C1,C2,C3,C4,C5], perm([cerveny,biely,modry,zlty,zeleny],C), index(brit,N,I3), index(cerveny,C,I3), • Ten, kto fajčí Blend, býva vedľa toho, kto chová mačku. F=[F1,F2,F3,F4,F5], perm([pallmall,dunhill,prince,blend,bluemaster],F), index(blend,F,I10), index(macka,Z,I11), vedla(I10,I11), vedla(I,J) :- I is J+1 ; J is I+1.

  5. Susedia - 3 ?- susedia(N,Z,P,F,C). N = [nor, dan, brit, nemec, sved] Z = [macka, kon, vtak, rybicky, pes] P = [voda, caj, mlieko, kava, pivo] F = [dunhill, blend, pallmall, prince, bluemaster] C = [zlty, modry, cerveny, zeleny, biely] ; No Kto chová rybičky?

  6. Susedia(iné riešenie, iná reprezentácia) http://sandbox.rulemaker.net/ngps/blog/119.html Houses = [ [N1,Z1,F1,P1,C1], % 1.dom [národ,zviera,fajčí,pije,farba] [N2,Z2,F2,P2,C2], % 2.dom [N3,Z3,F3,P3,C3], % 3.dom [N4,Z4,F4,P4,C4], % 4.dom [N5,Z5,F5,P5,C5] ].% 5.dom ako vyjadríme fakt, že: • nór býva v prvom dome Houses =[[norwegian, _, _, _, _] | _] • človek z prostredného domu pije mlieko Houses =[ _, _, [_, _, milk, _, _], _, _] • dán pije čaj member([dane, _, _, tea, _], Houses) • v susednom dome od … definujme pomocné predikáty next_to, iright next_to(X, Y, List) :- iright(X, Y, List) ; iright(Y, X, List). iright(L, R, [L, R | _]). iright(L, R, [_ | Rest]) :- iright(L, R, Rest).

  7. Susedia (alias zebra problem) http://sandbox.rulemaker.net/ngps/blog/119.html einstein(Houses, Fish_Owner) :- Houses = [[norwegian, _, _, _, _], _, [_, _, _, milk, _], _, _], member([brit, _, _, _, red], Houses), member([swede, dog, _, _, _], Houses), member([dane, _, _, tea, _], Houses), iright([_, _, _, _, green], [_, _, _, _, white], Houses), member([_, _, _, coffee, green], Houses), member([_, bird, pallmall, _, _], Houses), member([_, _, dunhill, _, yellow], Houses), next_to([_, _, dunhill, _, _], [_, horse, _, _, _], Houses), next_to([_, _, blend, _, _], [_, cat, _, _, _], Houses), next_to([_, _, blend, _, _], [_, _, _, water, _], Houses), member([_, _, bluemaster, beer, _], Houses), member([german, _, prince, _, _], Houses), next_to([norwegian, _, _, _, _], [_, _, _, _, blue], Houses), member([Fish_Owner, fish, _, _, _], Houses). % kto chová rybičky ? ?- einstein(Houses, Fish_Owner).

  8. Cesta v grafe • majme graf definovaný predikátom hrana/2 hrana(a,b). hrana(c,a). hrana(c,b). hrana(c,d). • predikát cesta/2 znamená, že medzi X a Y existuje postupnosť hrán cesta(X, X). cesta(X, Y) :- hrana(X, Z), cesta (Z, Y). cesta(X, Y) :- (hrana(X, Z) ; hrana(Z, X)), cesta (Z, Y). • ?-cesta(a,d). no • ?- cesta(a,d). … a b d c

  9. Cesta v cyklickom grafe a b d c • neohrana(X,Y) :- hrana(X,Y). neohrana(X,Y) :- hrana(Y,X). • cesta(X, X, _). cesta(X, Y,C):-neohrana(X, Z), not member(Z,C), cesta (Z, Y,[Z|C]). • ?-cesta(a,d,[a]). yes • cesta(X, X, C, Res) :- Res = C. cesta(X, Y,C,Res) :- neohrana(X, Z), not member(Z,C), cesta (Z, Y,[Z|C], Res). • ?- cesta(a,d,[],Res). Res = [a,c,d]

  10. Misionári a kanibali(príklad použitia prehľadávania grafu – stavového priestoru) Traja misionári a traja kanibali sa stretli na jednom brehu rieky. Na brehu bola malá loďka, na ktorú sa zmestia maximálne dve osoby. Všetci sa chcú prepraviť na druhý breh, ale na žiadnom brehu nesmie nikdy zostať prevaha kanibalov nad misionármi, inak by mohlo dôjst k tragédií. Akým spôsobom sa majú dostať na druhý breh? http://profuvsvet.ic.cz/view.php?cisloclanku=2007040006

  11. Misionári a kanibali(príklad použitia prehľadávaniagrafu do hľbky) check(M,K) :- M = 0 ; K =< M. check2(M,K) :- check(M,K), M1 is 3-M, K1 is 3-K, check(M1, K1). init(state(3,3,l)).% vľavo loďka, 3 missio a 3 canibs final(state(0,0,r)).% vpravo loďka, 3 missio a 3 canibs % príklad prechodového pravidla hrana(state(M,K,l), state(M1, K1, r)) :- check2(M,K), ((M>1, M1 is M-2, K1 is K); (M>0, M1 is M-1, K1 is K); (K>0, M1 is M, K1 is K-1); (M>0, K>0, M1 is M-1, K1 is K-1); (K>1, M1 is M, K1 is K-2)), check2(M1,K1). misio :- init(I), final(F), cesta(I,F,[],P), write(P). [state(0, 0, r), state(1, 1, l), state(0, 1, r), state(0, 3, l), state(0, 2, r), state(2, 2, l),state(1, 1, r), state(3, 1, l), state(3, 0, r), state(3, 2, l), state(2, 2, r), state(3, 3, l)]

  12. Japončíci • http://freeweb.siol.net/danej/riverIQGame.swf • Pravidla hry jsou následující:1. Na voru se mohou vést najednou maximálně dvě osoby.2. Otec nemůže zůstat ani s jednou dcerou bez přítomnosti matky3. Matka nemůže zůstat ani s jedním synem bez přítomnosti otce4. Kriminálník (v pruhovaném obleku) nemůže zůstat ani s jedním členem rodiny bez přítomnosti policisty.5. Jen otec, matka a policista se umí plavit na voru.

  13. japonci – stavy na ľavobrehu %--- [boat,father,mother,sons,daughters,policeman,criminal] %--- next(state1, state2) next([1,1,M,S,D,P,C], [0,0,M,S,D,P,C]). next([1,F,1,S,D,P,C], [0,F,0,S,D,P,C]). next([1,F,M,S,D,1,C], [0,F,M,S,D,0,C]). next([1,1,1,S,D,P,C], [0,0,0,S,D,P,C]). . . . . . next([1,1,M,S,D,P,C], [0,0,M,SX,D,P,C]) :- between(1,2,S), succ(SX,S). next([1,F,M,S,D,1,C], [0,F,M,SX,D,0,C]) :- between(1,2,S), succ(SX,S). next([1,F,M,S,D,1,C], [0,F,M,S,DX,0,C]) :- between(1,2,D), succ(DX,D). . . . . .

  14. japonci – kritické situácie valid_father([_,F,M,_,D,_,_]) :- F = M; (F = 1, D = 0); (F = 0, D = 2). valid_mother([_,F,M,S,_,_,_]) :- F = M; (M = 1, S = 0); (M = 0, S = 2). valid_criminal([_,F,M,S,D,P,C]) :- C = P; (C = 1, F = 0, M = 0, S = 0, D = 0) ; (C = 0, F = 1, M = 1, S = 2, D = 2). valid(S) :- valid_father(S), valid_mother(S), valid_criminal(S).

  15. japonci – riešenie ?- solve.[boat,father,mother,sons,daughters,policeman,criminal [1, 1, 1, 2, 2, 1, 1]počiatočný stav [0, 1, 1, 2, 2, 0, 0] P+C -> [1, 1, 1, 2, 2, 1, 0] <- P [0, 1, 1, 1, 2, 0, 0] P+S -> [1, 1, 1, 1, 2, 1, 1] <- P+C [0, 0, 1, 0, 2, 1, 1] F+S -> [1, 1, 1, 0, 2, 1, 1] <- F [0, 0, 0, 0, 2, 1, 1] F+M -> [1, 0, 1, 0, 2, 1, 1] <- M [0, 0, 1, 0, 2, 0, 0] P+C -> [1, 1, 1, 0, 2, 0, 0] <- F [0, 0, 0, 0, 2, 0, 0] M+F -> [1, 0, 1, 0, 2, 0, 0] <- M [0, 0, 0, 0, 1, 0, 0] M+D-> [1, 0, 0, 0, 1, 1, 1] <- P+C [0, 0, 0, 0, 0, 0, 1] P+D-> [1, 0, 0, 0, 0, 1, 1] <- P [0, 0, 0, 0, 0, 0, 0] P+C ->

  16. Hanoi classique http://www.csupomona.edu/~jrfisher/www/prolog_tutorial/2_3.html • hmove(1,X,Y,_) :- • write('Move top disk from '), • write(X), • write(' to '), • write(Y), • nl. • hmove(N,X,Y,Z) :- • N>1, • N1 is N-1, • hmove(N1,X,Z,Y), • hmove(1,X,Y,_), • hmove(N1,Z,Y,X). ?- hmove(3,a,b,c). Move top disk from a to b Move top disk from a to c Move top disk from b to c Move top disk from a to b Move top disk from c to a Move top disk from c to b Move top disk from a to b

  17. Hanoi inak • počiatočný a koncový stav v tvare Xs:Ys:Zs (kotúče sú očíslované) • hanoi_init(N,Xs:[]:[]):-jednaAzN(N,Xs). • hanoi_final(N,[]:[]:Zs):-jednaAzN(N,Zs). • legálne prechody zo stavu do stavu (trochu rozšafný test  • hanoi_move([X|Xs]:Ys:Zs,Xs:[X|Ys]:Zs) :- vzostupne([X|Ys]). • hanoi_move([X|Xs]:Ys:Zs,Xs:Ys:[X|Zs]) :- vzostupne([X|Zs]). • hanoi_move(Xs:[Y|Ys]:Zs,[Y|Xs]:Ys:Zs) :- vzostupne([Y|Xs]). • hanoi_move(Xs:[Y|Ys]:Zs,Xs:Ys:[Y|Zs]) :- vzostupne([Y|Zs]). • hanoi_move(Xs:Ys:[Z|Zs],[Z|Xs]:Ys:Zs) :- vzostupne([Z|Xs]). • hanoi_move(Xs:Ys:[Z|Zs],Xs:[Z|Ys]:Zs) :- vzostupne([Z|Ys]). • doit(N,Len) :- hanoi_init(N,I), hanoi_final(N,F), cesta(I,F,P), • length(P,Len), • write(P),nl, • write(Len),nl, • fail.

  18. Hanoi ešte inak ?- doit(3,L). [[]:[]:[1, 2, 3], [1]:[]:[2, 3], []:[1]:[2, 3], [2]:[1]:[3], [1, 2]:[]:[3], [1, 2]:[3]:[], [2]:[3]:[1], []:[2, 3]:[1], []:[1, 2, 3]:[], [1]:[2, 3]:[], [1]:[3]:[2], []:[3]:[1, 2], [3]:[]:[1, 2], [3]:[1]:[2], [2, 3]:[1]:[], [1, 2, 3]:[]:[]] 16; ?- doit(4,16). [[]:[]:[1, 2, 3, 4], []:[1]:[2, 3, 4], [2]:[1]:[3, 4], [1, 2]:[]:[3, 4], [1, 2]:[3]:[4], [2]:[3]:[1, 4], []:[2, 3]:[1, 4], []:[1, 2, 3]:[4], [4]:[1, 2, 3]:[], [1, 4]:[2, 3]:[], [1, 4]:[3]:[2], [4]:[3]:[1, 2], [3, 4]:[]:[1, 2], [3, 4]:[1]:[2], [2, 3, 4]:[1]:[], [1, 2, 3, 4]:[]:[]] 16 ?- doit(4,16). hanoi_move([X|Xs]:Ys:Zs,Xs:[X|Ys]:Zs) :- vzostupneParNepar([X|Ys]). hanoi_move([X|Xs]:Ys:Zs,Xs:Ys:[X|Zs]) :- vzostupneParNepar([X|Zs]). hanoi_move(Xs:[Y|Ys]:Zs,[Y|Xs]:Ys:Zs) :- vzostupneParNepar([Y|Xs]). hanoi_move(Xs:[Y|Ys]:Zs,Xs:Ys:[Y|Zs]) :- vzostupneParNepar([Y|Zs]). hanoi_move(Xs:Ys:[Z|Zs],[Z|Xs]:Ys:Zs) :- vzostupneParNepar([Z|Xs]). hanoi_move(Xs:Ys:[Z|Zs],Xs:[Z|Ys]:Zs) :- vzostupneParNepar([Z|Ys]).

  19. Reprezentácia grafu http://406notacceptable.com/java/breadth-first-tree-traversal-in-java/ • reprezentácia grafu: hrana(X,Y) hrana(a,b). hrana(c,a). hrana(c,b). hrana(c,d). • ?- hrana(c,X). X = a; X = b; X = d; No • iná reprezentácia grafu: susedia(c,[a,b,d]) • ako z prvej reprezentácie do druhej do druhej ?? s tým, čo vieme, to nejde ... lebo backtracking...

  20. Druho-rádové predikáty • bagof(Term, Cieľ, Bag) – Bag je zoznam inštancií Termu pre riešenia Cieľa • setof(Term, Cieľ, Set) – Set je množina inštancií Termu pre riešenia Cieľa Príklady: • [1..N] jednaAzN(N,List) :- bagof(X,between(1,N,X),List). • všetky kombinácie päťprvkovej množiny allCombinations(List) :- setof(C,comb(C,[1,2,3,4,5]),List).

  21. Existenčné premenné ?- bagof(X,(between(1,3,X),member(Y,[a,b,c])),Bag). Y = a,Bag = [1, 2, 3] ; Y = b,Bag = [1, 2, 3] ; Y = c,Bag = [1, 2, 3]. % existuje také Y, že X patrí do 1..3 a Y do a..c ?- bagof(X,Y^(between(1,3,X),member(Y,[a,b,c])),Bag). Bag = [1, 1, 1, 2, 2, 2, 3, 3, 3]. • findall(Term, Cieľ, Bag) – Bag je zoznam inštancií Termu pre riešenia Cieľa, pričom všetky voľné premenné sú existenčne viazané ?- findall(X,(between(1,3,X),member(Y,[a,b,c])),Bag). Bag = [1, 1, 1, 2, 2, 2, 3, 3, 3].

  22. Susedia, stupeň vrchola späť na grafy... • súvislé komponenty grafu obsahujúci X suvislyKomp(X,Comp):- setof(Y,Path^cesta(X,Y,[],Path),Comp). • susedia(X, Neibourghs) :- setof(Y,hrana(X,Y), Neibourghs). graph(G) :- setof( (X,Neibourghs), susedia(X, Neibourghs),G). • ?- graph(G). G = [ (a, [b]), (b, []), (c, [a, b, d]), (d, [])] • stupenVrchola(X,N) :- susedia(X, Neibourghs), length(Neibourghs,N). a b d c

  23. Prehľadávanie grafu do šírky cesta(X,Y) :- cestaDoSirky([X],[],Y). cestaDoSirky([Y|_],_,Y). cestaDoSirky([X|Xs],Navstivene,Y):-X\=Y, % zober všetky dostupné vrcholy z X, kde si ešte nebol setof(Z,(hrana(X,Z), not(member(Z,Navstivene))),Nasledovnici), % pridaj ich do fronty, na začiatok či koniec ? %append(Nasledovnici,Xs,Xs1), -- toto je do hľbky append(Xs,Nasledovnici,Xs1), -- a toto do šírky % opakuj v rekurzii kým vo fronte nie je vrchol kam smeruješ cestaDoSirky(Xs1,[X|Navstivene],Y). + dostaneme najkratšiu cestu - nevidíme ju (priamo) Treba sa zamyslieť nad tým, ako si uchovať informácie pre rekonštrukciu cesty

  24. Symbol rezu (cut) Symbol rezu – označovaný predikátovým symbolom ! - predstavuje cieľ, ktorý je v triviálne splnený, má jedno riešenie, a pri pokuse o znovusplnenie je neúspešný. Okrem toho zakáže hľadať alternatívne riešenia pre: • ciele vľavo od neho v klauzule, kde sa nachádza, a • vo všetkých klauzulách nachádzajúcich sa pod touto klauzulou. Príklad: • Ak neplatí x, k symbolu ! sa výpočet nedostane. • Ak sa podarí nájsť riešenie pre x, ! platí triviálne, hľadajú sa riešenia pre y. Side-effect symbolu ! je to, že • iné riešenia pre x sa už nehľadajú • ďalšie klauzuly pre b sa už nepoužijú –- ––––––– Príklad: foo:- a, b, c. b :- x,!, y. b :- z, w.

  25. Príklad použitia !(if-then-else) • definujme predikát, ktorý implementuje tradičný if-then-else ifthenelse(C,T,E) :- C,T. ifthenelse(C,T,E) :- not(C),E. not(C) sa implementuje tak, že sa spustí výpočet C, a ak • existuje riešenie pre C, not(C) neplatí, • neexistuje riešenie pre C, not(C) platí. tzv. negation as a failure. Problém: predikát C sa vyhodnocuje dvakrát v prípade, ak neplatí C. Riešenie (pomocou symbolu rezu): ifthenelse(C,T,E) :- C,!,T. ifthenelse(C,T,E) :- E. Veľký problém: po sémantickej stránke je to katastrofa.

  26. Príklady použitia symbolu rezu príklad z generátora zoznamu nAzJedna(0,[]). nAzJedna(N,[N|X]):-N>0,N1 is N-1,nAzJedna(N1,X). pomocou ! nTo1(0,[]):-!. nTo1(N,[N|X]):-N1 is N-1,nTo1(N1,X). Minulé cvičenie unary2bin(X,Y):-unary2bin(X,0,Y). unary2bin(0, A, A):-!. unary2bin(X,A,Y):-mod2(X,0),!,div2(X,X2),unary2bin(X2,o(A),Y). unary2bin(X,A,Y):- div2(X,X2),unary2bin(X2,i(A),Y).

  27. Zelené vs. červené ! Zelené rezy – jeho odstránenie nemení sémantiku programu, používame ho len pre zvýšenie efektívnosti – program je deterministickejší sign(X,-1) :- X<0, !. sign(X,0):-X=0, !. sign(X, 1):-X>0, !. Červené rezy – menia význam programu not C :- C, !, fail. not C. fail je predikát, ktorý nikdy neplatí true je predikát, ktorý vždy platí, a má jediné riešenie repeat je predikát, ktorý vždy platí a má nekonenčne veľa riešení repeat. repeat:-repeat.

  28. Cyklus repeat-fail Zadaj dvojciferné číslo z intervalu 10..99 a kým ho nezadáš, program ťa nepustí ďalej cisloXX(XX) :- repeat, write('Zadaj dvociferne cislo '), read(XX), (XX<100,XX>9, !, write(ok) ; write(zle), nl, fail). ak prejde test XX<100,XX>9, znefunkční sa druhá vetva ‘zle’ aj alternatívy pre repeat cisloXX1(XX) :- repeat, write('Zadaj dvociferne cislo '), read(XX), (XX<100,XX>9 -> write(ok) ; write(zle), nl, fail). ! ukrytý v C->T;E čo je syntax pre ifthenelse nemá vplyv na túto klauzulu, t.j. ak zadáme dvojciferné čislo, systém chce ďalšie , !

  29. neohr(1,2). neohr(1,3). neohr(1,4). neohr(1,5). neohr(2,3). neohr(2,4). neohr(3,4). neohr(3,5). Kaliningradské jednoťažky Kaliningradský problém – prejsť všetky mosty a skončiť tam, kde sme začali hrany(Hrany) :- setof((X,Y), neohr(X,Y), Hrany). jednotazka(X,Res) :- hrany(Hrany), jednotazka(X,Hrany,[X],Res). jednotazka(X,[],C,Res):-Res = C. jednotazka(X,Hrany,C,Res):- (delete((X,Y),Hrany,Hrany1) ; delete((Y,X),Hrany,Hrany1)), jednotazka(Y,Hrany1,[Y|C],Res). ?- jednotazka(2,R). R = [4, 2, 1, 5, 3, 1, 4, 3, 2] ; R = [4, 2, 1, 3, 5, 1, 4, 3, 2] ; R = [4, 1, 5, 3, 1, 2, 4, 3, 2] ;

  30. Farbenie mapy mapa( [susedia(portugal, Portugal, [Spain]), susedia(spain, Spain, [France,Portugal]), susedia(france, France, [Spain,Italy,Switzerland,Belgium,Germany,Luxemburg]), susedia(belgium, Belgium, [France,Holland,Luxemburg,Germany]), susedia(holland, Holland, [Belgium,Germany]), susedia(germany, Germany, [France,Austria,Switzerland,Holland,Belgium,Luxemburg]), susedia(luxemburg,Luxemburg,[France,Belgium,Germany]), susedia(italy, Italy, [France,Austria,Switzerland]), susedia(switzerland,Switzerland,[France,Austria,Germany,Italy]), susedia(austria, Austria, [Italy,Switzerland,Germany]) ]). colors([green,red,blue,yellow]).% zoznam farieb subset([],_). % všetci sa nachádzajú v... subset([X|Xs],Ys) :- member(X,Ys), subset(Xs,Ys).

  31. Farbenie mapy colorMap([],_). colorMap([susedia(_,Color,Neighbors)|Xs],Colors) :- select(Color,Colors,Colors1),% vyber farbu, ofarbi krajinu subset(Neighbors,Colors1), % prever, či susedia majú colorMap(Xs,Colors).% iné farby a opakuj, kým [] ?- mapa(M), colors(Cols), colorMap(M,Cols), write(M),nl. [susedia(portugal, green, [red]), susedia(spain, red, [green, green]), susedia(france, green, [red, red, blue, red, yellow, blue]), susedia(belgium, red, [green, green, blue, yellow]), susedia(holland, green, [red, yellow]), susedia(germany, yellow, [green, green, blue, green, red, blue]), susedia(luxemburg, blue, [green, red, yellow]), susedia(italy, red, [green, green, blue]), susedia(switzerland, blue, [green, green, yellow, red]), susedia(austria, green, [red, blue, yellow])]

  32. Hra NIM http://www.archimedes-lab.org/game_nim/nim.html jednokopový NIM: dvaja hráči postupne berú zkopy 1,2 alebo 3 zápalky, vyhráva ten, kto berie poslednú zápalku (prehráva, kto nemá čo brať) Rekurzívna definícia predikátov: • vitaznaPozicia1NIM/1, • prehravajucaPozicia1NIM/1, • spravnyTah1NIM vitaznaPozicia1NIM(N):-between(1,3,N). vitaznaPozicia1NIM(N):- tah1NIM(N,N1), % existuje správny ťah z N do N1, prehravajucaPozicia1NIM(N1).% že konfigurácia N1 je prehrávajúca tah1NIM(N,N1):- % existuje konkrétny Tah between(1,3,Tah), % v súľade s pravidlami jednokopového Tah=<N, N1 is N-Tah. % NIMu

  33. Hra NIM - prehrávajúca prehravajucaPozicia1NIM(0). % nemá čo brať prehravajucaPozicia1NIM(N):- % pre ľubovoľný ťah z N do N1, bagof(vitaznaPozicia1NIM(N1), tah1NIM(N,N1), All), forall(All). % nová konfigurácia je víťazná forall([]). % platia všetky podciele zoznamu forall([G|Gs]):-G, forall(Gs). spravnyTah1NIM(N):-tah1NIM(N,N1), prehravajucaPozicia1NIM(N1), write('nechaj ='), write(N1),nl. zlé pozície sú tvaru 4*k(k>0), t.j. 4, 8, 12, … a vítazná stratégia je: ak super zoberie Z zápaliek, ja beriem 4-Z, ak som vo vítaznej pozícii, ak som v prehrávajúcej pozícii, beriem čo najmenej (snáď sa pomýli…).

  34. Hra NIM - trace Ak si dáme vypisovať, pre ktoré ciele sa forall dokazuje, že platia, vidíme, že overovanie, že pozícia N je víťazná, sa vykonáva mnohokrát. ?- prehravajucaPozicia1NIM(8). [vitaznaPozicia1NIM(7), vitaznaPozicia1NIM(6), vitaznaPozicia1NIM(5)] [vitaznaPozicia1NIM(5), vitaznaPozicia1NIM(4), vitaznaPozicia1NIM(3)] [vitaznaPozicia1NIM(3), vitaznaPozicia1NIM(2), vitaznaPozicia1NIM(1)] [vitaznaPozicia1NIM(2), vitaznaPozicia1NIM(1)] [vitaznaPozicia1NIM(1)] [] [vitaznaPozicia1NIM(4), vitaznaPozicia1NIM(3)] [vitaznaPozicia1NIM(2), vitaznaPozicia1NIM(1), vitaznaPozicia1NIM(0)] [vitaznaPozicia1NIM(1), vitaznaPozicia1NIM(0)] [vitaznaPozicia1NIM(0)] [vitaznaPozicia1NIM(1), vitaznaPozicia1NIM(0)] [vitaznaPozicia1NIM(0)] . . . . . . . . . .

  35. 3-kopový NIM http://www.mathematische-basteleien.de/nimgame.html pravidlá (http://en.wikipedia.org/wiki/Nim): • hráč berie z ľubovoľnej kopy (ale len jednej) ľub.počet zápaliek • vyhráva ten, kto berie poslednú (t.j. prehráva ten, kto už nemá čo brať). predikáty: vitaznaPozicia3NIM/1, prehravajucaPozicia3NIM/1, spravnyTah3NIM %- pravidlá závislé na hre (konfigurácia a povolené ťahy): vitaznaPozicia3NIM([A,0,0]):-A>0. vitaznaPozicia3NIM([0,B,0]):-B>0. vitaznaPozicia3NIM([0,0,C]):-C>0.

  36. Hra 3-NIM - prehrávajúca %- toto je nezávislé na hre vitaznaPozicia3NIM(N):-tah3NIM(N,N1), % existuje správny ťah z N do N1, lemma(prehravajucaPozicia3NIM(N1)).% že N1 je prehrávajúca prehravajucaPozicia3NIM([0,0,0]). prehravajucaPozicia3NIM(N):- % pre ľub.ťah, nová konfigurácia je vítazná bagof(lemma(vitaznaPozicia3NIM(N1)), tah3NIM(N,N1), All), forall(All). spravnyTah3NIM(N):-tah3NIM(N,N1), lemma(prehravajucaPozicia3NIM(N1)), write('nechaj ='), write(N1),nl. • [1,2,3]  • [0,2,3]  -> [0,2,2]  • [1,1,3]  -> [1,1,0]  • [1,0,3]  -> [1,0,1]  • [1,2,2]  -> [0,2,2]  • [1,2,1]  -> [1,0,1]  • [1,2,0]  -> [1,1,0] 

  37. Hra 3-NIM – tabelizácia %- toto je nezávislé na hre vitaznaPozicia3NIM(N):-tah3NIM(N,N1), % existuje správny ťah z N do N1, lemma(prehravajucaPozicia3NIM(N1)).% že N1 je prehrávajúca prehravajucaPozicia3NIM([0,0,0]). prehravajucaPozicia3NIM(N):- % pre ľub.ťah, nová konfigurácia je vítazná bagof(lemma(vitaznaPozicia3NIM(N1)), tah3NIM(N,N1), All), forall(All). % lemma(P) je predikát logicky ekvivalentný P. Ale výpočtovo optimálnejší: ak sa nám raz podarilo P dokázať, zapamätáme si to ako fakt P:-true., a keď opätovne dokazujeme P, tak sa pozrieme, či sme už P dokazovali. :-dynamicprehravajucaPozicia3NIM/1, vitaznaPozicia3NIM/1. lemma(P):-clause(P,true),! ; P, assertz(P:-true).

  38. 3-NIM a XOR Prehrávajúca konfigurácia je taká, že XOR jednotlivých kôp je 0. 1 = 0012 4 = 1002 5 = 1012 ----------- XOR 0002 3 = 00112 7 = 01112 9 = 01002 ----------- XOR 00002 3 = 0112 4 = 1002 5 = 1012 ----------- XOR 0102 správny ťah 3-2= 1 3 = 00112 7 = 01112 9 = 10012 ----------- XOR 11012 správny ťah 9-5 = 4 http://www.numericana.com/answer/games.htm

  39. Práca s „databázou“ Reflexívne programovanie • asserta(Clause), assertz(Clause) – pridá klauzulu do databázy, asserta na začiatok, assertz na koniec procedúry, • clause(Head, Body) – hľadá klauzulu s porovnateľnú s Head:-Body, • retract(Clause) – odstráni klauzulu z databázy, • retractall(Clause) – odstráni všetky klauzuly z databázy. Predikáty spôsobujú side-effect: po backtracku sa ich účinky NEODSTRÁNIA, t.j. pridaná klauzula sa nevymaže a vymazaná sa nepridá. ?-otec(jonatan, izidora). No. ?-asserta(otec(jonatan,izidora)). Yes. ?- otec(jonatan,izidora). Yes. ?-retractall(otec(_,_)). Yes. ?- otec(jonatan,izidora). No. Hurá, máme globálnu premennú (databázu)

  40. Tabelizácia lemma(P):-write('zistujem '), write(P), nl, fail. lemma(P):-(clause(P,true),write('nasiel '), write(P), nl, !) ; (P,write('dokazal '), write(P), nl, assertz(P:-true)). % deklarácia, že predikát fib/2 bude modifikovaný. :-dynamic fib/2. fib(N,1):-N<2,!. fib(N,F):-N1 is N-1, N2 is N-2, lemma(fib(N1,F1)), lemma(fib(N2,F2)), F is F1+F2. ?- fib(5,N). zistujem fib(4, _G342) zistujem fib(3, _G345) zistujem fib(2, _G348) zistujem fib(1, _G351) dokazal fib(1, 1) zistujem fib(0, _G357) dokazal fib(0, 1) dokazal fib(2, 2) zistujem fib(1, _G369) nasiel fib(1, 1) dokazal fib(3, 3) zistujem fib(2, _G381) nasiel fib(2, 2) dokazal fib(4, 5) zistujem fib(3, _G393) nasiel fib(3, 3) N = 8.

  41. Ilustrácia findall,assert-retract Na ilustráciu realizujme predikát findall pomocou assert-retract % vygeneruje všetky riešenia do databázy findall(Term,Goal,_):-Goal, assertz(bof(Term)), fail. % pozbiera všetky riešenia z databázy do zoznamu findall(_,_,List):-loop(List), !. loop([X|List]):-retract(bof(X)), !, loop(List). loop([]). ?- gen(4,List). assertz(bof(1)). assertz(bof(2)). assertz(bof(3)). assertz(bof(4)). List = [1, 2, 3, 4] ?- gengen1(4,List). List = [[[[[1], 1, 2], 1, 2, 3], 1, 2, 3, 4]]. Kde je problém ???

  42. Príklad použitia findall Úmyselne vnoríme jeden findall do volania druhého % gen(N,List) ak List = [1,…,N] gen(N,List):-findall(X,between(1,N,X),List). % gen1(N,List) ak existuje 1<=M<=N, že List = [1,…,M] gen1(N,List):-between(1,N,M), gen(M,List). % gengen1(N,List) ak List = [[1],[1,2],[1,2,3], …, [1,…,N]] gengen1(N,ListList):-findall(List,gen1(N,List),ListList). ?- gen(5,L). L = [1, 2, 3, 4, 5] ; No ?- gen1(5,L). L = [1] ; L = [1, 2] ; L = [1, 2, 3] ; L = [1, 2, 3, 4] ; L = [1, 2, 3, 4, 5] ; No ?- gengen1(5,L). L = [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]] ; No

  43. findall2 Prvá verzia findall nefunguje v prípade vnorených konštrukcií findall - vylepšíme ho (predpokladáme, že end je nevyskytujúci sa extra symbol): % bof(end) je použité ako zarážka, odkiaľ boli riešenia generované findall(Term,Goal,_):-asserta(bof(end)),Goal,asserta(bof(Term)), fail. findall(_,_,List):-retract(bof(X)), loop(X, [], List), !. loop(end,L,L):- !.% stop, ak narazíme na zarážku bof(end) loop(X,L1,L):-retract(bof(Y)), !, loop(Y,[X|L1], L). ?- genn(4,List). List = [1, 2, 3, 4]. ?- genngenn1(4,List). List = [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]].

  44. Čo znamená ? vyjadrite význam pomocou predikátu findall/setof/bagof foo(X):-(X,(retract(db(fooo,_)),!,fail; asserta(db(fooo,X)), fail)) ; retract(db(fooo,X)). :-dynamic db/2. a. % predikát s jedným riešením b. % predikát s dvomi riešeniami b. c. % predikát s tromi riešeniami c. c. f:-fail.% predikát so žiadnym riešením ?- foo(a). ?- foo(b). ?- foo(c). ?- foo(f).

  45. Rébus 1 foo(X):-(X,(retract(db(fooo,_)),!,fail; asserta(db(fooo,X)), fail)) ; retract(db(fooo,X)). ak X nie je splniteľný, foo(X) neplatí, posledný retract sa nepodari, foo(X) zlyhá, ak X má riešenie, nájdeme prvé, retract(db(fooo,_)) zlyhá, takže assert(db(fooo,X)) uspeje, a následne fail, ak X nemá ďalšie riešenie posledný retract(db(fooo,X)) odmaže, čo assert vsunul. Teda, databáza je v pôvodnom stave. ak X má druhé riešenie, retract(db(foo,_)) vymaže prvé riešenie, urobí cut-fail takže výpočet pokračuje retract(db(fooo,X)), ktorý zlyhá. Podobne, ak má viac riešení. ?- foo(a). Yes ?- foo(b). No ?- foo(c). No ?- foo(f). No takže, foo(X) vlastne znamená (že X má práve jedno riešenie): foo(X):-findall(X,X,[_]).

  46. Rébus 2 Príklady programov, o ktorých nemožno tvrdiť, že sú logické, len preto, že sú v Prologu... predefinujte predikát goo bez assert a retract goo(X):- (X, (retract(db(gooo,_)),! ; asserta(db(gooo,1)), fail ) ); (retract(db(gooo,_)), fail). Ak X nemá riešenie, goo(X) neplatí. Ak má X jedno riešenie, tak retract(db(gooo,_)) zlyhá, vykoná sa asserta(db(gooo,1)), fail zlyhá. Ak neexistuje ďalšie riešenie pre X, retract(db(gooo,_)) odmaže db(gooo,1) a klauzula zlyhá. Ak existuje ďalšie riešenie pre X (napr. X má dve riešenia), retract(db(gooo,_)),! odmaže prvé a cut odstráni alternatívy. ?- p(1). Yes ?- p(2). Yes ?- p(3). No :-dynamic p/1. p(1):-retract(p(_):-_),assert(p(2)).

More Related