cs4026 formal models of computation part ii the logic model lecture 6 – arithmetic, fail and the...

Post on 28-Mar-2015

214 Views

Category:

Documents

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

CS4026Formal Models of

ComputationPart II

The Logic ModelLecture 6 – Arithmetic, fail and the

cut

formal models of computation 2

Arithmetic• Arithmetic expressions trees like any other

terms:

• Prolog does not treat arithmetic expressions differently, unless asked to do so.

• In order to evaluate arithmetic expressions we use the built-in “is”

?- X = 10 + (2 * 4).

X = 10 + (2 * 4) ?

yes

? -

X

4

10

+

2

*

?- X is 10 + (2 * 4).

X = 18 ?

yes

? -

formal models of computation 3

Arithmetic• The syntax of the built-in “is” is:

Variable is ArithmeticExpression• For instance:

Result is (10 * 7) NewRes is OldRes + 1

• Variables that appear on the expression– Must be instantiated when expression is

evaluated– Otherwise execution error!

• We can delay the evaluation until all variables have value:?- Exp = A + B, A = 3, B = 4, Res is Exp.A = 3,B = 4,Exp = 3 + 4Res = 7

formal models of computation 4

Evaluation in Haskell and Prolog• In Haskell, expressions are always evaluated

if they contribute to the final result. Terms stand for their results.

• In Prolog, every term stands for itself. Evaluation only happens when explicitly invoked by a built-in like “is”.

• Prolog functors (even arithmetic ones) are like Haskell constructors (e.g. :)

formal models of computation 5

Arithmetic: an Example• How can we find the size (no. elements) of a

list?• Simple recursive formulation:

– The number of elements of the empty list is zero– The number of elements of a list [X|Xs] is one

plus the number of elements of Xs.• Predicate length with 2 arguments:

– 1st argument is the list– 2nd argument is the size of the list

• For example:?- length([a,b,c,d],Length).Length = 4 ??- length([1,[2,3],4],L).L = 3 ??-

formal models of computation 6

Arithmetic: an Example• First attempt

length(L,S):- L = [], % if L is an empty list S = 0. % its length S is zerolength(L,S):- % otherwise L = [X|Xs], % if L is a list [X|Xs] S is 1 + length(Xs,S). % its length is 1 plus length of tail

length(L,S):- % S is the length of list L L = [], % if L is an empty list S = 0. % its length S is zerolength(L,S):- % otherwise L = [X|Xs], % if L is a list [X|Xs] S is 1 + length(Xs,S). % its length is 1 plus length of tail

Careful! Predicate calls are true or false!This expression does not make sense!

length(L,S):- % S is the length of list L L = [], % if L is an empty list S = 0. % its length S is zerolength(L,S):- % otherwise L = [X|Xs], % if L is a list [X|Xs] S is 1 + length(Xs,S). % its length is 1 plus length of tail

formal models of computation 7

Arithmetic: an Example• Second attempt

(Can you see what’s wrong?)

length(L,S):- % S is the length of list L L = [], % if L is an empty list S = 0. % its length S is zerolength(L,S):- % otherwise L = [X|Xs], % if L is a list [X|Xs] S is 1 + SXs, % length S is 1 plus length of tail length(Xs,SXs). % get the length SXs of tail Xs

length(L,S):- % S is the length of list L L = [], % if L is an empty list S = 0. % its length S is zerolength(L,S):- % otherwise L = [X|Xs], % if L is a list [X|Xs] S is 1 + SXs, % length S is 1 plus length of tail length(Xs,SXs). % get the length SXs of tail Xs

Careful! When this expression is evaluated, the value of SXs won’t yet exist!!

formal models of computation 8

Arithmetic: an Example• Third attempt:

• Simplified version:

length(L,S):- % S is the length of list L L = [], % if L is an empty list S = 0. % its length S is zerolength(L,S):- % otherwise L = [X|Xs], % if L is a list [X|Xs] length(Xs,SXs), % get the length SXs of its tail Xs S is 1 + SXs. % add 1 to the length of its tail

length([],0). % the empty list has length 0length([_|Xs],S):- % a non-empty list [_|Xs] has size S length(Xs,SXs), % get the length SXs of its tail Xs S is 1 + SXs. % add 1 to the length of its tail

length([],0). % the empty list has length 0length([_|Xs],S):- % a non-empty list [_|Xs] has size S length(Xs,SXs), % get the length SXs of its tail Xs S is 1 + SXs. % add 1 to the length of its tail

Anonymous variable, used as “place holder”. In this context, we don’t care what the value of the element is – we just want to count them!!

formal models of computation 9

Arithmetic: Summary• Arithmetic: via “is” built-in.• Some operators:

+, –, *, / (add, subtract, multiply, divide)// (integer division)mod (modulo)

• All variables on expression must have values, otherwise execution error!!

• Because of this restriction, we ought to bear in mind the order in which Prolog proves/executes the body of a clause (or a query).

formal models of computation 10

Failure-driven loops• Prolog offers a built-in predicate fail

which always fails:

• We can use this predicate to define a failure-driven loop, an alternative to recursion:

?- fail.

no

p(a).

p(b).

p(c).

loopFail:- % loopFail succeeds if

p(X), % we can prove p(X) and

write(X), % write the value of X and

nl, % skip a line.

fail. % fail and BACKTRACK!!

loopFail. % if no (more) answers, stop

formal models of computation 11

Failure-driven loops• Execution:

p(a).

p(b).

p(c).

loopFail:-

p(X),

write(X),

nl,

fail.

loopFail.

?- loopFail.

loopFail:-

p(X1),write(X1),nl,fail.

loopFail:-

p(X1),write(X1),nl,fail.

loopFail:-

p(X1),write(X1),nl,fail.

{X1/a}

loopFail:-

p(X1),write(X1),nl,fail.

{X1/a}

?- loopFail.

a

loopFail:-

p(X1),write(X1),nl,fail.

{X1/a} Backtrack!!

loopFail:-

p(X1),write(X1),nl,fail.

{X1/a} Backtracking skips over built-ins!!

loopFail:-

p(X1),write(X1),nl,fail.

loopFail:-

p(X1),write(X1),nl,fail.

{X1/b}

loopFail:-

p(X1),write(X1),nl,fail.

{X1/b}

loopFail:-

p(X1),write(X1),nl,fail.

{X1/b} Backtrack!!

loopFail:-

p(X1),write(X1),nl,fail.

loopFail:-

p(X1),write(X1),nl,fail.

{X1/c}

loopFail:-

p(X1),write(X1),nl,fail.

{X1/c}

loopFail:-

p(X1),write(X1),nl,fail.

{X1/c} Backtrack!!

loopFail:-

p(X1),write(X1),nl,fail.

No more values for p(X)!

loopFail.

?- loopFail.

a

b

?- loopFail.

a

b

c

?- loopFail.

a

b

c

yes

?-

formal models of computation 12

Controlling Backtracking via cuts (!)• Prolog’s backtracking mechanism may, in

some cases, lead to inefficiencies.• We can control backtracking via the built-in

“!”, called “cut”.• The “!” is used as an ordinary predicate, in

the body of the clause or query – it always succeeds!

• However, the “!” causes the execution to commit to the current clause and to the solutions (proofs) of the goals to its left.

• Example:p(A,B,C,D):- q(A), r(A,B), !, s(B,C),t(A,D).

formal models of computation 13

Controlling Backtracking via cuts (!)• Example:

p(a).

p(b).

p(c).

q(b,2).

q(c,3).

s(2).

s(3).

r(Y):- p(X),q(X,Y),!,s(Y).

?- r(Ans).

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).r(Y1):- p(X1),q(X1,Y1),!,s(Y1).r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/a}

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/a}

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/a} Fail!!Backtrack…

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/b}

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/b}

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/b,Y1/2}

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/b,Y1/2}

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/b,Y1/2}

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/b,Y1/2}?- r(Ans).

Ans = 2 ?

?- r(Ans).

Ans = 2 ? ; Force backtrack…

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/b,Y1/2}

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/b,Y1/2} No other proof for s(Y1)!

r(Y1):- p(X1),q(X1,Y1),!,s(Y1).

{X1/b,Y1/2} Cannot backtrack over “!”

?- r(Ans).

Ans = 2 ? ;

no

?-

Force backtrack…

formal models of computation 14

Commitment in Haskell and Prolog• In some ways, the Prolog cut (!) is similar in

spirit to a Haskell guard (|)– Both cause a commitment to the current

clause/case• But there are differences as well:

– Guards come before the critical tests, cuts come after

– Cuts also commit to choices made in subgoals on the left

• Let’s look at some ways in which the cut can be useful

formal models of computation 15

Avoiding unnecessary work with “!” • Example:

• Suppose– customer(X) picks out a customer from a

database sorted (decreasing order) by amount of money spent;

– eligiblePrize(X) checks if amount of money spent makes customer eligible to win a prize;

– If the best (first) customer does not qualify, why let Prolog try all the other 250000 customers with less money spent?

prize(X):- customer(X),eligiblePrize(X).

formal models of computation 16

Avoiding unnecessary work with “!” • Surely, this is a lot better:

• This new version saves 250000 unnecessary attempts!

• We can only add this cut because we know the first answer is the only one that is any good…

prize(X):- customer(X),!,eligiblePrize(X).

formal models of computation 17

Avoiding unnecessary work with “!” • Another type of case: “disjoint” cases

• In Prolog:

• Let’s try this:

if X < 3 then Y = 0.if X 3 and X < 6 then Y = 1.if X 6 then Y = 2.

?- range(1,Y), Y > 2.

range(X,0):- X < 3.

range(X,1):- X >= 3, X < 6.

range(X,2):- X >= 6.

range(X,0):- X < 3.

range(X,1):- X >= 3, X < 6.

range(X,2):- X >= 6.?- 1 < 3, 0 > 2.

?- 0 > 2.

Backtrack!

formal models of computation 18

Avoiding unnecessary work with “!” • Another (more concrete) case:

• In Prolog:

• Let’s try this:

if X < 3 then Y = 0.if X 3 and X < 6 then Y = 1.if X 6 then Y = 2.

?- range(1,Y), Y > 2.

range(X,0):- X < 3.

range(X,1):- X >= 3, X < 6.

range(X,2):- X >= 6.

range(X,0):- X < 3.

range(X,1):- X >= 3, X < 6.

range(X,2):- X >= 6.?- 1>=3, 1<6, 1 > 2.

Backtrack!

formal models of computation 19

Avoiding unnecessary work with “!” • Another (more concrete) case:

• In Prolog:

• Let’s try this:

if X < 3 then Y = 0.if X 3 and X < 6 then Y = 1.if X 6 then Y = 2.

?- range(1,Y), Y > 2.

range(X,0):- X < 3.

range(X,1):- X >= 3, X < 6.

range(X,2):- X >= 6.

range(X,0):- X < 3.

range(X,1):- X >= 3, X < 6.

range(X,2):- X >= 6.?- 1 >= 6, 2 > 2. Backtrack!

?- range(1,Y), Y > 2.

noFail!!

formal models of computation 20

Avoiding unnecessary work with “!” • The values of Y are mutually exclusive

– There is no point in trying different clauses!!– Let’s add cuts to reflect this:

• The previous query is:

?- range(1,Y), Y > 2.

range(X,0):- X < 3,!.

range(X,1):- X >= 3, X < 6,!.

range(X,2):- X >= 6. % no need to add a cut here!!

range(X,0):- X < 3,!.

range(X,1):- X >= 3, X < 6,!

range(X,2):- X >= 6.?- 1 < 3, 0 > 2.

?- 0 > 2. Backtrack!

?- range(1,Y), Y > 2.

noFail!!

formal models of computation 21

Cuts can be necessary: Avoiding bad loops• Example: build a list with decreasing

numbers countDown(0,[]).

countDown(N,[N|Ns]):-

NN is N – 1,

countDown(NN,Ns).

?- countDown(5,Nos).?- countDown(5,Nos).

Nos = [5,4,3,2,1] ?

?- countDown(5,Nos).

Nos = [5,4,3,2,1] ? ;

?- countDown(5,Nos).

Nos = [5,4,3,2,1] ? ;

?- countDown(5,Nos).

Nos = [5,4,3,2,1] ? ;

?- countDown(5,Nos).

Nos = [5,4,3,2,1] ? ;

LOOP!!

Cause: Being asked for more solutions, PROLOG will match countDown(0,[]) with the recursive rule. This will force it to compute countDown(-1,Ns), and so on until the stack overflows.

formal models of computation 22

Avoiding “bad” loops with cuts• Fixing the problem with a “!”:

countDown(0,[]):-

!.

countDown(N,[N|Ns]):-

NN is N – 1,

countDown(NN,Ns).

The new countDown on the left still has a problem: if we try?- countDown(-1,L).

The program would loop forever (actually, a stack overflow will stop it). Can you fix it?

Incidentally…

?- countDown(5,Nos).?- countDown(5,Nos).

Nos = [5,4,3,2,1] ?

?- countDown(5,Nos).

Nos = [5,4,3,2,1] ? ;

no

?-

formal models of computation 23

When to use cuts (!)• Cuts aren’t always necessary – don’t add

them “just in case”!! • There is usually no reason to add more than

one “!” on one clause.• There is no easy way to tell when to use cuts:

– You have seen some cases as guidelines…– Is the first answer enough? Do we need all

answers?– Is there a risk of an accidental loop?– Will backtracking allow clauses to be wrongly

used?• Ultimately, we (programmers) should be able

to decide where/if to add cuts…

formal models of computation 24

Cut-Fail Combination• We can combine “!” and “fail” to represent

exceptions:

– First clause defines when different fails– Second clause is an “else”, where all other cases

are dealt;– Notice the anonymous variables – they are not the

same!!

different(X,X):- !,fail.

different(_,_).

formal models of computation 25

Negation as Failure• The cut-fail combination allows us to define a

kind of logical negation:– not(Goal) is true if Goal is false

– Built-in call(Goal) attempts to prove Goal• For the in-house logicians:

– not(G) means “G cannot be proved”– not(G) does not mean “G can be proved false”– Can you tell these apart?

• This is called “negation as failure”– It is OK if we adopt the “closed world assumption”

not(G):- call(G),!,fail. % if G holds, then fail

not(_). % otherwise not(G) holds

formal models of computation 26

Declarative vs. Procedural Meanings• A Prolog program has two “meanings”

– Declarative: the logical relationships (i.e. the results)

– Procedural: the results and how they were computed

• Good Prolog programs:– Exploit the declarative side of logics

(relationships)– Take into account procedural aspects (efficiency).

• Declarative programs:– Allow for multiple answers and multiple uses of a

predicate (e.g., the member predicate)• Procedural programs:

– Single answers, single use of predicates

formal models of computation 27

Control in Logic Programming• In logic programming, you have to think

about control as well as logic:– To appropriately “time” arithmetic– To avoid loops– To avoid unnecessary backtracking

• The cut is an explicit control mechanism. The ordering of clauses and goals within clauses is less explicit but just as important

• But you also need to think about the logic!

top related