class Backup(object): """ Class object for normal-based backup network model. Parameters ---------- nodes: set of nodes links: set of links capacity: capacities per link based based on random failures mean: mean for failure random variable std: standard deviation for failure random variable invstd: inverse of Phi-normal distribution for (1-epsilon) Returns ------- solution: set of capacity assigned per backup link. """ # Private model object __model = [] # Private model variables __BackupCapacity = {} __bBackupLink = {} __ValidLink = {} # Private model parameters __links = [] __nodes = [] __capacity = [] __mean = [] __std = [] __invstd = 1 def __init__(self,nodes,links,capacity,mean,std,invstd): ''' Constructor ''' self.__links = links self.__nodes = nodes self.__capacity = capacity self.__mean = mean self.__std = std self.__invstd = invstd self.__loadModel() def __loadModel(self): # Create optimization model self.__model = Model('Backup') # Auxiliary variables for SOCP reformulation U = {} R = {} # Create variables for i,j in self.__links: self.__BackupCapacity[i,j] = self.__model.addVar(lb=0, obj=1, name='Backup_Capacity[%s,%s]' % (i, j)) self.__model.update() for i,j in self.__links: for s,d in self.__links: self.__bBackupLink[i,j,s,d] = self.__model.addVar(vtype=GRB.BINARY,obj=1,name='Backup_Link[%s,%s,%s,%s]' % (i, j, s, d)) self.__model.update() for i,j in self.__links: U[i,j] = self.__model.addVar(obj=1,name='U[%s,%s]' % (i, j)) self.__model.update() for i,j in self.__links: for s,d in self.__links: R[i,j,s,d] = self.__model.addVar(obj=1,name='R[%s,%s,%s,%s]' % (i,j,s,d)) self.__model.update() self.__model.modelSense = GRB.MINIMIZE #m.setObjective(quicksum([fixedCosts[p]*open[p] for p in plants])) self.__model.setObjective(quicksum(self.__BackupCapacity[i,j] for i,j in self.__links)) self.__model.update() #------------------------------------------------------------------------# # Constraints definition # # # # # #------------------------------------------------------------------------# # Link capacity constraints for i,j in self.__links: self.__model.addConstr(self.__BackupCapacity[i,j] >= quicksum(self.__mean[s,d]*self.__bBackupLink[i,j,s,d] for (s,d) in self.__links) + U[i,j]*self.__invstd,'[CONST]Link_Cap_%s_%s' % (i, j)) self.__model.update() # SCOP Reformulation Constraints for i,j in self.__links: self.__model.addConstr(quicksum(R[i,j,s,d]*R[i,j,s,d] for (s,d) in self.__links) <= U[i,j]*U[i,j],'[CONST]SCOP1[%s][%s]' % (i, j)) self.__model.update() # SCOP Reformulation Constraints for i,j in self.__links: for s,d in self.__links: self.__model.addConstr(self.__std[s,d]*self.__bBackupLink[i,j,s,d] == R[i,j,s,d],'[CONST]SCOP2[%s][%s][%s][%s]' % (i, j,s,d)) self.__model.update() for i in self.__nodes: for s,d in self.__links: # Flow conservation constraints if i == s: self.__model.addConstr(quicksum(self.__bBackupLink[i,j,s,d] for i,j in self.__links.select(i,'*')) - quicksum(self.__bBackupLink[j,i,s,d] for j,i in self.__links.select('*',i)) == 1,'Flow1[%s,%s,%s,%s]' % (i,j,s, d)) # Flow conservation constraints elif i == d: self.__model.addConstr(quicksum(self.__bBackupLink[i,j,s,d] for i,j in self.__links.select(i,'*')) - quicksum(self.__bBackupLink[j,i,s,d] for j,i in self.__links.select('*',i)) == -1,'Flow2[%s,%s,%s,%s]' % (i,j,s, d)) # Flow conservation constraints else: self.__model.addConstr(quicksum(self.__bBackupLink[i,j,s,d] for i,j in self.__links.select(i,'*')) - quicksum(self.__bBackupLink[j,i,s,d] for j,i in self.__links.select('*',i)) == 0,'Flow3[%s,%s,%s,%s]' % (i,j,s, d)) self.__model.update() def optimize(self,MipGap, TimeLimit): self.__model.write('backup.lp') if MipGap != None: self.__model.params.timeLimit = TimeLimit if TimeLimit != None: self.__model.params.MIPGap = MipGap # Compute optimal solution self.__model.optimize() # Print solution if self.__model.status == GRB.Status.OPTIMAL: solution = self.__model.getAttr('x', self.__BackupCapacity) for i,j in self.__links: if solution[i,j] > 0: print('%s -> %s: %g' % (i, j, solution[i,j])) else: print('Optimal value not found!\n') solution = [] return solution; def reset(self): ''' Reset model solution ''' self.__model.reset()
def get_mapping(PG, VG): vnodes, vhosts = multidict({n: len(VG.node[n]['host_ports']) for n in VG.nodes()}) pnodes, phosts = multidict({n: len(PG.node[n]['host_ports']) for n in PG.nodes()}) parcs, pcapacity = multidict({(m, n): PG.edge[m][n]['weight'] for (m, n) in PG.edges()}) parcs = tuplelist(parcs) varcs, vcapacity = multidict({(m, n): VG.edge[m][n]['weight'] for (m, n) in VG.edges()}) varcs = tuplelist(varcs) m = Model('mapping') # Create variables node_mapping = {} for i in vnodes: for j in pnodes: node_mapping[i, j] = m.addVar(vtype=GRB.BINARY, name="x_%s_%s" % (i, j)) edge_mapping = {} for i in vnodes: for p in VG.neighbors(i): for (j, q) in parcs: edge_mapping[i, p, j, q] = m.addVar(vtype=GRB.BINARY, name="y_%s_%s_%s_%s" % (i, p, j, q)) m.update() # Arc capacity constraints for i in vnodes: m.addConstr(quicksum(node_mapping[i, j] for j in pnodes) == 1, 'node_%s' % i) for i in vnodes: for p in VG.neighbors(i): for (j, q) in parcs: m.addConstr(edge_mapping[i, p, j, q] <= ( node_mapping[i, j] + node_mapping[p, q] )/2, 'edge_%s_%s_%s_%s' % (i, p, j, q)) for (j, q) in parcs: m.addConstr(quicksum(edge_mapping[i, p, j, q] + edge_mapping[p, i, j, q]for (i, p) in varcs) <= pcapacity[j, q], 'pcap_%s_%s' % (j, q)) for (i, p) in varcs: m.addConstr(quicksum(edge_mapping[i, p, j, q] + edge_mapping[p, i, j, q] for (j, q) in parcs) >= vcapacity[i, p], 'vcap_%s_%s' % (i, p)) for j in pnodes: m.addConstr(quicksum(node_mapping[i, j] * vhosts[i] for i in vnodes) <= phosts[j], 'phosts_%s' % j) for i in vnodes: m.addConstr(quicksum(node_mapping[i, j] * phosts[j] for j in pnodes) >= vhosts[i], 'vhosts_%s' % i) # Compute optimal solution m.optimize() # Print solution if m.status == GRB.status.OPTIMAL: mapping = {} mapping2 = {} portlist = {} for n in PG: if 'host_ports' in PG.node[n]: portlist[n] = PG.node[n]['host_ports'] solution = m.getAttr('x', edge_mapping) for h in solution: if solution[h] == 1.0: vid1, vid2, pid1, pid2 = h vport1, vport2 = list(VG.node[vid1]['links'][vid2])[0] if (vid1, pid1) not in mapping: mapping[(vid1, pid1)] =[vid1, pid1] if (pid1, vid1) not in mapping2: mapping2[(pid1, vid1)] =[pid1, vid1] (pport1, pport2) = PG.node[pid1]['links'][pid2].pop() # print vid1, vid2, pid1, pid2, pport1, pport2 if pid1 != pid2: PG.node[pid2]['links'][pid1].remove((pport2, pport1)) mapping[(vid1, pid1)].append(vport1) mapping[(vid1, pid1)].append(pport1) mapping2[(pid1, vid1)].append(pport1) mapping2[(pid1, vid1)].append(vport1) if (vid2, pid2) not in mapping: mapping[(vid2, pid2)] =[vid2, pid2] if (pid2, vid2) not in mapping2: mapping2[(pid2, vid2)] =[pid2, vid2] mapping[(vid2, pid2)].append(vport2) mapping[(vid2, pid2)].append(pport2) mapping2[(pid2, vid2)].append(pport2) mapping2[(pid2, vid2)].append(vport2) solution2 = m.getAttr('x', node_mapping) print [h for h in solution2 if solution2[h] == 1.0] for h in solution2: if solution2[h] == 1.0: vid, pid = h if len(VG.node[vid]['host_ports']) == 0: continue for vport in VG.node[vid]['host_ports']: pport = portlist[pid].pop() mapping[(vid, pid)].append(vport) mapping[(vid, pid)].append(pport) mapping2[(pid, vid)].append(pport) mapping2[(pid, vid)].append(vport) return mapping, mapping2 def main(): args = parse_args() VG = gen_graph(args.target_topology) if not networkx.is_connected(VG): print 'Target topology is not connected' sys.exit(1) PG = gen_graph(args.host_topology, int_idx=True) mapping, mapping2 = get_mapping(PG, VG) f = open(args.output, "w") print >>f, "P2Vmap" for id in mapping2: for id2 in mapping2[id]: print >>f, id2, print>>f, "65535 65535" print >>f, "V2Pmap" for id in mapping: for id2 in mapping[id]: print >>f, id2, print>>f, "65535 65535" if __name__ == "__main__": main()
def retrieve_values(lp_problem: LpProblem, lp_variables: List[LpVariable], model: gurobipy.Model) -> None: """ Extract the value of variables from the gurobi model and set them into the Flipy objects Parameters ---------- lp_problem: The Flipy object into which the variable values will be set lp_variables: A list of LpVariables of the problem model: The gurobi model to grab the variable values from """ try: var_name_to_values = dict( zip(model.getAttr(gurobipy.GRB.Attr.VarName, model.getVars()), model.getAttr(gurobipy.GRB.Attr.X, model.getVars()))) for var in lp_variables: var.set_value(var_name_to_values[var.name]) for constraint in lp_problem.lp_constraints.values(): if constraint.slack: constraint.slack_variable.set_value( var_name_to_values[constraint.slack_variable.name]) except (gurobipy.GurobiError, AttributeError): pass
def parse_results(model: gp.Model) -> None: objVal = model.getObjective().getValue() print("Get optimal Obj: {}".format(objVal)) print("Solution:") for name, val in zip(model.getAttr("varName"), model.getAttr("x")): print("Var {}: {}".format(name, val)) for con, val in zip(model.getAttr("constrName"), model.getAttr("Pi")): print("Dual var of {}: {}".format(con, val))
def VRPSol(n, K, C, Ps, Ds, d, F, TimeLimit): m = Model() m.setParam(GRB.Param.TimeLimit, TimeLimit) # Create variables x = {} for i in Ps: for j in Ps: if i != j : x[i,j] = m.addVar(obj=F(Ps[i], Ps[j]), vtype=GRB.BINARY, name='x'+str(i)+'_'+str(j)) # Create Miller variables (subtour elimination) u = {} for i in Ds: if i != d: u[i] = m.addVar(obj=0.0, vtype=GRB.CONTINUOUS, lb=Ds[i], ub=C, name='u'+str(i)) m.update() # Add outdegree constraint for j in Ps: if j != d: Ls = list(filter(lambda z: z!=j, Ps)) m.addConstr(quicksum(x[i,j] for i in Ls) == 1) # Add indegree constraint for i in Ps: if i != d: Ls = filter(lambda z: z!=i, Ps) m.addConstr(quicksum(x[i,j] for j in Ls) == 1) # Number of vehicles Ls = list(filter(lambda z: z!=d, Ps)) m.addConstr(quicksum(x[i,d] for i in Ls) == K) m.addConstr(quicksum(x[d,j] for j in Ls) == K) # Subtour elimination constraints for i in Ls: for j in Ls: if i != j: m.addConstr( u[i] - u[j] +C*x[i,j] <= C - Ds[j] ) m.update() # Solve the model m.optimize() solution = m.getAttr('x', x) selected = [(i,j) for (i,j) in solution if solution[i,j] > 0.5] # Xs = [p for p in Ps.values()] # Ws = [w for w in Ds.values()] # for i,j in selected: # DisegnaSegmento(Ps[i], Ps[j]) # plt.scatter([i for i,j in Xs[1:]], [j for i,j in Xs[1:]], # s=Ws[1:], alpha=0.3, cmap='viridis') # plt.plot([Xs[0][0]], [Xs[0][1]], marker='s', color='red', alpha=0.5) # plt.axis('square') # plt.axis('off') return m.objVal, selected
def ilp_node_reachability(reachability_dic, max_delay=180, log_path=None): # List of nodes ids node_ids = sorted(list(reachability_dic.keys())) #node_ids = node_ids[:100] try: # Create a new model m = Model("region_centers") if log_path: m.Params.LogFile = '{}/region_centers_{}.log'.format( log_path, max_delay) # xi = 1, if vertex Vi is used as a region center and 0 otherwise x = m.addVars(node_ids, vtype=GRB.BINARY, name="x") # Ensures that every node in the road network graph is reachable # within 'max_delay' travel time by at least one region center # selected from the nodes in the graph. # To extract the region centers, we select from V all vertices # V[i] such that x[i] = 1. for d in node_ids: m.addConstr( quicksum(x[o] * is_reachable(reachability_dic, o, d, max_delay) for o in node_ids) >= 1) # Set objective m.setObjective(quicksum(x), GRB.MINIMIZE) # Solve m.optimize() region_centers = list() if m.status == GRB.Status.OPTIMAL: var_x = m.getAttr('x', x) for n in node_ids: if var_x[n] > 0.0001: region_centers.append(n) return region_centers else: print('No solution') return None except GurobiError as e: print('Error code ' + str(e.errno) + ": " + str(e)) except AttributeError as e: print('Encountered an attribute error:' + str(e))
def solve_model(model: gurobipy.Model): model.optimize() if model.getAttr("STATUS") != gurobipy.GRB.OPTIMAL: raise ValueError sol = model.getVars() out = "" value = 0 for v in sol: out += f"{v.VarName} {v.X}\n" value += 1 if v.X >= 0.5 else 0 return out, value
def BarycenterBipartite(images, G): """ Compute the Kantorovich Wasserstein Barycenter of any order using bipartite subgraphs""" K = len(images) n = len(images[0]) # Build model m = Model() m.setParam(GRB.Param.Method, 2) m.setParam(GRB.Param.NumericFocus, 1) m.setParam(GRB.Param.OutputFlag, 0) m.setParam(GRB.Param.Crossover, 0) m.setAttr(GRB.Attr.ModelSense, 1) # Create variables Y = {} for v in range(n): Y[v] = m.addVar(obj=0) X = {} for e in G.edges(): i, j = e for k in range(K): X[i, j, k] = m.addVar(obj=G.edges[i, j]['weight']) m.update() # In and out flow variable on the bipartite graph for v in range(n): Fs = [w for w in G.out_edges(v)] for k in range(K): m.addConstr(quicksum(X[i, j, k] for i, j in Fs) == images[k][v]) for v in range(n): Bs = [w for w in G.in_edges(n + v)] for k in range(K): m.addConstr(quicksum(X[i, j, k] for i, j in Bs) == Y[v]) m.addConstr(quicksum(Y[v] for v in Y) == 1.0) # Solve the model m.optimize() return m.getAttr(GRB.Attr.ObjVal), [Y[i].X for i in Y]
def gurobi_tsp(distance_matrix): """ Solves tsp problem. :param distance_matrix: symmetric matrix of distances, where the i,j element is the distance between object i and j :return: matrix containing {0, 1}, 1 for each transition that is included in the tsp solution """ n = len(distance_matrix) m = Model() m.setParam("OutputFlag", False) m.setParam("Threads", 1) # Create variables vars = {} for i in range(n): for j in range(i + 1): vars[i, j] = m.addVar(obj=0.0 if i == j else distance_matrix[i][j], vtype=GRB.BINARY, name="e" + str(i) + "_" + str(j)) vars[j, i] = vars[i, j] m.update() # Add degree-2 constraint, and forbid loops for i in range(n): m.addConstr(quicksum(vars[i, j] for j in range(n)) == 2) vars[i, i].ub = 0 m.update() # Optimize model m._vars = vars m.params.LazyConstraints = 1 def subtour_fn(model, where): return subtourelim(n, model, where) m.optimize(subtour_fn) solution = m.getAttr("x", vars) selected = [(i, j) for i in range(n) for j in range(n) if solution[i, j] > 0.5] result = np.zeros_like(distance_matrix) for (i, j) in selected: result[i][j] = 1 return result
def BarycenterL2(images, G): """ Compute the Kantorovich Wasserstein Barycenter of order 1 with L2 as ground distance """ K = len(images) # Build model m = Model() m.setParam(GRB.Param.Method, 2) m.setParam(GRB.Param.NumericFocus, 1) m.setParam(GRB.Param.OutputFlag, 0) m.setParam(GRB.Param.Crossover, 0) m.setAttr(GRB.Attr.ModelSense, 1) # Create variables Y = {} for v in G.nodes(): Y[v] = m.addVar(obj=0) X = {} for e in G.edges(): i, j = e for k in range(K): X[i, j, k] = m.addVar(obj=G.edges[i, j]['weight']) m.update() # Flow variables for v in G.nodes(): Fs = [w for w in G.out_edges(v)] Bs = [w for w in G.in_edges(v)] for k in range(K): m.addConstr( quicksum(X[i, j, k] for i, j in Fs) - quicksum(X[i, j, k] for i, j in Bs) == images[k][v] - Y[v]) m.addConstr(quicksum(Y[v] for v in G.nodes()) == 1.0) m.update() # Solve the model m.optimize() return m.getAttr(GRB.Attr.ObjVal), [Y[i].X for i in Y]
def WassersteinDualSimplex(h1, h2, M): """ Find the Wasserstein distance using the dual simplex """ n = len(h1) # Build model m = Model() m.setParam(GRB.Param.NumericFocus, 3) #m.setParam(GRB.Param.TimeLimit, 300) #m.setParam(GRB.Param.Presolve, 0) #m.setParam(GRB.Param.Threads, 1) # Options are: # -1=automatic, 0=primal simplex, 1=dual simplex, 2=barrier, # 3=concurrent, 4=deterministic concurrent. #m.setParam(GRB.Param.Method, 0) print('1. Start building model') # Create variables x = {} P = set() D = [] for i in range(n): if h1[i] > 0: x[i] = {} for j in range(n): if h2[j] > 0: x[i][j] = m.addVar(ub=min(h1[i], h2[j]), obj=M[i][j]) D.append((i, j)) P.add(j) D = tuplelist(D) m.update() print('2. Add initial constraint sets') for i in x: m.addConstr(quicksum(x[i][j] for j in x[i]) <= h1[i]) for j in P: m.addConstr(quicksum(x[i][j] for i, j in D.select('*', j)) >= h2[j]) print('3. Start solution phase') # Solve the model m.optimize() return m.getAttr(GRB.Attr.ObjVal)
def SolveCuttingPlane(h1, h2, M): m = Model() m.setParam(GRB.Param.TimeLimit, 300) m.setParam(GRB.Param.Method, 1) # Create variables x = {} n = len(h1) for i in range(n): for j in range(n): x[i, j] = m.addVar(obj=M[i][j], name='x' + str(i) + '_' + str(j)) m.update() for i in range(n): m.addConstr(quicksum(x[i, j] for j in range(n)) == h1[i]) for j in range(n): m.addConstr(quicksum(x[i, j] for i in range(n)) == h2[j]) # Solve the model m.optimize() return m.getAttr(GRB.Attr.ObjVal)
def WassersteinMinFlowL1(h1, h2): """ Find the Wasserstein distance using a cutting plane on the dual """ def ID(x,y): return x*s+y n = len(h1) s = int(np.sqrt(n)) print(n,s) # Build model m = Model() #m.setParam(GRB.Param.TimeLimit, 300) #m.setParam(GRB.Param.Presolve, 0) #m.setParam(GRB.Param.Threads, 1) # Options are: # -1=automatic, 0=primal simplex, 1=dual simplex, 2=barrier, # 3=concurrent, 4=deterministic concurrent. #m.setParam(GRB.Param.Method, 1) # Set a maximization problem m.setAttr(GRB.Attr.ModelSense, 1) print('1. Start building model') # Create variables X = {} for i in range(s): for j in range(s): X[ID(i,j)] = {} X[n] = {} P = [] for i in range(s): for j in range(s-1): X[ID(i,j)][ID(i,j+1)] = m.addVar(obj=1) X[ID(i,j+1)][ID(i,j)] = m.addVar(obj=1) P.append((ID(i,j), ID(i,j+1))) P.append((ID(i,j+1), ID(i,j))) for i in range(s-1): for j in range(s): X[ID(i,j)][ID(i+1,j)] = m.addVar(obj=1) X[ID(i+1,j)][ID(i,j)] = m.addVar(obj=1) P.append((ID(i,j), ID(i+1,j))) P.append((ID(i+1,j), ID(i,j))) # Infintiy norm: need diagonal arcs (cost 1) for i in range(s-1): for j in range(s-1): X[ID(i,j)][ID(i+1,j+1)] = m.addVar(obj=math.sqrt(2)) X[ID(i+1,j+1)][ID(i,j)] = m.addVar(obj=math.sqrt(2)) P.append((ID(i,j), ID(i+1,j+1))) P.append((ID(i+1,j+1), ID(i,j))) X[ID(i,j+1)][ID(i+1,j)] = m.addVar(obj=math.sqrt(2)) X[ID(i+1,j)][ID(i,j+1)] = m.addVar(obj=math.sqrt(2)) P.append((ID(i,j+1), ID(i+1,j))) P.append((ID(i+1,j), ID(i,j+1))) # Better approximation for i in range(s-2): for j in range(s-2): X[ID(i,j)][ID(i+2,j+1)] = m.addVar(obj=math.sqrt(5)) X[ID(i+2,j+1)][ID(i,j)] = m.addVar(obj=math.sqrt(5)) P.append((ID(i,j), ID(i+2,j+1))) P.append((ID(i+2,j+1), ID(i,j))) X[ID(i,j)][ID(i+1,j+2)] = m.addVar(obj=math.sqrt(5)) X[ID(i+1,j+2)][ID(i,j)] = m.addVar(obj=math.sqrt(5)) P.append((ID(i,j), ID(i+1,j+2))) P.append((ID(i+1,j+2), ID(i,j))) X[ID(i,j+2)][ID(i+1,j)] = m.addVar(obj=math.sqrt(5)) X[ID(i+1,j)][ID(i,j+2)] = m.addVar(obj=math.sqrt(5)) P.append((ID(i,j+2), ID(i+1,j))) P.append((ID(i+1,j), ID(i,j+2))) X[ID(i,j+2)][ID(i+2,j+1)] = m.addVar(obj=math.sqrt(5)) X[ID(i+2,j+1)][ID(i,j+2)] = m.addVar(obj=math.sqrt(5)) P.append((ID(i,j+2), ID(i+2,j+1))) P.append((ID(i+2,j+1), ID(i,j+2))) P = tuplelist(P) m.update() # Flow variables print('2. Add initial constraint sets') for i in range(n): b = h2[i] - h1[i] m.addConstr(quicksum(X[i][j] for j in X[i])-quicksum(X[j][i] for j,i in P.select('*',i)) == b) #m.addConstr(quicksum(X[n][i] for i in range(n)) >= abs(sum(h1)-sum(h2))) print('3. Start solution phase') # Solve the model m.optimize() return m.getAttr(GRB.Attr.ObjVal)
class KPPBase(metaclass=ABCMeta): def __init__(self, G, k, verbosity): self.G = G self.model = Model() self.model.modelSense = GRB.MINIMIZE self.k = k self.y = {} self.model.setParam("OutputFlag", 0) for e in self.G.es(): u = min(e.source, e.target) v = max(e.source, e.target) if 'weight' in e.attributes(): self.y[u, v] = self.model.addVar(obj=e['weight'], ub=1.0) else: self.y[u, v] = self.model.addVar(obj=1.0, ub=1.0) self.x = {} self.z = {} self.discretized = False self.constraints = [] self.sep_algs = [] self.out = sys.stdout self.verbosity = verbosity def get_solution(self): return Solution(self.model.getAttr('x', self.x), self.model.getAttr('x', self.y), self.model.getAttr('x', self.z)) def get_colouring(self): '''Map of colours to nodes with that colour''' if self.discretized and self.model.status == 2: n = self.G.vcount() K = self.num_colours() colouring = [[] for i in range(K)] x = self.get_solution().x for u in range(n): for i in range(K): if abs(x[u, i] - 1.0) < 1e-3: colouring[i].append(u) return colouring else: raise(RuntimeError('Can only extract colouring if KPP has been fully solved')) def add_fractional_cut(self): if self.x: raise RuntimeError( 'Fractional y-cut can only be added before the x variables have been added') if not self.model.status == 2: raise RuntimeError( 'Fractional y-cut can only be added after successful a cutting plane phase (and before constraint removal)') y_lb = sum(self.model.getAttr('x', self.y).values()) eps = self.model.params.optimalityTol if abs(ceil(y_lb) - y_lb) > eps: sum_y = LinExpr() for e in self.G.es(): u = min(e.source, e.target) v = max(e.source, e.target) sum_y.addTerms(1.0, self.y[u, v]) self.model.addConstr(sum_y >= ceil(y_lb)) return True def cut(self): if self.discretized: raise RuntimeError( 'Cutting plan algorithm can only be used before model has been discretized') if self.verbosity > 0: print('Running cutting plane algorithms', file=self.out) it_count = 0 total_added = 0 while True: it_count += 1 self.model.optimize() if self.verbosity > 1: print('\n', 10 * '-', 'Iteration ', it_count, 10 * '-', file=self.out) print(" Objective value: ", self.model.objVal, file=self.out) new_constraints = [] sol = self.get_solution() for sep_alg in self.sep_algs: constr_list = sep_alg.find_violated_constraints( sol, self.verbosity - 1) new_constraints.extend(constr_list) total_added += len(new_constraints) for constr in new_constraints: self.add_constraint(constr) if not new_constraints: if self.verbosity > 1: print(' Found no constraints to add; exiting cutting plane loop', file=self.out) if self.verbosity > 0: print(' Added a total of', total_added, 'constraints', file=self.out) print(' Lower bound: ', self.model.objVal) break return total_added def remove_redundant_constraints(self, hard=False, allowed_slack=1e-3): slack, dual = 0, 0 to_remove = [] for constr in self.constraints: if abs(constr.Slack) > allowed_slack: to_remove.append(constr) slack += 1 elif hard and constr.Pi == 0.0: to_remove.append(constr) dual += 1 for constr in to_remove: self.model.remove(constr) self.constraints.remove(constr) if self.verbosity > 0: print(" Removed", slack, "constraints with slack greater than", allowed_slack, file=self.out) print(" Removed", dual, "constraints with zero dual variable", file=self.out) print("", len(self.constraints), "constraints remaining", file=self.out) self.model.update() return slack + dual def add_separator(self, sep_alg): self.sep_algs.append(sep_alg) def add_constraint(self, constraint): expr = LinExpr() for e, coef in constraint.x_coefs.items(): expr.addTerms(coef, self.x[e]) for e, coef in constraint.y_coefs.items(): expr.addTerms(coef, self.y[e]) for e, coef in constraint.z_coefs.items(): expr.addTerms(coef, self.z[e]) if constraint.op == '<': cons = self.model.addConstr(expr <= constraint.rhs) elif constraint.op == '>': cons = self.model.addConstr(expr >= constraint.rhs) elif constraint.op == '==': cons = self.model.addConstr(expr == constraint.rhs) self.constraints.append(cons) def solve(self): if not self.x: self.add_node_variables() if not self.discretized: self.discretize() if self.verbosity > 0: print("Running branch-and-bound", file=self.out) self.model.optimize() if self.verbosity > 0: print(" Optimal objective value: ", self.model.objVal, file=self.out) @abstractmethod def add_node_variables(self): pass @abstractmethod def num_colours(self): pass def discretize(self): if not self.x: raise RuntimeError( "Cannot discretize problem before x variables have been added") for var in self.x.values(): var.vtype = GRB.BINARY self.discretized = True @abstractmethod def print_solution(self): pass @abstractmethod def num_colours(self): pass
def calculate_ILP(g, quadratic=False, dummy_edge_cost=100, distance_cost=1, comb_angle_cost=5, verbose=True, visualize=False, linear=False, angle_cost_factor=0): print "starting constructing ILP" model = Model() # model.setParam(GRB.Param.TimeLimit, 7200.0) variables = {} # Add variables to the model, per edge in the graph one variable for edge in g.nx_graph.edges_iter(data=True): i = edge[0] j = edge[1] dist = edge[2]['distance'] cur_dir_vector = edge[2]['dir_vector'] angle_cost = 0 if angle_cost_factor != 0: angle1 = get_angle(g, i, cur_dir_vector) angle2 = get_angle(g, j, cur_dir_vector) angle_cost = (angle1 + angle2) * angle_cost_factor # angle = utils.angle_between_vecs(dir_vec_of_node, cur_dir_vec) # print dist # print angle1, angle2, cur_dir_vector variables[i, j] = model.addVar(obj=(dist * distance_cost + angle_cost)**1, vtype=GRB.BINARY, name='e' + str(i) + '_' + str(j)) variables[j, i] = variables[i, j] # This is the number for the dummy node. This guarantees that the id is not already occcupied by a node id n = np.max(g.nx_graph.nodes()) + 1 g.add_geom_features_to_edges() g.add_geom_features_to_nodes() for node_id in g.nx_graph.nodes_iter(): # Add dummy node, here the costs decide about how expensive it is to open / close a chain variables[node_id, n] = model.addVar(obj=dummy_edge_cost, vtype=GRB.BINARY, name='dummy1_%s' % str(node_id)) variables[node_id, n + 1] = model.addVar(obj=dummy_edge_cost, vtype=GRB.BINARY, name='dummy2_%s' % str(node_id)) variables[n, node_id] = variables[node_id, n] variables[n + 1, node_id] = variables[node_id, n + 1] model.update() for node_id in g.nx_graph.nodes_iter(): neighbours = g.nx_graph.neighbors(node_id) neighbours.extend([n, n + 1]) model.addConstr(quicksum(variables[node_id, j] for j in neighbours) == 2, name='node_%i' % node_id) model.update() print "Intermediate number of variables before adding combination aspect", model.NumVars if quadratic: if verbose: print "adding quadratic terms" quad = QuadExpr() for node_id, node_attr in g.nx_graph.nodes_iter(data=True): neighbours = g.nx_graph.neighbors(node_id) neighbours.sort() # Add the quadratic terms for the combination of each edge pair incident to the same node for ii in range(len(neighbours) - 1): neighbour_id1 = neighbours[ii] for jj in range(len(neighbours) - ii - 1): neighbour_id2 = neighbours[jj + ii + 1] spanning_angle = node_attr['spanning_angles'][( neighbour_id1, neighbour_id2)] quad.add( variables[node_id, neighbour_id1] * variables[node_id, neighbour_id2] * (np.abs(spanning_angle - np.pi) * comb_angle_cost)**2) # Add linear costs to quadratic expression for edge in g.nx_graph.edges_iter(data=True): i = edge[0] j = edge[1] dist = edge[2]['distance'] cur_dir_vector = edge[2]['dir_vector'] angle1 = get_angle(g, i, cur_dir_vector) angle2 = get_angle(g, j, cur_dir_vector) angle_cost = (angle1 + angle2) * angle_cost_factor total_cost = angle_cost + dist * distance_cost quad.add(variables[i, j] * (total_cost)) for node_id in g.nx_graph.nodes_iter(): # Add dummy node, here the costs decide about how expensive it is to open / close a chain quad.add(variables[node_id, n] * dummy_edge_cost) quad.add(variables[node_id, n + 1] * dummy_edge_cost) print "model collection costs finished" model.setObjective(quad) model.update() print "Number of variables after adding quadratic component", model.NumVars elif linear: # Add additional variables that represent the combination of two edges respectively edge_combinations = {} for node_id, node_attr in g.nx_graph.nodes_iter(data=True): neighbours = g.nx_graph.neighbors(node_id) neighbours.sort() for ii in range(len(neighbours) - 1): neighbour_id1 = neighbours[ii] for jj in range(len(neighbours) - ii - 1): neighbour_id2 = neighbours[jj + ii + 1] spanning_angle = node_attr['spanning_angles'][( neighbour_id1, neighbour_id2)] edge_combinations[node_id, neighbour_id1, neighbour_id2] = \ model.addVar(obj=(np.abs(spanning_angle - np.pi) * comb_angle_cost) ** 2, vtype=GRB.BINARY, name='node_%i_edge_%i_%i' % (node_id, neighbour_id1, neighbour_id2)) model.update() # Add corresponding constraints to new introduced variables (specifically, # combination of egdes should only be switched on if both corresponding edges are switched on) for node_id, node_attr in g.nx_graph.nodes_iter(data=True): neighbours = g.nx_graph.neighbors(node_id) neighbours.sort() for ii in range(len(neighbours) - 1): neighbour_id1 = neighbours[ii] for jj in range(len(neighbours) - ii - 1): neighbour_id2 = neighbours[jj + ii + 1] model.addConstr(edge_combinations[node_id, neighbour_id1, neighbour_id2] <= variables[node_id, neighbour_id1]) model.addConstr(edge_combinations[node_id, neighbour_id1, neighbour_id2] <= variables[node_id, neighbour_id2]) model.addConstr(edge_combinations[node_id, neighbour_id1, neighbour_id2] + 1 >= variables[node_id, neighbour_id2] + variables[node_id, neighbour_id1]) model.update() if verbose: print "starting Optimization" print "Number of variables %i" % model.NumVars print "Number of linear constraints %i" % model.NumConstrs model.optimize() # Contains a label for each edge solution = model.getAttr("X", variables) if linear: comb_solution = model.getAttr("X", edge_combinations) new_edgelist = [] count2 = 0 for edge, sol in solution.iteritems(): if n + 1 in edge or n in edge: if sol == 1: count2 += 1 elif sol == 1: if not edge in new_edgelist or not (edge[1], edge[0]) in new_edgelist: new_edgelist.append(edge) if visualize: g.visualize(edgelist=new_edgelist, only_edges_from_edgelist=True) mlab.show() # Create new graph from solution graph_solution = create_graph_from_solution(g, new_edgelist) graph_solution.print_statistics() if linear: check_consistency(comb_solution, solution) if linear: return graph_solution, [model, solution, comb_solution] else: return graph_solution, [model, solution]
def optmodel(): #form need to be in html datein = request.form['startDate'] dateout = request.form['endDate'] nhall = int(request.form['ExhibitHalls']) nmeeting = int(request.form['MeetingRooms']) naudi = int(request.form['Auditorium']) nball = int(request.form['Ballrooms']) minsqft = int(request.form['Minsqft']) rooms = transQuery("SELECT * FROM ROOM") roomsDF = pd.DataFrame(rooms, columns=[ "RoomID", "Name", "Sqft", "Cost", "Building", "Floor", "X", "Y" ]) roomsIndex = [int(i) for i in roomsDF["RoomID"]] convName = ["Sqft", "Cost", "Building", "Floor", "X", "Y"] for name in convName: roomsDF[name] = pd.to_numeric(roomsDF[name], errors='ignore') OccupiedID = transQuery( "SELECT RoomID FROM BOOKED WHERE dateIN BETWEEN ? AND ? AND dateout BETWEEN ? AND ?", ( datein, dateout, datein, dateout, )) OccupiedID = pd.DataFrame(OccupiedID, columns=["RoomID"]) OccupiedID = [int(i) for i in OccupiedID["RoomID"]] Arooms = transQuery( "SELECT * FROM ROOM WHERE RoomID NOT IN (SELECT RoomID FROM booked WHERE dateIN BETWEEN ? AND ? AND dateout BETWEEN ? AND ?)", ( datein, dateout, datein, dateout, )) #"SELECT * FROM ROOM WHERE RoomID NOT IN (SELECT RoomID FROM booked WHERE dateIN BETWEEN '2019-08-14' AND '2019-08-20' AND dateout BETWEEN '2019-08-14' AND '2019-08-20');" #[40, 41, 42, 106, 107, 108, 109, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 140, 141] AroomsDF = pd.DataFrame(Arooms, columns=[ "RoomID", "Name", "Sqft", "Cost", "Building", "Floor", "X", "Y" ]) for name in convName: AroomsDF[name] = pd.to_numeric(AroomsDF[name], errors='ignore') # AroomsDF.astype({"Sqft":'float32',"Cost":'float32',"Building":'float32',"Floor":'float32',"X":'float32',"Y":'float32'}) AroomsIndex = [int(i) for i in AroomsDF["RoomID"]] #MODEL m = Model('Rooms') m.setParam('TimeLimit', 360) x = m.addVars(roomsIndex, name="x", vtype=GRB.BINARY) d = m.addVar(0, name="d", vtype=GRB.CONTINUOUS) DearDaniel = 7 e = [0, 1, 2, 40, 41, 42, 43, 44, 106, 107, 108, 109, 143, 23, 24, 87] a = [39, 122, 123] b = [102, 103, 104, 105, 137, 138, 139] g = np.setdiff1d(roomsIndex, e + a + b) m.setObjective((quicksum(x[i] * roomsDF.iloc[i, 3] for i in roomsIndex) + DearDaniel * d), GRB.MINIMIZE) #no occupied room #need to change room id m.addConstr(sum(x[i] for i in OccupiedID) == 0) m.addConstr(sum(x[i] for i in e) >= nhall) m.addConstr(sum(x[i] for i in a) >= naudi) m.addConstr(sum(x[i] for i in b) >= nball) m.addConstr(sum(x[i] for i in g) >= nmeeting) #if E is selected, Meeting room in that can't be selected m.addConstr((x[2] * (x[4] + x[5] + x[3])) == 0) m.addConstr((x[40] * (x[46] + x[47] + x[45])) == 0) m.addConstr((x[106] * (x[112] + x[113] + x[110] + x[111])) == 0) m.addConstr(x[142] * (x[13] + x[14]) == 0) m.addConstr(x[78] * (x[79] + x[80]) == 0) m.addConstr(x[94] * (x[95] + x[96]) == 0) #minimum room m.addConstrs(x[i] == 0 for i in AroomsIndex if roomsDF.iloc[i, 2] < minsqft) #calculate the distance pRooms = [(AroomsDF.iloc[i, 4], AroomsDF.iloc[i, 5], AroomsDF.iloc[i, 6], AroomsDF.iloc[i, 7]) for i in range(len(AroomsIndex))] Sum = 0 distMat = np.empty([AroomsDF.shape[0], AroomsDF.shape[0]]) i = 0 while i < len(Arooms): room1 = pRooms[i] j = i while j < len(Arooms): room2 = pRooms[j] adiff = [((room1[k] - room2[k])**2) for k in range(4)] dist = math.sqrt(sum(adiff)) distMat[i][j] = dist distMat[j][i] = dist Sum += dist j += 1 i += 1 m.addConstr(d == sum([((x[i] * x[j]) * distMat[i][j]) for i in range(len(AroomsIndex)) for j in range(len(AroomsIndex))])) m.optimize() if m.status == GRB.Status.OPTIMAL or m.status == GRB.Status.TIME_LIMIT: x_sol = m.getAttr('x', x) """ chosenroom = [] chosenbuild = [] sumsqft = 0 sumcost=0 for i in roomsIndex: if round(x_sol[i])>= 1: chosenroom.append(roomsDF.iloc[i,1]) chosenbuild.append(roomsDF.iloc[i,4]) sumsqft = sumsqft + roomsDF.iloc[i,2] sumcost = sumcost + roomsDF.iloc[i,3] for i in range(len(chosenbuild)): if chosenbuild[i] == 0: chosenbuild[i] = "A" elif chosenbuild[i]== 200: chosenbuild[i] = "B" else: chosenbuild[i] = "C" """ rdict = {} choosenroomA = [] choosenroomB = [] choosenroomC = [] for i in roomsIndex: if round(x_sol[i]) >= 1: if roomsDF.iloc[i, 4] == 0: choosenroomA.append(roomsDF.iloc[i, 1]) rdict.update({"A": choosenroomA}) elif roomsDF.iloc[i, 4] == 200: choosenroomB.append(roomsDF.iloc[i, 1]) rdict.update({"B": choosenroomB}) else: choosenroomC.append(roomsDF.iloc[i, 1]) rdict.update({"C": choosenroomC}) costinput = [key for key in rdict.keys()] sqft = float(request.form['sqft']) rentTotal = float(request.form['RentTotal']) attendance = int(request.form["attendance"]) roomNights = int(request.form["RoomNights"]) foodBev = float(request.form['FB']) dateIn = datetime.strptime(datein, "%Y-%m-%d") dateOut = datetime.strptime(dateout, "%Y-%m-%d") eventName = request.form["EventName"] eventType = request.form["eventType"] subDate = request.form["RFPSubmission"] eventDuration = abs((dateOut - dateIn).days) rfpSubmission = datetime.strptime(request.form["RFPSubmission"], "%Y-%m-%d") contactTillStart = abs((dateIn - rfpSubmission).days) #eventDuration = dateout-datein dictEvent = { "sqftPerEvent": sqft, "orderedRentTotal": rentTotal, "Attendance": attendance, "totalRoomNights": roomNights, "FB": foodBev, "eventDuration": eventDuration, "contactTillStart": contactTillStart, "rooms": rdict, "eventType": eventType, "dateIn": dateIn.month, "eventName": eventName, "startDate": datein, "endDate": dateout, "subDate": subDate } return redirect(url_for('roompage', data=rdict, eventInfo=dictEvent))
def BarycenterLinf(images): """ Compute the Kantorovich Wasserstein Barycenter of order 1 with Linf as ground distance """ K = len(images) n = len(images[0]) s = int(np.sqrt(n)) def ID(x, y): return x * s + y # Build model m = Model() m.setParam(GRB.Param.Method, 2) m.setParam(GRB.Param.Crossover, 0) m.setParam(GRB.Param.NumericFocus, 1) m.setParam(GRB.Param.OutputFlag, 0) m.setAttr(GRB.Attr.ModelSense, 1) # Create variables Z = {} for i in range(n): Z[i] = m.addVar(obj=0) X = {} for k in range(K): for i in range(s): for j in range(s): X[k, ID(i, j)] = {} X[k, n] = {} A = [] for k in range(K): for i in range(s): for j in range(s - 1): X[k, ID(i, j)][k, ID(i, j + 1)] = m.addVar(obj=1) X[k, ID(i, j + 1)][k, ID(i, j)] = m.addVar(obj=1) if k == 0: A.append((ID(i, j), ID(i, j + 1))) A.append((ID(i, j + 1), ID(i, j))) for i in range(s - 1): for j in range(s): X[k, ID(i, j)][k, ID(i + 1, j)] = m.addVar(obj=1) X[k, ID(i + 1, j)][k, ID(i, j)] = m.addVar(obj=1) if k == 0: A.append((ID(i, j), ID(i + 1, j))) A.append((ID(i + 1, j), ID(i, j))) for i in range(s - 1): for j in range(s - 1): X[k, ID(i, j)][k, ID(i + 1, j + 1)] = m.addVar(obj=1) X[k, ID(i + 1, j + 1)][k, ID(i, j)] = m.addVar(obj=1) X[k, ID(i, j + 1)][k, ID(i + 1, j)] = m.addVar(obj=1) X[k, ID(i + 1, j)][k, ID(i, j + 1)] = m.addVar(obj=1) if k == 0: A.append((ID(i, j), ID(i + 1, j + 1))) A.append((ID(i + 1, j + 1), ID(i, j))) A.append((ID(i, j + 1), ID(i + 1, j))) A.append((ID(i + 1, j), ID(i, j + 1))) A = tuplelist(A) m.update() # Flow variables for i in range(n): Fs = A.select(i, '*') Bs = A.select('*', i) for k in range(K): m.addConstr( quicksum(X[k, i][k, j] for _, j in Fs) - quicksum(X[k, j][k, i] for j, _ in Bs) == images[k][i] - Z[i]) m.addConstr(quicksum(Z[i] for i in range(n)) == 1.0) # Solve the model m.optimize() return m.getAttr(GRB.Attr.ObjVal), [Z[i].X for i in range(n)]
def calculate_ILP_linear(g, params, verbose=True, visualize=False, timelimit=120): # This is a reimplementaiton of the original version of setting up the ILP for microtubule tracking. (as described # in paper) if verbose: print "starting constructing ILP" for key, value in params.__dict__.iteritems(): print key, value model = Model() if timelimit > 0: model.setParam(GRB.Param.TimeLimit, timelimit) variables = {} # Add variables to the model, per edge in the graph one variable for edge in g.nx_graph.edges_iter(data=True): i = edge[0] j = edge[1] dist = edge[2]['distance'] cur_dir_vector = edge[2]['dir_vector'] angle_cost = 0 if params.angle_cost_factor != 0: angle1 = get_angle(g, i, cur_dir_vector) angle2 = get_angle(g, j, cur_dir_vector) angle_cost = (angle1 + angle2) * params.angle_cost_factor variables[i, j] = model.addVar(obj=(dist * params.distance_cost + angle_cost)**1, vtype=GRB.BINARY, name='e' + str(i) + '_' + str(j)) variables[j, i] = variables[i, j] sink_variables = {} selection_cost_variables = {} for node_id in g.nx_graph.nodes_iter(): # Add dummy node (sink), here the costs decide about how expensive it is to open / close a chain sink_variables[node_id] = model.addVar(obj=params.dummy_edge_cost, vtype=GRB.BINARY, name='dummy_%s' % str(node_id)) # Add cost for selecting a candidate (this is uniformly set, # but can potentially exchanged with adaptive costs from underlying pipeline) selection_cost_variables[node_id] = model.addVar( obj=params.selection_cost, vtype=GRB.BINARY, name='selectioncost_%s' % str(node_id)) model.update() # Add consistency constraints for guaranteeing coherent topology # If a candidate is selected, two edge variables should also be selected for node_id in g.nx_graph.nodes_iter(): neighbours = g.nx_graph.neighbors(node_id) model.addConstr( 2 * selection_cost_variables[node_id] - (quicksum(variables[node_id, j] for j in neighbours) + sink_variables[node_id]) <= 0, name='nodeconstraint1_%i' % node_id) model.addConstr( 2 * selection_cost_variables[node_id] - (quicksum(variables[node_id, j] for j in neighbours) + sink_variables[node_id]) >= 0, name='nodeconstraint2_%i' % node_id) # model.addConstr(selection_cost_variables[0] == 1, # name='nodeconstraint3_%i' %node_id) model.update() # If a link is selected, the two incident candidates on this link also need to be selected # The other way round is not true, if a candidate is selected for edge in g.nx_graph.edges_iter(): node_id1 = edge[0] node_id2 = edge[1] model.addConstr( 2 * variables[edge] - selection_cost_variables[node_id1] - selection_cost_variables[node_id2] <= 0, name='edgeconstraint_%i_%i' % edge) model.update() print "Intermediate number of variables before adding combination aspect", model.NumVars if params.pairwise: # Microtubules are rigid. Add cost for bending model, edge_combinations = add_pairwaisefactors_to_model( model, g, params, variables) if params.exclusive_distance: # Too many candidates for the same microtubules cause parallel occurence model = add_proximity_exclusivity(model, g, selection_cost_variables, params.exclusive_distance_threshold) if verbose: print "starting Optimization" print "Number of variables %i" % model.NumVars print "Number of linear constraints %i" % model.NumConstrs # model.display() model.optimize() print 'Obj:', model.ObjVal # Contains a label for each edge solution = model.getAttr("X", variables) if params.pairwise: comb_solution = model.getAttr('X', edge_combinations) check_consistency(comb_solution, solution) new_edgelist = [] for edge, sol in solution.iteritems(): if sol == 1: new_edgelist.append(edge) if visualize: g.visualize(edgelist=new_edgelist, only_edges_from_edgelist=True) mlab.show() # Create new graph from solution nx_skeleton_solution = create_graph_from_solution(g, new_edgelist) nx_skeleton_solution.print_statistics() return nx_skeleton_solution, model
def optimize_traffic_load(n, h, u): # create a model m = Model('traffic load') # create decision variables x = m.addVars(sa, sa, vtype=GRB.BINARY, name='x') y = m.addVars(sa, dc, vtype=GRB.BINARY, name='y') # add constraints # x is symmetric m.addConstrs((x[i, j] == x[j, i] for i in sa for j in sa), 'symmetric constraint') # Two service areas cant use the same stateful functions when x[i,j] = 0 m.addConstrs((y[i, t] + y[j, t] <= x[i, j] + 1 for i in sa for j in sa for t in dc), 'x = 0 constraint') # Two service areas use the same stateful functions when x[i,j] = 1 m.addConstrs(((y[i, t] - y[j, t] <= 1 - x[i, j]) for i in sa for j in sa for t in dc), 'x = 1 constraint') # Each should be at least managed by one dc m.addConstrs((sum(y[i, t] for t in dc) == 1 for i in sa), 'one dc for one sa') # high availability constraint m.addConstr( sum((1 - x[i, j]) for i in sa for j in sa if i != j) >= 1, 'ha') # maximum state transfer frequency m.addConstr( sum(h * (1 - x[i, j]) for i in sa for j in sa if i != j) <= State_max, 'max state transfer constraint') # dc0 will have the most heavy load for t in dc: if t != dc[0]: m.addConstr( sum(y[i, t] * n * (L_sig + u * L_session) for i in sa) <= sum(y[i, dc[0]] * n * (L_sig + u * L_session) for i in sa), 'less than max load') # Objective function # Optimize load on one cloud centers and mandate other centers to be less than m.setObjective(sum(y[i, dc[0]] * n * (L_sig + u * L_session) for i in sa), GRB.MINIMIZE) m.optimize() # check model feasible or not if m.getAttr('status') == GRB.INFEASIBLE: return 'infeasible' # Calculate performance metrics # traffic load on stateful functions traffic_load = sum( getattr(y[i, dc[0]], 'X') * n * (L_sig + u * L_session) for i in sa) # state transfer frequency state_transfer = sum(h * (1 - getattr(x[i, j], 'X')) for i in sa for j in sa if i != j) # number of function num_func = M_dc - sum( prod(1 - getattr(y[i, t], 'X') for i in sa) for t in dc) # total metrics total_metrics = [u, h, u, state_transfer, traffic_load, num_func] # utopia point, nadir point worst_state = state_transfer best_load = traffic_load return total_metrics, worst_state, best_load
def VRPGu(n, K, C, Ps, Ds, d, F, TimeLimit): m = Model() m.setParam(GRB.Param.TimeLimit, TimeLimit) # Create variables x = {} for i in Ps: for j in Ps: if i != j : x[i,j] = m.addVar(obj=F(Ps[i], Ps[j]), vtype=GRB.BINARY, name='x'+str(i)+'_'+str(j)) # Create Miller variables (subtour elimination) u = {} for i in Ds: if i != d: u[i] = m.addVar(obj=0.0, vtype=GRB.CONTINUOUS, lb=Ds[i], ub=C, name='u'+str(i)) m.update() # Add outdegree constraint for j in Ps: if j != d: Ls = list(filter(lambda z: z!=j, Ps)) m.addConstr(quicksum(x[i,j] for i in Ls) == 1) # Add indegree constraint for i in Ps: if i != d: Ls = filter(lambda z: z!=i, Ps) m.addConstr(quicksum(x[i,j] for j in Ls) == 1) # Number of vehicles Ls = list(filter(lambda z: z!=d, Ps)) m.addConstr(quicksum(x[i,d] for i in Ls) <= K) m.addConstr(quicksum(x[d,j] for j in Ls) <= K) m.addConstr(quicksum(x[i,d] for i in Ls) >= 3) m.addConstr(quicksum(x[d,j] for j in Ls) >= 3) # for a,b in [(15,18), (9,22), (19,20), (5,6), (8,22), (7,2), (9,10)]: Fs = [] for i in Ps: if i == a or i == b: for j in Ps: if i != j and j != a and j != b: Fs.append((i,j)) m.addConstr(quicksum(x[i,j] for i,j in Fs) >= 1) for a,b,c in [(5,6,9), (10,11,14)]: Fs = [] for i in Ps: if i == a or i == b or i == c: for j in Ps: if i != j and j != a and j != b and j != c: Fs.append((i,j)) m.addConstr(quicksum(x[i,j] for i,j in Fs) >= 2) # for a,b in [(15,18), (9,22), (19,20), (5,6), (8,22), (7,2)]: # m.addConstr(x[a,b] + x[b,a] <= 1) m.update() # Solve the model m.optimize() solution = m.getAttr('x', x) selected = [(i,j) for (i,j) in solution if solution[i,j] > 0.5] # Xs = [p for p in Ps.values()] # Ws = [w for w in Ds.values()] # for i,j in selected: # DisegnaSegmento(Ps[i], Ps[j]) # plt.scatter([i for i,j in Xs[1:]], [j for i,j in Xs[1:]], # s=Ws[1:], alpha=0.3, cmap='viridis') # plt.plot([Xs[0][0]], [Xs[0][1]], marker='s', color='red', alpha=0.5) # plt.axis('square') # plt.axis('off') return m.objVal, selected
for j in range(n): m.addConstr((ct[p, k - 1] + pt[j] - ct[p, k]) <= 0) m.update() for p in range(p_max): for k in range(K): for j in range(n): m.addConstr((ct[p, k] - dt[j] - M * (1 - vars[j, p, k]) - ta[j]) <= 0) m.update() # Optimize model m._vars = vars m.params.LazyConstraints = 1 m.optimize(add_ct) solution = m.getAttr('x', vars) selected = [(j, p, k) for p in range(p_max) for k in range(K) for j in range(n) if solution[j, p, k] > 0.5] # assert len(subtour(selected)) == n print('Optimal cost: %g' % m.objVal) jobs = [] # sd_p = [0] * p_max for p in range(p_max): jobs.append(Picker(p, batches=[])) ans = {} for j, p, k in selected: ans[p, k] = [] for j, p, k in selected: ans[p, k].append(list(df_orders.index)[j]) l = 0
# vars = tupledict() # for i,j in dist.keys(): # vars[i,j] = m.addVar(obj=dist[i,j], vtype=GRB.BINARY, # name='e[%d,%d]'%(i,j)) # Add degree-2 constraint m.addConstrs(vars.sum(i, '*') == 2 for i in range(n)) # Using Python looping constructs, the preceding would be... # # for i in range(n): # m.addConstr(sum(vars[i,j] for j in range(n)) == 2) # Optimize model m._vars = vars m.Params.lazyConstraints = 1 m.optimize(subtourelim) vals = m.getAttr('x', vars) selected = tuplelist((i, j) for i, j in vals.keys() if vals[i, j] > 0.5) tour = subtour(selected) assert len(tour) == n print('') print('Optimal tour: %s' % str(tour)) print('Optimal cost: %g' % m.objVal) print('')
def generate_multi_dim_sample(bounds, directory, num_teams, num_md_per_cycle, numSam, numCycle, theoretical): # the list of sample dimensions, the +1 cycle = list(range(numCycle)) day = list(range(num_md_per_cycle)) days = list(range(num_md_per_cycle + 1)) home = away = list(range(num_teams)) constrList = [ [(0, ), (1, )], [(0, ), (2, )], [(0, ), (3, )], [(0, ), (1, 2)], [(0, ), (1, 3)], [(0, ), (2, 3)], [(0, ), (1, 2, 3)], [(1, ), (0, )], [(1, ), (2, )], [(1, ), (3, )], [(1, ), (0, 2)], [(1, ), (0, 3)], [(1, ), (2, 3)], [(1, ), (0, 2, 3)], [(2, ), (0, )], [(2, ), (1, )], [(2, ), (3, )], [(2, ), (0, 1)], [(2, ), (0, 3)], [(2, ), (1, 3)], [(2, ), (0, 1, 3)], [(3, ), (0, )], [(3, ), (1, )], [(3, ), (2, )], [(3, ), (0, 1)], [(3, ), (0, 2)], [(3, ), (1, 2)], [(3, ), (0, 1, 2)], [(0, 1), (2, )], [(0, 1), (3, )], [(0, 1), (2, 3)], # cons away = 31 [(0, 2), (1, )], [(0, 2), (3, )], [(0, 2), (1, 3)], # cons home = 34 [(0, 3), (1, )], [(0, 3), (2, )], [(0, 3), (1, 2)], [(1, 2), (0, )], [(1, 2), (3, )], [(1, 2), (0, 3)], [(1, 3), (0, )], [(1, 3), (2, )], [(1, 3), (0, 2)], [(2, 3), (0, )], [(2, 3), (1, )], [(2, 3), (0, 1)], [(0, 1, 2), (3, )], [(0, 1, 3), (2, )], [(0, 2, 3), (1, )], [(1, 2, 3), (0, )] ] try: model = Model("sspSolver") # give verbose logging when 1, otherwise 0 model.setParam(GRB.param.OutputFlag, 1) ### Decision Variables ### # 0 = cycles, 1 = days, 2 = away, 3 = home # regular combinations over the 4 dimensions x = model.addVars(cycle, day, home, away, vtype=GRB.BINARY, name="base") n = model.addVars(cycle, day, home, vtype=GRB.BINARY, name="n") o = model.addVars(cycle, day, away, vtype=GRB.BINARY, name="o") p = model.addVars(cycle, home, away, vtype=GRB.BINARY, name="p") q = model.addVars(day, home, away, vtype=GRB.BINARY, name="q") r = model.addVars(cycle, day, vtype=GRB.BINARY, name="r") s = model.addVars(cycle, home, vtype=GRB.BINARY, name="s") t = model.addVars(cycle, away, vtype=GRB.BINARY, name="t") u = model.addVars(day, home, vtype=GRB.BINARY, name="u") v = model.addVars(day, away, vtype=GRB.BINARY, name="v") w = model.addVars(home, away, vtype=GRB.BINARY, name="w") #y = model.addVars(cycle, day, home, away, vtype=GRB.BINARY, name="basetrans") #yn = model.addVars(cycle, day, home, vtype=GRB.BINARY, name="trans_n") cNA = model.addVars(cycle, day, day, away, vtype=GRB.BINARY, name="cons") cNAs = model.addVars(cycle, days, day, away, vtype=GRB.BINARY, name="cons_min") cNH = model.addVars(cycle, day, day, home, vtype=GRB.BINARY, name="consHome") cNHs = model.addVars(cycle, days, day, home, vtype=GRB.BINARY, name="consHomes") cZy = model.addVars(cycle, day, day, home, vtype=GRB.BINARY, name="days_betw_games") cZys = model.addVars(cycle, days, day, home, vtype=GRB.BINARY, name="days_btw_gamess") # transpose function #model.addConstrs( # y[c, d, h, a] == x[c, d, h, a] + x[c, d, a, h] for c in cycle for d in day for a in away for h in home) #model.addConstrs((y.sum(c, d, h, '*') == yn[c, d, h] for c in cycle for d in day for h in home), "yn_y") model.addConstrs((x.sum(c, d, '*', a) == o[c, d, a] for c in cycle for d in day for a in away), "xo") model.addConstrs((x.sum(c, d, h, '*') == n[c, d, h] for c in cycle for d in day for h in home), "xn") model.addConstrs((x.sum(c, '*', h, a) == p[c, h, a] for c in cycle for h in home for a in away), "xp") model.addConstrs((x.sum('*', d, h, a) == q[d, h, a] for d in day for h in home for a in away), "xq") model.addConstrs( (r[c, d] <= n.sum(c, d, '*') for c in cycle for d in day), "rn") model.addConstrs( (t[c, a] <= n.sum(c, '*', a) for c in cycle for a in away), "tn") model.addConstrs( (v[d, a] <= n.sum('*', d, a) for d in day for a in away), "vn") model.addConstrs( (r[c, d] <= o.sum(c, d, '*') for c in cycle for d in day), "ro") model.addConstrs( (s[c, h] <= o.sum(c, '*', h) for c in cycle for h in home), "so") model.addConstrs( (u[d, h] <= o.sum('*', d, h) for d in day for h in home), "uo") model.addConstrs( (s[c, h] <= p.sum(c, h, '*') for c in cycle for h in home), "sp") model.addConstrs( (t[c, a] <= p.sum(c, '*', a) for c in cycle for a in away), "tp") model.addConstrs( (w[h, a] <= p.sum('*', h, a) for h in home for a in away), "wp") model.addConstrs( (u[d, h] <= q.sum(d, h, '*') for d in day for h in home), "uq") model.addConstrs( (v[d, a] <= q.sum(d, '*', a) for d in day for a in away), "vq") model.addConstrs( (w[h, a] <= q.sum('*', h, a) for h in home for a in away), "wq") if theoretical: ### Hard constraints -- not yet in bounds ### # never play yourself model.addConstrs(x[c, d, i, i] == 0 for c in cycle for d in day for i in home) # only play one game per day model.addConstrs((x.sum(c, d, i, '*') + x.sum(c, d, '*', i) <= 1 for c in cycle for d in day for i in home), "1gamePerDay") # Hard constraints from bounds files ### # bounds 0 = countLowerbound # bounds 1 = countUpperBound # bounds 2 = minConsZero # bounds 3 = maxConsZero # bounds 4 = minConsNonZero # bounds 5 = maxConsNonZero for i in range(len(bounds)): ### SEED COUNT BOUNDS: bounds[i,0] is the lowerbound, bounds[i,1] is the upperbound if bounds[i, 0] > 0: # this part covers count lowerbound if constrList[i] == [(0, ), (1, )]: model.addConstrs((r.sum(c, '*') >= bounds[i, 0] for c in cycle), "LWR_constr-(0,), (1,)") elif constrList[i] == [(0, ), (2, )]: model.addConstrs((t.sum(c, '*') >= bounds[i, 0] for c in cycle), "LWR_constr-(0,), (2,)") elif constrList[i] == [(0, ), (3, )]: model.addConstrs((s.sum(c, '*') >= bounds[i, 0] for c in cycle), "LWR_constr-(0,), (3,)") elif constrList[i] == [(0, ), (1, 2)]: model.addConstrs( (o.sum(c, '*', '*') >= bounds[i, 0] for c in cycle), "LWR_constr-(0,), (1,2)") elif constrList[i] == [(0, ), (1, 3)]: model.addConstrs( (n.sum(c, '*', '*') >= bounds[i, 0] for c in cycle), "LWR_constr-(0,), (1,3)") elif constrList[i] == [(0, ), (2, 3)]: model.addConstrs( (p.sum(c, '*', '*') >= bounds[i, 0] for c in cycle), "LWR_constr-(0,), (2,3)") elif constrList[i] == [(0, ), (1, 2, 3)]: model.addConstrs((x.sum(c, '*', '*', '*') >= bounds[i, 0] for c in cycle), "LWR_constr-(0,), (1,2,3)") elif constrList[i] == [(1, ), (0, )]: model.addConstrs((r.sum('*', d) >= bounds[i, 0] for d in day), "LWR_constr-(1,), (0,)") elif constrList[i] == [(1, ), (2, )]: model.addConstrs((v.sum(d, '*') >= bounds[i, 0] for d in day), "LWR_constr-(1,), (2,)") elif constrList[i] == [(1, ), (3, )]: model.addConstrs((u.sum(d, '*') >= bounds[i, 0] for d in day), "LWR_constr-(1,), (3,)") elif constrList[i] == [(1, ), (0, 2)]: model.addConstrs((o.sum('*', d, '*') >= bounds[i, 0] for d in day), "LWR_constr-(1,), (0,2)") elif constrList[i] == [(1, ), (0, 3)]: model.addConstrs((n.sum('*', d, '*') >= bounds[i, 0] for d in day), "LWR_constr-(1,), (0,3)") elif constrList[i] == [(1, ), (2, 3)]: model.addConstrs((q.sum(d, '*', '*') >= bounds[i, 0] for d in day), "LWR_constr-(1,), (2,3)") elif constrList[i] == [(1, ), (0, 2, 3)]: model.addConstrs( (x.sum('*', d, '*', '*') >= bounds[i, 0] for d in day), "LWR_constr-(1,), (0,2,3)") elif constrList[i] == [(2, ), (0, )]: model.addConstrs((t.sum('*', h) >= bounds[i, 0] for h in home), "LWR_constr-(2,), (0,)") elif constrList[i] == [(2, ), (1, )]: model.addConstrs((v.sum('*', h) >= bounds[i, 0] for h in home), "LWR_constr-(2,), (1,)") elif constrList[i] == [(2, ), (3, )]: model.addConstrs((w.sum(h, '*') >= bounds[i, 0] for h in home), "LWR_constr--(2,), (3,)") elif constrList[i] == [(2, ), (0, 1)]: model.addConstrs( (o.sum('*', '*', h) >= bounds[i, 0] for h in home), "LWR_constr--(2,), (0,1)") elif constrList[i] == [(2, ), (0, 3)]: model.addConstrs( (p.sum('*', h, '*') >= bounds[i, 0] for h in home), "LWR_constr--(2,), (0,3)") elif constrList[i] == [(2, ), (1, 3)]: model.addConstrs((q.sum('*', h, '*') >= bounds[i, 0] for h in home), "LWR_constr-(2,), (1,3)") elif constrList[i] == [(2, ), (0, 1, 3)]: model.addConstrs((x.sum('*', '*', h, '*') >= bounds[i, 0] for h in home), "LWR_constr-(2,), (0,1,3)") elif constrList[i] == [(3, ), (0, )]: model.addConstrs((s.sum('*', a) >= bounds[i, 0] for a in away), "LWR_constr-(3,), (0,)") elif constrList[i] == [(3, ), (1, )]: model.addConstrs((u.sum('*', a) >= bounds[i, 0] for a in away), "LWR_constr-(3,), (1,)") elif constrList[i] == [(3, ), (2, )]: model.addConstrs((w.sum('*', a) >= bounds[i, 0] for a in away), "LWR_constr-(3,), (2,)") elif constrList[i] == [(3, ), (0, 1)]: model.addConstrs((n.sum('*', '*', a) >= bounds[i, 0] for a in away), "LWR_constr-(3,), (0,1)") elif constrList[i] == [(3, ), (0, 2)]: model.addConstrs((p.sum('*', '*', a) >= bounds[i, 0] for a in away), "LWR_constr-(3,), (0,2)") elif constrList[i] == [(3, ), (1, 2)]: model.addConstrs((q.sum('*', '*', a) >= bounds[i, 0] for a in away), "LWR_constr-(3,), (1,2)") elif constrList[i] == [(3, ), (0, 1, 2)]: model.addConstrs((x.sum('*', '*', '*', a) >= bounds[i, 0] for a in away), "LWR_constr-(3,), (0,1,2)") elif constrList[i] == [(0, 1), (2, )]: model.addConstrs((o.sum(c, d, '*') >= bounds[i, 0] for c in cycle for d in day), "LWR_constr-(0,1), (2,)") elif constrList[i] == [(0, 1), (3, )]: model.addConstrs((n.sum(c, d, '*') >= bounds[i, 0] for c in cycle for d in day), "LWR_constr-(0,1), (3,)") elif constrList[i] == [(0, 1), (2, 3)]: model.addConstrs((x.sum(c, d, '*', '*') >= bounds[i, 0] for c in cycle for d in day), "LWR_constr-(0,1), (2,3)") elif constrList[i] == [(0, 2), (1, )]: bound = bounds[i, 0] model.addConstrs((o.sum(c, '*', a) >= bounds[i, 0] for c in cycle for a in away), "LWR_constr-(0,2), (1,)") elif constrList[i] == [(0, 2), (3, )]: model.addConstrs((p.sum(c, '*', a) >= bounds[i, 0] for c in cycle for a in away), "LWR_constr-(0,2), (3,)") elif constrList[i] == [(0, 2), (1, 3)]: model.addConstrs((x.sum(c, '*', a) >= bounds[i, 0] for c in cycle for a in away), "LWR_constr-(0,2), (1,3)") elif constrList[i] == [(0, 3), (1, )]: model.addConstrs((n.sum(c, '*', h) >= bounds[i, 0] for c in cycle for h in home), "LWR_constr-(0,3), (1,)") elif constrList[i] == [(0, 3), (2, )]: model.addConstrs((p.sum(c, '*', h) >= bounds[i, 0] for c in cycle for h in home), "LWR_constr-(0,3), (2,)") elif constrList[i] == [(0, 3), (1, 2)]: model.addConstrs((x.sum(c, '*', '*', h) >= bounds[i, 0] for c in cycle for h in home), "LWR_constr-(0,3), (1,2)") elif constrList[i] == [(1, 2), (0, )]: model.addConstrs((o.sum('*', d, a) >= bounds[i, 0] for d in day for a in away), "LWR_constr-(1,2), (0,)") elif constrList[i] == [(1, 2), (3, )]: model.addConstrs((q.sum(d, a, '*') >= bounds[i, 0] for d in day for a in away), "LWR_constr-(1,2), (3,)") elif constrList[i] == [(1, 2), (0, 3)]: model.addConstrs((x.sum('*', d, a, '*') >= bounds[i, 0] for d in day for a in away), "LWR_constr-(1,2), (0,3)") elif constrList[i] == [(1, 3), (0, )]: model.addConstrs((n.sum('*', d, h) >= bounds[i, 0] for d in day for h in home), "LWR_constr-(1,3), (0,)") elif constrList[i] == [(1, 3), (2, )]: model.addConstrs((q.sum(d, '*', h) >= bounds[i, 0] for d in day for h in home), "LWR_constr-(1,3), (2,)") elif constrList[i] == [(1, 3), (0, 2)]: model.addConstrs((x.sum('*', d, '*', h) >= bounds[i, 0] for d in day for h in home), "LWR_constr-(1,3), (0,2)") elif constrList[i] == [(2, 3), (0, )]: model.addConstrs((p.sum('*', h, a) >= bounds[i, 0] for h in home for a in away), "LWR_constr-(2,3), (0,)") elif constrList[i] == [(2, 3), (1, )]: model.addConstrs((q.sum('*', h, a) >= bounds[i, 0] for h in home for a in away), "LWR_constr-(2,3), (1,)") elif constrList[i] == [(2, 3), (0, 1)]: model.addConstrs((x.sum('*', '*', h, a) >= bounds[i, 0] for h in home for a in away), "LWR_constr-(2,3), (0,1)") elif constrList[i] == [(0, 1, 2), (3, )]: model.addConstrs((x.sum(c, d, a, '*') >= bounds[i, 0] for c in cycle for d in day for a in away), "LWR_constr-(0,1,2), (3,)") elif constrList[i] == [(0, 1, 3), (2, )]: model.addConstrs((x.sum(c, d, '*', h) >= bounds[i, 0] for c in cycle for d in day for h in home), "LWR_constr-(0,1,3), (2,)") elif constrList[i] == [(0, 2, 3), (1, )]: model.addConstrs((x.sum(c, '*', a, h) >= bounds[i, 0] for c in cycle for a in away for h in home), "LWR_constr-(0,2,3), (1,)") elif constrList[i] == [(1, 2, 3), (0, )]: model.addConstrs((x.sum('*', d, a, h) >= bounds[i, 0] for d in day for a in away for h in home), "LWR_constr-(1,2,3), (0,)") if bounds[i, 1] > 0: # this part covers count lowerbound if constrList[i] == [(0, ), (1, )]: model.addConstrs((r.sum(c, '*') <= bounds[i, 1] for c in cycle), "constr-(0,), (1,)") elif constrList[i] == [(0, ), (2, )]: model.addConstrs((t.sum(c, '*') <= bounds[i, 1] for c in cycle), "constr-(0,), (2,)") elif constrList[i] == [(0, ), (3, )]: model.addConstrs((s.sum(c, '*') <= bounds[i, 1] for c in cycle), "constr-(0,), (3,)") elif constrList[i] == [(0, ), (1, 2)]: model.addConstrs((o.sum(c, '*', '*') <= bounds[i, 1] for c in cycle), "constr-(0,), (1,2)") elif constrList[i] == [(0, ), (1, 3)]: model.addConstrs((n.sum(c, '*', '*') <= bounds[i, 1] for c in cycle), "constr-(0,), (1,3)") elif constrList[i] == [(0, ), (2, 3)]: model.addConstrs((p.sum(c, '*', '*') <= bounds[i, 1] for c in cycle), "constr-(0,), (2,3)") elif constrList[i] == [(0, ), (1, 2, 3)]: model.addConstrs((x.sum(c, '*', '*', '*') <= bounds[i, 1] for c in cycle), "constr-(0,), (1,2,3)") elif constrList[i] == [(1, ), (0, )]: model.addConstrs((r.sum('*', d) <= bounds[i, 1] for d in day), "LWR_constr-(1,), (0,)") elif constrList[i] == [(1, ), (2, )]: model.addConstrs((v.sum(d, '*') <= bounds[i, 1] for d in day), "LWR_constr-(1,), (2,)") elif constrList[i] == [(1, ), (3, )]: model.addConstrs((u.sum(d, '*') <= bounds[i, 1] for d in day), "LWR_constr-(1,), (3,)") elif constrList[i] == [(1, ), (0, 2)]: model.addConstrs((o.sum('*', d, '*') <= bounds[i, 1] for d in day), "LWR_constr-(1,), (0,2)") elif constrList[i] == [(1, ), (0, 3)]: model.addConstrs((n.sum('*', d, '*') <= bounds[i, 1] for d in day), "LWR_constr-(1,), (0,3)") elif constrList[i] == [(1, ), (2, 3)]: model.addConstrs((q.sum(d, '*', '*') <= bounds[i, 1] for d in day), "LWR_constr-(1,), (2,3)") elif constrList[i] == [(1, ), (0, 2, 3)]: model.addConstrs( (x.sum('*', d, '*', '*') <= bounds[i, 1] for d in day), "LWR_constr-(1,), (0,2,3)") elif constrList[i] == [(2, ), (0, )]: model.addConstrs((t.sum('*', h) <= bounds[i, 1] for h in home), "constr-(2,), (0,)") elif constrList[i] == [(2, ), (1, )]: model.addConstrs((v.sum('*', h) <= bounds[i, 1] for h in home), "constr-(2,), (1,)") elif constrList[i] == [(2, ), (3, )]: model.addConstrs((w.sum(h, '*') <= bounds[i, 1] for h in home), "constr--(2,), (3,)") elif constrList[i] == [(2, ), (0, 1)]: model.addConstrs((o.sum('*', '*', h) <= bounds[i, 1] for h in home), "constr--(2,), (0,1)") elif constrList[i] == [(2, ), (0, 3)]: model.addConstrs((p.sum('*', h, '*') <= bounds[i, 1] for h in home), "constr--(2,), (0,3)") elif constrList[i] == [(2, ), (1, 3)]: model.addConstrs((q.sum('*', h, '*') <= bounds[i, 1] for h in home), "constr-(2,), (1,3)") elif constrList[i] == [(2, ), (0, 1, 3)]: model.addConstrs((x.sum('*', '*', h, '*') <= bounds[i, 1] for h in home), "LWR_constr-(2,), (0,1,3)") elif constrList[i] == [(3, ), (0, )]: model.addConstrs((s.sum('*', a) <= bounds[i, 1] for a in away), "constr-(3,), (0,)") elif constrList[i] == [(3, ), (1, )]: model.addConstrs((u.sum('*', a) <= bounds[i, 1] for a in away), "constr-(3,), (1,)") elif constrList[i] == [(3, ), (2, )]: model.addConstrs((w.sum('*', a) <= bounds[i, 1] for a in away), "constr-(3,), (2,)") elif constrList[i] == [(3, ), (0, 1)]: model.addConstrs((n.sum('*', '*', a) <= bounds[i, 1] for a in away), "constr-(3,), (0,1)") elif constrList[i] == [(3, ), (0, 2)]: model.addConstrs((p.sum('*', '*', a) <= bounds[i, 1] for a in away), "constr-(3,), (0,2)") elif constrList[i] == [(3, ), (1, 2)]: model.addConstrs((q.sum('*', '*', a) <= bounds[i, 1] for a in away), "constr-(3,), (1,2)") elif constrList[i] == [(3, ), (0, 1, 2)]: model.addConstrs((x.sum('*', '*', '*', a) <= bounds[i, 1] for a in away), "constr-(3,), (0,1,2)") elif constrList[i] == [(0, 1), (2, )]: model.addConstrs((o.sum(c, d, '*') <= bounds[i, 1] for c in cycle for d in day), "constr-(0,1), (2,)") elif constrList[i] == [(0, 1), (3, )]: model.addConstrs((n.sum(c, d, '*') <= bounds[i, 1] for c in cycle for d in day), "constr-(0,1), (3,)") elif constrList[i] == [(0, 1), (2, 3)]: model.addConstrs((x.sum(c, d, '*', '*') <= bounds[i, 1] for c in cycle for d in day), "constr-(0,1), (2,3)") elif constrList[i] == [(0, 2), (1, )]: model.addConstrs((o.sum(c, '*', a) <= bounds[i, 1] for c in cycle for a in away), "constr-(0,2), (1,)") elif constrList[i] == [(0, 2), (3, )]: model.addConstrs((p.sum(c, '*', a) <= bounds[i, 1] for c in cycle for a in away), "constr-(0,2), (3,)") elif constrList[i] == [(0, 2), (1, 3)]: model.addConstrs((x.sum(c, '*', a) <= bounds[i, 1] for c in cycle for a in away), "constr-(0,2), (1,3)") elif constrList[i] == [(0, 3), (1, )]: model.addConstrs((n.sum(c, '*', h) <= bounds[i, 1] for c in cycle for h in home), "constr-(0,3), (1,)") elif constrList[i] == [(0, 3), (2, )]: model.addConstrs((p.sum(c, '*', h) <= bounds[i, 1] for c in cycle for h in home), "constr-(0,3), (2,)") elif constrList[i] == [(0, 3), (1, 2)]: model.addConstrs((x.sum(c, '*', '*', h) <= bounds[i, 1] for c in cycle for h in home), "constr-(0,3), (1,2)") elif constrList[i] == [(1, 2), (0, )]: model.addConstrs((o.sum('*', d, a) <= bounds[i, 1] for d in day for a in away), "constr-(1,2), (0,)") elif constrList[i] == [(1, 2), (3, )]: model.addConstrs((q.sum(d, a, '*') <= bounds[i, 1] for d in day for a in away), "constr-(1,2), (3,)") elif constrList[i] == [(1, 2), (0, 3)]: model.addConstrs((x.sum('*', d, a, '*') <= bounds[i, 1] for d in day for a in away), "constr-(1,2), (0,3)") elif constrList[i] == [(1, 3), (0, )]: model.addConstrs((n.sum('*', d, h) <= bounds[i, 1] for d in day for h in home), "constr-(1,3), (0,)") elif constrList[i] == [(1, 3), (2, )]: model.addConstrs((q.sum(d, '*', h) <= bounds[i, 1] for d in day for h in home), "constr-(1,3), (2,)") elif constrList[i] == [(1, 3), (0, 2)]: model.addConstrs((x.sum('*', d, '*', h) <= bounds[i, 1] for d in day for h in home), "constr-(1,3), (0,2)") elif constrList[i] == [(2, 3), (0, )]: model.addConstrs((p.sum('*', h, a) <= bounds[i, 1] for h in home for a in away), "constr-(2,3), (0,)") elif constrList[i] == [(2, 3), (1, )]: model.addConstrs((q.sum('*', h, a) <= bounds[i, 1] for h in home for a in away), "constr-(2,3), (1,)") elif constrList[i] == [(2, 3), (0, 1)]: model.addConstrs((x.sum('*', '*', h, a) <= bounds[i, 1] for h in home for a in away), "constr-(2,3), (0,1)") elif constrList[i] == [(0, 1, 2), (3, )]: model.addConstrs((x.sum(c, d, a, '*') <= bounds[i, 1] for c in cycle for d in day for a in away), "constr-(0,1,2), (3,)") elif constrList[i] == [(0, 1, 3), (2, )]: model.addConstrs((x.sum(c, d, '*', h) <= bounds[i, 1] for c in cycle for d in day for h in home), "constr-(0,1,3), (2,)") elif constrList[i] == [(0, 2, 3), (1, )]: model.addConstrs((x.sum(c, '*', a, h) <= bounds[i, 1] for c in cycle for a in away for h in home), "constr-(0,2,3), (1,)") elif constrList[i] == [(1, 2, 3), (0, )]: model.addConstrs((x.sum('*', d, a, h) <= bounds[i, 1] for d in day for a in away for h in home), "constr-(1,2,3), (0,)") if bounds[34, 5] + bounds[34, 4] > 0: # definition for the first day model.addConstrs((cNH[c, 0, 0, h] == n[c, 0, h] for c in cycle for h in home), "cNH1") model.addConstrs((cNH[c, d1 + 1, 0, h] <= n[c, d1 + 1, h] for c in cycle for h in home for d1 in day if d1 < len(day) - 1), "cNA2") model.addConstrs((cNH[c, d1 + 1, 0, h] <= 1 - n[c, d1, h] for c in cycle for h in home for d1 in day if d1 < len(day) - 1), "cNA3") model.addConstrs( (cNH[c, d1 + 1, 0, h] >= n[c, d1 + 1, h] - n[c, d1, h] for c in cycle for d1 in day for h in home if d1 < len(day) - 1), "cNA4") # # definition for the second day and the third, fourth, etc... model.addConstrs((cNH[c, 0, d2, h] == 0 for c in cycle for d2 in day for h in home if d2 > 0), "2cNA1") model.addConstrs((cNH[c, d1, d2, h] <= cNH[c, d1 - 1, d2 - 1, h] for c in cycle for h in home for d1 in day for d2 in day if d1 > 0 if d2 > 0)) model.addConstrs((cNH[c, d1, d2, h] <= n[c, d1, h] for c in cycle for d1 in day for d2 in day for h in home if d1 > 0 if d2 > 0)) model.addConstrs((cNH[c, d1, d2, h] >= n[c, d1, h] + cNH[c, d1 - 1, d2 - 1, h] - 1 for c in cycle for d1 in day for d2 in day for h in home if d1 > 0 if d2 > 0)) if bounds[34, 5] > 0: model.addConstr((quicksum( cNH[c, d1, d2, a] for c in cycle for d1 in day for a in away for d2 in range(bounds[34, 5].astype(int), len(day))) == 0), "cnASum") if bounds[34, 4] > 0: model.addConstrs((cNHs[c, 0, d2, h] == 0 for c in cycle for d2 in day for h in home), "minConsPlay") model.addConstrs((cNHs[c, d1, d2, h] <= cNH[c, d1 - 1, d2, h] for c in cycle for h in home for d1 in day for d2 in day if d1 > 0)) model.addConstrs((cNHs[c, d1, d2, h] <= 1 - n[c, d1, h] for c in cycle for d1 in day for d2 in day for h in home if d1 > 0)) model.addConstrs( (cNHs[c, d1, d2, h] >= cNH[c, d1 - 1, d2, h] - n[c, d1, h] for c in cycle for d1 in day for d2 in day for h in home if d1 > 0)) model.addConstrs((cNHs[c, num_md_per_cycle, d2, h] >= cNH[c, num_md_per_cycle - 1, d2, h] for c in cycle for d2 in day for h in home)) model.addConstr((quicksum( cNHs[c, d1, d2, a] * (bounds[34, 4] - 1 - d2) for c in cycle for a in away for d1 in days for d2 in range(bounds[34, 4].astype(int) - 1)) == 0)) if bounds[31, 5] + bounds[31, 4] > 0: # definition for the first day model.addConstrs((cNA[c, 0, 0, a] == o[c, 0, a] for c in cycle for a in away), "cNA1") model.addConstrs((cNA[c, d1 + 1, 0, a] <= o[c, d1 + 1, a] for c in cycle for a in away for d1 in day if d1 < len(day) - 1), "cNA2") model.addConstrs((cNA[c, d1 + 1, 0, a] <= 1 - o[c, d1, a] for c in cycle for a in away for d1 in day if d1 < len(day) - 1), "cNA3") model.addConstrs( (cNA[c, d1 + 1, 0, a] >= o[c, d1 + 1, a] - o[c, d1, a] for c in cycle for d1 in day for a in away if d1 < len(day) - 1), "cNA4") # # definition for the second day and the third, fourth, etc... model.addConstrs((cNA[c, 0, d2, a] == 0 for c in cycle for d2 in day for a in away if d2 > 0), "2cNA1") model.addConstrs((cNA[c, d1, d2, a] <= cNA[c, d1 - 1, d2 - 1, a] for c in cycle for a in away for d1 in day for d2 in day if d1 > 0 if d2 > 0)) model.addConstrs((cNA[c, d1, d2, a] <= o[c, d1, a] for c in cycle for d1 in day for d2 in day for a in away if d1 > 0 if d2 > 0)) model.addConstrs((cNA[c, d1, d2, a] >= o[c, d1, a] + cNA[c, d1 - 1, d2 - 1, a] - 1 for c in cycle for d1 in day for d2 in day for a in away if d1 > 0 if d2 > 0)) if bounds[31, 5] > 0: model.addConstr((quicksum( cNA[c, d1, d2, a] for c in cycle for d1 in day for a in away for d2 in range(bounds[31, 5].astype(int), len(day))) == 0), "cnASum") if bounds[31, 4] > 0: model.addConstrs((cNAs[c, 0, d2, a] == 0 for c in cycle for d2 in day for a in away), "minConsPlay") model.addConstrs((cNAs[c, d1, d2, a] <= cNA[c, d1 - 1, d2, a] for c in cycle for a in away for d1 in day for d2 in day if d1 > 0)) model.addConstrs((cNAs[c, d1, d2, a] <= 1 - o[c, d1, a] for c in cycle for d1 in day for d2 in day for a in away if d1 > 0)) model.addConstrs( (cNAs[c, d1, d2, a] >= cNA[c, d1 - 1, d2, a] - o[c, d1, a] for c in cycle for d1 in day for d2 in day for a in away if d1 > 0)) model.addConstrs((cNAs[c, num_md_per_cycle, d2, a] >= cNA[c, num_md_per_cycle - 1, d2, a] for c in cycle for d2 in day for a in away)) model.addConstr((quicksum( cNAs[c, d1, d2, a] * (bounds[31, 4] - 1 - d2) for c in cycle for a in away for d1 in days for d2 in range(bounds[31, 4].astype(int) - 1)) == 0)) # Sets the number of solutions to be generated model.setParam(GRB.Param.PoolSolutions, numSam) # grab the most optimal solutions model.setParam(GRB.Param.PoolSearchMode, 2) model.optimize() numSol = model.SolCount print("Number of solutions found for the model: " + str(numSol)) if model.status == GRB.Status.INFEASIBLE: model.computeIIS() print("Following constraints are infeasible: ") for c in model.getConstrs(): if c.IISConstr: print(c.constrName) if model.status == GRB.Status.OPTIMAL: model.write('m.sol') for i in range(numSol): model.setParam(GRB.Param.SolutionNumber, i) # get value from subobtimal MIP sol (might change this in X if we dont do soft constraints) solution = model.getAttr('xn', x) tmp = np.zeros([numCycle, num_md_per_cycle, num_teams, num_teams]) for key in solution: tmp[key] = round(solution[key]) tmp_sol = tmp.astype(np.int64) with open(os.path.join(directory, "sol" + str(i) + ".csv"), "w+", newline='') as sol_csv: csv_writer = csv.writer(sol_csv, delimiter=',') # writes cycle row row = [''] for c in range(numCycle): row.extend(['C' + str(c)] * num_md_per_cycle * num_teams) csv_writer.writerow(row) # writes round row row = [''] for c in range(numCycle): for d in range(num_md_per_cycle): row.extend(['R' + str(d)] * num_teams) csv_writer.writerow(row) # writes awayteam row row = [''] for c in range(numCycle): for d in range(num_md_per_cycle): for t in range(num_teams): row.append('T' + str(t)) csv_writer.writerow(row) # write the actual solution per team tmp_sol.astype(int) for t in range(num_teams): row = ['T' + str(t)] for c in range(numCycle): for r in range(num_md_per_cycle): for team in range(num_teams): row.append(tmp_sol[c][r][t][team]) csv_writer.writerow(row) except GurobiError as e: raise e
for i, j in arcs: x[i, j] = m.addVar(obj=cost[i, j], vtype='B', name='x_%s%s' % (i, j)) N = len(nodes) for i in nodes: if i != nodes[N - 1]: u[i] = m.addVar(obj=0, name='u_%s' % i) m.update() for j in nodes: m.addConstr( quicksum(x[i, j] for i in nodes if i != j) == 1, 'incom_%s' % (j)) for i in nodes: m.addConstr( quicksum(x[i, j] for j in nodes if i != j) == 1, 'outgo_%s' % (i)) for i, j in arcs: if i != nodes[N - 1] and j != nodes[N - 1]: m.addConstr(u[i] - u[j] + N * x[i, j] <= N - 1, 'subtour_%s_%s' % (i, j)) m.optimize() if m.status == GRB.Status.OPTIMAL: print 'objective: %f' % m.ObjVal solution = m.getAttr('x', x) for i, j in arcs: if solution[i, j] > 0: print('%s -> %s: %g' % (i, j, solution[i, j]))
class PathBackup(object): """ Class object for normal-based backup network model. Parameters ---------- nodes: set of nodes links: set of links paths: set of paths in the graph Psd: set of backup paths for link (s,d). Pij: set of (s,d) paths that use link (i,j). capacity: capacities per link based based on random failures mean: mean for failure random variable std: standard deviation for failure random variable invstd: inverse of Phi-normal distribution for (1-epsilon) Returns ------- solution: set of capacity assigned per backup link. """ # Private model object __model = [] # Private model variables __BackupCapacity = {} __bPath = {} # Private model parameters __links = [] __paths = [] __nodes = [] __capacity = [] __mean = [] __std = [] __Psd = [] __Pij = [] __invstd = 1 def __init__(self,nodes,links,paths,Psd,Pij,capacity,mean,std,invstd): ''' Constructor ''' self.__links = links self.__nodes = nodes self.__paths = paths self.__capacity = capacity self.__mean = mean self.__std = std self.__invstd = invstd self.__Psd = Psd self.__Pij = Pij self.__loadModel() def __loadModel(self): # Create optimization model self.__model = Model('PathBackup') # Auxiliary variables for SOCP reformulation U = {} R = {} # Create variables for i,j in self.__links: self.__BackupCapacity[i,j] = self.__model.addVar(lb=0, obj=1, name='Backup_Capacity[%s,%s]' % (i, j)) self.__model.update() for p in self.__paths: #LP Relaxation #self.__bPath[self.__paths.index(p)] = self.__model.addVar(lb=0,obj=1,name='Backup_Path[%s]' % (self.__paths.index(p))) self.__bPath[self.__paths.index(p)] = self.__model.addVar(vtype=GRB.BINARY,obj=1,name='Backup_Path[%s]' % (self.__paths.index(p))) self.__model.update() for i,j in self.__links: U[i,j] = self.__model.addVar(obj=1,name='U[%s,%s]' % (i, j)) self.__model.update() for i,j in self.__links: for s,d in self.__links: R[i,j,s,d] = self.__model.addVar(obj=1,name='R[%s,%s,%s,%s]' % (i,j,s,d)) self.__model.update() self.__model.modelSense = GRB.MINIMIZE self.__model.setObjective(quicksum(self.__BackupCapacity[i,j] for i,j in self.__links)) self.__model.update() #------------------------------------------------------------------------# # Constraints definition # # # # # #------------------------------------------------------------------------# # Link capacity constraints for i,j in self.__links: self.__model.addConstr(self.__BackupCapacity[i,j] >= quicksum(self.__mean[s,d]*quicksum(self.__bPath[self.__paths.index(p)] for p in self.__Pij[i,j,s,d]) for s,d in self.__links) + U[i,j]*self.__invstd,'[CONST]Link_Cap[%s][%s]' % (i, j)) self.__model.update() # SCOP Reformulation Constraints for i,j in self.__links: self.__model.addConstr(quicksum(R[i,j,s,d]*R[i,j,s,d] for s,d in self.__links) <= U[i,j]*U[i,j],'[CONST]SCOP1[%s][%s]' % (i, j)) self.__model.update() # SCOP Reformulation Constraints for i,j in self.__links: for s,d in self.__links: self.__model.addConstr(self.__std[s,d]*quicksum(self.__bPath[self.__paths.index(p)] for p in self.__Pij[i,j,s,d]) == R[i,j,s,d],'[CONST]SCOP2[%s][%s][%s][%s]' % (i,j,s,d)) self.__model.update() # Unique path for s,d in self.__links: self.__model.addConstr(quicksum(self.__bPath[self.__paths.index(p)] for p in self.__Psd[s,d]) == 1,'UniquePath[%s,%s]' % (s, d)) self.__model.update() def optimize(self,MipGap,TimeLimit): self.__model.write('pathbackup.lp') if TimeLimit != None: self.__model.params.timeLimit = TimeLimit if MipGap != None: self.__model.params.MIPGap=MipGap # Compute optimal solution self.__model.optimize() # Print solution if self.__model.status == GRB.Status.OPTIMAL: solution = self.__model.getAttr('x', self.__bPath) for p in self.__paths: if solution[self.__paths.index(p)] > 0.001: print('Path[%s] = %s = %s' % (self.__paths.index(p),p,solution[self.__paths.index(p)])) solution = self.__model.getAttr('x', self.__BackupCapacity) for i,j in self.__links: if solution[i,j] > 0: print('%s -> %s: %g' % (i, j, solution[i,j])) else: print('Optimal value not found!\n') solution = self.__model.getAttr('x', self.__BackupCapacity) for i,j in self.__links: if solution[i,j] > 0: print('%s -> %s: %g' % (i, j, solution[i,j])) #solution = [] return solution; def reset(self): ''' Reset model solution ''' self.__model.reset()
def optimize_pareto(n, h, u, ju_s, ju_l, jn_s, jn_l, w): # check input parameters if ju_l == jn_l or ju_s == jn_s: return 'worst and best overlap' # create a model m = Model('Pareto') # create decision variables x = m.addVars(sa, sa, vtype=GRB.BINARY, name='x') y = m.addVars(sa, dc, vtype=GRB.BINARY, name='y') # add constraints # x is symmetric m.addConstrs((x[i, j] == x[j, i] for i in sa for j in sa), 'symmetric constraint') # Two service areas cant use the same stateful functions when x[i,j] = 0 m.addConstrs((y[i, t] + y[j, t] <= x[i, j] + 1 for i in sa for j in sa for t in dc), 'x = 0 constraint') # Two service areas use the same stateful functions when x[i,j] = 1 m.addConstrs(((y[i, t] - y[j, t] <= 1 - x[i, j]) for i in sa for j in sa for t in dc), 'x = 1 constraint') # Each should be at least managed by one dc m.addConstrs((sum(y[i, t] for t in dc) == 1 for i in sa), 'one dc for one sa') # high availability constraint m.addConstr( sum((1 - x[i, j]) for i in sa for j in sa if i != j) >= 1, 'ha') # maximum state transfer frequency m.addConstr( sum(h * (1 - x[i, j]) for i in sa for j in sa if i != j) <= jn_s - 1, 'max state transfer constraint') # maximum traffic load constraint m.addConstr((sum(y[i, dc[0]] * n * (L_sig + u * L_session) for i in sa) <= jn_l - 1), 'load maximum constraint') # dc0 will have the most heavy load for t in dc: if t != dc[0]: m.addConstr( sum(y[i, t] * n * (L_sig + u * L_session) for i in sa) <= sum(y[i, dc[0]] * n * (L_sig + u * L_session) for i in sa), 'less than max load') # Objective function m.setObjective((1 - w) * (sum(y[i, dc[0]] * n * (L_sig + u * L_session) for i in sa) - ju_l) / (jn_l - ju_l) + w * (sum(h * (1 - x[i, j]) for i in sa for j in sa if i != j) - ju_s) / (jn_s - ju_s), GRB.MINIMIZE) m.optimize() # check model feasible or not if m.getAttr('status') == GRB.INFEASIBLE: return 'infeasible' # Calculate performance metrics # traffic load on stateful functions traffic_load = sum( getattr(y[i, dc[0]], 'X') * n * (L_sig + u * L_session) for i in sa) # state transfer frequency state_transfer = sum(h * (1 - getattr(x[i, j], 'X')) for i in sa for j in sa if i != j) # number of functions num_func = M_dc - sum( prod(1 - getattr(y[i, t], 'X') for i in sa) for t in dc) # total metrics total_metrics = [u, h, u, state_transfer, traffic_load, num_func] return total_metrics
def WassersteinDualCutting(h1, h2, M): """ Find the Wasserstein distance using a cutting plane on the dual """ n = len(h1) P = [] for i in range(n): for j in range(n): P.append((i, j)) # Build model m = Model() m.setParam(GRB.Param.TimeLimit, 300) #m.setParam(GRB.Param.Presolve, 0) #m.setParam(GRB.Param.Threads, 1) # Options are: # -1=automatic, 0=primal simplex, 1=dual simplex, 2=barrier, # 3=concurrent, 4=deterministic concurrent. m.setParam(GRB.Param.Method, 1) # Set a maximization problem m.setAttr(GRB.Attr.ModelSense, -1) print('1. Start building model') # Create variables V = {} U = {} for i, j in P: # First set of dual variables V[i, j] = m.addVar(lb=-GRB.INFINITY, ub=0, obj=h1[i, j]) # Second set of dual variables u_ub = sum([M[v, w][i, j] for v, w in P]) U[i, j] = m.addVar(lb=0, ub=u_ub, obj=h2[i, j]) m.update() print('2. Add initial constraint sets') for i, j in P: for v, w in P: if M[i, j][v, w] <= 16.001: # Threshold for first set of constraints m.addConstr(V[i, j] + U[v, w], GRB.LESS_EQUAL, M[i, j][v, w]) print('3. Start Cutting planes') # Solve the model it = 0 stime = 0 while True: it += 1 m.optimize() break stime += m.RunTime flag = True max_depth = 0 for i, j in P: depth = -1 a, b, c, d = -1, -1, -1, -1 for v, w in P: if V[i, j].X + U[v, w].X - M[i, j][v, w] > depth: a, b, c, d = i, j, v, w depth = V[i, j].X + U[v, w].X - M[i, j][v, w] if (max_depth == 0 and depth > 0.001) or (depth >= max_depth): max_depth = max(max_depth, depth) flag = False m.addConstr(V[a, b] + U[c, d], GRB.LESS_EQUAL, M[a, b][c, d]) print('ITERATION:', it, ' MAX DEPTH:', round(max_depth, 3), ' Time:', round(stime, 3)) if flag: break #else: # m.addConstr(V[a,b] + U[c,d], GRB.LESS_EQUAL, M[a,b][c,d]) return m.getAttr(GRB.Attr.ObjVal)
def generatesSample( num_days, num_shifts, num_nurses, numSam, bounds, constrList, partial_sol, x_mapping, y_mapping, gid, ): N = list(range(num_nurses)) D = list(range(num_days)) Ds = list(range(num_days + 1)) S = list(range(num_shifts)) Ss = list(range(num_shifts + 1)) # Sk=list(range(2)) # constrList=[[(0,),(1,)],[(0,),(2,)],[(0,),(1,2)],[(1,),(0,)],[(1,),(2,)],[(1,),(0,2)],[(2,),(0,)],[(2,),(1,)],[(2,),(0,1)],[(0,1),(2,)],[(0,2),(1,)],[(1,2),(0,)]] try: sys.stdout = open(os.devnull, "w") m = Model("nspSolver") sys.stdout = sys.__stdout__ m.setParam(GRB.Param.OutputFlag, 0) ########### Decision Variables ############# # x = m.addVars(N,D,S,Sk, vtype=GRB.BINARY, name="x") o = m.addVars(N, D, S, vtype=GRB.BINARY, name="o") p = m.addVars(N, D, vtype=GRB.BINARY, name="p") q = m.addVars(N, S, vtype=GRB.BINARY, name="q") r = m.addVars(S, D, vtype=GRB.BINARY, name="r") tw = m.addVars(N, D, D, vtype=GRB.BINARY, name="tw") sw = m.addVars(N, Ds, D, vtype=GRB.BINARY, name="sw") tw1 = m.addVars(N, D, S, D, vtype=GRB.BINARY, name="tw1") sw1 = m.addVars(N, Ds, S, D, vtype=GRB.BINARY, name="sw1") tws = m.addVars(N, S, S, vtype=GRB.BINARY, name="tws") sws = m.addVars(N, Ss, S, vtype=GRB.BINARY, name="sws") tfs = m.addVars(N, S, S, vtype=GRB.BINARY, name="tfs") sfs = m.addVars(N, Ss, S, vtype=GRB.BINARY, name="sfs") tf = m.addVars(N, D, D, vtype=GRB.BINARY, name="tf") sf = m.addVars(N, Ds, D, vtype=GRB.BINARY, name="sf") tw1f = m.addVars(N, D, S, D, vtype=GRB.BINARY, name="tw1f") sw1f = m.addVars(N, Ds, S, D, vtype=GRB.BINARY, name="sw1f") ########### Required Constraints ############# for n in N: for d in D: for s in S: if not np.isnan(partial_sol[n, d, s]): m.addConstr((o[n, d, s] == partial_sol[n, d, s]), "partial solution") m.addConstrs((o.sum(n, d, "*") == p[n, d] for n in N for d in D), "po") # m.addConstrs((x.sum(n,d,s,'*')==o[n,d,s] for n in N for d in D for s in S),"xo") # m.addConstrs((x[n,d,s,sk]==o[n,d,s] for n in N for d in D for s in S for sk in Sk if nurse_skill[n]==sk),"xo") # m.addConstrs((x[n,d,s,sk]==0 for n in N for d in D for s in S for sk in Sk if nurse_skill[n]!=sk),"xo") m.addConstrs((q[n, s] <= o.sum(n, "*", s) for n in N for s in S), "qo") m.addConstrs((q[n, s] * o.sum(n, "*", s) == o.sum(n, "*", s) for n in N for s in S), "qo") m.addConstrs((r[s, d] <= o.sum("*", d, s) for d in D for s in S), "ro") m.addConstrs((r[s, d] * o.sum("*", d, s) == o.sum("*", d, s) for d in D for s in S), "ro") ########### Hard Constraints ############# # print(bounds) for i in range(len(bounds)): if bounds[i, 0] > 0: # print(bounds[i,0]) if constrList[i] == "0:1": m.addConstrs((r.sum("*", d) >= bounds[i, 0] for d in D), "constr") elif constrList[i] == "0:2": m.addConstrs((p.sum("*", d) >= bounds[i, 0] for d in D), "constr") elif constrList[i] == "0:1,2": m.addConstrs((o.sum("*", d, "*") >= bounds[i, 0] for d in D), "constr") elif constrList[i] == "1:0": m.addConstrs((r.sum(s, "*") >= bounds[i, 0] for s in S), "constr") elif constrList[i] == "1:2": m.addConstrs((q.sum("*", s) >= bounds[i, 0] for s in S), "constr") elif constrList[i] == "1:0,2": m.addConstrs((o.sum("*", "*", s) >= bounds[i, 0] for s in S), "constr") elif constrList[i] == "2:0": m.addConstrs((p.sum(n, "*") >= bounds[i, 0] for n in N), "constr") elif constrList[i] == "2:1": m.addConstrs((q.sum(n, "*") >= bounds[i, 0] for n in N), "constr") elif constrList[i] == "2:0,1": m.addConstrs((o.sum(n, "*", "*") >= bounds[i, 0] for n in N), "constr") elif constrList[i] == "0,1:2": m.addConstrs( (o.sum("*", d, s) >= bounds[i, 0] for d in D for s in S), "constr", ) elif constrList[i] == "0,2:1": m.addConstrs( (o.sum(n, d, "*") >= bounds[i, 0] for d in D for n in N), "constr", ) elif constrList[i] == "1,2:0": m.addConstrs( (o.sum(n, "*", s) >= bounds[i, 0] for n in N for s in S), "constr", ) if bounds[i, 1] > 0: # print(bounds[i,1]) if constrList[i] == "0:1": m.addConstrs((r.sum("*", d) <= bounds[i, 1] for d in D), "constr") elif constrList[i] == "0:2": m.addConstrs((p.sum("*", d) <= bounds[i, 1] for d in D), "constr") elif constrList[i] == "0:1,2": m.addConstrs((o.sum("*", d, "*") <= bounds[i, 1] for d in D), "constr") elif constrList[i] == "1:0": m.addConstrs((r.sum(s, "*") <= bounds[i, 1] for s in S), "constr") elif constrList[i] == "1:2": m.addConstrs((q.sum("*", s) <= bounds[i, 1] for s in S), "constr") elif constrList[i] == "1:0,2": m.addConstrs((o.sum("*", "*", s) <= bounds[i, 1] for s in S), "constr") elif constrList[i] == "2:0": m.addConstrs((p.sum(n, "*") <= bounds[i, 1] for n in N), "constr") elif constrList[i] == "2:1": m.addConstrs((q.sum(n, "*") <= bounds[i, 1] for n in N), "constr") elif constrList[i] == "2:0,1": m.addConstrs((o.sum(n, "*", "*") <= bounds[i, 1] for n in N), "constr") elif constrList[i] == "0,1:2": m.addConstrs( (o.sum("*", d, s) <= bounds[i, 1] for d in D for s in S), "constr", ) elif constrList[i] == "0,2:1": m.addConstrs( (o.sum(n, d, "*") <= bounds[i, 1] for d in D for n in N), "constr", ) elif constrList[i] == "1,2:0": m.addConstrs( (o.sum(n, "*", s) <= bounds[i, 1] for n in N for s in S), "constr", ) # if mt==1: # for i in range(len(nurse_preference)): # m.addConstr((o[i,nurse_preference[i][0],nurse_preference[i][1]] == 0),"nursePref") if constrList[i] == "2:0" and bounds[i, 5] + bounds[i, 4] > 0: m.addConstrs((tw[n, 0, 0] == p[n, 0] for n in N), "MaxConsWork") m.addConstrs( (tw[n, d1 + 1, 0] <= p[n, d1 + 1] for n in N for d1 in D if d1 < len(D) - 1), "MaxConsWork", ) m.addConstrs( (tw[n, d1 + 1, 0] <= 1 - p[n, d1] for n in N for d1 in D if d1 < len(D) - 1), "MaxConsWork", ) m.addConstrs( (tw[n, d1 + 1, 0] >= p[n, d1 + 1] - p[n, d1] for n in N for d1 in D if d1 < len(D) - 1), "MaxConsWork", ) m.addConstrs((tw[n, 0, d2] == 0 for n in N for d2 in D if d2 > 0), "MaxConsWork") m.addConstrs( (tw[n, d1, d2] <= tw[n, d1 - 1, d2 - 1] for n in N for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsWork", ) m.addConstrs( (tw[n, d1, d2] <= p[n, d1] for n in N for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsWork", ) m.addConstrs( (tw[n, d1, d2] >= p[n, d1] + tw[n, d1 - 1, d2 - 1] - 1 for n in N for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsWork", ) if bounds[i, 5] > 0: m.addConstr( (quicksum(tw[n, d1, d2] for n in N for d1 in D for d2 in range(bounds[i, 5], len(D))) == 0), "maxconswork", ) if bounds[i, 4] > 0: m.addConstrs((sw[n, 0, d2] == 0 for n in N for d2 in D), "MinConsWork") m.addConstrs( (sw[n, d1, d2] <= tw[n, d1 - 1, d2] for n in N for d1 in D for d2 in D if d1 > 0), "MinConsWork", ) m.addConstrs( (sw[n, d1, d2] <= 1 - p[n, d1] for n in N for d1 in D for d2 in D if d1 > 0), "MinConsWork", ) m.addConstrs( (sw[n, d1, d2] >= tw[n, d1 - 1, d2] - p[n, d1] for n in N for d1 in D for d2 in D if d1 > 0), "MinConsWork", ) m.addConstrs( (sw[n, num_days, d2] == tw[n, num_days - 1, d2] for n in N for d2 in D), "MinConsWork", ) m.addConstr( (quicksum(sw[n, d1, d2] * (bounds[i, 4] - 1 - d2) for n in N for d1 in Ds for d2 in range(bounds[i, 4] - 1)) == 0), "minconswork", ) if constrList[i] == [(2, ), (0, )] and bounds[i, 3] + bounds[i, 2] > 0: m.addConstrs((tf[n, 0, 0] == 1 - p[n, 0] for n in N), "MaxConsFree") m.addConstrs( (tf[n, d1 + 1, 0] <= p[n, d1] for n in N for d1 in D if d1 < len(D) - 1), "MaxConsFree", ) m.addConstrs( (tf[n, d1 + 1, 0] <= 1 - p[n, d1 + 1] for n in N for d1 in D if d1 < len(D) - 1), "MaxConsFree", ) m.addConstrs( (tf[n, d1 + 1, 0] >= p[n, d1] - p[n, d1 + 1] for n in N for d1 in D if d1 < len(D) - 1), "MaxConsFree", ) m.addConstrs((tf[n, 0, d2] == 0 for n in N for d2 in D if d2 > 0), "MaxConsFree") m.addConstrs( (tf[n, d1, d2] <= tf[n, d1 - 1, d2 - 1] for n in N for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsFree", ) m.addConstrs( (tf[n, d1, d2] <= 1 - p[n, d1] for n in N for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsFree", ) m.addConstrs( (tf[n, d1, d2] >= tf[n, d1 - 1, d2 - 1] - p[n, d1] for n in N for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsFree", ) if bounds[i, 3] > 0: m.addConstr( (quicksum(tf[n, d1, d2] for n in N for d1 in D for d2 in range(bounds[i, 3], len(D))) == 0), "maxconsfree", ) if bounds[i, 2] > 0: m.addConstrs((sf[n, 0, d2] == 0 for n in N for d2 in D), "MinConsFree") m.addConstrs( (sf[n, d1, d2] <= tf[n, d1 - 1, d2] for n in N for d1 in D for d2 in D if d1 > 0), "MinConsFree", ) m.addConstrs( (sf[n, d1, d2] <= p[n, d1] for n in N for d1 in D for d2 in D if d1 > 0), "MinConsFree", ) m.addConstrs( (sf[n, d1, d2] >= tf[n, d1 - 1, d2] + p[n, d1] - 1 for n in N for d1 in D for d2 in D if d1 > 0), "MinConsFree", ) m.addConstrs( (sf[n, num_days, d2] == tf[n, num_days - 1, d2] for n in N for d2 in D), "MinConsFree", ) m.addConstr( (quicksum(sf[n, d1, d2] * (bounds[i, 2] - 1 - d2) for n in N for d1 in Ds for d2 in range(bounds[i, 2] - 1)) == 0), "minconsfree", ) if constrList[i] == [(2, ), (1, )] and bounds[i, 5] + bounds[i, 4] > 0: m.addConstrs((tws[n, 0, 0] == q[n, 0] for n in N), "MaxConsWork") m.addConstrs( (tws[n, s1 + 1, 0] <= q[n, s1 + 1] for n in N for s1 in S if s1 < len(S) - 1), "MaxConsWork", ) m.addConstrs( (tws[n, s1 + 1, 0] <= 1 - q[n, s1] for n in N for s1 in S if s1 < len(S) - 1), "MaxConsWork", ) m.addConstrs( (tws[n, s1 + 1, 0] >= q[n, s1 + 1] - q[n, s1] for n in N for s1 in S if s1 < len(S) - 1), "MaxConsWork", ) m.addConstrs((tws[n, 0, s2] == 0 for n in N for s2 in S if s2 > 0), "MaxConsWork") m.addConstrs( (tws[n, s1, s2] <= tws[n, s1 - 1, s2 - 1] for n in N for s1 in S for s2 in S if s1 > 0 if s2 > 0), "MaxConsWork", ) m.addConstrs( (tws[n, s1, s2] <= q[n, s1] for n in N for s1 in S for s2 in S if s1 > 0 if s2 > 0), "MaxConsWork", ) m.addConstrs( (tws[n, s1, s2] >= q[n, s1] + tws[n, s1 - 1, s2 - 1] - 1 for n in N for s1 in S for s2 in S if s1 > 0 if s2 > 0), "MaxConsWork", ) if bounds[i, 5] > 0: m.addConstr( (quicksum(tws[n, s1, s2] for n in N for s1 in S for s2 in range(bounds[i, 5], len(S))) == 0), "maxconswork", ) if bounds[i, 4] > 0: m.addConstrs((sws[n, 0, s2] == 0 for n in N for s2 in S), "MinConsWork") m.addConstrs( (sws[n, s1, s2] <= tws[n, s1 - 1, s2] for n in N for s1 in S for s2 in S if s1 > 0), "MinConsWork", ) m.addConstrs( (sws[n, s1, s2] <= 1 - q[n, s1] for n in N for s1 in S for s2 in S if s1 > 0), "MinConsWork", ) m.addConstrs( (sws[n, s1, s2] >= tws[n, s1 - 1, s2] - q[n, s1] for n in N for s1 in S for s2 in S if s1 > 0), "MinConsWork", ) m.addConstrs( (sws[n, num_shifts, s2] == tws[n, num_shifts - 1, s2] for n in N for s2 in S), "MinConsWork", ) m.addConstr( (quicksum(sws[n, s1, s2] * (bounds[i, 4] - 1 - s2) for n in N for s1 in Ss for s2 in range(bounds[i, 4] - 1)) == 0), "minconswork", ) if constrList[i] == [(2, ), (1, )] and bounds[i, 3] + bounds[i, 2] > 0: m.addConstrs((tfs[n, 0, 0] == 1 - q[n, 0] for n in N), "MaxConsFree") m.addConstrs( (tfs[n, s1 + 1, 0] <= q[n, s1] for n in N for s1 in S if s1 < len(S) - 1), "MaxConsFree", ) m.addConstrs( (tfs[n, s1 + 1, 0] <= 1 - q[n, s1 + 1] for n in N for s1 in S if s1 < len(S) - 1), "MaxConsFree", ) m.addConstrs( (tfs[n, s1 + 1, 0] >= q[n, s1] - q[n, s1 + 1] for n in N for s1 in S if s1 < len(S) - 1), "MaxConsFree", ) m.addConstrs((tfs[n, 0, s2] == 0 for n in N for s2 in S if s2 > 0), "MaxConsFree") m.addConstrs( (tfs[n, s1, s2] <= tfs[n, s1 - 1, s2 - 1] for n in N for s1 in S for s2 in S if s1 > 0 if s2 > 0), "MaxConsFree", ) m.addConstrs( (tfs[n, s1, s2] <= 1 - q[n, s1] for n in N for s1 in S for s2 in S if s1 > 0 if s2 > 0), "MaxConsFree", ) m.addConstrs( (tfs[n, s1, s2] >= tfs[n, s1 - 1, s2 - 1] - q[n, s1] for n in N for s1 in S for s2 in S if s1 > 0 if s2 > 0), "MaxConsFree", ) if bounds[i, 3] > 0: m.addConstr( (quicksum(tfs[n, s1, s2] for n in N for s1 in S for s2 in range(bounds[i, 3], len(S))) == 0), "maxconsfree", ) if bounds[i, 2] > 0: m.addConstrs((sfs[n, 0, s2] == 0 for n in N for s2 in S), "MinConsFree") m.addConstrs( (sfs[n, s1, s2] <= tfs[n, s1 - 1, s2] for n in N for s1 in S for s2 in S if s1 > 0), "MinConsFree", ) m.addConstrs( (sfs[n, s1, s2] <= q[n, s1] for n in N for s1 in S for s2 in S if s1 > 0), "MinConsFree", ) m.addConstrs( (sfs[n, s1, s2] >= tfs[n, s1 - 1, s2] + q[n, s1] - 1 for n in N for s1 in S for s2 in S if s1 > 0), "MinConsFree", ) m.addConstrs( (sfs[n, num_shifts, s2] == tfs[n, num_shifts - 1, s2] for n in N for s2 in S), "MinConsWork", ) m.addConstr( (quicksum(sfs[n, s1, s2] * (bounds[i, 2] - 1 - s2) for n in N for s1 in Ss for s2 in range(bounds[i, 2] - 1)) == 0), "minconsfree", ) if constrList[i] == [(1, 2), (0, )] and bounds[i, 5] + bounds[i, 4] > 0: m.addConstrs( (tw1[n, 0, s, 0] == o[n, 0, s] for n in N for s in S), "MaxConsSameShift", ) m.addConstrs( (tw1[n, d1 + 1, s, 0] <= o[n, d1 + 1, s] for s in S for n in N for d1 in D if d1 < len(D) - 1), "MaxConsSameShift", ) m.addConstrs( (tw1[n, d1 + 1, s, 0] <= 1 - o[n, d1, s] for s in S for n in N for d1 in D if d1 < len(D) - 1), "MaxConsSameShift", ) m.addConstrs( (tw1[n, d1 + 1, s, 0] >= o[n, d1 + 1, s] - o[n, d1, s] for s in S for n in N for d1 in D if d1 < len(D) - 1), "MaxConsSameShift", ) m.addConstrs( (tw1[n, 0, s, d2] == 0 for s in S for n in N for d2 in D if d2 > 0), "MaxConsSameShift", ) m.addConstrs( (tw1[n, d1, s, d2] <= tw1[n, d1 - 1, s, d2 - 1] for s in S for n in N for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsSameShift", ) m.addConstrs( (tw1[n, d1, s, d2] <= o[n, d1, s] for s in S for n in N for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsSameShift", ) m.addConstrs( (tw1[n, d1, s, d2] >= o[n, d1, s] + tw1[n, d1 - 1, s, d2 - 1] - 1 for s in S for n in N for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsSameShift", ) if bounds[i, 5] > 0: m.addConstr( (quicksum(tw1[n, d1, s, d2] for s in S for n in N for d1 in D for d2 in range(bounds[i, 5], len(D))) == 0), "maxconssameshift", ) if bounds[i, 4] > 0: m.addConstrs( (sw1[n, 0, s, d2] == 0 for s in S for n in N for d2 in D), "MinConsSameShift", ) m.addConstrs( (sw1[n, d1, s, d2] <= tw1[n, d1 - 1, s, d2] for s in S for n in N for d1 in D for d2 in D if d1 > 0), "MinConsSameShift", ) m.addConstrs( (sw1[n, d1, s, d2] <= 1 - o[n, d1, s] for s in S for n in N for d1 in D for d2 in D if d1 > 0), "MinConsSameShift", ) m.addConstrs( (sw1[n, d1, s, d2] >= tw1[n, d1 - 1, s, d2] - o[n, d1, s] for s in S for n in N for d1 in D for d2 in D if d1 > 0), "MinConsSameShift", ) m.addConstrs( (sw1[n, num_days, s, d2] == tw1[n, num_days - 1, s, d2] for n in N for s in S for d2 in D), "MinConsWork", ) m.addConstr( (quicksum(sw1[n, d1, s, d2] * (bounds[i, 4] - 1 - d2) for s in S for n in N for d1 in Ds for d2 in range(bounds[i, 4] - 1)) == 0), "minconssameshift", ) if constrList[i] == [(1, 2), (0, )] and bounds[i, 3] + bounds[i, 2] > 0: m.addConstrs( (tw1f[n, 0, s, 0] == 1 - o[n, 0, s] for n in N for s in S), "MaxConsFree", ) m.addConstrs( (tw1f[n, d1 + 1, s, 0] <= o[n, d1, s] for n in N for s in S for d1 in D if d1 < len(D) - 1), "MaxConsFree", ) m.addConstrs( (tw1f[n, d1 + 1, s, 0] <= 1 - o[n, d1 + 1, s] for n in N for s in S for d1 in D if d1 < len(D) - 1), "MaxConsFree", ) m.addConstrs( (tw1f[n, d1 + 1, s, 0] >= o[n, d1, s] - o[n, d1 + 1, s] for n in N for s in S for d1 in D if d1 < len(D) - 1), "MaxConsFree", ) m.addConstrs( (tw1f[n, 0, s, d2] == 0 for n in N for s in S for d2 in D if d2 > 0), "MaxConsFree", ) m.addConstrs( (tw1f[n, d1, s, d2] <= tw1f[n, d1 - 1, s, d2 - 1] for n in N for s in S for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsFree", ) m.addConstrs( (tw1f[n, d1, s, d2] <= 1 - o[n, d1, s] for n in N for s in S for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsFree", ) m.addConstrs( (tw1f[n, d1, s, d2] >= tw1f[n, d1 - 1, s, d2 - 1] - o[n, d1, s] for n in N for s in S for d1 in D for d2 in D if d1 > 0 if d2 > 0), "MaxConsFree", ) if bounds[i, 3] > 0: m.addConstr( (quicksum(tw1f[n, d1, s, d2] for n in N for s in S for d1 in D for d2 in range(bounds[i, 3], len(D))) == 0), "maxconsfree", ) if bounds[i, 2] > 0: m.addConstrs( (sw1f[n, 0, s, d2] == 0 for n in N for s in S for d2 in D), "MinConsw1free", ) m.addConstrs( (sw1f[n, d1, s, d2] <= tw1f[n, d1 - 1, s, d2] for n in N for s in S for d1 in D for d2 in D if d1 > 0), "MinConsw1free", ) m.addConstrs( (sw1f[n, d1, s, d2] <= o[n, d1, s] for n in N for s in S for d1 in D for d2 in D if d1 > 0), "MinConsw1free", ) m.addConstrs( (sw1f[n, d1, s, d2] >= tw1f[n, d1 - 1, s, d2] + o[n, d1, s] - 1 for n in N for s in S for d1 in D for d2 in D if d1 > 0), "MinConsw1free", ) m.addConstrs( (sw1f[n, num_days, s, d2] == tw1f[n, num_days - 1, s, d2] for n in N for s in S for d2 in D), "MinConsWork", ) m.addConstr( (quicksum(sw1f[n, d1, s, d2] * (bounds[i, 2] - 1 - d2) for n in N for s in S for d1 in Ds for d2 in range(bounds[i, 2] - 1)) == 0), "minconsw1free", ) m.setParam(GRB.Param.PoolSolutions, numSam) m.setParam(GRB.Param.PoolSearchMode, 2) m.optimize() nSolutions = m.SolCount # print("Number of solutions found: " + str(nSolutions)) if m.status == GRB.Status.INFEASIBLE: m.computeIIS() # print("\nThe following constraint(s) cannot be satisfied:") for c in m.getConstrs(): if c.IISConstr: # print("%s" % c.constrName) pass # if m.status == GRB.Status.OPTIMAL: # m.write("m.sol") # print(nSolutions) # print(partial_sol) multi_predictions = [] for i in range(nSolutions): provenance = ("countor", gid + "-" + str(uuid4())) m.setParam(GRB.Param.SolutionNumber, i) solution = m.getAttr("xn", o) # print(m.getAttr("xn", p)) tmp = np.zeros([num_nurses, num_days, num_shifts]) for key in solution: tmp[key] = round(solution[key]) # tSample=np.swapaxes(np.swapaxes(tmp,0,1),1,2) tmp_sol = tmp.astype(int) # print(partial_sol) for n in N: for d in D: for s in S: # print(x_mapping[n,d,s],y_mapping[n,d,s]) if np.isnan(partial_sol[n, d, s]): # print("geer") multi_predictions.append( Prediction( Coordinate( y_mapping[n, d, s].item(), x_mapping[n, d, s].item(), ), tmp_sol[n, d, s].item(), 1, provenance, )) return multi_predictions except GurobiError as e: print("Error code " + str(e.errno) + ": " + str(e)) except AttributeError: print("Encountered an attribute error")
def solve_tsp_gurobi(D, selected_idxs): #print #print "============== GUROBI =============" n = len(selected_idxs) if selected_idxs[0] == selected_idxs[-1]: n = n - 1 # no need to invoke Gurobi for tiny TSP cases if n <= 3: sol = None obj_f = 0.0 if n > 1: sol = list(selected_idxs) if sol[0] != sol[-1]: sol.append(sol[0]) obj_f = sum(D[sol[i - 1], sol[i]] for i in range(1, len(sol))) return sol, obj_f m = Model("TSP") m.params.OutputFlag = 0 # Create variables edgevars = {} for i in range(n): for j in range(i + 1): from_node = selected_idxs[i] to_node = selected_idxs[j] edgevars[i, j] = m.addVar(obj=D[from_node, to_node], vtype=GRB.BINARY, name='e' + str(i) + '_' + str(j)) edgevars[j, i] = edgevars[i, j] m.update() # Add degree-2 constraint, and forbid loops for i in range(n): m.addConstr(quicksum(edgevars[i, j] for j in range(n)) == 2) edgevars[i, i].ub = 0 m.update() # Optimize model m._vars = edgevars m.params.LazyConstraints = 1 m.setParam('TimeLimit', MAX_MIP_SOLVER_RUNTIME) m.setParam('Threads', MIP_SOLVER_THREADS) m.optimize(_subtourelim) # restore SIGINT callback handler which is changed by gurobipy signal(SIGINT, default_int_handler) status = m.Status if status == GRB.TIME_LIMIT: raise GurobiError( 10023, "Gurobi timeout reached when attempting to solve TSP") elif m.Status == GRB.INTERRUPTED: raise KeyboardInterrupt() solution = m.getAttr('x', edgevars) selected = [(i, j) for i in range(n) for j in range(n) if solution[i, j] > 0.5] cycles = _subtour(selected, n) assert len(cycles) == n # make the route always start from the 1st index sol = [selected_idxs[i] for i in cycles] + [selected_idxs[0]] obj_f = m.objVal return sol, obj_f
class BFPBackupNetwork_Continuous(object): """ Class object for buffered failure probability-based model. Parameters ---------- Gamma: importance sampling vector Nodes: set of nodes Links: set of links Capacity: capacities per link based based on random failures Survivability: desired survivabiliy factor (epsilon) K: number of random scenarios Returns ------- BackupCapacity: set of capacity per backup link. BackupRoutes: set of backup links """ # Private model object model = [] # Private model variables BackupCapacity = {} bBackupLink = {} z0 = {} z = {} def __init__(self): """ Constructor """ def LoadModel(self, Gamma, Nodes, Links, Capacity, Survivability, NumSamples): """ Load model. Parameters ---------- Gamma : importance sampling vector """ self.Links = tuplelist(Links) self.Capacity = Capacity # Create optimization model self.model = Model("Backup") # Create variables for i, j in self.Links: self.BackupCapacity[i, j] = self.model.addVar( vtype=GRB.CONTINUOUS, lb=0, name="Backup_Capacity[%s,%s]" % (i, j) ) # self.BackupCapacity[i,j] = self.model.addVar(lb=0, name='Backup_Capacity[%s,%s]' % (i, j)) self.model.update() for i, j in self.Links: for s, d in self.Links: self.bBackupLink[i, j, s, d] = self.model.addVar( vtype=GRB.BINARY, name="Backup_Link[%s,%s,%s,%s]" % (i, j, s, d) ) self.model.update() for i, j in self.Links: for k in range(NumSamples): self.z[k, i, j] = self.model.addVar(lb=0, name="z[%s][%s][%s]" % (k, i, j)) self.model.update() for i, j in self.Links: self.z0[i, j] = self.model.addVar(lb=-GRB.INFINITY, name="z0[%s][%s]" % (i, j)) self.model.update() self.model.modelSense = GRB.MINIMIZE self.model.setObjective(quicksum(self.BackupCapacity[i, j] for i, j in self.Links)) self.model.update() # ------------------------------------------------------------------------# # Constraints definition # # # # # # ------------------------------------------------------------------------# # Buffer probability I for i, j in self.Links: self.model.addConstr( self.z0[i, j] + 1 / (NumSamples * Survivability) * quicksum(self.z[k, i, j] for (k) in range(NumSamples)) <= 0, "[CONST]Buffer_Prob_I[%s][%s]" % (i, j), ) self.model.update() # Link capacity constraints for i, j in self.Links: for k in range(NumSamples): if Gamma == None: self.model.addConstr( ( quicksum(self.bBackupLink[i, j, s, d] * Capacity[k, s, d] for s, d in self.Links) - self.BackupCapacity[i, j] - self.z0[i, j] ) <= self.z[k, i, j], "[CONST]Buffer_Prob_II[%s][%s][%s]" % (k, i, j), ) else: self.model.addConstr( ( quicksum(self.bBackupLink[i, j, s, d] * Capacity[k, s, d] for s, d in self.Links) - self.BackupCapacity[i, j] - self.z0[i, j] ) * Gamma[k] <= self.z[k, i, j], "[CONST]Buffer_Prob_II[%s][%s][%s]" % (k, i, j), ) self.model.update() # Link capacity constraints for i, j in self.Links: for k in range(NumSamples): self.model.addConstr(self.z[k, i, j] >= 0, "[CONST]Buffer_Prob_III[%s][%s][%s]" % (k, i, j)) self.model.update() for i in Nodes: for s, d in self.Links: # Flow conservation constraints if i == s: self.model.addConstr( quicksum(self.bBackupLink[i, j, s, d] for i, j in self.Links.select(i, "*")) - quicksum(self.bBackupLink[j, i, s, d] for j, i in self.Links.select("*", i)) == 1, "Flow1[%s,%s,%s]" % (i, s, d), ) # Flow conservation constraints elif i == d: self.model.addConstr( quicksum(self.bBackupLink[i, j, s, d] for i, j in self.Links.select(i, "*")) - quicksum(self.bBackupLink[j, i, s, d] for j, i in self.Links.select("*", i)) == -1, "Flow2[%s,%s,%s]" % (i, s, d), ) # Flow conservation constraints else: self.model.addConstr( quicksum(self.bBackupLink[i, j, s, d] for i, j in self.Links.select(i, "*")) - quicksum(self.bBackupLink[j, i, s, d] for j, i in self.Links.select("*", i)) == 0, "Flow3[%s,%s,%s]" % (i, s, d), ) self.model.update() def Optimize(self, MipGap=None, TimeLimit=None, LogLevel=None): """ Optimize the defined model. Parameters ---------- MipGap : desired gap TimeLimit : time limit LogLevel: log level 1 for printing all optimal variables and None otherwise Returns ------- BackupCapacity: The total capacity assigned per backup link BackupRoutes: The set of selected backup links A tuple list with all paths for edge (s,d) that uses (i,j). """ self.model.write("bpbackup.lp") if MipGap != None: self.model.params.MIPGap = MipGap if TimeLimit != None: self.model.params.timeLimit = TimeLimit # Compute optimal solution self.model.optimize() # Print solution if self.model.status == GRB.Status.OPTIMAL: if LogLevel == 1: for v in self.model.getVars(): print("%s %g" % (v.varName, v.x)) self.BackupCapacitySolution = self.model.getAttr("x", self.BackupCapacity) self.BackupRoutesSolution = self.model.getAttr("x", self.bBackupLink) self.BackupLinksSolution = {} self.HatBackupCapacity = {} for link in self.BackupCapacitySolution: if self.BackupCapacitySolution[link] < 1 and self.BackupCapacitySolution[link] > 0.001: self.HatBackupCapacity[link] = math.ceil(self.BackupCapacitySolution[link]) else: self.HatBackupCapacity[link] = math.floor(self.BackupCapacitySolution[link]) if self.HatBackupCapacity[link] > 0: if len(self.BackupLinksSolution) == 0: self.BackupLinksSolution = [link] else: self.BackupLinksSolution = self.BackupLinksSolution + [link] else: print("Optimal value not found!\n") self.BackupCapacitySolution = [] self.BackupRoutesSolution = {} self.BackupLinksSolution = {} return self.BackupCapacitySolution, self.BackupRoutesSolution, self.BackupLinksSolution, self.HatBackupCapacity def SaveBakupNetwork(self, file_name): """Save the optimal backup network to the file ``file_name``.""" data = { "links": [i for i in self.BackupCapacitySolution], "capacities": [self.BackupCapacitySolution[i] for i in self.BackupCapacitySolution], "routes": [i for i in self.BackupRoutesSolution], "status": [self.BackupRoutesSolution[i] for i in self.BackupRoutesSolution], } f = open(file_name, "w") json.dump(data, f) f.close() def LoadBackupNetwork(self, file_name): """Load a backup network from the file ``file_name``. Returns the backup network solution saved in the file. """ f = open(file_name, "r") data = json.load(f) f.close() self.BackupCapacitySolution = {} self.BackupRoutesSolution = {} self.BackupLinksSolution = {} links = [i for i in data["links"]] capacities = [i for i in data["capacities"]] routes = [i for i in data["routes"]] status = [i for i in data["status"]] IndexAux = 0 for i, j in links: self.BackupCapacitySolution[i, j] = capacities[IndexAux] IndexAux = IndexAux + 1 self.HatBackupCapacity = {} for link in self.BackupCapacitySolution: if self.BackupCapacitySolution[link] < 1 and self.BackupCapacitySolution[link] > 0.001: self.HatBackupCapacity[link] = math.ceil(self.BackupCapacitySolution[link]) else: self.HatBackupCapacity[link] = math.floor(self.BackupCapacitySolution[link]) if self.HatBackupCapacity[link] > 0: if len(self.BackupLinksSolution) == 0: self.BackupLinksSolution = [link] else: self.BackupLinksSolution = self.BackupLinksSolution + [link] IndexAux = 0 for i, j, s, d in routes: self.BackupRoutesSolution[i, j, s, d] = status[IndexAux] IndexAux = IndexAux + 1 return self.BackupCapacitySolution, self.BackupRoutesSolution, self.BackupLinksSolution, self.HatBackupCapacity def ResetModel(self): """ Reset model solution. """ self.BackupCapacity = {} self.bBackupLink = {} self.z0 = {} self.z = {} if self.model: self.model.reset()
def SU_Gurobi_Model(data): # Create the model suModel = Model('Getir') # Set parameters suModel.setParam('OutputFlag', True) n = len(data['vehicles']) #number of vehicles m = len(data['jobs']) #number of jobs S = range(0, n) # source nodes of the vehicles J = range(n, n + m) # job or customer nodes V = range(0, n) # vehicles S_J = range(0, n + m) # sources and jobs J_E = range(n, n + m + m) # jobs and ARTIFICIAL ending nodes # Add variables x = suModel.addVars( S_J, J_E, V, vtype=GRB.BINARY, name='x') #assigment variable - between arcs(locations) u = suModel.addVars( J_E, V, lb=2, ub=m, vtype=GRB.INTEGER, name='u' ) # sequence variable which is required for subtour elimination # minimize the total travel time suModel.setObjective( quicksum(data['matrix'][i][j] * x[i, j, k] for i in S_J for j in J_E for k in V if j < n + m), GRB.MINIMIZE) suModel.addConstrs( (quicksum(x[i, j, k] for j in J) == 1 for i in S for k in V if i == k), name='c1') suModel.addConstrs( (quicksum(x[i, j, k] for j in J) == 1 for i in S for k in V if i == k), name='c2') suModel.addConstrs((quicksum(x[i, i + m, k] for i in J) == 1 for k in V), name='c3') suModel.addConstrs((quicksum(x[i, j, k] for i in S_J for k in V if i != j) == 1 for j in J), name='c4') suModel.addConstrs((quicksum(x[i, j, k] for i in S_J) == quicksum(x[j, h, k] for h in J_E) for k in V for j in J), name='c5') #subtour eliminations suModel.addConstrs((u[i, k] - u[j, k] + m * x[i, j, k] <= (m - 1) for i in J for j in J_E for k in V if i != j), name='c6') # Optimize the model suModel.optimize() # write the results #OutputDictionary(suModel,data) Output(suModel) # print the LP file (this file can be used in different optimization platforms such as CPLEX, Gams, etc.) suModel.write('suGetir.lp') # print the sol file suModel.write('suGetir.sol') routes = {} solution = suModel.getAttr('x', x) for k in V: route = [] for i in S: for j in J: if solution[i, j, k] == 1: route.append(i) route.append(j) while route[-1] < n + m: for j in J_E: if route[-1] < n + m: if solution[route[-1], j, k] == 1: route.append(j) routes[str(k)] = route[0:len(route) - 1] print(routes) return routes
from gurobipy import Model, GRB m = Model("hw51") x1 = m.addVar(name="x1") x2 = m.addVar(name="x2") m.update() m.setObjective(5 * x1 + 4 * x2, GRB.MAXIMIZE) m.addConstr(6 * x1 + 4 * x2 <= 24, 'constraint1') m.addConstr(x1 + 2 * x2 <= 6, 'constraint2') m.addConstr(-x1 + x2 <= 1, 'constraint3') m.addConstr(x2 <= 2, ' constraint4') m.optimize() for v in m.getVars(): print('%s: %f' % (v.varName, v.x)) print('Obj: %f' % m.objVal) print 'reduced costs: ' print ' ', m.getAttr('rc', m.getVars()) print 'shadow prices: ' print ' ', m.getAttr('pi', m.getConstrs())
def solve_weighted_max_sat( n: int, model: MaxSatModel, context: Clause, num_sol ) -> Optional[Instance]: if any(w and (w > 1 or w < 0) for w, _ in model): raise AttributeError("Weights must be between in the interval [0, 1]") with suppress_stdout(): mod = Model("MaxSat") mod.setParam("OutputFlag", False) m = len(model) # Variables x_l = [mod.addVar(vtype=GRB.BINARY, name=f"x_{l})") for l in range(n)] cov_j = [mod.addVar(vtype=GRB.BINARY, name=f"cov_{j})") for j in range(m)] w_j = [ mod.addVar(vtype=GRB.CONTINUOUS, lb=0, ub=1, name=f"w_{j}") for j in range(m) ] mod.setObjective(quicksum([w_j[j] for j in range(m)]), GRB.MAXIMIZE) for j, (weight, clause) in enumerate(model): # FOR-ALL_l: cov_j >= x_l * a_jl+ OR cov_j >= (1 - x_l) * a_jl- for i in clause: if i < 0: l = abs(i) - 1 mod.addConstr(cov_j[j] >= (1 - x_l[l]), name=f"cov_{j} >= (1 - x_{l})") else: l = i - 1 mod.addConstr(cov_j[j] >= x_l[l], name=f"cov_{j} >= x_{l}") # Force it to be false if no literal is satisfied mod.addConstr( cov_j[j] <= quicksum((1 - x_l[abs(i) - 1]) if i < 0 else x_l[i - 1] for i in clause), name=f"cov_{j} <= SUM_l clause_{j}", ) if weight is None: # Constraint is hard, thus weight is 0 mod.addConstr(w_j[j] == 0, name=f"w_{j} = 0") # Constraint is hard, thus must be covered mod.addConstr(cov_j[j] >= 1, name=f"cov_{j} >= 1") else: # Weight is 0 if clause is not covered, and weight otherwise mod.addConstr( w_j[j] == weight * cov_j[j], name=f"w_{j} = {weight} * cov_{j}" ) for i in context: # Fix values given by context if i < 0: l = abs(i) - 1 mod.addConstr(x_l[l] == 0, name=f"x_{l} = 0") else: l = i - 1 mod.addConstr(x_l[l] == 1, name=f"x_{l} = 1") mod.setParam(GRB.Param.PoolSolutions, num_sol) mod.setParam(GRB.Param.PoolSearchMode, 2) mod.setParam(GRB.Param.PoolGap, 0) mod.optimize() if num_sol == 1: if mod.status == GRB.Status.OPTIMAL: return np.array([x_l[l].x for l in range(n)]) else: return None num_sol = mod.SolCount list_sol = [] for i in range(num_sol): mod.setParam(GRB.Param.SolutionNumber, i) if mod.status == GRB.Status.OPTIMAL: sol = mod.getAttr("xn", x_l) if mod.status == GRB.Status.OPTIMAL: list_sol.append(np.array([sol[l] for l in range(n)])) # else: # list_sol.append(None) return list_sol