Приёмы моделирования
Прикладные задачи часто содержат конструкции, которые в их «естественной» формулировке нелинейны: фиксированные затраты, активные только при принятии решения; правила, действующие в одних режимах работы и не действующие в других; отклонения по модулю; ступенчатые функции стоимости; альтернативные технологические маршруты.
Прямо в линейные выражения такие конструкции не помещаются. Большинство из них выразимо через стандартные приёмы моделирования — введение вспомогательных переменных и булевых индикаторов с дополнительными линейными ограничениями.
Приёмы из этого раздела — рабочий инструментарий смешанно-целочисленного программирования. Они позволяют оставаться в рамках линейной модели для широкого класса задач планирования и распределения ресурсов. В учебной и исследовательской литературе по операциям и оптимизации они известны под именами «big-M reformulation», «disjunctive constraints», «piecewise-linear approximation» и составляют ядро практики MIP-моделирования.
Если в задаче много разнородных условных ограничений, число вспомогательных переменных и big-M-ограничений быстро делает модель непрактичной. В такой ситуации задачу целесообразно перенести на модель ограничений. Она поддерживает условные ограничения и нелинейные конструкции на уровне готовых семейств ограничений.
Индикаторные переменные и big-M
Сценарий. Непрерывная переменная x ⩾ 0 — например, объём производства на линии — может принимать положительное значение только при активации (запуске линии). Активация связана с фиксированными затратами F, которые включаются в целевую функцию только при x > 0.
Формулировка. Вводится булева переменная-индикатор y ∈ {0, 1} («линия активна»). Связь между x и y выражается ограничением:
x ⩽ M · y
Здесь M — заведомо большое значение, ограничивающее x сверху. При y = 0 ограничение даёт x ⩽ 0, что в сочетании с x ⩾ 0 даёт x = 0. При y = 1 ограничение становится x ⩽ M — фактически неактивно при содержательно выбранном M.
Выбор M. Чрезмерно большое M — типичная причина медленного поиска. Оно ослабляет LP-релаксацию, и метод ветвей и границ перебирает существенно больше ветвей.
На практике M назначается равным содержательной верхней границе переменной x — мощности установки, оперативному лимиту, бюджету. «Заведомо большое число» в качестве M — плохая практика. Если содержательная граница известна, её и следует использовать. Если нет, ставится разумная и расширяется только при необходимости.
Прикладные задачи. Фиксированные затраты на открытие склада, на запуск производственной линии (lot-sizing), на использование транспортного средства; задачи facility location.
МощностьЛинииСутки = 10000;
ОбъёмВыпуска = Модель.Переменные().ДобавитьИзДиапазона(0, МощностьЛинииСутки, "ОбъёмВыпуска");
ЛинияАктивна = Модель.Переменные().ДобавитьБулеву("ЛинияАктивна");
// Объём положителен только при активной линии
Модель.Ограничения().ЗначениеМеньшеИлиРавно(
ОбъёмВыпуска,
Модель.Выражения().Терм(ЛинияАктивна, МощностьЛинииСутки)
);
// В целевой функции — переменные затраты на единицу плюс фиксированные затраты на запуск
Модель.ЦелеваяФункция().Минимизировать(
Модель.Выражения().Сумма(
Модель.Выражения().Терм(ОбъёмВыпуска, СтоимостьЕдиницы),
Модель.Выражения().Терм(ЛинияАктивна, ФиксированныеЗатратыНаЗапуск)
)
);
Условные ограничения через big-M
Сценарий. Ограничение a · x ⩽ b должно действовать только в активном режиме, отмеченном булевой переменной y = 1. При y = 0 ограничение игнорируется. Пример: лимит на расход дешёвого сырья действует только при использовании альтернативной рецептуры.
Формулировка. К правой части добавляется слагаемое big-M, которое «выключает» ограничение при y = 0:
a · x ⩽ b + M · (1 − y)
При y = 1 множитель обнуляется, ограничение принимает исходный вид. При y = 0 правая часть увеличивается на M, и нарушить ограничение становится фактически невозможно — при содержательно выбранном M.
Прикладные задачи. Правила, действующие только в активные периоды планирования; нормативные ограничения, привязанные к выбранному режиму; ограничения по сорту сырья при выборе альтернативной рецептуры.
Расход = Модель.Переменные().ДобавитьИзДиапазона(0, БольшойЛимит, "Расход");
РежимАктивен = Модель.Переменные().ДобавитьБулеву("РежимАктивен");
// При активном режиме расход не превышает Лимит; при неактивном — ограничение снимается
ВыключательОграничения = Модель.Выражения().Сумма(
Лимит,
Модель.Выражения().Терм(РежимАктивен, -БольшойЛимит) // -M*y; при добавлении M даёт M*(1-y)
);
Модель.Ограничения().ЗначениеМеньшеИлиРавно(
Расход,
Модель.Выражения().Сумма(
ВыключательОграничения,
БольшойЛимит
)
);
Дизъюнкция «либо одно, либо другое»
Сценарий. Должно быть выполнено одно из двух ограничений, но не обязательно оба. Пример: изделие обрабатывается либо на станке A со временем tA, либо на станке B со временем tB.
Формулировка. Каждому варианту ставится в соответствие булева переменная-индикатор y₁, y₂ с условием:
y₁ + y₂ ⩾ 1— обязателен хотя бы один вариант;y₁ + y₂ = 1— ровно один вариант.
Каждое из дизъюнктных ограничений записывается в условной форме через big-M (см. предыдущий раздел). Оно действует только при истинности соответствующего индикатора.
Прикладные задачи. Альтернативные технологические маршруты обработки изделия, выбор поставщика с различающимися условиями, выбор схемы загрузки оборудования.
МаршрутA = Модель.Переменные().ДобавитьБулеву("МаршрутA");
МаршрутB = Модель.Переменные().ДобавитьБулеву("МаршрутB");
// Изделие проходит ровно по одному маршруту
Модель.Ограничения().ЗначениеРавно(
Модель.Выражения().Сумма(МаршрутA, МаршрутB),
1
);
// Соответствующие операционные ограничения активируются по индикатору
// (запись через big-M аналогична разделу выше)
Абсолютное значение в целевой функции
Сценарий. Минимизируется отклонение фактического значения от целевого по модулю. Примеры: отклонение фактического выпуска от плана, отклонение остатка склада от норматива, отклонение нагрузки от средней.
Формулировка. Минимизация |x| для свободной по знаку переменной x (или |f(x)| для линейного выражения) сводится к замене на новую неотрицательную переменную t ⩾ 0 и пару линейных ограничений:
t ⩾ x, t ⩾ −x
В целевую функцию вместо |x| включается t. При минимизации решатель выберет t равным max(x, −x) = |x|, что и требовалось.
Условие применимости. Приём работает, когда |x| входит в целевую функцию с положительным коэффициентом при минимизации (или с отрицательным при максимизации). В обратном случае минимум t не совпадёт с |x| — потребуется введение булевой переменной знака и big-M-формулировка.
Прикладные задачи. Минимизация суммарного отклонения плана от прогноза, выравнивание нагрузки между подразделениями, регрессия по модулю отклонений (L¹).
Отклонение = Модель.Переменные().ДобавитьИзДиапазона(0, БольшоеЗначение, "Отклонение");
ФактическийВыпуск = Модель.Переменные().ДобавитьИзДиапазона(0, МощностьСутки, "ФактическийВыпуск");
// Отклонение ⩾ |ФактическийВыпуск - Плановый|
Модель.Ограничения().ЗначениеБольшеИлиРавно(
Отклонение,
Модель.Выражения().Выражение(СтрШаблон("%1 - %2", ФактическийВыпуск.Имя, ПлановыйВыпуск))
);
Модель.Ограничения().ЗначениеБольшеИлиРавно(
Отклонение,
Модель.Выражения().Выражение(СтрШаблон("%1 - %2", ПлановыйВыпуск, ФактическийВыпуск.Имя))
);
Модель.ЦелеваяФункция().Минимизировать(Отклонение);
Минимум и максимум выражений
Сценарий. В целевой функции участвует максимум (или минимум) из нескольких выражений: пиковая нагрузка, наихудшее по сценариям отклонение, минимальный из остатков по складам.
Формулировка. Для z = max(f₁, f₂, …, fₙ) вводится новая переменная z и набор ограничений:
z ⩾ f₁, z ⩾ f₂, …, z ⩾ fₙ
В целевую функцию включается z, направление поиска — минимизация. Для z = min(...) всё симметрично: z ⩽ fᵢ и максимизация.
Условие применимости такое же, как для абсолютного значения: знак z в целевой функции должен «прижимать» переменную к нужному значению.
Прикладные задачи. Минимизация пиковой загрузки оборудования, минимизация наибольшего отклонения по группе показателей (минимаксная задача), задача о справедливом распределении нагрузки.
ПиковаяНагрузка = Модель.Переменные().ДобавитьИзДиапазона(0, МаксНагрузка, "ПиковаяНагрузка");
Для Каждого Период Из Периоды Цикл
// ПиковаяНагрузка ⩾ Нагрузка[Период]
Модель.Ограничения().ЗначениеБольшеИлиРавно(
ПиковаяНагрузка,
Нагрузка[Период]
);
КонецЦикла;
Модель.ЦелеваяФункция().Минимизировать(ПиковаяНагрузка);
Кусочно-линейная функция
Сценарий. Зависимость нелинейная по форме, но представима последовательностью линейных участков. Примеры: ступенчатые скидки от объёма закупки, ступенчатый тариф на электроэнергию, ставка налога с прогрессивной шкалой, ступенчатые затраты на хранение.
Формулировка. Аппроксимация кусочно-линейной функции в линейной модели выполняется через сегментацию. Переменная-аргумент представляется как сумма переменных-сегментов:
x = x₁ + x₂ + … + xₖ, 0 ⩽ xᵢ ⩽ Δᵢ
Значение функции — сумма произведений сегментов на угловые коэффициенты соответствующих участков.
Если порядок выбора сегментов важен (следующий участок используется только после полного исчерпания предыдущего), добавляются булевы переменные-индикаторы участков и связывающие big-M-ограничения.
Прикладные задачи. Lot-sizing со ступенчатыми затратами на партию, прогрессивные тарифы и налоги, затраты на хранение и оборотные средства, объёмные скидки.
Кусочно-линейные конструкции — наиболее техноёмкий из приёмов моделирования. В больших задачах требуется аккуратное управление численной стабильностью и качеством LP-релаксации. Полные сценарии — в специализированной литературе по линейному программированию и в примерах со ступенчатыми функциями стоимости.
Дискретный выбор «один из вариантов»
Сценарий. Из набора альтернатив (поставщиков, технологических маршрутов, конфигураций оборудования) выбирается ровно одна или не более одной.
Формулировка. Каждому варианту ставится в соответствие булева переменная yᵢ ∈ {0, 1}. Условие выбора:
- Σ yᵢ = 1 — выбрана ровно одна альтернатива;
- Σ yᵢ ⩽ 1 — выбрана не более одной альтернативы;
- Σ yᵢ ⩾ 1 — выбрана хотя бы одна альтернатива.
Содержательные параметры выбранного варианта — стоимость, сроки, нормативы — включаются в модель через произведение этих параметров на соответствующую yᵢ.
Прикладные задачи. Выбор поставщика, выбор размещения склада из нескольких кандидатов, выбор конфигурации продукта, задачи о назначениях. Полный пример — Назначение исполнителей.
ВыбранПоставщик = Модель.Переменные().ДобавитьМассивБулевых(
ПоставщикиКандидаты.Количество(),
"ВыбранПоставщик"
);
// Ровно один поставщик
Модель.Ограничения().ЗначениеРавно(
Модель.Выражения().Сумма(ВыбранПоставщик),
1
);
// Стоимость закупки = сумма стоимостей выбранного поставщика
СтоимостьЗакупки = Модель.Выражения().СоздатьПостроительВыражений();
Для К = 0 По ПоставщикиКандидаты.ВГраница() Цикл
СтоимостьЗакупки.ДобавитьТерм(
ВыбранПоставщик[К],
ЦенаПоставщика[К]
);
КонецЦикла;
Линейное масштабирование коэффициентов
Скорость и численная стабильность поиска существенно зависят от порядков величины коэффициентов модели.
Если в одной модели одновременно присутствуют переменные с диапазонами в сотни тысяч (рубли) и в десятых долях (доли, проценты), а коэффициенты — от микроскопических нормативов до больших стоимостей, матрица модели становится плохо обусловленной. Малые погрешности округления накапливаются, решатель замедляется, статус решения может стать неустойчивым.
Стандартный приём — приведение к одному порядку:
- рубли пересчитываются в тысячи рублей или в миллионы;
- время — в часах или в минутах в зависимости от характерной длительности задачи;
- доли — в процентах.
После расчёта значения масштабируются обратно на этапе обработки решения.
Контрольные признаки плохого масштабирования:
- большие значения констант
Mв big-M-ограничениях — десятки тысяч и больше при содержательных значениях переменных в единицах; - коэффициенты в одной строке матрицы, различающиеся на 6 и более порядков.
При таких признаках масштабирование выполняется до запуска решателя.
См. также
- Переменные — типы переменных и роль булевых индикаторов
- Ограничения — условные ограничения и операторы
- Целевая функция — многокритериальная свёртка
- Модель ограничений (CP-SAT) — альтернатива для задач с богатой условной логикой
- Примеры использования — полные сценарии прикладных задач