Миницинк, как создать карту или словарную структуру данных
У меня есть простой вопрос относительно синтаксиса Minizinc. Мой входной файл.dzn содержит набор из двух размерных массивов (примерно до 30 массивов), объявленных следующим образом:
rates_index_0 = array2d(1..3, 1..501, [ 15, 20, 23, ....
rates_index_12 = array2d(1..3, 1..501, [ 21, 24, 27, ....
...
примечание: в индексных номерах есть пробелы (например, 12 -> 20)
В моей модели мне нужно использовать один из этих массивов в зависимости от значения переменной. В общепринятом языке программирования я бы решил это, используя карту или словарную структуру данных. Но в Minizinc я жестко кодирую это следующим образом:
function var int: get_rate(int: index, var int: load, int: dc_size) =
if index == 0 then
rates_index_0[dc_size, load]
else if index == 12 then
rates_index_12[dc_size, load]
else if index == 16 then
rates_index_16[dc_size, load]
else if index == 20 then
rates_index_20[dc_size, load]
else
assert(false, "unknown index", 0)
endif endif endif endif;
Одна очевидная проблема с этим кодом заключается в том, что мне нужно менять модель каждый раз, когда я меняю ввод. Есть ли лучший способ, как я могу кодировать это в общем виде?
Спасибо!
1 ответ
В более абстрактном смысле структура карты - это не что иное, как функция, отображающая входные данные определенного типа в массив. Таким образом, карта может быть заменена массивом и функцией. (Разница в том, что вам придется самостоятельно определять функцию)
Прежде чем начать с остальными, я хотел бы отметить, что если ваша модель компилируется в целом быстро, вы можете попробовать использовать тройной массив без функции, rates_index = array3d(0..60, 1..3, 1..501, [ 15, 20, 23, ....
, Это будет стоить больше памяти, но сделает модель более гибкой.
Общий способ использования структуры карты - определить функцию map_index
, который отображает ваши входные данные, в данном случае целые числа, на индекс массива, также целые числа. Это означает, что мы можем тогда определить дополнительный массив уровня, чтобы указать на правильный: rates_index = array3d(0..nr_arrays, 1..3, 1..501, ....
, Это означает, что содержание get_rates
тогда может быть: rates_index[map_index(index), dc_size, load]
,
Функция map_index
Сам в своей простейшей форме будет содержать другую версию вашего if-then-else
заявления:
function int: map_index(int: index) =
if index == 0 then
0
else if index == 12 then
1
else if index == 16 then
2
else if index == 20 then
3
else
assert(false, "unknown index", 0)
endif endif endif endif;
Однако вы можете сделать его динамическим, создав дополнительный массив, содержащий номер массива для каждого индекса, указав -1 для всех недоступных массивов. Для вашего примера отображение будет выглядеть так: array[0..20] of int: mapping = [0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3];
, map_index
Функция может быть динамически определена как:
function int: map_index(int: index) =
mapping[index];