I have a simple example below of a prolog program I have written, which contains a satisfiable query that always returns false for searches.
male(william).
male(harry).
% parent(x,y) - the parent of x is y
parent(william, diana).
parent(william, charles).
parent(harry, diana).
parent(harry, charles).
% Brother - the brother of X is Y
brother(X,Y) :- X\=Y, parent(X,A), parent(Y,A), male(Y).
When I ask if two constants are brothers, that works fine, but if I try to find a brother of a constant prolog returns false.
?- brother(william,harry).
true
?- brother(william,X).
false.
What am I doing wrong?
The problem is here X\=Y this part lucks logical purity since \=/2 is non-monotonic. Simply to make it work change the order:
brother(X,Y) :- X\=Y, parent(X,A), parent(Y,A), male(Y).
to:
brother(X,Y) :- parent(X,A), parent(Y,A), male(Y), X\=Y.
But a much better solution would be to use dif/2 which is preserves purity:
brother(X,Y) :- dif(X,Y), parent(X,A), parent(Y,A), male(Y).
Related
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.
My DataBase =>
fact(a).
fact(b).
likes(a, rain).
likes(a, snow).
likes(b, X) :- not(likes(a, X)).
human(X) :-
not(likes(X, rain)),
fact(X).
alien(X) :-
likes(X, snow),
fact(X).
Prolog question =>
?- human(X)
no
The logic here is
likes(a, rain),
so by rule
not(likes(b, rain)) is True AND fact(b) is True
human(b) is No
human(X) is No
Should be Yes but it doesnt make the connection
How can I make with prolong this check so it understands that it should return b ?
A lowercase x is a constant, so it looks for not(likes(x, rain)), which indeed holds, but fact(x) does not hold since there is no clause fact(x), only for a and b.
As for human(X) (so as a variable), not(likes(X, rain)) will not succeed, since there is an X that likes rain: a likes rain, hence likes(X, rain) can be unfied, and therefore not(likes(X, rain)) fails. The fact that there is a b that does not like rain, is not relevant. Negation in Prolog is not constructive, it is implemented as finite failure: something is not true if all attempts to proof that it is true fail and these attempts are finite (otherwise we get stuck in an infinite loop).
You can however swap the fact(X) and not(likes(X, rain)) clauses:
human(X) :-
fact(X),
\+ likes(X, rain).
If you then call human(X), it will succeed with X = b. This works since it will first unify X with a, but that will fail for the \+ likes(a, rain) clause, but then it will retry by unfying X with b, and this will succeed.
I just altered the order of the predicate and it seems to work know:
human(X) :-
fact(X),
\+ likes(X, rain).
?- human(X).
X = b.
The reason behind this is that before unification of X you ask for likes(X, rain) and you want it to be false. So prolog searches for likes(X, rain), finds likes(a, rain) returns true, negates it and will therefore fail. Resolve the issue by adressing fact(X) first, so it will ask for this particular X and not just any value.
I am currently writing a PROLOG program that represents Family Relationships.
Right now I have implemented the following functions that work.
male(X). Returns true if X is male.
female(X). Returns true if X is female.
mother_of(X,Y). Returns true if X is the mother of Y.
father_of(X,Y). Returns true if X is the father of Y.
sister_of(X,Y). Returns true if X is the sister of Y.
brother_of(X,Y). Returns true if X is the brother of Y.
Now I want to implement a function to check if someone is a single child/has no sister/brother.
I have tried the following functions but none of them is working:
single_child(X) :- (\+ sister_of(X,Y)),(\+ brother_of(X,Y)).
single_child(X) :- not(sister_of(X,Y)), not(brother_of(X,Y)).
single_child(X) :- \+ (sister_of(X,Y),\+ brother_of(X,Y)).
single_child(X) :- not(sister_of(X,Y),brother_of(X,Y)).
Does anyone know how I could implement such a function correctly?
Kind Regards
David J.
I found a Solution myself:
single_child(X) :- \+ has_sibling(X),(parent(P,X)).
parent(X,Y) :- father_of(X,Y);mother_of(X,Y).
sibling(X,Y):- parent(Z,X), parent(Z,Y), X\=Y.
has_sibling(X) :- sibling(X,_).
I'm trying to run a query for a family tree but when I enter all the information, I'm getting a syntax error: operator expected. I'm new to Prolog.
domains
name=symbol
predicates
parent(name,name)
female(name)
male(name)
sister(name,name)
son(name,name)
father(name)
grandmother(name)
clauses
female(stella).
female(lizzy).
female(emily).
female(mia).
female(alice).
male(hubert).
male(ben).
male(john).
male(danny).
male(sam).
parent(stella,ben).
parent(stella,mia).
parent(hubert,ben).
parent(hubert,mia).
parent(lizzy,emily).
parent(lizzy,john).
parent(ben,emily).
parent(ben,john).
parent(mia,sam).
parent(mia,alice).
parent(danny,sam).
parent(danny,alice).
sister(X,Y):-female(X),parent(Par,X),parent(Par,Y),X\==XY.
son(X,Y):-parent(Z,X),parent(Z,Y),male(X),X\==Y.
father(X,Y):-parent(X,Y),male(X).
grandmother(X,Y):-parent(X,Y),female(X)
There are two problems here:
you forgot a dot (.) at the end rhat signals the end of the clause; and
this is not really an error, but you write X\==XY in the sister/2 clause, since XY is a new variable, this will always succeed.
There is also a semantical problem with the grandmother/2 predicate: right now it defines a "mother" predicate. I leave this as an exercise.
I also advise to reformat your code (Prolog does not charge you per line, and it makes it more clear where a clause ends and what it does).
sister(X,Y) :-
female(X),
parent(Par,X),
parent(Par,Y),
X \== Y.
son(X,Y) :-
parent(Z,X),
parent(Z,Y),
male(X),
X \== Y.
father(X,Y) :-
parent(X,Y),
male(X).
grandmother(X,Y) :-
parent(X,Y),
female(X).
When I try to see who is brother to who and same for sister it gives me the sons and daughter, I cannot find the mistake...
father(pedro-i,fernando-i).
father(pedro-i,beatriz(1347)).
father(pedro-i,joão(1349)).
father(pedro-i,dinis(1354)).
father(pedro-i,joão_grão_mestre_da_ordem_de_avis).
mother(constança(1320),luis).
mother(constança(1320),maria(1342)).
mother(constança(1320),fernando-i).
mother(inês_de_castro,beatriz(1347)).
Any other opinion I appreciate that
ancestor(X,Y) :- mother(X,Y).
ancestor(X,Y) :- father(X,Y).
if_then_else(X,Y,male) :- father(X,Y).
if_then_else(X,Y,female) :- mother(X,Y).
son(X,Y) :- father(X,Y).
sister(X,Y) :- ancestor(Z,Y),X\==Y,if_then_else(X,Y,female).
brother(X,Y) :- ancestor(Z,Y),X\==Y,if_then_else(X,Y,male).
descendent (X,Y) :- filho(X,Y).
descendent (X,Y) :- filho(X,Z),descendent (Z,Y).
grandfather(X,Y) :- ancestor(X,Z),ancestor(Z,Y).
grandmother(X,Y) :- ancestor(X,Z),ancestor(Z,Y).
grandchildren(X,Y) :- ancestor(Z,X),ancestor(Y,Z).
uncle(X,Y) :- brother(X,Z),ancestor(Z,Y).
Your clause brother(X,Y) :- ancestor(Z,Y),X\==Y,if_then_else(X,Y,male). requires Y to have an ancestor, but X also needs to have an ancestor -- the same ancestor:
brother(X,Y) :- ancestor(Z,Y),ancestor(Z,X), X\==Y,if_then_else(X,Y,male).
You also need to eliminate the requirement at the end that X be the father of Y.
brother(X,Y) :- ancestor(Z,Y),ancestor(Z,X), X\==Y,male(X).
male needs to depend simply on the individual (you don't need to be a father to be a male.) male (fernando-i)., etc.