我在知识库中有以下事实:
line(a,b). -- denotes the line determined by point a and b
line(c,d). -- denotes the line determined by point c and d
lineEqual(line(a,b),line(c,d)) -- denotes the length of two lines are equal
我想要另一个可以交换lineEqual / 2的两个参数的规则:
lineEqual(line(C, D), line(A, B)):-
lineEqual(line(A,B),line(C,D)).
不幸的是,该规则将在Prolog中创建一个无限循环。还有其他想法吗?
感谢您的更新。不确定我是否理解你的最后一条规则:
transitiveSymmetricRelPath(L1, L2, IntermediateNodes) :- symmetricRel(L1, L3),
\+member(L3, IntermediateNodes),
transitiveSymmetricRelPath(L1, L2, [L3 | IntermediateNodes]).
我可以想象,每当它试图剥离头节点时,如果它恰好与L1和L3相连,对吧?因此,如果我们最终得到一个空列表,那么我们可以使用此规则:
transitiveSymmetricRel(L1, L2) :- transitiveSymmetricRelPath(L1, L2, []).
但我真的没有得到的是你从哪里获得transitiveSymmetricRelPath / 3的中间节点的非空列表。我实际上用给定的事实rel(a,b)尝试了你的代码。相对(A,C)。并且它不返回transitiveSymmetricRel(b,c),也不返回transitiveSymmetricRel(c,b)。你能看一下吗?
非常感谢!
编辑: 我通过修改你的规则来实现它:
transitiveSymmetricRelPath(L2, L3, IntermediateNodes) :- symmetricRel(L1, L3),
\+member(L3, IntermediateNodes),
transitiveSymmetricRelPath(L1, L2, [L3 | IntermediateNodes]).
无论如何,谢谢你的建议。
答案 0 :(得分:1)
您应避免在单个名称下引入类似数据的语句(如第一个示例中的line
和lineEqual
)和代码(如第二个示例中的lineEqual
)。相反,请将您的数据库事实保存在其他名称下。然后,您可以例如定义:
areLinesEqual(L1, L2) :- linesEqual(L1, L2).
areLinesEqual(L1, L2) :- linesEqual(L2, L1).
通常,如果你有一个关系rel
,并且你想构建一个对称的传递闭包,你应该一次引入一个概念。例如:
symmetricRel(L1, L2) :- rel(L1, L2).
symmetricRel(L1, L2) :- rel(L2, L1).
transitiveSymmetricRel(L1, L2) :-
transitiveSymmetricRelPath(L1, L2, []).
transitiveSymmetricRelPath(L1, L2, _) :-
symmetricRel(L1, L2).
transitiveSymmetricRelPath(L1, L2, IntermediateNodes) :-
symmetricRel(L1, L3),
\+ member(L3, IntermediateNodes),
transitiveSymmetricRelPath(L1, L2, [L3 | IntermediateNodes]).
(请注意,在这里我们必须基本上在无向图中找到路径,并且必须小心以避免循环)。在您的情况下,也可能需要将line(A, B)
和line(B, A)
视为相同。为此,您应该再引入另一个间接层:
% to check two lines for identity
same(line(A, B), line(A, B)).
same(line(A, B), line(B, A)).
linesEqual2(L1, L2) :-
same(L1, LI1),
same(L2, LI2),
(linesEqual(LI1, LI2); linesEqual(LI2, LI1)).
...并在对称关系的定义中使用linesEqual2
代替linesEqual
。
现在困难的部分是一个命名方案,这样你就不会混淆所有这些谓词......
你也可以用另一种方式来做。鉴于您寻求对称关系的传递闭包,它基本上是所有节点集合(此处为:行)的分区为可分离的子集。这种见解将帮助您编写上述更有效的代码......但这已经超出了这个问题的范围。