23
Prolog OR (disjunction) “;” is same as a logical OR It is also equivalent to using separate clauses... parent(X, Y) :- mother(X, Y). parent(X, Y) :- father(X, Y). SAME AS... parent(X, Y) :- mother(X, Y) ; father(X, Y). Although this saves writing some code, both versions are equivalent in efficiency. 1 COSC 2P93 Prolog: Cut

Prolog OR (disjunction)

Embed Size (px)

DESCRIPTION

Prolog OR (disjunction). “;” is same as a logical OR It is also equivalent to using separate clauses... parent(X, Y) :- mother(X, Y). parent(X, Y) :- father(X, Y). SAME AS... parent(X, Y) :- mother(X, Y) ; father(X, Y). - PowerPoint PPT Presentation

Citation preview

Page 1: Prolog OR (disjunction)

Prolog OR (disjunction)

“;” is same as a logical OR It is also equivalent to using separate clauses...

parent(X, Y) :- mother(X, Y).

parent(X, Y) :- father(X, Y).

SAME AS...

parent(X, Y) :-

mother(X, Y)

;

father(X, Y).

Although this saves writing some code, both versions are equivalent in efficiency.

1COSC 2P93 Prolog: Cut

Page 2: Prolog OR (disjunction)

Be careful with “;”!

What is going on here?

p(X) :-

(q(X, Y) ; (r(Y), (s(U, Y); a(U), b(U)) ; r(X)),

t(X, Y); w(X) ; z(A),z(B),

etc...

Too many or’s can make programs very hard to debug (trace)! Rule of thumb: Don’t use or’s in order to reduce number of clauses.

2COSC 2P93 Prolog: Cut

Page 3: Prolog OR (disjunction)

Controlling Prolog execution

Prolog exhaustively searches the computation tree for solutions If a goal fails, OR the user inputs ‘;’ at the prompt, then backtracking

reverts to the last place in which a clause was chosen, and tries the next.

There are lots of advantages of this scheme, most notably, searching for a solution, or multiple solutions, to a query.

However, it can be expensive: Sometimes there is only one solution, and it is a waste of time

searching for others -- they don’t exist! Sometimes ‘failure’ after the first solution can take lots of time to infer Memory resources are used to contain the computation tree for

backtracking. Prolog permits some user control of execution, in order to reduce

backtracking.

3COSC 2P93 Prolog: Cut

Page 4: Prolog OR (disjunction)

1. If-then-else

(If -> Then ; Else)

If goals in If are true, then do Then; else do Else Once Then is executed, will go to Then or Else, but cannot

backtrack from Then to Else, nor back to If. Backtracking will return multiple solutions in Then, and in Else.

(If -> Then)

This is equivalent to: (If -> Then ; fail)

4COSC 2P93 Prolog: Cut

Page 5: Prolog OR (disjunction)

Example If-then-else

If N is prime, return ‘prime’, Else ‘notprime’.

idNum(N, prime) :-

prime(N).

idNum(N, notprime) :-

\+ prime(N).

Note that prime/N is called twice – with identical results! Prime testing might be very slow for large integers, so this is very

wasteful.

5COSC 2P93 Prolog: Cut

Page 6: Prolog OR (disjunction)

Example if-then-else

filterNum(N, Ans) :-

(prime(N) ->

Ans = prime

;

Ans = notprime).

Here, prime/1 is called once. No backtracking into it.

6COSC 2P93 Prolog: Cut

Page 7: Prolog OR (disjunction)

2. once

Often, we want just one solution from a predicate. Multiple answers may slow execution, due to needless

backtracking.

once(Goal): This calls Goal, and returns first solution. Backtracking will immediately fail. Built-in to Sicstus Prolog.

7COSC 2P93 Prolog: Cut

Page 8: Prolog OR (disjunction)

Example of once/1

% delete(A, L, R): Delete A from L, resulting in R.

delete(A, [A|T], T).

delete(A, [B|T], [B|T2]) :-

delete(A, T, T2).

delete(_, [ ], [ ]).

?- delete(a, [a,b,a,c,a],L).

L = [b,a,c,a] ? ;

L = [a,b,c,a] ? ;

L = [a,b,a,c] ? ;

L = [a,b,a,c,a] ? ;

?- once( delete(a, [a,b,a,c,a],L) ).

L = [b,a,c,a] ? ;

no

8COSC 2P93 Prolog: Cut

Page 9: Prolog OR (disjunction)

3. The cut, !

The cut takes the form of a goal in a clause. Should use only one cut per clause. A predicate can have one or more clauses with cuts.

Scheme:

1. all the clauses before the first clause with a cut are executed with normal backtracking.

2. if the goals before the cut fail, the cut does not activate, and the subsequent clause is used, as normal.

3. if the goals before the cut succeed, the cut activates:a) backtracking back to goals before the cut cannot occur

b) backtracking to subsequent clauses after the one with the cut cannot occur --> that clause with the activated cut is “committed”

c) the goals after the cut are executed with normal backtracking

9COSC 2P93 Prolog: Cut

Page 10: Prolog OR (disjunction)

The cut - example

p(1). %1

p(2). %2

p(Y) :- q(3, Z), !, r(Z, Y). %3

p(4). %4

q(2, 4). r(5, 6).

q(3, 5). r(5, 7).

Clauses 1, 2 are executed as normal In 3, the goal q(3,Z) executes; if it succeeds, then the ! is activated, and

the goal r is executed as normal. However, in activating this cut...

clause 4 will not execute for this particular execution call clause 3 will not backtrack to q again (in this goal inference)

Note that backtracking in r(Z,Y) occurs as expected, and hence you can still get multiple solutions from clause 3

10COSC 2P93 Prolog: Cut

Page 11: Prolog OR (disjunction)

Green and red cuts

There are two usages of cuts:

(i) Green cuts (GOOD): cuts that prune execution branches that do not lead to useful solutions.

(ii) Red cuts (BAD): cuts that prune valid solutions

11COSC 2P93 Prolog: Cut

Page 12: Prolog OR (disjunction)

Example: green cut

% A list is bad if: (1) it is empty; (2) it has more than 100 items; or (3) it has an integer.

test_list(L) :-

test_if_bad(L),

!,

write(‘Bad list,’), nl, fail. % print message and fail

test_list(L) :-

write(‘Good list’), nl. % print message and succeed

test_if_bad([ ]).

test_if_bad(L) :- length(L, N), N > 100.

test_if_bad(L) :- member(X, L), integer(X).

a “green cut”, because we know that only one of test_list clauses must succeed to say a list is bad.

backtracking makes no sense with it.

12COSC 2P93 Prolog: Cut

Page 13: Prolog OR (disjunction)

Green cut

Note that we could do the same with if-then-else...

test_list(L) :-

(test_if_bad(L) ->

write(‘Bad list,’), nl,

fail

; write(‘Good list’), nl ).

13COSC 2P93 Prolog: Cut

Page 14: Prolog OR (disjunction)

Example: red cut

A bad use of cut...

parent(P, C) :- father(P, C), !.

parent(P, C) :- mother(P, C).

father(bob, sue).

father(bob, kim).

mother(mary, sue).

mother(mary, kim).

A red cut: we get the first solution from father, and never give another valid solution again, from either father or mother!

?- parent(A, B).

A = bob, B = sue ;

no.

14COSC 2P93 Prolog: Cut

Page 15: Prolog OR (disjunction)

Red cut

Variation:

parent(P, C) :- !, father(P, C).

parent(P, C) :- mother(P, C).

(rest as before)

?- parent(A, B).

A = bob, B = sue ;

A = bob, B = kim ;

no

Same as...

parent(P, C) :- father(P, C).

15COSC 2P93 : Cut

Page 16: Prolog OR (disjunction)

Implementation: If-then-else

If-then-else is implemented with a cut:

P :- (If ->

Then

;

Else).

Same as...

P :- If,

!,

Then.

P :- Else.

16COSC 2P93 Prolog: Cut

Page 17: Prolog OR (disjunction)

Implementation: once/1

once(P) :-

call(P),

!

or...

once(P) :-

P,

!.

This is a “meta-logical” call. Usually built into Prolog.

17COSC 2P93 Prolog: Cut

Page 18: Prolog OR (disjunction)

More cut examples

Example: a deterministic member/2: memberd/2 deterministic clause: one that returns one solution per call

member(A, [A|_).

member(A, [_|R]) :- member(A, R).

memberd(A, [A|_]) :- !.

memberd(A, [_ | R]) :- memberd(A, R).

Here, as soon as memberd clause 1 finds a match, it succeeds Subsequent backtracking to memberd then fails, due to the cut

we prevent memberd clause 2 from finding another match

Note: memberd same as... ?- once(member(X,Y)).

18COSC 2P93 Prolog: Cut

Page 19: Prolog OR (disjunction)

Cut examples

Example: sum the integers between 1 and n

sum_to(1, 1) :- !.

sum_to(N, Sum) :-

M is N - 1,

sum_to(M, Tmp),

Sum is Tmp + N.

Without the cut, backtracking proceeds to sum_to(0,_), sum_to(-1,...) etc with the cut, when the case sum_to(1,1) occurs, backtracking will not

commence (via clause 2) again, a green cut: only one solution desired BUT... simply checking size of N in 2nd clause will prevent need for a cut...

19COSC 2P93 Prolog: Cut

Page 20: Prolog OR (disjunction)

Take out the cut...

sum_to(1, 1).

sum_to(N, Sum) :-

N > 1,

M is N - 1,

sum_to(M, Tmp),

Sum is Tmp + N.

20COSC 2P93 Prolog: Cut

Page 21: Prolog OR (disjunction)

Cuts Cuts are extralogical: they almost always destroy a program’s

logical “declarative” reading. Consider test_list example again...

test_list(L) :-

test_if_bad(L),

!,

write(‘Bad list,’), nl, fail.

test_list(L) :-

write(‘Good list’), nl.

Read literally, the second clause says that all lists are good lists! Hence we must now ascertain the meaning of this predicate by

inspecting what the cut is doing. The second clause’s meaning is dependent upon the first clause.

21COSC 2P93 Prolog: Cut

Page 22: Prolog OR (disjunction)

Cuts

Cuts are unavoidable in many programs. Without them, the program can become too large and inefficient

However, cuts usually ruin a logic program’s readability

Careless use of cuts can make a Prolog program unintelligible, and hard to debug.

22COSC 2P93 Prolog: Cut

Page 23: Prolog OR (disjunction)

When to use cuts

1. Try to make a declarative predicate if feasible: correct, concise, efficient.

2. Else, use “->” (if-then-else) or once/1 if they help.

3. Else, use a cut if it is a green cut.

4. Red cut: use as rarely as possible. Document their function!

23COSC 2P93 Prolog: Cut