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

时间:2017-10-07 08:26:41

标签: prolog family-tree

我正在尝试查找给定家庭的kth代的所有家庭成员的列表。我们也得到了家庭的第一批成员和家谱。下面是我的KB相同和实现。我无法弄清楚如何获得这个家谱的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).

1 个答案:

答案 0 :(得分:2)

为了制作更一般的谓词,你可以使用递归:

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)),这很重要,因为如果无向您可能会陷入周期(例如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或lina的第4代,你可以单独找到它,写一个连接结果的另一个谓词......

更新2

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

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.

现在,如果您想将所有结果放在一个列表中:

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