Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Моделирование и оптимизация в LINGO

..pdf
Скачиваний:
10
Добавлен:
12.11.2023
Размер:
2.55 Mб
Скачать

SETS:

MONTHS /JAN..DEC/;

DAYS /SUN..SAT/; ENDSETS

CALC:

YR, MN, DAY, DWK = @STM2YMD( @STMNOW()); @WRITE(

'Год: ', YR, @NEWLINE( 1),

'Месяц: ', MONTHS( MN), @NEWLINE( 1), 'День: ', DAY, @NEWLINE( 1),

'День недели: ', DAYS( DWK), @NEWLINE( 1), );

ENDCALC

Результат:

Год: 2017

Месяц: FEB День: 21

День недели: TUE

Шесть функций @STM2YR(stm), @STM2MON(stm), @STM2DAY(stm), @STM2HR(stm), @STM2MIN(stm), @STM2SEC(stm) преобразуют скалярное время соответственно в год, месяц, день, часы, минуты и секунды.

Функция @STM2DWK(stm) конвертирует скалярное время в день недели (его номер). При этом первым днем считается воскресенье, а седьмым – суббота.

6.7. Другие функции

Функция @BLOCKROW(block_index, row_name), аргументами которой являются номер блока и имя строки, входящей в блок, применяется при использовании BNP решателя. При нескольких строках, входящих в блок, функция повторяется с одним индексом блока.

Хорошо известная в программировании конструкция

@IF (logical_condition, true_result, false_result)

позволяет возвращать значение, зависящее от истинности или ложности условия. Например, она применима в модели производственной системы, в которой при ненулевом выпуске продукции в затраты входят и фиксированные расходы на организацию выпуска, иначе затрат нет. Следует иметь в виду, что функция @IF вносит

51

в модель нелинейность и разрывность функции в нуле, что затрудняет нахождение глобального решения. Иногда в таких случаях LINGO может выполнить линеаризацию, если в окне Lingo Options

на вкладке Model Generator установить опцию Linearization Degree на уровень Math and Logical.

Функция @USER(user_determined_arguments) может быть представлена пользователем как внешняя DLL или файл с объектным кодом. В подразд. 8.4.3 мы вернемся к ней и на примере покажем ее создание.

7. ПРОГРАММИРОВАНИЕ МОДЕЛИ И РЕШЕНИЯ

LINGO предоставляет возможности программирования, включающие в себя контроль модели, управление порядком выполнения операторов, генерирование модели, использование операторов вывода, установку всех параметров, организацию решения стохастических задач, а также ряд утилит.

Большинство операторов программирования применяются в CALC-секции для написания скрипта, определяющего, что и в каком порядке выполнять.

Нередко при моделировании и решении сложных задач приходится иметь дело не с единой математической моделью задачи, а с рядом разных моделей (подмоделей), которые нуждаются в передаче данных между собой и должны решаться в определенной последовательности и/или, возможно, в цикле.

Для выделения подмоделей в разделе ММ предназначены операторы SUBMODEL и ENDSUBMODEL, между которыми записываются выражения соответствующей подмодели. Каждой подмодели присваивается уникальное имя, которое записывается после SUBMODEL и заканчивается двоеточием.

Например:

SUBMODEL OBJECTIVE: MIN=@SUM(TIME(I): X(I));

ENDSUBMODEL

52

При решении задачи с подмоделями используется функция @SOLVE, размещаемая в секции CALC. Синтаксис этой функции:

@SOLVE( [SUBMODEL_NAME[, …, SUBMODEL_NAME_N]]),

где в качестве аргумента имеем имя подмодели или список имен подмоделей. В случае списка LINGO объединяет подмодели и решает их как единую модель. Если же аргументы отсутствуют, то LINGO будет выполнять все операторы выше функции @SOLVE,

не входящие в подмодели. В секции CALC число функций @SOLVE,

как правило, больше одной, и в таких случаях решение происходит в том порядке, в каком записаны функции.

Для отладки подмоделей при неограниченности критерия или противоречивости условий применяется функция @DEBUG, располагаемая в секции CALC. Ее аргументами являются имена подмоделей:

@DEBUG( [SUBMODEL_NAME[, …, SUBMODEL_NAME_N]]).

Соответственно действие функции распространяется на одну или несколько подмоделей, отлаживаемых как единая модель. При отсутствии аргумента отладке подлежат все операторы выше функции, не входящие в подмодели.

В случае необходимости распознавания ситуации можно использовать функцию @STATUS, которая возвращает финальный статус решения. Возможные значения статуса и их смысл приведены в табл. 2.

 

Таблица 2

 

 

Значения

Интерпретация

0

Global Optimum – Найдено глобальное оптимальное решение

1

Infeasible – Нет допустимых решений

2

Unbounded – Целевая функция не ограничена

3

Undetermined – Остановка процесса решения

4

Feasible – Найдено допустимое решение, которое может быть и

 

не оптимальным

5

Infeasible or Unbounded – Препроцессор определил недопусти-

 

мость или неограниченность модели. Для уточнения статуса

 

можно отключить препроцессорную обработку и повторить за-

 

пуск решения

53

 

Окончание табл. 2

 

 

Значения

Интерпретация

6

Local Optimum – Найдено локальное оптимальное решение

7

Locally Infeasible – Хотя допустимые решения могут быть,

 

LINGO их не нашел

8

Cutoff – Достигнут заданный уровень целевой функции

9

Numeric Error – Решатель остановился из-за неопределенной

 

арифметической операции в одном из ограничений

Следующий пример иллюстрирует применение последних двух функций:

MODEL:

. . . .

SUBMODEL Proba:

. . . .

ENDSUBMODEL CALC:

@SOLVE(Proba);

@IFC( @STATUS() #NE# 0: @DEBUG(Proba)); ENDCALC

END

Используемый здесь оператор @IFC позволяет проверять условия. Полная форма условного оператора, применяемая для ветвления хода решения, имеет вид

@IFC( <conditional-exp>: statement_1[; …; statement_n;]

[@ELSE

statement_1_1[; …; statement_1_n;]] );

При этом, как и в других языках программирования, допускается вложение этого оператора в другой такой же оператор.

Синтаксис оператора @FOR в CALC-секции такой же, как в разделе ММ, но его действие иное: в CALC-секции он не генерирует ограничения модели, а только создает цикл выполнения операторов по элементам множества, определенного в аргументах @FOR. Пример:

Title Числа Фибоначчи; sets:

NUMBER /1..6/: f;

54

endsets data:

f=1,1,,,,; enddata calc:

@FOR(NUMBER(I): f(I+2)=f(I+1)+f(I);@IFC(I #EQ# 4: @BREAK);

); endcalc

Получаем решение:

Model Title: Числа Фибоначчи

Variable

Value

F( 1)

1.000000

F( 2)

1.000000

F( 3)

2.000000

F( 4)

3.000000

F( 5)

5.000000

F( 6)

8.000000

Операторы @BREAK, @PAUSE(‘text’) и @STOP(‘text’) дейст-

вуют так же, как одноименные в других языках программирования. Оператор @WHILE, как и @FOR, предназначен для организа-

ции цикла в CALC-секции согласно синтаксису:

@WHILE( <conditional-exp>: statement_1[; …; statement_n;]);

Пока условие истинно, выполняется цикл по операторам (statements), определенным как аргументы функции @WHILE.

Когда в CALC-секции переменной присваивается фиксированное значение, тогда при выполнении оператора @SOLVE она не может изменяться. Чтобы вернуть такой переменной возможность изменяться (быть оптимизируемой), применяется функция @RELEASE, аргументом которой является имя фиксированной переменной. Пример:

@FOR( DAY( D):

!Переменной START(D) присваивается нулевое значение;

START(D) = 0; @SOLVE();

!Запоминается значение целевой функции;

OBJ0(D) = OBJ;

55

! Переменная START(D) становится свободной;

@RELEASE( START(D));

);

Как было показано в первых разделах, в решатель посылается не исходная модель, а преобразованная. Для преобразования модели в формат, совместимый с решателем, используются два оператора.

Оператор @GEN генерирует развернутую прямую модель, в которой раскрыты все условия и переменные.

Оператор @GENDUAL преобразует исходную модель линейного программирования в развернутую двойственную модель.

Аргументами этих операторов являются имена подмоделей. При нескольких именах генерируется развернутая модель всех перечисленных подмоделей как единая модель. Если имена отсутствуют, будет развернута та часть модели, которая записана выше @GEN или @GENDUAL и не содержит подмоделей. По умолчанию развернутая модель посылается на дисплей. Аналогичные действия вы-

зывают команды меню Solver/Generate/Display model и …/Dual. Ге-

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

Следующий пример демонстрирует получение развернутых моделей:

SETS:

Products /A B/:Price,X;

Resources /one two three four/:Q; Consumption (Resources,Products): U;

ENDSETS

DATA:

Price=10 7;

Q=20 9 45 37; U= 2 5

1 3

9 6

3 2; ENDDATA

max=@SUM(Products: Price*X); @FOR(RESOURCES: [DV]@SUM(Products:U*X)<=Q);

CALC:

@WRITE('Прямая модель ',@NEWLINE(1));

56

@GEN();

@WRITE('Двойственная модель ',@NEWLINE(1)); @GENDUAL();

ENDCALC

В окне отчетов получим:

Прямая модель

MODEL:

[_1] MAX= 10 * X_A + 7 * X_B; [DV_ONE] 2 * X_A + 5 * X_B <= 20; [DV_TWO] X_A + 3 * X_B <= 9; [DV_THREE] 9 * X_A + 6 * X_B <= 45; [DV_FOUR] 3 * X_A + 2 * X_B <= 37; END

Двойственная модель

MODEL:

MIN= 20 * DV_ONE + 9 * DV_TWO + 45 * DV_THREE + 37 * DV_FOUR;

[X_A] 2 * DV_ONE + DV_TWO + 9 * DV_THREE + 3 * DV_FOUR >= 10;

[X_B] 5 * DV_ONE + 3 *DV_TWO + 6 *DV_THREE + 2 * DV_FOUR >= 7;

END

Здесь [DV_ONE]- [DV_FOUR] – имена ограничений в прямой модели и двойственные переменные в двойственной модели.

Для получения развернутых моделей в форматах MPI или MPS и направления их в заявленный файл используется оператор @SMPI или @SMPS соответственно.

Суммарную статистику по развернутым моделям можно получить оператором @STATS( [SUBMODEL_NAME[, …,

SUBMODEL_NAME_N]]).

 

Теперь

обсудим два оператора

вывода, которые наряду

с функциями

отчета, рассмотренными

выше, могут применяться

в секциях DATA, INIT, а также в скрипте CALC-секции. Оператор вывода @SOLU вводится согласно синтаксису:

@SOLU( [0|1[,MODEL_OBJECT[, 'REPORT_HEADER']]]).

При отсутствии аргументов он выводит на дисплей стандартный отчет LINGO, содержащий полученное решение. Когда первый

57

аргумент равен нулю, выводятся только ненулевые переменные и связанные строки. Если же он равен 1, будет показана вся информация. Для вывода определенной информации следует указать 2-й аргумент, который может быть либо атрибутом, либо именем строки. Последний аргумент используется для вывода заголовка.

Основным средством вывода в CALC-секции является оператор @WRITE. Его аргументами могут быть текст и значения:

@WRITE('TEXT1'|VALUE1[,…,'TEXTN'|VALUEN]).

Он аналогичен одноименной функции подготовки отчетов, но в секции CALC используется как оператор (без функции вывода

@TEXT()).

По умолчанию вывод посылается на экран. Для перенаправления его в файл используется оператор @DIVERT, аргументом которого является имя файла. Он используется дважды: для открытия специфицированного именем файла и для его закрытия (имя опускается), после которого вывод снова идет на стандартное устройство. Следующий фрагмент иллюстрирует сказанное:

CALC:

@SOLVE();

@DIVERT( 'MYREPORT.TXT');

@WRITE(. . ., @NEWLINE(1)); @WRITE(. . ., @NEWLINE(1));

. . . . . .

!WS и NC – переменные;

@WRITE( ' WS = ', WS, @NEWLINE(1), ' NC = ', NC, @NEWLINE(2));

. . . . . .

@DIVERT();

ENDCALC

Если файл существует, добавление 2-го аргумента в виде символа ‘А’ приведет к записи в конец этого файла, иначе файл будет перезаписан. Операторы @DIVERT могут быть вложенными, обеспечивая тем самым вывод в файлы нескольких уровней.

Среди пакетов оптимизации не существует единого формата записи модели. В LINGO есть два оператора, которые генерируют модель и пишут ее в файл в формате MPI или MPS. Это операторы

58

@SMPI и @SMPS соответственно. Аргументом их является имя файла, а необязательные последующие аргументы представляют имена подмоделей.

Для изменения или установки параметров применяется оператор @SET согласно синтаксису:

@SET(‘PARAM_NAME’, PARAMETER_VALUE).

Измененному параметру можно возвратить значение по умолчанию, опустив второй аргумент. Если при этом вместо имени указать ‘DEFAULT’, то все параметры вернутся к значениям по умолчанию. В пособии не приводится подробное описание многочисленных параметров LINGO, а краткое описание и значения по умолчанию всех параметров, используемых в режиме командной строки, вынесены в приложение 4. Здесь поясним только параметр TERSEO, устанавливаемый оператором @SET, который определяет объем выводимой информации. Он может принимать 3 значения (моды):

0 (Verbose) – полный вывод, включая отчеты о решении (значение по умолчанию);

1 (Terse) – краткий вывод, не содержащий отчета о решении или экспорте данных;

2 – минимальный вывод или вывод операторами WRITE;

3 (Errors only) – вывод операторами WRITE и сообщения об ошибках.

Помимо оператора @SET параметры интерфейса, генерации моделей и решателей доступны для изменения через команду меню

Solver|Options.

Кроме того, ряд параметров в библиотеке решателя LINDO API, недоступных через стандартную установку, можно установить функцией @APISET.

Как и в других языках программирования, в LINGO могут использоваться процедуры. Процедура начинается с заголовка PROCEDURE <имя процедуры>: и заканчивается словом ENDPROCEDURE. Между ними записываются операторы, разрешенные в секции CALC. Процедуры создают собственную секцию

59

модели, которую обычно размещают в конце раздела ММ. При решении модели процедуры автоматически не выполняются: для их вызова делаются ссылки на их имена в секции CALC.

Пример структуры модели:

Sets:

. . . . .

Endsets

Date:

. . . . .

Enddate Submodel A:

. . . . .

Endsubmodel

. . . . .

Submodel C:

. . . . .

Endsubmodel PROCEDURE PRIMER:

. . . . .

ENDPROCEDURE CALC:

@SET('TERSEO', 2); @SOLVE(A, C);

@WRITE( @NEWLINE(2), 10*' '); PRIMER;

@SOLVE(B, C;);

@WRITE( @NEWLINE(2), 10*' '); PRIMER;

ENDCALC

Специальные операторы языка LINGO предназначены для решения задач стохастического программирования, их несколько десятков, и они здесь не рассматриваются. Соответственно не приводятся функции распределения вероятностей, включающие категории кумулятивных, инверсных и PDF распределений, каждая из которых содержит 24 оператора. Описание названных операторов и функций и применения LINGO для решения задач стохастического программирования требует отдельного пособия. В настоящем пособии не приводятся также функции построения диаграмм и графиков (их 17), соответствующие 13 типам графического отображения данных

60

Соседние файлы в папке книги