swi prolog abs操作员未在clpfd模块中工作

swi prolog abs操作员未在clpfd模块中工作,prolog,swi-prolog,clpfd,Prolog,Swi Prolog,Clpfd,我正在用swi prolog中的CLPFD库进行一些玩具测试 有人知道为什么下面的程序不起作用吗 start(X,Y):- Vars = [X,Y], Vars ins 1..3, abs(X-Y) #>= 2, X #>= Y, nl, write([X,Y]), nl. start(X,Y)的预期答案是X=3和Y=1。但是,swi prolog向我指出了多个答案。如果我更换,程序工作正常 abs(X-Y) #>= 2 借 我的问题是

我正在用swi prolog中的CLPFD库进行一些玩具测试

有人知道为什么下面的程序不起作用吗

start(X,Y):- 
   Vars = [X,Y],
   Vars ins 1..3,
   abs(X-Y) #>= 2,
   X #>= Y,
   nl,
   write([X,Y]), nl.
start(X,Y)的预期答案是X=3和Y=1。但是,swi prolog向我指出了多个答案。如果我更换,程序工作正常

abs(X-Y) #>= 2


我的问题是我是否以正确的方式使用abs运算符。

首先,约束和副作用不会聚集在一起。相反,只需坚持程序的纯部分:

start(X,Y):- 
   Vars = [X,Y],
   Vars ins 1..3,
   abs(X-Y) #>= 2,
   X #>= Y.
现在,查询您的关系:

?- start(X,Y).
X in 1..3,
X#>=Y,
abs(X-Y)#>=2,
Y in 1..3.
答案是有条件的:

是的,
X
Y
都有解决方案,只要所有这些条件都成立

要获得实际值,必须消除所有这些条件。您有几个选择:

在这种情况下,您可以使用
标签/2

?- start(X,Y), labeling([], [X,Y]).
X = 3,
Y = 1.
因此,只有一个解决方案。光是
clpfd
-solver不够强大,无法得出这个结论,它需要一些额外的帮助

最好使用
合同/1

?- start(X,Y), clpfd:contracting([X,Y]).
X = 3,
Y = 1.
与标记不同,收缩尝试在不进行(可见)搜索的情况下减小域的大小。这会使解算器更强大

解算器功能不够强大的原因

  • 在非常普遍的情况下,解决这样的算术问题是非常困难的

  • 在更具体的情况下,算法的成本会非常高。事实上,房间里不止一个

  • 即使是更简单的算法,在实现工作和运行时方面都非常昂贵

  • 对于许多情况,解算器归结为在一个约束1内保持一致性。因此,在不同约束之间“沟通”的唯一方式是变量域

在您的情况下,abs约束允许更多的解决方案

?- [X,Y]ins 1..3, abs(X-Y)#>=2, labeling([],[X,Y]).
X = 1,
Y = 3 ;
X = 3,
Y = 1.

?- [X,Y]ins 1..3, X-Y#>=2, labeling([],[X,Y]).
X = 3,
Y = 1.
您期望的是额外的约束
X#>=Y
会有所帮助。唉,具体的一致性机制太弱了。甚至连
X#>Y
都没有帮助:

?- [X,Y]ins 1..3, abs(X-Y)#>=2, X#>Y.
X in 2..3,
Y#=<X+ -1,
abs(X-Y)#>=2,
Y in 1..2.
请注意abs是如何解析的

使用SICStus具有相同的强度:

| ?- X in 1..3, Y in 1..3, abs(X-Y)#>=2, X#>Y.
X = 3,
Y = 1 ? ;
no


1请注意,我避免使用局部一致性而不是全局一致性的概念,因为全局一致性通常也仅指一个“全局”约束内的一致性。

但是,当abs(X-Y)>=2被X-Y>=2替换时,为什么clpfd解算器提供实例化?答案不应该是一样的?为什么我们需要前者的标签而不需要后者的标签?SWI中的CLP(FD)非常弱。我建议您改用CLP(Z)。
?(A)
,而不是
#(A)
| ?- assert(clpfd:full_answer).
yes
| ?- X in 1..3, Y in 1..3, abs(X-Y)#>=2.
Y+_A#=X,
X in 1..3,
Y in 1..3,
_A in{-2}\/{2} ? ;
no
| ?- X in 1..3, Y in 1..3, abs(X-Y)#>=2, X#>Y.
X = 3,
Y = 1 ? ;
no
| ?- X in 1..3, Y in 1..3, abs(X-Y)#>=2, X#>Y.
X = 3,
Y = 1 ? ;
no