Prolog (8) Jan Hric, KTI MFF UK, a
Heuristické prohledávání grafu Heuristicke prohledavani, pomoci prioritni fronty, vybirame vrchol, ktery ma nejbliz do Cile -interface grafu: start/1, solution/1, child/2 (anebo children/2) -interface heuristiky: estimate_goal(+Node, - Estimate) -interface haldy: empty_heap(-H), add_heap(+H0,+Cost,+Node,-H), get_from_heap/4 % ADT -knihovna: keysort/2, ord_union/4 best_first(Answer):- start(Start), initial_heap(Start, Heap), best_star(Heap,[Start],Answer), % b_s(otevrene, uzavrene, answer) solution(Answer). initial_heap(Start,Heap):- estimate_goal(Start, Estimate),% odhad ceny do cile empty_heap(Empty), add_heap(Empty, Estimate, Start, Heap).% pridani startu do haldy best_star(Heap, Closed, Answer):- get_from_heap(Heap, _, Node, Heap1), % vraci min. z haldy ( Answer=Node% akt. Vrchol na vystup ; children_4(Node, Closed,Closed1, Heap1, Heap2),% deti aktualniho Node best_star( Heap2, Closed1, Answer)% rekurze, s novymi akumulatory ). children_4(ParentNode, Closed, Closed1, Heap, Heap1):-% pridani deti ordered_children(ParentNode,Closed,Closed1, OrdPairs),% zjisteni sjedn. a novych vrcholu add_children(OrdPairs, Heap, Heap1).% vlastni pridani do haldy, bez opakovani(!)
Heuristicke prohledavani grafu 2 ordered_children(ParentNode, Closed, Closed1, OrdPairs):- children(ParentNode, ChildrenSet), ord_union(Closed, ChildrenSet, Closed1, NewChildren),% z knihovny compute_ranks(NewChildren, RawPairs), keysort(RawPairs,OrdPairs).% usporadani podle klice-kriteria compute_ranks([],[]). compute_ranks([Child|Children],[Estimate-Child|Pairs]):-% vyroba seznamu vrcholu s odhadem estimate_goal(Child, Estimate), % pouziti heuristiky compute_ranks(Children, Pairs). add_children([],Heap, Heap). add_children([Estimate-Child|Children], Heap0, Heap):-% pridani novych v. na haldu add_heap(Heap0,Estimate, Child, Heap1), add_children(Children,Heap1,Heap). - v umělé inteligenci alg. A* pro hledání nejkratší cesty - seřazení vrcholů podle ceny: součet ceny od startu a odhadu do cíle (jiná interpretace estimate_goal/2)
Dámy na šachovnici (generuj a testuj) queens(N,Queens):- length(Queens,N), % volné proměnné: Qs=[_,_,_, …] rows_columns(Queens,Rows,Cols,0),% čísluje Rows od 1 % Qs=[1-C1, 2-C2, 3-C3, …] perm(Rows,Cols),% naváže Cols; generuj … noattack(Queens).% … a testuj, rows_columns([],[],[],_). % výroba dvojic, řádků a (volných) sloupců rows_columns([R-C|Queens],[R|Rs],[C|Cs],R0) :- R is R0+1, row_columns(Queens,Rs,Cs,R).% R je posl. vygener. sloupec noattack([]).% kontrola neohrožování na celé desce noattack([R-C|Queens]):- noattack(Queens,R,C),noattack(Queens). noattack([],_,_).% kontrola ostatních vůči jedné noattack([R2-C2|Queens], R1, C1):- % kontrola ostatních vůči jedné R2 + C2 =\= R1 + C1, R2 – C2 =\= R1 – C1, % různá diagonála noattack(Queens, R1,C1)%
Eliza – z oboru Umělé Inteligence Eliza – simulace rozhovoru s psychoanalytikem (pp.151) Fraze = [[w(i),s(X),w(my),s(Y)]-[w(your),s(Y),s([?,why,do,you]),s(X),s([it,?])], …], KlicFraze = [mother-[s(X)]*[s([tell,me,more,about,your,family])], alike-[s(X)]*[in,what,way,?],…], % data: každý uživatel má svoje odezva(Fraze,KlicFraze,Veta,Odezva):- ( member(VzorF-VzorO,Fraze) % přímé reakce ; member(Klic,Veta), member(Klic-VzorF*VzorO,KlicFraze) % reakce podle klíče ), match(VzorF,Veta), match(VzorO,Odezva),% porovnani vzoru a odpoved match([],[]). match([Vzor|Vzory], [Slovo|Slova]):- match(Vzor, Vzory, Slovo, Slova). match(w(Slovo),Vzory,Slovo,Slova):- match(Vzory,Slova). % porovnani slova match(s([Slovo|Seg]),Vzory,Slovo,Slova0):- append(Seg,Slova1, Slova0), match(Vzory,Slova1). %porovnani segmentu, nedeterministicky ?- odezva(F,KF,[i,like,my,job],O). O=[your,job,?,why,do,you, like,it,?] - vyloučení opakování reakcí, pamatování si klíčů a návrat k tématům (ze zásobníku)
Eliza - příklad > all men are alike. % klíč. slovo In what way ? > they always want the same thing. Can you be more specific ? > are you trying to be funny? % vzor: are you X Would you prefer it if I weren't trying to be funny ? %..weren’t Y > computers are stupid. % X are Y What if they were not stupid ? %... were not Y > This conversation is silly. % bez klíče I'm sorry. Could you please rephrase that ? >.
Plánování interpretace datové struktury struktura plánů: Act1 // Act2- paralelní vykonávání Act1, Act2- nejprve Act1, pak Act2 do(BasicAct)- vykonej primitivní akci execute(Plan) – jako Popis, kde plan(Plan, Popis) informace o BasicAct precond(BA1,BA2) – před BA1 se musí uskutečnit BA2 cost(BA, Cena)- cena zákl. plánu -spočítání ceny plánu (pp. 267) plan_cost(Plan, Cost) :- plan_cost(Plan,0,Cost). plan_cost(Act1 // Act2, C0, C):- plan_cost(Act1,C0,C1), plan_cost(Act2,C1,C). plan_cost((Act1,Act2), C0, C):- plan_cost(Act1,C0,C1), plan_cost(Act2,C1,C). plan_cost(do(BasicAct), C0, C):- cost(BasicAct, Cost), C is C0+Cost. plan_cost(execute(Name), C0, C):- plan(Name,Plan), plan_cost(Plan,C0,C). - skontrolování správnosti plánu
(Práce s databází) assert(C), assertz(C) -vloží klauzuli na konec db. asserta(C).. vloží na začátek db. př.: assert((member(X,[_|L]):-member(X,L)). závorky kolem (částí) klauzulí :- -> ;, retract(C).. vypustí klauzuli z db. nesubstituuje za volné výstupní proměnné statické vs. dynamické predikáty. :- dynamic append/3. % direktiva v zdroj.soub., Informace pro kompilátor, že se pracuje s predikátem dynamicky abolish(P/N).. zničí definici P/N ?- abolish([p/1,q/2]). databáze záznamů (blackboard), impl. závislé (SWI ) recorda(+Klic,+Hodn), recordz(+K,+H), recorded(+K,-H), erase(+K)
Clause umožňuje přístup do databáze clause(Hlava,Telo) Hlava musí určit aspoň jméno a četnost predikátu ?- clause(member(A,B),C). A=_1 B=[_1|_2] C=true ; A=_1 B=[_2|_3] C=member(_1,_3) ; no fakty vrací: Telo = true
Datové struktury binární stromy void/0, t/3 map_t(P,T1,T0) St má 4 param. ; 3 vstupní a 1 výstupní 2-3 stromy: void/0, t2/3, t3/5 map_t23(P,T1,T0) Asociativní seznam: nil/0, cons/3 (klic, hodn, AS) ... map může převádět na jiné struktury: seznam seznam klíčů, seznam hodnot...
Neúplné datové struktury (vyhledávací slovník) rozdílové seznamy graf pointry jsou realizovány vazbami proměnných problémy se změnami (log. prom.) při změně se struktura kopíruje pro Prolog jsou strukt. “nekonečné” problém s výpisy, unifikací...
Rozdílové seznamy umožňují spojení seznamů v konstantním čase k danému seznamu je možné připojit jen jeden seznam je přístupný konec seznamu pomocí volné (logické) proměnné idea: [a,b,c] ~> [a,b,c|K]-K; []~>K-K rozdílový seznam - d.s.: Začátek - Konec převody: seznam rozdíl. seznam list2dlist(L,Z-K):- append(L,K,Z). append/3 ušetříme, pouze pokud nepřevádíme dlist2list(L-[],L). dappend(Z1-K1,Z2-K2,Z1-K2):-K1=Z2. %...
Aplikace r. seznamů Program: qsort([],Z-Z). qsort([X|L],Z-K):- split(X,L,L1,L2), qsort(L1,Z-[X|K1]), % přidání prvku X nakonec qsort(L2,K1-K). volání: ?- qsort([3,1,4,2],V-[]). Argumenty lze předat samostatně, podobné akumulátoru 2.arg je výstup, 3. arg je akumulátor,který naplňujeme odzadu ?- qsort([3,1,4,2],V,[]).
Kompilace aritm. výrazu, do zásobníkového stroje :- op(600,xfx, :=). ?- cc(var(a):=var(b)+const(1), Kod,[]). % volání Kod=[load(b),load(const(1)),plus,store(a)] cc(var(V),[load(V)|Kod],Kod). cc(const(C),[load(const(C))|Kod],Kod). cc(V1+V2, Kod1,Kod3):- cc(V1,Kod1,Kod2), cc(V2,Kod2,[plus|Kod3]). % postfixní kód cc(var(V):=Vyr,Kod1,Kod2):- cc(Vyr,Kod1,[store(V)|Kod2]). Podobně interpretace výrazu
Kompilace příkazů DC faktorial cc(( read(i); j:=1; while(i>0, ( j:= j*i; i:= i-1 ) ); write(j) ), Kod,[]).
Programování s omezujícími podmínkami Prolog řeší rovnice nad “symbolickými” výrazy jiné domény: reálná čísla, konečné domény, řetězce, množiny, grafy... interface Prolog - řešič Prolog posílá podmínky (a odebírá), deklarativně řešič vrací “soustava podmínek je řešitelná” na konci výpočtu: nějaký tvar řešení zjednodušené podmínky (vyřešený tvar) posloupnost řešení př.: rovnice nad reálnými čísly vyřešené lineární rovnice a nerovnice s par. zbylé nelineární podm.
Konečné domény řešení kombinatorických problémů grafy, plánování... místo “generuj a testuj”: “omez a generuj” obarvení grafu n barvami pro v_i prom. X_i pro hranu v_i - v_j podm. X_i\=X_j domény: X_i :: {1,2,..n} Prakticky používané systémy Eclipse ILOG solver - knihovny řešiče a interface pro C
Příště funkcionální programování...
Binární vyhl. stromy %insert(X,I,O) insert(X,void,t(void,X,void).
Insert do AVL stromu strukt: v/0, t(Levy,Koren,, Pravy) i(+Strom, +Y, -NovyStrom, +deltaHloubky: inc,noinc) - insert i(v,Y,t(v,Y,=,v),inc). % dále pouze přidávání do levého podstromu =;V= <), i(L,Y,L0,DH), upd0(V,DH,V0,DH0). %bez změny hloubky i(t(t(LL,LX,LV,LR),X,>,R), Y,t(LL0,LX,LV0,t(LR,X,=,R),DH0):- (LV= =;LV= <), i(LL,Y,LL0,DH), upd1(LV,DH,LV0,DH0). %jednoduchá rotace i(t(t(LL,LX,LV,t(LLL,LLX,LLV,LLR)), X,V,R), Y, t(t(LL,LX,V1,LLL0),LLX,=,t(LLR,X,V3,R)), noinc):- %dvojitá r. i(LLL,Y,LLL0,DH), upd2(left,LLV,…). i(t(t(LL,LX,LV,t(LLL,LLX,LLV,LLR)),X,V,R), Y, t(t(LL,LX,V1,LLL),LLX,=,t(LLR0,X,V3,R)), noinc):- i(LLR,Y,LLR0,DH), upd2(right,…). upd0(V,D,V0,D0):- member(f(V,D,V0,D0), [f(X,noinc,X,noinc), f(=,inc,>,inc), f(<,inc, =,noinc)]). % seznam případů místo klauzulí upd1(V,D,V0,D0):- member(f(V,D,V0,D0), [f(=,noinc,<,noinc), f(=,inc,=,inc), f(<,inc,<,inc)]). % ?? upd2(S,V,D,V1,V2,noinc):- member(f(S,V,D,V1,V2), [f(left,>,noinc,>,,,inc,=,,inc,>,=), f(right,=,inc,>,=)]). Jiná reprezentace: vyvážení jako čísla -1, 0, +1.
(Regulární výrazy příklad reprezentace)