Subject: Re: [SWIPL] Logic Puzzle Solver (fwd) again

From: "Richard A. O'Keefe" <[email-masked]>
Date: Wed, 9 May 2001 12:52:32 +1200 (NZST)

Concerning the 'puzzle' program, which was said to work in Quintus Prolog.

1.  When consulting the file into Quintus Prolog release 3.4,
    I get a _lot_ of Singleton variable warnings.

2.  When I call test_puzzle(test, X) I get the response
    | ?- test_puzzle(test, X).
    ! Existence error in write_ln/1
    ! procedure user:write_ln/1 does not exist
    ! goal:  write_ln(_9387)
    which tells me that the code posted is NOT the code that ran under
    Quintus Prolog.

3.  After adding the definition write_ln(Term) :- write(Term), nl.
    I called test_puzzle(test, X) again.  This time I got
    | ?- test_puzzle(test, X).
    _9712
    ! Instantiation error in argument 2 of is/2
    ! goal:  _9472 is _9475+1
    which is presumably the same error that SWI Prolog found.

    test_puzzle calls
        solve_puzzle calls
            solve calls itself recursively and then calls
                (house(...,green),house(...,ivory),
		 houseposition(...,V1),houseposition(...,V2),
                 write_ln(V1), V2 is V1+1)

    from which it is clear that the calls to houseposition(..,..) were
    expected to bind their second argument, but did not do so.
                
    Indeed, looking at the preceding clues (this is number 5) it is
    clear that none of them can possibly have bound these variables.

4.  I rewrote nextto/2 and added nextafter/2.

nextto(X, Y) :-                
    (   integer(X), integer(Y) -> abs(X-Y) = 1
    ;   integer(X) -> (Y is X+1, Y =< 5 ; Y is X-1, Y >= 1)
    ;   integer(Y) -> (X is Y-1, X >= 1 ; X is Y+1, X =< 5)
    ;   between(1, 4, X), Y is X+1
    ;   between(2, 5, Y), X is Y-1
    ).

nextafter(X, Y) :-
    (   integer(X) -> Y is X+1, Y =< 5
    ;   integer(Y) -> X is Y-1, X >= 1
    ;   between(1, 4, X), Y is X+1
    ).

    I changed the 'is' in the clue so that the fifth clue reads

        (house(Man1Clue5,green),house(Man2Clue5,ivory),
         houseposition(Man1Clue5,A),houseposition(Man2Clue5,B),
         nextafter(A, B), write(A), nl),

    Loaded in a couple of libraries (because between/3 and member/2
    are library predicates in Quintus Prolog), and then found that
    drink/2 is not defined.  Changed the call to drink/2 to call
    drinks/2 (which is defined) instead.  Finally got the output

| ?- test_puzzle(test,X).
1

X = [[_10019,' owns the zebra'],[_10019,' drinks water']] 

Actually, there are lots more answers, all with unbound variables.

	>This same program ran under Quintus Prolog on a RISC 6000.

I don't believe this, because the program that was posted does NOT
run under Quintus Prolog on a SPARC.

	Seems there is a problem in your program.  SICStus gave the
	same error.  I managed to track it down to the write_ln, that
	indicates A is unbound.  I'll use this program to improve the
	debugger as it was quite hard to find this.  No clue why Quintus
	answered it without error.
	
Quintus didn't answer it without error, but DID make it easy to find in
the debugger.

Here is a cleaned-up version of the code without any run-time exceptions,
but it still doesn't yield the right answers.

next_to(X, Y) :-
    (   integer(X), integer(Y) -> abs(X - Y) = 1
    ;   integer(X) -> ( Y is X + 1, Y =< 5 ; Y is X - 1, Y >= 1 )
    ;   integer(Y) -> ( X is Y - 1, X >= 1 ; X is Y + 1, X =< 5 )
    ;   between(1, 4, X), Y is X + 1
    ;   between(2, 5, Y), X is Y - 1
    ).

next_after(X, Y) :-
    (   integer(X) -> Y is X + 1, Y =< 5
    ;   integer(Y) -> X is Y - 1, X >= 1
    ;   between(1, 4, X), Y is X + 1
    ).

solve_puzzle(puzzle(Clues,Queries,Solution), Solution) :-
    solve(Clues),
    solve(Queries).

solve([]).
solve([Clue|Clues]) :-
    call(Clue),
    solve(Clues).

test_puzzle(Name, Solution) :-
    structure(Name, Structure),
    clues(Name, Structure, Clues),
    queries(Name, Structure, Queries, Solution),
    solve_puzzle(puzzle(Clues,Queries,Solution), Solution).

structure(test, [
	man(1,_Colour1,_Nationality1,_Pet1,_Drink1,_Smoke1),
	man(2,_Colour2,_Nationality2,_Pet2,_Drink2,_Smoke2),
	man(3,_Colour3,_Nationality3,_Pet3,_Drink3,_Smoke3),
	man(4,_Colour4,_Nationality4,_Pet4,_Drink4,_Smoke4),
	man(5,_Colour5,_Nationality5,_Pet5,_Drink5,_Smoke5)
    ]).

house_position(man(H,_,_,_,_,_), H).
house(         man(_,C,_,_,_,_), C).
nationality(   man(_,_,N,_,_,_), N).
pet(           man(_,_,_,P,_,_), P).
drinks(        man(_,_,_,_,D,_), D).
smokes(        man(_,_,_,_,_,S), S).

clues(test, _Man, [
    (	house(Man1Clue1, red),
	nationality(Man1Clue1, english)		),
    (	nationality(Man1Clue2, spanish), 
	pet(Man1Clue2, dog)			),
    (	house(Man1Clue3, green),
	drinks(Man1Clue3, coffee)		),
    (	nationality(Man1Clue4, ukrainian),
	drinks(Man1Clue4, tea)			),
    (	house(Man1Clue5, green),
	house(Man2Clue5, ivory),
	house_position(Man1Clue5, A),
	house_position(Man2Clue5, B),
	next_after(A, B), write(A), nl		),
    (	smokes(Man1Clue6, winston),
	pet(Man1Clue6, snails)			),
    (	house(Man1Clue7, yellow),
	smokes(Man1Clue7, kools)			),
    (	drinks(Man1Clue8, milk),
	house_position(Man1Clue8, 3)		),
    (	nationality(Man1Clue9, norwegian),
	house_position(Man1Clue9, 1)		),
    (	smokes(Man1Clue10, chesterfields),
	pet(Man2Clue10, fox),
	house_position(Man1Clue10, P),
	house_position(Man2Clue10, Q),
	next_to(P, Q)				),
    (	smokes(Man1Clue11, kools),
	pet(Man2Clue11, horse),
	house_position(Man1Clue11, R),
	house_position(Man2Clue11, S),
	next_to(R, S)				),
    (	smokes(Man1Clue12, luckystrike),
	drinks(Man1Clue12, orangejuice)		),
    (	nationality(Man1Clue13, japanese),
	smokes(Man1Clue13, parliaments)		),
    (	nationality(Man1Clue14, norwegian),
	house(Man2Clue14, blue),
	house_position(Man1Clue14, I),
	house_position(Man2Clue14, J),
	next_to(I, J)				)]).

queries(test, Man,
    [	member(Q1, Man), nationality(Q1, N1), pet(Q1, zebra),
	member(Q2, Man), nationality(Q2, N2), drinks(Q2, water)],
    [	pet(N1,zebra), drinks(N2,water) ]).