1

I am trying to find a list of all the family members for the kth generation of a given family. We are given the first members of the family and the family tree as well. Below is my KB for the same and also the implementation. I am not able to figure how I can get the kth generation for this family tree? Lets say k = 4. One way of doing it is that I can find 4 times the relation like this:

4thGen(X,Y) :- parent(X,A),parent(A,B),parent(B,C),parent(C,Y)

but this is not the correct way for this I believe.

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

female(lina).
female(julia).
female(rosa).
female(eva).
female(ruth).
female(silvia).
female(ida).
female(irma).
female(olga).
female(marie).
female(tina).

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).






father(X,Y):-parent(X,Y),male(X).
grandfather(X,Y):-father(X,Z),parent(Z,Y).
halfer
  • 19,824
  • 17
  • 99
  • 186
CodeHunter
  • 2,017
  • 2
  • 21
  • 47

1 Answers1

2

In order to make more general predicates you can use recursion:

kthGen(X,Y,1):-parent(X,Y).
kthGen(X,Y,K) :- parent(X,A),K1 is K-1,kthGen(A,Y,K1).

Here are some queries:

?- kthGen(alex,julia,1).
true ;
false.

?- kthGen(alex,peter,2).
true ;
false.

?- kthGen(alex,bruno,2).
false.

?- kthGen(alex,bruno,3).
true ;
false.

Two important things to notice here:

  • Firstly your graph is directed (e.g if parent(A,B) you can't have parent(B,A) ), this matters because if it was undirected you could fall into cycles (e.g kthGen(alex,julia,4). would succeed due to the path alex->julia->alex->julia ,you could solve that by adding another list that keeps track persons you've visited).
  • Secondly if you try:

    ?- kthGen(alex,bruno,K). ERROR: Arguments are not sufficiently instantiated ERROR: In: ERROR: [8] kthGen(alex,bruno,_7630) ERROR: [7] <user>

So the predicate kthGen/3 does not have relational behavior. You could use library CLPFD:

:- use_module(library(clpfd)).

kthGen(X,Y,1):-parent(X,Y).
kthGen(X,Y,K) :- parent(X,A),K1 #= K-1,kthGen(A,Y,K1).

Now if you try:

?- kthGen(alex,bruno,K).
K = 3 ;
false

much better !!.


UPDATE

In order to find kth generation persons from a person X you could modify accordingly:

:- use_module(library(clpfd)).

kthGen(Y,1,[Y]).
kthGen(X,K,[X|T]) :- parent(X,A),K1 #= K-1,kthGen(A,K1,T).

Example:

?- kthGen(alex,4,L).
L = [alex, julia, peter, bruno] ;
L = [alex, julia, peter, georg] ;
L = [alex, julia, peter, irma] ;
L = [alex, rosa, silvia, otto] ;
L = [alex, rosa, silvia, pascal] ;
false.

This gives all the possible 4th generations from alex. If you want to find more complex e.g 4th gen from alex or lina you could find it separately an write another predicate that concatenates the results...


UPDATE 2

In last update I keep track of all persons until 4th generation. If you want just 4th gen simply modify like:

kthGen(Y,1,[Y]).
kthGen(X,K,L) :- parent(X,A),K1 #= K-1,kthGen(A,K1,L).

Examlpe:

?- kthGen(alex,4,L).
L = [bruno] ;
L = [georg] ;
L = [irma] ;
L = [otto] ;
L = [pascal] ;
false.

Now if you want all results in one list:

?- findall(X,kthGen(alex,4,[X]),L).
L = [bruno, georg, irma, otto, pascal].
coder
  • 12,832
  • 5
  • 39
  • 53
  • Great one! But how do I combine all these people in a single list, which at the end of the query gives me all `kth` gen members? For e.g., for k = 4, it should return `[Bruno, georg, Irma, otto, pascal]` – CodeHunter Oct 07 '17 at 09:33
  • I was able to achieve similar result with my lineage function as well, but your way of implementation is far better than mine was. But I still couldn't figure out a way to get all people of a given generation. One way I tried to do is to run through all family members and add to list whichever satisfied my current criteria. But, this is very inefficient and I think there might be better way for that? – CodeHunter Oct 07 '17 at 09:37
  • How is it supposed to return `[Bruno, georg, Irma, otto, pascal]` since Bruno is not parent of georg?? – coder Oct 07 '17 at 09:56
  • Bruno and georg are both 4th generation of the family tree if you consider alex and lina as first generation. Bruno and georg are coming from peter who is the 3rd in family tree generation. So, both bruno and georg will be of 4th gen. They are step brothers. – CodeHunter Oct 07 '17 at 09:59
  • To be more specific in what query do you expect the list above? kthGen(bruno,pascal,4)?? – coder Oct 07 '17 at 10:02
  • `kthGen(alex,lina,4,L)` where alex and lina are the first generation and counting from them, we need the 4th generation to be displayed in the list `L`. – CodeHunter Oct 07 '17 at 10:04
  • Ok I may misunderstood since in your example: `4thGen(X,Y) :- parent(X,A),parent(A,B),parent(B,C),parent(C,Y)` X,Y are X the start Y the end but now you're asking alex,lina to be the start (both 1st gen) ... I will edit accordingly but is this what you want to find: kthGen(X,Y,..) X,Y will be in same generation?? – coder Oct 07 '17 at 10:08
  • Also this diesn't make sense to me since if you want to find 4th gen from alex,lina why not just find kthGen(alex,4,L) and kthGen(lina,4,L)? which would be much simpler? – coder Oct 07 '17 at 10:11
  • yes. X and Y would be in same generation. To make matter simple, we can assume X and Y as alex and lina respectively. One way I thought was using all the output we get from descendants(Ds,X) where Ds will contain all descendants of X. We can then pass that list to check for each entry whether it is actually the fourth generation of X or not. Does it sound efficient? – CodeHunter Oct 07 '17 at 10:11
  • yes, kthGen(alex,4,L) would also make same sense actually. – CodeHunter Oct 07 '17 at 10:12
  • cool! Now we just need to retrieve the last element from each of these lists and append it in L. Thanks a lot! – CodeHunter Oct 07 '17 at 10:19