Get only one solution for sibling pairs in family tree - prolog

I have the following Prolog code, modified from Wikipedia:
mother_child(trude, sally).
father_child(tom, sally).
father_child(tom, erica).
father_child(mike, tom).
different(X, Y) :- X \== Y.
sibling(X, Y) :- parent_child(Z, X), parent_child(Z, Y), different(X, Y).
parent_child(X, Y) :- father_child(X, Y).
parent_child(X, Y) :- mother_child(X, Y).
I get the following:
?- sibling(X, Y).
X = sally,
Y = erica ;
X = erica,
Y = sally ;
false.
Is it possible to modify my code so that ?- sibling(X, Y) to return only: X = sally, y = erica ; false.? That is, I want to eliminate instances where X = Y and Y = X (converse).

The comment by #lurker says it all. Ask yourself what it is that the query is asking:
Is there a pair X, Y such that:
X has the parent Z:
Z is a father
Z is a mother
Y has the parent Z:
Z is a father
Z is a mother
X and Y are not the same
In your current database, a child can have at most one mother and one father, so the two clauses of parent_child/2 happen to be mutually exclusive for a single child.
But you have the subgoal parent_child/2 twice in sibling/2, so for every pair of siblings, you can have either one of the two in the first, and then the other one in the second, so you have two proofs for each pair. Saying X #< Y instead of X \== Y will make sure that only one of the two possible combinations of X and Y lead to a successful proof.

Related

How to formulate an exception for findall/3 correctly?

I have startet to learn Prolog and I want to get a list of opponents of players with findall/3. In the Generalization I just want to add only the opponents to the list who are actually players, except the player I am asking for itself. How can I formulate this exception? I know about the negation as failure concept but I am not sure if and how I need it here.
player(irina).
player(anton).
player(michael).
opponent(irina, anton).
opponent(irina, maria).
opponent(irina, michael).
% Only opponents who are also players should be added to the list,
% except the player of interest itself
opponent(X, Y) :- X \= Y, player(Y).
% the query
?- findall(O, opponent(irina,O) , OpponentList).
% the result
% only the first three results from the facts,
% the results from the rule, a second entry of
% anton and michael are missing.
OpponentList = [anton, maria, michael].
I actually expected, that the resolution would work as follows:
opponent(irina, irina) :- irina \= irina, player(irina).
% false true
% false
% false, hence not added to the list
opponent(irina, anton) :- irina \= anton, player(anton).
% true true
% true
% true, hence added to the list
What am I missing?
Many thanks in advance!
Code:
player(irina).
player(anton).
player(michael).
opponent(irina, anton).
opponent(irina, maria).
opponent(irina, michael).
opponent(X, Y) :-
format("Called with X = ~q, Y = ~q\n",[X,Y]),
X \= Y, % this will fail if Y is still fresh because X and Y can be unified!
player(Y).
opponent_mod(X, Y) :-
format("Called with X = ~q, Y = ~q\n",[X,Y]),
player(Y), % this will set Y to various players
X \= Y. % the test for un-unifiability of two set vars may or may not succeed
% query helpfully as code:
q(Who,OpponentList) :- findall(O, opponent(Who,O) , OpponentList).
q_mod(Who,OpponentList) :- findall(O, opponent_mod(Who,O) , OpponentList).
% even better
q_mod_set(Who,OpponentList) :- setof(O, opponent_mod(Who,O) , OpponentList).
Run it:
Not expected:
?- q(irina,X).
Called with X = irina, Y = _19654
X = [anton, maria, michael].
Expected:
?- q_mod(irina,X).
Called with X = irina, Y = _20568
X = [anton, michael].
So what happens in the "not expected" case with Who = irina:
findall/3 tries to collect all values Y such that opponent(Who,O)
It finds anton, maria, michal through the facts
opponent(irina, anton).
opponent(irina, maria).
opponent(irina, michael).
It also tries the rule opponent(X, Y) :- ... with X = irina (once only). But the test X \= Y fails because X has been constrained to be irina but Y is still fresh (completely unconstrained). This means that a unification of X and Y could succeed if it were attempted (which is what is being tested, = does not as such mean "is not equal"). So X \= Y is false at this point of computation. If you move X \= Y after player(Y), then Y will have been constrained to whatever was grabbed from the player/1 facts, and this would reduce to an actual comparison of the values of X and Y.

Can I use integers as parameters?

How can I know if a person X is descendant of a person Y given the descendancy degree?
I've tried this:
descendant(X, Y, 1) :- son(X, Y).
descendant(X, Y, Degree) :- son(X, Z) , descendant(Z, Y, Degree-1).
Where son(X, Y) returns yes if X is son of Y. If Degree == 1 it returns the correct answer but for descendant(X, Y, 2), for instance, should return yes if X is grandson of Y but returns no.
1) Naming: Does son(X,Y) mean "X is the son of Y"—or vice-versa?
son_of(X,Y) is better.
2) Exploit successor-arithmetics: We don't need to do general arithmetics here... we only need to count.
So let's start in the beginning...
child_of(abel, adam). % from source
child_of(abel, eve).
child_of(cain, adam).
child_of(cain, eve).
child_of(enoch, cain).
child_of(irad, enoch).
child_of(mehujael, irad).
child_of(methushael, mehujael).
child_of(lamech, methushael).
child_of(jabal, lamech).
child_of(jabal, adah).
child_of(jubal, lamech).
child_of(jubal, adah).
child_of(tubal_cain, lamech).
child_of(tubal_cain, zillah).
child_of(naamah, lamech).
child_of(naamah, zillah).
child_of(seth, adam).
child_of(seth, eve).
child_of(enos, seth).
child_of(kenan, enos).
child_of(mahalalel, kenan).
child_of(jared, mahalalel).
child_of(enoch, jared).
child_of(methuselah, enoch).
child_of(lamech, methuselah).
child_of(noah, lamech).
child_of(shem, noah).
child_of(ham, noah).
child_of(japheth, noah).
Based on child_of/2 we first define ancestor_of/2—this should be nothing new to you!
ancestor_of(Y, Z) :-
child_of(Z, Y). % If Z is a child of Y ...
% then Y is an ancestor of Z.
ancestor_of(X, Z) :-
child_of(Z, Y), % If Z is a child of Y ...
ancestor_of(X, Y). % and X is an ancestor of Y ...
% then X is an ancestor of Z.
Next, we add an additional parameter indicating the distance.
We use s/1 terms to represent natural numbers and add a new argument to ancestor_of/2:
ancestor_of_dist(Y, Z, s(0)) :-
child_of(Z, Y). % If Z is a child of Y ...
% then Y is an ancestor of Z with distance = 1."
ancestor_of_dist(X, Z, s(N)) :-
child_of(Z, Y), % If Z is a child of Y ...
ancestor_of_dist(X, Y, N). % and X is an ancestor of Y with distance N ...
% then X is an ancestor of Z with distance N+1.
So ... who is grandparent of whom?
?- ancestor_of_dist(X, Z, s(s(0))).
X = adam, Z = enoch
; X = eve, Z = enoch
; X = cain, Z = irad
; X = jared, Z = irad
; X = enoch, Z = mehujael
; ...
; X = lamech, Z = japheth
; false.
Prolog is not a functional language. Thus, the Degree-1 term is not interpreted and evaluated as an expression. For Prolog, Degree-1 is just a compound term with two arguments. That can be made clear using the standard write_canonical/1 predicate, which writes a term without using operator notation:
?- write_canonical(Degree-1).
-(_,1)
true.
Write instead:
descendant(X, Y, 1) :-
son(X, Y).
descendant(X, Y, Degree) :-
son(X, Z) ,
descendant(Z, Y, Degree0),
Degree is Degree0 + 1.
The is/2 standard built-in predicate unifies the left argument with the value of the arithmetic expression in the right argument.
P.S. Note that the alternative descendant/3 predicate definition I suggest will solve the problem you described but it is not an efficient definition as it is not a tail-recursive definition. I.e. the recursive call in the second clause is not the last call in the clause body. This issue can be easily solved, however, by using an accumulator.

Prolog, X element before element Y on list [duplicate]

This question already has answers here:
Prolog, X before Y in a List
(4 answers)
Closed 6 years ago.
I am going to write predicate which is true iff only and only when element X occurs before Y on list L
before(L, X, Y) :-
nth1(PX, L, X),
nth1(PY, L, Y),
PX < PY.
Above, you can see my solution. What do you think about it ?
When it comes to my specific question:
My predicate returns true when there is exists at least one pair that Y followed X. How to define predicate such that it is true for each pair ?
The solution you show works for the "if one exists" case, but is somewhat imperative in nature. That is, it's a little bit like a C program translated to Prolog. Imperative means you are telling the computer, using the programming language, what steps to execute in order to achieve your results.
To be more declarative or relational, your "exists" solution could be expressed nicely as a DCG:
... --> [].
... --> [_], ... .
before(X, Y) --> ... , [X], ... , [Y], ... .
(NOTE: You can in Prolog have a predicate named ..., which is shown here.) This describes the relationship of X and Y in the list. It does not describe steps to execute, but instead describes the relationship of X and Y in a sequence. This solution has been shown before on SO.
Following this approach (where we describe the relationship of X and Y), one way (not necessarily the only way) to express that all the X precede all the Y would be:
before_all(X, Y) -->
{ dif(X,Y) },
any_sequence_but(Y), [X], any_sequence_but(Y), [Y], any_sequence_but(X).
any_sequence_but(_) --> [].
any_sequence_but(Y) --> [X], { dif(X,Y) }, any_sequence_but(Y).
Which yields a solution like this:
?- phrase(before_all(X,Y), [b,a,b,c,a,b,d]).
X = b,
Y = d ;
X = a,
Y = d ;
X = b,
Y = d ;
X = c,
Y = d ;
X = a,
Y = d ;
X = b,
Y = d ;
false.
?-
If the condition should hold for all pairs, the condition should hold for at least one pair, while its converse shouldn't be true for any pair.
I took the liberty of renaming your before/3 to beforeSome/3.
beforeSome(L, X, Y) :-
nth1(PX, L, X),
nth1(PY, L, Y),
PX < PY.
beforeAll(L, X, Y) :-
beforeSome(X,Y),
not(beforeSome(L, Y, X)).
Which yields the desired results:
?- beforeAll([1,2,3,1,4,5], 1, 4).
true.
?- beforeAll([1,2,3,1,4,5], 1, 2).
false.
Please note that your use of nth1/3 precludes it being used with uninstantiated variables. In other words, beforeAll([1,2,3,1,4,5], X, Y). is false.
A better implementation of beforeSome/3 would be something like
beforeSome([X|T], X, Y) :-
member(Y, T).
beforeSome([_|T], X, Y) :-
beforeSome(T, X, Y).
% no change needed, but repeated here for completeness' sake
beforeAll(L, X, Y) :-
beforeSome(X,Y),
not(beforeSome(L, Y, X)).

Prolog: Unification or Backtracking errors in program

I have a simple knowledge base that encodes a family tree. Some important rules in this representation are as follows:
% fathers
father(michael,cathy).
father(michael,sharon).
father(charles_gordon,michael).
father(charles_gordon,julie).
father(charles,charles_gordon).
father(jim,melody).
father(jim,crystal).
father(elmo,jim).
father(greg,stephanie).
father(greg,danielle).
% mothers
mother(melody,cathy).
mother(melody,sharon).
mother(hazel,michael).
mother(hazel,julie).
mother(eleanor,melody).
mother(eleanor,crystal).
mother(crystal,stephanie).
mother(crystal,danielle).
% parents
parent(X,Y) :- father(X,Y).
parent(X,Y) :- mother(X,Y).
% men
male(michael).
male(charles_gordon).
male(charles).
male(jim).
male(elmo).
male(greg).
% women
female(cathy).
female(sharon).
female(julie).
female(hazel).
female(eleanor).
female(melody).
female(crystal).
female(stephanie).
female(danielle).
person(X) :- male(X) ; female(X).
parent(X,Y) :- father(X,Y) ; mother(X,Y). % X is parent of Y
child(X,Y) :- parent(Y,X).
elder(X,Y) :- parent(X,Y). % X is an elder of Y, meaning X is a parent or an ancestor of Y
elder(X,Y) :- parent(X,Z), elder(Z,Y).
junior(X,Y) :- child(X,Y). % X is a junior of Y, meaning X is a child or some descendant of Y
junior(X,Y) :- child(X,Z), junior(Z,Y).
I am attempting to find the nearest elder between two individuals(predicate ne(X,Y,Z)). This individual Z is the elder of both X and Y, and no junior of Z is also an elder of BOTH X and Y.
My attempt looks like this:
ne(X,Y,Z) :- person(X),
person(Y),
X \= Y,
elder(Z,X),
elder(Z,Y),
junior(A,Z),
not(elder(A,X)),
not(elder(A,Y)).
but this is somehow incorrect, because whenever I run ?- ne(stephanie,cathy,Z). i get
Z = jim ;
Z = jim ;
Z = jim ;
Z = jim ;
Z = elmo ;
Z = elmo ;
Z = elmo ;
Z = elmo ;
Z = eleanor ;
Z = eleanor ;
Z = eleanor ;
Z = eleanor ;
but i'm only supposed to get one answer, and I can't figure out what's wrong. Thanks!
from this graph
seems this answer is correct
?- ne(stephanie,cathy,A).
A = eleanor ;
A = jim.
here is my attempt to ne/3
ne(X,Y,Z) :-
setof(A, (
elder(A, X),
elder(A, Y),
X \= Y,
\+ (elder(A, T), elder(T, X) , elder(T, Y) ))
, As), member(Z, As).
not sure it's the better way...
Setof/3 (joined with member/2) is used to eliminate duplicate answers, since we get
?- aggregate(count,A^ne(stephanie,cathy,A),N).
N = 32.
with this core logic
ne(X,Y,A) :-
elder(A, X),
elder(A, Y),
X \= Y,
\+ (elder(A, T), elder(T, X) , elder(T, Y)).
note variable A replaces locally the original Z
edit
I didn't took in account the savvy comment by #Boris, but after removing the duplicate parent/2 definition, the setof/3+member/2 trick become useless.

Basic prolog issue with syntax of statement

I'm sort of a beginner to Prolog and I have a quick question. I've written a sister_of/2 predicate that goes like this:
sister_of(X, Y) :-
female(X),
parents(X, Z, W) == parents(Y,Z,W),
X \= Y.
I read this as X is a sister of Y if X is a female and the parents of X which are Z W are the same parents of Y, Z W and X and Y are not the same person. This isn't running for some reason though, so it must be a syntax issue, some insight would be fantastic. Thank you.
Prolog is not a functional language, it's a relational language. You define predicates (i.e. relations), not functions. Thus, your parents(X, Z, W) == parents(Y,Z,W) is just comparing two terms, parents(X, Z, W) and parents(Y,Z,W) for equality. Assuming that a parents/3 predicate is also defined, you want something like:
sister_of(X, Y) :-
female(X),
parents(X, Z, W),
parents(Y, Z, W),
X \= Y.
Well, you began the construction of reasoning alright, but failed during the comparison. Here's what you've missed:
sister_of(X, Y) :-
female(X),
parents(X, Z, W),
parents(Y, Z, W),
X \= Y.
Now the reasoning goes as follows:
X is a sister of Y;
if X is a female;
if X has parents Z and W;
if Y has parents Z and W;
and, of course, X is not Y, so that X is not a sister of itself.
Notice that, the comparison you performed earlier is not necessary (and in fact, does not mean what you expected), since Z and W become limited to be the parents of X in step 3. This means that, Z and W already have a determined value after step 3 -- they are bound, in other words.
After that, in step 4, Y can only assume the same value of X, or some other value that makes parents(Y, Z, W) true. Finally, you remove the cases where X == Y in step 5, which gives you a valid definition of sister_of(X, Y).

Resources