我需要创建一个谓词:
applyConstraints(L)
这对L中的变量应用约束,使得L中没有两个连续元素都是奇数,甚至我怎么能这样做?固定尺寸L很简单,但可变尺寸L呢? 我需要使用sicstus-prolog clpfd库来完成。
答案 0 :(得分:5)
% SICStus:
applyConstraints([]).
applyConstraints([X|Xs]) :-
X mod 2 #= R,
applyConstraints(Xs, R).
applyConstraints([], _).
applyConstraints([X|Xs], R) :-
X mod 2 #= S,
S #\= R,
applyConstraints(Xs, S).
% Query:
| ?- applyConstraints(L), length(L,2), !, domain(L,-2,2), labeling([],L).
L = [-2,-1] ? ;
L = [-2,1] ? ;
L = [-1,-2] ? ;
L = [-1,0] ? ;
L = [-1,2] ? ;
L = [0,-1] ? ;
L = [0,1] ? ;
L = [1,-2] ? ;
L = [1,0] ? ;
L = [1,2] ? ;
L = [2,-1] ? ;
L = [2,1] ? ;
no
答案 1 :(得分:2)
受@ MatsCarlsson版本的启发,我试图尽量减少所涉及的约束变量的数量:
applyConstraints(Xs) :-
S #\= R,
applyConstraints(Xs, S, R).
applyConstraints([], _, _).
applyConstraints([X|Xs], S, R) :-
X mod 2 #= S,
applyConstraints(Xs, R, S).
编辑:这个版本有一个目标applyConstraints([])
的缺陷,不容易看到。实际上,需要在SICStus中切换到full_answer
模式,如下所示:
| ?- applyConstraints([]).
yes
| ?- assertz(clpfd:full_answer).
yes
| ?- applyConstraints([]).
clpfd:(_A#\=_B),
_A in inf..sup,
_B in inf..sup ? ;
no
所以我们有这种无用的约束,可能会占用资源。 为克服这一缺陷,需要一些特殊的外壳:
applyConstraints([]).
applyConstraints([X|Xs]) :-
X mod 2 #= S,
S #\= R,
applyConstraints(Xs, R, S).
注1 - 在 SWI或 YAP中,无法直接切换完整应答模式。解决问题的唯一方法是将查询包装在call_residue_vars/2
中,如下所示:
?- applyConstraints([]).
true.
?- call_residue_vars(applyConstraints([]),RVs).
RVs = [_G794, _G797],
_G794#\=_G797.
注2 - 感谢@mat,自SWI 7.3以来有类似的功能(请记住,SWI 7需要--traditional
才能兼容):
?- set_prolog_flag(toplevel_residue_vars, true).
true.
?- applyConstraints([]).
% with detached residual goals
_G430#\=_G433.
(目前尚不清楚“分离”在这种背景下应该是什么意思,毕竟残余目标 是真的,以使答案成立。所以没有涉及分离。 )
答案 2 :(得分:1)
只考虑一对元素
applyConstraints([A,B|R]) :-
A mod 2 #\= B mod 2,
applyConstraints([B|R]).
applyConstraints([_]).
测试(使用SWI-Prolog库(clpfd),也许你需要用来自Sicstus的对应物替换ins / 2)
?- L=[X,Y,Z], applyConstraints(L), L ins 1..4, label(L).
L = [1, 2, 1],
X = Z, Z = 1,
Y = 2 ;
L = [1, 2, 3],
X = 1,
Y = 2,
Z = 3 ;
...