Equipment assigned twice despite constraint
AnsweredHello everyone,
I am writing to you because I have an issue with my optimization model and I don't know what to do anymore. I have a milp model that should assign loading and unloading equipment to some trains, with one of the constraint being that each equipment can only be assigned to one carriage at a time (called Not_two_trains_at_the_same_time). However, it seems that this particular constraint is not respected, as you can see in the Excel created at the end intitled "Optimized_equipment.xlsx" or the Gantt chart below, where the equipment 4 is used for two trains at the same time.
The input dataframe is available at the following link: https://docs.google.com/spreadsheets/d/1oVcufltdOHRXtk144ADEzN1UAWqidn3W/edit?usp=sharing&ouid=114195968585792324243&rtpof=true&sd=true
This is a simplified version of what I would want to do (less trains, very little carriages), but it still doesn't work so I hope you could help me to find what is wrong. Also I am trying to consider things such as an equipment of a certain type can only go to the trains of a certain type, etc... Also, a train should finish to be loaded or unloaded before the equipment can be transfered to another train, and there could be more than one equipment per train at the same time but on the same carriage, but I am not really sure how to ensure that...
I also try to use another variable "x = {(i, j, e): m.addVar(vtype=gp.GRB.BINARY, name=f'x_{i}_{j}_{e}') for i in I for j in J[i] for e in E}" and modify the constraints Not_two_trains_at_the_same_time and Equipment_to_train_with_goods accordingly but with no success.
Thank you a lot in advance.
The code is as follow:
import gurobipy as gp
import pandas as pd
file_path = r"C:\...\Optimized_trains.xlsm"
sheet_name = "Optimized trains scheduling"
excel = pd.ExcelFile(file_path)
df = pd.read_excel(excel, sheet_name=sheet_name)
df = df.dropna()
excel.close()I = df.index.tolist()
Train,Train_nb,Line,A,A0,D,J_number,G = [df.iloc[:,i].tolist() for i in range(8)]
M = 15000
Pta = 45
Ptd = 45
w_ij = []
J = []
E= [1,2,3,4,5,6,7]
Goods = [0,1]
Ig=[[],[]]
Cg = [3,4] # Cg corresponds to the total number of equipment available for each type of goods g
Eg = [[1,2,3],[4,5,6,7]]for n in J_number:
J.append([i for i in range(n)])for i in I:
if G[i] == 'Steel coils & equivalent':
w_ij.append([15 for j in range(J_number[i])])
Ig[0].append(I[i])
elif G[i] == 'Containers':
w_ij.append([3 for j in range(J_number[i])])
Ig[1].append(I[i])T = [i for i in range(0,1441)] # 24h or 1440 min
# Model
m = gp.Model("Stage_2")
# Decision variables
y = {(i, j, t): m.addVar(vtype=gp.GRB.BINARY, name=f'y_{i}_{j}_{t}') for i in I for j in J[i] for t in T}
ST = {(i, j): m.addVar(vtype=gp.GRB.CONTINUOUS, name=f'ST_{i}_{j}') for i in I for j in J[i]}
ET = {(i, j): m.addVar(vtype=gp.GRB.CONTINUOUS, name=f'ET_{i}_{j}') for i in I for j in J[i]}
t = m.addVars(T,vtype=gp.GRB.INTEGER,name='t')
x_simple = {(i, e): m.addVar(vtype=gp.GRB.BINARY, name=f'x_{i}_{e}') for i in I for e in E}# Subject to constraints
# Time constraints
Min_start = m.addConstrs((ST[i, j] >= A[i] + Pta for i in I for j in J[i]), name="Min_start")
Max_end = m.addConstrs((ET[i, j] <= D[i]  Ptd for i in I for j in J[i]), name='Max_end')
Time_carriage = m.addConstrs((ET[i, j]  ST[i,j] >= w_ij[i][j] for i in I for j in J[i]), name='Time_carriage')
Two_consecutive_carriages = m.addConstrs((ST[i, p] >= ET[i, j] for i in I for j in J[i] for p in J[i] if j < p), name='Two_consecutive_carriages')t_ub = m.addConstrs((t  ET[i,j] + 1 <= M*(1  y[i,j,t]) for i in I for j in J[i] for t in T), name='t_ub')
t_lb = m.addConstrs((ST[i,j]  t <= M*(1  y[i,j,t]) for i in I for j in J[i] for t in T), name='t_lb')# Resource constraints
Nb_carriage_under_work_at_a_time = m.addConstrs((gp.quicksum(y[i,j,t] for i in Ig[g] for j in J[i]) <= Cg[g] for g in Goods for t in T), name='Nb_carriage_under_work_at_a_time')
Equipment_to_train_with_goods = m.addConstrs((gp.quicksum(x_simple[i, e] for e in Eg[g]) == 1 for g in Goods for i in Ig[g]), name='Eq_to_train_with_goods')Not_two_trains_at_the_same_time = m.addConstrs((x_simple[i, e] + x_simple[ii, e] <= 1 + M*(2y[i, j, t]y[ii, jj, t]) for g in Goods for i in Ig[g] for ii in Ig[g] if i < ii for j in J[i] for jj in J[ii] for e in Eg[g] for t in T), name='Not_two_trains_at_the_same_time')
# Objective function
m.setObjective(gp.quicksum(ET[i,J[i][1]]  ST[i,0] for i in I), gp.GRB.MINIMIZE)# Update the model with the variables & constraints
m.update()# Solve the model
m.optimize()
# Write the model
m.write('Stage 2.lp')data = []
for i in I:
for j in J[i]:
for e in E:
if x_simple[i,e].X == 1: #Check the value of the variable x
data.append({
'Equipment': f'Equipment n°{e}',
'To train': Train_nb[i],
'Carriage': J[i][j],
'Start Time': ST[i,j].X,
'End Time': ET[i,j].X,
})new_df = pd.DataFrame(data)
# Save the new dataframe
new_excel_path = 'C:\...\Optimized_equipment.xlsx'
new_df.to_excel(new_excel_path,sheet_name='Optimized equipment scheduling',index=False)

Hello, if my post isn't in the proper section please tell me, or transfer it if possible...
I really don't know what is wrong with my code as one piece of equipment shouldn't be able two times at the same time right?
Please I really need someone's help, I am fairly new to optimization and gurobi
0 
Hi Alexandre,
It is quite some effort to debug such a code. We usually recommend to do the following:
 Create a tiny artificial instance of your problem where you can already observe that the obtained solution violates some constraints.
 Write out the model in readable form as LP file (which you are already doing).
 If the solver terminates with status OPTIMAL, all included constraints should be respected (subject to some very small violations  by default around 1e6  resulting from limited precision computation).
 In nearly all cases, some constraints are missing in the model, they have been wrongly implemented, or they are mathematically wrong.
 These cases can usually be found by analyzing the LP model file together with the found solution values.
Best regards,
Mario0
Please sign in to leave a comment.
Comments
2 comments