Hi all,
I have modeled a vehicle routing problem which seems to be working just fine.
After that I want to add an extra assignment (consisting of a pickup point and a delivery point).
I use an insertion method which inserts the assignment in one of the routes, namely the route where the least amount of extra distance is travelled.
For that I use the variable y[i,j,k], where i is the assignment number (zero in this case, as i only have 1 assignment), k is the route in which the job should be inserted and j is the node in route k after which the assignment is inserted.
I let the model run and it finds that the optimal solution is: zero for all values of y[i,j,k] except for y[0,1,0] which equals 1. This makes sense since there is only 1 job to be assigned and when I plot it, this result seems very plausible.
Now I add a callback function with a lazy constraint. This lazy constraint has the goal to cut off the solutions that exceed the trucks load capacity or do not honor the time windows (each node has a time window in which it should be visited). Now something very strange happens. The first part of my callback function goes like this:
def time_and_capacity_constraint(model,where):
if where == GRB.callback.MIPSOL:
print(model.cbGetSolution(model._vars))
for i in range(A):
for k in range(K):
for j in range(L[k]-1):
sol = model.cbGetSolution(model._vars[i,j,k])
if sol > 0.9:
print('i = ' + str(i))
print('j = ' + str(j))
print('k = ' + str(k))
As you can see I print the solution in the third line. Now in the output console I read that the solution that it checks first only has y[0,1,1] as a value of 1. I already think this is weird, why would the solution not be y[0,1,0] from the start? It then gives the following error:
sol = model.cbGetSolution(model._vars[i,j,k])
KeyError: (1, 2, 1)
This does not make sense to me either since the values of i,j and k are 0,1,1 and not 1,2,1. So of course it can not find the solution of model_vars[1,2,1] because there is only 1 job! It does not exist.
After this is starts over and returns y[0,0,0] as the solution, this also does not make sense to me. This does not give any errors however.
After this it does it again but now returns y[0,1,0] as the solution. Then the output returns:
Exception ignored in: 'gurobipy.callbackstub'
Traceback (most recent call last):
File "callback.pxi", line 183, in gurobipy.CallbackClass.callback
File "C:/Users/alexs/Desktop/Universiteit/MSc/Research Assignment/three_routes_each_one_truck_combined_with_time_windows.py", line 609, in capacity_constraint
sol = model.cbGetSolution(model._vars[i,j,k])
KeyError: ((1, 2, 1),)
And eventually my callback function and lazy constraint dont work. Can anybody explain this to me?
My entire callback function:
def time_and_capacity_constraint(model,where):
if where == GRB.callback.MIPSOL:
print(model.cbGetSolution(model._vars))
for i in range(A):
for k in range(K):
for j in range(L[k]-1):
sol = model.cbGetSolution(model._vars[i,j,k])
if sol > 0.9:
print('i = ' + str(i))
print('j = ' + str(j))
print('k = ' + str(k))
Q=1.5
load_2 = load_solution[j,k]
load_ass = q_ass[i]
Exp = LinExpr([(1,model._vars[i,j,k])])
reference = (truck_size+1.5)-load_2-load_ass
if reference <= 1:
Q -= 1
next_node = arc_order.select(j,'*',k) # here I select the node that would normally follow the node after which the assignment is inserted
if len(next_node)>=2:
next_node = arc_order.select(j,'*',k)[1][1]
else:
next_node = arc_order.select(j,'*',k)[0][1]
new_time= time_solution[next_node,k]+extra_time(routes,i,j,k)
index = 1+sum(L_copy[f] for f in range(k))+j
if new_time > Time_windows[index][1]:
Q -= 1
if k == 0:
dist = math.sqrt((route1[j][0]-assignments[2*i][0])*(route1[j][0]-assignments[2*i][0]) + (route1[j][1]-assignments[2*i][1])*(route1[j][1]-assignments[2*i][1]))
if time_solution[j,k]+(dist/speed)+s1[j] > Time_windows_ass[2*i][1]:
Q -= 1
for i in range(L_copy[k]-3-j): #this determines how many times it must be checked whether the truck arrives before each next time window
new_time = new_time + traveltime(points1,j+1+i,j+2+i)+s1[j+1+i]
if new_time > Time_windows1[j+1+i][1]:
Q -= 1
if k == 1:
dist = math.sqrt((route2[j][0]-assignments[2*i][0])*(route2[j][0]-assignments[2*i][0]) + (route2[j][1]-assignments[2*i][1])*(route2[j][1]-assignments[2*i][1]))
if time_solution[j,k]+(dist/speed)+s2[j] > Time_windows_ass[2*i][1]:
Q -= 1
for i in range(L_copy[k]-3-j): #this determines how many times it must be checked whether the truck arrives before each next time window
new_time = new_time + traveltime(points2,j+1+i,j+2+i)+s2[j+1+i]
if new_time > Time_windows2[j+1+i][1]:
Q -= 1
if k == 2:
dist = math.sqrt((route3[j][0]-assignments[2*i][0])*(route3[j][0]-assignments[2*i][0]) + (route3[j][1]-assignments[2*i][1])*(route3[j][1]-assignments[2*i][1]))
if time_solution[j,k]+(dist/speed)+s3[j] > Time_windows_ass[2*i][1]:
Q -= 1
for i in range(L_copy[k]-3-j): #this determines how many times it must be checked whether the truck arrives before each next time window
new_time = new_time + traveltime(points3,j+1+i,j+2+i)+s3[j+1+i]
if new_time > Time_windows3[j+1+i][1]:
Q -= 1
model.cbLazy(Exp <= Q)