Föreläsning 14 Logik med tillämpningar
Innehåll u Cuts och negation u Input/output u Extralogiska predikat u Interaktiva program, failure-drivna loopar u Generate and test u 11, 12.1, , 14.1 i Sterling/Shapiro
merge([X|Xs],[Y|Ys],[X|Zs]) :- X<Y, merge(Xs,[Y|Ys],Zs). merge([X|Xs],[Y|Ys],[X,Y|Zs]) :- X=Y, merge(Xs,Ys,Zs). merge([X|Xs],[Y|Ys],[Y|Zs]) :- X>Y, merge([X|Xs],Ys,Zs). merge(Xs,[ ],Xs). merge([ ],Ys,Ys).
Cuts = beskärningar u En beskärning, ett cut, (betecknas !) kan användas för att uttrycka denna ömsesidiga uteslutning av klausuler. u Beskär sökträdet och förkortar därmed beräknings- tiden och minskar mängden minne som behövs. u Målet lyckas och ”binder” Prolog till alla val den gjort från det att föräldramålet unifierades med huvudet till klausulen som cutet finns i.
Operationellt gäller följande: u Ett cut beskär alla klausuler nedanför den aktuella klausulen. u Ett cut beskär alla alternativa lösningar till den konjunktion av mål som står till vänster om beskärningspunkten i klausulen. u Ett cut påverkar inte målen som står till höger om beskärningspunkten. Över dessa sker backtracking som vanligt.
merge([X|Xs],[Y|Ys],[X|Zs]) :- X<Y,!, merge(Xs,[Y|Ys],Zs). merge([X|Xs],[Y|Ys],[X,Y|Zs]) :- X=Y,!, merge(Xs,Ys,Zs). merge([X|Xs],[Y|Ys],[Y|Zs]) :- X>Y,!, merge([X|Xs],Ys,Zs). merge(Xs,[ ],Xs):- !. merge([ ],Ys,Ys):- !.
Exempel: Svara på frågan test(M,N) test(X, Y) :- p(X), koll(X,Y). test(X, Y) :- p(Z), Y is Z*3. koll(X, X) :- X >=2. p(1). p(2). test(X, Y) :- p(X), koll(X,Y). test(X, Y) :- p(Z), Y is Z*3. koll(X, X) :- X >=2. p(1):- !. p(2).
minimum(X,Y,X) :- X =< Y. minimum(X,Y,Y) :- X > Y. minimum(X,Y,X) :- X =< Y, !. minimum(X,Y,Y) :- X > Y. minimum(X,Y,X) :- X =< Y, !. minimum(X,Y,Y).
u Observera att den sista versionen inte har samma betydelse som de tidigare två. Den lyckas för målet minimum(2,5,5). u Inte logiskt korrekt! Ett cut som förändrar programmets mening kallas för rött.
Gröna vs röda cuts u Vi skiljer på två typer av cuts, gröna och röda. u Att addera eller ta bort gröna cuts från ett program påverkar inte programmets mening. Gröna cuts beskär endast vägar som inte leder till nya lösningar. Cuts som inte är gröna är röda. u Röda cuts används vanligen för att utelämna explicita villkor.
Vilka cut är gröna och vilka är röda? member(X, [X | Xs]) :- !. member(X, [Y | Ys]) :- member(X, Ys). max(X, Y, Y) :- X =< Y, !. max(X, Y, X) :- X > Y, !. likes(jan, glass) :- !. likes(pelle, vatten) :- !. likes(lena, te) :- !.
Några principer för cuts u Vanliga fel när man använder cuts: –Man antar att beräkningar beskärs som inte gör det –Man antar att vissa beräkningar inte beskärs trots att de gör det. u Gör cuts så lokala som möjligt. u Sätt ett cut så fort man vet att den korrekta klausulen har valts. u Lägg inte in cuts i ett program förrän det fungerar korrekt.
quicksort([X|Xs], Ys) :- partition(Xs, X, Littles, Bigs), quicksort(Littles, Ls), quicksort(Bigs, Bs), append(Ls, [X|Bs], Ys). quicksort([],[]). partition([X|Xs], Y, [X|Ls], Bs) :- X =< Y, partition(Xs, Y, Ls, Bs). partition([X|Xs], Y, Ls, [X|Bs]) :- X > Y, partition(Xs, Y, Ls, Bs). p artition([], Y, [], []).
Negation not(X) :- X, !, fail. not(X). Vad händer vid frågan not(G) ? Om G lyckas så beskärs trädet och misslyckas på fail, och not(G) misslyckas. Om anropet till G däremot misslyckas så används den andra regeln, som lyckas. Alltså: not(G) misslyckas om G lyckas och lyckas om G misslyckas.
Extra-logiska predikat u Ligger utanför den logiska modellen. u Genererar en sidoeffekt. u Finns 3 typer: –Input/Output –Manipulationer av programmet –Interface mot underliggande operativsystem (tas inte upp här..)
Input/Output u read(X). % läser input (stdin) write(X). % skriver output (stdout) En Pascal-liknade writeln kan definieras så här: writeln([X|Xs]) :- write(X), writeln(Xs). writeln([]) :- nl. % nl är ett predikat som ger % en ny linje
Interaktiva program u Läs in ett fakta, processa faktat och läs in nytt fakta. u Ofta implementerat som while-loopar i andra programspråk. u Bygger på svans-rekursion i Prolog.
Grundläggande while-loop echo :- read(X), echo(X). echo(X) :- last_input(X), !. echo(X) :- write(X),nl,read(Y),!,echo(Y). last_input är ett predikat som kollar om X uppfyller avslutningsvillkoret för loopen. u Om villkoret ej är uppfyllt skrivs X ut och ett nytt värde läses in.
Failure-driven loop u Den misslyckandebaserade slingan är ett sätt att skapa upprepning med hjälp av återspårning istället för med rekursion. u Liknar repeat-loopar i andra språk. u Har ingen logisk motsvarighet utan kan bara förklaras operationellt.
Grundläggande repeat-loop u repeat. repeat :- repeat. echo :- repeat, read(X), echo(X), !. echo(X) :- last_input(X), !. echo(X) :- write(X), nl, fail. u Cut i klausulen med repeat är viktigt annars skulle vi kunna få oändlig körning pga backtracking.
Generera och testa (generate and test) u Bygger på failure-driven loop. u Ett problemlösningsparadigm som man ofta använder sig av som Prologprogrammerare. u En process eller rutin genererar kandidater till lösningen på ett problem och en annan process (rutin) testar kandidaterna för att hitta alla lösningar. u find(X) :- generate(X), test(X).
u Låt oss skriva ett program som genererar alla prim- tal mellan M och N. Först behöver vi en procedur som avgör om ett tal är ett primtal: u prime(X) :- X > 1, Y is X - 1, prime(X,2,Y). prime(X,M,N) :- N < M. prime(X,M,N) :- not(0 is X mod M), M1 is M+1, prime(X,M1,N).
Effektivare: prime(X) :- 0 is X mod 2, X > 2, !, fail. prime(X) :- X > 1, Y is integer(sqrt(X)), prime(X,3,Y), !. prime(X,M,N) :- N < M. prime(X,M,N) :- not(0 is X mod M), M1 is M+2, prime(X, M1, N).
Generator av tal u Vi behöver en generator som genererar alla tal i intervallet [M..N]. Finns ofta inbyggd som genlist: genlist(M,M,[M]) :- !. genlist(M,N,[M | Ls]) :- M1 is M+1, genlist(M1,N,Ls).
Vårt program blir då: u primes(M,N,X) :- genlist(M,N,Ls), member(X,Ls), prime(X).