带约束forall(x中的i)(x [i] <= x [i + 1]);的不满足的解决方案;

时间:2019-02-12 11:00:30

标签: minizinc

我正在研究玩具问题以学习微量锌。取一个值在0到9之间的数组(现在硬编码为大小3),并找到总和等于乘积的组合。

par int: n = 3; % hardcode for now 

array[1..n] of var 0..9: x;

constraint sum(x) != 0;
constraint sum(x) == product(x);

output["\(x)"];

输出

[2, 3, 1]
----------

这按预期工作,但是,接下来我尝试进行约束,以使值必须按顺序增加。

首先,我尝试了这一点:

constraint forall(i in x)( 
   x[i] <= x[i+1]
);

这是不满意的。我在想这可能是由于i+1索引大于最后一项的数组大小。因此,我为forall添加了一个条件,以防止最后一项的索引超出范围:

constraint forall(i in x)( 
   i < n /\ x[i] <= x[i+1]
);

但是,这也不令人满意。

根据我的概念理解,有些事情是不对的。我的方法有什么问题?

1 个答案:

答案 0 :(得分:4)

问题。

通常,约束很好。但是,在此示例的上下文中,它是不一致的。让我们看看为什么会这样。

我们知道解决方案必须包含1, 2, 3,因此,我们可以推断出约束条件

constraint forall (i in x) (
    x[i] <= x[i+1]
);

“等同于”

constraint x[1] <= x[2];
constraint x[2] <= x[3];
constraint x[3] <= x[4];

mzn2fzn报告以下问题的

  WARNING: undefined result becomes false in Boolean context
  (array access out of bounds)
  ./t.mzn:12:
  in binary '<=' operator expression
  in array access

当写入相同约束而没有硬编码的索引值时,mzn2fzn编译器在调用求解器之前无法检测到不一致。但是,access out of bounds的语义在运行时仍然相同(即false),因此该公式变得无法满足。

约束

constraint forall(i in x)( 
   i < n /\ x[i] <= x[i+1]
);

通过要求i必须小于n来扩大先前的约束。对于i = 3显然是错误的,因此模型中还有一个不一致之处。如果您使用暗示符号->代替(逻辑)和符号/\,则约束将是正确的。


解决方案。

首先,让我撇开对该语言的可能误解。您在模型中使用的理解i in x引用数组x中的元素,而不引用x的索引集。在此特定情况下,解决方案和x的索引集包含相同的值,因此不会引起不一致。但是,通常情况并非如此,因此最好使用函数index_set(),如下所示:

constraint forall(i, j in index_set(x) where i < j)(
   x[i] <= x[j]
);

示例

par int: n = 3; % hardcode for now 

array[1..n] of var 0..9: x;

constraint sum(x) != 0;
constraint sum(x) == product(x);

constraint forall(i, j in index_set(x) where i < j)(
   x[i] <= x[j]
);

solve satisfy;

output["\(x)"];

收益

~$ mzn2fzn test.mzn 
~$ optimathsat -input=fzn < test.fzn 
x = array1d(1..3, [1, 2, 3]);
----------

优雅的解决方案是使用以下全局约束,在MiniZinc的{​​{3}}中提到:

predicate increasing(array [int] of var bool: x)
predicate increasing(array [int] of var int: x)
predicate increasing(array [int] of var float: x)

谓词允许在数组中重复值,也就是说,它强制执行非严格的升序(如果需要,将increasingdistinct组合在一起)。

谓词包含在文件increasing.mzn中。但是,人们通常会改用文件globals.mzn来访问所有谓词。

示例

include "globals.mzn";

par int: n = 3; % hardcode for now 

array[1..n] of var 0..9: x;

constraint sum(x) != 0;
constraint sum(x) == product(x);

constraint increasing(x);

solve satisfy;

output["\(x)"];

收益

~$ mzn2fzn t.mzn 
~$ optimathsat -input=fzn < t.fzn 
x = array1d(1..3, [1, 2, 3]);
----------