Перейти к основному содержимому

Ограничения

Менеджер ограничений (Модель.Ограничения()) объединяет несколько категорий правил, на которые опирается решатель помимо топологии и целевой функции:

  • выражения-ограничения — условия на линейные комбинации переменных;
  • границы значений ресурсов в точках маршрута — жёсткие пределы значений ресурсов в конкретных позициях маршрута (основа временных окон);
  • группы альтернативных узлов (дизъюнкции) — наборы узлов, из которых нужно посетить заданное число; за каждый непосещённый узел платится штраф;
  • пары погрузки и доставки — два узла, обслуживаемые одним маршрутом, причём погрузка раньше доставки;
  • политики погрузки и доставки — порядок обработки активных пар на маршруте (Любая / 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);

Сигнатуры:

Модель.Ограничения().РесурсВТочкеМаршрутаНеМенее(Ресурс, ТочкаМаршрута, Значение)
Модель.Ограничения().РесурсВТочкеМаршрутаНеБолее(Ресурс, ТочкаМаршрута, Значение)

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

Shared depot и ТочкаМаршрута

Если несколько транспортных средств стартуют из одного узла-Депо, у каждого ТС своя стартовая точка маршрута. Для ограничения на значение ресурса в стартовой позиции конкретного ТС используйте Модель.ТочкиМаршрута().ПолучитьСтарт(ТС) — вместо узла Депо.

Группы альтернативных узлов (дизъюнкции)

Группа альтернативных узлов — это набор узлов, из которых маршрут обязан посетить заданное число (НормаПосещений) или меньше. За каждый непосещённый узел группы к общей стоимости добавляется штраф.

Модель.Ограничения().ГруппаАльтернативныхУзлов(
Узлы,
Штраф,
НормаПосещений = Неопределено
)
  • Узлы — массив идентификаторов узлов (объект, имя или индекс — все формы равноправны).
  • Штраф — целое число, штраф за каждый непосещённый узел группы.
  • НормаПосещений — необязательное целое: сколько узлов группы максимум может быть посещено. По умолчанию ограничение сверху отсутствует.

Дизъюнкция — это базовый механизм, через который реализуются два разных по смыслу сценария.

Опциональный узел со штрафом

Узел оборачивается в группу из одного элемента с заданным штрафом — посещение перестаёт быть жёстким требованием:

Клиент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.Утилиты().Массив(Фура)
);

После такой регистрации узел может попасть только в маршрут указанного транспортного средства; для прочих он становится недостижимым. Если разрешённых ТС несколько — массив включает их все.

Полный перечень методов

Полный набор методов менеджера ограничений — в разделе Программный интерфейс — Ограничения.