minizinc寻求解决方案的各种问题

时间:2019-07-12 19:08:22

标签: minizinc

我正在尝试使用minizinc为我建立一个true / false矩阵,其中每一列都满足某些条件(至少3个真实值,并且必须有奇数个真实值)。到目前为止,一切都很好-但是,当我添加其他约束以使其每一列(与所有其他列)都不相同时,我不会得到一致的结果:

使用以下注释掉的版本,在Ubuntu-on-WSL(Windows)上使用minizinc 2.1.7,它几乎可以立即找到解决方案。但是,无论是在Mac上还是在ArchLinux安装上,任何版本的minizinc(2.1.7、2.2.0、2.3.1)都不能满足约束条件(至少在几分钟之内)。所有这些都与Gecode有关。

Chuffed可以很好地满足约束条件,再次使用注释掉的代码版本,而不是下面的代码。

但是,如果我解决了使某些值最小化的问题(请参见第二段),则Chuffed不再找到任何解决方案(同样,至少在几分钟之内)。我希望它至少能找到与“满意”相同的解决方案。

我在做什么错?有没有更好的方法来编写更一致地工作的“不同的列”约束?对于约束求解器,我不认为这是一个特别困难的问题,因此我怀疑这实际上与如何编写约束有关。

我想将H矩阵保留为true / false的2d矩阵,因为将它做成这种形状还有其他限制。

int: k = 7;
int: n = 47;

array[1..k,1..n] of var bool: H;
array[1..k] of var bool : flip_bits;



predicate all_different_int(array[int] of var int: x) =
  forall(i,j in index_set(x) where i < j) ( x[i] != x[j] );


constraint forall(j in 1..n)(
  sum(i in 1..k)(
    if H[i,j] then 1 else 0 endif
  ) mod 2 > 0
);

constraint forall(j in 1..n)(
  sum(i in 1..k)(
    if H[i,j] then 1 else 0 endif
  ) >= 3
);

%array[1..n] of var int: H_t;
%constraint forall(j in 1..n)(
% H_t[j] = sum(i in 1..k)(
%   if H[i,j] then pow(2,i) else 0 endif
% )
%);
%constraint all_different_int(H_t);

constraint all_different_int(
  [sum(i in 1..k)(if H[i,j] then pow(2,i) else 0 endif) | j in 1..n]
);

solve satisfy;
var int: z2 = sum(i in 1..k, j in 1..n)(if H[i,j] then 1 else 0 endif);
var int: z1 = max(i in 1..k)(sum (j in 1..n)(if H[i,j] then 1 else 0 endif));

solve minimize z1*1000+z2;

1 个答案:

答案 0 :(得分:1)

这是模型的重写版本。 Chuffed在43秒内解决了该问题,请参见下面的最佳解决方案。

保留h_t是因为它似乎可以使用all_different约束更好地“驱动”解决方案。 lex2约束是一个对称破坏约束,它确保矩阵H应该按字典顺序排列。

此外,还重写了一些其他约束,例如当sum ... ( if H[i.j] then 1 else 0 endif)就足够时,在某些约束条件下删除了sum .. (H[i,j])

include "globals.mzn";

int: k = 7;
int: n = 47;

array[1..k,1..n] of var bool: H;
array[1..k] of var bool : flip_bits;

constraint forall(j in 1..n)(
    sum(i in 1..k)(H[i,j]) mod 2  = 1);

constraint forall(j in 1..n)(
     sum(i in 1..k)(H[i,j]) >= 3);

array[1..n] of var int: H_t;
constraint 
  forall(j in 1..n)(
    H_t[j] = sum(i in 1..k)(
      if H[i,j] then pow(2,i) else 0 endif
    )
  );
constraint all_different_int(H_t);

var int: z2 = sum(i in 1..k, j in 1..n)(H[i,j]);
var int: z1 = max(i in 1..k)(sum (j in 1..n)(H[i,j]));

constraint
  z1 > 0 /\ z2 > 0 /\  z > 0
;

% symmetry breaking
constraint lex2(H); 

var int: z = z1*1000+z2;

% solve :: int_search(H_t, first_fail, indomain_split, complete) minimize z;
% solve satisfy;
solve minimize z;

output [
  "z: \(z)\n",
  % "H: \(H)\n",
  "H_t: \(H_t)\n"
]
++
[
 if j = 1 then "\n" else "" endif++
   "\(H[i,j]*1)"

   | i in 1..k, j in 1..n
];

43秒后使用以下命令找到最佳解决方案      $ time minizinc test96.mzn -a -s --solver chuffed

 z: 24165
 H_t: [224, 208, 176, 112, 200, 168, 104, 152, 88, 56, 248, 196, 164, 100, 148, 84, 52, 140, 76, 44, 236, 28, 124, 194, 162, 98, 146, 82, 50, 242, 138, 74, 42, 234, 26, 218, 134, 70, 38, 230, 22, 182, 118, 14, 158, 94, 62]

 00000000000000000000000111111111111111111111111
 00000000000111111111111000000000000011111111111
 00001111111000000111111000000011111100000001111
 01110001111000111000011000111100001100001110111
 10110110011011001001101011001100110000110110001
 11011010101101010010101101010101010101010010010
 11101101001110100100100110100110010110010100100
 ----------
 ==========

其他一些评论:

  • 所有列均应不同的约束可以通过以下内容说明

    约束    forall(2..n中的j)(      sum(i在1..k中)(H [i,j]!= H [i,j-1])> 0    )  ;

    但是,(在此模型中)它不如all_different变体有效。

  • 当求解器似乎很慢时,一个提示是测试不同的搜索策略。当我开始使用模型时,这似乎会更快一些:

    solve :: int_search(H_t,first_fail,indomain_split,complete)最小化z;

    但是,当添加lex2约束时,它比普通的solve minimize z慢。 使用搜索策略通常是一件好事...