490 likes | 505 Views
Learn logic programming concepts with algorithms and examples in Prolog. Covering code, relations, recursion, memoization, dynamic programming, and more. Explore logic modeling and pitfalls like negation. Master list operations and logic rules.
E N D
PROgramming LOGicContinued A logic programming language is a notational system for writing logical statements together with specified algorithms for implementing inference rules. Head/Lander
What will be covered • Lots of code Head/Lander
Another relation ?? Remember "is" breaks the logical model. squares( [ ], [ ] ). squares( [N|T ], [S|ST ] ) :– S is N*N, squares( T, ST). ? – squares( [ 0, 2, 3, 1], X ). X = [ 0, 4, 9, 1] ? – squares( [ ], X ). X = [ ] ? – squares( [2, 4, 6], [4, 16, 36] ). yes Head/Lander
More simple examples • Counts all the positive numbers in a list. (i.e. n >0) Your solution should allow only one correct solutions. positive( List, NumberOfPos). • Partition a list of numbers into a positive list and a negative list. selectpn( List, PositiveList, NegList ) Head/Lander
positive( [ ], 0). positive( [ H | T ], Z ) :– H > 0, !, positive( T, Z1 ), Z is 1 + Z1. positive( [ _ | T ] , Z ) :– positive( T, Z ). ? – positive( [ 0, –1, –5, 5], X ). X = 1 ? – positive( [1, –2, 4, 2, 3], X ). X = 4 ? – positive( [ ], X ). X = 0 Head/Lander
selectpn( [ ], [ ], [ ] ). selectpn( [ 0 | T ], X, Y ) :– selectpn( T, X, Y ), !. selectpn( [ H | T ], [ H|Z ], X ) :– H > 0, !, selectpn ( T, Z, X ). selectpn( [ H | T ], X, [ H|Z ] ) :– selectpn ( T, X, Z ). ? – selectpn( [ 0, –1, –5, 5], X, Y ). X = [5] Y = [–1, –5] ? – selectpn( [1, –2, 4, 2, 3], X, Y ). X = [1, 4, 2, 3] Y = [–2] Head/Lander
permute( [ ], [ ] ). permute(L, [ X | Y ] ) :– select( L, X, T ), permute( T, Y ). select( [ X | Y ], X, Y ). select( [ X | Y ], Z, [ X | T ] ) :– select( Y, Z, T). ? – permute( [ 1, 4, 7 ], X ). X = [ 1, 4, 7 ]; X = [ 1, 7, 4 ]; X = [ 4, 1, 7 ]; X = [ 4, 7, 1 ]; X = [ 7, 1, 4 ]; X = [ 7, 4, 1 ]; no Head/Lander
Try: callperm( X ):– permute( X ,Y ), write(Y ), nl, fail. ? – callperm( [1, 4, 7] ). [1, 4, 7] [1, 7, 4] [4, 1, 7] [4, 7, 1] [7, 1, 4] [7, 4, 1] no Head/Lander
Recursion revisited fibonacci_1( X , 1) :– X =< 2. fibonacci_1( X , Y ) :– X > 2, X1 is X – 1, X2 is X – 2, fibonacci_1( X 1, Y1), fibonacci_1( X 2, Y2), Y is Y1 + Y2. Head/Lander
Improvement: MemoizationUsing asserta to add facts to our program.(Need directive :-dynamic) fibonacci_2( 1, 1). fibonacci_2( 2, 1). fibonacci_2( X, Y ) :– X > 2, X1 is X – 1, X2 is X – 2, fibonacci_2( X1, Y1 ), fibonacci_2( X2, Y2 ), Y is Y1 + Y2, asserta(fibonacci_2( X,Y )). Head/Lander
Dynamic ProgrammingUSING STATE VARIABLES (ACCUMULATORS) TO PASS VALUES FROM ONE ITERATION TO THE NEXT.(How would you simulate an array in Prolog?) fibonacci_3( N, Fib):– fib_aux( 2, N, 1, 1, Fib ). fib_aux ( N, N, F1, Fib, Fib ). fib_aux ( M, N, F1, F2, F ) :– M < N, NextM is M + 1, NextF2 is F1 + F2, fib_aux(NextM, N, F2, NextF2, F). Head/Lander
Breaking the model • Another break of the logical model ... • Problems that can occur depending on the position of Variables in a predicate • Problems that can occur depending on the order of the predicates in a Query • The problem with NOT Head/Lander
% Assume family.pl parent( X , Y ) :– mother( X , Y ). /* If mother( X ,Y ) then parent( X ,Y ) */ parent( X , Y ) :– father( X , Y ). grandparent( X , Z ) :– parent( X , Y ),parent(Y, Z ). mother(mary, ann). mother(mary, joe). mother(sue, marY ). father(mike, ann). father(mike, joe). grandparent(sue, ann). /* Redundant */ sibling( X , Y ) :– parent(P, X ), parent(P, Y ). ?- sibling( X, Y ). X = ann Y = ann Head/Lander
sibling( X , Y ) :– parent(P, X ), parent(P, Y ), not( X = Y). both-parent-sibling( X , Y ) :– mother( M, X ), mother( M, Y ), father( F, X ), father( F, Y ), not( X = Y ). 1?- sibling( X, Y ). X = ann Y= joe 2?- both-parent-sibling( X , ann). X = joe Head/Lander
Negation: not(P) :– call(P), !, fail. not(P). alternatively: not(P):– P, !, fail; true. alternatively: not(P):– P, !, fail. not(P):-true. Head/Lander
The trouble with “not” test( S, T) :- S = T.1?- test( 3, 5). no 2?- test( 5, 5).yes 3?- not( test( 5,5)).no 4?- test( X,3), R is X+2.X=3R=5 5?- not( not( test( X,3))), R is X+2. warning unbounded variable in arithmetic expression fail ... /* When not(test(X,3)) fails the instantiation of X to 3 is released */ Head/Lander
Another problem with not /* X instantiated to 0, then not( 0= 1) succeeds. */ 6?- X = 0, not( X=1). X=0 /* X instantiated to 1, not( X=1) fails, the goal X = 0 is never reached */ 7?- not( X=1 ), X=0. no Head/Lander
append and reverse • Define append(L,M,Result)where Result is L appended to M. ?- append([1,2],[a,b],R). R = [1,2,a,b] • Pick the list to recur on: L or M. • BASE case? You only need one fact. • Recursive case? You only need one rule. M = L = 1, 2 a, b Result = 1, 2 a, b Head/Lander
append continued • Using append to retrieve the prefix, suffix of a list append(Prefix,[e,e|Suffix],[a,b,c,d,e,e,f,g]). • Partitioning a list around an element. -- delete append (Before, [d|After], [a,b,c,d,e,e,f,g]). • Another definition of member member( E, L) :- append( L1,[E|L2], L). • What is big "O" of append? Head/Lander
Reversing a list • Naive code using append. • Examine the recursion -- work done during the return. • Using a "helper" functor to have the work done before the call. • Faster Head/Lander
Reverse- Slow rev([ ], [ ]). rev([Head|Tail],Result) :- rev(Tail, ReversedTail), append(ReversedTail,[Head],Result). • Without cuts ?- rev(X,[a,b])goes into a loop after “;” Head/Lander
Reverse-Slow revA([ ], [ ]). revA([Head|Tail],Result) :- append(ReversedTail,[Head],Result), revA(Tail, ReversedTail). • Without cuts ?- revA([a,b], X)goes into a loop after “;” Head/Lander
Reverse--Fast revEff(List,RList) :- revEff(List,[ ],RList). % Helper -- t.r. revEff([ ],RL,RL). revEff([Element|List],RevPrefix,RL) :- revEff(List,[Element|RevPrefix],RL). • Without cuts ?- revEff(X,[a,b])goes into a loop after “;” Head/Lander
Difference lists • Represent a list segment as a list-pairs, separated by any symbol, typically the “-” sign • The second of the pair is the later part of the first list: [a,b| X] - X where L = [a,b | X](L - X) L X L [a, b | X] a b Head/Lander
The “difference” is interpreted (by the reader ) as a list containing only the first part of the first of the pair;up to the beginning of the second list in the pair: [a,b,c,d | X] - [c,d | X] is interpreted as [a,b] • In fact, one of the best forms to work with is: [a,b,c,d | X ] - X which is interpreted as [a,b,c,d] Head/Lander
Consider appendDL (L – M, M – N, L – N). compared to: append( [ ],X,X ). append( [X|Y],Z,[X|T ] ):– append(Y,Z,T). appendDL([a,b,c| A] -A, [d,e | B] - B, R - V) L M M N B A a d b e c Head/Lander
appendDL([a,b,c|A] -A, [d,e |B] - B, R - V).appendDL (L – M, M – N, L – N). L M M N R V a d b e c Head/Lander
appendDL (L – M, M – N, L – N). 1?–appendDL( [1,2,3|X]-X,[4,5]-[ ],Y – Z ). X = [4,5] Y = [1,2,3,4,5] Z = [ ] 2?–appendDL( [1,2,3|X]-X, [4,5|Y]-Y, W–Z ). X = [4,5| _n] Y = _n W = [1,2,3,4,5| _n] Z = _n Head/Lander
Converting a Difference List to a list: simplify( X -Y,[] ):- X == Y. simplify( [X|Y]-Z,[X|W] ):- simplify(Y-Z,W). ?-simplify( [1,2,3|X]-X, Y ). Y = [1,2,3] Head/Lander
Quick sort is very intuitive in Prolog: qsort( [P|L], Outlist):– partition( P ,L,Small,Large), qsort(Small,Localsmall), qsort(Large,Locallarge), append(Localsmall, [P|Locallarge], Outlist). qsort( [ ], [ ] ). partition( _,[ ],[ ],[ ] ). partition( P ,[Y|T],[Y|Sml],Lg) :– P > Y, !, partition(P, T, Sml,Lg). partition( P ,[Y|T],Sml,[Y|Lg] ):– partition(P, T, Sml,Lg). Head/Lander
QuickSort using Difference Lists qsort1(Inlist, Outlist):– qsort2(Inlist,Outlist – [ ] ). qsort2( [X|Tl], A1–Z2):– partition( X ,Tl,Sm,Lg), qsort1(Sm,A1–[X|A2] ), qsort1(Lg,A2–Z2). qsort2( [ ], Z–Z ). Head/Lander
Grammars and Prolog • Prolog is use in artificial intelligent processing especially for natural language processing. • Recognizers are easy to program in Prolog given a BNF grammar. • Converting the BNF grammar for anbn S-> a b | a S b where S is a non-terminal symbol and a,b terminal symbol s --> [a],[b]. s --> [a], s, [b]. where "[]" are used for terminal symbols and atoms for non-terminal symbols. Replace ->with -->, S with s and a, b with [a],[b] Head/Lander
Under the Covers s --> [a],[b]. s --> [a], s, [b]. • Is syntactic sugar for s(A, B) :- 'C'(A, a, C), 'C'(C, b, B). s(A, B) :- 'C'(A, a, C), s(C, D), 'C'(D, b, B). 'C'([A|B], A, B). • Notice that 'C' is an atom and C is a variable • We represent the language as a list of a & b atoms. • To check if a string is recognized enter the following query: s([a,a,a,b,b,b], []). s([a,a,b,b,a,a,b,b,], []). Head/Lander
Be careful with the Grammar • Because of the way Prolog executes it is a top down parser. • It behaviors like a recursive decent parser. • Left recursion must be removed to avoid "stack overflow". • So the grammar for balance "()" s -> ( ) | ( s ) | s s can not be used • However it can be transformed to : s -> ( ) | ( ) s | ( s ) | ( s ) s Head/Lander
Additional Examples-- may not be discussed • Sum of Subset • Towers of Hanoi puzzle • Recursive data structures - trees • looping -- generate and test • Implementing repeat loop in Prolog • Implementing for loop in Prolog Head/Lander
Naturally solved Problems using Prolog • Logic programming is a natural choice for problems that fit the database model and for algorithms that require the built-in backtracking search capability of logic programming. • Sum of subset decision problem. • What is the problem? • What is the code? • sumOfsubset(Set, Sum, SubSet). • What is the fact? • What are the rules? Head/Lander
Sum of Subsets • Problem: Given n positive integers w1, ... wn and a positive integer W. Find all subsets of w1, ... wn that sum to W. • Similar to the 0-1 knapsack problem. When the benefit of each item is equal to its weight the 0/1 Knapsack problem becomes the sum of subsets problem. • Example: n=3, W=6, and w1=2, w2=4, w3=6 • Solutions: {2,4} and {6} Head/Lander
Sum of subsets • We will assume a binary state space tree. • The nodes at level 1 are for including (yes, no) item 1, the nodes at level 2 are for item 2, etc. • The left branch includes wi, and the right branch excludes wi. • The nodes contain the weights included so far Head/Lander
Sum of subset Problem: State SpaceTree for 3 items w1 = 2, w2 = 4, w3 = 6 and W = 6 0 yes no i1 2 0 yes no no yes 4 6 0 i2 2 no yes no yes yes yes no no 8 2 i3 6 10 0 12 6 4 The total weight up to the node is stored at the node. Head/Lander
Towers of Hanoi puzzle: hanoi(N):– move(N,left,right,center). move(0, _ , _ , _ ) :– !. move(N,A,B,C):– M is N–1, move(M,A,C,B), inform(A,B), move(M, C, B, A). inform(X,Y):–write([move,a,disc,X,to,Y]),nl. ?-hanoi(3). move a disc left to rightmove a disc left to centermove a disc right to centermove a disc left to rightmove a disc center to leftmove a disc center to rightmove a disc left to right Head/Lander
Recursive "data" structure: • Representing Binary Trees Binary tree structure: node(Self, Leftsubtree, Rightsubtree). binarytree(empty ). binarytree(node ( X , Y, Z )):– binarytree (Y ), binarytree (Z ). Head/Lander
Searching the binary tree structure treeMember (E, node (E, _ , _ )):– !. /* cut off search after first time the element is found */ treeMember(E, node ( N , L, _ )):– E < N, !, treeMember (E, L). /* cut if E < N to avoid searching the right subtree */ treeMember(E, node ( _ , _ , R )):–treeMember(E, R). Head/Lander
Repetition: Generate and test natural(1). natural(N) :- natural(M), N is M+1. loop(N) :-natural(Int), Int =< N, write(Int), nl, Int=N, !. Head/Lander
Repetition Through BacktrackingBuilt-in: repeat repeat. repeat :- repeat. % repeat turns any predicate into a generator % Infinite number of “*” stars :- repeat, write(‘*’), fail. % repeat until “end of line” keyBoard :- repeat, get0(C), C = 0, !. Head/Lander
Limitations of Repeat • Prolog’s repeat is quite different than a procedural language’s repeat because backtracking can take any subgoal that has an untried alternative. • The only way to pass information from one pass to another is to use assert to store data in the knowledge base. Head/Lander
Repetition Through Backtrackingfor loop: for Index = Start to Finish for(I,I,I) :- !. %R1 for(I,I,_). %R2 for(Index,S,F) :- N is S+1, for(Index,N,F). %R3 printint(S,F) :- for(Ind,S,F), write(Ind), nl, fail. Head/Louden p457 ex 32
% ForLoop: for(I,I,I) :- !. for(I,I,_). for(Index,S,F):- N is S+1,for(Index,N,F). printint(S,F):-for(Ind,S,F),write(Ind),nl, fail. ?- for(I, -1, 2). I = -1 ; I = 0 ; I = 1 ; I = 2 ; No ?- Head/Lander
HOW? ?-printint(1,2). Pattern matching Unification printint(S,F) subgoal write(Ind),nl,fail. for(Ind,S, F) for(_v, 1, 2) write(1),nl,fail. for( 1, 1, 2). R2 fails try to redo for(_v, 1, 2) Succeeds Head
for(_v, 1, 2) redone for(Ind,S, F) write(Ind),nl,fail. for(_v, 1,2) write(2),nl,fail. for(Index,S,F) R3subgoals fails Backtracking fails no more solutions for(Index,N,F) N is S+1 R1 _v2 is 1+1 for(_v,2,2) 2 is 1+1 for( 2,2,2) Head