1 prolog. 2 why ai programming languages? prolog keeps us away from the machine search algorithms...
TRANSCRIPT
11
PrologProlog
22
Why AI Programming Languages?Why AI Programming Languages?
PrologProlog Keeps us away from the machineKeeps us away from the machine Search algorithms are built into the Search algorithms are built into the
languagelanguage Clearly defined semantics since it’s based Clearly defined semantics since it’s based
on FOPLon FOPL Easily extendable—necessary since AI Easily extendable—necessary since AI
programming is exploratoryprogramming is exploratory Basic unit is the ruleBasic unit is the rule
– Scope of variables restricted to a single ruleScope of variables restricted to a single rule– Modifications are simplifiedModifications are simplified
33
Task in PrologTask in Prolog
Describe the problem in terms of its Describe the problem in terms of its logical constraintslogical constraints
That is, tell the computer what is trueThat is, tell the computer what is true Pattern search then looks for a Pattern search then looks for a
solutionsolution
44
HistoryHistory
Grew out of work on theorem proving Grew out of work on theorem proving using resolution refutationusing resolution refutation
Invented in France in the early 70’s Invented in France in the early 70’s as part of work on NLPas part of work on NLP
Standard Prolog is called Clocksin Standard Prolog is called Clocksin and Mellishand Mellish
Developed in the AI lab at the Developed in the AI lab at the University of Edinburgh in late 70’sUniversity of Edinburgh in late 70’s
55
Problems with FOPLProblems with FOPL
No control structureNo control structure Not guaranteed to haltNot guaranteed to halt CNF is difficult to work withCNF is difficult to work withEX:EX:V X (~rain(X) ^ sunny(X) V X (~rain(X) ^ sunny(X)
blue_sky(X))blue_sky(X))becomes in CNFbecomes in CNFrain(X) V ~sunny(X) V blue_sky(X)rain(X) V ~sunny(X) V blue_sky(X)
66
Horn ClausesHorn Clauses
Horn Clauses joined with a depth-first Horn Clauses joined with a depth-first search, backtracking regimen search, backtracking regimen answers all objectionsanswers all objections
Def Horn DatabaseDef Horn DatabaseA database is horn if it is equivalent to set A database is horn if it is equivalent to set
of sentences of the form:of sentences of the form:aa1 1 ^ … ^^ … ^ aam m b b
Where b is a single positive predicateWhere b is a single positive predicaterain(X) ^ cold(X) rain(X) ^ cold(X) cloudy(X) cloudy(X)
77
Properties of Horn ClausesProperties of Horn Clauses Most T/F knowledge we have about the world can Most T/F knowledge we have about the world can
be described in horn formbe described in horn formJohn is a lawyer or a waiterJohn is a lawyer or a waiter~lawyer(john) ~lawyer(john) waiter(john) waiter(john)
Horn DB have attractive computational propertiesHorn DB have attractive computational properties– In a horn DB, the time needed to determine whether or In a horn DB, the time needed to determine whether or
not a particular item follows is O(N*D) not a particular item follows is O(N*D) – where N is the maximum number of premises in any rule where N is the maximum number of premises in any rule
and D is the number of rules in the databaseand D is the number of rules in the database– Modus Ponens is capable of finding every valid Modus Ponens is capable of finding every valid
consequence in a horn DBconsequence in a horn DB The truth of P and P -> Q is allows us to infer the truth of QThe truth of P and P -> Q is allows us to infer the truth of Q
88
A Prolog program is a horn A Prolog program is a horn database with these modificationsdatabase with these modifications
a a b is written b:- a b is written b:- a a ^ b a ^ b c is written c :- a, b. c is written c :- a, b. ~a ^ b ~a ^ b c is written c :- ~a, b. c is written c :- ~a, b. Facts are entered like this: prof(paul)Facts are entered like this: prof(paul)
99
Universal QuantifiersUniversal Quantifiers
All prolog variables are assumed to All prolog variables are assumed to be universally quantifiedbe universally quantified
1010
Existential QuantifiersExistential Quantifiers
Case 1: The value the existentially Case 1: The value the existentially quantified variable is knownquantified variable is known– likes(paul,simcha) is an instance oflikes(paul,simcha) is an instance of
V X(likes(paul,X))V X(likes(paul,X))
i.e., there exists X (likes(paul,X))i.e., there exists X (likes(paul,X))
So likes(paul,simcha) may be entered So likes(paul,simcha) may be entered directlydirectly
1111
Case 2: Ask Prolog to find a value Case 2: Ask Prolog to find a value that makes the expression truethat makes the expression true
-likes(paul, X)-likes(paul, X)
Prolog will determine whether a value Prolog will determine whether a value of X exists under which the of X exists under which the expression is true.expression is true.
1212
Closed World AssumptionClosed World Assumption
Anything is false whose opposite is not provably trueAnything is false whose opposite is not provably trueIf you query the DB and your query cannot be proved true, If you query the DB and your query cannot be proved true,
then your query is assumed to be false.then your query is assumed to be false.Suppose we have these predicates in the db:Suppose we have these predicates in the db:likes(paul,simcha)likes(paul,simcha)likes(paul,binky)likes(paul,binky)
If we askIf we asklikes(paul,skiing)likes(paul,skiing)
Prolog responds “no”Prolog responds “no”
So, all knowledge for a particular universe of discourse is in So, all knowledge for a particular universe of discourse is in the DB. If something is not in the DB, that something is the DB. If something is not in the DB, that something is false.false.
1313
Prolog CommandsProlog Commands To start prolog, type gTo start prolog, type gprologprolog: $gprolog : $gprolog To get out: type To get out: type halthalt: :
?- halt.?- halt. To enter a db you’ve created in a fileTo enter a db you’ve created in a file
– Store the db with an extension pl (pgm1.pl)Store the db with an extension pl (pgm1.pl)– type type consult(pgm1):consult(pgm1):
?- consult(pgm1).?- consult(pgm1). To see the current DB, type To see the current DB, type listing:listing:
?- listing.?- listing. To trace execution, type trace:To trace execution, type trace:
?-trace.?-trace. To turn off tracing, type notrace:To turn off tracing, type notrace:
?- notrace.?- notrace.
1414
ListsLists
A list is an ordered collection of elements, consisting of:A list is an ordered collection of elements, consisting of: Head – the first element in the listHead – the first element in the list Tail – everything else which is a, possibly empty, listTail – everything else which is a, possibly empty, list Syntax: [a|b,c,d]Syntax: [a|b,c,d]
– Head = aHead = a– Tail = [b,c,d]Tail = [b,c,d]
Elements in a list are enclosed w/in brackets: [b,c,d]Elements in a list are enclosed w/in brackets: [b,c,d] Head can be separated from tail with |Head can be separated from tail with |
[a|b,c,d][a|b,c,d] _ in H or T position means we don’t care about it:_ in H or T position means we don’t care about it:
[a|_][a|_]
1515
Member CheckingMember Checking
An element is a member of a list ifAn element is a member of a list if
1.1. It is the head of the listIt is the head of the list
2.2. It is a member of the tailIt is a member of the tail But an element is a member of the tailBut an element is a member of the tail
If it is the head of the tailIf it is the head of the tail If it is a member of the tail of the tailIf it is a member of the tail of the tail
……
1616
More PreciselyMore Precisely
mem(A, [A|_).mem(A, [A|_).
mem(A, [_|Tail) :- mem(A,Tail).mem(A, [_|Tail) :- mem(A,Tail).
1717
TraceTrace
Mem(a,[c,b,a])
R1--FMem(a,[b,a])
R1--F Mem(a,[a])
R1--TT
T
T
1818
Displaying a ListDisplaying a List
1.1. Display the headDisplay the head2.2. Display the head of the tailDisplay the head of the tail3.3. Display the head of the tail of the tailDisplay the head of the tail of the tail4.4. ……5.5. Continue this process until the list is Continue this process until the list is
emptyempty
write(arg) : displays argwrite(arg) : displays argwrite(nl) : causes carriage return/new linewrite(nl) : causes carriage return/new line
1919
More PreciselyMore Precisely
writelist([]).writelist([]).
writelist([H|T]) :- write(H), nl, writelist([H|T]) :- write(H), nl, writelist(T).writelist(T).
2020
TraceTracewritelist([a,b,c]).writelist([a,b,c]).R1-FR1-FR2R2
write(a)write(a) aawrite(nl)write(nl) newlinenewlinewritelist([b,c])writelist([b,c])R1-FR1-FR2R2
write(b) write(b) bbwrite(nl)write(nl) newlinenewlinewritelist([c])writelist([c])R1-FR1-FR2R2 write(c)write(c) cc write(nl)write(nl) newlinenewline writelist([])writelist([]) R1-TR1-T
TT TTTT
2121
Reversing Elements in a ListReversing Elements in a List
reverse(L,R)reverse(L,R)
1.1. Pop items from LPop items from L
2.2. Push them onto an empty listPush them onto an empty list
3.3. When L is empty all items will be on When L is empty all items will be on the buffer list in reverse orderthe buffer list in reverse order
4.4. Copy buffer list to RCopy buffer list to R
2222
More PreciselyMore Precisely
rev(L,R) :- rev1(L, [], R).rev(L,R) :- rev1(L, [], R).
rev1([], Temp, Temp).rev1([], Temp, Temp).
rev1([H|T], Temp, R) :- rev1(T,[H|Temp], R).rev1([H|T], Temp, R) :- rev1(T,[H|Temp], R).
2323
TraceTrace
rev([a,b,c],R)rev([a,b,c],R) rev1([a,b,c], [], R)rev1([a,b,c], [], R)
R1-FR1-Frev1([b,c], [a|[]], R)rev1([b,c], [a|[]], R) R1-FR1-F
rev1([c], [b|a], R)rev1([c], [b|a], R) R1-FR1-F rev1([], [c|b,a], R)rev1([], [c|b,a], R)
R1-T {[c,b,a]/R}R1-T {[c,b,a]/R} T {[c,b,a]/R}T {[c,b,a]/R} T {[c,b,a]/R}T {[c,b,a]/R} T {[c,b,a]/R}T {[c,b,a]/R} T {[c,b,a]/R}T {[c,b,a]/R}T {[c,b,a]/R}T {[c,b,a]/R}
2424
Writing Out a List in ReverseWriting Out a List in Reverse
Reverse the ListReverse the List
Then Write it outThen Write it out
2525
More PreciselyMore Precisely
rev_write1(L) :- rev(L,R), writelist(R).rev_write1(L) :- rev(L,R), writelist(R).
2626
Elegant, but there’s a problemElegant, but there’s a problem
Requires two recursive callsRequires two recursive calls
2727
SolutiionSolutiion
Take advantage of the fact that reverse Take advantage of the fact that reverse unwinds the list and gives access to the unwinds the list and gives access to the head at every level. At the bottom level is head at every level. At the bottom level is the last item in the list:the last item in the list:
rev(L,R) :- rev1(L, [], R).rev(L,R) :- rev1(L, [], R).rev1([], Temp, Temp).rev1([], Temp, Temp).rev1([H|T], Temp, R) :- rev1(T,[H|Temp], R).rev1([H|T], Temp, R) :- rev1(T,[H|Temp], R).
And the single clause, write(H), to the last premiseAnd the single clause, write(H), to the last premiseGiving:Giving:rev_write2(L,R) :- work(L, [], R).rev_write2(L,R) :- work(L, [], R).work([], Temp, Temp).work([], Temp, Temp).work([H|T], Temp, R) :- work(T,[H|Temp], R), write(H).work([H|T], Temp, R) :- work(T,[H|Temp], R), write(H).
2828
But notice that we don’t use RBut notice that we don’t use R
Leads to:Leads to:
rev_write3(L) :- work(L, []).rev_write3(L) :- work(L, []).
work([], Temp, Temp).work([], Temp, Temp).
work([H|T], Temp) :- work(T,[H|Temp]), nl, work([H|T], Temp) :- work(T,[H|Temp]), nl, write(H).write(H).
What Else?What Else?
2929
We don’t need to push the head We don’t need to push the head onto the stack. onto the stack.
This eliminates the need for a separate clause This eliminates the need for a separate clause containing the empty list as an argument.containing the empty list as an argument.
rev_write4([]).rev_write4([]).
rev_write4([H|T]) :- rev_write4(T), nl, write(H).rev_write4([H|T]) :- rev_write4(T), nl, write(H).
3030
TraceTracerev_write4([a,b,c])rev_write4([a,b,c])
R1-FR1-F rev_write4([b,c])rev_write4([b,c])
R1-FR1-F rev_write4([c])rev_write4([c])
R1-FR1-F rev_write4([])rev_write4([])
R1-TR1-Tnlnlwrite(c)write(c)
TT nlnl write(b)write(b)TTnlnlwrite(a)write(a)
TTTT
3131
Appending one list to anotherAppending one list to another
TechniqueTechnique
1.1. Pick up list 1Pick up list 1
2.2. Slide list 2 under itSlide list 2 under it
3.3. Put list 1 downPut list 1 down
append(L1, L2, Result).append(L1, L2, Result).
3232
Rule 1: Base CaseRule 1: Base Case
If list 1 is empty, unification copies list If list 1 is empty, unification copies list 2 to Result2 to Result
append([], L2, L2). append([], L2, L2).
3333
Rule 2: RecursionRule 2: Recursion
If list 1 has at least 1 itemIf list 1 has at least 1 item
1.1. Copy head of list 1 to head of Result on Copy head of list 1 to head of Result on LHSLHS
2.2. Pop head from list 1 on RHSPop head from list 1 on RHS
3.3. Eventually, list 1 will be empty. R1 will Eventually, list 1 will be empty. R1 will succeed and Result on the RHS holds list succeed and Result on the RHS holds list 2. As recursion unwinds, the elements of 2. As recursion unwinds, the elements of list 1 appear at the front of list 2 on the list 1 appear at the front of list 2 on the RHS in reverse order.RHS in reverse order.
3434
AppendAppend
app([], L, L).app([], L, L).
app(H|T, L2, [H|R]) :- app(T, L2, R).app(H|T, L2, [H|R]) :- app(T, L2, R).
3535
TraceTrace
app([a,b], [c,d], R) {[a,b,c,d]/R}app([a,b], [c,d], R) {[a,b,c,d]/R}
R1-F app([a,b],[c,d], [a|R]R1-F app([a,b],[c,d], [a|R]
ifif app([b],[c,d],R) {[b,c,d]/R}app([b],[c,d],R) {[b,c,d]/R}
R1-F app([b],[c,d],[b|R])R1-F app([b],[c,d],[b|R])
ifif app([],[c,d],R)app([],[c,d],R)
R1-T {[c,d]/R}R1-T {[c,d]/R}
3636
Length of a ListLength of a List
Suppose N is a number and X is a variableSuppose N is a number and X is a variableThen “X is N + 1” causes X to be bound to Then “X is N + 1” causes X to be bound to
the value of N + 1the value of N + 1TechniqueTechnique BasisBasis
– Length of list with no elements is 0Length of list with no elements is 0– Len([],0)Len([],0)
Recursive stepRecursive step– Length of a non-empty list is the length of its Length of a non-empty list is the length of its
tail + 1tail + 1– Len([H|T],L) :- len(T, Lt), L is Lt + 1.Len([H|T],L) :- len(T, Lt), L is Lt + 1.
3737
TraceTrace
len([a,b,c],L)len([a,b,c],L)R1-FR1-F len([a|b,c], L)len([a|b,c], L) ifif len([b,c],Lt), L is Lt + 1len([b,c],Lt), L is Lt + 1R1-F len(b,c],L) {2/Lt}R1-F len(b,c],L) {2/Lt} ifif len([c], Lt), L is Lt + 1 {1/Lt}len([c], Lt), L is Lt + 1 {1/Lt}R1-F len([c],L)R1-F len([c],L) ifif len([],Lt), L is Lt + 1 {1/L}len([],Lt), L is Lt + 1 {1/L}R1-T {0/Lt}R1-T {0/Lt}
3838
StackStack
The data structure used is the listThe data structure used is the list
3939
Two Data Structures in PrologTwo Data Structures in Prolog
StacksStacks QueuesQueues
4040
EmptyEmpty
A stack is empty if the list is the A stack is empty if the list is the empty listempty list
empty([])empty([])
4141
PushPush
Argument 1 is the element to be Argument 1 is the element to be pushedpushed
Argument 2 is the stackArgument 2 is the stack Argument 3 is the new stackArgument 3 is the new stack push(Top, Stack, [Top|Stack])push(Top, Stack, [Top|Stack])
4242
PopPop
Same as push, but this time the Same as push, but this time the second argument is the new stacksecond argument is the new stack
pop(Top, Stack, [Top|Stack])pop(Top, Stack, [Top|Stack])
4343
TopTop
Here we don’t care about the tailHere we don’t care about the tail top(Top, [Top|_])top(Top, [Top|_])
4444
isInisIn
We can use our member programWe can use our member program isIn(Elt,Stack) :- mem(Elt,Stack)isIn(Elt,Stack) :- mem(Elt,Stack)
4545
Write (Reverse)Write (Reverse)
TechniqueTechnique– Pop the stack repeatedly until the stack Pop the stack repeatedly until the stack
is emptyis empty– Then begin to write out the elements, Then begin to write out the elements,
effectively from bottom to topeffectively from bottom to top
4646
write_r(Stack) :- empty(Stack).write_r(Stack) :- empty(Stack).
write_r(Stack) :- pop(Top,Rest,Stack),write_r(Stack) :- pop(Top,Rest,Stack),
write_r(Rest),write_r(Rest),
write(Top),write(Top),
nl.nl.
4747
QueueQueue
A little harder since we have to A little harder since we have to traverse the underlying list either for traverse the underlying list either for enqueue or for serve. enqueue or for serve.
We’ll traverse for enqueueWe’ll traverse for enqueue
4848
Empty, isIn, and serve are identical Empty, isIn, and serve are identical to empty, isIn, and pop for stackto empty, isIn, and pop for stack
empty([]).empty([]). isIn(Elt,Stack) :- mem(Elt,Stack)isIn(Elt,Stack) :- mem(Elt,Stack) serve(Top, Stack, [Top|Stack])serve(Top, Stack, [Top|Stack])
4949
EnqueueEnqueue
Necessary to recursively traverse the listNecessary to recursively traverse the list If the queue is empty, the enqueued If the queue is empty, the enqueued
element is the queueelement is the queue– enqueue(Elt, [], [Elt]).enqueue(Elt, [], [Elt]).
Else pick up the stack, item by item, slide Else pick up the stack, item by item, slide in the new element and replace the stackin the new element and replace the stack– enqueue(Elt, [H|T], [H|Tnew]) :-enqueue(Elt, [H|T], [H|Tnew]) :-
enqueue(Elt, T, Tnew).enqueue(Elt, T, Tnew).
5050
Writing the Queue is easyWriting the Queue is easy
writeQ(Queue) :- empty(Queue).writeQ(Queue) :- empty(Queue).
writeQ(Queue) :- writeQ(Queue) :- serve(Top,Rest,Queue),serve(Top,Rest,Queue),
writeQ(Top), nl, writeQ(Rest),nl.writeQ(Top), nl, writeQ(Rest),nl.
5151
Recursion without listsRecursion without listsThe Ancestor ProblemThe Ancestor Problem
Basis: person A is the ancestor of person Basis: person A is the ancestor of person B, if person A is the parent of person B.B, if person A is the parent of person B.– ancestor(A,B) :- parent(A,B).ancestor(A,B) :- parent(A,B).
Recursive Step: Person A is the ancestor of Recursive Step: Person A is the ancestor of person C, if person A is the ancestor of person C, if person A is the ancestor of person B and person B is the ancestor of person B and person B is the ancestor of person Cperson C– ancestor(A,C) :- parent(A,B), ancestor(B,C).ancestor(A,C) :- parent(A,B), ancestor(B,C).
5252
Adding facts to our family treeAdding facts to our family tree
parent(marguerite,paul).parent(marguerite,paul). parent(eleanora,marguerite).parent(eleanora,marguerite). parent(anna,eleanora).parent(anna,eleanora). Etc.Etc.