0

我在知识库中有以下事实:

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

无论如何感谢您的建议。

4

1 回答 1

1

您应该避免在一个名称下引入类似数据的语句(如第一个示例中的linelineEqual)和代码(如第二个示例中的)。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

现在最困难的部分是命名方案,这样您就不会混淆所有这些谓词......</p>

你也可以用另一种方式来做。鉴于您寻求对称关系的传递闭包,它基本上是将所有节点(此处:线)的集合划分为可分离的子集。这种洞察力将帮助您编写比上述更有效的代码……但这已经超出了这个问题的范围。

于 2012-12-29T02:26:52.413 回答