unexpected backtracking in simple prolog example - prolog

The following is a simple prolog program.
% parent facts
parent(john, jane).
parent(john, james).
parent(sally, jane).
parent(martha, sally).
parent(deirdre, martha).
% ancestor recursive definition
ancestor(X,Y) :- parent(X,Y).
ancestor(X,Y) :- parent(X,A), ancestor(A,Y).
Using SWI-Prolog, specifically swish.swi-prolog.org, the following simple query produces the correct answer true, but also appears to backtrack and then say false.
?- ancestor(john, jane).
true
false
This puzzles me, and is unexpected.
I tried tracing:
trace, ancestor(john, jane).
Call:ancestor(john,jane)
Call:parent(john,jane)
Exit:parent(john,jane)
Exit:ancestor(john,jane)
1true
Redo:parent(john,jane)
Fail:parent(john,jane)
Redo:ancestor(john,jane)
Call:parent(john,_696)
Exit:parent(john,jane)
Call:ancestor(jane,jane)
Call:parent(jane,jane)
Fail:parent(jane,jane)
Redo:ancestor(jane,jane)
Call:parent(jane,_698)
Fail:parent(jane,_698)
Fail:ancestor(jane,jane)
Redo:parent(john,_696)
Exit:parent(john,james)
Call:ancestor(james,jane)
Call:parent(james,jane)
Fail:parent(james,jane)
Redo:ancestor(james,jane)
Call:parent(james,_698)
Fail:parent(james,_698)
Fail:ancestor(james,jane)
Fail:ancestor(john,jane)
What puzzles me is that prolog seems to redo: parent(john, jane). Question: Why is this?
My own (admittedly student) understanding is that prolog will only backtrack to try additional values for variables unbound at query time. Here there are no variables in the first rule of the recursive definition that are unbound at query time: ancestor(X,Y) :- parent(X,Y).
I could understand prolog trying new values for the variables in the second rule of the recursive definition: ancestor(X,Y) :- parent(X,A), ancestor(A,Y). Here prolog could try new values for A.
UPDATE - I tried removing the recursive part of the definition:
ancestor(X,Y) :- parent(X,Y).
% ancestor(X,Y) :- parent(X,A), ancestor(A,Y).
The query still results in backtracking.
?- ancestor(john, jane).
true
false
.. although the trace is shorter.
trace, ancestor(john, jane).
Call:ancestor(john,jane)
Call:parent(john,jane)
Exit:parent(john,jane)
Exit:ancestor(john,jane)
1true
Redo:parent(john,jane)
Fail:parent(john,jane)
Fail:ancestor(john,jane)
false
This focusses on the unexpected behaviour more sharply. Why does prolog backtrack to a point which has no unbound variables?

This can be boiled down to:
parent(john, jane).
parent(john, james).
parent(sally, jane).
?- parent(john, jane).
true ;
false.
The choicepoint happens because there is no index on the combination of both arguments.
The easiest way to solve this is to use tabling, by adding to the code:
:- table parent/2.
:- table ancestor/2.
... which improves determinism.

Related

Expanding Prolog clauses without parameters

I am writing a program that transforms other programs by expanding predicates. I usually do this using clause/2, but it doesn't always expand a predicate if it has no parameters:
:- set_prolog_flag('double_quotes','chars').
:- initialization(main).
main :- clause(thing,C),writeln(C).
% this prints "true" instead of "A = 1"
thing :- A = 1.
Is it possible to expand predicates that have no parameters?
Some general remark: Note that this code is highly specific to SWI. In other systems which are ISO conforming you can only access definitions via clause/2, if that predicate happens to be dynamic.
For SWI, say listing. to see what is happening.
?- assert(( thing :- A = 1 )).
true.
?- listing(thing).
:- dynamic thing/0.
thing.
true.
?- assert(( thing :- p(A) = p(1) )).
true.
?- assert(( thing(X) :- Y = 2 )).
true.
?- listing(thing).
:- dynamic thing/0.
thing.
thing :-
p(_)=p(1).
:- dynamic thing/1.
thing(_).
true.
It all looks like some tiny source level optimization.

Need help Converting to Prolog rule

Everybody likes a job if it's fun and it pays
we=>likes(X, Job):-fun(Job), pay_well(Job).
Not sure if it's correct and if it matters that I put Job as a variable?
Just provide definitions for the other two predicates and you have a working program. Something along these lines:
likes_job(_Person, Job) :-
is_fun(Job),
pays_well(Job).
is_fun('scuba diving instructor').
is_fun('tour guide').
pays_well('software developer').
pays_well('scuba diving instructor').
A couple of examples:
?- likes_job('Peter', Job).
Job = 'scuba diving instructor' ;
false.
?- likes_job('Peter', 'software developer').
false.
?- likes_job('Peter', 'tour guide').
false.
?- likes_job('John', 'scuba diving instructor').
true.
?- likes_job(X, 'scuba diving instructor').
true.
Instead of defining the two predicates, you can just declare them as "dynamic" and they are now empty (instead of absent):
likes_job(_Person, Job) :-
is_fun(Job),
pays_well(Job).
:- dynamic is_fun/1.
:- dynamic pays_well/1.
$ swipl -q
?- [likesjob].
true.
?- likes_job(A, B).
false.
?- assertz(is_fun(x)).
true.
?- assertz(pays_well(x)).
true.
?- likes_job(A, B).
B = x.

family relation in prolog :descendantTree

I want recursively store a family relation in a list structure. I have the following code:
descendantTree(X,[X]) :-
\+ parent(X,_).
descendantTree(X,L) :-
forall(parent(X,Y), descendantTree(Y,YL)),
append([X],[YL],L).
parent(john, paul).
parent(john, mary).
parent(paul, henry).
parent(paul, june).
parent(mary, adam).
parent(henry, helen).
What I expected is like:
L =[john,[paul,[henry,[helen]],[june]],[mary,[adam]]]
But actually it just return:
L = [john, _9250].
Could you tell me why?
The forall/2 predicate implements a generate and test loop using negation. It can be defined as:
% for all solutions of Generate, Test is true
forall(Generate, Test) :-
\+ (Generate, \+ Test)).
The use of negation means that no bindings will be returned when a call succeeds. In your case, that means that you're calling:
append([X],[_],L)
hence the result you get:
L = [john, _9250].
Look instead into the all-solutions family of predicates: bagof/3, setof/3, and findall/3 and then consider editing your question with your findings.

Prolog - 2 ways for progenitor predicate implementation

Given a set of facts that represent parent-child relationships via the predicate parent/2, what are the differences when defining the relation "progenitor"(ancestor) with the predicates pred1/2 and pred2/2 as shown below?
pred1(X,Z) :- parent(X,Z).
pred1(X,Z) :- parent(X,Y), pred1(Y,Z).
pred2(X,Z) :- parent(X,Z).
pred2(X,Z) :- parent(Y,Z), pred2(X,Y).
The major difference are the termination properties of both, provided there are some cycles in the relation. To understand this, I will use a failure-slice which cuts down the program to its essence w.r.t. termination.
pred1(X,Z) :- false, parent(X,Z).
pred1(X,Z) :- parent(X,Y), pred1(Y,Z). % Z has no influence
pred2(X,Z) :- false, parent(X,Z).
pred2(X,Z) :- parent(Y,Z), pred2(X,Y). % X has no influence
For pred1/2, the second argument has no influence on termination at all, whereas in pred2/2, the first argument has no influence. To see this, try the original definitions with the fact:
parent(a,a).
?- pred1(b, _), false.
false. % terminates
?- pred2(b, _), false.
loops.
?- pred1(_, b), false.
loops.
?- pred2(_, b), false.
false. % terminates
See closure/3 for a general approach to avoid such loops.
For completeness, here is another variation of transitive closure which has some conceptual advantages:
pred3(X,Z) :- parent(X,Z).
pred3(X,Z) :- pred3(X,Y), pred3(Y,Z).
Alas, its termination properties are worst. In fact, it never terminates, as is testified by the following fragment:
pred3(X,Z) :- false, parent(X,Z).
pred3(X,Z) :- pred3(X,Y), false, pred3(Y,Z).
In this fragment, the first argument is only passed on. So, no matter, what the arguments are, the program will always loop!
?- pred3(b,b), false.
loops.

Prolog query exercise

Here are my given clauses
beats(rock, scissors).
beats(scissors, paper).
beats(paper, rock).
better(battleaxe, scissors).
better(lightsabre, battleaxe).
better(boulder, rock).
better(adamantium, boulder).
better(palisade, paper).
better(nanomesh, palisade).
uses(wolverine, adamantium).
uses(vader, lightsabre).
uses(conan, battleaxe).
uses(richard, rock).
win(X,Y) :- beats(X,Y).
win(X,Y) :- better(X,Y).
win(X,Y) :- better(X,'underscore here'), beats('underscore here',Y).
win(X,Y) :- better(X,A), better(Y,B), win(A,B).
win(X,Y) :- uses(X,A), uses(Y,B), !, win(A,B).
play(X,Y,X) :- win(X,Y).
play(X,Y,Y) :- win(Y,X).
the question is asking what result i would get from
?- win(X, nanomesh).
the answer is supposed to be X = lightsabre. However I really do not get why.
Could anyone explain this please?
There are several ways how you can try to understand this particular query. One way, is to add goals false into your program, such that you still get the same answer. By adding false the program is specialized. If it then still gets the same answer, we know that a responsible part is in the visible area. The strike-through parts indicate clauses you now can ignore completely.
beats(rock, scissors) :- false.
beats(scissors, paper).
beats(paper, rock) :- false.
better(battleaxe, scissors).
better(lightsabre, battleaxe).
better(boulder, rock) :- false.
better(adamantium, boulder) :- false.
better(palisade, paper).
better(nanomesh, palisade).
win(X,Y) :- beats(X,Y).
win(X,Y) :- false, better(X,Y).
win(X,Y) :- false, better(X,'underscore here'), beats('underscore here',Y).
win(X,Y) :- better(X,A), better(Y,B), win(A,B).
?- win(lightsabre, nanomesh).
So you have two chains:
nanomesh -> palisade -> paper`
lightsabre -> battleaxe -> scissors
And finally scissors beat paper.
Not sure I agree with this kind of reasoning, though.

Resources