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.
Related
The following is the classic "textbook" vanilla meta-interpreter for prolog.
% simplest meta-interpreter
solve(true) :- !.
solve((A,B)):- !, solve(A), solve(B).
solve(A) :- clause(A,B), solve(B).
The following is simple program which establishes facts two relations which are "positive" and one relation which makes use of negation by failure \+.
% fruit
fruit(apple).
fruit(orange).
fruit(banana).
% colour
yellow(banana).
% Mary likes all fruit
likes(mary, X) :- fruit(X).
% James likes all fruit, as long as it is yellow
likes(james, X) :- fruit(X), yellow(X).
% Sally likes all fruit, except yellow fruit
likes(sally, X) :- fruit(X), \+ (yellow(X)).
The meta-interpeter can handle goals related to the first two relations ?-solve(likes(mary,X)) and ?- solve(likes(james,X)_.
However it fails with a goal related to the third relation ?- solve(likes(sally,X). The swi-prolog reports a stack limit being reached before the program crashes.
Question 1: What is causing the meta-interpreter to fail? Can it be easily adjusted to cope with the \+ negation? Is this related to the sometimes discussed issue of built-ins not being executed by the vanilla meta-interpreter?
Question 2: Where can I read about the need for those cuts in the vanilla meta-interpreter?
Tracing suggests the goal is being grown endlessly:
clause(\+call(call(call(call(yellow(apple))))),_5488)
Exit:clause(\+call(call(call(call(yellow(apple))))),\+call(call(call(call(call(yellow(apple)))))))
Call:solve(\+call(call(call(call(call(yellow(apple)))))))
Call:clause(\+call(call(call(call(call(yellow(apple)))))),_5508)
Exit:clause(\+call(call(call(call(call(yellow(apple)))))),\+call(call(call(call(call(call(yellow(apple))))))))
Call:solve(\+call(call(call(call(call(call(yellow(apple))))))))
Change solve(A) into:
solve(Goal) :-
writeln(Goal),
sleep(1),
clause(Goal, Body),
solve(Body).
... and we see:
?- solve_mi(likes(sally,X)).
likes(sally,_8636)
fruit(_8636)
\+yellow(apple)
\+call(yellow(apple))
\+call(call(yellow(apple)))
\+call(call(call(yellow(apple))))
...
clause/2 determines the body of \+yellow(apple) to be \+call(yellow(apple)), which is not a simplification.
Can use instead:
solve_mi(true) :-
!.
solve_mi((Goal1, Goal2)):-
!,
solve_mi(Goal1),
solve_mi(Goal2).
solve_mi(\+ Goal) :-
!,
\+ solve_mi(Goal).
solve_mi(Goal) :-
clause(Goal, Body),
solve_mi(Body).
Result in swi-prolog:
?- solve_mi(likes(sally,X)).
X = apple ;
X = orange ;
false.
I'm using solve_mi because solve conflicts with e.g. clpBNR, and I'm not using variable names A and B because they convey no meaning.
For understanding the cuts, I'd recommend gtrace, to see the unwanted unification with other goals that would otherwise take place.
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.
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.
I have tracing meta-interpreter made from my previous questions here and I would like to make similar meta-interpreter but this time for making execution trees.
I've made something like this below using similar to same code found on the web and techniques from my previous questions.
clause_tree(true,_,true) :- !, true.
clause_tree((G,R),Trail,(TG,TR)) :-
!,
clause_tree(G,Trail,TG),
clause_tree(R,Trail,TR).
clause_tree(G,_,prolog(G)) :-
(predicate_property(G,built_in) ;
predicate_property(G,compiled) ),
call(G).
clause_tree(G,Trail,tree(G,T)) :-
clause(G,Body),
clause_tree(Body,[G|Trail],T).
why(G) :-
call_with_depth_limit(
catch(
clause_tree(G,[],T),
cut,
fail),
30,
_Message),
nl,
draw_tree(T,0).
draw_tree(tree(Root,Branches),Tab) :- !,
tab(Tab),
write(Tab),
write(': '),
write(Root),
nl,
Tab1 is Tab + 1,
draw_tree(Branches,Tab1).
draw_tree((B,Bs),Tab) :- !,
draw_tree(B,Tab),
draw_tree(Bs,Tab).
draw_tree(Node,Tab) :-
tab(Tab),
write(Tab),
write(': '),
write(Node),
nl.
%example program for testing
%?-p(X).
p(X) :- a(X).
p(X) :- b(X),c(X), d(X),e(X).
p(X) :- f(X).
b(Y) :- g(Y), h(Y).
b(1).
b(2).
a(1).
c(1).
c(2).
d(1).
d(2).
e(2).
f(3).
g(2).
g(1).
h(2).
How can I alter this interpreter that it displays branches that fails and that tree is only one with all solutions? Consider that trees are done only for similar programs like example program written in code if that matters.
I am using swi-prolog.
Edit : I am trying to achieve something like this but in textual form.
I need to create a Prolog predicate for power of 2, with the natural numbers.
Natural numbers are: 0, s(0), s(s(0)) ans so on..
For example:
?- pow2(s(0),P).
P = s(s(0));
false.
?- pow2(P,s(s(0))).
P = s(0);
false.
This is my code:
times2(X,Y) :-
add(X,X,Y).
pow2(0,s(0)).
pow2(s(N),Y) :-
pow2(N,Z),
times2(Z,Y).
And it works perfectly with the first example, but enters an infinite loop in the second..
How can I fix this?
Here is a version that terminates for the first or second argument being bound:
pow2(E,X) :-
pow2(E,X,X).
pow2(0,s(0),s(_)).
pow2(s(N),Y,s(B)) :-
pow2(N,Z,B),
add(Z,Z,Y).
You can determine its termination conditions with cTI.
So, how did I come up with that solution? The idea was to find a way how the second argument might determine the size of the first argument. The key idea being that for all i ∈ N: 2i > i.
So I added a further argument to express this relation. Maybe you can strengthen it a bit further?
And here is the reason why the original program does not terminate. I give the reason as a failure-slice. See tag for more details and other examples.
?- pow2(P,s(s(0))), false.
pow2(0,s(0)) :- false.
pow2(s(N),Y) :-
pow2(N,Z), false,
times2(Z,Y).
It is this tiny fragment which is the source for non-termination! Look at Z which is a fresh new variable! To fix the problem, this fragment has to be modified somehow.
And here is the reason why #Keeper's solution does not terminate for pow2(s(0),s(N)).
?- pow2(s(0),s(N)), false.
add(0,Z,Z) :- false.
add(s(X),Y,s(Z)) :-
add(X,Y,Z), false.
times2(X,Y) :-
add(X,X,Y), false.
pow2(0,s(0)) :- false.
pow2(s(N),Y) :- false,
var(Y),
pow2(N,Z),
times2(Z,Y).
pow2(s(N),Y) :-
nonvar(Y),
times2(Z,Y), false,
pow2(N,Z).
This happends because the of evaluation order of pow2.
If you switch the order of pow2, you'll have the first example stuck in infinite loop..
So you can check first if Y is a var or nonvar.
Like so:
times2(X,Y) :-
add(X,X,Y).
pow2(0,s(0)).
pow2(s(N),Y) :-
var(Y),
pow2(N,Z),
times2(Z,Y).
pow2(s(N),Y) :-
nonvar(Y),
times2(Z,Y),
pow2(N,Z).