400 likes | 415 Views
Explore the limitations and solutions of logic programming through Prolog with examples and tips on controlling backtracking and optimization. Learn how the "cut" feature can enhance Prolog efficiency.
E N D
Weakness of logic Programming • Horn clause cannot cover all logics • “every living thing is an animal or a plant • animal(X) V plant(X) living(X) • So we must have the following definition in Prolog animal(X):- living(X), not plant(X). plant(X):- living(X), not animal(X). Prolog can only have one element on this side Not will only satisfy if we can’t find that X is an animal.
Another weakness is the way that Prolog uses its rules from top to bottom. We already saw the problem • “not” means cannot find. It does not mean false.
exercises • Binary search Tree • nil • t(L,M,R) • isin(item, Tree) isin(X,t(L,X,R)). isin(X,t(L,M,R)):- X<M, isin(X,L). isin(X,t(L,M,R)):- X>M, isin(X,R). • add(X,Tree,ResultTree) add(X,nil,t(nil,X,nil)). add(X,t(L,X,R),t(L,X,R)). add(X,t(L,M,R),t(L1,M,R)):- X, <M add(X,L,L1). add(X,t(L,M,R),t(L,M,R1)):- X>M, add(X,R,R1).
Controlling backtracking • We can prevent backtracking, by using a feature called “cut”. • Normally, prolog backtrack to find all answers, but sometimes we only need the first solution. • Example f(X,0):-X <3. f(X,2):- 3=<X, X<6. f(X,4):- 6=<X.
f(X,0):-X <3. f(X,2):- 3=<X, X<6. f(X,4):- 6=<X. • If we try ?-f(1,Y), 2<Y. We will have Y = 0, and then 2<Y will be false So prolog will try to substitute another value for Y.
f(X,0):-X <3. f(X,2):- 3=<X, X<6. f(X,4):- 6=<X. This picture shows all the substitutions. f(1,Y), 2<Y. Rule 2 Y =2 Rule 3 Y =4 Rule 1 Y =0 f(1,0), 2<0. f(1,2), 2<Y. f(1,4), 2<4. fail 1 <3. 6=<1. 3=<1, 1<6. fail succeed fail • Notice that all the rules are mutually exclusive. • If rule 1 succeed, other rules will surely fail. • There is no point substituting rule 2 and 3 if rule 1 succeeds.
f(X,0):-X <3. f(X,2):- 3=<X, X<6. f(X,4):- 6=<X. f(X,0):-X <3, !. f(X,2):- 3=<X, X<6, !. f(X,4):- 6=<X. Rule 1 Y =0 f(1,0), 2<0. Fail, normally it will backtrack pass 1<3. But this time it’ll stop At ! 1 <3. succeed No further execution -> execution speed increases.
f(X,0):-X <3, !. f(X,2):- 3=<X, X<6, !. f(X,4):- 6=<X. • Let’s try another example ?-f(7,Y) Y = 4. (this is the answer) • First, try rule 1. • X <3 fails. So the program backtracks and uses rule 2. (we have not pass the “cut” so it’s ok to backtrack.) • Try rule 2 • 3=<7 but 7<6 fails. Therefore it backtracks to rule 3. • Try rule 3 • Succeeds.
f(X,0):-X <3, !. f(X,2):- 3=<X, X<6, !. f(X,4):- 6=<X. • We can optimize it further. • Notice that if X<3 fails, 3=<X in rule 2 will always succeed. • Therefore we do not need to test it. (same reasoning for 6=<X in rule 3). • So we can rewrite the rules to: f(X,0):-X <3, !. f(X,2):- X<6, !. f(X,4).
f(X,0):-X <3, !. f(X,2):- X<6, !. f(X,4). • Be careful now. If we do not have “cut”, we may get several solutions, some of which may be wrong. For example: ?-f(1,Y) Y=0 ; Y=2 ; Y=4 We order it to try other rules here. If we do not have “cut”, it will try other rules and succeed because we’ve deleted the conditional tests.
H:-B1, B2, …, Bm, !, …, Bn. • When finding answer up to “cut”, the system has already found solutions of B1 to Bm. • When the “cut” is executed, solutions B1 to Bm are considered fix. For example: C:-P,Q,R,!,S,T,U. C:-V. A:-B,C,D. ?-A. • When ! Is executed. P,Q,R will be fixed (no backtracking) and C:-V. will never get executed. • Backtracking is still possible in S,T,U but will never go back beyond the ! We put the question here.
C:-P,Q,R,!,S,T,U. C:-V. A:-B,C,D. ?-A. A B, C, D P,Q,R,!,S,T,U. Can backtrack if not reach ! Can backtrack to ! But not beyond that Let’s see another example next page.
max(X,Y,X):-X=>Y. max(X,Y,Y):-X<Y. • The rules are mutually exclusive. • So we can use “else if” for efficiency. max(X,Y,X):-X=>Y, !. max(X,Y,Y). • Be careful of the following situation: ?-max(3,1,1). yes. • It does not get matched with the first rule from the start. • But it then matches the second rule, because we already took out the conditional test. • So we fix it in the next page.
max(X,Y,X):-X=>Y, !. max(X,Y,Y). max(X,Y,Max):- X=>Y, !, Max =X. max(X,Y,Max):- Max =Y. ?-max(3,1,1). Program is able to enter the first rule because Max is not matched to any value. Once X=>Y in the first rule is satisfied, there is no backtracking. Let’s see an example on list next page.
member(X, [X|L]). member(X, [Y|L]):-member(X, L). • If there are many X in the list, this definition allow any X to be returned when we order it to backtrack. • If we want to make sure that only the first occurrence of X will be returned, we will have to use “cut”. member(X, [X|L]):-! member(X, [Y|L]):-member(X, L). ?-member(X, [a,b,c]). X=a; no Order it to find another solution (backtrack)
add(X, L, L):-member(X,L), !. add(X, L, [X|L]). ?-add(a,[b,c],L). L=[a,b,c] ?-add(X,[b,c],L). L=[b,c] X=b ?add(a,[b,c,X],L). L=[b,c,a] X=a • Add non-duplicate item into a list This is just one solution
Be careful. • If we define things using “cut”, we normally intend that every rule is tried, right from the first rule. So “cut” can serve its purpose. • Any query that allows rule skipping will destroy everything. ?add(a,[a],[a,a]). yes Does not match the first rule, but match the second rule. This makes things incorrect.
beat(tom, jim). beat(ann, tom). beat(pat, jim). • tennis match example • We want to categorize players into 3 types: • Winner: win every game • Fighter: player with mixed records • Sportman: lose every game
beat(tom, jim). beat(ann, tom). beat(pat, jim). • X is a fighter if • X is a winner if • We can use “if then else”: class(X,fighter):- beat(X,_), beat(_,X), !. class(X,winner):-beat(X,_), !. class(X,sportman):-beat(_,X). • We still need to be careful about rules getting skipped. For example: • ?-class(tom,sportman). • yes (but in fact tom is a fighter)
p(1). p(2):-!. p(3). ?-p(X). X=1; X=2; no ?-p(X),p(Y). X=1, Y=1; X=1, Y=2; X=2, Y=1; X=2, Y=2; no ?-p(X),!, p(Y). X=1, Y=1; X=1, Y=2; no
class(Number,positive):- Number>0. class(0,zero). class(Number,negative):-Number<0. class(0,zero):-!. class(Number,positive):- Number>0, !. class(Number,negative). Use cut
split([],[],[]). split([H|T],[H|Z],R):- H=>0,split(T,Z,R). split([H|T],R,[H|Z]):-H<0,split(T,R,Z). • Splitting a list to list of positive (including 0) and negative numbers. Use cut split([],[],[]). split([H|T],[H|Z],R):- H=>0,!, split(T,Z,R). split([H|T],R,[H|Z]):- split(T,R,Z). More difficult to understand Careful: ?-split([8,1,-3,0,-4,5],[1,0,5],[8,-3,-4]). Yes (it matches rule 3, skipping earlier rules.)
Make it better split([],[],[]). split([H|T],[H|Z],R):- H=>0,!, split(T,Z,R). split([H|T],R,[H|Z]):- H<0, split(T,R,Z). More committal split([],[],[]). split([H|T],[H|Z],R):- H=>0,!, split(T,Z,R). split([H|T],R,[H|Z]):- H<0, !, split(T,R,Z).
Unnecessary cut split([],[],[]):- ! split([H|T],[H|Z],R):- H=>0,!, split(T,Z,R). split([H|T],R,[H|Z]):- H<0, !, split(T,R,Z). Any match here will not match any thing else. H<0 is in the last clause, Whether or not H<0 fails, there are no choices laft.
Multiple choice with cut squint([],[]). sqluint([X|T],[Y|L]):- integer(X), !, Y is X*X, squint(T,L). sqluint([X|T],[X|L]):-squint(T,L). The third clause is not used when the goal backtracks. But it still does not stand independently.
Partial maps evens([],[]). evens([X|T],[X|L]):- 0 is X mod 2, evens(T,L). evens([X|T],L):- 1 is X mod 2, evens(T,L). • evens([],[]). • evens([X|T],[X|L]):- 0 is X mod 2, !, evens(T,L). • evens([X|T],L):- 1 is X mod 2, evens(T,L).
setify([],[]). setify([X|T],L):- member(X,T), setify(T,L). setify([X|T],[X|L]):- setify(T,L). setify([],[]). setify([X|T],L):- member(X,T), !, setify(T,L). setify([X|T],[X|L]):- setify(T,L).
tree insert(I,[], n(I,[],[])). insert(I, n(N,L,R) , n(N,L1,R)):- I<N, !, insert(I, L, L1). insert(I, n(N,L,R) , n(N,L,R1)):- I>N, !, insert(I, R, R1). insert(I, n(I,L,R) , n(I,L,R)).
Negation as failure “Mary likes all animals but snake.” likes(mary,X):-snake(X),!,fail. likes(mary,X):-animal(X). Or likes(mary,X):-snake(X),!,fail ; animal(X).
different(X,X):- !, fail. different(X,Y). Or different(X,Y):- X=Y, !, fail. ; true.
The “not” predicate not(P):-P,!,fail ; true. Some prolog allows not p(X) or \+(p(X))
member(X,[X|_]). member(X,[_|T]):-member(X,T). notmem(X,L):- \+(member(X,L)). notmem1(X,[]). notmem1(X,[Y|T]):-X\==Y, notmem1(X,T).
likes(mary,X):- animal(X), not snake(X). • Same examples with the use of “not” It means ->otherwise likes(mary,X):- animal(X), (snake(X), !, fail ; true). different(X,Y):- not X=Y. class(X,fighter):- beat(X,_), beat(_,X). class(X,winner):-beat(X,_), not beat(_,X). class(X,sportman):-beat(_,X), not beat(X,_).
Conclusion about “cut” • Pros • Avoid unnecessary execution. • Use like if-then-else • Cons • The rule must be tried in order, no skipping. P:-a,b P:-c. P:- a,!,b. P:-c. P:-c. P:-a,!,b. Logic is P <-> (a ^ b) V c Changing order has no effect. Logic is P <-> (a ^ b) V ((not a) ^ c) Different meaning Logic is P <-> c V (a ^ b)
goodteam(manunited). expensive(manunited). goodteam(liverpool). reasonable(T):- not expensive(T). ?-goodteam(X), reasonable(X). X=liverpool. ?- reasonable(X) , goodteam(X). no Has assigned value Has no assigned value. The “not” clause does not assign a value for you. See next page.
Only need to find a single value of X. ?- expensive(X). Means ?-not expensive(X). Means not It is forall, so prolog cannot instantiate a single value. So it gives “no” in the previous page.
Flight • timetable(Place1, Place2, ListOfFlights) • Flight = DepTime / ArrTime / FlightNo / ListOfDays • timetable(london, edinburgh, [9:40 / 10:50 / ba4733 / alldays, 19:40 / 20:50 / ba4833 / [mo,tu,we,th,fr,su]]). List of days or alldays
route(P1, P2, Day, Route) • flight(P1, P2, Day, Num, DepTime, ArrTime) • deptime(Route, Time) • transfer(T1, T2) List of From / To / FlightNo / DepTime
route(P1, P2, Day, Route):- flight(P1,P2,Day,Fnum,DepTime,_). route(P1, P2, Day, [(P1/P3/F1/Dep1)|RestRoute]):- route(P3,P2,Day,RestRoute), flight(P1,P3,Day,F1,Dep1,Arr1), deptime(RestRoute,Dep2), transfer(Arr1, Dep2). flight(P1, P2, Day, Fnum, DepTime, ArrTime):- timetable(P1,P2, FlightList). member(DepTime / ArrTime / Fnum / Daylist, FlightList), flyday(Day,Daylist). deptime([P1 / P2 / Fnum / Dep | _ ], Dep). transfer(H1:M1, H2:M2):- 60*(H2-H1) + M2 – M1 >= 40.
Logic circuit B A A C B inv(0,1). inv(1,0). and(1,1,1). and(1,0,0). and(0,1,0). and(0,0,0).