2
votes

I am working on creating a family tree in prolog. Where I am running into trouble is when I call on sister or brother. The results I get are correct, where julie is the sister of mike, julie is the sister of amanda, amanda is the sister of mike and amanda is the sister of julie. But what happens rather than ending there, if i keep hitting the 'n' key it will loop back through the results again. Why is this happening?

parent(pete,mike).
parent(pete,julie).
parent(pete,amanda).
parent(mary,mike).
parent(mary,julie).
parent(mary,amanda).
female(mary).
female(julie).
female(amanda).
male(mike).
male(pete).



mother(X,Y):-
    parent(X,Y),
    female(X).

father(X,Y):-
    parent(X,Y),
    male(X).

sibling(X,Y):-
    parent(Z,X),
    parent(Z,Y),
    X\=Y.

sister(X,Y):-
    sibling(X,Y),
    female(X).

brother(X,Y):-
    sibling(X,Y),
    male(X).
2

2 Answers

1
votes

Every pair of siblings will have both the same father and the same mother (in the more conservative societies, at least, and in your program at the moment). This is where you get the double answers from. You could maybe say that siblings always share both parents?

1
votes

As stated, you get double answers because you're checking if they have the same parent, and they have two of those. Moreover, you're getting even more solutions because e.g. mike is sibling of amanda, but also amanda is sibling of mike, and you do nothing to prevent both solutions to appear. So instead of:

sibling(X, Y):-
    parent(Z, X),
    parent(Z, Y),
    X\=Y.

to solve problem of two parents, you could say they always share both parents:

sibling(X, Y):-
    mother(Z, X),
    mother(Z, Y),
    father(W, X),
    father(W, Y),
    X\=Y.

You could stop second problem (X=mike, Y=amanda; X=amanda, Y=mike) by introducing @<:

sibling(X, Y):-
    mother(Z, X),
    mother(Z, Y),
    father(W, X),
    father(W, Y),
    X@<Y.

This way, only one set of solutions is appearing, but you have to be careful with it, as it might not get you want you want, depending on what you want to achieve (X=julie, Y=amanda would not be true in this case).

Depending on the need, perhaps more elegant and general solution (not requiring both parents to be same) would be to use setof (http://www.swi-prolog.org/pldoc/doc_for?object=setof/3) with your original sibling clause, but you would rework your brother/sister clauses, e.g.:

sibling(X, Y):-
    parent(Z, X),
    parent(Z, Y),
    X\=Y.

sister(X,Y,L):-
    female(X),
    setof([X, Y], (sibling(X, Y)), L).

brother(X,Y,L):-
    male(X),
    setof([X, Y], (sibling(X, Y)), L).

This would get you a list of unique pairs in list L, e.g. for sister(X, Y, L) you get:

X = julie
L = [[julie, amanda], [julie, mike]]

X = amanda
L = [[amanda, julie], [amanda, mike]]

Play with it a little to get exactly what you need.