Двумерные таблицы
Рассмотрим данные параметра cost, индексированного по двум наборам:
set ORIG; set DEST; param cost{ORIG,DEST} >= 0;
Данные воспринимаются проще, когда они имеют вид таблицы:
param cost: FRA DET LAN WIN STL FRE LAF := GARY 39 14 11 14 16 82 8 CLEV 27 9 12 9 26 95 17 PITT 24 14 17 13 28 99 20 ;
Метки строк содержат первый индекс, а столбцы - второй. Так, что для параметра cost ["GARY", "FRA"] задано значение 39. Чтобы позволить AMPL распознавать это как таблицу, двоеточие должно следовать за именем параметра, а оператор := следует за списком меток столбцов.
Для больших наборов индексов столбцы в таблице невозможно просмотреть в пределах ширины одного экрана или страницы. Чтобы справиться с этой ситуацией, AMPL предлагает несколько альтернатив:
- Если только одно из измерений двумерной таблицы велико, таблицу можно преобразовать так, чтобы метки столбцов соответствовали меньшему набору:
param cost(tr): GARY CLEV PITT := FRA 39 27 24 DET 14 9 14 LAN 11 12 17 WIN 14 9 13 STL 16 26 28 FRE 82 95 99 LAF 8 17 20 ;
Обозначение (tr), после имени параметра, указывает на преобразованную таблицу, в которой метки столбцов дают первый индекс, а строки - второй индекс.
Когда оба набора индексов велики, тогда таблица, либо ее преобразование могут быть разделены. Поскольку разрывы строк игнорируются, каждая строка может быть разделена на несколько строк:
param cost: FRA DET LAN WIN STL FRE LAF := GARY 39 14 11 14 16 82 8 CLEV 27 9 12 9 26 95 17 PITT 24 14 17 13 28 99 20 ;
Или таблицу можно разбить по столбцам на несколько более мелких:
param cost: FRA DET LAN WIN := GARY 39 14 11 14 CLEV 27 9 12 9 PITT 24 14 17 13 : STL FRE LAF := GARY 16 82 8 CLEV 26 95 17 PITT 28 99 20 ;
Двоеточие указывает начало каждой новой вложенной таблицы. В этом примере каждая вложенная таблица имеет одинаковые метки строк, но разные подмножества меток столбцов.
В альтернативном описании этой модели, параметр cost указан не для всех комбинаций элементов ORIG и DEST, а для подмножества пар:
set LINKS within {ORIG,DEST}; param cost{LINKS} >= 0;
Членство в LINKS может быть кратко описано с помощью списка пар:
set LINKS := (GARY,*) DET LAN STL LAF (CLEV,*) FRA DET LAN WIN STL LAF (PITT,*) FRA WIN STL FRE ;
Вместо того, чтобы быть представленными списком, значения параметра cost могут быть даны в таблице:
param cost: FRA DET LAN WIN STL FRE LAF := GARY . 14 11 . 16 . 8 CLEV 27 9 12 9 26 . 17 PITT 24 . . 13 28 99 . ;
Значение параметра cost дается для всех пар, которые существуют в LINKS, а точка «.» служит заполнителем для пар, которые отсутствуют в LINKS. Точка может появиться в любой таблице AMPL, чтобы уточнить, что «здесь не указано значение». Сам набор LINKS может быть задан в виде следующей таблицы:
set LINKS: FRA DET LAN WIN STL FRE LAF := GARY - + + - + - + CLEV + + + + + - + PITT + - - + + + - ;
«+»Указывает на пару, которая является элементом набора, а «-» указывает на пару, которая не является элементом набора.
Двумерные срезы многомерных данных
Чтобы представить данные для параметров индексируемых по более чем двум измерениям, можно указать значения в двумерных срезах, которые представлены в виде таблиц. Правила использования срезов в таблицах, практически такие же, как и для списков. В качестве примера рассмотрим трехмерный параметр cost:
set ROUTES within {ORIG,DEST,PROD}; param cost{ROUTES} >= 0;
Значения параметра cost в виде списка:
param cost := [*,*,bands] CLEV FRA 27 CLEV DET 9 CLEV LAN 12 CLEV STL 26 CLEV LAF 17 PITT FRA 24 PITT WIN 13 PITT STL 28 PITT FRE 99 [*,*,coils] GARY LAN 11 GARY STL 16 GARY LAF 8 CLEV FRA 23 CLEV DET 8 CLEV LAN 10 CLEV WIN 9 CLEV STL 21 PITT FRE 81
Вместо этого можно представить в виде таблицы:
param cost := [*,*,bands]: FRA DET LAN WIN STL FRE LAF := CLEV 27 9 12 . 26 . 17 PITT 24 . . 13 28 99 . [*,*,coils]: FRA DET LAN WIN STL FRE LAF := GARY . . 11 . 16 . 8 CLEV 23 8 10 9 21 . . PITT . . . . . 81 . ;
Поскольку мы работаем с двумерными таблицами, в шаблонах должно быть два знака *. Метка строки табличного значения заменяется на первый знак *, а метка столбца на второй, если только обратное не указано оператором (tr) сразу после шаблона. Можно опустить любые строки или столбцы, в которых отсутствуют значимые записи. Например, строка для GARY в таблице [*, *, band] выше.
Точка в таблице для любого среза указывает на отсутствующие данные.
Аналогичную таблицу для указания набора ROUTES можно построить, поставив +, на тех пересечениях, где должны появиться числа:
set ROUTES := (*,*,bands): FRA DET LAN WIN STL FRE LAF := CLEV + + + - + - + PITT + - - + + + - (*,*,coils): FRA DET LAN WIN STL FRE LAF := GARY - - + - + - + CLEV + + + + + - - PITT - - - - - + - ;
Поскольку указанные шаблоны представляют собой шаблоны наборов, а не шаблоны параметров, они заключены в круглые (), а не в квадратные скобки [].
Многомерные таблицы
Поместив несколько индексов слева от каждой строки или в верхней части каждого столбца, можно описать многомерные данные в одной таблице, а не в серии срезов. Мы продолжим с трехмерными данными затрат, чтобы проиллюстрировать некоторые возможности. Поместив первые два индекса наборов ORIG и DEST слева, а третий индекс из набора PROD вверху, мы получим следующую трехмерную таблицу затрат:
param cost: bands coils := CLEV FRA 27 23 CLEV DET 8 8 CLEV LAN 12 10 CLEV WIN . 9 CLEV STL 26 21 CLEV LAF 17 . PITT FRA 24 . PITT WIN 13 . PITT STL 28 . PITT FRE 99 81 GARY LAN . 11 GARY STL . 16 GARY LAF . 8 ;
Поместив только первый индекс слева, а второй и третий сверху, мы получаем следующую таблицу, которую для удобства разбиваем на две части:
param cost: FRA DET LAN WIN STL FRE LAF : bands bands bands bands bands bands bands := CLEV 27 9 12 . 26 . 17 PITT 24 . . 13 28 99 . : FRA DET LAN WIN STL FRE LAF : coils coils coils coils coils coils coils := GARY . . 11 . 16 . 8 CLEV 23 8 10 9 21 . . PITT . . . . . 81 . ;
Как правило, двоеточие должно предшествовать каждой строке заголовка таблицы, тогда как := ставится только после последней подстроки заголовка. Индексы используются в том порядке, в котором они появляются, сначала слева, а затем сверху, если не указано иное. Как и в других таблицах, можно добавить индикатор (tr) для транспонирования таблицы, чтобы индексы располагались сначала сверху, а затем слева:
param cost (tr): CLEV CLEV CLEV CLEV CLEV CLEV : FRA DET LAN WIN STL LAF := bands 27 8 12 . 26 17 coils 23 8 10 9 21 . : PITT PITT PITT PITT GARY GARY GARY : FRA WIN STL FRE LAN STL LAF := bands 24 13 28 99 . . . coils . . . 81 11 16 8 ;
Шаблоны также могут использоваться для более точного определения того, откуда берутся те или иные индексы. Для многомерных таблиц, шаблон содержит два символа: «*»- для обозначения индексов, которые появляются слева, и «:» для обозначения индексов, которые появляются вверху. Например, шаблон [*, :, *] определяет, что первый и третий индексы находятся слева, а второй - вверху:
param cost := [*,:,*] : FRA DET LAN WIN STL FRE LAF := CLEV bands 27 9 12 . 26 . 17 CLEV coils 23 8 10 9 21 . . PITT bands 24 . . 13 28 99 . PITT coils . . . . . 81 . GARY coils . . 11 . 16 . 8 ;
Порядок индексов всегда сохраняется в таблицах такого рода. Третий индекс никогда не размещается перед первым, независимо от того, используется транспонирование или шаблоны.
Для параметров четырех или более измерений, идеи нарезки и многомерных таблиц могут применяться вместе, обеспечивая особенно широкий набор возможных форматов таблиц. Например, если cost был проиндексирован по ORIG, DEST, PROD и 1..T, то шаблоны [*, :, band, *] и [*, :, coils, *] можно использовать для указания двух срезов через третий индекс. Каждый из которых, определяется многомерной таблицей с двумя индексами слева и одним сверху.
Выбор формата
Расположение срезов для представления многомерных данных не влияет на то, как значения данных используются в модели. Пользователь может свободно выбирать наиболее удобный для него формат. Для приведенного выше параметра cost, может потребоваться сделать срез вдоль третьего измерения, чтобы значения данных были организованы в одну таблицу стоимости доставки cost для каждого продукта PROD. Кроме того, размещение всех пар происхождение-продукт ORIG-PROD слева, дает особенно краткое представление.