Advertisement
dsfdfw

Untitled

Feb 9th, 2024 (edited)
32
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.18 KB | None | 0 0
  1. from gurobipy import *
  2. import gurobipy as gu
  3. import pandas as pd
  4. import itertools
  5. import time
  6. import matplotlib.pyplot as plt
  7.  
  8. # Create DF out of Sets
  9. I_list = [1,2,3]
  10. T_list = [1,2,3,4,5,6,7]
  11. K_list = [1,2,3]
  12. I_list1 = pd.DataFrame(I_list, columns=['I'])
  13. T_list1 = pd.DataFrame(T_list, columns=['T'])
  14. K_list1 = pd.DataFrame(K_list, columns=['K'])
  15. DataDF = pd.concat([I_list1, T_list1, K_list1], axis=1)
  16. Demand_Dict = {(1, 1): 2, (1, 2): 1, (1, 3): 0, (2, 1): 1, (2, 2): 2, (2, 3): 0, (3, 1): 1, (3, 2): 1, (3, 3): 1,
  17.           (4, 1): 1, (4, 2): 2, (4, 3): 0, (5, 1): 2, (5, 2): 0, (5, 3): 1, (6, 1): 1, (6, 2): 1, (6, 3): 1,
  18.           (7, 1): 0, (7, 2): 3, (7, 3): 0}
  19.  
  20. class MasterProblem:
  21.     def __init__(self, dfData, DemandDF, iteration):
  22.         self.iteration = iteration
  23.         self.physicians = dfData['I'].dropna().astype(int).unique().tolist()
  24.         self.days = dfData['T'].dropna().astype(int).unique().tolist()
  25.         self.shifts = dfData['K'].dropna().astype(int).unique().tolist()
  26.         self.roster = list(range(1,self.iteration+2))
  27.         self.demand = DemandDF
  28.         self.model = gu.Model("MasterProblem")
  29.         self.cons_demand = {}
  30.         self.cons_lmbda = {}
  31.  
  32.     def buildModel(self):
  33.         self.generateVariables()
  34.         self.generateConstraints()
  35.         self.generateObjective()
  36.         self.setStartSolution()
  37.         self.modelFlags()
  38.         self.model.update()
  39.  
  40.     def generateVariables(self):
  41.         self.slack = self.model.addVars(self.days, self.shifts, vtype=gu.GRB.CONTINUOUS, lb=0, name='slack')
  42.         self.motivation_i = self.model.addVars(self.physicians, self.days, self.shifts, self.roster, vtype=gu.GRB.CONTINUOUS, lb= 0, ub= 1, name = 'motivation_i')
  43.         self.lmbda = self.model.addVars(self.physicians, self.roster, vtype=gu.GRB.INTEGER, lb = 0, name = 'lmbda')
  44.     def generateConstraints(self):
  45.         for i in self.physicians:
  46.             self.cons_lmbda[i] = self.model.addLConstr(gu.quicksum(self.lmbda[i, r] for r in self.roster) == 1)
  47.         for t in self.days:
  48.             for s in self.shifts:
  49.                 self.cons_demand[t,s] = self.model.addConstr(gu.quicksum(self.motivation_i[i, t, s, r] for i in self.physicians for r in self.roster) + self.slack[t, s] >= self.demand[t, s])
  50.         return self.cons_lmbda, self.cons_demand
  51.  
  52.     def generateObjective(self):
  53.         self.model.setObjective(gu.quicksum(self.slack[t, s] for t in self.days for s in self.shifts), sense = gu.GRB.MINIMIZE)
  54.  
  55.     def solveRelaxModel(self):
  56.         for v in self.model.getVars():
  57.             v.setAttr('vtype', 'C')
  58.         self.model.optimize()
  59.  
  60.     def getDuals_i(self):
  61.         Pi_cons_lmbda = self.model.getAttr("Pi", self.cons_lmbda)
  62.         return Pi_cons_lmbda
  63.  
  64.     def getDuals_ts(self):
  65.         Pi_cons_demand = self.model.getAttr("Pi", self.cons_demand)
  66.         return Pi_cons_demand
  67.  
  68.     def getObjValues(self):
  69.         obj = self.model.objVal
  70.         return obj
  71.  
  72.     def updateModel(self):
  73.         self.model.update()
  74.  
  75.     def addColumn(self, newSchedule, iter, i):
  76.         colName = f"ScheduleUsed[{i},{iter}]"
  77.         Column = gu.Column(newSchedule, self.model.getConstrs())
  78.         self.model.addVar(vtype=gu.GBR.CONTINOUS, lb=0, obj=1.0, column=Column, name=colName)
  79.         self.model.update()
  80.  
  81.     def setStartSolution(self):
  82.         startValues = {}
  83.         for i, t, s, r in itertools.product(self.physicians, self.days, self.shifts, self.roster):
  84.             startValues[(i, t, s, r)] = 0
  85.         for i, t, s, r in startValues:
  86.             self.motivation_i[i, t, s, r].Start = startValues[i, t, s, r]
  87.  
  88.     def modelFlags(self):
  89.         self.model.Params.OutputFlag = 0
  90.  
  91.     def solveModel(self, timeLimit, EPS):
  92.         self.model.setParam('TimeLimit', timeLimit)
  93.         self.model.setParam('MIPGap', EPS)
  94.         self.model.optimize()
  95.  
  96.     def writeModel(self):
  97.         self.model.write("master.lp")
  98.  
  99. class Subproblem:
  100.     def __init__(self, duals_i, duals_ts, dfData, i):
  101.         self.days = dfData['T'].dropna().astype(int).unique().tolist()
  102.         self.shifts = dfData['K'].dropna().astype(int).unique().tolist()
  103.         self.duals_i = duals_i
  104.         self.duals_ts = duals_ts
  105.         self.Max = 5
  106.         self.M = 100
  107.         self.alpha = 0.5
  108.         self.model = gu.Model("Subproblem")
  109.         self.i = i
  110.  
  111.     def buildModel(self):
  112.         self.generateVariables()
  113.         self.generateConstraints()
  114.         self.generateObjective()
  115.         self.modelFlags()
  116.         self.model.update()
  117.  
  118.     def generateVariables(self):
  119.         self.x = self.model.addVars(self.days, self.shifts, vtype=GRB.BINARY, name='x')
  120.         self.mood = self.model.addVars(self.days, vtype=GRB.CONTINUOUS, lb = 0, ub = 1, name='mood')
  121.         self.motivation = self.model.addVars(self.days, self.shifts, vtype=GRB.CONTINUOUS, lb = 0, ub = 1, name='motivation')
  122.  
  123.     def generateConstraints(self):
  124.         for t in self.days:
  125.             self.model.addConstr(self.mood[t] == 1 - self.alpha * quicksum(self.x[t, s] for s in self.shifts))
  126.         for t in self.days:
  127.             self.model.addConstr(gu.quicksum(self.x[t, s] for s in self.shifts) <= 1)
  128.         for t in range(1, len(self.days) - self.Max + 1):
  129.             self.model.addConstr(gu.quicksum(self.x[u, s] for s in self.shifts for u in range(t, t + 1 + self.Max)) <= self.Max)
  130.         for t in self.days:
  131.             for s in self.shifts:
  132.                 self.model.addConstr(self.mood[t] + self.M*(1-self.x[t, s]) >= self.motivation[t, s])
  133.                 self.model.addConstr(self.motivation[t, s] >= self.mood[t] - self.M * (1 - self.x[t, s]))
  134.                 self.model.addConstr(self.motivation[t, s] <= self.x[t, s])
  135.  
  136.     def generateObjective(self):
  137.         self.model.setObjective(0-gu.quicksum(self.motivation[t,s]*self.duals_ts[t,s] for t in self.days for s in self.shifts)-self.duals_i[self.i], sense = gu.GRB.MINIMIZE)
  138.  
  139.     def getNewSchedule(self):
  140.         return self.model.getAttr("X", self.motivation)
  141.  
  142.     def getObjVal(self):
  143.         obj = self.model.getObjective()
  144.         value = obj.getValue()
  145.         return value
  146.  
  147.     def getStatus(self):
  148.         return self.model.status
  149.  
  150.     def solveModel(self, timeLimit, EPS):
  151.         self.model.setParam('TimeLimit', timeLimit)
  152.         self.model.setParam('MIPGap', EPS)
  153.         self.model.optimize()
  154.  
  155.     def modelFlags(self):
  156.         self.model.Params.OutputFlag = 0
  157.  
  158. #### Column Generation
  159. # Prerequisites
  160. modelImprovable = True
  161. objValHist = []
  162. t0 = time.time()
  163. max_itr = 3000
  164. itr = 0
  165.  
  166. # Build MP
  167. master = MasterProblem(DataDF, Demand_Dict, itr)
  168. master.buildModel()
  169.  
  170. master.updateModel()
  171. master.solveRelaxModel()
  172.  
  173. # Get Duals
  174. duals_i = master.getDuals_i()
  175. duals_ts = master.getDuals_ts()
  176.  
  177. ## Start
  178. print('         *****Column Generation Iteration*****          \n')
  179. while (modelImprovable) and itr < max_itr:
  180.     # Start
  181.     itr += 1
  182.     print('current iteration time: ', itr)
  183.  
  184.     # Solve RMP
  185.     master.updateModel()
  186.     master.solveRelaxModel()
  187.     objValHist.append(master.getObjValues)
  188.     print('Current RMP ObjVal: ', objValHist)
  189.  
  190.     # Get Duals
  191.     duals_i = master.getDuals_i()
  192.     duals_ts = master.getDuals_ts()
  193.  
  194.     # Solve SPs
  195.     for i in I_list:
  196.         subproblem = Subproblem(duals_i, duals_ts, DataDF, i)
  197.         subproblem.buildModel()
  198.         subproblem.solveModel(3600, 1e-6)
  199.         status = subproblem.getStatus()
  200.         if status != 2:
  201.             raise Exception("Pricing-Problem can not reach optimality!")
  202.         reducedCost = subproblem.getObjVal()
  203.         print('reduced cost', reducedCost)
  204.         if reducedCost < -1e-6:
  205.             ScheduleCuts = subproblem.getNewSchedule()
  206.             master.addColumn(ScheduleCuts, itr, i)
  207.         else:
  208.             modelImprovable = False
  209.  
  210. # Solve MP
  211. master.solveModel(3600, 0.01)
  212.  
  213. # Results
  214. master.writeModel()
  215. print('*** Results ***')
  216. print('Total iteration: ', itr)
  217. t1 = time.time()
  218. print('Total elapsed time: ', t1 - t0)
  219. print('Exact solution cost:', master.getAttr("ObjVal"))
  220.  
  221. # Plot
  222. plt.scatter(list(range(len(rmp_objvals))), rmp_objvals, c='r')
  223. plt.xlabel('History')
  224. plt.ylabel('Objective function value')
  225. title = 'Solution: ' + str(rmp_objvals[-1])
  226. plt.title(title)
  227. plt.show()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement