Title: logic
1Dave Reed
- Prolog programming
- unification/matching
- programs as deductive databases
- resolution, goal reduction
- declarative vs. procedural readings
- code tracing
- lists
2Prolog exercise
- recall a Prolog program is a collection of facts
rules that define relations about objects
0
1
- write Prolog facts rules that capture the
properties of these blocks - constants? predicates?
2
4
3
5
- use Prolog to show that
- there is a small block on top of a large block
- block 4 is above block 5
- there is a blue block above another blue block
- there is nothing above a green block
3Prolog unification
- when variables are present, inference requires
finding appropriate matches between facts rules
- i.e., must Universally Instantiate variables so
that facts rules match - mother(M, C) - parent(M, C), female(M).
- ?- mother(laura, charlie).
- ? requires instance
- mother(laura,charlie) - parent(laura,charlie),
female(laura). - ?- mother(laura, jack).
- ? requires instance
- mother(laura,jack) - parent(laura,jack),
female(laura).
- unification is an algorithm for determining the
variable instantiations needed to make
expressions match - query mother(laura, charlie)
- rule conclusion mother(M, C)
- these expressions unify/match with the variable
instantiations - M laura, C charlie
4Prolog unification
- Prolog's unification algorithm (for matching
expressions t1 and t2) - if t1 and t2 are constants, then they match if
they are the same object - if t1 is a variable, then they match with t1
instantiated to t2 (i.e., t1 t2) - if t1 and t2 are function/predicate expressions,
then they match if - they have the same function/predicate symbol, AND
- all of their arguments match (simultaneously)
- foo(you) foo(you) match since identical
- foo(X) foo(you) match, with X you
- foo(X) foo(Y) match, with X Y
- bar(X,b) bar(a,Y) match, with X a, Y b
- bar(X,f(X)) bar(a,f(a)) match, with X a
- foo(X) boo(X) no match, with foo ? boo
5Prolog programs as databases
- matching/unification alone can provide for
computation - consider a database of facts about movies at a
video store
- to see if Bull Durham is available
- ?- movie(_,title('Bull Durham'),_,_,_).
- Yes
- to find all comedies
- ?- movie(type(comedy),title(T),_,_,_).
- T 'My Man Godfrey'
- T 'Bull Durham'
- No
- to find movies starring costner
- ?- movie(_,title(T),year(Y),
- actors(kevinCostner,_),_).
- T 'Dances with Wolves'
movies.pro Dave Reed 1/25/02
movie(type(comedy),
title('My Man Godfrey'), year(1936),
actors(williamPowell,caroleLombard),
director(gregoryLaCava)). movie(type(drama),
title('Dances with Wolves'), year(1990),
actors(kevinCostner,maryMcDonnell),
director(kevinCostner)). movie(type(comedy),
title('Bull Durham'), year(1988),
actors(kevinCostner,susanSarandon),
director(ronShelton)).
'_' is the anonymous variable, matches anything
(but not reported)
6Deductive databases
- but Prolog databases also allow for deduction
- can define new relations that require computation
- ?- costars(M, F).
- M williamPowell
- F caroleLombard
- M kevinCostner
- F maryMcDonnell
- Yes
- ?- versatile(Who).
- Who kevinCostner
- Yes
- ?- modern(Who).
- Who kevinCostner
movies.pro Dave Reed 1/25/02
movie info as
before costars(M,F) - movie(_,_,_,actors(M,F
),_). versatile(P) - movie(_,_,_,actors(
P,_),_), movie(_,_,_,_,director(P)). versatile
(P) - movie(_,_,_,actors(_,P),_),
movie(_,_,_,_,director(P)). modern(P) -
movie(_,_,year(Y),actors(P,_),_), Y gt
1990. modern(P) - movie(_,_,year(Y),actors(_,
P),_), Y gt 1990. modern(P) -
movie(_,_,year(Y),_,director(P)), Y gt 1990.
7Resolution
- the proof procedure for answering queries in
Prolog is known as resolution, or goal reduction - can think of a query as a goal (or sequence of
goals) to be solved or proven - can think of the rule H - B1, B2. as saying
- "to solve/prove goal H, solve/prove subgoal B1
and then subgoal B2 "
- to solve/prove goals G1, , Gn
- if n 0, then the answer is 'Yes'
- else
- find a fact or rule whose conclusion matches G1
(searching top-to-bottom) - if no match, the answer is 'No'
- rename variables so there is no overlap with goal
variables - replace G1 with the premises (rhs) of the rule
- if matched a fact, simply remove G1 from the
goal list - instantiate all goals according to the above
match - recursively solve the new goal list
- if successful, the answer is 'Yes' and report
all variable bindings - else BACKTRACK (go back to goals G1, , Gn and
try next fact/rule)
8Resolution example
?- father(F, charlie). matches the father
rule rename variables in the rule F1, C1 match
binds F F1, C1 charlie replace goal with
premises, apply binding ? ?- parent(F1,
charlie), male(F1). first goal matches the top
fact match binds F1 dave remove first goal,
apply binding ? ?- male(dave). goal matches
fact remove goal ? ?- no goals, SUCCESS answer
is the variable binding F F1 dave F
dave Yes
- parent(dave, charlie).
- parent(dave, jack).
- parent(laura, charlie).
- parent(laura, jack).
- male(dave).
- male(charlie).
- male(jack).
- female(laura).
- father(F, C) -
- parent(F, C), male(F).
- mother(M, C) -
- parent(M, C), female(M).
9Example with backtracking
?- mother(M, charlie). matches the mother
rule rename variables in the rule M1, C1 match
binds M M1, C1 charlie replace goal with
premises, apply binding ? ?- parent(M1,
charlie), female(M1). first goal matches the top
fact match binds M1 dave remove first goal,
apply binding ? ?- female(dave). no match,
FAILURE BACKTRACK to previous goal list ? ?-
parent(M1, charlie), female(M1). continue search
after top fact, matches next fact match binds M1
laura remove first goal, apply binding ? ?-
female(laura). matches fact, remove goal ? ?- no
goals, SUCCESS answer is the variable binding M
M1 laura M laura Yes
- parent(dave, charlie).
- parent(dave, jack).
- parent(laura, charlie).
- parent(laura, jack).
-
- male(dave).
- male(charlie).
- male(jack).
- female(laura).
- father(F, C) -
- parent(F, C), male(F).
- mother(M, C) -
- parent(M, C), female(M).
10Dual readings
- Prolog programs can be read procedurally
- H - B1, B2. "to solve H, solve B1 and B2"
- or declaratively
- H - B1, B2. B1 ? B2 ? H
- "H is true if B1 and B2 are true"
- under the declarative view
- programming is defining relations using a subset
of the predicate calculus - a goal G is true (follows logically from the
program) if - there is a fact that matches G, or
- there is an instance of a rule with conclusion G
whose premises are all true (recursively) - in short, Prolog computation is logical inference
? logic programming
11Declarative vs. procedural
- the declarative reading of programs is generally
more intuitive - easier to reason with (centuries of research in
logic) - static
- however, must keep the procedural reading in mind
- in reality, rule and premise ordering matters
- ancestor(A,P) - parent(A,P).
- ancestor(A,P) - parent(A,C), ancestor(C,P).
- is more efficient than
- ancestor(A,P) - parent(A,C), ancestor(C,P).
- ancestor(A,P) - parent(A,P).
- which is still better than
- ancestor(A,P) - ancestor(C,P), parent(A,C).
- ancestor(A,P) - parent(A,P).
12Ancestor tracing (1)
?- consult(family). family compiled 0.16 sec,
72 bytes ?- listing(ancestor). ancestor(A, B)
- parent(A, B). ancestor(A, B) -
parent(A, C), ancestor(C, B). ?-
trace. Yes trace ?- ancestor(Who, jack).
Call (6) ancestor(_G383, jack) ? creep Call
(7) parent(_G383, jack) ? creep Exit (7)
parent(dave, jack) ? creep Exit (6)
ancestor(dave, jack) ? creep Who dave Yes
- built-in predicates
- listing will display all facts relations
defining a predicate - trace will cause each inference step to be
displayed - in this case, an answer is found quickly since
the "simple" case is listed first
13Ancestor tracing (2)
?- listing(ancestor). ancestor(A, B) -
parent(A, C), ancestor(C, B). ancestor(A,
B) - parent(A, B). Yes ?-
trace. Yes trace ?- ancestor(Who, jack).
Call (7) ancestor(_G386, jack) ? creep Call
(8) parent(_G386, _G441) ? creep Exit (8)
parent(winnie, dave) ? creep Call (8)
ancestor(dave, jack) ? creep Call (9)
parent(dave, _G441) ? creep Exit (9)
parent(dave, charlie) ? creep Call (9)
ancestor(charlie, jack) ? creep Call (10)
parent(charlie, _G441) ? creep Fail (10)
parent(charlie, _G441) ? creep Redo (9)
ancestor(charlie, jack) ? creep Call (10)
parent(charlie, jack) ? creep Fail (10)
parent(charlie, jack) ? creep Fail (9)
ancestor(charlie, jack) ? creep Redo (9)
parent(dave, _G441) ? creep Exit (9)
parent(dave, jack) ? creep Call (9)
ancestor(jack, jack) ? creep Call (10)
parent(jack, _G441) ? creep Fail (10)
parent(jack, _G441) ? creep Redo (9)
ancestor(jack, jack) ? creep Call (10)
parent(jack, jack) ? creep Fail (10)
parent(jack, jack) ? creep Fail (9)
ancestor(jack, jack) ? creep Fail (9)
parent(dave, _G441) ? creep Redo (8)
ancestor(dave, jack) ? creep Call (9)
parent(dave, jack) ? creep Exit (9)
parent(dave, jack) ? creep Exit (8)
ancestor(dave, jack) ? creep Exit (7)
ancestor(winnie, jack) ? creep Who winnie Yes
- in this case, finding an answer requires
extensive backtracking - harder, recursive case is first
- leads to many dead ends
14Ancestor tracing (3)
?- listing(ancestor). ancestor(A, B) -
ancestor(C, B), parent(A, C). ancestor(A,
B) - parent(A, B). Yes ?-
trace. Yes trace ?- ancestor(Who, jack).
Call (7) ancestor(_G386, jack) ? creep Call
(8) ancestor(_G440, jack) ? creep Call (9)
ancestor(_G440, jack) ? creep Call (10)
ancestor(_G440, jack) ? creep Call (11)
ancestor(_G440, jack) ? creep Call (12)
ancestor(_G440, jack) ? creep Call (13)
ancestor(_G440, jack) ? creep Call (14)
ancestor(_G440, jack) ? creep Call (15)
ancestor(_G440, jack) ? creep Call (16)
ancestor(_G440, jack) ? creep Call (17)
ancestor(_G440, jack) ? creep . . .
- in this case, the initial recursive call leads to
an infinite loop - GENERAL ADVICE
- put simpler cases first (e.g., facts before
rules) - for recursive rules, put the recursive call last,
after previous inferences have constrained
variables
15Another example
connect.pro Dave Reed 2/5/02
road(a, b).
road(b, c). road(c, a). road(c, b).
road(c, d). road(d, e). road(e,
d). connected(City1, City2) - road(City1,
City2). connected(City1, City2) -
road(City1, City3), connected(City3, City2).
?- connected(a, c). Yes ?- connected(c,
a). Yes ?- connected(b, d). Yes ?-
connected(b, e). ERROR Out of local stack
16Prolog lists
- the most general data structure in Prolog is the
list - a list is a (possibly empty) sequence of items,
enclosed in -
- foo
- cityA, cityB, cityC
- for a non-empty list,
- we say the first item is the HEAD and the rest of
the list is the TAIL - foo ? HEAD foo, TAIL
- cityA, cityB, cityC ? HEAD cityA, TAIL
cityB, cityC - lists are useful flexible structures (also
central to LISP/Scheme)
17List notation
- notation for lists is syntactic sugar for
function expressions - the dot functor combines the HEAD and TAIL of a
list - foo ? .(foo, )
- cityA, cityB, cityC ? .(cityA, .(cityB,
.(cityC, )))
- the dot notation highlights the recursive nature
of lists - a list is either
- empty, OR
- a structure with a HEAD (an item) and a TAIL (a
list)
- in Prolog, can use either notation
- ?- a,b .(a, .(b, )).
- Yes
18List matching
since a list is really a function expression, can
access via matching
?- X,Y foo, bar. X foo Y
bar Yes ?- HT a, b, c. H a T b,
c Yes ?- H1,H2T a, b, c. H1 a H2
b T c Yes
- can match variables to specific list items
- can match variables to the HEAD and TAIL using
'' - can match variables to multiple items at the
front, then the TAIL
19List operations
- there are numerous predefined predicates for
operating on lists - member(X, L) X is a member of list L
- recursive definition X is a member of L if
either - X is the HEAD of L, OR
- X is a member of the TAIL of L
?- member(a, a, b, c). Yes ?- member(a, b,
a, c). Yes ?- member(a, b, c). No
member is predefined, but we could define it
ourselves if we had to member(X,
X_. member(X, _T) - member(X, T).
20Example revisited
connect.pro Dave Reed 2/5/02
road(a, b).
road(b, c). road(c, a). road(c, b).
road(c, d). road(d, e). road(e,
d). connected(City1, City2) -
pathConnected(City1, City2). pathConnected(Cit
y1_, City2) - road(City1,
City2). pathConnected(CityXRest, City2) -
road(CityX, CityY), not(member(CityY,Rest)),
pathConnected(CityY,CityXRest, City2).
- can add loop checking to the connected relation
- need to keep track of the path traveled so far
- at each step, make sure a city hasn't been
visited before adding it to path - here, code utilizes a help function with
(reversed) path so far as first arg - makes use of member to test if visited, built-in
not predicate to reverse
?- connected(b, e). Yes ?- connected(e, a). No