how to avoid duplicates here? - prolog

I have these predicates:
male(roelof).
male(mans).
male(ronald).
male(jan).
female(chantal).
female(marie).
female(gerda).
female(dagmar).
female(denise).
female(kimberly).
parent(mans,gerda).
parent(mans,roelof).
parent(marie,gerda).
parent(marie,roelof).
parent(dagmar,denise).
parent(dagmar,kimberly).
parent(ronald,denise).
parent(ronald,kimberly).
parent(chantal,tamara).
parent(roelof,tamara).
parent(jan,chantal).
parent(jan,dagmar).
father_child(Father, Child) :-
parent(Father, Child),
male(Father).
mother_child(Mother, Child) :-
parent(Mother, Child),
female(Mother).
child_father_mother(Child, Father, Mother) :-
father_child(Father, Child),
mother_child(Mother, Child).
same_father(Child, Sibling) :-
father_child(Father, Child),
father_child(Father, Sibling).
same_mother(Child, Sibling) :-
mother_child(Mother, Child),
mother_child(Mother, Sibling).
siblings(X,Y) :-
( same_father(X, Y),
X \= Y
; same_mother(X, Y),
\+ same_father(X, Y)
).
display_siblings(Person) :-
findall(Person-Y, siblings(Person,Y), Sibs),
display_the_siblings(Sibs).
display_the_siblings([]) :-
write('Er zijn geen zussen/broers bekend').
display_the_siblings([X-Y]) :-
write('The enigste broer of zuster is '),
write(Y).
display_the_siblings([XY0,XY1|XYs2]) :-
XYs0=[XY0,XY1|XYs2],
write('Alle zusterparen zijn : \n '),
forall(( member(X - Y,XYs0)
),( format('~w en ~w. \n',[X,Y])
)).
It works fine but if you do display_siblings(X) you will see duplicates like this
Person 1 - Person 2
Person 2 - Person 1
How can I change this so the duplicates will not show up.
I know I can change findall to setof but then I see no output at all.
Roelof
Edit 1: #< works but it also means that display(kimberly) fails because Kimberly is further on the alphabet then denise. Can I not use the same trick as this topic : How can I prevent duplicates in prolog.

the simplest way should be to break the symmetry, for instance
...
findall(Person-Y, (siblings(Person,Y), Person #< Y), Sibs),
...

Related

Prolog: duplicated family member

I have the following prolog code:
man(otto).
man(horst).
man(dieter).
man(hans).
man(stefan).
man(martin).
woman(gerda).
woman(ursula).
woman(petra).
woman(susann).
father(otto, dieter).
father(otto, hans).
father(horst, susann).
father(dieter, stefan).
father(dieter, martin).
mother(gerda, dieter).
mother(gerda, hans).
mother(ursula, susann).
mother(petra, stefan).
mother(susann, martin).
parent(Father, Child) :- father(Father, Child).
parent(Mutter, Child) :- mother(Mutter, Child).
child(Child, Parent) :- parent(Parent, Child).
grantparent(Grantparent, Grantchild) :-
parent(Grantparent, Child),
parent(Child, Grantchild).
grantchild(Grantchild, Grantparent) :- grantparent(Grantparent, Grantchild).
son(Son, Parent) :-
parent(Parent, Son),
man(Son).
daughter(Daughter, Parent) :-
parent(Parent, Daughter),
woman(Daughter).
brother(Brother, Sibling) :-
parent(Parent, Brother),
parent(Parent, Sibling),
man(Brother),
Brother \== Sibling.
uncle(Uncle, Person) :-
bruder(Uncle, Parent),
parent(Parent, Person).
The most of my queries match. But when I try to figure out what the brother of 'dieter' is, 'hans' will be printed two times.
?- brother(dieter, Brother).
Brother = hans ;
Brother = hans ;
false.
Also when I ask, what is the uncle of 'martin'.
?- uncle(Uncle, martin).
Uncle = hans ;
Uncle = hans ;
false.
Can you help and tell me what's the problem with my family?
The parent/2 predicate will cause duplicate, since:
father(otto, dieter),
father(otto, hans).
holds, and;
mother(gerda, dieter),
mother(gerda, hans).
Holds. This will thus result two possible traces where dieter and hans are brothers.
If the families are "simple" families, where there are no half siblings. You can pick one of the two. For example:
brother(Brother, Sibling) :-
father(Parent, Brother),
father(Parent, Sibling),
man(Brother),
Brother \== Sibling.
If you want to exclude half-siblings, you should, like you say yourself, check both the father and the mother:
brother(Brother, Sibling) :-
father(Father, Brother),
father(Father, Sibling),
mother(Mother, Brother),
mother(Mother, Sibling),
man(Brother),
Brother \== Sibling.
Another approach is to define siblings/2 as
siblings(S1, S2) :-
parent(P, S1),
parent(P, S2),
S1 #< S2.
This avoids generating both siblings(dieter,hans) and siblings(hans,dieter).
(The brother/2 relation can then be defined using siblings/2.)

Family tree in Prolog

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.

why does this not display the right answer

I have these facts and rules :
male(roelof).
male(mans).
male(ronald).
male(jan).
female(chantal).
female(marie).
female(gerda).
female(dagmar).
female(denise).
female(kimberly).
parent(mans,gerda).
parent(mans,roelof).
parent(marie,gerda).
parent(marie,roelof).
parent(dagmar,denise).
parent(dagmar,kimberly).
parent(ronald,denise).
parent(ronald,kimberly).
parent(chantal,tamara).
parent(roelof,tamara).
parent(jan,chantal).
parent(jan,dagmar).
father_child(Father, Child) :-
parent(Father, Child),
male(Father).
mother_child(Mother, Child) :-
parent(Mother, Child),
female(Mother).
child_father_mother(Child, Father, Mother) :-
father_child(Father, Child),
mother-child(Mother, Child).
same_father(Child, Sibling) :-
father_child(Father, Child),
father_child(Father, Sibling).
same_mother(Child, Sibling) :-
mother_child(Mother, Child),
mother_child(Mother, Sibling).
siblings(Child, Sibling) :-
same_father(Child, Sibling),
Child \= Sibling.
siblings(Child, Sibling) :-
same_mother(Child, Sibling),
Child \= Sibling.
display_siblings(X,Y) :-
setof(X-Y, (siblings(X,Y), \+X=Y), Sibs),
member((X-Y,Y), Sibs),
\+ (Y#<X, member((Y,X), Sibs)).
But when I do display_siblings I expected to see roelof-gerda.
But the output is only x=roelof
What did I do wrong.
Im a beginner at Prolog and try to understand how this works.
Roelof
Edit 1: Could this be a solution: How can I prevent duplicates in prolog
Edit 2: I will do but I still do not understand why 'setof(X-Y, (siblings(X,Y), X #< Y), Sibs),write(Sibs).' is wrong. It works in both cases display_'siblings(gerda,X)' and 'display_siblings(X,Y)'
Most of your problem lies in your display_siblings predicate:
display_siblings(X,Y) :-
setof(X-Y, (siblings(X,Y), \+X=Y), Sibs),
member((X-Y,Y), Sibs),
\+ (Y#<X, member((Y,X), Sibs)).
In the second line, the \+X=Y is superfluous since siblings already enforces that they are different. So that can be:
setof(X-Y, siblings(X,Y), Sibs),
The next line is querying whether (X-Y,Y) is a member of Sibs. However, Sibs consists of X-Y terms which will never match an (X-Y,Y) term. So this call to member will always fail. It should probably be:
member(X-Y, Sibs),
And then the last line is overly complex if all you want to do is eliminate symmetrical duplicates. You can simply use X #< Y and for efficiency, make this part of the setof check:
display_siblings(Sibs) :-
setof(X-Y, (siblings(X,Y), X #< Y), Sibs).
This will yield:
?- display_siblings(Sibs).
Sibs = [chantal-dagmar, denise-kimberly, gerda-roelof].
If you want to select all of the siblings for a given person and still avoid the symmetry redundancies, you may need to process out those redundancies after the setof:
display_siblings(X, Sibs) :-
setof(A-B, ((X = A ; X = B), siblings(A,B)), SibPairs),
pack(SibPairs, Sibs).
pack([X-Y|T], Sibs) :-
pack(T, SibList),
( member(Y-X, SibList)
-> SibList = Sibs
; Sibs = [X-Y|SibList]
).
pack([], []).
?- display_siblings(gerda, Sibs).
Sibs = [roelof-gerda].

How to find blood relatives only in prolog

Using recursion i need to find all blood relatives of any person in the family tree.
My attempt so far has failed.
Here is my code, with my attempt at the bottom
female(helen).
female(debbie).
female(louise).
female(yvonne).
female(belinda).
female(heather).
male(john).
male(andrew).
male(barry).
male(daniel).
male(charles).
parent(helen, debbie).
parent(helen, barry).
parent(helen, louise).
parent(john, debbie).
parent(john, barry).
parent(andrew, louise).
parent(debbie, yvonne).
parent(debbie, daniel).
parent(barry, charles).
parent(barry, belinda).
parent(louise, heather).
mother(X, Y) :-
female(X),
parent(X, Y).
father(X, Y) :-
male(X),
parent(X,Y).
child(X, Y) :-
parent(Y, X).
daughter(X, Y) :-
parent(Y, X),
female(X).
son(X, Y) :-
parent(Y,X),
male(X).
sister(X, Y) :-
female(X),
parent(Q,X),
parent(Q,Y).
brother(X, Y) :-
male(X),
parent(Q,X),
parent(Q,Y).
sibling(X, Y) :-
parent(Q,X),
parent(Q,Y),
X\=Y.
uncle(X, Y) :-
parent(P,Y),
brother(X,P).
aunt(X, Y) :-
parent(P,Y),
sister(X,P).
cousin(C, Cousin):-
parent(Parent,C),
sibling(Parent,AU),
child(Cousin,AU).
%Here is Relative
relative(An, Re):-
An\=Re,
parent(An, Re);
sibling(An, Re).
relative(An, Rela):-
parent(An, Child);
sibling(An, Rela),
relative(Child, Rela),
An\=Rela, C\=Rela.
Sort of works, but gets stuck in an infinite loop at the end.
Thanks.
not sure about 'relatives' (any person bound reachable in a parent/child relation ?), but your definition seems more complex than needed ( do you know what ; does ?).
I tried
relative(An, Re):-
parent(An, Re).
relative(An, Rela):-
parent(An, C),
relative(C, Rela).
that yields
16 ?- forall(relative(X,Y),writeln(X:Y)).
helen:debbie
helen:barry
helen:louise
john:debbie
john:barry
andrew:louise
debbie:yvonne
debbie:daniel
barry:charles
barry:belinda
louise:heather
helen:yvonne
helen:daniel
helen:charles
helen:belinda
helen:heather
john:yvonne
john:daniel
john:charles
john:belinda
andrew:heather
true.
edit I tried another relation, using a generalized parent/2, but still too permissive.
relative(Pers, Re):-
ancestor(Re, Pers) ; sibling(Pers, Re) ; cousin(Pers, Re) ; uncle(Re, Pers) ; aunt(Re, Pers).
ancestor(Anc, Pers) :- parent(Anc, Pers).
ancestor(Anc, Pers) :- parent(Anc, P), ancestor(P, Pers).
Maybe cousin/2 is too permissive also. Here is the graph
I guess that heather should have only luise,helen,andrew as relatives. It's this true ?
edit given latest comment, seems that the definition could be right. I get
24 ?- setln(X,relative(heather,X)).
andrew
barry
belinda
charles
daniel
debbie
helen
louise
yvonne
true.
that is everyone is related to heather apart john.
Here's one way that works, but it will sometimes produce duplicates. Using setof will give the unique collection. I avoided the miscellaneous relations and stuck with descendent or parent.
descendent(A, B) :-
parent(B, A).
descendent(A, B) :-
parent(C, A),
descendent(C, B).
relative(A, B) :-
descendent(B, A).
relative(A, B) :-
descendent(A, B).
relative(A, B) :-
descendent(A, C),
descendent(B, C),
A \= B.
setof(A, relative(heather, A), Relatives).
Relatives = [andrew,barry,belinda,charles,daniel,debbie,helen,louise,yvonne]
If you don't have setof, you can use the findall/3 and sort/2 ISO predicates:
findall(A, relative(heather, A), R), sort(R, Relatives).
Note that the solutions presented so far assume that all of the relatives have unique names. A general case of dealing with relatives with the same first name (and possibly the same last name) you would need to track and compare lineages for differences.

Prolog: X is the grandfather of Y

Assume that the following facts are already entered into the Prolog database:
father(X, Y) // X is the father of Y
mother(X, Y) // X is the mother of Y
male(X) // X is a male
female(X) // X is a female
parent(X, Y) // X is a parent of Y
diff(X, Y) // X and Y are different
(1) Now add a Prolog rule for grandpa_of(X, Y) where "X is the grandfather of Y"
(2) Add another rule for sibling(X, Y) where "X is the sibling of Y"
My thoughts:
Question 1:
I am confused on how I can find the parents of the parents, all I have so far is
grandpa_of(X,Y) :- male(X), ...
Question 2:
sibling(X, Y) :- parent(P, X), parent(P, Y), diff(X, Y)
I think Jason means grandpa_of(X,Y) :- father(X,P), parent(P,Y).
It has been a long time... The first one is something like this:
grandpa_of(X, Y) :- father(X, P), father(P, Y).
Been too long... :-P
Hamad is the parent of Bilal, Laiba, and Marium.
Ali and Mona are Hamad's parents.
Musarat is also the parent of Bilal, Laiba, and Marium.
Kamran and Javeria are her parents.
Kamran and Javeria are also the parents of Salma, and Umar.
Parents are ancestors as are ancestors of parents.
Siblings share a parent.
mother
brother
grandfather
uncle
aunt
male(hamad).
male(bilal).
male(ali).
male(kamran).
male(umar).
female(laiba).
female(marium).
female(mona).
female(musarat).
female(javeria).
female(salma).
parents(ali, hamad).
parents(mona, hamad).
parents(kamran, musarat).
parents(javeria, musarat).
parents(kamran, salma).
parents(kamran, umar).
parents(javeria, salma).
parents(javeria, umar).
parents(hamad, bilal).
parents(hamad, laiba).
parents(hamad, marium).
parents(musarat, bilal).
parents(musarat, laiba).
parents(musarat, marium).
mother(X, Y) :-
parents(X, Y),
female(X),
write(X),
write(' is a mother of '),
write(Y),
nl.
brother(X, Y) :-
male(X),
x \= y,
parents(Z, X),
parents(Z, Y),
write(X),
write(' is a brother of '),
write(Y),
nl.
sister(X, Y) :-
female(X),
x \= y,
parents(Z, X),
parents(Z, Y),
write(X),
write(' is a sister of '),
write(Y),
nl.
grandfather(X, Y) :-
parents(X, P),
parents(P, Y),
male(X),
write(X),
write(' is grandfather of '),
write(Y),
nl.
uncle(X, Z) :-
brother(X, P),
parents(P, Z),
male(X),
write(X),
write(' is an uncle of '),
write(Z),
nl.
aunt(X, Z) :-
sister(X, P),
parents(P, Z),
female(X),
write(X),
write(' is an aunt of '),
write(Z),
nl.
%Sample program of X is a Grandfather of Y
%knowledgebase or database
female(amrita).
female(aroti).
female(manusi).
female(parboti).
male(susanta).
male(prasanta).
male(haran).
male(ratan).
male(srijit).
%clause
parent(manusi,susanta).
parent(ratan,amrita).
parent(aroti,amrita).
parent(haran,prasanta).
parent(haran,susanta).
parent(manusi,prasanta).
parent(susanta,srijit).
%rules
mother(X,Y):-parent(X,Y),female(X).
father(X,Y):-parent(X,Y),male(X).
sister(X,Y):-female(X),x==y,parent(Z,X),parent(Z,Y).
brother(X,Y):-male(X),x==y,parent(Z,X),parent(Z,Y).
grandparent(X,Y):-parent(X,Y),parent(Y,Z).
grandmother(X,Y):-mother(X,Y),parent(Y,Z).
grandfather(X,Y):-father(X,Y),parent(Y,Z).

Resources