1
votes

I am new to prolog and I don't know how to solve this. I have to write a siblings rule. All the way at the bottom of the code I have my siblings rule. The problem with the rule is that it returns the siblings twice. For example, if I want to get julia's siblings, I get "rosa" twice. I suppose that what is happening is that the program evaluates for each parent (alex and lina). So how could I fix my rule so I only get julia's (or anyone's) siblings just once?

parent(alex,julia).
parent(alex,rosa).
parent(lina,julia).
parent(lina,rosa).
parent(romeo,peter).
parent(julia,peter).
parent(rosa,silvia).
parent(oscar,ida).
parent(eva,ida).
parent(eva,bruno).
parent(peter,bruno).
parent(peter,georg).
parent(peter,irma).
parent(ruth,georg).
parent(ruth,irma).
parent(silvia,otto).
parent(silvia,pascal).
parent(irma,olga).
parent(irma,jean).
parent(otto,olga).
parent(otto,jean).
parent(jean,tina).
parent(marie,tina).

male(alex).
male(romeo).
male(oscar).
male(peter).
male(bruno).
male(georg).
male(otto).
male(pascal).
male(jean).


husband(alex,lina).
husband(romeo,julia).
husband(oscar,eva).
husband(peter,ruth).
husband(otto,irma).
husband(jean,marie).

% father(X,Y) :- X is the father of Y.

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

% grandfather(X,Y) :- X is the grandfather of Y.

grandfather(X,Y) :- father(X,P), parent(P,Y).

% brother(X,Y) :- X is the brother of Y.

brother(X,Y) :- parent(P,X), parent(P,Y), male(X), X \= Y.

% uncle(X,Y) :- X is the uncle of Y.

uncle(X,Y) :- brother(X,P), parent(P,Y).

% female(X) :- X is a female person.

female(X) :- \+ male(X).

% sister(X,Y) :- X is the sister of Y.

sister(X,Y) :- parent(P,X), parent(P,Y), female(X), X \= Y.

% has_son(X) :- the person X has a son.

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

% married(X,Y) :- X and Y are married to each other.

married(X,Y) :- husband(X,Y).
married(X,Y) :- husband(Y,X).

% brother_in_law(X,Y) :- X is the brother-in-law of Y.

brother_in_law(X,Y) :- brother(X,P), married(P,Y).
brother_in_law(X,Y) :- husband(X,W), sister(W,Y).

% ancestor(X,Y) :- X is an ancestor of Y.

ancestor(X,Y) :- parent(X,Y).
ancestor(X,Y) :- parent(X,P), ancestor(P,Y).

% relatives(X,Y) :- X and Y are relatives (related by blood to each other).

relatives(X,X).
relatives(X,Y) :- ancestor(X,Y).
relatives(X,Y) :- ancestor(Y,X).
relatives(X,Y) :- ancestor(A,X), ancestor(A,Y).

% ancestors(As,X) :- As is the set of all (known) ancestors of X.

ancestors(As,X) :- setof(A,ancestor(A,X),As).

% descendants(Ds,X) :- Ds is the set of all (known) descendants of X.

descendants(Ds,X) :-setof(D,ancestor(X,D),Ds).

% ancestor(X,Y,L) :- X is an ancestor of Y, and L is the list of names
% leading from X to Y.

ancestor(X,Y,[X,Y]) :- parent(X,Y).
ancestor(X,Y,[X|L]) :- parent(X,P), ancestor(P,Y,L).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Exercise 1
% Write a rule that determines if mother (M) is mother of (C) child.
% mother(M, C) :-

mother(M,C) :- female(M), parent(M,C).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Exercise 2
% Write a rule that infers the siblings of certain (X) person
% siblings. Ss is the siblings list.
% siblings(Ss, X) :-

sibling(X,Y) :- dif(X,Y),parent(Z,X),parent(Z,Y).
1
Use mother/2 and/or father/2 to make the predicate "assymetrical" (given of course same-sex marriages are not allowed). - Willem Van Onsem

1 Answers

1
votes

Your suspicion is correct. The problem with your predicate is that a person has (normally) two parents: a mother/2 and a father/2.

That means that if rosa and julia are (real) siblings (then they share the same mother/2 and father/2).

If we trace. we see that this orginates in the duplication:

?- trace.
true.

[trace]  ?- sibling(rosa, julia).
   Call: (8) sibling(rosa, julia) ? creep
   Call: (9) dif:dif(rosa, julia) ? creep
   Exit: (9) dif:dif(rosa, julia) ? creep
   Call: (9) parent(_5278, rosa) ? creep
   Exit: (9) parent(alex, rosa) ? creep
   Call: (9) parent(alex, julia) ? creep
   Exit: (9) parent(alex, julia) ? creep
   Exit: (8) sibling(rosa, julia) ? creep
true ;
   Redo: (9) parent(alex, julia) ? creep
   Fail: (9) parent(alex, julia) ? creep
   Redo: (9) parent(_5278, rosa) ? creep
   Exit: (9) parent(lina, rosa) ? creep
   Call: (9) parent(lina, julia) ? creep
   Exit: (9) parent(lina, julia) ? creep
   Exit: (8) sibling(rosa, julia) ? creep
true.

So first we find a sibling/2 relation through alex (the father/2 of the two), and later we find the sibling/2 relation through lina (the mother/2 of the two).

If there are no half-siblings here (two persons sharing the same father/2 or mother/2, but not the same mother/2 or father/2), then we can "deduplicate" this by picking only one of the two parents, for example the mother/2:

sibling(A, B) :-
    dif(A, B),
    mother(M, A),
    mother(M, B).

Based on the comment, it appears that your female/1 predicate is not working properly. So I propose you try to fix this.

or through a father/2:

sibling(A, B) :-
    dif(A, B),
    father(F, A),
    father(F, B).

In case we consider a family with half-siblings, we can implement a predicate where we consider a sibling/2 by checking both the mother/2 and father/2.