如何在 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].
我正在尝试查找给定家庭 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].