我正在使用clpfd库在(swi)prolog中使用约束。
我正在尝试识别一组约束何时封装或包含另一组约束,例如当前者为真时,X <4封装X <7,后者为真。这可以使用逻辑蕴涵来轻松表示。但是,我无法得到#==&gt;运算符给我我想要的结果,所以我求助于不使用(Co1#/ \#\ Co2),其中Co1和Co2是约束。这适用于个别约束,但我想将约束的连接传递给Co1和Co2。
现在就是这个问题。当我尝试
X#<7 #/\ #\X#<4.
我回来了
X in 4..6,
X+1#=_G822,
X+1#=_G834,
_G822 in 5..7,
_G834 in 5..7.
(奇怪的是,在Sicstus中执行此操作会导致分段错误)
当我通过时
X#<7,X#<4
我得到了所需的
X in inf..3.
显然,我无法将后者传递给(Co1#/ \#\ Co2),但前者并没有给我我想要的结果。任何人都可以解释为什么这两种方法产生不同的结果,以及我如何让前者像后者那样行事?
答案 0 :(得分:4)
一般来说,对整数的一般算术约束的假设是不可判定的,因此所有正确的求解器都有固有的限制,超过这些限制,它们必须延迟它们的答案,直到知道更多。如果你知道你的域是有限的,你可以发布域,然后尝试使用约束求解器的标签/ 2谓词找到会使含义无效的反例。还要考虑Q上的线性不等式是可判定的,并且SWI-Prolog的库(clpq)对它们来说是完整的。因此,您可以使用以下命令在CLP(Q)中尝试约束:
?- use_module(library(clpq)).
true.
?- { X < 4, X >= 7 }.
false.
并且看到Q中没有这样的反例(因此也不存在于Z中),因此其含义成立。
答案 1 :(得分:2)
看来你正在处理CLP(FD)。这些求解器区分了解决约束问题的设置阶段和标记阶段。
CLP(FD)求解器在设置阶段不能完全减少问题。因为它有机会在标记阶段减少可变范围。因此,在设置过程中可能会出现一个问题,可以通过其他求解器将其减少为“否”,但不会使用CLP(FD)求解器。只有在标记过程中才会检测到“否”。
在设置阶段进行多少减少很大程度上取决于给定的CLP(FD)系统。一些CLP(FD)系统在设置阶段进行更多的减少,而其他的则做得更少。例如,GNU Prolog使用一些索引传播,而SWI Prolog则没有。所以我们找到了例如,不是你的例子:
SWI-Prolog的:
?- X #< Y, Y #< Z, Z #< X.
Z#=<X+ -1,
X#=<Y+ -1,
Y#=<Z+ -1.
GNU Prolog:
?- X #< Y, Y #< Z, Z #< X.
(7842 ms) no
此外,由于您正在使用具体化的约束,因此它还取决于具体设置的巧妙程度。但我想在目前的情况下它只是传播的问题。我们现在找到你的例子:
SWI-Prolog的:
?- X #< 4 #==> X #< 7.
X+1#=_G1330,
X+1#=_G1342,
7#>=_G1330#<==>_G1354,
_G1354 in 0..1,
_G1377#==>_G1354,
_G1377 in 0..1,
4#>=_G1342#<==>_G1377.
GNU Prolog:
?- X #< 4 #==> X #< 7.
X = _#22(0..268435455)
在设置阶段进行更多缩减并将更多工作留给标签阶段之间存在权衡。整个事情也取决于给定的例子。但是当您在设置旁边标记时,您将看不到结果方面的任何差异:
SWI-Prolog的:
?- X in 0..9, X #< 4 #==> X #< 7, label([X]).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5 ;
X = 6 ;
X = 7 ;
X = 8 ;
X = 9.
GNU Prolog:
?- fd_domain(X,0,9), X #< 4 #==> X #< 7, fd_labeling([X]).
X = 0 ? ;
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
X = 4 ? ;
X = 5 ? ;
X = 6 ? ;
X = 7 ? ;
X = 8 ? ;
X = 9
我没有使用SICStus Prolog或B-Prolog进行测试。但我猜他们会在SWI-Prolog和GNU Prolog的某个地方表现得很好。
如果您的域名真的是FD,那么CLP(Q)不是真正的替代品,因为它会错过一些“否”减少,CLP(FD)不会错过。例如,以下在CLP(FD)中是不可满足的,但在CLP(Q)中是可满足的:X = Y + 1, Y < Z, Z < X.
再见