为什么将clpfd变量分配给具体化中的实际值?

时间:2013-12-19 17:33:02

标签: list prolog swi-prolog clpfd

我正在开发一个(SWI-)Prolog程序,它使用CLP(FD)约束来找到特定问题的解决方案。要做到这一点,我碰巧需要我称之为两个列表的“未定位”重叠。那就是:

  • 列表La的长度为A
  • 列表Lb的长度为B
  • A>乙
  • 未定位的重叠列表为La+Lb,其中元素以逐一的方式添加。

但是,我需要Lb有一个变量偏移量(即每个列表的第一个元素不在La+Lb添加的相同位置。但是,list { {1}}始终在Lb的宽度范围内。例如:

LaLa = [0,1,1,1,1,0,1,1,1]

可能的案例1

Lb = [1,2,2]

可能的案例2

(Lb) 1 2 2 . . . . . . ---> offset = 0
(La) 0 1 1 1 1 0 1 1 1
( +) 1 3 3 1 1 0 1 1 1   

可能的情况3

(Lb) . . . 1 2 2 . . . ---> offset = 3
(La) 0 1 1 1 1 0 1 1 1
( +) 0 1 1 2 3 2 1 1 1   

我想要的是将(Lb) . . . . . 1 2 2 . ---> offset = 5 (La) 0 1 1 1 1 0 1 1 1 ( +) 0 1 1 1 1 1 3 3 1 定义为 clpfd 变量,并使用与之关联的特定域。为了计算offset,我编写了谓词La+Lb,其中包含以下内容:

overlap/6

我们的想法是通过调用overlap([],[],_,_,_,[]) :- !. overlap([],_, _,_,_,[]) :- !. overlap(A, [],_,_,_, A) :- !. overlap(A, _,Os,_,_, A) :- length(A,L), L =< Os, !. overlap([A|As],[B|Bs],0,Os,S,[A|Ls]) :- % Os is the actual Offset A #= B #<== S #= Os, % S is a clpfd variable overlap(As,Bs,0,Os,S,Ls),!. overlap([A|As],Bs,Acc,Os,S,[A|Ls]) :- Acc > 0, Acc0 is Acc-1, overlap(As,Bs,Acc0,Os,S,Ls),!. 来查找La+Lb,然后使用overlap/6,使数字收敛到添加的特定解决方案。我的问题是,当Prolog到达indomain(S)行时,A #= B #<==> S #= Os被分配给S(案例偏移值),而不是用{8}来约束Os

我疯了,这没有意义吗?有没有正确的方法来做我正在尝试的事情?提前谢谢!

修改:我们的目的是为A域内的每个点调用overlap/6,然后使用此约束列表标记正确的S

统一的例子:

S

或者:

?- S in 0..2,
   L0 = [0,0,0,0],
   overlap(L0, [1,2], 0, S, L1),
   overlap(L1, [1,2], 1, S, L2),
   overlap(L2, [1,2], 2, S, L).
L = [_G1, _G2, _G3, _G4]

_G1 in 0\/1
_G2 in 0\/1\/2
_G3 in 0\/1\/2
_G4 in 0\/2

_G1 #= 1 #<== S #= 0
_G1 #= 0 #<== S #> 0

_G2 #= 2 #<== S #= 0
_G2 #= 1 #<== S #= 1
_G2 #= 0 #<== S #> 2

_G3 #= 0 #<== S #= 0
_G3 #= 2 #<== S #= 1
_G3 #= 1 #<== S #< 2

_G1 #= 0 #<== S #= 0
_G4 #= 0 #<== S #= 1
_G4 #= 2 #<== S #= 2

1 个答案:

答案 0 :(得分:3)

如果与起始位置S重叠,我们希望约束的连接,以便涵盖所有重叠位置。例如:

:- use_module(library(clpfd)).

overlap_at(As, Bs, S, ABs) :-
        length(As, L),
        L1 #= L - 1,
        S in 0..L1,
        overlap_at_(As, Bs, S, 0, ABs).

overlap_at_([], _, _, _, []).
overlap_at_([A|As], Bs, S, N0, [AB|ABs]) :-
        overlap_here(Bs, [A|As], [AB|ABs], Conj),
        S #= N0 #==> Conj,
        S #> N0 #==> AB #= A,
        N1 #= N0 + 1,
        overlap_at_(As, Bs, S, N1, ABs).

overlap_here(_, [], _, 1) :- !.
overlap_here([], _, _, 1).
overlap_here([B|Bs], [A|As], [AB|ABs], (AB #= A + B #/\ Rest)) :-
        overlap_here(Bs, As, ABs, Rest).

注意我如何在overlap_here/4中描述一个连词。

示例查询:

?- overlap_at([0,1,1,1,1,0,1,1,1], [1,2,2], 3, ABs).
ABs = [0, 1, 1, 2, 3, 2, _G909, _G912, _G915],
_G909 in inf..sup,
_G912 in inf..sup,
_G915 in inf..sup.

这为您提供了很好的解决方案:所有直到并包含重叠的元素都会根据需要进行实例化。第三个参数当然也可以是变量:例如试试

?- overlap_at([0,1,1,1,1,0,1,1,1], [1,2,2], S, ABs), 
   indomain(S), writeln(ABs), false.

产生的结果如下:

[1,3,3,_,_,_,_,_,_]
[0,2,3,3,_,_,_,_,_]
[0,1,2,3,3,_,_,_,_]
[0,1,1,2,3,2,_,_,_]
[0,1,1,1,2,2,3,_,_]
[0,1,1,1,1,1,3,3,_]
[0,1,1,1,1,0,2,3,3]
[0,1,1,1,1,0,1,2,3]
[0,1,1,1,1,0,1,1,2]

我把剩下的作为练习:不受重叠影响的尾随位置需要等于A的元素。此外,您可能希望进一步限制重叠的可能位置,我保持相当普遍。