1 / 27

Formal Models of Computation Part II The Logic Model

Formal Models of Computation Part II The Logic Model. Lecture 6 – Arithmetic, fail and the cut. Arithmetic. X. +. *. 10. 2. 4. Arithmetic expressions trees like any other terms: Prolog does not treat arithmetic expressions differently, unless asked to do so.

evadne
Télécharger la présentation

Formal Models of Computation Part II The Logic Model

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Formal Models of ComputationPart IIThe Logic Model Lecture 6 – Arithmetic, fail and the cut

  2. Arithmetic X + * 10 2 4 • 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 is 10 + (2 * 4). X = 18 ? yes ? - formal models of computation

  3. Arithmetic • The syntax of the built-in “is” is: VariableisArithmeticExpression • 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 + 4 Res = 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 length(L,S):- % S is the length of list L L = [], % if L is an empty list S = 0. % its length S is zero length(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! • First attempt length(L,S):- % S is the length of list L L = [], % if L is an empty list S = 0. % its length S is zero length(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):- L = [], % if L is an empty list S = 0. % its length S is zero length(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 length(L,S):- % S is the length of list L L = [], % if L is an empty list S = 0. % its length S is zero length(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!! • 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 zero length(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 formal models of computation

  8. Arithmetic: an Example length([],0). % the empty list has length 0 length([_|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!! • 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 zero length(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 0 length([_|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 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 loopFail:- p(X1),write(X1),nl,fail. {X1/a} loopFail:- p(X1),write(X1),nl,fail. {X1/a} Backtrack!! Backtracking skips over built-ins!! loopFail:- p(X1),write(X1),nl,fail. {X1/b} Backtrack!! loopFail:- p(X1),write(X1),nl,fail. {X1/c} Backtrack!! • Execution: 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} p(a). p(b). p(c). loopFail:- p(X), write(X), nl, fail. loopFail. loopFail:- p(X1),write(X1),nl,fail. {X1/b} loopFail:- p(X1),write(X1),nl,fail. loopFail:- p(X1),write(X1),nl,fail. {X1/b} loopFail:- p(X1),write(X1),nl,fail. {X1/c} loopFail:- p(X1),write(X1),nl,fail. loopFail:- p(X1),write(X1),nl,fail. {X1/c} ?- loopFail. a b ?- loopFail. a b c yes ?- ?- loopFail. a ?- loopFail. ?- loopFail. a b c loopFail:- p(X1),write(X1),nl,fail. No more values for p(X)! loopFail. 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 (!) r(Y1):- p(X1),q(X1,Y1),!,s(Y1). {X1/a} Fail!!Backtrack… ?- r(Ans). Ans = 2 ? ; ?- r(Ans). Ans = 2 ? ; no ?- Force backtrack… Force backtrack… 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 “!” • 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(Y1):- p(X1),q(X1,Y1),!,s(Y1). {X1/a} 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). 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} 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(Ans). ?- r(Ans). Ans = 2 ? r(Y1):- p(X1),q(X1,Y1),!,s(Y1). {X1/b,Y1/2} 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 “!” ?- 0 > 2. Backtrack! • 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(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. ?- range(1,Y), Y > 2. ?- 1 < 3, 0 > 2. formal models of computation

  18. Avoiding unnecessary work with “!” ?- 1>=3, 1<6, 1 > 2. Backtrack! • 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(X,0):- X < 3. range(X,1):- X >= 3, X < 6. range(X,2):- X >= 6. ?- range(1,Y), Y > 2. range(X,0):- X < 3. range(X,1):- X >= 3, X < 6. range(X,2):- X >= 6. formal models of computation

  19. Avoiding unnecessary work with “!” ?- 1 >= 6, 2 > 2. Backtrack! ?- range(1,Y), Y > 2. no Fail!! • 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(X,0):- X < 3. range(X,1):- X >= 3, X < 6. range(X,2):- X >= 6. ?- range(1,Y), Y > 2. range(X,0):- X < 3. range(X,1):- X >= 3, X < 6. range(X,2):- X >= 6. formal models of computation

  20. Avoiding unnecessary work with “!” ?- 0 > 2. Backtrack! ?- range(1,Y), Y > 2. no Fail!! • 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(X,0):- X < 3,!. range(X,1):- X >= 3, X < 6,!. range(X,2):- X >= 6. % no need to add a cut here!! ?- range(1,Y), Y > 2. range(X,0):- X < 3,!. range(X,1):- X >= 3, X < 6,! range(X,2):- X >= 6. ?- 1 < 3, 0 > 2. 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 Incidentally… 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? • Fixing the problem with a “!”: 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] ? ; 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! formal models of computation

More Related