标签的初步猜测

时间:2014-06-27 07:32:45

标签: prolog clpfd sicstus-prolog

鉴于这个小例子:

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

  postConstraints( X, Y ),

  labeling( [minimize(Y), X ).

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

我们假设我们没有(或极少)了解postConstraints设置的约束。但我们知道最佳解决方案(或一个好的解决方案)将是X包含可能域的或多或少的均匀分布。即值1将出现在8(200/25)次左右,2将出现在8次左右,等等。

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

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

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

我认为如果在标记之前可以将初始'猜测'应用于X,则搜索会更快。 防爆。如果X填充了域中的随机值? 在Sicstus有没有办法做到这一点?这是您在value(Enum)中使用labeling的位置吗?

2 个答案:

答案 0 :(得分: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也会受到影响。

答案 1 :(得分:0)

你说好的解决方案将在可能的域上进行或多或少的均匀分布",我认为这意味着所有域值在解决方案向量中都会出现相似的次数。

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

我没有SICStus,但这里有一个ECLiPSe示例,应该很容易适应。我已经引入了约束来计算主变量向量1中不同域值NDXs的出现频率。然后计算变量Ns的不平衡在变量Imbalance中计算,这是首先标记的变量(从值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)

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