我正在研究玩具问题以学习微量锌。取一个值在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]
);
但是,这也不令人满意。
根据我的概念理解,有些事情是不对的。我的方法有什么问题?
答案 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)
谓词允许在数组中重复值,也就是说,它强制执行非严格的升序(如果需要,将increasing
与distinct
组合在一起)。
谓词包含在文件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]);
----------