[net.lang.prolog] PROLOG Digest V4 #36

PROLOG-REQUEST@SU-SCORE.ARPA (Chuck Restivo, The Moderator) (08/12/86)

PROLOG Digest            Tuesday, 12 Aug 1986      Volume 4 : Issue 36

Today's Topics:
                  Implementation - Manipulating ->,
                  Puzzle - Farmer & Extension Tables
----------------------------------------------------------------------

Date: Sun 10 Aug 86 14:04:09-PDT
From: Fernando Pereira <PEREIRA@SRI-CANDIDE.ARPA>
Subject: Manipulating Programs With ->

To be honest I can't remember any substantial discussion on
this topic back when -> was added to the DEC-10 interpreter,
but looking back into it I see a very good reason. The
alternatives of a disjunction are like the alternative
clauses of a disjunction, -> is like cut in one of those
clauses. Thus

        p :- a -> b; c.

is equivalent to

        p :- q.

        q :- a, !, b.
        q :- c.

If -> had the higher precedence, the most obvious interpretation
would be

        q :- a, !, r.

        r :- b.
        r :- c.

which is clearly useless. The argument becomes even more compelling
if one thinks about the intended interpretation of goals like

        (a -> b;
         c;
         d -> f;
         g)


-- F

------------------------------

Date: 11 Aug 1986 11:10-EST
From: Saumya Debray <debray%suny-sbcs@csnet-relay>
Subject: Manipulating Programs With ->

I agree with you regarding the parse of "P -> Q ; R",
_if_ we're to understand -> in terms of cut.  I'd
prefer not to have to do that as far as possible --
for one thing, understanding program behaviour in the
presence of cuts isn't always straightforward, and
for another, cuts can invalidate program transformations
that one would like to have hold (e.g. "hard" cuts
invalidate unfold transformations; "soft" cuts as in

-> can invalidate "clause factoring" transformations,
as in the example I gave earlier).

I guess I'd much rather deal with a distfix ->/3, which
I find more intuitive.

-Saumya Debray

[recall; Much of this ground has been covered in prehistoric Digest 
 exchanges.  Reconsulting the Archives might be in order. -ed]

------------------------------

Date: 11 Aug 1986 11:17-EST
From: Suzanne Dietrich <suzanne%suny-sb@csnet-relay>
Subject: Farmer Puzzle and Extension Tables

I agree with Ed Windes:

>- First, I don't think your 'linked' procedure is doing what it
>should.  Seems to me that the query 'linked(state(1,1,1,1),X).'
>should produce four distinct alternatives.

The alternatives are:

        1) farmer takes the fox
        2) farmer takes the goose
        3) farmer takes the grain
        4) farmer takes only himself across

Also, I think there may be a typo in the 'linked' procedure.

>linked(state(F1,X1,G1,A1),state(F2,X2,G2,A2)) :-same(no,F1,F2),
>
>(same(yes,X1,X2);(same(yes,F1,X1),same(yes,G1,G2),same(yes,A1,A2))),
>(same(yes,G1,A2);(same(yes,F1,G1),same(yes,X1,X2),same(yes,A1,A2))),

---------------------^    Should this be G2?
>(same(yes,A1,A2);(same(yes,F1,A1),same(yes,G1,G2),same(yes,X1,X2))).


Ed Windes also suggests:

>- Second, you need to rewrite your 'path' procedure because
>A) it is left-recursive, and B) you need to keep a record of
>states already visited, and exclude them from the possible
>next states.

The path procedure as written is logically correct. Unfortunately,
Prolog enters an infinite loop on this program due to the points
A and B above.

Consider another solution to the Farmer Program (of unknown
origin):

-----------------------------------------------------------
/* state(Farmer,Fox,Goose,Grain) */

state(n,n,n,n).         /* Initial state */
state(X,X,U,V):-        /* Farmer takes Fox */
        safe(X,X,U,V),opp(X,X1),state(X1,X1,U,V).
state(X,Y,X,V):-        /* Farmer takes Goose */
        safe(X,Y,X,V),opp(X,X1),state(X1,Y,X1,V).
state(X,Y,U,X):-        /* Farmer takes Grain */
        safe(X,Y,U,X),opp(X,X1),state(X1,Y,U,X1).
state(X,Y,U,V):-        /* Farmer goes by himself */
        safe(X,Y,U,V),opp(X,X1),state(X1,Y,U,V).

/* North(n) and South(s) are opposite shores */
opp(n,s).
opp(s,n).

/* safe(Farmer,Fox,Goose,Grain) */

safe(X,Y,X,V).                  /* Farmer is with Goose */
safe(X,X,X1,X):-opp(X,X1).      /* Farmer is not with Goose */

/*       QUERY: state(s,s,s,s).         */
-----------------------------------------------------------------

This program also suffers from an infinite loop due to revisiting
of states. David S. Warren and I have developed an algorithm which
evaluates most simple recursive programs (including left-recursion).
The method, known as extension tables, applies the dynamic
programming principle to computation in which previous results are
saved and later reused to avoid recomputation. The algorithm, called
the ET algorithm, is a simple source-to-source transformation on a
Prolog program.  The latter farmer program is successfully executed
with an ET saved on the predicate state/4. I also used the ET
algorithm on the predicate path/2 in the former Farmer program (with
the correction of A2 to G2) and the query succeeded.

Here is the ET transformation for the predicate state/4:

1]  Define a predicate  code_state/4 to have the original
    definition for state

code_state(n,n,n,n).            /* Initial state */
code_state(X,X,U,V):-           /* Farmer takes Fox */
        safe(X,X,U,V),opp(X,X1),state(X1,X1,U,V).
code_state(X,Y,X,V):-           /* Farmer takes Goose */
        safe(X,Y,X,V),opp(X,X1),state(X1,Y,X1,V).
code_state(X,Y,U,X):-           /* Farmer takes Grain */
        safe(X,Y,U,X),opp(X,X1),state(X1,Y,U,X1).
code_state(X,Y,U,V):-           /* Farmer goes by himself */
        safe(X,Y,U,V),opp(X,X1),state(X1,Y,U,V).

2]  Redefine the predicate state/4 to save calls and answers

state(X1,X2,X3,X4) :-
    call_state(Y1,Y2,Y3,Y4),              /* check for call */
    same(state(Y1,Y2,Y3,Y4),state(X1,X2,X3,X4)),!,
    et_state(X1,X2,X3,X4).                /* use et answers */
state(X1,X2,X3,X4) :-
    assert(call_state(X1,X2,X3,X4)),      /*    save call   */
    code_state(X1,X2,X3,X4),              /* compute answer */
    not(et_state(Y1,Y2,Y3,Y4),
        same(state(Y1,Y2,Y3,Y4),state(X1,X2,X3,X4))),
    assert(et_state(X1,X2,X3,X4)).        /*   save answer  */

Note:   The predicate same/2 identifies two terms to be the same
        if they are identical upon renaming of variables.
        A predicate subsumes/2 can be used instead of same/2:
        if there was a previous call to p(X,Y) and p(X,b) is
        called, then the answers for p(X,b) are a selection of
        the answers for p(X,Y) so a table lookup can be used.

The ET algorithm is not complete for Datalog (function-free
Prolog). This simple facility, which modifies Prolog's top-down
left-to-right depth-first evaluation strategy, executes and
terminates evaluation on many programs for which Prolog's
evaluation enters an infinite  loop.  The ET* algorithm, which
is complete for Datalog, iterates  using the ET algorithm until
no new answers are produced.

------------------------------

End of PROLOG Digest
********************