Я сформулировал MILP для моделирования многопериодной задачи планирования для нескольких клиентов в PuLP. Цель состоит в том, чтобы запланировать несколько партий продукции, которые будут производиться в неделю, так, чтобы все партии продукции производились путем минимизации общих затрат труда. Каждый день имеет регулярную смену и сверхурочную смену (которая обходится дороже из-за переменных затрат на рабочую силу).
Я использовал две переменные, которые созданы как переменные типа Integer. Тем не менее, я все еще получаю десятичные и отрицательные значения в моем решении проблемы. Как это возможно? Пожалуйста, смотрите мой код ниже.
'''
Multi-Period Scheduling Problem
'''
from pulp import *
import itertools
Создание параметров и данных:
'''SETS'''
#list of batch_id's waiting for production
batch_ids = ['b1', 'b2', 'b3', 'b4', 'b5', 'b6']
#list of the days available in a week
days = ['mon', 'tue', 'wed', 'thu', 'fri']
#list of shifts in a day
shifts= ['rt', 'ot']
'''PARAMETERS'''
#batch quantity needed
batch_size= {
'b1': 45,
'b2': 60,
'b3': 120,
'b4': 80,
'b5': 230,
'b6': 40
}
#regular time and over time values
time_dict= {'rt': 450, 'ot': 300}
#dict to store minutes available per day per shift
mins_per_day= {d: {s: time_dict[s] for s in shifts} for d in days}
#cycle time in minutes per unit per batch
cycle_time = {
'b1': 45,
'b2': 30,
'b3': 10,
'b4': 80,
'b5': 13,
'b6': 35
}
'''minimum needed units per batch per day; as of now this is a fixed qty= 10, but we can create a separate
dict to store different qty per batch if needed and then use it in the dict comprehension here'''
min_qty= {d:{b: 5 for b in batch_ids} for d in days}
pay_by_shift= {'ot': 0.8625, 'rt': 0.575}
#cost per minute per shift per day:
pay_dict= {d: {s: pay_by_shift[s] for s in shifts} for d in days}
#indexes for batch and day combinations
shifts_ind = [(d,s) for d in days for s in shifts]
#indexes for the make variable:
make_ind= [(d,b) for d in days for b in batch_ids]
Определение переменных:
'''VARIABLES'''
#number of units of a batch scheduled for production per day per shift
make= LpVariable.dicts("Make Per Day",(days, batch_ids, shifts),0, None, cat= 'Integer')
#binary variable to decide wether OT is scheduled on a given day or not
y= LpVariable.dicts("Use Shift",(days, shifts), 0, 1, cat= 'Integer')
'''model formulation'''
#create model object with a minimize objective
prob= LpProblem("FlexLine Problem",LpMinimize)
Определение целевой функции
#objective function
prob += lpSum([y[d][s] for d in days for s in shifts]) + \
lpSum([make[d][b][s]* cycle_time[b]* pay_dict[d][s] for d in days for b in batch_ids for s in shifts]), "Total labor cost per week"
Определение ограничений:
'''CONSTRAINTS'''
#demand constraint
for b in batch_ids:
prob += lpSum([make[d][b][s] for d in days for s in shifts]) == batch_size[b]
#time constraint
for (d,s) in shifts_ind:
prob += lpSum([make[d][b][s] * cycle_time[b] for b in batch_ids]) <= mins_per_day[d][s] * y[d][s]
#minimum per day constraint
for (d,b) in make_ind:
prob += lpSum([make[d][b][s] for s in shifts]) >= min_qty[d][b]
#linking constraint
for (d,s) in shifts_ind:
prob += lpSum([make[d][b][s] for b in batch_ids]) <= 100000 * y[d][s]
Решение модели:
prob.solve()
Out: -1
print ("Status:", LpStatus[prob.status])
Out: Status: Infeasible
Печать значений переменных:
for v in prob.variables():
print (v.name, "=", v.varValue)
Out:Make_Per_Day_fri_b1_ot = 0.0
Make_Per_Day_fri_b1_rt = 5.0
Make_Per_Day_fri_b2_ot = 0.0
Make_Per_Day_fri_b2_rt = -5.5
Make_Per_Day_fri_b3_ot = 0.0
Make_Per_Day_fri_b3_rt = 5.0
Make_Per_Day_fri_b4_ot = 1.5625
Make_Per_Day_fri_b4_rt = 3.4375
Make_Per_Day_fri_b5_ot = 0.0
Make_Per_Day_fri_b5_rt = 5.0
Make_Per_Day_fri_b6_ot = 5.0
Make_Per_Day_fri_b6_rt = 0.0
Make_Per_Day_mon_b1_ot = 0.0
Make_Per_Day_mon_b1_rt = 5.0
Make_Per_Day_mon_b2_ot = 0.0
Make_Per_Day_mon_b2_rt = -5.5
Make_Per_Day_mon_b3_ot = 0.0
Make_Per_Day_mon_b3_rt = 5.0
Make_Per_Day_mon_b4_ot = 2.9375
Make_Per_Day_mon_b4_rt = 2.0625
Make_Per_Day_mon_b5_ot = 5.0
Make_Per_Day_mon_b5_rt = 0.0
Make_Per_Day_mon_b6_ot = 0.0
Make_Per_Day_mon_b6_rt = 5.0
Make_Per_Day_thu_b1_ot = 25.0
Make_Per_Day_thu_b1_rt = 0.0
Make_Per_Day_thu_b2_ot = 61.0
Make_Per_Day_thu_b2_rt = 0.0
Make_Per_Day_thu_b3_ot = 131.5
Make_Per_Day_thu_b3_rt = 0.0
Make_Per_Day_thu_b4_ot = 60.0
Make_Per_Day_thu_b4_rt = 0.0
Make_Per_Day_thu_b5_ot = 210.0
Make_Per_Day_thu_b5_rt = 0.0
Make_Per_Day_thu_b6_ot = 16.142857
Make_Per_Day_thu_b6_rt = 12.857143
Make_Per_Day_tue_b1_ot = 5.0
Make_Per_Day_tue_b1_rt = 0.0
Make_Per_Day_tue_b2_ot = 0.83333333
Make_Per_Day_tue_b2_rt = 4.1666667
Make_Per_Day_tue_b3_ot = 5.0
Make_Per_Day_tue_b3_rt = 0.0
Make_Per_Day_tue_b4_ot = 0.0
Make_Per_Day_tue_b4_rt = 5.0
Make_Per_Day_tue_b5_ot = 0.0
Make_Per_Day_tue_b5_rt = 5.0
Make_Per_Day_tue_b6_ot = 0.0
Make_Per_Day_tue_b6_rt = -4.0
Make_Per_Day_wed_b1_ot = 5.0
Make_Per_Day_wed_b1_rt = 0.0
Make_Per_Day_wed_b2_ot = 5.0
Make_Per_Day_wed_b2_rt = 0.0
Make_Per_Day_wed_b3_ot = -26.5
Make_Per_Day_wed_b3_rt = 0.0
Make_Per_Day_wed_b4_ot = 1.5625
Make_Per_Day_wed_b4_rt = 3.4375
Make_Per_Day_wed_b5_ot = 5.0
Make_Per_Day_wed_b5_rt = 0.0
Make_Per_Day_wed_b6_ot = 0.0
Make_Per_Day_wed_b6_rt = 5.0
Use_Shift_fri_ot = 1.0
Use_Shift_fri_rt = 1.0
Use_Shift_mon_ot = 1.0
Use_Shift_mon_rt = 1.0
Use_Shift_thu_ot = 41.216667
Use_Shift_thu_rt = 1.0
Use_Shift_tue_ot = 1.0
Use_Shift_tue_rt = 1.0
Use_Shift_wed_ot = 1.0
Use_Shift_wed_rt = 1.0
Повторюсь, я вижу отрицательные значения, десятичные числа, а также двоичные переменные, отображающие больше 1. Как это происходит?