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

标签 list prolog swi-prolog clpfd

我正在开发一个 (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),!.
    

    这个想法是找到La+Lb调用 overlap/6然后,使用 indomain(S) ,使数字收敛到加法的特定解。我的问题是,当 Prolog 到达 A #= B #<==> S #= Os 行时, S分配给 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
    

    或者:
    ?- 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]
    

    最佳答案

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

    关于list - 为什么在具体化中将 clpfd 变量分配给实际值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20688099/

    相关文章:

    python - 如何检查两个列表是否具有相同顺序的相同对象?

    python - 如何将整数列表加入一个整数python

    list - 检查列表是否是回文。如果没有,插入元素使其成为回文。 (序言)

    mysql - swi prolog mysql + web

    logic - Prolog - 查找当前目录, 'tell' 谓词的相对目录

    python - 如何在列表中每次运行连续零时删除除 x 之外的所有零?

    list - 对4个不同列表的元素进行分组

    list - 解释为什么 append/3 在这些情况下会产生无限数量的解决方案

    c++ - PL_new_term_refs() : No foreign environment

    python - 在 Python 中通过引用将一个列表的元素存储在另一个列表中?