Добавление бинарного ограничения в Pulp python без нарушения ограничения линейности - PullRequest
1 голос
/ 09 апреля 2020

Уважаемые коллеги python пользователей,

Я строю многопериодную модель планирования нескольких продуктов с использованием Pulp. То, что должна делать модель, довольно просто: планируйте производство с учетом минимальных затрат на хранение и производства при удовлетворении спроса.

У меня есть следующие данные:

periods = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
products = ['A', 'B', 'C']

И я создаю следующие переменные:

prod_vars = pulp.LpVariable.dicts('production', [(i,j) for i in products for j in periods],0) 
inv_vars = pulp.LpVariable.dicts('inventory', [(i,j) for i in products for j in periods],0)

Есть 2 ограничения, 1 для удовлетворения спроса и 1 для оставаться ниже производственных мощностей. Обратите внимание, что существует фрейм данных (input_data), который извлекает значение данного спроса для этого периода.

for i in products:
    for j in periods[1:]: 
        model.addConstraint(pulp.LpConstraint(
                    e=inv_vars[(i,j-1)] + prod_vars[(i,j)] - inv_vars[(i,j)],
                sense=pulp.LpConstraintEQ,
                name='inv_balance_'  + str(i)+ str(j),
                rhs=input_data[i][j-1]))

for j in periods:
model.addConstraint(pulp.LpConstraint(
    e=(pulp.lpSum(prod_vars[(i,j)] for i in products)),
    sense=pulp.LpConstraintLE,
    name='total_production_capacity'+str(j),
    rhs=(input_data['production_capacity'][j-1])

Затем я добавляю функцию стоимости и устанавливаю цель:

total_production_cost = production_cost*pulp.lpSum(prod_vars)
total_holding_cost =holding_cost * pulp.lpSum(inv_vars)

target = total_holding_cost + total_production_cost + активации_cost model.setObjective (target)

Эта модель отлично работает и выдает такой вывод. prod_vars: (A, 1) = 5, (B, 1) = 10, (C, 1) = 15 и т. д. для всех периодов. Тем не менее: я хочу наказать систему для производства нескольких продуктов. То есть добавление фиксированных затрат при выборе для производства второго или третьего продукта. Тогда было бы более выгодно производить больше продукта А и хранить запасы в течение нескольких месяцев, чем производить А каждый месяц. Я попытался сделать это, добавив еще одну переменную:

use_vars = pulp.LpVariable.dicts('uselocation', [(i,j) for i in products for j in periods] , 0,1,pulp.LpBinary)

И добавив фиксированные затраты на использование переменной:

activation_cost = pulp.lpSum(activation_cost*use_vars[(i,j)] for i in products for j in periods)

Я думаю, что мне нужно будет умножить все мои prod_vars на мои use_vars в два ограничения. Однако, если бы я сделал это в моем первом ограничении инвентаря, Pulp выдает ошибку, что мое ограничение больше не является линейным.

Кто-нибудь знает, как я могу это сделать ?? Заранее спасибо:)

Ответы [ 2 ]

1 голос
/ 10 апреля 2020

Я хочу наказать систему за производство нескольких продуктов. То есть добавление фиксированных затрат при выборе второго или третьего продукта.

Лучше всего отойти от кода и посмотреть на него математически.

Let x(i,t)>=0 be the production of item i in period t 

По мере необходимости чтобы посчитать, нам нужны бинарные переменные. Итак, введем:

y(i,t) = 1 if item i is produced in period t
         0 otherwise

Затем мы можем добавить

x(i,t) <= M*y(i,t)   (M large enough constant: i.e. capacity)

Это реализует y(i,t)=0 => x(i,t)=0. Нам не нужно беспокоиться об обратном x(i,t)=0 => y(i,t)=0, так как об этом позаботится цель (минимизируйте стоимость).

Чтобы добавить особые затраты на производство 2 или 3 продуктов, нам нужен один дополнительная двоичная переменная:

count(k,t) = 1 if the number of products produced is k (k=0,1,2,3)
           = 0 otherwise

Это можно рассчитать как:

 y(A,t)+y(B,t)+y(C,t) = 1*count(1,t)+2*count(2,t)+3*count(3,t)   
 count(1,t)+count(2,t)+count(3,t) <= 1

Теперь вы можете добавить слова: 100*count(2,t)+200*count(3,t) к вашему расчету стоимости. (Примечание: только для полноты: я предположил, что стоимость трех продуктов, по крайней мере, равна стоимости двух продуктов).

0 голосов
/ 10 апреля 2020

Чтобы достичь того, что вы хотите, вы можете добавить дополнительные ограничения, соединяющие prod_vars и use_vars например (псевдокод):

prod_vars[(i, j)] >= use_vars[(i, j)] forall i, j
prod_vars[(i, j)] <= M * use_vars[(i, j)] forall i, j

, где M может быть установлено на max(input_data['production_capacity']).

Для этого вам не нужно изменять исходные ограничения.

...