Все началось с того, что мне довелось поучаствовать в увлекательном проекте. В рамках тендера необходимо было разработать прототип системы производственного планирования для парфюмерно-косметического предприятия. Прототип необходимо было реализовать в виде модуля для 1С:ERP.
Технического задания не было. Вводные данные поступали малыми порциями по мере раскуривания ментатами. Задача из обыденного “давайте тут красиво отобразим доступные остатки” стремительно трансформировалась в “отрисуй-ка мне здесь детальное расписание загрузки оборудования с учетом этого, этого и, возможно, еще вот этого, но это не точно…”.
Сложность разработки прототипа усугублялась тем, что производство косметики подразумевает работу с жидкостями, а жидкости:
можно переливать, и тогда надо понимать, куда именно и в какой момент;
можно не переливать, и тогда аппарат превращается в ячейку хранения и исключается из процесса производства;
все же рано или поздно нужно куда-то перелить, и тогда приходится учитывать длину подающих шлангов и расположение оборудования относительно друг друга;
могут пачкать поверхности, и тогда их надо очищать, а способ и длительность очистки зависят от жидкости и поверхности;
да много там всего у этих жидкостей…
Стало понятно, что заказчик ждет от нас рабочий алгоритм, который:
формирует валидное расписание на несколько дней вперед с учетом разнообразных требований (взаимной удаленности оборудования, порядкозависимой переналадки, технических особенностей аппаратов, численности персонала по графику работы и пр.);
оптимизирует расписание по одному или нескольким параметрам (минимизация простоя, минимизация переналадок, минимизация неиспользуемого объема аппаратов и пр.).
Где взять этот алгоритм?
Вариантов немного. Мне известно три.
Вариант “Я у мамы инженер”
Вы пишете собственный алгоритм планирования прямо в 1С. Закидываетесь энергетиком. Обильно уделываете своими токенами конфигуратор.
Алгоритм готов. Вы привели в этот мир то, чего здесь быть не должно. Оно не работает, как вам нужно. Оно не работает, как нужно заказчику. Оно работает, как может.
На вопрос “почему” вы уже знаете ответ:
Оно работает не быстро. Сама платформа 1С не торопится. Разница с низкоуровневыми языками примерно в 30 раз. Арифметика, работа со структурами данных — все тлен;
Оно работает на одном ядре. Многопоточности в 1С нет;
Оно считает десятичными (decimal) числами. Целых чисел нет. Чисел с плавающей запятой нет;
Оно не тестировалось никем, кроме вас. Готовых алгоритмических библиотек в 1С нет. Ничего нет.
Этот вариант вообще не выглядит как план.
Вариант “Я системный интегратор”
Вы достаете где-то готовую APS-систему. Выбрать нужно ту, где есть презентация на двести слайдов со словами “optimization” или “оптимизация”, если это отечественное ПО.
Вероятно, вам повезет, и APS сможет загрузить в себя данные переработанных заказов, переработанных спецификаций, переработанных регистров с параметрами производства, а презентация будет достаточно убедительной, чтобы обосновать, что отдельный рабочий стол/экран/монитор — это и есть модуль для 1С:ERP.
Вам не повезет.
Вариант “Lego. Собери сам”
Вы ищете библиотеку для математической оптимизации. Раскуриваете ее в одиночестве или в паре со своим GPT-терапевтом. Вокруг выбранной библиотеки поднимаете службу.
На стороне 1С наворачиваете рабочий стол с диаграммой Ганта и другими впечатляющими воображение элементами. Собираете данные, необходимые для планирования, и отправляете их в свой самописный софт. Результаты вычислений принимаете обратно и красиво отображаете в виде разноцветных прямоугольников.
Выглядит как план! Звучит как план!
Это работает?!
Это работает! На Хабре есть замечательный канал Алексея Ложкинса, где он популярным языком рассказывает про алгоритмы математической оптимизации и приводит примеры решения часто встречающихся задач. Статьи, посвященной операционному планированию, на канале пока нет, зато есть статья про планирование расписаний сотрудников. Принципы, описанные в этой статье, те же. Настоятельно рекомендую к прочтению, если вы интересуетесь подобным матаном и хотите применить его где-то на практике.
У меня применить получилось. Прототип подсистемы планирования заработал и на демонстрациях заказчику бодро перерисовывал Ганта. При этом получилось реализовать следующую магию:
парковку заданий передним или задним бампером в зависимости от типа операции;
отображение интервалов простоя аппаратов в момент их разгрузки на конвейерах;
отображение интервалов переналадки с учетом порядка следования этапов;
учет плановой и внеплановой недоступности аппаратов;
перераспределение заданий с учетом численности рабочего персонала (параллельные задания становились последовательными, если численности не хватало);
многопараметрическую оптимизацию с учетом матрицы удаленностей, матрицы переналадок и недогрузки объемов варочных аппаратов;
возможность ручной фиксации интервалов на графике с последующей “перетанцовкой” расписания;
последовательную достройку графика с учетом уже существующего графика за предыдущие дни.
Выглядело это все космически, и тендер отдали нам.
После данного краткого вступления можно перейти и к самой сути статьи.
А в чем, собственно, проблема?
А проблема в том, что реализованный прототип — это всего лишь прототип, и в нем были учтены далеко не все требования, которые предстояло бы учесть в продуктивном варианте. Но на этапе создания прототипа уже стало понятно, что сам процесс его реализации имеет существенные недостатки:
вести разработку приходится минимум на двух платформах, а значит, на этапе полноценного проекта большинство регулярных кодеров 1С задействовать не получится, придется искать специалистов со специфическими навыками или кодить в четыре руки;
при быстро меняющихся требованиях скорость разработки сильно проседает, т.к. приходится модифицировать не только основные алгоритмы, но и транспортный слой — переделывать DTO, их заполнение на одной стороне и обработку на другой, а потом то же самое в обратном направлении. Отладка тоже затруднена: искать баг нужно в коде обеих сторон и в транспорте;
документация к алгоритмическим библиотекам может быть недостаточно полной или подразумевать у разработчика какой-то ненулевой багаж знаний в этой области, поэтому можно серьезно подвиснуть при реализации какой-то простой фичи, которая обычно делается за несколько минут.
Возник вопрос: можно ли реализовать подход, при котором преимущества сохраняются, а недостатки — нет?
Что делать?
Решение задачи математической оптимизации можно разбить на два этапа:
На первом этапе разработчик с помощью API библиотеки описывает математическую модель. В модели он определяет переменные (неизвестные величины), описывает, какие между ними есть соотношения и ограничения, а также указывает, что именно необходимо оптимизировать.
На втором этапе описанный пазл (модель) передается решающему алгоритму (решателю). Решатель должен за разумное время подобрать значения переменных. Найденные значения — это и есть решение.
Благодаря такому разделению мат. модель, сохраненная в какой-то универсальный формат, может быть решена алгоритмами разных производителей. То есть формирование модели и ее решение не обязательно должно происходить с использованием одной библиотеки, и не обязательно в рамках одной программной платформы. Это и есть ключ!
Далее ход мыслей следующий:
решать модель на стороне 1С мы не можем, т.к. алгоритмических библиотек нет и сама платформа не про это;
формировать модель на стороне 1С мы можем, т.к. для этого не нужна экстремальная производительность;
для формирования модели на стороне 1С потребуется какой-то API, а значит, нужно расширение, которое его предоставляет;
если мы формируем модель на стороне 1С, то исходные бизнес-данные никуда передавать не надо, они уже зашиты внутри модели, нам достаточно только получить их из БД и подставить в модель в виде конкретных числовых значений;
сформированная на стороне 1С модель будет иметь утвержденный формат, а значит, и механизмы передачи этой модели решателю можно тоже заранее утвердить и реализовать в том же расширении;
раз данные из 1С будут передаваться в стандартизированном виде, то необходимо реализовать сервис, который будет принимать эти данные и передавать их далее решателю в уникальном для решателя формате;
раз мы все равно пишем готовый сервис для обработки моделей из 1С, то ничто не мешает включить в этот сервис несколько решателей, чтобы разработчик на стороне 1С мог переключаться между ними при необходимости;
в таком виде прикладной программист 1С отвечает только за описание мат. модели с помощью встроенного API, а сам API, алгоритмический сервис и механизмы транспорта поставляются уже готовыми, то есть в виде готовой платформы, которую можно отдельно задокументировать;
такая платформа может иметь собственный жизненный цикл, не привязанный к конкретной системе конкретного предприятия.
Выглядит как что-то, что можно попробовать. Остается реализовать прототип.
Как я провел лето
На первый релиз ушел месяц. В него вошли:
расширение для описания мат. модели на 1С;
дистрибутив на .Net, который работает как ASP-служба и как консольная утилита (маленькие модели решаем синхронно через REST, а большие асинхронно через файлики и консоль);
в качестве решателя — CP-SAT от Google.
Кроме CP-SAT существуют и другие промышленные решатели, но, чтобы теперь достать для них лицензию, нужна не только пехота, но и флот.
Модуль планирования переписался под новую схему. Код, отвечающий за решение модели, сильно сократился и умещался примерно в 500 строк. Код самописной службы ликвидировался за ненадобность, вместо нее теперь отрабатывал “коробочный” сервис.
Еще несколько месяцев ушло на:
покрытие тестами;
реализацию сайта с документацией и примерами;
написание конвейера для автоматической сборки релизов под различные платформы;
добавление решателей для линейных и сетевых моделей.
Вот так теперь выглядит для программиста 1С задача смешивания из двух переменных:
// Хотим произвести столы и стулья, но материалы ограничены. Как быть? // Ограничения: древесина (20 ед.) и краска (18 ед.) // Прибыль: стул — 3 у.е., стол — 5 у.е. // 1. Создаем модель Модель = О2.СоздатьМодель(); // 2. Объявляем переменные модели КолвоСтульев = Модель.Переменные().Добавить("X"); КолвоСтолов = Модель.Переменные().Добавить("Y"); // 3. Описываем ограничения Модель.Ограничения().Соотношение("X >= 0; Y >= 0"); Модель.Ограничения().Соотношение("2 * X + 4 * Y <= 20"); // <-- расход древесины Модель.Ограничения().Соотношение("3 * X + 2 * Y <= 18"); // <-- расход краски // 4. Устанавливаем цель — максимизировать прибыль Модель.ЦелеваяФункция().Максимизировать("3 * X + 5 * Y"); // 5. Решаем модель Решение = Модель.Решить(); // <-- здесь происходит магия // 6. Наслаждаемся результатом Сообщить("Количество стульев: " + Решение.ЗначениеПеременной(КолвоСтульев)); // --> 4 Сообщить("Количество столов: " + Решение.ЗначениеПеременной(КолвоСтолов)); // --> 3 Сообщить("Максимальная прибыль: " + Решение.ЗначениеЦелевойФункции()); // --> 27
В данном примере O2 — это имя основного фасада расширения, сокращение от “Оптимизация операций”.
Так как служба решателя — это теперь отдельно поддерживаемый компонент, то удалось реализовать различные варианты его развертывания:
локально на сервере 1С (дистрибутив встраивается в само расширение и запускается как консольная утилита);
как служба на отдельном узле;
как бессерверная функция в Яндекс.Облако (для kid-size моделей).
Для выбора варианта достаточно передать параметр:
Сервис = О2.Сервисы().Локальный(); // или Сервис = О2.Сервисы().ВебСлужба(Новый HTTPСоединение("my-server.local", 4762)); // или Сервис = О2.Сервисы().ЯндексОблако("func_id", "func_token"); ПараметрыПоиска = О2.СоздатьПараметрыПоиска(Сервис); Решение = Модель.Решить(ПараметрыПоиска);
Окончательно стало понятно, что схема рабочая, когда получилось решить задачу раскроя пластиковых панелей для случайно обратившегося к нам производителя стеклопакетов. На создание рабочего стола по планированию у программиста 1С ушло примерно три с половиной часа и не потребовало никаких интеграций.
Этим программистом не был Альберт Эйнштейн.
Выводы
Подход работает. Расширение для 1С описывает математическую модель, отдельный сервис решает её, а программист на стороне 1С не выходит за пределы привычной платформы. Не нужна интеграция, не нужны отдельные специалисты, не нужно знание мат. библиотек — достаточно освоить декларативный стиль описания задач.
Но есть нюансы.
Из-за патологической нерасторопности 1С могут возникать обратные “релятивистские” эффекты, при которых время на формирование модели требуется больше, чем на её решение. Обычно такое проявляется на моделях небольшого размера на серверах с включенным режимом отладки. Не критично, но имейте в виду.
Документация к проекту, к сожалению, не обладает заявленными магическими свойствами: коллегам по-прежнему трудно переключаться с привычного императивного подхода на декларативный. Требуется время на адаптацию, но оно окупается. После освоения технологии мозг уже подсознательно пытается найти ей применение даже в тех местах, где и так все вроде бы работает без всякой оптимизации.
Зато документацию весьма бодро всасывают ИИ-агенты. Opus 4.7 вообще входит в режим “батя-кодинга” и начинает выдавать крайне нетривиальные логико-математические этюды, как будто его тренировали на альтернативной версии GitHub, забитого терабайтами BSL-кода. Полагаю, это позволит в скором будущем создавать системы планирования, которые будут корректировать алгоритмы в реальном времени.
Надеюсь, эта статья поможет быстро сориентироваться, когда понадобится решать алгоритмические задачи в 1С. Я не стал перегружать ее примерами решения типовых задач, но если вам эта тема интересна, отпишитесь в комментариях — я вынесу их в отдельную публикацию.
Интересных вам проектов!
DMGarikk
Довелось коснуться этой темы, причем тоже с Алексеем Ложкинсом, только лично :) никогда бы не подумал что коснусь этой темы, но довелось делать очень интересный проект в сфере APS, главная проблема этой отрасли это не сам матан и моделирование, а просто категорическое отсутствие обычных программистов которые готовы и хотят вообще в этом направлении что-то делать, из-за чего качество кода таких сервисов это прямо рукалицо
Также бизнес у нас явно не готов с софту такого класса с вычислениями и моделированием.
GreenBear Автор
Как раз сегодня демонстрировал на крупном производстве форму, в которой эта штука пересчитывает модель на 15 тыс. параметров. Технолог заявил, что он не понимает как оно работает, и пытался на бумажке показать, как он руками в экселе каждый раз руками что то передвигает и сверяет получившиеся остатки. А Ганта просто строит в уме. Технологии на базе естественного интеллекта.