简单传递性检查的不必要的谓词定义?

时间:2017-02-27 21:50:26

标签: prolog transitivity

对于给定的事实:

trust_direct(p1, p2).
trust_direct(p1, p3).
trust_direct(p2, p4).
trust_direct(p2, p5).
trust_direct(p5, p6).
trust_direct(p6, p7).
trust_direct(p7, p8).
trust_direct(p100, p200).

此解决方案:

trusts(A, B) :-
        trust_direct(A, B).
trusts(A, C) :-
        trust_direct(A, B),
        trusts(B, C).

...用于改善Prolog: check transitivity for simple facts中描述的堆栈溢出问题。

解决方案本身就像一个魅力。但是,我对双倍trust_direct(A, B)感到困惑。为什么这有必要?

trusts(A, C)谓词是否已涵盖trust_direct(A, B)关系?

1 个答案:

答案 0 :(得分:4)

这是一个很好的问题!

为了说明原因,我使用以下定义来启用声明性调试

:- op(920,fy, *).

*_.

我现在可以将*置于任何目标之前将其概括为。声明地说,这意味着我可以简单地忽略目标(回想一下目标始终是约束,限制任何解决方案)。我当然也可以简单地评论目标,但这对于子句体的 last 目标来说效果不佳。

现在考虑你的定义:

trusts(A, B) :-
        trust_direct(A, B).
trusts(A, C) :-
        trust_direct(A, B),
        trusts(B, C).

现在,为了回答你非常合理的问题,假设我们只有有第二个条款,即:

trusts(A, C) :-
        trust_direct(A, B),
        trusts(B, C).

为了让我们的生活更简单,我现在概括这个定义如下:

trusts(A, C) :-
        * trust_direct(A, B),
        trusts(B, C).

> 片段,然后trusts(X, Y) 保留此定义。

我使用删除文本来表示不相关的目标(因为它们被推广)。所以,这在声明上等同于:

trusts(A, C) :-
        trusts(B, C).

让我们以声明的方式阅读

  

X持有如果 Y成立。

但是当 trusts(X, Y)举行时?当然(通过简单地再次应用定义),如果 trusts(A, C)成立。并且这样做时?当然(通过简单地应用定义), if ...等。从这里,很容易看出我们永远不会找到任何trusts(B, C)trusts(B, C)以便trusts(B', C')完全拥有

尽管事实上这实际上是原始子句的明显更通用的版本!因此,没有丝毫希望满足更具体的版本!

这回答了我们的问题:我们需要一个实际上持有的案例,以及比谈论A更简单的事情,这实际上是我们绝对的最简单的情况期待更通用的关系C来保持

因此从这种情况开始是很自然的,并说:

  

如果 trusts(A, C)持有,则 trust_direct/2成立。

在Prolog:

trusts(X, Y) :- trust_direct(X, Y).

这正是你的第一个条款!