Ограничения
Менеджер ограничений (Модель.Ограничения()) объединяет несколько категорий правил, на которые опирается решатель помимо топологии и целевой функции:
- выражения-ограничения — условия на линейные комбинации переменных;
- границы значений ресурсов в точках маршрута — жёсткие пределы значений ресурсов в конкретных позициях маршрута (основа временных окон);
- группы альтернативных узлов (дизъюнкции) — наборы узлов, из которых нужно посетить заданное число; за каждый непосещённый узел платится штраф;
- пары погрузки и доставки — два узла, обслуживаемые одним маршрутом, причём погрузка раньше доставки;
- политики погрузки и доставки — порядок обработки активных пар на маршруте (Любая / LIFO / FIFO);
- разрешённые транспортные средства для узла — узел можно обслужить только подмножеством ТС.
Выражения-ограничения
Условие на линейные комбинации переменных модели (включая ресурсные и маршрутные). Выражения собираются через менеджер Выражения.
Доступные операторы сравнения:
Модель.Ограничения().ЗначениеРавно(Выражение1, Выражение2)
Модель.Ограничения().ЗначениеНеРавно(Выражение1, Выражение2)
Модель.Ограничения().ЗначениеБольше(Выражение1, Выражение2)
Модель.Ограничения().ЗначениеБольшеИлиРавно(Выражение1, Выражение2)
Модель.Ограничения().ЗначениеМеньше(Выражение1, Выражение2)
Модель.Ограничения().ЗначениеМеньшеИлиРавно(Выражение1, Выражение2)
Глобальные предикаты:
Модель.Ограничения().ВсеРазличные(Выражения) // значения всех выражений попарно различны
Модель.Ограничения().МинимумРавен(Выражения, Значение) // минимум среди значений = Значение
Модель.Ограничения().МаксимумРавен(Выражения, Значение) // максимум среди значений = Значение
Модель.Ограничения().ЗначениеВСписке(Выражение, Значения) // выражение принимает одно из перечисленных значений
Все методы принимают опциональный параметр Условия — массив булевых выражений, при которых ограничение «включается». Если Условия пуст или не задан, ограничение действует безусловно.
Границы значения ресурса в точке маршрута
Жёсткие границы значения ресурса в конкретной точке маршрута — главный механизм описания временных окон:
Клиент1 = Модель.Узлы().Получить("Клиент1");
ТочкаКлиента1 = Модель.ТочкиМаршрута().ПолучитьПоУзлу(Клиент1);
// Клиент1 принимает с 09:00 до 11:00 (минуты от полуночи)
Модель.Ограничения().РесурсВТочкеМаршрутаНеМенее("Время", ТочкаКлиента1, 540);
Модель.Ограничения().РесурсВТочкеМаршрутаНеБолее("Время", ТочкаКлиента1, 660);
Сигнатуры:
Модель.Ограничения().РесурсВТочкеМаршрутаНеМенее(Ресурс, ТочкаМаршрута, Значение)
Модель.Ограничения().РесурсВТочкеМаршрутаНеБолее(Ресурс, ТочкаМаршрута, Значение)
Если ни один маршрут не способен обслужить узел внутри его окна, задача станет невыполнимой. В таких ситуациях узел можно сделать опциональным через дизъюнкцию или ослабить границу до мягкой через штраф за превышение/недобор.
Если несколько транспортных средств стартуют из одного узла-Депо, у каждого ТС своя стартовая точка маршрута. Для ограничения на значение ресурса в стартовой позиции конкретного ТС используйте Модель.ТочкиМаршрута().ПолучитьСтарт(ТС) — вместо узла Депо.
Группы альтернативных узлов (дизъюнкции)
Группа альтернативных узлов — это набор узлов, из которых маршрут обязан посетить заданное число (НормаПосещений) или меньше. За каждый непосещённый узел группы к общей стоимости добавляется штраф.
Модель.Ограничения().ГруппаАльтернативныхУзлов(
Узлы,
Штраф,
НормаПосещений = Неопределено
)
Узлы— массив идентификаторов узлов (объект, имя или индекс — все формы равноправны).Штраф— целое число, штраф за каждый непосещённый узел группы.НормаПосещений— необязательное целое: сколько узлов группы максимум может быть посещено. По умолчанию ограничение сверху отсутствует.
Дизъюнкция — это базовый механизм, через который реализуются два разных по смыслу сценария.
Опциональный узел со штрафом
Узел оборачивается в группу из одного элемента с заданным штрафом — посещение перестаёт быть жёстким требованием:
Клиент1 = Модель.Узлы().Получить("Клиент1");
Модель.Ограничения().ГруппаАльтернативныхУзлов(
О2.Утилиты().Массив(Клиент1),
1000 // штраф за пропуск
);
Применение: «при нехватке транспортных средств часть клиентов можно перенести на завтра» — каждому переносимому клиенту назначается штраф, эквивалентный «стоимости переноса». Решатель оставит без обслуживания тех, для кого крюк дороже штрафа.
Выбор одной альтернативы из нескольких
Группа из нескольких узлов с НормаПосещений = 1 — например, у клиента есть несколько доступных точек разгрузки, и нужно выбрать одну:
Модель.Ограничения().ГруппаАльтернативныхУзлов(
О2.Утилиты().Массив("Точка1", "Точка2", "Точка3"),
0,
1 // ровно одна точка из группы
);
Пары погрузки и доставки
Пара погрузки и доставки — это два связанных узла:
- узел погрузки — где транспортное средство забирает груз;
- узел доставки — где транспортное средство отдаёт груз.
При регистрации пары решатель обязан включить оба узла в маршрут одного и того же транспортного средства, причём узел погрузки должен предшествовать узлу доставки в порядке обхода.
Модель.Ограничения().ПогрузкаИДоставка(
УзелПогрузки,
УзелДоставки,
УпорядочивающийРесурс = Неопределено
)
УпорядочивающийРесурс — опциональный параметр: ресурс, по которому навязывается строгое возрастание значения от точки погрузки к точке доставки. Применяется, когда порядок «погрузка раньше доставки» нужно зафиксировать через значения конкретного ресурса (например, времени), а не только через позицию в маршруте.
ОтправительА = Модель.Узлы().Получить("Отправитель_А");
ПолучательА = Модель.Узлы().Получить("Получатель_А");
Модель.Ограничения().ПогрузкаИДоставка(ОтправительА, ПолучательА);
Это базовый механизм для задач курьерской доставки и сборных перевозок. Пары можно дополнительно связать с ресурсом «груз»: погрузка увеличивает значение ресурса, доставка уменьшает — решатель будет следить, чтобы транспортное средство в любой момент маршрута не превышало свою грузоподъёмность.
Политики погрузки и доставки
Политика — это правило, по которому транспортное средство обрабатывает активные пары (те, у которых уже была погрузка, но ещё не было доставки). Поддерживаются три политики:
| Политика | Поведение |
|---|---|
| Любая | Активные пары обрабатываются в любом порядке; ограничение — только на «погрузка раньше доставки» внутри одной пары. По умолчанию. |
| LIFO | «Last-In-First-Out» — что погружено последним, доставляется первым. Применяется, когда контейнеры или паллеты физически складываются стопкой и доставать «снизу» нельзя. |
| FIFO | «First-In-First-Out» — что погружено первым, доставляется первым. Применяется, когда нужно обеспечить очередь. |
Политика устанавливается на уровне транспортного средства, не модели в целом — у разных ТС могут быть разные политики:
ТС = Модель.ТранспортныеСредства().Получить("ТС1");
Модель.Ограничения().ПолитикаПогрузкиИДоставки(
ТС,
Перечисления.О2_Routing_ПолитикиПогрузкиИДоставки.LIFO
);
Разрешённые транспортные средства для узла
По умолчанию любой узел может быть обслужен любым транспортным средством. Если нужно ограничить — например, у крупногабаритного заказа клиента только один большегруз способен подъехать — на узел вешается список разрешённых ТС:
КрупныйЗаказ = Модель.Узлы().Получить("Крупный_заказ");
Фура = Модель.ТранспортныеСредства().Получить("ТС_фура");
Модель.Ограничения().РазрешенныеТранспортныеСредстваУзла(
КрупныйЗаказ,
О2.Утилиты().Массив(Фура)
);
После такой регистрации узел может попасть только в маршрут указанного транспортного средства; для прочих он становится недостижимым. Если разрешённых ТС несколько — массив включает их все.
Полный перечень методов
Полный набор методов менеджера ограничений — в разделе Программный интерфейс — Ограничения.