 
 
 CS661 Artifical Intelligence
 Lecture 8 - more PROLOG 
 -  the cut 
  -  succeeds immediately but is never resatisfied 
-  as side effect - commits to all before it 
-  so cut stops backtracking 
-  genesis family example 
    father(abraham,ishmael). 
    father(abraham,isaac).  
    is_father(X) :- father(X,_). 
    ?-is_father(X).  
        abraham ; abraham
  
   in order to get the result only once ... 
  
    father(abraham,ishmael). 
    father(abraham,isaac).  
    is_father :- father(X,_), !. 
    ?-is_father(X).  
        abraham 
  
   the cut is like a fence 
  
   -  foo :- a, b, c, !, d, e, f. 
-  a, b, c backtrack, but once c succeeds we never try a or b or c again 
-  d, e, f can later backtrack 
use of !, fail.
       average_taxpayer(X) :- non_citizen(X), fail.  
       average_taxpayer(X) :- income<100000.
  
   this is wrong since may resatisfy later ! 
   so use ... 
  
       average_taxpayer(X) :- non_citizen(X), !, fail.
       average_taxpayer(X) :- income<100000.
  
   let's sum from 1 to N (assume N>=1) 
  
       sum(1,1) :- !.  
       sum(N,R) :- N1 is N-1, sum(N1,R), R is R+N.  
  
   need the cut since if had 
  
   -  go :- sum(1,X), foo(Y). 
-  and foo(Y) fails, PROLOG will try to reinstantiate sum(1,X). 
can replace cut with use of not( ) predicate
   -  sum(1,1).  sum(N,R) :- not(N=<1), N1 is N-1, sum(N1,R), R is R+N. 
PROLOG lists
  -  LISP language has list as its only data structure 
   -  which is why it is a list processing language 
-  PROLOG has list a one possible data structure 
-  a list is a set with order 
-  by placing lists inside lists we can make tree structures 
-  examples: 
   -  [ ] the empty list 
-  [a, b, c, d] a list with four elements 
-  [a, [b,c], d] a list with three elements, the second of which is a list 
-  one manipulation of lists is to separate head from tail 
   -  head is the first elements in the list, the tail is the rest of the list (a list!) 
-  [ head | tail ] 
-  there are potential problems with this notation, e.g. [A|B] = [X,Y] 
    -  ?- [H, T] = [a, b, c, d].    H=a T=[b,c,d] 
-  ?- [H,T] = [a].   H=a, T=[ ] 
-  ?- [H,T] = [ ].  no 
-  dot notation - binary tree interpretation 
   -  [a] == .(a,[]) 
-  [a,b,c] == .(a,.(b,.(c,[]))) 
-  some LISP-like predicates (most with 2 uninstantiated variables) 
   -  append 
    -  ?- append([a,b,c], [1,2,3], [a,b,c,1,2,3]).  yes 
-  ?- append([a,b], [c,d], X).  X=[a,b,c,d] 
-  ?- append(X, [b,c,d], [a,b,c,d]).  X=[a] 
-  how is append defined ? 
        append([ ], L, L).   
        append([H | L1], L2, [H | L3]) :- append(L1, L2, L3).
    
   
    is_list 
   
    -  tells if instantiated variable is a list 
-  note that not all [A|B] are lists - only if B is a list ! 
-  how is is_list defined ? 
        is_list([]). 
        is_list( [A | B] ) :- is_list(B).
    
     meaningless for uninstantiated variable 
    
     -  1) use var predicate 
-  2) use weaker test, e.g. is_list([]).  is_list([_,_]). (but some non-lists will pass) 
member
    -  defined in the following way: 
-  this is better than defining 
     -  member(X, [Y | _ ] :- X=Y. 
-  member(X, [_ | Y]) :- member(X,Y). 
last
      last(X,[X]).   
      last(X,[_|Y) :- last(X,Y).
   
    append can often be used instead 
   
    -  last(L,List) := append(_,[L],List). 
-  member(M,List) :- append(_,[M|_], List). 
recursion
  -  basic tools in AI languages such as PROLOG and LISP 
-  need to ensure termination (easy for lists and the cut) 
-  first example 
   -  is_integer:  is_integer(0). 
-  is_integer(X) :- is_integer(Y), X is Y+1. 
-  answers are  0; 1; 2; 3 ... 
-  classic exmaple of recursion is factorial 
     factorial(1,1).
     factorial(N,R) :- N>1, N1 is N-1, factorial(N1,Tmp), R is N*Tmp.
   
    need N>1 to terminate the recursion 
    more elegant with cut 
   
     factorial(1,1) :- !.
     factorial(N,R) :- N1 is N-1, factorial(N1,Tmp), R is N*Tmp.
   
     
   Hanoi rings puzzle 
  
       hanoi(N) :- move(N,left,center,right).
       move(0,_,_,_) :- !.
       move(N,A,B,C) :- M is N-1, move(M,A,C,B), print(‘move a disc from ‘, A, ‘ to ‘, B), nl, move(M,C,B,A).
  
   recursion is often used with lists 
  
    printlist([]).
    printlist([H|T]) :- print(H),printlist(T).
  
   bad recursions 
  
       parent(X,Y) :- child(Y,X).  
       child(A,B) :- parent(B,A).
   
    left recursion (fix by reversing order in rule) 
   
        person(X) :- person(Y), parent(Y,X).  
        person(adam).  
    
  
   some particularly useful recursions 
  
    -  repeat 
-  defined as repeat :- repeat. 
-  e.g. get0(C) :- repeat, get(X), X>32, !. 
Wumpus world in Prolog (agent part, need simulator also)
   can_enter(X,Y) :- not_wumpus(X,Y), not_pit(X,Y).
   not_wumpus(X,Y) :- not(stench(X1,Y1)), adjacent(X,Y,X1,Y1).   and same for not_pit 
   adjacent(X,Y,X1,Y1) :- X1is X-1, Y1 is Y.  
   adjacent(X,Y,X1,Y1) :- X1 is X+1, Y1 is Y.  etc.
   pickup_gold(X,Y) :- glitter(X,Y).  
   climb_out(X,Y) :- X=1, Y=1, have_gold.
   forward(X,Y) :- angle=0, X is X=1, update(X,Y).  update is simulator function
 
 
 
