Reputation: 43
I have the provided definition of descendent as below:
"a person who is in direct line to an ancestor. Eg: child, grandchild, great-grandchild, and forever"
and also other rules like:
...
childof(X, Y).
parent(X, Y).
grandchild(X, Y).
ancestor(X, Y).
...
So can I just simply write a rule as below,
descendant(X, Y):- ancestorof(Y, X).
or is there a better way of doing it?
Upvotes: 0
Views: 498
Reputation: 74267
This is a problem of tree traversal or graph traversal.
I would generalize an ancestor_of/3
predicate:
ancestor(Ancestor,Generations,Descendant)
Assuming you have, say, a set of facts like
parents( mother, father, child ).
On can say that a parent is either the mother or father of a child:
% P is a parent of C if P is either the mother or father of C.
parent(P,C) :- parents(P,_,C).
parent(P,C) :- parents(_,P,C).
And given the above, the solution might look like this:
ancestor(Ancestor, Generations, Descendant) :-
ancestor( Ancestor, 0, Generations, Descendant )
.
ancestor( A, N, G, D ) :- % A is an ancestor of D...
parent(A,D), % * if A is the immediate parent of D
G is N+1 % * in which case, tick the generation count
. % Easy!
ancestor( A, N, G, D ) :- % otherwise, A is an ancestor of D...
parent(A,X), % * if A is the immediate parent of somebody
X \= D, % * other than D
N1 is N+1, % * [ tick the generation count]
ancestor( X, N1, G, D ) % and that somebody is the ancestor of D
. % Also easy!
That allows us to say things like:
grandparent(A,C) :- ancestor(A,2,C).
great-grandparent(A,C) :- ancestor(A,3,C).
etc.
This will work for biological parentage, but if you are allowing non-biological parentage (e.g., step-parents and the like, then "I'm my own grandpa" is a possibility, and you will need to carry a list of visited nodes around so you can detect any cycles in the graph.
Try to figure out how to determine different degrees of kinship from this (what does a second cousin thrice removed look like?). You'll need to determine sibling status for starters.
Upvotes: 1