【问题标题】:Initial guess in labeling标签中的初步猜测
【发布时间】:2014-06-29 02:53:27
【问题描述】:

举个小例子:

go:-
  length( X, 200 ),
  domain( X, 1, 25),

  postConstraints( X, Y ),

  labeling( [minimize(Y), X ).

如果我们假设postConstraints 设置了一些复杂的约束。 Y 从postConstraints 返回并在标记期间用作成本函数。

我们假设我们对postConstraints 设置的约束一无所知(或知之甚少)。但是我们知道最优解(或好的解)将是 X 包含或多或少均匀分布的可能域。 IE。值 1 将出现大约 8 (200/25) 次,2 将出现大约 8 次,依此类推。

但是我们不知道每个值会出现在什么位置。

如果我们从使用默认标签开始,X 将首先被分配只有 1,这是一个解决方案,但不是一个好的解决方案(高 Y)。通过长时间的搜索,将找到最优解,它在可能的域上或多或少是均匀分布的。

这意味着搜索需要很长时间才能从第一个可能的解决方案转到最佳(或更好的)解决方案。

我认为,如果可以在标记之前对 X 应用初始“猜测”,则搜索会更快。 前任。如果 X 填充了来自域的随机值? 在 Sicstus 有没有办法做到这一点?这是您在labeling 中使用value(Enum) 的地方吗?

【问题讨论】:

    标签: prolog clpfd sicstus-prolog


    【解决方案1】:

    你的问题没有具体的例子,所以很难给出具体的建议。但是,您可以首先考虑标签选项ff。至少有一个简单的原因:添加预定义的标签选项可能会影响运行时间,但不会影响正确性。更复杂的方法总是有引入错误的风险。

    谓词labeling/2 提供了两种预定义的方式来枚举选定变量的值:up(默认)和down。要从不同的值开始,您可以将一个变量映射到另一个再次使用内置枚举之一的变量。定义自己的枚举方法是可能的,但绝对不是初学者的任务。事实上,即使library/clpfd/examples/ 也没有提供一个例子。

    为了说明如何以不同方式枚举变量,我将使用单个变量X

    | ?- X in 1..5, labeling([],[X]).
    X = 1 ? ;
    X = 2 ? ;
    X = 3 ? ;
    X = 4 ? ;
    X = 5 ? ;
    no
    | ?- X in 1..5, labeling([down],[X]).
    X = 5 ? ;
    X = 4 ? ;
    X = 3 ? ;
    X = 2 ? ;
    X = 1 ? ;
    no
    

    现在我们要以值 3 开始X。因此,X 映射到 Xx,它将用于标记:

    | ?- X in 1..5, Xx #= (X+5-3)mod 5,labeling([],[Xx]).
    X = 3,
    Xx = 0 ? ;
    X = 4,
    Xx = 1 ? ;
    X = 5,
    Xx = 2 ? ;
    X = 1,
    Xx = 3 ? ;
    X = 2,
    Xx = 4 ? ;
    no
    

    通过这种方式,您可以将每个变量映射到其他一些初始值。或者都一样。但是请注意,由于(mod)/2 的一致性相对较弱,因此无法立即看到原始变量中存在的所有信息。如果您使用像 ff 这样动态检查域的选项,这反过来可能会恶化标签:

    | ?- assert(clpfd:full_answer).
    yes
    | ?- X in 1..5, Xx #= (X+5-3)mod 5, X #\= 2.
    clpfd:(_A#=X+2),
    clpfd:(_A mod 5#=Xx),
    X in{1}\/(3..5),
    _A in{3}\/(5..7),
    Xx in 0..4 ? ;
    no
    

    所以在这里,Xx 的域还没有更新为0..3,虽然:

    | ?- X in 1..5, Xx #= (X+5-3)mod 5, X #\= 2, Xx = 4.
    no
    

    非常智能的默认选项step 也受到类似影响。

    【讨论】:

      【解决方案2】:

      您说好的解决方案将“在可能的域上或多或少均匀分布”,我想这意味着所有域值将在解决方案向量中出现相似的次数。

      在这种情况下,您可以引入一个辅助变量,以某种方式测量变量分配的启发式质量。然后,您首先标记此辅助变量,然后再标记其他变量,从而开始搜索。这样,可以首先检查潜在的好分配。

      我没有 SICStus,但这里有一个 ECLiPSe 示例,应该很容易适应。我引入了约束来计算不同域值1ND 在主变量向量Xs 中出现的频率。然后在变量Imbalance 中计算计数变量Ns 的不平衡,这是最先被标记的变量(从值0 开始,即完美平衡):

      :- lib(ic).
      :- lib(ic_global).
      
      main(NX, ND, Xs) :-
          length(Xs,NX),
          Xs::1..ND,
          ( for(I,1,ND), foreach(N,Ns), param(Xs) do
              occurrences(I, Xs, N)    % SICStus: count(I,Xs,#=,N)
          ),
          sum(Ns) #= NX,
          Imbalance #= max(Ns) - min(Ns),
          Imbalance :: 0..NX,
      
          labeling([Imbalance|Xs]).
      

      示例运行显示了如何首先枚举平衡解决方案:

      ?- main(4, 2, Xs), writeln(Xs), fail.
      [1, 1, 2, 2]
      [1, 2, 1, 2]
      [1, 2, 2, 1]
      [2, 1, 1, 2]
      [2, 1, 2, 1]
      [2, 2, 1, 1]
      [1, 1, 1, 2]
      [1, 1, 2, 1]
      [1, 2, 1, 1]
      [1, 2, 2, 2]
      [2, 1, 1, 1]
      [2, 1, 2, 2]
      [2, 2, 1, 2]
      [2, 2, 2, 1]
      [1, 1, 1, 1]
      [2, 2, 2, 2]
      No (0.01s cpu)
      

      您的实际问题约束可以简单地添加到此模板中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-18
        • 1970-01-01
        • 1970-01-01
        • 2012-10-14
        • 2021-10-08
        • 1970-01-01
        相关资源
        最近更新 更多