Minizinc, как создать карту или структуру данных словаря

У меня простой вопрос по синтаксису Minizinc. Мой входной файл .dzn содержит набор из 2-х мерных массивов (примерно до 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;

Одна очевидная проблема с этим кодом заключается в том, что мне нужно менять модель каждый раз, когда я меняю ввод. Есть ли лучший способ, как я могу кодировать это обычным способом?

Спасибо!


person kirbo    schedule 17.09.2017    source источник


Ответы (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];
person Dekker1    schedule 17.09.2017
comment
Хорошо, понятно, не могли бы вы пояснить свое утверждение о времени компиляции и использовании памяти. Требует ли array3d (0..60, 1..3, 1..501) больше вычислительных ресурсов / памяти, чем 60 array2d (1..3, 1..501)? Я понял ваше решение, в основном я просто объединяю свои array2ds в один 3d, а затем отображаю индексы. Единственным недостатком является то, что данные будут труднее воспринимать людьми. Но, конечно, мне не нужно менять модель. Спасибо! - person kirbo; 18.09.2017
comment
Я думаю, вы поняли! Что касается потребления памяти: 60 2d-массивов не занимают больше памяти во время компиляции, чем объединенные 3-мерные массивы. Однако, если вы не хотите выполнять этап трансляции и решили добавить в 3d-массив дополнительные (пустые) массивы, которых не было среди 2-х массивов, это может привести к большим накладным расходам памяти. - person Dekker1; 19.09.2017