from IPython.display import HTML
HTML('''<script>
code_show=true;
function code_toggle() {
if (code_show){
$('div.input').hide();
} else {
$('div.input').show();
}
code_show = !code_show
}
$( document ).ready(code_toggle);
</script>
<form action="javascript:code_toggle()"><input type="submit" value="Click here to toggle on/off the raw code."></form>''')
Analyst:Luoben Zhang
Date: 2019/11/10
The Westvaco Company is facing distribution problem. They want to minimize their cost for truckloads to carriers that meet the necessary requirements. There are 6 carriers who are willing to provide their services: ABCT, IRST, LAST, MRST, NEST, PSST. Each of them have a different cost per mile, the stops to the same destination are the same, but the Stop-off charge is also part of the company cost. For each destination, the company should choose number carriers that equal to the total trips required (same carrier can be chosen several times). On the other hand, each carrier also has a minimum charge per truckload. If the total cost for one trip belows this minimum charge amount, the carrier would still charge the company the minimum charge they asked. This case is to help Westvoca Company to find a most optimize way to lower their transportation cost.
from gurobipy import*
m = Model("Minimum Cost")
Destination = ['Atlanta','Everett','Ephrata','Riverview','Carson','Chamblee','Roseville','Hanover','Sparks','Parsippany','Effingham','Kearny','MinCharge','StopOffCharge']
State = ['GA','MA','PA','MI','CA','GA','MN','PA','NV','NJ','IL','NJ','','']
trips = [4,1,3,5,1,1,1,1,2,1,5,7,'','']
stops = [0,3,0,0,2,0,3,0,0,1,0,0,'','']
miles = [612, 612, 190, 383, 3063, 429, 600, 136, 2439, 355, 570, 324,'','']
minCharge = [350,400,350,300,350,300]
stopoffCharge = [50,75,50,35,50,50]
ABCT = ['*','*','*',0.79,'*','*',1.24,'*','*','*',0.87,'*',350,50]
IRST = [0.88,1.18,3.42,1.01,0.8,1.23,1.13,4.78,1.45,1.62,0.87,2.01,400,75]
LAST = [1.15,1.27,1.73,1.25,0.87,1.61,1.89,2.23,'*',1.36,1.25,1.54,350,50]
MRST = [0.87,1.39,1.71,0.96,'*',1.22,1.32,2.39,1.2,1.39,0.87,1.53,300,35]
NEST = [0.95,1.35,1.82,0.95,1.00,1.33,1.41,2.26,'*',1.03,0.9,1.28,350,50]
PSST = [1.05,1.28,2,1.11,'*',1.47,1.41,2.57,'*',1.76,1.31,1.95,300,50]
import pandas as pd
ak = pd.DataFrame.from_dict({
'Destination': Destination,
'State': State,
'Trips': trips,
'Stops': stops,
'Miles': miles,
'ABCT': ABCT,
'IRST': IRST,
'LAST': LAST,
'MRST': MRST,
'NEST': NEST,
'PSST': PSST
})
ak
zlb = [ABCT[0:12],IRST[0:12],LAST[0:12],MRST[0:12],NEST[0:12],PSST[0:12]]
ub = 9999999
cost1 = []
for i in range(len(zlb)):
cost=[]
for j in range(len(zlb[i])):
if zlb[i][j] == "*":
cost.append(ub)
elif zlb[i][j]*miles[j]+stops[j]*stopoffCharge[i] > minCharge[i]:
cost.append(zlb[i][j]*miles[j]+stops[j]*stopoffCharge[i])
else:
cost.append(minCharge[i])
cost1.append(cost)
ap = pd.DataFrame.from_dict({
'Destination': Destination[0:12],
'ABCT': cost1[0],
'IRST': cost1[1],
'LAST': cost1[2],
'MRST': cost1[3],
'NEST': cost1[4],
'PSST': cost1[5]
})
ap
m.remove(m.getVars())
m.remove(m.getConstrs())
There are 72 decision variables in total: 12 cities and 6 carriers.
#Decision Variables
var = [[m.addVar(vtype=GRB.INTEGER, name="Carrier"+str(i+1)+"_"+"Dest"+str(j+1)) for j in range(len(zlb[i]))] for i in range(len(zlb))]
m.update()
The sum of truckloads for each carrier should less than the available pulls for each carrier, but greater than the commitment. The total truckloads for each destination should equal to the total trips needed for each destination.
#Constraints
Available_Pulls = [4,8,7,7,3,4]
Commitment = [1,7,6,0,0,4]
for i in range(len(var)):
m.addConstr(sum(var[i]),GRB.LESS_EQUAL,Available_Pulls[i])
m.addConstr(sum(var[i]),GRB.GREATER_EQUAL,Commitment[i])
trips1 = [4,1,3,5,1,1,1,1,2,1,5,7]
for j in range(12):
m.addConstr(var[0][j]+var[1][j]+var[2][j]+var[3][j]+var[4][j]+var[5][j],GRB.EQUAL,trips1[j])
m.update()
The objective function is minimize of the total cost. Total cost is the sumproduct of decision variables and Cost for each Carrier to different destinationstable for each carrier.
#Objective
k = []
for i in range(len(var)):
for j in range(len(var[i])):
k.append(cost1[i][j]*var[i][j])
m.setObjective(sum(k),GRB.MINIMIZE)
m.update()
# Optimization
m.optimize()
a = []
for v in m.getVars():
if '%g' % (v.x) == -0:
a.append(0)
else:
a.append(int('%g' % (v.x)))
b = [('$%g' % m.objVal),'','','','','','','','','','','']
ad = pd.DataFrame.from_dict({
'Destination': Destination[0:12],
'ABCT': a[0:12],
'IRST': a[12:24],
'LAST': a[24:36],
'MRST': a[36:48],
'NEST': a[48:60],
'PSST': a[60:72],
'MinCost': b
})
ad
print('The optimal result in this case will be:','$%g' % m.objVal)
In order to get my objective, I used the cost for each carrier to different destinations multiply by the number of times we choose each carrier for a certain destination (my decision variables). Add these costs together, we could get a total cost for the whole transportation progress. I used both Gurobi and Excel to get an optimized solution for this case, and the results are the same: The least-cost of truckloads to carriers that meets the necessary requirements will be $22394.4. I will describe the plan for each carrier in details:
For ABCT, the company should assign 4 truckloads and all towards Riverview.
For IRST, the company should assign 1 truckload towards Carson, 1 truckload towards Chamblee, 1 truckload towards Roseville, and 5 truckloads towards Effingham.
For LAST, the company should assign 1 truckload to Ephrata, and 5 truckloads towards Kearny.
For MRST, the company should assign 4 truckloads towards Atlanta, 1 truckload towards Riverview, and 2 truckloads towards Sparks.
For NEST, the company should assign 1 truckloads towards Parsippany, and 2 truckloads towards Kearny.
For PSST, the company should assign 1 truckload towards Everett, 2 truckloads towards Ephrata, and 1 truckload towards Hanover.
There are a lot of challenges while doing this assignment. The first challenge is tranfer my mind from r to python. I watch the videos the professor posted online, and they are really helpful. They remind me how to use Gurobi for our last assignments. The most difficult part to build the model for this Westvaco case is to determine the cost for each carrier towards certain destination. In excel, I don't know how to deal with the cost per mile at the beginning. However, after reading the book, I learned we can assign a big value to it so they will never be chosen. Thus, I write an if statement in excel, if the cost per mile = , then I assign 999999 to that cell. If not, we choose the maximum value between the actual cost and the minimum charge for that carrier. Opensolver is another challenge since I'm more familiar with using solver, but after watching the videos, I can finally use it to solve this case.
The gurobi the hardest part for this assignment. But since I build an Excel Model first, I got a clear logic towards solving this problem. I have concerns about how to use for loops to set up constraints and decision variables instead of hardcoding. After carefully understanding the logic relationships between those variables, I successfully simplify my codes to fewer lines. I learned how to build a dataframe using panda through videos, and I think it is really helpful. For the output part, I don't know how to just print out the decision variables result, so I googled and change the code to a for loop in order to get the result I want.
Overall, this assignment makes me get more familiar with Gurobi and the logic behind it. I enjoy doing this assignment.