ПРОБЛЕМА (ы).
В общем, ограничение в порядке.В контексте этого примера, однако, это противоречиво.Давайте посмотрим, почему это так.
Мы знаем, что решение должно включать 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
, поэтому в модели есть еще одно несоответствие.Ограничение будет правильным, если вы используете символ импликации ->
вместо (логического) и символа /\
.
SOLUTION (s).
Во-первых, позвольте мне отложить в сторону возможное неправильное понимание языка.Понятие 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]);
----------
Более элегантное решение заключается в использовании следующего глобального ограничения, которое упомянуто в документации (версия 2.2.3) из MiniZinc
:
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]);
----------