forked from gabriel301/DiscreteOptimizationCoursera
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMIP.py
154 lines (119 loc) · 7.19 KB
/
MIP.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
from pyscipopt import Model, quicksum
import math
from Preprocessing import Preprocessing
from EnumSettings import MipSolver
import docplex.mp.model as cpx
from docplex.util.status import JobSolveStatus
class MIP:
DEBUG_MESSAGES = False
def __init__(self, f, c, instanceName,mipSolver):
self.initialize(f,c,instanceName,mipSolver)
def clear(self):
self.facilities = []
self.customers = []
self.instanceName = None
self.varFacilityAssignment = {}
self.varCustomerAssignment = {}
def initialize(self, f, c, instanceName,mipSolver):
self.clear()
self.facilities = f
self.customers = c
self.instanceName = instanceName
self.varFacilityAssignment = {}
self.varCustomerAssignment = {}
self.solver = mipSolver
def optimize(self,timeLimit):
if(self.solver == MipSolver.SCIP):
self.__createModelSCIP()
return self.__optimizeSCIP(timeLimit)
elif (self.solver == MipSolver.CPLEX):
self.__createModelCPLEX()
return self.__optimizeCPLEX(timeLimit)
def __createModelSCIP(self):
self.model = Model(self.instanceName)
print("SCIP - Creating Variables...")
#Variables
for f in self.facilities:
self.varFacilityAssignment[f.index] = self.model.addVar(vtype="B",name="facility-%s" % f.index)
for c in self.customers:
#Demand is binary because each customer must be served by exaclty one facility
self.varCustomerAssignment[f.index,c.index] = self.model.addVar(vtype="B",name="demand-(%s,%s)" % (f.index,c.index))
print("SCIP - Creating Constraints...")
#Constraints
#Ensure all customers are assigned to one facility
for customer in self.customers:
self.model.addCons(quicksum(self.varCustomerAssignment[facility.index,customer.index] for facility in self.facilities) == 1,"Demand(%s)"% customer.index)
#Ensure the demand carried by the facility is at most its capacity
for facility in self.facilities:
self.model.addCons(quicksum(self.varCustomerAssignment[facility.index,customer.index]*customer.demand for customer in self.customers) <= facility.capacity*self.varFacilityAssignment[facility.index],"Capacity(%s)" % facility.index)
#Strong Formulation
for facility in self.facilities:
for customer in self.customers:
self.model.addCons(self.varCustomerAssignment[facility.index,customer.index] <= facility.capacity*self.varFacilityAssignment[facility.index],"Strong(%s,%s)"%(facility.index,customer.index))
self.model.addCons(self.varCustomerAssignment[facility.index,customer.index] >= 0 )
print("SCIP - Creating Objective Function...")
#Objective Function
self.model.setObjective(quicksum(self.varFacilityAssignment[facility.index]*facility.setup_cost for facility in self.facilities) + quicksum(Preprocessing.getEuclideanDistance(facility.location,customer.location)*self.varCustomerAssignment[facility.index,customer.index] for facility in self.facilities for customer in self.customers),"minimize")
self.model.data = self.varFacilityAssignment, self.varCustomerAssignment
def __createModelCPLEX(self):
self.model = cpx.Model(self.instanceName)
print("CPLEX - Creating Variables...")
#Variables
for f in self.facilities:
self.varFacilityAssignment[f.index] = self.model.binary_var(name="facility-%s" % f.index)
for c in self.customers:
#Demand is binary because each customer must be served by exaclty one facility
self.varCustomerAssignment[f.index,c.index] = self.model.binary_var(name="demand-(%s,%s)" % (f.index,c.index))
print("CPLEX - Creating Constraints...")
#Constraints
#Ensure all customers are assigned to one facility
for customer in self.customers:
self.model.add_constraint(ct=self.model.sum(self.varCustomerAssignment[facility.index,customer.index] for facility in self.facilities) == 1,ctname="Demand(%s)"% customer.index)
#Ensure the demand carried by the facility is at most its capacity
for facility in self.facilities:
self.model.add_constraint(ct=self.model.sum(self.varCustomerAssignment[facility.index,customer.index]*customer.demand for customer in self.customers) <= facility.capacity*self.varFacilityAssignment[facility.index],ctname="Capacity(%s)" % facility.index)
#Strong Formulation
for facility in self.facilities:
for customer in self.customers:
self.model.add_constraint(ct=self.varCustomerAssignment[facility.index,customer.index] <= facility.capacity*self.varFacilityAssignment[facility.index],ctname="Strong(%s,%s)"%(facility.index,customer.index))
self.model.add_constraint(self.varCustomerAssignment[facility.index,customer.index] >= 0,ctname="Strong2(%s,%s)"%(facility.index,customer.index))
print("CLPEX - Creating Objective Function...")
#Objective Function
objective = self.model.sum(self.varFacilityAssignment[facility.index]*facility.setup_cost for facility in self.facilities) + self.model.sum(Preprocessing.getEuclideanDistance(facility.location,customer.location)*self.varCustomerAssignment[facility.index,customer.index] for facility in self.facilities for customer in self.customers)
self.model.minimize(objective)
def __optimizeCPLEX(self,timeLimit):
print("Instace: %s" % self.instanceName)
if self.DEBUG_MESSAGES:
self.model.print_information()
self.model.parameters.timelimit = timeLimit
self.model.parameters.threads = 8
print("CPLEX - Optimizing...")
solution = self.model.solve(log_output=self.DEBUG_MESSAGES)
if solution is not None:
print("Instace: %s solved." % self.instanceName)
else:
print("Instace: %s is infeasible" % self.instanceName)
return None
assignments = []
for f in self.facilities:
for c in self.customers:
if(self.varCustomerAssignment[f.index,c.index].solution_value == 1):
assignments.append((f.index,c.index))
obj = self.model.objective_value
status = "No optimal"
if self.model.get_solve_status() == JobSolveStatus.OPTIMAL_SOLUTION:
status = "optimal"
return obj,assignments,status
def __optimizeSCIP(self,timeLimit):
print("Instace: %s" % self.instanceName)
if not self.DEBUG_MESSAGES:
self.model.hideOutput()
self.model.setRealParam('limits/time', timeLimit)
print("SCIP - Optimizing...")
self.model.optimize()
print("Instace: %s solved." % self.instanceName)
EPS = 1.e-6
_,cAssigned = self.model.data
assignments = [(facility,customer) for (facility,customer) in cAssigned if self.model.getVal(cAssigned[facility,customer]) > EPS]
obj = self.model.getObjVal()
return obj,assignments,self.model.getStatus()