在SWI-Prolog中,以下查询给出了以下结果:
?- X mod 2 #= 0, X mod 2 #= 0.
X mod 2#=0,
X mod 2#=0.
虽然正确,但显然不需要第二个约束
类似地:
?- dif(X,0), dif(X,0).
dif(X, 0),
dif(X, 0).
有没有办法避免这种重复约束? (显然,最正确的方法是不编写导致这种情况的代码,但并不总是这么容易。)
答案 0 :(得分:4)
您可以避免发布冗余约束,也可以使用类似setof/3
的构造删除它们。两者都是特定于实现的。 SICStus提供了用于此目的的最佳界面。其他实现,如YAP或SWI或多或少复制了该接口,省略了some essential parts。克服SWI缺陷的recent attempt被拒绝了。
在SICStus中,您可以使用frozen/2
来实现此目的:
| ?- dif(X,0), frozen(X,Goal).
Goal = prolog:dif(X,0),
prolog:dif(X,0) ? ;
no
| ?- X mod 2#=0, frozen(X, Goal).
Goal = clpfd:(X in inf..sup,X mod 2#=0),
X mod 2#=0,
X in inf..sup ? ;
no
否则,copy_term/3
可能已经足够好了,前提是约束条件没有太多相互关联。
在这里,类似于setof的构造以及call_residue_vars/1
和copy_term/3
可能是最好的方法。同样,最初的实现是在SICStus ....
答案 1 :(得分:3)
仅对于dif/2
,可以在不诉诸任何内部的情况下测试蕴涵:
difp(X,Y) :-
( X \= Y -> true
; dif(X, Y)
).
答案 2 :(得分:2)
由于CLP标记不是SMT,因此很少有约束编程系统实现与分辨率定理证明中的因子分解相关的收缩。收缩是structural rule,它的内容如下,假设约束以(| - )/ 2之前以否定形式存储。
G, A, A |- B
------------ (Left-Contraction)
G, A |- B
我们也可以将它扩展到两个A的推导等价的情况。最有可能的是,这是没有实现的,因为它很昂贵。例如,Jekejeke Minlog已经实现了CLP(FD)的收缩,即有限域。我们找到类似于OP的第一个查询的查询:
?- use_module(library(finite/clpfd)).
% 19 consults and 0 unloads in 829 ms.
Yes
?- Y+X*3 #= 2, 2-Y #= 3*X.
3*X #= -Y+2
?- X #< Y, Y-X #> 0.
X #=< Y-1
基本上我们归一化为A1 * X1 + .. + An * Xn#= B分别为A1 * X1 + .. + An * Xn#=&lt; B其中gcd(A1,..,An)= 1并且X1,..,Xn是词法排序的,然后我们检查约束存储中是否已存在相同的约束。但对于CLP(H),即Herbrand域名术语,我们还没有实现收缩。我们仍在考虑一种有效的算法:
?- use_module(library(term/herbrand)).
% 2 consults and 0 unloads in 35 ms.
Yes
?- neq(X,0), neq(X,0).
neq(X, 0),
neq(X, 0)
dif / 2的收缩意味着通过dif / 2约束中定义的实例化实现一种(==)/ 2。即,我们需要在将dif / 2约束中定义的变量和术语与约束存储中已有的所有其他dif / 2约束配对后应用递归测试。测试包含而不是收缩也会更有意义。
在一些适当的索引技术的帮助下,实现dif / 2的收缩或包含可能是唯一可行的。在Jekejeke Minlog中,例如对于CLP(FD),我们对X1进行索引,但我们还没有实现CLP(H)的一些索引。我们首先可能需要弄清楚的是dif / 2约束的正常形式,另请参阅此问题here。