SWI Prolog与GNU Prolog - SWI下的CLP(FD)问题

时间:2017-12-26 06:24:01

标签: prolog swi-prolog clpfd gnu-prolog clp

我在Prolog中写了一个快速谓词,尝试了CLP(FD)及其解决方程组的能力。

problem(A, B) :-
    A-B #= 320,
    A #= 21*B.

当我在SWI中调用它时,我得到:

?- problem(A,B).
320+B#=A,
21*B#=A.

在GNU中,我得到了正确答案:

| ?- problem(A,B).

A = 336
B = 16

这里发生了什么?理想情况下,我希望在SWI中获得正确的结果,因为它是一个更加强大的环境。

1 个答案:

答案 0 :(得分:5)

这是一个很好的观察。

乍一看,毫无疑问,它似乎是SWI 的缺点,它无法像GNU Prolog一样强烈传播。

然而,这里还有其他因素在起作用。

核心问题

首先,请在GNU Prolog中尝试以下查询:

| ?- X #= X.

声明性地,查询可以读作:X整数。原因是:

  • (#=)/2仅适用于整数
  • X #= X不会以任何方式约束整数X的域。

然而,至少在我的机器上,GNU Prolog回答:

X = _#0(0..268435455)

所以,事实上,整数X已成为有限,即使我们没有以任何方式限制它!

为了比较,我们在例如SICStus Prolog中获得:

?- X #= X.
X in inf..sup.

这表明整数X的域以任何方式受到限制。

使用CLP(Z)

复制结果

让我们平衡竞争环境。我们可以通过人工将变量的域限制为,例如,有限区间0..2 64 ,用SWI-Prolog模拟上述情况:

?- problem(A, B),
   Upper #= 2^64,
   [A,B] ins 0..Upper.

作为回应,我们现在使用SWI-Prolog:

A = 336,
B = 16,
Upper = 18446744073709551616.

因此,将域限制为有限整数子集使我们能够使用SWI-Prolog的CLP(FD)求解器或其后继者{GNP Prolog复制我们知道的结果。 {3}}

原因

CLP(Z)的目标是在高级声明性替代的用户程序中完全替换低级算术谓词,可以用作真正的关系和当然也作为 drop-in 替换。因此,CLP(Z)支持无界整数,它们可以增长到计算机内存允许的大小。在CLP(Z)中,所有整数变量的默认域是所有整数的集合。这意味着只要其中一个域是无限的,就不会执行为有界域应用的某些传播。

例如:

?- X #> Y, Y #> X.
X#=<Y+ -1,
Y#=<X+ -1.

这是条件答案:原始查询可以满足 iff 所谓的残差约束是可以满足的。

相比之下,我们得到了有限域:

?- X #> Y, Y #> X, [X,Y] ins -5000..2000.
false.

只要所有域都是有限的,我们希望所涉及的系统具有大致相同的传播强度。

固有限制

一般来说,求解整数方程是CLP(Z)。因此,对于CLP(Z),我们知道 no 决策算法始终会产生正确的结果。

出于这个原因,您有时会得到残留约束而不是无条件答案。在有限整数集上,方程式当然是可判定的:如果所有域都是有限的并且您没有得到具体的解决方案作为答案,那么使用枚举谓词中的一个来穷举寻找解决方案。

在可以推理无限整数集的系统中,你迟早会和必然遇到这样的现象。