Математическая формулировка задачи
v2020.12.23
Базовая модель:
- бинарные (0 или 1) переменные для каждого заказа (приняли/отклонили)
- отгрузка продукции - это принятые заказы
- объем производства ограничен сверху мощностью
- запасы для каждого дня - это накопленное производство минус накопленная отгрузка
- запасы неотрицательные
- объем склада не ограничен
- срок хранения каждого продукта ограничен
- максимизиурем выручку минус затраты в деньгах
- связанные продукты - для производства одного продукта нужны другие продукты
- в ц.ф. добавляем штраф на величину запасов
(May change order in list above)
0. Размерность (время и продукты)
0.1 Мы решаем задачу отбора заказов и планирования выпуска на горизонте \(n_{days}\) дней
0.2 Мы рассматриваем производство четырех продуктов, которым присвоены буквенные обозначения.
1. Производство, отгрузка, запасы
1.1 Производство
\(prod_{pt}\) - объем производства продукта p в день t, тонн
Объем производства определяется как результат решения задачи оптимизации.
На основе объемов производства рассчитываются затраты:
1.2 Отгрузка
\(ship_{pt}\) - отгрузка продукта p в день t, тонн
Рассчитывается исходя из выбранных заказов (см. ниже).
1.3 Совокупный объем использования
\(req_{pt}\) - требуемый объем использованием продукта p в день t, тонн
Он рассчитывается исходя из матрицы полных затрат. Расчет описан здесь, можем представить в виде матриц:
\(B_{ij}\) - количество единиц товара \(j\), напрямую необходимых для выпуска единицы товара \(i\) (матрица прямых затрат).
\(R_{ij}\) - количество единиц товара \(j\), непосредстванно или косвенно необходимых для выпуска единицы товара \(i\) (матрица полных затрат).
\(R = (I-B)^{-1}\)
Если \(y = [y_A, y_B, y_C, y_D]\) - вектор-строка с количеством каждого продукта для продажи, то \(x = yR\) - полный выпуск каждого продукта с учетом внутреннего потребления.
Пример:
from numpy import array, identity, matmul
from numpy.linalg import inv
B = array([[0. , 0. , 0. ],
[0.1, 0. , 0. ],
[0. , 1.2, 0. ]])
R = inv(identity(3) - B)
# array([[ 1. , 0. , 0. ],
# [ 0.1 , 1. , -0. ],
# [ 0.12, 1.2 , 1. ]])
y = array ([1, 1, 1])
x = matmul(y, R)
# array([1.22, 2.2 , 1. ])
1.5 Запасы
\(inventory_{pt}\) - запасы продукта p в конец дня t, тонн
Запасы определяются как разница между накопленной суммой производства и накопленным использованием:
2. Заказы
2.1 Структура данных заказа
Завод на весь период планирования получает \(n_{orders}\) заказов на различные продукты:
В каждом заказе указаны (k - порядковый номер заказа):
- продукт \(product_k\), который заказан
- объем поставки \(volume_k\) (тонн)
- день поставки \(day_k\)
- цена поставки \(price_k\) (долл. США за тонну)
2.2 Переменные выбора заказа
Для каждого заказа создается бинарная переменная accept, которая показывает решение принимать заказ или нет:
2.3 Расчеты на основе заказов
Объем поставок:
Объем продаж:
3. Ограничения
3.1 Мощность
Ежедневный объем производства неотрицательный и ограничен сверху мощностью
3.2 Запасы неотрицательные
3.3 Закрытая сумма за период
Сумма производства равна сумме отгрузки для каждого продукта:
Комментарий: возможно, это ограничение становится незначимо после введения ограничений на минимизацию запасов.
3.4 Ограничение срока хранения
Запасы на день d не должны превышать использования продукта за следующие \(s_p\) дней, где \(s_p\) - это максимальный срок хранения p продукта на складе.
Комментарий: в первое неравенство можно подставить срок хранения s=1, тогда остаток на складе должен быть не больше объема следующего дня использования (\(req_{p,d+1}\))
Ключевые слова: shelf life, product life, "условие непротухания".
4. Целевая функция
\(\lambda \cdot inventory\) - штраф, позволяющий минимзировать запасы. \(\lambda\) берется меньше цены продукта.
5. Результат расчетов
- \(prod_{pt}\) - объем производства по дням
- \(accept_{k}\) - бинерные переменные выбора заказов
Возможные изменения
- разные варианты целевых функций
- матричная форма записи
- сроки производства продукта более 1 дня
- веса для штрафа по запасам пропорциональны цене