Ограничения
Ограничение — условие, которому должно удовлетворять решение. Ограничения добавляются через менеджер ограничений — свойство Ограничения() объекта модели:
МенеджерОграничений = Модель.Ограничения();
Ограничения, поддерживаемые библиотекой, разделены на четыре семейства по характеру условия. В каждом семействе содержится несколько связанных по смыслу методов, отличающихся видом аргументов или режимом работы.
Семейства ограничений
- Ограничения на значения — арифметические соотношения и глобальные ограничения над выражениями: равенства, неравенства, попарная различность, минимум, максимум, произведение, упорядочивание последовательности, разрешённые и запрещённые комбинации, целочисленные операции (модуль, остаток, целочисленное деление), индексирование массива, биекция между массивами.
- Булева логика — ограничения над булевыми переменными и булевыми выражениями: конъюнкция, дизъюнкция, исключающее «или», импликация, ровно один, не более одного, не менее одного.
- Интервалы и ресурсы — ограничения для расписаний и упаковки: интервалы как тройки «начало + размер = конец», запрет перекрытий, прямоугольники для упаковки 2D, конкурентное использование ресурсов, динамические резервуары.
- Графы и автоматы — ограничения, в которых решение представляет собой маршрут на графе или последовательность состояний автомата.
В нетривиальной задаче обычно применяются ограничения нескольких семейств одновременно. Например, в производственном планировании сочетаются интервалы для операций на станках, булева логика для условных переключений между сценариями и ограничения на значения для согласования числовых параметров.
Обязательные и условные ограничения
В большинстве методов установки ограничений присутствует опциональный параметр Условия — набор булевых выражений, объединяемых логическим «И».
- Если
Условияне передан или пуст, ограничение является обязательным: решатель учитывает его всегда. - Если в
Условияпередана булева переменная или массив булевых выражений, ограничение является условным: оно проверяется решателем только тогда, когда все указанные булевы выражения истинны.
ВажныйКлиент = Модель.Переменные().ДобавитьБулеву("важный_клиент");
ВремяДоставки = Модель.Переменные().ДобавитьИзДиапазона(0, 72, "доставка_часы");
// Обязательное ограничение
Модель.Ограничения().ЗначениеМеньшеИлиРавно(ВремяДоставки, 72);
// Условное ограничение: для важного клиента — не позже 24 часов
Модель.Ограничения().ЗначениеМеньшеИлиРавно(
ВремяДоставки,
24,
ВажныйКлиент
);
В качестве условий принимаются не только булевы переменные, но и любые булевы выражения — отрицания, константы Переменные().ЗначениеИстина и Переменные().ЗначениеЛожь (см. Переменные).
Условные ограничения являются основным механизмом гибкости в модели. Вместо пересборки модели при изменении параметров задачи в неё закладываются потенциальные ограничения, активируемые булевыми переменными. Решатель самостоятельно определяет значения этих переменных, балансируя их с целевой функцией и остальными ограничениями.
Индикаторные булевы переменные
Опираясь на условные ограничения, реализуется приём построения дизъюнкции ограничений. Одна и та же булева переменная активирует одно ограничение, а её отрицание — другое. В найденном решении окажется выполнен ровно один из двух наборов ограничений.
В API дизъюнкция «ограничение А или ограничение Б» напрямую не задаётся, но строится связкой из двух условных ограничений:
// Поставка возможна одним из двух способов:
// — стандартный (срок не более 7 дней);
// — экспресс (срок не более 2 дней).
ВыбранЭкспресс = Модель.Переменные().ДобавитьБулеву("экспресс");
СрокПоставки = Модель.Переменные().ДобавитьИзДиапазона(0, 30, "срок_дней");
Модель.Ограничения().ЗначениеМеньшеИлиРавно(СрокПоставки, 7,
Модель.Переменные().Отрицание(ВыбранЭкспресс));
Модель.Ограничения().ЗначениеМеньшеИлиРавно(СрокПоставки, 2,
ВыбранЭкспресс);
Булева переменная ВыбранЭкспресс не задаётся пользователем заранее. Решатель самостоятельно подбирает её значение, и в зависимости от выбора активным оказывается одно из двух ограничений на срок. Этот шаблон («индикатор и его отрицание для дизъюнкции ограничений») является основным способом моделировать конструкцию «или то, или другое» в модели ограничений.
В развитой форме приём применяется для:
- выбора одного сценария из нескольких — массив индикаторов с ограничением
ТолькоОдин; - активации производных параметров — например, при выборе альтернативного поставщика срок доставки увеличивается на фиксированное число дней, и это условие активируется индикатором выбора;
- штрафов за нарушение мягких условий — индикатор «условие нарушено» добавляется в целевую функцию с весом штрафа.
Иллюстрация: согласование комплектности с заказчиком
Допустим, в задаче конфигурации заказа количество позиций согласовано с заказчиком на двух уровнях: либо фиксированный набор из 12 позиций (стандартный комплект), либо набор от 4 до 8 позиций (упрощённый комплект). Решатель самостоятельно выбирает уровень и соответствующее количество.
УпрощённыйКомплект = Модель.Переменные().ДобавитьБулеву("упрощённый");
КоличествоПозиций = Модель.Переменные().ДобавитьИзДиапазона(0, 50, "позиций");
// Стандартный комплект: ровно 12 позиций
Модель.Ограничения().ЗначениеРавно(КоличествоПозиций, 12,
Модель.Переменные().Отрицание(УпрощённыйКомплект));
// Упрощённый комплект: от 4 до 8 позиций
Модель.Ограничения().ЗначениеБольшеИлиРавно(КоличествоПозиций, 4,
УпрощённыйКомплект);
Модель.Ограничения().ЗначениеМеньшеИлиРавно(КоличествоПозиций, 8,
УпрощённыйКомплект);
В найденном решении значение УпрощённыйКомплект определит, какой из двух наборов условий действует, а значение КоличествоПозиций будет согласовано с выбранным набором.
Полный перечень методов
Полный набор методов менеджера ограничений и описание условных ограничений приведены в разделе Программный интерфейс — Ограничения.