490 likes | 503 Views
PROgramming LOGic Continued. A logic programming language is a notational system for writing logical statements together with specified algorithms for implementing inference rules. What will be covered. Lots of code. Another relation ?? Remember "is" breaks the logical model.
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