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

Переменные

Переменная — неизвестная величина, значение которой определяется решателем. Переменные служат базовыми элементами модели; выражения, ограничения и целевая функция формулируются над ними.

Все переменные модели ограничений целочисленные. Если значения прикладной задачи представлены вещественными числами, они масштабируются до целочисленного диапазона на этапе подготовки данных (стоимость в копейках вместо рублей, длительность в минутах вместо часов).

Способы создания переменных

Любая переменная модели определена на домене — подмножестве целых чисел, из которого решатель выбирает её значение. Различия между методами регистрации сводятся к тому, как этот домен задаётся при создании переменной:

  • Переменные().Добавить — домен не указывается явно: переменная принимает значения из широкого подмножества Int64. Применяется, когда границы заранее неизвестны и выводятся из ограничений.
  • Переменные().ДобавитьИзДиапазона — домен задаётся сплошным интервалом [a, b]. Самый частый способ: множество значений по смыслу укладывается в один диапазон (день недели, индекс смены, номер станка, объём продукции).
  • Переменные().ДобавитьИзДомена — домен передаётся явно произвольной структуры: объединение диапазонов, перечисление значений, дополнение и т.п. Применяется, когда допустимое множество нерегулярное и не сводится к одному диапазону. Способы построения домена описаны в разделе Домены.
  • Переменные().ДобавитьБулеву — домен фиксирован как [0, 1]. Сокращение для частного случая переменной диапазона; помимо обычной целочисленной семантики такая переменная играет особую роль индикатора (см. ниже).
  • Переменные().Константа — домен состоит из одного значения. Удобна как именованное число в ограничениях и выражениях.

Все методы возвращают одинаковую по структуре фиксированную структуру; различается только домен, с которым переменная попадает в модель. Возвращённая структура сохраняется в локальной переменной 1С, передаётся в другие методы и хранится в коллекциях прикладного кода.

Имена переменных

Каждой переменной присваивается имя. Если имя не указано пользователем, оно генерируется автоматически по шаблону _<индекс> (например, _0, _1, _2).

Имя используется в двух сценариях:

  • обращение к значению переменной в решении по имени — без удержания ссылки на объект переменной;
  • запись имени в строковом линейном выражении — например, "2*x + y - 5".

Если переменные впоследствии читаются по имени, осмысленные имена назначаются явно (например, "расход_материала"). При массовой регистрации переменных в цикле автогенерируемых имён обычно достаточно.

Булева переменная как индикатор

Помимо роли обычной целочисленной переменной с диапазоном [0, 1], булева переменная связывает между собой различные части модели:

  • условие активации ограничения — ограничение действует только при истинности булевой переменной (см. Ограничения — обязательные и условные);
  • флаг существования интервала — опциональный интервал учитывается в расписании только при истинности связанной булевой переменной (см. Интервалы и ресурсы);
  • признак выбора альтернативы — ограничения над массивом булевых переменных (ТолькоОдин, НиМенееОдного) задают логику выбора (см. Булева логика);
  • индикатор использования дуги графа — булева переменная отмечает, входит ли дуга в найденный маршрут (см. Графы и автоматы).

Подробное описание приёма «индикатор и его отрицание для дизъюнкции ограничений» приведено в разделе Ограничения — индикаторные булевы переменные.

Из булевых переменных строятся производные булевы выражения без введения новых переменных:

  • отрицание (Модель.Переменные().Отрицание(Б)) — соответствует НЕ Б;
  • константы Переменные().ЗначениеИстина() и Переменные().ЗначениеЛожь() — фиксированные истина и ложь, применяются как нейтральные условия в обобщённом коде.

Производные булевы выражения принимаются в качестве условий ограничений наравне с булевыми переменными.

Массивы переменных

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

  • Переменные().ДобавитьМассив — массив полных переменных;
  • Переменные().ДобавитьМассивИзДиапазона — массив переменных с одинаковым диапазоном;
  • Переменные().ДобавитьМассивИзДомена — массив переменных с общим доменом;
  • Переменные().ДобавитьМассивБулевых — массив булевых переменных.

Все фабрики принимают префикс имени и формируют имена вида <префикс>0, <префикс>1, ... — это позволяет ссылаться на конкретные переменные в строковых выражениях.

Метод Переменные().ДобавитьСловарь связывает целочисленную переменную, принимающую значения 0..N-1, с массивом из N булевых переменных. Эквивалентность двусторонняя: если целочисленная переменная равна i, то i-я булева переменная истинна, остальные ложны. Словарь применяется в задачах, в которых часть ограничений естественнее формулируется над целым числом, а часть — над набором булевых индикаторов выбора.

Типичный сценарий — кодирование перечислений и классификаторов: дней недели (Пн, Вт, Ср, ...), смен (Утро, День, Ночь), разрядов работников (Первый, Второй, Третий), категорий клиентов и т.п. Целочисленная переменная удобна для сквозных ограничений по конкретному значению (например, «день обучения должен совпадать у всей бригады»), а булевы индикаторы — для подсчёта и условной активации других ограничений (например, «не более двух ночных смен подряд» или «если работник второго разряда — доплата за наставничество»).

Например, при планировании дежурств для каждого работника заводится словарь по дням недели:

ДниНедели = 7; // 0 — понедельник, ..., 6 — воскресенье

Для Каждого Работник Из СписокРаботников Цикл

День = Модель.Переменные().ДобавитьИзДиапазона(
0,
ДниНедели - 1,
СтрШаблон("деньДежурства_%1", Работник.Код)
);

Индикаторы = Модель.Переменные().ДобавитьМассивБулевых(
ДниНедели,
СтрШаблон("дежурит_%1_день", Работник.Код)
);

Модель.Переменные().ДобавитьСловарь(День, Индикаторы);

ДеньДежурства [Работник] = День; // удобно для ограничений «у напарников день дежурства совпадает»
ИндикаторыДней [Работник] = Индикаторы; // удобно для ограничений «в субботу дежурят минимум двое»

КонецЦикла;

Та же пара представлений позволяет одновременно сформулировать «у напарников день дежурства совпадает» (через равенство целых переменных) и «в каждый день недели должно быть назначено не менее одного дежурного» (через сумму булевых индикаторов соответствующего дня по всем работникам).

Иллюстрация: переменные для задачи назначения

В задачах задач назначения применяется матрица булевых переменных «работник × задача», в которой значение 1 означает, что работник назначен на задачу:

КоличествоРаботников = СписокРаботников.Количество();
КоличествоЗадач = СписокЗадач.Количество();

Назначения = О2.Утилиты().МассивИзвестногоРазмера(КоличествоРаботников);

Для Р = 0 По КоличествоРаботников - 1 Цикл

Назначения[Р] = Модель.Переменные().ДобавитьМассивБулевых(
КоличествоЗадач,
СтрШаблон("назн_%1_", Р)
);

КонецЦикла;

На построенную матрицу впоследствии накладываются ограничения «каждой задаче ровно один исполнитель», «нагрузка работника не превышает лимита» и аналогичные. Полностью задача с балансировкой нагрузки разобрана на странице Назначение исполнителей с балансировкой нагрузки.

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

Полный набор методов регистрации переменных и работы с булевыми выражениями приведён в разделе Программный интерфейс — Переменные.