How to find blood relatives only in prolog

2019-09-10 01:35发布

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.

标签: prolog
2条回答
走好不送
2楼-- · 2019-09-10 02:29

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.

查看更多
We Are One
3楼-- · 2019-09-10 02:38

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

enter image description here

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.

查看更多
登录 后发表回答