Lesson 10

advertisement
Lecture 10
Logic programming,
PROLOG
(PROgramming in LOGic)
Logic programming
 The
method of pure logic programming is a
special restricted case of the general resolution
method. There are two principle constraints:
Prolog works only with Horn clauses that
contain at most one positive literal;
 Prolog applies the linear strategy for the
generation of resolvents;

 This
linear strategy is combined with
backtracking
2
Prolog notation & terminology

Rules (conditional statements): P:- Q1, Q2,..,Qn.




Facts (unconditional statements): P.


This is a clause without negative literals.
Goals (questions): ?- Q1, Q2,..,Qn.


Gloss: P, if Q1 and Q2 and … Qn
Note that this is equivalent to these formulas:
(Q1  Q2  …  Qn  P)  (Q1  Q2  …  Qn)  P
The former is a clause with one positive literal.
Note that this is equivalent to the clause without a positive literal:
Q1  Q2  …  Qn
Empty clause:

, YES: success, the goals have been met
Remark: Unlike in the FOL language, variables are written as
beginning with upper-case letters, other predicates and terms with
lower-case letters.
3
Foundations of Prolog





A logic program is a sequence of conditional and unconditional statements, that
is rules and facts.
A procedure of a logic program is the set of rules and facts with the same head
(positive literal).
The goal clauses represent questions to which the program should answer. The
answer is YES, if a goal is entailed by the given set of statements, otherwise the
answer is NO.
Hence the way how to answer the questions (that is how to meet the goals) is a
matter of the program interpreter. It should decide whether the goals are entailed
by the given program knowledge base. Moreover, the interpreter is also able to
provide information about the values that yielded a positive answer. These
values are obtained by unification of literals.
Note. Logic program is a declarative rather than imperative specification of an
algorithm.

In this sense we should understand the notion of a statement. It is simply a logical
formula.
 We specify what to do rather than how to do it.
For details see, e.g.,
http://www.ling.helsinki.fi/kit/2004k/ctl272/Bangor/clbook_9.html
4
Prolog & Horn clauses
Prolog works with the language of clauses
restricted to Horn clauses.
Example: “All members of a sport club are skiers or
rock climbers”.
Problem. The consequent is in the form of
disjunction:
x [SC(x)  (SKI(x)  CLIMB(x))] 
x [SC(x)  SKI(x)  CLIMB(x)]
This statement/rule cannot be specified in the form
of a Horn clause; there are two positive literals.
5
Example: sport club



1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
Tom, Peter and John are members of a sport club. Every member of the
club is a skier or a climber. No climber likes raining. All skiers like
snow. Peter does not like what Tom likes, and does like what Tom does
not like. Tom likes snow and raining.
Question: Is there in the club a sportsman who is a climber but
not a skier?
Knowledge base (+ query 11):
SC(t)
SC(p)
SC(j)
x [ SC(x)  (SKI(x)  CLIMB(x)) ] problem: 2 pozitive literals
x [ CLIMB(x)  LIKE(x,r) ]
x [ SKI(x)  LIKE(x,s)]
x [LIKE(t,x)  LIKE(p,x)]
x [LIKE(t,x)  LIKE(p,x)]
LIKE(t,s)
LIKE(t,r)
? x [SC(x)  CLIMB(x)  SKI(x)]
Example: sport club

This problem is easily solvable in the
general resolution method of FOL.
 Try

to do it as a homework
However, its specification in Prolog is not
possible in a direct way.
Prolog constraints (summary)
1.
2.
At most one positive literal (Horn clauses)
We cannot directly express negative facts
Negation = fail of deduction;
Prolog’s answer NO means this:
The answer to your question cannot be derived from the
program (knowledge base)
(The closed-world assumption)
3.
Prolog is a declarative language. Thus there are
only two possibilities how to affect program
execution:


The order of clauses in the program; the order of literals
in a clause
Predicate/Command ! (cut)
Example


All students are younger than Peter’s mother.
Tom and Anne are students.
Who is younger than Peter’s mother?
Formalisation in FOL:
intended interpretation
x [St(x)  Y(x, f(a))]
St  the set of students
St(b)
Y  relation of being younger;
St(c)
a  Peter; b  Tom; c  Anne; f  mother of …



 y Y(y, f(a)) ???
Program in Prolog:
younger(X, mother_of(peter)):- student(X).
student(tom).
student(anne).
?- younger(Y, mother_of(peter)).
rule
fact
fact
question/goal
Solution by general resolution
1.
St(x)  Y(x, f(a))
2.
St(b)
3.
St(c)
(y) Y(y, f(a))
Y(b, f(a))
4.
5.
6.
7.
8.
Y(c, f(a))
negated conclusion
rezolution 1,2; b/x
4,5 – YES (y = b)
rezolution 1,3; c/x
4,7 – YES (y = c)
Solution in Prolog
younger(X, mother_of(peter)):- student(X).
student(tom).
student(anne).
?- younger(Y, mother_of(peter)).
The interpreter takes care of unification and resolution; it applies goal-driven linear strategy
of program execution:
1)
The goal ?- younger(Y, mother_of(peter)) is unified with
younger(X, mother_of(peter)), Y=X;
2)
A new goal is generated: ?- student(Y)
3)
This goal is unified with the second fact; success: Y = tom
4)
Answer: YES, Y = tom;
Insertion of the semicolon (;) means that we ask „anybody else?“
This causes backtracking. The interpreter returns to the last goal and tries to meet it again:
?- student(Y).
The second clause cannot be used again. Hence the interpreter uses the third fact:
5)
The answer is again positive: YES, Y = anne;
(anybody else?)
NO
Note. Semicolon ‘;’ means logical disjunction or
comma ‘,’ means logical conjunction and
Example modified
1. younger(X, mother_of(peter)):- student(X).
2. student(tom).
3. student(anne).
4. younger(X, mother_of(peter)):- child(X, mother(peter)).
5. child(X,Y):-Y=mother_of(X).
?- younger(Y, mother_of(peter)).
question (goal)
a) YES, Y = tom;
b)
YES, Y = anne;
Anybody else? The answer is Y = peter.
(Peter is younger than his mother)
backtracking
younger(Y,mother_of(peter)
1
student(Y)
2
4
child(Y,mother_of(peter))
3
5
Yes
Yes
mother_of(peter)=mother_of(Y)
Y=tom;
Y=anne;
Y=peter;
No
Example continued
1. younger(X, mother_of(peter)):- student(X).
2. student(tom).
3. student(anne).
4. younger(X, mother_of(peter)):- child(X, mother(peter)).
5. child(X,Y):-Y=mother_of(X).
?- younger(Y, mother_of(peter)).
question (goal)
a)
YES, Y = tom;
b)
YES, Y = anne;
c)
Yes, Y = peter.
Now we ask another question:
?- student(peter).
Answer: NO
This does not mean that Peter actually is not a student. Rather, due to the closed-world
assumption it only means that the fact that Peter is a student is not entailed by the
given program.
Negation is a failure of deduction. We cannot directly insert negative facts to the program.
Negation in Prolog

If we want to express the fact that Marie is not a
student, we can use the predicate not:
not(student(marie)):call(student(marie)), !, fail.
not(student(marie)).

not(student(marie))
(semantics)
 call(student(marie)):
If the program entails that Marie is a
student then the call succeeds; another goal ! (cut) also
succeeds; but the predicate fail yields the answer NO.

 If
cut ! : no backtracking; „do not try again“, it is not true that Marie
is not a student.
call(student(marie)) fails then not(student(marie))
succeeds; it is true that Marie is not a student.
Example: Eukleides algorithm
In mathematics, the greatest common divisor (gcd), also known as the greatest
common factor (gcf), or highest common factor (hcf), of two or more non-zero
integers, is the largest positive integer that divides the numbers without a remainder.
For example, the GCD of 8 and 12 is 4.
1.
2.
3.
gcdX,X,X.
gcdX,Y,Z:- X>Y, gcdX-Y,Y,Z.
gcdX,Y,Z:- Y>X, gcdX,Y-X,Z.
Note. Prolog has built in basic arithmetic.
4.
?- gcd4,6,Z.
5.
Execution:
?- 4>6, gcd4-6,6,Z
resolution: 4,2.
4.
5.
6.
7.
8.
9.
?- gcd4,6,Z
?- 6>4, gcd4,6-4,Z
?- gcd4,2,Z
?- 4>2, gcd4-2,2,Z
?- gcd2,2,Z
yes, Z=2.
backtracking
resolution: 4,3.
fact "6>4“; hence calculate gcd4,2,Z
resolution: 6,2.
Calculating the clause 7, fact "4>2"
resolution: 8,1.
Calculating natural numbers
1. nat0.
0 is a natural number
2. nats(X):-nat(X). the successor of a natural number is a natural number
3. ?- nats(X).
Which are all the natural numbers?
Execution:
4. ?-natX
resolution 3,2.
5. YES, X = 0;
3. ?- nats(X)
backtracking
4. ?-nat(X)
resolution 3,5.
6. YES, X = s(0);
7. YES, X = s(s(0));
8. YES, X = s(s(s(0)));
and so on, ad infinity
......
Note. This program generates a potential infinity, not actual. Potentially, if we
had an infinite time at our disposal, we’d obtain all the naturals.
The order of clauses can change the execution
of a program due to the linear strategy
Program A:
1. parent(tom, marie).
2. parent(anne, marie).
3. descendant(X,Y):- ancestor(Y,X).
4. child(X,Y):- parent(Y,X).
5. ancestor(X,Y):- descendant(Y,X).
6. descendant(X,Y):- child(X,Y).
7. descendant(X,Y):- child(X,Z), descendant(Z,Y).
8. ?- descendant(marie,X).
Note. Prolog renames variables, if needed
Execution tree
descendant(marie,X)
3
ancestor(X,marie)
5
descendant(marie,X)
3
ancestor(X,marie)
etc. ....
6
child(marie,X)
4
parent(X,marie)
1
X=tom;
X=anne (2)
The program does not answer though there is a solution;
„first aid“: move the clauses 3, 5 down and cut them
off (!); “there is a cycle, it will be corrected later on”
„the first aid“ (carefully): cut !
Program B:
1. parent(tom, marie).
2. parent(anne,marie).
3. descendant(X,Y):- child(X,Y).
4. descendant(X,Y):- child(X,Z), descendant(Z,Y).
5. child(X,Y):- parent(Y,X).
6. descendant(X,Y):- !, ancestor(Y,X).
7. ancestor(X,Y):- !, descendant(Y,X).
8. ?- descendant(marie,X).
The order of literals
parent(tom, marie).
2.
parent(anne,marie).
3.
descendant(X,Y):- child(X,Y).
4.
descendant(X,Y):- descendant(X,Z), child(Z,Y).
5.
child(X,Y):- parent(Y,X).
6.
?- descendant(marie,W).
Execution: ?- child(marie,W), ?-parent(W,marie),
W=tom; W=anne; ?????  infinite cycle
After the second semicolon the program starts looping:
?-parent(W,marie), ?- child(marie,W),
?- descendant(marie,W),
?-descendant(marie,Z), ?- child(Z’,Z), ?descendant(marie,Z’), ?- child(Z,Z’), ?- child(Z’,Z’’), …
It suffices to change the order of literals in the clause 4.
1.
Correctly:
1.
2.
3.
4.
5.
6.
parent(tom, marie).
parent(anne,marie).
descendant(X,Y):- child(X,Y).
descendant(X,Y):- child(X,Z), descendant(Z,Y).
child(X,Y):- parent(Y,X).
?- descendant(marie,W).
Remedial tenet: first facts, then rules.
In the recursive rules, recursive predicate as the last one.
Recursive rules: the predicate of a consequent
(rule head) is applied again in the antecedent
(rule body)
These rules correspond to cycles in imperative languages
The function factorial:
x! = x × x – 1 × … × 1, 0! = 1
fact(0, Factorial, Factorial).
fact(Number,Help,Factorial) :P1 is Number – 1,
I1 is Help × Number,
fact(P1,I1,Factorial).
?- fact(3,1,X).
Execution:
fact(3,1,Factorial)
fact(2,3,Factorial)
fact(1,6,Factorial)
fact(0,6,Factorial)
YES, Factorial = 6
(Help = 1)
(Help = 3)
(Help = 6)
Goal-driven linear strategy of execution +
backtracking


Prolog interpreter examines the execution tree to the depth
and left-to-right;
This strategy is not complete; the problem can be left
unsolved though there is a solution. This is due to the fact
that the interpreter can get stuck in an infinite branch.
Reordering clauses and/or literals can solve the problem.
There are complete control strategies that examine the execution
tree to the width; all branches simultaneously. However, whereas
the above depth strategy needs only one stack (“LIFO” memory
structure), the width strategy needs for each execution branch
another stack  less effective
See, e.g.,
http://www.ling.helsinki.fi/kit/2004k/ctl272/Bangor/clbook_9.html


Prolog proof strategy



When a query has been typed, the interpreter searches for a head that matches
the (first) goal in the query (it tries to prove this goal before attempting to prove a
second goal, if there is one). If the goal matches a fact, it has been proven, and
the interpreter is finished with it. If it matches the head of a rule, each of the
terms in the body becomes a new goal that must be satisfied. The interpreter
does not finish until all goals have been satisfied by reaching the level of
matching a fact; if one of them does not, the whole query fails.
There are two cases where the interpreter might have to make a decision about
how to tackle a query which has nothing to do with the logic of the program. This
happens when there is more than one head which matches a goal, and when
the body of a rule consists of more than one clause.
Prolog's control strategy works as follows: in the former case, the first matching
clause in the files is tried first, and in the second case, the goals in a body are
attempted in the order they appear. It makes it possible to write programs such
that although a query can be proven by a program in principle, the interpreter
fails to do so. This can however to some extent be avoided by ordering the
clauses carefully in the program, and if required the programmer can write a
meta-interpeter which changes the proof strategy.
example

sibling_in_law(X, Y) :- married(X, Z), sibling(Z, Y).
sibling_in_law(X, Y) :- sibling(X, Z), married(Z, Y).

This program identifies two ways of being a sibling-in-law: assuming
that you correspond to the first argument of sibling_in_law, the
siblings of the person you are married to are your siblings in law (the
first case above), as are your siblings' spouses (second case). In
attempting to answer the query
?- sibling_in_law(owen, geraint).
there will be several points where the interpreter has to make a
choice. Firstly, there are two clauses whose heads match the initial
query (this corresponds to the OR of formal logic). Secondly (once
one rule has been selected), the two terms in the body are
separated by a comma which corresponds to logical conjunction, so
from a logical point of view, we could start with either.
Prolog's control strategy works as follows: in the former case, the
first matching clause in the files is tried first, and in the second case,
the goals in a body are attempted in the order they appear.


Example; incompleteness
1.
2.
3.
4.
Program
A:- E.
A:- B.
B:- C.
E:- D.
C.
D:- E.
?- A.
execution tree
A
1
2
E
B
4
3
D
C
6.
E 6
5
7.
D 4
Yes
8.
E 6
9.
…
There are two ways of computing the procedure A;
the first one does not yield the solution
5.
Clause cut: !
(compare with „go to“ in imperative languages)





Controls and restricts backtracking
It cuts off “branches that are not needed in this execution”
This goal is met only once; if we attempt backtracking over !, the
interpreter omits all the clauses of the procedure being executed
and goes back to the goal coming before the procedure
Red cut changes the declarative semantics of the
program; it should not be used (wrong programming
practice)
Green cut does not change the semantics; it is applied in
order to make the program more effective in these cases:
a)
b)
c)
Realization of „if, then, else“ (exclusive or)
Management of exceptions (errors)
In order to restrict seeking over large knowledge bases (when a
success is reached after the given number of attempts)
„if, then, else“ by means of „fail“
Repeat:
If the temperature is high (more than 30%), then switch off
heating, else if the temperature is low (less than 15%),
then switch on heating, else don’t do anything.
thermostat(Action) :
temperature(X),
action(X,Action),
write(‘Do’, Action), nl,
fail.
% fail yields backtraching
action(X,’switch-on’) :X < 15, !.
action(X,’switch-off’) :X > 30, !.
action(X,’don’t do anything’).
?- thermostat(X).
„if, then, else“ by means of „fail“
thermostat(Action) :temperature(X),
action(X,Action),
write(‘Do’, Action), nl,
fail.
% fail yields backtraching
action(X,’switch-on’) :X < 15, !.
action(X,’switch-off’) :X > 30, !.
action(X,’don’t do anything’).
?- thermostat(X).
Possible actions: switch on, switch off, don’t do anything
Without cut the possible instructions would be like this:
switch on, don’t do anything, switch off, don’t do anything, don’t do
anything, …
“if, then, else“
action(X,’switch-on’) :X < 15.
action(X,’swithch-off’) :X > 30.
action(X,’noting’) :not(X < 15), not(X > 30).
 Less effective; we keep testing the condition
Exceptions, errors
test(X) :X = error, !, fail.
test(X) :write(‘valid:’, X).
If there is an error then the cut lets fail be applied;
the test fails. However, backtracking to the second
clause is blocked. The execution returns to the
clause preceding the first test.
 Equivalent, less effective but more comprehensible
program:
test(X) :
not(X = error),
write(‘valid:’, X).
Data structure list

List is a potentially infinite ordered n-tuple.
 [fish,


tortoise, crab, octopus, …]
Notation: [Head|Body], where Head is an element
of the list and Body is again a list.
Empty list [ ].

Procedure member (mostly built-in) tests whether the
first argument is an element of the list
member(X,[X|_]). X is an element if it is the head
member(X,[_|Y]) :- member(X,Y). else check body

Procedure append (two lists)
append([ ],L,L).
append([H,T],L,[H,T1]) :- append(T,L,T1).
Download