Распределение рабочих мест по производству пленок для нескольких машин для производства пленок с помощью PuLP (python)

Я пытаюсь решить проблему, которая чем-то похожа на проблему с упаковкой бункера. В этой задаче я должен распределять задания на машины для производства пленки, где машины имеют разную ширину пленки. Все машины должны иметь одинаковый объем использования. Каждый рулон имеет определенную ширину. Машина может выполнять несколько заданий длинной, если сумма ширины всех заданий меньше ширины пленки машины.

Я смоделировал это как проблему с упаковкой мусорного ведра. Поскольку мне нужно было убедиться, что на всех машинах одинаковое количество рулонов, у меня есть ящики как двумерный массив, где каждый тип имеет несколько ящиков. В моей формулировке c - это вместимость машины, x - это двоичная переменная, которая указывает, используется ли корзина, y - двоичная переменная, которая указывает, назначен ли рулон корзине. Общая цель - свести к минимуму образующиеся отходы.

 уравнение

Исходя из этого, я написал код Python с использованием пульпы.

from pulp import *
prob = LpProblem("Production Problem",LpMinimize)
capacity = [1350, 2100]
rolls = [970, 1050, 970, 1100, 1050, 500, 500, 500, 1050, 1350,1200, 370]
I = range(2) # machine film width
J = range(10) # bins for each machine film width 
K = range(len(rolls)) # number of rolls in total 

# variable to determine wether a particular bin is used
x = LpVariable.dicts(name = "Bin", indexs = ((i,j) for i in I for j in J), cat = 'Binary')
# variable to determine if roll is assigned to a particular bin 
y = LpVariable.dicts(name = "RollBin", indexs = ((i,j, k) for i in I for j in J for k in K), cat = 'Binary')
# variable to calculate wastage 
w = LpVariable(name = 'wastage', lowBound = 0, cat = LpInteger)

w = LpVariable(name = 'wastage')
for j in J:
    for i in I:
        firstPart = capacity[i] * x[(i,j)]
        for k in K:
            secondPart = rolls[k] * y[(i,j,k)]
        w += firstPart - secondPart
prob+=w

#each roll is assigned to exactly 1 bin
for k in K:
    prob += lpSum([y[(i,j,k)] for i in I for j in J]) == 1

#bin size is not exceeded
for i in I:
    for j in J:
        prob += lpSum(rolls[k] * y[(i,j,k)] for k in K) - capacity[i] * x[(i,j)] <= 0

# similar number of bins of each type are used 
# for i in range(0,len(capacity)-1):
#         prob+= lpSum(x[(i,j)] for j in J) - lpSum(x[(i + 1,j)] for j in J) <= 2
prob+= x[(i,j)] == x[i+1,j] for i in I for j in J 

status = prob.solve()
print(prob)
for v in prob.variables():
    if v.varValue > 0:
        print(v.name, "=", v.varValue)
print(value(prob.objective))
print(LpStatus[status])

Моя первая проблема в том, что я не знаю, как указать последнее ограничение. Прямо сейчас выдает ошибку. Во-вторых, я попытался снять ограничение и получил объективное значение 0, что определенно неверно. Я думал, что первое ограничение гарантирует, что все рулоны будут назначены машине, но когда я распечатал решение, ни один из рулонов не был назначен, и ни одна из машин (бункеров) не использовалась.

Может ли кто-нибудь помочь мне здесь. Что-то не так с моей формулировкой?

[Обновление]: теперь включен только исходный вопрос.


person Harsh Vardhan Bansal    schedule 15.05.2017    source источник
comment
С ограничением типа x(i,j)=x(i+1,j) вам действительно не нужен x(i,j), а только x(j).   -  person Erwin Kalvelagen    schedule 16.05.2017


Ответы (1)


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

Ограничение в правильном формате:

for i in I[:-1]:
    for j in J:
        prob += x[i,j] == x[i+1,j]

Во-вторых, я попытался снять ограничение и получил объективное значение 0, что определенно неверно. Я думал, что первое ограничение гарантирует, что все рулоны будут назначены машине, но когда я распечатал решение, ни один из рулонов не был назначен, и ни одна из машин (бункеров) не использовалась.

Есть и другие мелкие недочеты.

В этом блоке:

w = LpVariable(name = 'wastage')
for j in J:
    for i in I:
        firstPart = capacity[i] * x[(i,j)]
        for k in K:
            secondPart = rolls[k] * y[(i,j,k)]
        w += firstPart - secondPart
prob+=w

secondPart постоянно обновляется и принимает только значение последнего k. Вы, наверное, этого не хотите. Кроме того, насколько я понимаю, выражение w+= добавляет термины к целевой функции. Однако prob+=w добавляет w поверх других добавленных терминов, и поскольку w является непрерывной неограниченной переменной, проблема не ограничена. Я добавил нижнюю границу нуля на w, и все заработало.

Правильный блок:

w = LpVariable(name = 'wastage', lowBound=0)
for j in J:
    for i in I:
        firstPart = capacity[i] * x[(i,j)]
        secondPart = lpSum(rolls[k] * y[(i,j,k)] for k in K)
        w += firstPart - secondPart
prob+=w

Весь код изменен (я удалил решатель, потому что его у меня нет):

from pulp import *
prob = LpProblem("Production Problem",LpMinimize)
capacity = [1350, 2100]
rolls = [970, 1050, 970, 1100, 1050, 500, 500, 500, 1050, 1350,1200, 370, 370]

I = range(2) # machine film width
J = range(10) # bins for each machine film width 
K = range(len(rolls)) # number of rolls in total 

# variable to determine wether a particular bin is used
x = LpVariable.dicts(name = "Bin", indexs = ((i,j) for i in I for j in J), lowBound = 0, upBound = 1, cat = 'Integer')
# variable to determine if roll is assigned to a particular bin 
y = LpVariable.dicts(name = "RollBin", indexs = ((i,j, k) for i in I for j in J for k in K), lowBound = 0, upBound = 1, cat = 'Integer')
w = LpVariable(name = 'wastage', lowBound=0)
for j in J:
    for i in I:
        firstPart = capacity[i] * x[(i,j)]
        secondPart = lpSum(rolls[k] * y[(i,j,k)] for k in K)
        w += firstPart - secondPart
prob+=w
#prob += lpSum(capacity[i] * x[(i,j)] - lpSum(rolls[k]*y[(i,j,k)] for k in K) for i in I for j in J)

for k in K:
    prob += lpSum([y[(i,j,k)] for i in I for j in J]) == 1

for k in K:
    prob += lpSum([rolls[k] * y[(i,j,k)] for i in I for j in J]) <= lpSum([capacity[i] * x[(i,j)] for i in I for j in J])

for i in I[:-1]:
    for j in J:
        prob += x[i,j] == x[i+1,j]

status = prob.solve()
print(prob)
for v in prob.variables():
    if v.varValue > 0:
        print(v.name, "=", v.varValue)
print(value(prob.objective))
print(LpStatus[status])

Выход решения:

('Bin_(0,_9)', '=', 1.0)
('Bin_(1,_9)', '=', 1.0)
('RollBin_(0,_3,_7)', '=', 1.0)
('RollBin_(0,_4,_12)', '=', 1.0)
('RollBin_(0,_6,_5)', '=', 1.0)
('RollBin_(0,_7,_10)', '=', 1.0)
('RollBin_(1,_0,_2)', '=', 1.0)
('RollBin_(1,_0,_6)', '=', 1.0)
('RollBin_(1,_2,_0)', '=', 1.0)
('RollBin_(1,_3,_11)', '=', 1.0)
('RollBin_(1,_4,_3)', '=', 1.0)
('RollBin_(1,_6,_1)', '=', 1.0)
('RollBin_(1,_8,_4)', '=', 1.0)
('RollBin_(1,_9,_8)', '=', 1.0)
('RollBin_(1,_9,_9)', '=', 1.0)
-7530.0
Optimal

Также обратите внимание, что комментарий Эрвина верен: x_{ij} чрезмерно спроектирован. Я не касался этого, но действительно неплохо дать x единый индекс.

Надеюсь, это поможет!

person Ioannis    schedule 16.05.2017
comment
Большое спасибо за помощь. Я понял, что делаю не так. Я также понял, что мое второе ограничение было неправильным. Это должно было гарантировать, что размер бункера не был превышен всеми назначенными ему рулонами. Однако он суммировал все ширины бункера, а затем выполнял вычитание. - person Harsh Vardhan Bansal; 16.05.2017
comment
Второе ограничение должно быть для i в I: для j в J: prob + = lpSum (rolls [k] * y [(i, j, k)] для k в K) - capacity [i] * x [( i, j)] ‹= 0. Извините за плохое форматирование, не понял, как это сделать - person Harsh Vardhan Bansal; 16.05.2017
comment
Ах да, действительно, я этого не заметил! Форматирование: вы можете перейти в режим редактирования моего ответа, чтобы узнать, как это сделать. - person Ioannis; 16.05.2017
comment
У меня была другая часть вопроса. Пожалуйста, посмотрите, есть ли у вас время - person Harsh Vardhan Bansal; 16.05.2017
comment
Попробуйте распечатать свою модель, как и раньше: это очень помогает при отладке. Теперь у меня все в порядке, но я подозреваю, что добавленные вами новые ограничения (i) уравнивают все переменные y (ii) в какой-то момент они читают (ii) 10 * {двоичная полоса} == 22 * ​​{следующая двоичная машина}, что вместе допускают только y = 0 для всех индексов, что может быть причиной неосуществимости - person Ioannis; 16.05.2017
comment
Пожалуйста, откройте новый вопрос, чтобы решить новую проблему, иначе это может сбить с толку людей, которые приходят сюда за помощью, потому что становится сложно проверить, совпадает ли их проблема с вашим вопросом. Сказав это, обратите внимание, что решатель не возвращает решение, когда сообщает, что проблема недопустима, и то, что вы видите в векторе решения, является одной из попыток решателя найти возможное решение. - person Ioannis; 16.05.2017