Некоторые наборы явно упорядочены, например арифметические прогрессии, интервалы, подмножества упорядоченных наборов, if выражения, чьи предложения then и else являются упорядоченными наборами.
Числа часто используются для представления объектов, таких как периоды времени. Порядок которых важен для спецификации модели. Например, чтобы описать разницу между запасами на текущей неделе и запасами на предыдущей неделе, нам нужно указать недели, чтобы понятие «предыдущая» неделя было четко определено.
Ordered & circular
Модель AMPL может определять свой собственный порядок для любого набора чисел или строк, добавляя ключевое слово ordered или circular (упорядоченный или циркулярный) в объявление набора.
В объявлениях для упорядоченных наборов указывается одна из фраз:
ordered [ by [reversed] sexpr] circular [ by [reversed] sexpr]
Ordered – означает, что массив значений начинается с 1 элемента. Для 1-го элемента отсутствует предшественник. Circular – для 1-го элемента предшественником выступает последний элемент. Порядок, в котором пользователь указывает элементы набора, либо в модели, либо в данных, является порядком, с которым затем будет работать AMPL. Упорядоченные наборы строк часто обеспечивают лучшее описание данных модели, чем наборы чисел. Наборы размером два или более измерений в настоящее время не могут быть упорядоченными ordered или circular. Объявление одномерных упорядоченных наборов происходит следующим образом:
set WEEKS ordered; set WEEKS circular; subject to Balance0 {p in PROD}: Make[p,first(WEEKS)] + inv0[p] = Sell[p,first(WEEKS)] + Inv[p,first(WEEKS)]; subject to Balance {p in PROD, t in WEEKS: ord(t) > 1}: Make[p,t] + Inv[p,prev(t)] = Sell[p,t] + Inv[p,t];
С упорядоченными наборами можно выполнять следующие действия:
first(), last(), member()
- Возвращать значение элемента по его абсолютной позиции в наборе:
first(S) первый элемент S last(S) последний элемент S member(j,S) j-й элемент S; 1 ≤ j ≤ card(S), j целое число first(WEEKS), last(WEEKS), member(5,WEEKS) – 5 элемент массива WEEKS. first(S)- возвращает первый элемент S, last(S)- возвращает последний элемент S, member(j,S) возвращает j-й элемент S.
Следующий пример демонстрирует как можно создавать индексированный набор на основании значения индекса материнского(их) наборов:
set K = 1..10; set k1 = {k in K: k mod 2 = 0} ordered; set k2 = {k in K: k mod 2 = 1} ordered; set ODs{i in 1..card(k1)} = {member(i,k1),member(i,k2 )}; display k1,k2, ODs;
Prev, prevw, next, nextw
2. Возвращать значение элемента по его относительной позиции в наборе:
next(e,S,k) позиция элемента k после элемента e в наборе S next(e,S) то же самое, с k = 1 next(e) следующий элемент набора, для которого e - фиктивный индекс nextw(e,S,k) элемент k занимает позицию после элемента e в наборе S, цикличность nextw(e,S) изменяет направление для версии next(e,S) nextw(e) изменяет направление для версии next(e) prev(e,S,k) позиции элемента k перед элементом e в наборе S prev(e,S) то же самое, с k = 1 prev(e) предыдущий элемент набора, для которого e - фиктивный индекс prevw(e,S,k) элемент k позиционирует перед элементом e в наборе S, цикличность prevw(e,S) циклическая версия prev(e,S) prevw(e) циклическая версия prev(e)
Если S - выражение для упорядоченного набора из n элементов, e - j-й элемент S , а k - целочисленное выражение, тогда next (e,S,k) является элементом j+k из S, если 1≤ j+k ≤ n, в противном случае - ошибка. Если S является циклическим, тогда next (e,S,k) является элементом 1+((j+k-1) mod n) из S. Функция nextw (next с циклическим переходом) такая же, как и next, за исключением того, что она обрабатывает все упорядоченные наборы как циклические. prev (e,S,k) ≡ next (e,S,-k) и prevw (e,S,k) ≡ nextw (e,S,-k). Допускается несколько сокращений. Если k не задано, оно принимается равным 1. Если k и S опущены, то e должен быть фиктивным индексом в области действия выражения индексации, которое выполняется через S, например, как в {e in S}.
Выражения: prev (t,WEEKS,5), next (t,WEEKS,3), означает 5 элемент до элемента со значением t и 3 элемент после элемента со значением t. Во всех указанных функциях первый аргумент должен содержать число или строку, второй аргумент - упорядоченный набор, а третий - целое число. next (t,WEEKS,0) совпадает с t, а next (t,WEEKS,-5) совпадает с prev (t,WEEKS,5).
Если первый аргумент next, nextw, prev, prevw или ord является фиктивным индексом, который перебирает упорядоченный набор, а набор не указан в качестве второго аргумента (но связанный с ним индексный набор предполагает t in WEEKS, тогда функции ord (t) и prev (t) интерпретируются так, как если бы они были записаны как: prev (e,S).
Card, arity, indexarity
Встроенная функция card вычисляет количество элементов входящих в набор. Функция card работает с любым конечным набором: card (sexpr) возвращает количество элементов в sexpr. Если sexpr является выражением индексации, скобки можно опустить. Например:
card({i in A: x[i] >= 4}) или card {i in A: x[i] >= 4}
Например, card(NUTR) - вычисляет количество элементов в NUTR.
Например:
model; set PROD; set PROD2 = PROD diff {1}; data; set PROD:= 1, 2, u,p; display card(PROD diff PROD2);
Команда display возвращает значение 1.
Функция arity возвращает арность заданного аргумента. функция indexarity возвращает арность набора индексации ее аргумента.
arity (S) арность S, если S - множество, иначе 0; для использования с _SETS
indexarity (E) арность набора индексации объекта E.
Ord & card
3. Функции, которые возвращают положение элемента в наборе:
ord (e,S) порядковый номер элемента e в S;
ord (e) порядковый номер элемента e в наборе, для которого он является фиктивным индексом;
ord0 (e,S) порядковый номер элемента e в S; 0, если нет;
ord0 (e) то же, что и ord (e);
card(S) количество элементов в наборе S;
ord (t, WEEKS) возвращает числовую позицию t в пределах набора WEEKS или выдает сообщение об ошибке, если t не является элементом WEEKS. Альтернативный ord0 (t, WEEKS) такой же как ord (), за исключением того, что он возвращает 0, если t не является элементом WEEKS.
ord (t, WEEKS) и prev (t, WEEKS)
Функцией ord можно подсчитать количество элементов набора. Запись:
ord (last (Groups),Groups) эквивалентна card (Groups)
Для этих функций первый аргумент должен иметь положительное целое число или строку, а второй - упорядоченное множество.
subject to Balance {p in PROD, t in WEEKS: ord(t) > 1}: Make[p,t] + Inv[p,prev(t)] = Sell[p,t] + Inv[p,t];
Полная модель и данные показаны ниже. В качестве компромисса для более значимых названий недель, мы должны написать немного более сложную модель.
set PROD; # Продукты set WEEKS ordered; # Номер недель param rate {PROD} > 0; # Производительность тонн/час param inv0 {PROD} >= 0; # initial inventory param avail{WEEKS} >= 0; # Доступное количество часов/неделя param market{PROD,WEEKS} >= 0; # Ограничение объема продаж тонн/неделя param prodcost{PROD} >= 0; # Стоимость производства руб./тонна param invcost{PROD} >= 0; # carrying cost/ton of inventory param revenue{PROD,WEEKS} >= 0; # Прибыль от продаж var Make{PROD,WEEKS} >= 0; # Производительность тонн var Inv{PROD,WEEKS} >= 0; # tons inventoried var Sell{p in PROD, t in WEEKS} >= 0, <= market[p,t]; # продажна тонн maximize Total_Profit: sum{p in PROD, t in WEEKS} (revenue[p,t]*Sell[p,t] - prodcost[p]*Make[p,t] - invcost[p]*Inv[p,t]); # Целевая функция: общая выручка – затраты по всем периодам subject to Time {t in WEEKS}: sum {p in PROD} (1/rate[p]) * Make[p,t] <= avail[t]); # Total of hours used by all products # may not exceed hours available, in each week subject to Balance0 {p in PROD}: Make[p,first(WEEKS)] + inv0[p] = Sell[p,first(WEEKS)] + Inv[p,first(WEEKS)]; subject to Balance {p in PROD, t in WEEKS: ord(t) > 1}: Make[p,t] + Inv[p,prev(t)] = Sell[p,t] + Inv[p,t]; # Tons produced and taken from inventory # must equal tons sold and put into inventory set PROD:= bands coils ; set WEEKS:= 27sep 04oct 11oct 18oct ; param avail:= 27sep 40 04oct 40 11oct 32 18oct 40 ; param rate:= bands 200 coils 140 ; param inv0:= bands 10 coils 0 ; param prodcost:= bands 10 coils 11 ; param invcost:= bands 2.5 coils 3 ; param revenue: 27sep 04oct 11oct 18oct := bands 25 26 27 27 coils 30 35 37 39 ; param market: 27sep 04oct 11oct 18oct := bands 6000 6000 4000 6500 coils 4000 2500 3500 4200 ;
card () может применяться и для неупорядоченных наборов.
ord & member
Аналогия между ord и member:
param Sold {d in DAYS}:= sum {dd in DAYS: ord(dd) <= ord(d)} UnitSales[dd]; эквивалентно: param Sold1{d in DAYS}:= sum {dd in 1..ord(d)} UnitSales [member (dd, DAYS)];
Упорядоченные множества также можно использовать с любыми операторами и функциями AMPL, которые применяются к множествам в целом. Результат операции diff сохраняет порядок левого операнда, поэтому ограничение баланса материала может быть записано так:
subject to Balance{p in PROD, t in WEEKS diff {first(WEEKS)}}: Make[p,t] + Inv[p,prev(t)] = Sell[p,t] + Inv[p,t];
Однако для union, inter и symdiff упорядочение результата не является четко определенным. AMPL рассматривает результат как неупорядоченный набор.
Ord - выбор четных и не четных элементов
Ord можно использовать для выборки четных и нечетных элементов набора.
set X ordered := {'a','b','c','d','e'}; # условие отбора нечетных элементов набора display {j in X: ord(j) mod 2 = 1}; set {j in X: ord(j, X) mod 2 == 1} := a c e; # условие отбора четных элементов набора display {j in X: ord(j) mod 2 = 0}; set {j in X: ord(j, X) mod 2 == 0} := b d;
Набор значений по четным/нечетным значениям набора
set K = 1..10; set k1 = {k in K: k mod 2 = 0}; set k2 = {k in K: k mod 2 = 1}; display k1,k2;
или
param K = 10; set k1 = 2..K by 2; set k2 = 1..K by 2; display k1,k2;
ordered by & circular by
Для набора, содержащегося в упорядоченном наборе, AMPL предоставляет способ сказать, что порядок должен быть унаследован через выражение ordered by и circular by.
Если набор S упорядочен ordered by T или circular by T, тогда набор T сам должен быть упорядоченным набором, содержащим S, и S наследует порядок от T. Если упорядочивающей фразой является by reversed T, то S наследует обратный порядок от T. Последние элементы становятся первыми. Если S упорядочено ordered by T или circular by T и не указано упорядочение by sexpr, то применяется один из двух случаев. Если элементы S явно указаны выражением = {member-list} в модели или списком элементов в разделе данных, S принимает порядок этого списка. Если S рассчитан из назначенного или заданного по умолчанию sexpr в модели, AMPL сохранит порядок явно упорядоченных наборов (поясняется ниже), а в противном случае может выбрать произвольный порядок.
Предположим, например, что мы хотим попробовать запустить многопериодную модель производства с горизонтами разной длины. В следующих декларациях упорядоченный набор ALL_WEEKS и параметр T определены в данных, в то время как подмножество WEEKS определяется выражением индексации, которое включает только первые T недель:
set ALL_WEEKS ordered; param T > 0 integer; set WEEKS = {t in ALL_WEEKS: ord(t) <= T} ordered by ALL_WEEKS;
Мы указываем ordered by ALL_WEEKS, чтобы WEEKS стал упорядоченным набором, причем его элементы имеют тот же порядок, что и в ALL_WEEKS. Фразы ordered by и circular by имеют тот же эффект, что и фразы ordered или circular, за исключением того, что они также заставляют объявленный набор наследовать упорядочение из содержащего набора.
ordered by reversed & circular by reversed
Фразы ordered by reversed и circular by reversed, приводят к тому, что объявленный набор имеет порядок, противоположный порядку содержащего набора. Все эти фразы могут использоваться либо с подмножеством, предоставленным в данных, либо с подмножеством, определенным выражением, как в примере выше.