如何在 Prolog 中找到家谱的第 k 代?

How to find kth generation of a family tree in Prolog?

我正在尝试查找给定家庭 kth 代的所有家庭成员的列表。我们也获得了家庭的第一批成员和家谱。下面是我的知识库,同样也是实现。我不知道如何获得此家谱的 kth 代?让我们说 k = 4。一种方法是我可以找到 4 倍这样的关系:

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

但我认为这不是正确的方法。

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

为了制作更通用的谓词,您可以使用递归:

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

以下是一些查询:

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

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

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

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

这里要注意两件重要的事情:

  • 首先你的图表是定向(例如如果parent(A,B)你不能有parent(B,A)),这很重要因为如果它是undirected 你可能会陷入循环(例如 kthGen(alex,julia,4). 由于路径 alex->julia->alex->julia 会成功,你可以通过添加另一个列表来解决这个问题,该列表可以跟踪你访问过的人)。
  • 其次如果你尝试:

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

所以谓词 kthGen/3 没有关系行为。您可以使用库 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).

现在如果你尝试:

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

好多了!!


更新

为了从一个人 X 中找到第 k 代人,您可以相应地修改:

:- use_module(library(clpfd)).

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

示例:

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

这给出了 alex 所有可能的第 4 代。如果你想找到更复杂的,例如 alex 或 lina 的第 4 代,你可以单独找到它,写另一个连接结果的谓词...


更新 2

在上次更新中,我一直跟踪所有的人,直到第 4 代。如果你只想要第 4 代,只需修改如下:

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

示例:

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

现在,如果您希望所有结果都在一个列表中:

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