【问题标题】:Why a clpfd variable is assigned to an actual value in a reification?为什么在具体化中将 clpfd 变量分配给实际值?
【发布时间】:2014-01-08 09:35:13
【问题描述】:

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

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

但是,我需要Lb 有一个可变偏移量(即每个列表的第一个元素在La+Lb 添加的位置不同。但是,列表Lb 总是在La 的宽度内。例如:

成为La = [0,1,1,1,1,0,1,1,1]Lb = [1,2,2]

可能的情况 1

(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   

可能的情况 2

(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   

可能的情况 3

(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   

我想要的是将offset 定义为一个 clpfd 变量,并具有与之关联的特定域。为了计算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),!.

想法是通过调用overlap/6 找到La+Lb,然后使用indomain(S) 使数字收敛到加法的特定解。我的问题是,当 Prolog 到达A #= B #&lt;==&gt; S #= Os 行时,S 被分配给Os(大小写偏移值),而不是用具体条件约束A

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

编辑:这个想法是为S的域内的每个点调用overlap/6,然后使用这个约束列表来标记一个正确的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

或者:

?- 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),
   indomain(S).
S = 0
L = [1, 2, 0, 0]

【问题讨论】:

  • 约束和!不要聚集在一起。首先尝试说明你的定义什么时候应该成功,什么时候应该失败。
  • 事实上,它应该总是成功...! 只是为了削减(其余)不需要的解决方案。
  • 你说“它应该总是成功”。不,绝对不是,否则overlap(_,_,_,_,_,_). 将是一个完美的实现!
  • 对。它应该在以下情况下成功:LaLb 是任意长度的列表并且它们的长度是 A&gt;=B 并且偏移量绑定到实际数字 (&gt;=0) 并且 S(最终偏移量)是 不绑定到一个数字,但有一个有界且众所周知的域。这是你的意思吗? (顺便说一句,我编辑了问题)
  • 举个具体的例子!真的很有帮助。

标签: list prolog swi-prolog clpfd


【解决方案1】:

如果与起始位置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 的元素。此外,您可能希望进一步限制重叠的可能位置,我一直保持相当笼统。

【讨论】:

  • 非常感谢!这对我来说似乎很精彩。我使用overlap_here([], [A|As], [AB|ABs], (AB #= A #/\ Rest)) :- overlap_here([], As, ABs, Rest). 也考虑了那些不受重叠影响的元素。
猜你喜欢
  • 1970-01-01
  • 2016-02-10
  • 2022-10-05
  • 1970-01-01
  • 2018-03-01
  • 2017-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多