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 initialize_model(cost_matrix, cutoff, model=None): #Add dummy detection cost_matrix = np.insert(cost_matrix, 0, np.ones(cost_matrix.shape[0]) * cutoff, axis=1) M, N = cost_matrix.shape if model is None: model = Model() else: model.remove(model.getVars()) model.remove(model.getConstrs()) model.setParam('OutputFlag', False) # y = [] # for i in range(M): # y.append([]) # for j in range(N): # y[i].append(m.addVar(vtype=GRB.BINARY, name = 'y_%d%d'%(i,j))) y = model.addVars(M, N, vtype=GRB.BINARY, name='y') model.setObjective( quicksum( quicksum([y[i, j] * cost_matrix[i][j] for j in range(N)]) for i in range(M)), GRB.MINIMIZE) # for i in range(M): model.addConstrs( (quicksum(y[i, j] for j in range(N)) == 1 for i in range(M)), name='constraint for track') # for j in range(1,N): model.addConstrs( (quicksum(y[i, j] for i in range(M)) <= 1 for j in range(1, N)), name='constraint for detection') y = list(y.values()) return model, M, N, y
def solve_lp_knapsack_gurobi(scores, costs, budget): from gurobipy import Model, LinExpr, GRB n = len(scores) # Create a new model. m = Model("lp_knapsack") # Create variables. for i in range(n): m.addVar(lb=0.0, ub=1.0) m.update() vars = m.getVars() # Set objective. obj = LinExpr() for i in range(n): obj += scores[i] * vars[i] m.setObjective(obj, GRB.MAXIMIZE) # Add constraint. expr = LinExpr() for i in range(n): expr += costs[i] * vars[i] m.addConstr(expr, GRB.LESS_EQUAL, budget) # Optimize. m.optimize() assert m.status == GRB.OPTIMAL x = np.zeros(n) for i in range(n): x[i] = vars[i].x return x
def TWTgurobi(): jobs = tuple(range(1,5)) jobPairs = [(i,j) for i in jobs for j in jobs if i < j] # job_id as keys and weight as content weight = dict(zip(jobs, (4,3,4,5))) duration = dict(zip(jobs, (12,8,15,9))) deadline = dict(zip(jobs, (16,26,25,27))) # Big M for modeling M = sum(duration.values()) try: m = Model('TWTexample') x = m.addVars(jobPairs, vtype=GRB.BINARY, name='x') startTime = m.addVars(jobs, name='startTime') tardiness = m.addVars(jobs, name='tardiness') m.setObjective(quicksum([weight[j]*tardiness[j] for j in jobs]), GRB.MINIMIZE) m.addConstrs((startTime[j] >= startTime[i]+duration[i]-M*(1-x[i,j]) for(i,j) in jobPairs), 'NoOverplap1') m.addConstrs((startTime[i] >= startTime[j]+duration[j]-M*x[i,j] for(i,j) in jobPairs), 'NoOverplap2') m.addConstrs((tardiness[j] >= startTime[j]+duration[j]-deadline[j] for j in jobs), 'Deadline') m.optimize() if m.status == GRB.Status.INF_OR_UNBD: m.setParam(GRB.Param.DualReductions, 0) m.optimize() if m.status == GRB.Status.OPTIMAL: for v in m.getVars(): print('%s:\t%g' %(v.varName, v.x)) print('Objective:\t%g' % m.objVal) else: statstr = StatusDict[m.status] print('Optimization was stopped with status %s' %statstr) except GurobiError as e: print('Error code '+str(e.errno)+': '+str(e))
def main(): try: (sizes, cs, aovs, ems) = loadData('./data.csv') cs = cs[:7] + cs[12:13] + cs[18:19] aovs = aovs[:7] + aovs[12:13] + aovs[18:19] # ems = fixEms(ems) # Create a new model m = Model("mip1") # Create variables vars = createVariables(m) # Integrate new variables m.update() # maximize \sum_{i=1}^{2096}sizes_i\sum_{j=1}^{24}cs_j*aov_j # Set objective m.setObjective(sum([sum([cs[i][j]*aovs[i][j]*vars[i][j] for i in range(ncategory)])*sizes[j] for j in range(nrecords)]), GRB.MAXIMIZE) # c1,c2,c3,c4,c5,c6,c7,c42,c64 # v0,v1,v2,v3,v4,v6,v6,v7, v8 # Add constraints: sum([vars[7][j]+vars[8][j]+vars[9][j] for j in range(nrecords)]) == sum([vars[0][j] for j in range(nrecords)]) m.addConstr(sum([vars[7][j] for j in range(nrecords)]) <= sum([vars[3][j] for j in range(nrecords)])) m.addConstr(sum([vars[8][j] for j in range(nrecords)]) <= sum([vars[5][j] for j in range(nrecords)])) m.addConstr(sum([vars[7][j] for j in range(nrecords)]) <= 18000) m.addConstr(sum([vars[7][j] for j in range(nrecords)]) >= 8000) m.addConstr(sum([vars[8][j] for j in range(nrecords)]) <= 6000) m.addConstr(sum([vars[8][j] for j in range(nrecords)]) >= 3000) m.addConstr(sum([vars[0][j] for j in range(nrecords)]) <= 25000) m.addConstr(sum([vars[0][j] for j in range(nrecords)]) >= 10000) m.addConstr(sum([vars[1][j] for j in range(nrecords)]) <= 8500) m.addConstr(sum([vars[1][j] for j in range(nrecords)]) >= 5000) m.addConstr(sum([vars[2][j] for j in range(nrecords)]) <= 8000) m.addConstr(sum([vars[2][j] for j in range(nrecords)]) >= 1500) m.addConstr(sum([vars[3][j] for j in range(nrecords)]) <= 10000) m.addConstr(sum([vars[3][j] for j in range(nrecords)]) >= 4000) m.addConstr(sum([vars[4][j] for j in range(nrecords)]) <= 8000) m.addConstr(sum([vars[4][j] for j in range(nrecords)]) >= 1500) m.addConstr(sum([vars[5][j] for j in range(nrecords)]) <= 20000) m.addConstr(sum([vars[5][j] for j in range(nrecords)]) >= 9000) m.addConstr(sum([vars[6][j] for j in range(nrecords)]) <= 15000) m.addConstr(sum([vars[6][j] for j in range(nrecords)]) >= 8000) for j in range(nrecords): m.addConstr(sum([vars[i][j] for i in range(0, 9)]) <= 3*sizes[j]) m.update() m.optimize() m.write("./macy.lp") for v in m.getVars(): print v.varName, v.x print 'Obj:', m.objVal except GurobiError: print 'Error reported: {}'.format(GurobiError)
def repair(self): this = self data_size = self.instance.size() def get_cj(j, x_vars): x_list = [x_vars[i][j] for i in xrange(data_size)] multi_list = list() for k in xrange(data_size): if k not in self.neighbor_map[j]: continue for i in xrange(data_size): multi_list.append(x_vars[i][k]) return quicksum(x_list) + quicksum(multi_list) def build_objective(x_vars): result = list() for i, record1 in enumerate(this.instance.data): for j, record2 in enumerate(this.instance.data): result.append(record1.distance(record2) * x_vars[i][j]) return result try: m = Model('mip1') x = list() y = list() for i, record in enumerate(self.instance.data): variables = [m.addVar(vtype=GRB.BINARY, name='x_%d_%d' % (i, j)) for j in xrange(data_size)] x.append(variables) y.append(m.addVar(vtype=GRB.BINARY, name='y_%d' % i)) m.addConstr(quicksum(x[i]) == 1, name='sum_%d' % i) for j, record in enumerate(self.instance.data): c_j = get_cj(j, x) m.addConstr(c_j - self.k * y[j] >= 0, name='constr_1_%d' % j) m.addConstr(y[j] * data_size - c_j >= 1 - self.k, name='constr_2_%d' % j) m.addConstr(y[j] + quicksum([y[i] if i in self.neighbor_map[j] else 0 for i in xrange(data_size)]) - quicksum([x[k][j] for k in xrange(data_size)]) / float(data_size) >= 0, name='constr_3_%d' % j) m.setObjective(quicksum(build_objective(x))) print '---- Begin to solve the ILP ----' m.optimize() repair_result = list() for v in m.getVars(): if v.varName.startswith('x') and v.x == 1: _, record_id, candidate_id = v.varName.split('_') repair_result.append((int(record_id), int(candidate_id))) print('Obj: %g' % m.objVal) return repair_result except GurobiError as e: print('Error code ' + str(e.errno) + ": " + str(e)) except AttributeError: import traceback; traceback.print_exc() print('Encountered an attribute error')
def netshield(adj, k, al_out=None): """ Perform the NetShield algorithm with QP solver Parameters ---------- A: 2D numpy array Adjancency matrix of graph to be immunised k: Integer Number of nodes to remove from graph al_out: Integer Optional, already removed nodes or nodes that should be ignored. Not intended for direct callers Returns -------- Tuple of 1D numpy array and float First is indices of selected nodes Second is eigendrop """ eigval, eigvec = utils.get_max_eigen(adj) n = adj.shape[0] if k == 1: m = Model("lp") else: m = Model("qp") m.setParam('OutputFlag', False) variables = [ m.addVar(name="x_{}".format(i), vtype=GRB.BINARY) for i in range(n) ] obj = _build_objective_qd(adj, variables, eigval, eigvec) const = quicksum(variables) == k m.setObjective(obj, GRB.MAXIMIZE) m.addConstr(const, "c1") if al_out is not None: for c in np.where(al_out)[0]: m.addConstr(variables[c] == 0) m.optimize() out = np.array([i for i, v in enumerate(m.getVars()) if v.x == 1]) adj_pert = np.array(adj) adj_pert[out, :] = 0 adj_pert[:, out] = 0 eig_drop = eigval - utils.get_max_eigenvalue(adj_pert) return out, eig_drop
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 TWTgurobi(): # TWT Problem Data jobs = tuple([i + 1 for i in range(4)]) jobPairs = [(i, j) for i in jobs for j in jobs if i < j] weight = dict(zip(jobs, (4, 5, 3, 5))) duration = dict(zip(jobs, (12, 8, 15, 9))) deadline = dict(zip(jobs, (16, 26, 25, 27))) M = sum(duration.values()) try: # Create a new model m = Model('TWTexample') # Create variables # x[(i,j)] = 1 if i << j, else j >> i x = m.addVars(jobPairs, vtype=GRB.BINARY, name='x') startTime = m.addVars(jobs, name='startTime') tardiness = m.addVars(jobs, name='tardiness') # Set objective function m.setObjective(quicksum([weight[j] * tardiness[j] for j in jobs]), GRB.MINIMIZE) # Add constraints m.addConstrs( (startTime[j] >= startTime[i] + duration[i] - M * (1 - x[(i, j)]) for (i, j) in jobPairs), 'NoOverlap1') m.addConstrs( (startTime[i] >= startTime[j] + duration[j] - M * x[(i, j)] for (i, j) in jobPairs), 'NoOverlap2') m.addConstrs((tardiness[j] >= startTime[j] + duration[j] - deadline[j] for j in jobs), 'Deadline') # Solve model m.optimize() if m.status == GRB.Status.INF_OR_UNBD: # Disable dual reductions to determine solve status m.setParam(GRB.Param.DualReductions, 0) m.optimize() # Display solution if m.status == GRB.Status.OPTIMAL: for v in m.getVars(): print('%s:\t%g' % (v.varName, v.x)) print('Objective:\t%g' % m.objVal) else: statstr = StatusDict[m.status] print('Optimization was stopped with status %s' % statstr) except GurobiError as e: print('Error code ' + str(e.errno) + ": " + str(e))
def _upper_t(self, g, key, lower=None): """Solves the uppper bound at time t. @param g: subgraph of bipartite graph at time t. @param key: the resource name. @return: the uppper bound at t. """ print(lower) # Compute the maximum weighted independent set. try: # Create a new model m = Model() m.NumObj = 2 variables = m.addVars(range(len(g.vs)), vtype=GRB.CONTINUOUS, ub=1.0, lb=0.0) for e in g.es: m.addConstr(variables[e.source]+variables[e.target] <= 1) if lower is not None: m.addConstr(sum(variables[v] * g.vs[v][key] for v in xrange(len(g.vs))) <= lower) m.ModelSense = GRB.MAXIMIZE m.setParam(GRB.Param.ObjNumber, 0) m.ObjNPriority = 1 m.setAttr(GRB.Attr.ObjN, variables, map(abs, g.vs[key])) m.ModelSense = GRB.MAXIMIZE m.setParam(GRB.Param.ObjNumber, 1) m.ObjNPriority = 0 m.setAttr(GRB.Attr.ObjN, variables, [-self.stp.shortest_path_pair("x0", x) - self.stp.shortest_path_pair(x, "x0") for x in g.vs["name"]]) m.optimize() for v in m.getVars(): print('%s %g' % (v.varName, v.x)) print('Obj: %g' % m.objVal) return [x.x for x in m.getVars()] except GurobiError as e: print('Error code ' + str(e.errno) + ": " + str(e))
def generateInstance(self): # Check that variables have been intialized correctly if (not self.planes) or (self.n == 0) or (self.T == 0): logging.error( 'Store is not initialized correctly. Check for completeness of input-file.' ) return None model = Model("PlaneSolver") """ r: Earliest landing possibility b: Best landing d: latest landing g: penalty for each time earlier from best h: penalty for each time later from best s_ij: if i lands before j: s needs to pass in time x_i: Landing time for i p_i: positive divertion from bi n_i: negative divertion from bi """ bigM = max([max(x["s"]) for x in self.planes]) logging.debug("Using bigM punishment: " + str(bigM)) # generate Variables x = {} # Landing time p = {} # Positive divertion from optimal landing time n = {} # Negative divertion from optimal landing time s = {} # 1 iff plane i lands before j + buffer is invalid s1 = {} # for these, see constraints s2 = {} h1 = {} h2 = {} for i in range(len(self.planes)): x[i] = model.addVar(name="x_%d" % (i + 1), vtype="i", lb=self.planes[i]["r"], ub=self.planes[i]["d"]) p[i] = model.addVar(name="p_%d" % (i + 1), vtype="i", obj=self.planes[i]["h"], lb=0, ub=self.planes[i]["d"] - self.planes[i]["b"]) n[i] = model.addVar(name="n_%d" % (i + 1), vtype="i", obj=self.planes[i]["g"], lb=0, ub=self.planes[i]["b"] - self.planes[i]["r"]) for j in range(len(self.planes)): s[i, j] = model.addVar(name="s_%d_%d" % (i + 1, j + 1), vtype="b", obj=bigM, lb=0, ub=1) s1[i, j] = model.addVar(name="s1_%d_%d" % (i + 1, j + 1), vtype="b", obj=0, lb=0, ub=1) s2[i, j] = model.addVar(name="s2_%d_%d" % (i + 1, j + 1), vtype="b", obj=0, lb=0, ub=1) h1[i, j] = model.addVar(name="h1_%d_%d" % (i + 1, j + 1), vtype="i", obj=0, lb=0) h2[i, j] = model.addVar(name="h2_%d_%d" % (i + 1, j + 1), vtype="i", obj=0, lb=0) model.modelSense = GRB.MINIMIZE model.update() for y in model.getVars(): if y.ub < 10000: logging.debug("%10s\t[%5d:%5d]\tobj %4d", y.varName, y.lb, y.ub, y.obj) # Constraints for i in range(len(self.planes)): logging.debug("{} == {} + {} - {}".format(x[i].varName, self.planes[i]["b"], p[i].varName, n[i].varName)) model.addConstr(x[i] == self.planes[i]["b"] + p[i] - n[i]) for j in range(len(self.planes)): if j == i: continue # model.addConstr(x[j] - x[i] ) # Force s = s1 AND s2 model.addConstr(s[i, j] <= s1[i, j]) model.addConstr(s[i, j] <= s2[i, j]) model.addConstr(s[i, j] >= s1[i, j] + s2[i, j] - 1) # s2 == xj - xi > 0 logging.debug("{}\t <= {}\t - {}\t - {}\t".format( s2[i, j].varName, x[j].varName, x[i].varName, h1[i, j].varName)) model.addConstr(s2[i, j] <= x[j] - x[i] + h1[i, j]) logging.debug("{}\t >= 1\t".format(h1[i, j].varName)) model.addConstr(h1[i, j] >= 1) logging.debug("{}\t - {}\t + {}\t <= {}\t*{}\t".format( x[j].varName, x[i].varName, h1[i, j].varName, s2[i, j].varName, bigM)) model.addConstr(x[j] - x[i] + h1[i, j] <= s2[i, j] * bigM) # s1 == xi + sij - xj > 0 logging.debug("{}\t + {}\t - {}\t >= {}\t".format( x[i].varName, self.planes[i]["s"][j], x[j].varName, s1[i, j].varName)) model.addConstr(s1[i, j] <= x[i] + self.planes[i]["s"][j] - x[j] + h2[i, j]) logging.debug("{}\t + {}\t - {}\t <= {}\t*{}\t".format( x[i].varName, self.planes[i]["s"][j], x[j].varName, s1[i, j].varName, bigM)) model.addConstr( x[i] + self.planes[i]["s"][j] - x[j] <= s1[i, j] * bigM) # solve it model.optimize() # Debugging printouts dbgStrs = {} for y in model.getVars(): if y.varName[0:2] not in dbgStrs: dbgStrs[y.varName[0:2]] = [] dbgStrs[y.varName[0:2]].append( "%8s = %4s [%4s]" % (y.varName, int(y.x), int(y.x * y.obj) if y.obj else "")) for x in dbgStrs: dbgStrs[x].sort() while dbgStrs: printed = False keys = [x for x in dbgStrs.keys()] keys.sort() logStr = "" for x in keys: if dbgStrs[x]: logStr += dbgStrs[x][0] dbgStrs[x] = dbgStrs[x][1::] printed = True else: logStr += " " * 22 logging.debug(logStr) if not printed: break self.model = model
def _optimize_gurobi(cobra_model, new_objective=None, objective_sense='maximize', min_norm=0, the_problem=None, tolerance_optimality=1e-6, tolerance_feasibility=1e-6, tolerance_barrier=None, tolerance_integer=1e-9, error_reporting=None, print_solver_time=False, copy_problem=False, lp_method=0, relax_b=None, quad_precision=False, quadratic_component=None, reuse_basis=True, lp_parallel=None, update_problem_reaction_bounds=True): """Uses the gurobi (http://gurobi.com) optimizer to perform an optimization on cobra_model for the objective_coefficients in cobra_model._objective_coefficients based on objective sense. cobra_model: A cobra.Model object new_objective: Reaction, String, or Integer referring to a reaction in cobra_model.reactions to set as the objective. Currently, only supports single objective coeffients. Will expand to include mixed objectives. objective_sense: 'maximize' or 'minimize' min_norm: not implemented the_problem: None or a problem object for the specific solver that can be used to hot start the next solution. tolerance_optimality: Solver tolerance for optimality. tolerance_feasibility: Solver tolerance for feasibility. quad_precision: Boolean. Whether or not to used quad precision in calculations error_reporting: None or True to disable or enable printing errors encountered when trying to find the optimal solution. print_solver_time: False or True. Indicates if the time to calculate the solution should be displayed. quadratic_component: None or scipy.sparse.dok of dim(len(cobra_model.reactions),len(cobra_model.reactions)) If not None: Solves quadratic programming problems for cobra_models of the form: minimize: 0.5 * x' * quadratic_component * x + cobra_model._objective_coefficients' * x such that, cobra_model._lower_bounds <= x <= cobra_model._upper_bounds cobra_model._S * x (cobra_model._constraint_sense) cobra_model._b NOTE: When solving quadratic problems it may be necessary to disable quad_precision and use lp_method = 0 for gurobi. reuse_basis: Boolean. If True and the_problem is a model object for the solver, attempt to hot start the solution. update_problem_reaction_bounds: Boolean. Set to True if you're providing the_problem and you've modified reaction bounds on your cobra_model since creating the_problem. Only necessary for CPLEX lp_parallel: Not implemented lp.optimize() with Salmonella model: cold start: 0.063 seconds hot start: 0.057 seconds (Slow due to copying the LP) """ if relax_b is not None: raise Exception('Need to reimplement constraint relaxation') from numpy import array, nan, zeros #TODO: speed this up if objective_sense == 'maximize': objective_sense = -1 else: objective_sense = 1 from gurobipy import Model, LinExpr, GRB, QuadExpr sense_dict = {'E': GRB.EQUAL, 'L': GRB.LESS_EQUAL, 'G': GRB.GREATER_EQUAL} from cobra.flux_analysis.objective import update_objective from cobra.solvers.legacy import status_dict, variable_kind_dict variable_kind_dict = eval(variable_kind_dict['gurobi']) status_dict = eval(status_dict['gurobi']) #Update objectives if they are new. if new_objective and new_objective != 'update problem': update_objective(cobra_model, new_objective) #Create a new problem if not the_problem or the_problem in ['return', 'setup'] or \ not isinstance(the_problem, Model): lp = Model("cobra") lp.Params.OutputFlag = 0 lp.Params.LogFile = '' # Create variables #TODO: Speed this up variable_list = [lp.addVar(lb=float(x.lower_bound), ub=float(x.upper_bound), obj=objective_sense*float(x.objective_coefficient), name=x.id, vtype=variable_kind_dict[x.variable_kind]) for x in cobra_model.reactions] reaction_to_variable = dict(zip(cobra_model.reactions, variable_list)) # Integrate new variables lp.update() #Set objective to quadratic program if quadratic_component is not None: if not hasattr(quadratic_component, 'todok'): raise Exception('quadratic component must be a scipy.sparse type array') quadratic_objective = QuadExpr() for (index_0, index_1), the_value in quadratic_component.todok().items(): quadratic_objective.addTerms(the_value, variable_list[index_0], variable_list[index_1]) lp.setObjective(quadratic_objective, sense=objective_sense) #Constraints are based on mass balance #Construct the lin expression lists and then add #TODO: Speed this up as it takes about .18 seconds #HERE for the_metabolite in cobra_model.metabolites: constraint_coefficients = [] constraint_variables = [] for the_reaction in the_metabolite._reaction: constraint_coefficients.append(the_reaction._metabolites[the_metabolite]) constraint_variables.append(reaction_to_variable[the_reaction]) #Add the metabolite to the problem lp.addConstr(LinExpr(constraint_coefficients, constraint_variables), sense_dict[the_metabolite._constraint_sense.upper()], the_metabolite._bound, the_metabolite.id) else: #When reusing the basis only assume that the objective coefficients or bounds can change if copy_problem: lp = the_problem.copy() else: lp = the_problem if not reuse_basis: lp.reset() for the_variable, the_reaction in zip(lp.getVars(), cobra_model.reactions): the_variable.lb = float(the_reaction.lower_bound) the_variable.ub = float(the_reaction.upper_bound) the_variable.obj = float(objective_sense*the_reaction.objective_coefficient) if the_problem == 'setup': return lp if print_solver_time: start_time = time() lp.update() lp.setParam("FeasibilityTol", tolerance_feasibility) lp.setParam("OptimalityTol", tolerance_optimality) if tolerance_barrier: lp.setParam("BarConvTol", tolerance_barrier) if quad_precision: lp.setParam("Quad", 1) lp.setParam("Method", lp_method) #Different methods to try if lp_method fails the_methods = [0, 2, 1] if lp_method in the_methods: the_methods.remove(lp_method) if not isinstance(the_problem, Model): lp.optimize() if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': #Try to find a solution using a different method lp.setParam("MarkowitzTol", 1e-2) for lp_method in the_methods: lp.setParam("Method", lp_method) lp.optimize() if status_dict[lp.status] == 'optimal': break else: lp.setParam("TimeLimit", 0.6) lp.optimize() lp.setParam("TimeLimit", "default") if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': lp.setParam("MarkowitzTol", 1e-2) #Try to find a solution using a different method for lp_method in the_methods: lp.setParam("Method", lp_method) lp.optimize() if status_dict[lp.status] == 'optimal': break if status_dict[lp.status] != 'optimal': lp = optimize_gurobi(cobra_model, new_objective=new_objective, objective_sense=objective_sense, min_norm=min_norm, the_problem=None, print_solver_time=print_solver_time)['the_problem'] if print_solver_time: print 'optimize time: %f'%(time() - start_time) x_dict = {} y_dict = {} y = None if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status == 'optimal': objective_value = objective_sense*lp.ObjVal [x_dict.update({v.VarName: v.X}) for v in lp.getVars()] x = array([x_dict[v.id] for v in cobra_model.reactions]) if lp.isMIP: y = y_dict = None #MIP's don't have duals else: [y_dict.update({c.ConstrName: c.Pi}) for c in lp.getConstrs()] y = array([y_dict[v.id] for v in cobra_model.metabolites]) else: y = y_dict = x = x_dict = None objective_value = None if error_reporting: print 'gurobi failed: %s'%lp.status the_solution = Solution(objective_value, x=x, x_dict=x_dict, y=y, y_dict=y_dict, status=status) solution = {'the_problem': lp, 'the_solution': the_solution} return solution
class LinearProgram: def __init__(self, counters_task): self.model = Model(counters_task.instance_name + '.lp') # LP Vars self.variables = [] self.make_model_vars(counters_task) self.model.update() # LP Constraints self.constraints = [] self.make_model_constraints(counters_task) self.model.update() self.goal_constraints = set() def copy(self): from copy import deepcopy new_lp = LinearProgram() new_lp.variables = deepcopy(self.variables) new_lp.goal_constraints = deepcopy(self.goal_constraints) new_lp.model = self.model.copy() new_lp.constraints = [] for index, ext_constraint in enumerate(self.constraints): new_lp.constraints.append((deepcopy(ext_constraint[0]), new_lp.model.getConstrs()[index])) return new_lp def make_model_vars(self, task): for x_c in task.counter_values: x_c_2 = self.model.addVar(name=x_c.name, lb=min(x_c.domain), ub=max(x_c.domain), vtype=GRB.INTEGER) self.variables.append(x_c_2) def make_model_constraints(self, task): for i in range(0, len(self.variables)): x = task.counter_values[i] x2 = self.variables[i] # Equivalence constraints for v in x.domain: c = self.model.addConstr(x2 == v) self.constraints.append(([(x.index, v)], c)) # Bounds constraints gt_zero = self.model.addConstr(x2 >= 0) lt_max = self.model.addConstr(x2, GRB.LESS_EQUAL, task.max_value) self.constraints.append(([], gt_zero)) self.constraints.append(([], lt_max)) def make_goal_constraints(self, goal_condition): goal_constraints = [] for cond, lhs, rhs in goal_condition: x_lhs = None x_rhs = None for x in self.model.getVars(): if lhs in x.getAttr('VarName'): x_lhs = x if rhs in x.getAttr('VarName'): x_rhs = x assert x_lhs is not None assert x_rhs is not None c = None if cond == '<': c = ([], self.model.addConstr(x_lhs <= x_rhs)) self.constraints.append(c) goal_constraints.append(len(self.constraints) - 1) c = ([], self.model.addConstr(x_lhs <= x_rhs - 1)) self.constraints.append(c) goal_constraints.append(len(self.constraints) - 1) elif cond == '>': c = ([], self.model.addConstr(x_lhs >= x_rhs)) self.constraints.append(c) goal_constraints.append(len(self.constraints) - 1) c = ([], self.model.addConstr(x_lhs - 1 >= x_rhs)) self.constraints.append(c) goal_constraints.append(len(self.constraints) - 1) elif cond == '=': c = ([], self.model.addConstr(x_lhs == x_rhs)) self.constraints.append(c) goal_constraints.append(len(self.constraints) - 1) else: assert False self.model.update() self.goal_constraints = set(goal_constraints) return self.goal_constraints
def generateInstance(self): # Check that variables have been intialized correctly if (not self.planes) or (self.n == 0) or (self.T == 0): logging.error('Store is not initialized correctly. Check for completeness of input-file.') return None model = Model("PlaneSolver") """ r: Earliest landing possibility b: Best landing d: latest landing g: penalty for each time earlier from best h: penalty for each time later from best s_ij: if i lands before j: s needs to pass in time x_i: Landing time for i p_i: positive divertion from bi n_i: negative divertion from bi """ bigM = max([max(x["s"]) for x in self.planes]) logging.debug("Using bigM punishment: " + str(bigM)) # generate Variables x = {} # Landing time p = {} # Positive divertion from optimal landing time n = {} # Negative divertion from optimal landing time s = {} # 1 iff plane i lands before j + buffer is invalid s1 = {} # for these, see constraints s2 = {} h1 = {} h2 = {} for i in range(len(self.planes)): x[i] = model.addVar(name="x_%d" % (i+1), vtype="i", lb=self.planes[i]["r"], ub=self.planes[i]["d"]) p[i] = model.addVar(name="p_%d" % (i+1), vtype="i", obj=self.planes[i]["h"], lb=0, ub=self.planes[i]["d"] - self.planes[i]["b"]) n[i] = model.addVar(name="n_%d" % (i+1), vtype="i", obj=self.planes[i]["g"], lb=0, ub=self.planes[i]["b"] - self.planes[i]["r"]) for j in range(len(self.planes)): s[i, j] = model.addVar(name="s_%d_%d" % (i+1, j+1), vtype="b", obj=bigM, lb=0, ub=1) s1[i, j] = model.addVar(name="s1_%d_%d" % (i+1, j+1), vtype="b", obj=0, lb=0, ub=1) s2[i, j] = model.addVar(name="s2_%d_%d" % (i+1, j+1), vtype="b", obj=0, lb=0, ub=1) h1[i, j] = model.addVar(name="h1_%d_%d" % (i+1, j+1), vtype="i", obj=0, lb=0) h2[i, j] = model.addVar(name="h2_%d_%d" % (i+1, j+1), vtype="i", obj=0, lb=0) model.modelSense = GRB.MINIMIZE model.update() for y in model.getVars(): if y.ub < 10000: logging.debug("%10s\t[%5d:%5d]\tobj %4d", y.varName, y.lb, y.ub, y.obj) # Constraints for i in range(len(self.planes)): logging.debug("{} == {} + {} - {}".format(x[i].varName, self.planes[i]["b"], p[i].varName, n[i].varName)) model.addConstr(x[i] == self.planes[i]["b"] + p[i] - n[i]) for j in range(len(self.planes)): if j == i: continue # model.addConstr(x[j] - x[i] ) # Force s = s1 AND s2 model.addConstr(s[i, j] <= s1[i, j]) model.addConstr(s[i, j] <= s2[i, j]) model.addConstr(s[i, j] >= s1[i, j] + s2[i, j] - 1) # s2 == xj - xi > 0 logging.debug("{}\t <= {}\t - {}\t - {}\t".format(s2[i, j].varName, x[j].varName, x[i].varName, h1[i, j].varName)) model.addConstr(s2[i, j] <= x[j] - x[i] + h1[i, j]) logging.debug("{}\t >= 1\t".format(h1[i, j].varName)) model.addConstr(h1[i, j] >= 1) logging.debug("{}\t - {}\t + {}\t <= {}\t*{}\t".format(x[j].varName, x[i].varName, h1[i, j].varName, s2[i, j].varName, bigM)) model.addConstr(x[j] - x[i] + h1[i, j] <= s2[i, j]*bigM) # s1 == xi + sij - xj > 0 logging.debug("{}\t + {}\t - {}\t >= {}\t".format(x[i].varName, self.planes[i]["s"][j], x[j].varName, s1[i, j].varName)) model.addConstr(s1[i, j] <= x[i] + self.planes[i]["s"][j] - x[j] + h2[i, j]) logging.debug("{}\t + {}\t - {}\t <= {}\t*{}\t".format(x[i].varName, self.planes[i]["s"][j], x[j].varName, s1[i, j].varName, bigM)) model.addConstr(x[i] + self.planes[i]["s"][j] - x[j] <= s1[i, j]*bigM) # solve it model.optimize() # Debugging printouts dbgStrs = {} for y in model.getVars(): if y.varName[0:2] not in dbgStrs: dbgStrs[y.varName[0:2]] = [] dbgStrs[y.varName[0:2]].append("%8s = %4s [%4s]" % (y.varName, int(y.x), int(y.x*y.obj) if y.obj else "")) for x in dbgStrs: dbgStrs[x].sort() while dbgStrs: printed = False keys = [x for x in dbgStrs.keys()] keys.sort() logStr = "" for x in keys: if dbgStrs[x]: logStr += dbgStrs[x][0] dbgStrs[x] = dbgStrs[x][1::] printed = True else: logStr += " "*22 logging.debug(logStr) if not printed: break self.model = model
def make_model(strong_inequalities=False, relax=False, callback=False, hascapacity=1): # Relabel data commodities = data.commodities arcs = data.arcs capacity = data.capacity variable_cost = data.variable_cost fixed_cost = data.fixed_cost nodes = data.nodes demand = data.demand periods = data.periods # Create optimization model env = Env(logfilename="") m = Model('multi-period-netflow', env) # Create variables flow, arc_open = {}, {} for t in periods: for i, j in arcs: arc_open[i, j, t] = m.addVar(vtype=GRB.BINARY, lb=0.0, ub=1.0, obj=fixed_cost[(i, j), t], name='open_{0:d}_{1:d}_{2:d}'.format( i, j, t)) for h in commodities: origin, destination = [ key_val[1] for key_val in demand.keys() if key_val[0] == h ][0] upper = capacity[i, j] if has_capacity else demand[(h, (origin, destination), t)] flow[h, i, j, t] = m.addVar(obj=variable_cost[i, j], name='flow_{0:d}_{1:d}_{2:d}_{3:d}'.format( h, i, j, t)) m.update() # Arc capacity constraints and unique arc setup constraints constrs = [] for (i, j) in arcs: m.addConstr( quicksum(arc_open[i, j, l] for l in range(1, len(data.periods) + 1)) <= 1, 'unique_setup{0:d}_{1:d}'.format(i, j)) for t in periods: if not hascapacity: capacity[i, j] = sum(demand[i] for i in demand.keys() if i[2] == t) m.addConstr( quicksum(flow[h, i, j, t] for h in commodities) <= capacity[i, j] * quicksum(arc_open[i, j, s] for s in xrange(1, t + 1)), 'cap_{0:d}_{1:d}_{2:d}'.format(i, j, t)) if not callback and strong_inequalities: for (commodity, (origin, destination), period) in demand: if period == t: constrs.append( m.addConstr( flow[commodity, i, j, t] <= demand[commodity, (origin, destination), period] * quicksum(arc_open[i, j, l] for l in range(1, t + 1)), name='strong_com{0:d}_{1:d}-{2:d}_per{3:d}'. format(commodity, i, j, t))) # Flow conservation constraints for (commodity, (origin, destination), period) in demand: for j in nodes: if j == origin: node_demand = demand[commodity, (origin, destination), period] elif j == destination: node_demand = -demand[commodity, (origin, destination), period] else: node_demand = 0 h = commodity m.addConstr( -quicksum(flow[h, i, j, period] for i, j in arcs.select('*', j)) + quicksum(flow[h, j, k, period] for j, k in arcs.select(j, '*')) == node_demand, 'node_{0:d}_{1:d}_{2:d}'.format(h, j, period)) m.update() # Compute optimal solution m.setParam("TimeLimit", 7200) # m.params.NodeLimit = 1 # m.params.cuts = 0 # m.setParam("Threads", 2) m.setAttr('Lazy', constrs, [3] * len(constrs)) # m.write("eyes.lp") # try: if strong_inequalities: if not relax: # m.setParam("NodeLimit", 1000000) # m.params.Cuts = 0 if callback: print 'callback in action! :)' m.params.preCrush = 1 m.update() m._vars = m.getVars() m.optimize(strong_inequalities_callback) else: m.optimize(time_callback) else: m = m.relax() m.optimize(time_callback) else: m.optimize(time_callback) if PRINT_VARS: for var in m.getVars(): if str(var.VarName[0]) == 'f' and var.X > 0.0001: name = var.VarName.split('_') print 'arc: \t {} \t commodity: {} \t period: {} \t value: \t {}'.format( (int(name[2]), int(name[3])), int(name[1]), int(name[4]), var.x) # Grab the positive flows and see how many variables open during the first period positive_flows = [ var for var in m.getVars() if var.VarName[0] == 'o' and var.X > 0.5 ] first_period_arcs = sum([ var.X for var in positive_flows if int(var.VarName.split('_')[3]) == 1 ]) print '% of arcs that open in first period: {}%'.format( 100 * first_period_arcs / len(positive_flows)) print '% of arcs that are utilized: {}%'.format( (100. * len(positive_flows)) / len(data.arcs)) objective = m.getObjective().getValue() fixed_cost_percentage = sum([ fixed_cost[(i, j), t] * arc_open[i, j, t].X for i, j in data.arcs for t in data.periods ]) / objective print 'Fixed cost percentage: {}%'.format(fixed_cost_percentage * 100.) for var in m.getVars(): if str(var.VarName[0]) == 'o' and var.X > 0.0001: name = var.VarName.split('_') print 'Arc: \t {} \t Period: {} \t Value: \t {}'.format( (int(name[1]), int(name[2])), int(name[3]), var.X) # m.write('trial2.lp') except: if m.status == GRB.status.INFEASIBLE and DEBUG: print 'Infeasible model. Computing IIS..' m.computeIIS() m.write('trial.ilp')
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()
m.addConstr(v[i] >= 0, name="l" + i) m.addConstr(v[i] <= demand[int(i[1])], name="u" + i) #set objecrive fucntion to be sum of all y variables obj = 0 for i in v: if i[0] == 'y': obj += v[i] # print(obj) m.setObjective(obj, GRB.MAXIMIZE) #optimize model function m.optimize() #print results status_code = { 1: 'LOADED', 2: 'OPTIMAL', 3: 'INFEASIBLE', 4: 'INF_OR_UNBD', 5: 'UNBOUNDED' } status = m.status print('The optimization status is {}'.format(status_code[status])) if status == 2: # Retrieve variables value print('Optimal solution:') for v in m.getVars(): print('%s = %g' % (v.varName, v.x)) print('Optimal objective value:\n{}'.format(m.objVal))
def _optimize_gurobi(cobra_model, new_objective=None, objective_sense='maximize', min_norm=0, the_problem=None, tolerance_optimality=1e-6, tolerance_feasibility=1e-6, tolerance_barrier=None, tolerance_integer=1e-9, error_reporting=None, print_solver_time=False, copy_problem=False, lp_method=0, relax_b=None, quad_precision=False, quadratic_component=None, reuse_basis=True, lp_parallel=None, update_problem_reaction_bounds=True): """Uses the gurobi (http://gurobi.com) optimizer to perform an optimization on cobra_model for the objective_coefficients in cobra_model._objective_coefficients based on objective sense. cobra_model: A cobra.Model object new_objective: Reaction, String, or Integer referring to a reaction in cobra_model.reactions to set as the objective. Currently, only supports single objective coeffients. Will expand to include mixed objectives. objective_sense: 'maximize' or 'minimize' min_norm: not implemented the_problem: None or a problem object for the specific solver that can be used to hot start the next solution. tolerance_optimality: Solver tolerance for optimality. tolerance_feasibility: Solver tolerance for feasibility. quad_precision: Boolean. Whether or not to used quad precision in calculations error_reporting: None or True to disable or enable printing errors encountered when trying to find the optimal solution. print_solver_time: False or True. Indicates if the time to calculate the solution should be displayed. quadratic_component: None or scipy.sparse.dok of dim(len(cobra_model.reactions),len(cobra_model.reactions)) If not None: Solves quadratic programming problems for cobra_models of the form: minimize: 0.5 * x' * quadratic_component * x + cobra_model._objective_coefficients' * x such that, cobra_model._lower_bounds <= x <= cobra_model._upper_bounds cobra_model._S * x (cobra_model._constraint_sense) cobra_model._b NOTE: When solving quadratic problems it may be necessary to disable quad_precision and use lp_method = 0 for gurobi. reuse_basis: Boolean. If True and the_problem is a model object for the solver, attempt to hot start the solution. update_problem_reaction_bounds: Boolean. Set to True if you're providing the_problem and you've modified reaction bounds on your cobra_model since creating the_problem. Only necessary for CPLEX lp_parallel: Not implemented lp.optimize() with Salmonella model: cold start: 0.063 seconds hot start: 0.057 seconds (Slow due to copying the LP) """ if relax_b is not None: raise Exception('Need to reimplement constraint relaxation') from numpy import array, nan, zeros #TODO: speed this up if objective_sense == 'maximize': objective_sense = -1 else: objective_sense = 1 from gurobipy import Model, LinExpr, GRB, QuadExpr sense_dict = {'E': GRB.EQUAL, 'L': GRB.LESS_EQUAL, 'G': GRB.GREATER_EQUAL} from cobra.flux_analysis.objective import update_objective from cobra.solvers.legacy import status_dict, variable_kind_dict variable_kind_dict = eval(variable_kind_dict['gurobi']) status_dict = eval(status_dict['gurobi']) #Update objectives if they are new. if new_objective and new_objective != 'update problem': update_objective(cobra_model, new_objective) #Create a new problem if not the_problem or the_problem in ['return', 'setup'] or \ not isinstance(the_problem, Model): lp = Model("cobra") lp.Params.OutputFlag = 0 lp.Params.LogFile = '' # Create variables #TODO: Speed this up variable_list = [ lp.addVar(lb=float(x.lower_bound), ub=float(x.upper_bound), obj=objective_sense * float(x.objective_coefficient), name=x.id, vtype=variable_kind_dict[x.variable_kind]) for x in cobra_model.reactions ] reaction_to_variable = dict(zip(cobra_model.reactions, variable_list)) # Integrate new variables lp.update() #Set objective to quadratic program if quadratic_component is not None: if not hasattr(quadratic_component, 'todok'): raise Exception( 'quadratic component must be a scipy.sparse type array') quadratic_objective = QuadExpr() for (index_0, index_1), the_value in quadratic_component.todok().items(): quadratic_objective.addTerms(the_value, variable_list[index_0], variable_list[index_1]) lp.setObjective(quadratic_objective, sense=objective_sense) #Constraints are based on mass balance #Construct the lin expression lists and then add #TODO: Speed this up as it takes about .18 seconds #HERE for the_metabolite in cobra_model.metabolites: constraint_coefficients = [] constraint_variables = [] for the_reaction in the_metabolite._reaction: constraint_coefficients.append( the_reaction._metabolites[the_metabolite]) constraint_variables.append(reaction_to_variable[the_reaction]) #Add the metabolite to the problem lp.addConstr( LinExpr(constraint_coefficients, constraint_variables), sense_dict[the_metabolite._constraint_sense.upper()], the_metabolite._bound, the_metabolite.id) else: #When reusing the basis only assume that the objective coefficients or bounds can change if copy_problem: lp = the_problem.copy() else: lp = the_problem if not reuse_basis: lp.reset() for the_variable, the_reaction in zip(lp.getVars(), cobra_model.reactions): the_variable.lb = float(the_reaction.lower_bound) the_variable.ub = float(the_reaction.upper_bound) the_variable.obj = float(objective_sense * the_reaction.objective_coefficient) if the_problem == 'setup': return lp if print_solver_time: start_time = time() lp.update() lp.setParam("FeasibilityTol", tolerance_feasibility) lp.setParam("OptimalityTol", tolerance_optimality) if tolerance_barrier: lp.setParam("BarConvTol", tolerance_barrier) if quad_precision: lp.setParam("Quad", 1) lp.setParam("Method", lp_method) #Different methods to try if lp_method fails the_methods = [0, 2, 1] if lp_method in the_methods: the_methods.remove(lp_method) if not isinstance(the_problem, Model): lp.optimize() if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': #Try to find a solution using a different method lp.setParam("MarkowitzTol", 1e-2) for lp_method in the_methods: lp.setParam("Method", lp_method) lp.optimize() if status_dict[lp.status] == 'optimal': break else: lp.setParam("TimeLimit", 0.6) lp.optimize() lp.setParam("TimeLimit", "default") if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': lp.setParam("MarkowitzTol", 1e-2) #Try to find a solution using a different method for lp_method in the_methods: lp.setParam("Method", lp_method) lp.optimize() if status_dict[lp.status] == 'optimal': break if status_dict[lp.status] != 'optimal': lp = optimize_gurobi( cobra_model, new_objective=new_objective, objective_sense=objective_sense, min_norm=min_norm, the_problem=None, print_solver_time=print_solver_time)['the_problem'] if print_solver_time: print 'optimize time: %f' % (time() - start_time) x_dict = {} y_dict = {} y = None if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status == 'optimal': objective_value = objective_sense * lp.ObjVal [x_dict.update({v.VarName: v.X}) for v in lp.getVars()] x = array([x_dict[v.id] for v in cobra_model.reactions]) if lp.isMIP: y = y_dict = None #MIP's don't have duals else: [y_dict.update({c.ConstrName: c.Pi}) for c in lp.getConstrs()] y = array([y_dict[v.id] for v in cobra_model.metabolites]) else: y = y_dict = x = x_dict = None objective_value = None if error_reporting: print 'gurobi failed: %s' % lp.status cobra_model.solution = the_solution = Solution(objective_value, x=x, x_dict=x_dict, y=y, y_dict=y_dict, status=status) solution = {'the_problem': lp, 'the_solution': the_solution} return solution
def optimize(data): from gurobipy import Model, GRB from collections import OrderedDict # Create a new model m = Model("ComedorSocial") m.Params.outputFlag = 0 # Create variables X = [[ m.addVar(vtype=GRB.INTEGER, name=f"Alimento_{a}CompradoDia{i}") for a in range(data['alimentos']) ] for i in range(data['dias'])] Y = [[ m.addVar(vtype=GRB.INTEGER, name=f"Alimento_{a}UsadoDia{i}") for a in range(data['alimentos']) ] for i in range(data['dias'])] I = [[ m.addVar(vtype=GRB.INTEGER, name=f"Alimento_{a}AlmacenadoDia{i}") for a in range(data['alimentos']) ] for i in range(data['dias'])] extra = [ m.addVar(vtype=GRB.INTEGER, name=f"DineroExtraDia{i}") for i in range(data['dias']) ] surplus = [ m.addVar(vtype=GRB.INTEGER, name=f"SurplusElDía{i}") for i in range(data['dias'] + 1) ] # Set objective m.setObjective(sum(extra[i] for i in range(data['dias'])), GRB.MINIMIZE) # Add constraint m.addConstr(surplus[0] == 0, f'Surplus inicial') for a in range(data['alimentos']): m.addConstr(I[0][a] == 0, f"Inventario inicial del alimento {a}") for i in range(data['dias']): m.addConstr( sum(data['costo_alimento'][a] * X[i][a] for a in range(data['alimentos'])) + (data['sueldo_fijo'] / 30.5) <= extra[i] + data['donaciones_monetarias'][i] + data['visitas'][i] * data['entrada'] + surplus[i], f"Límite de gastos en el día {i}") m.addConstr( surplus[i + 1] <= extra[i] + data['donaciones_monetarias'][i] + data['visitas'][i] * data['entrada'] + surplus[i] - (sum(data['costo_alimento'][a] * X[i][a] for a in range(data['alimentos'])) + (data['sueldo_fijo'] / 30.5)), f"Surplus en el día {i}") m.addConstr( sum(I[i][a] * data['volumen_alimentos'][a] for a in range(data['alimentos'])) <= data['vol_max'], f"Límite de almacenamiento día {i}") m.addConstr( sum(Y[i][a] * data['proteina'][a] for a in range(data['alimentos'])) >= data['visitas'][i], f"Una proteina mínimo por comida día {i}") m.addConstr( sum(Y[i][a] * data['carbohidrato'][a] for a in range(data['alimentos'])) >= data['visitas'][i], f"Un carbohidrato mínimo por comida día {i}") m.addConstr( sum(Y[i][a] * data['verdura'][a] for a in range(data['alimentos'])) >= data['visitas'][i], f"Una verdura mínimo por comida día {i}") m.addConstr( sum(Y[i][a] * data['fruta'][a] for a in range(data['alimentos'])) >= data['visitas'][i], f"Una fruta mínimo por comida día {i}") m.addConstr(extra[i] >= 0, f"Naturaleza de Z en dia {i}") m.addConstr(surplus[i] >= 0, f"Naturaleza de s en dia {i}") for a in range(data['alimentos']): m.addConstr( Y[i][a] <= X[i][a] + I[max(0, i - 1)][a] + data['cantidad_alimento'][a][i], f"No se puede usar más de lo que se tiene ") m.addConstr( I[i][a] <= X[i][a] + (I[i - 1][a] if i else 0) + data['cantidad_alimento'][a][i] - Y[i][a], f'No se puede guardar más de lo que no se usa') m.addConstr(X[i][a] >= 0, f"Naturaleza de X en dia {i} y alimento {a}") m.addConstr(Y[i][a] >= 0, f"Naturaleza de Y en dia {i} y alimento {a}") m.addConstr(I[i][a] >= 0, f"Naturaleza de I en dia {i} y alimento {a}") m.optimize() final = OrderedDict() for v in m.getVars(): final[v.VarName] = v.X return final
# funcion objetivo obj = quicksum( quicksum(p[i] * quicksum(v[i, j, t] for j in j_c[:u[i]]) + P[i] * quicksum(v[i, j, t] for j in j_c[u[i]:U[i]]) - Q[i] * w[i, t] - C[i] * n[i, t] - Z[i] * Gamma[i, t] for i in i_c) - E * Beta[t] - k * Lambda[t] for t in t_c[1:]) model.setObjective(obj, GRB.MAXIMIZE) model.write("model.lp") # optimizar model.optimize() # resultados # model.printAttr("X") vars = [(i, var) for i, var in enumerate(model.getVars())] with open("holguras.txt", "w") as file: with open("antiholguras.txt", "w") as antifile: for x in model.getConstrs(): if round(x.slack, 10) == 0: if x.sense != "=": file.write(f"{x.ConstrName} {x.slack}\n") else: antifile.write(f"{x.ConstrName} {x.slack}\n") with open("resultados.txt", "w") as file: file.write(f"{model.objVal}\n") for var in vars: if ("Beta" in var[1].varName or "Gamma" in var[1].varName) or "Lambda" in var[1].varName: file.write('%s %g' % (var[1].varName, var[1].x) + "\n") if "total" in var[1].varName:
def optimize(V, d, s, lam, lam_triple, pv, pc, T, P, p_list, v_to_next_v, v_to_pre_v): model = Model("bus-flow") xv = {} for v in V: xv[v] = model.addVar(vtype=GRB.BINARY, name='xv[%s]' % (v), lb=0) xpuv = {} for u in V: for v in V: for p in P: xpuv[p, u, v] = model.addVar(vtype=GRB.BINARY, name='xuv[%s, %s, %s]' % (p, u, v), lb=0) fuv = {} for u in V: for v in V: # if u != v: fuv[u, v] = model.addVar(vtype=GRB.CONTINUOUS, name='fuv[%s, %s]' % (u, v), lb=0) # fuv[u, v] = 0 fuvw = {} for u in V: for v in V: for w in V: fuvw[u, v, w] = model.addVar(vtype=GRB.CONTINUOUS, name='fuvw[%s, %s, %s]' % (u, v, w), lb=0) # fuvw[u, v, w] = 0 # bound 1 for u in V: for v in V: if u != v: model.addConstr(fuv[u, v] <= s * d[u, v]) # bound 2 for u in V: for v in V: for p in P: if u != v and u == p_list[p][0] and v in p_list[p]: model.addConstr(fuv[u, v] >= s * d[u, v] * (1 - xpuv[p, u, v])) # bound 3 for u in V: for v in V: for w in v_to_next_v[v]: if u != w and w != v: if lam_triple.get((u, v, w), -1) != -1: model.addConstr( fuvw[u, v, w] <= s * lam_triple[u, v, w]) # bound 4 for u in V: for v in V: for p in P: for w in v_to_next_v[v]: if u != w and w != v and u == p_list[p][0] and v in p_list[ p]: model.addConstr( fuvw[u, v, w] >= s * lam_triple[u, v, w] * (1 - xpuv[p, u, v])) for u in V: for v in V: for p in P: if u != v and u == p_list[p][0] and v in p_list[p]: model.addConstr( quicksum(xv[v] for x in p_list[p] if p_list[p].index(x) <= p_list[p].index(v)) * 9999 >= xpuv[p, u, v]) model.addConstr( quicksum(xv[v] for x in p_list[p] if p_list[p].index( x) <= p_list[p].index(v)) <= 9999 * xpuv[p, u, v]) # bound 5 for u in V: model.addConstr(lam[u] * s * (1 - xv[u]) == quicksum( fuvw[u, u, w] for w in v_to_next_v[u] if u != w)) # bound 6.1 for u in V: for v in V: if u != v: model.addConstr( quicksum(fuvw[u, x, v] * (1 - xv[v]) for x in v_to_pre_v[v]) == fuv[u, v] + quicksum(fuvw[u, v, w] for w in v_to_next_v[v] if u != w)) # xv <= 2 model.addConstr(quicksum(xv[v] for v in V) <= 2) # object 1 # model.setObjective( # quicksum(xv[v] * pv * T for v in V) + # quicksum(T * pc * (lam[u] * s - lam[u] * s * xv[u] - # quicksum(quicksum(fuvw[u, x, v] * xv[v] for v in v_to_next_v[x] if u != v) for x in V)) for u # in V if lam.get(u, -1) != -1), # GRB.MINIMIZE) # object 3 model.setObjective( quicksum( quicksum( quicksum(fuvw[u, x, v] * xv[v] for x in v_to_pre_v[v]) for u in V if u != v) + lam[v] * s * xv[v] for v in V), GRB.MAXIMIZE) model.params.OutputFlag = 0 model.optimize() print model.status if model.status == GRB.status.OPTIMAL: print "Opt.value = ", model.ObjVal res = model.getVars() for i in res: if i.x < 0: print i.varName, i.x
for p in self.parameters['products'].values(): for t in self.parameters['transportation'].values(): name = 'transport_{0}_from_{1}_to_{2}_using_{3}'.format( p.id_, t.from_, t.to, t.id_) self['transportation'][t.from_, t.to, t.id_, p.id_] = model.addVar(vtype=GRB.INTEGER, lb=0, name=name) def _set_storage(self, model: Model, periods: int): for i in range(periods): for p in self.parameters['products'].values(): for s in self.parameters['stores'].values(): name = 'stock_{0}_at_{1}_in_{2}'.format(p.id_, s.id_, i) self['storage'][p.id_, s.id_, i] = model.addVar(vtype=GRB.INTEGER, lb=0, name=name) if __name__ == "__main__": with open('data/PATHS.json') as file: PATHS = json_load(file) parameters = ParametersContainer(PATHS) variables = VariablesContainer(parameters) model = Model() variables.set_all(model, 12) model.update() print(len(model.getVars()))
def createModel(self): w = {} self.y = {} m = Model("Optimization Model") #part of 6a -- create w variables for n in range(1,self.nScenario+1): for k in range(1,self.numberOfFinancialAsstValues+1): #I'm not sure how the "paramDF" file will be structured--this is temporary for j in range(1,self.nOwners+1): w[j, k, n] = m.addVar(vtype=GRB.CONTINUOUS, name="w_"+str(j)+"_"+str(k)+"_"+str(n)) #Constraint 6f for k in range(1,self.numberOfFinancialAsstValues+1): for j in range(1,self.nOwners+1): self.y[j, k] = m.addVar(vtype=GRB.BINARY, name="y_"+str(j)+"_"+str(k)) m.update() #6a continued #for k in range(1,self.numberOfFinancialAsstValues+1): #6a updated for n in range(1,self.nScenario+1): m.addConstr(quicksum(w[1,k,n] for k in range(1,self.numberOfFinancialAsstValues+1)) == self.SecondStgValues[n-1]*quicksum(self.DecisionProb[n,1,k]*self.y[1, k] for k in range(1,self.numberOfFinancialAsstValues+1)), name = "6a_1_"+str(n)) # w[1,k,n] = self.SecondStgValues[n-1] #6b updated for r in range(2,self.nOwners+1): for n in range(1,self.nScenario+1): #if self.ProbDict["("+str(n)+", 1, 0, "+str(k)+")"] > 0: # for self.ProbDict["("+str(n)+", 1, 0, "+str(k)+")"] > 0: m.addConstr(quicksum(w[r-1,k,n] for k in range(1,self.numberOfFinancialAsstValues+1)) == quicksum(w[r,k,n]*(1/self.DecisionProb[n,r,k]) for k in range(1,self.numberOfFinancialAsstValues+1)), name = "6b_"+str(r)+"_"+str(n)) #if self.ProbDict["("+str(n)+", 1, 1, "+str(k)+")"] > 0: # m.addConstr(quicksum(w[r-1,k,n] for k in range(1,self.numberOfFinancialAsstValues+1)) == quicksum(w[r,k,n]*(1/self.ProbDict["("+str(n)+", 1, 1, "+str(k)+")"]) for k in range(1,self.numberOfFinancialAsstValues+1)), name = "6b_"+str(r)+"_"+str(n)) #6b #for r in range(2, self.nOwners+1): # for n in range(1,self.nScenario+1): # m.addConstr(quicksum(quicksum(self.ProbDict["("+str(n)+", "+str(r-1)+", "+str(l)+", "+str(k)+")"]*w[r-1,k,n] for l in (0,1)) # for k in range(1,self.numberOfFinancialAsstValues+1)) == quicksum(w[r, k, n] for k in range(1,self.numberOfFinancialAsstValues+1)), name = "6b_"+str(r)+"_"+str(n)) #for n in range(1,self.nScenario+1): # m.addConstr(quicksum(w[r, k, n] for k in range(1,self.numberOfFinancialAsstValues+1)), name = "6b_"+str(r)+"_"+str(n)) #for k in range(1,self.numberOfFinancialAsstValues+1): # for r in range(2, self.ownerNums+2): # for n in range(1,self.nScenario+1): # for l in (0,1): # m.addConstr(quicksum(quicksum(self.ProbDict["("+str(n)+", "+str(r-1)+", "+str(l)+", "+str(k)+")"]*w[r-1,k,n]) == quicksum(w[r, k, n]), # name = "6b_"+str(r)+"_"+str(k)+"_"+str(n))) #6c #Not sure if this is the proper formatting for this constraint #Is this the proper use of self.SecondStgValues? #for n in range(1,self.nScenario +1): # for k in range(1,self.numberOfFinancialAsstValues+1): #I'm not sure how the "paramDF" file will be structured--this is temporary # for r in range(1,self.ownerNums+2): #6c updated for k in range(1,self.numberOfFinancialAsstValues+1): for r in range(1, self.nOwners+1): for n in range(1,self.nScenario+1): m.addConstr(w[r, k, n] <= self.y[r, k]*self.SecondStgValues[n-1], name = "6c_"+str(r)+"_"+str(k)+"_"+str(n)) #print str(r)+"_"+str(k)+"_"+str(n) #for r in range(1, self.ownerNums+2) for k in range(1,self.numberOfFinancialAsstValues+1) for n in range(1,self.nScenario+1)) #Constraint 6d #the sum of the financial assistance offered to all landowners is less than or equal to the agency's budget #Where does C come from? m.addConstr(quicksum(quicksum(self.C_k[k-1]*self.y[j, k] for k in range(1,self.numberOfFinancialAsstValues+1))for j in range(1,self.nOwners+1)) <= self.Budget_param, name = "6d") #Constraint 6e for j in range(1,self.nOwners+1): m.addConstr(quicksum(self.y[j, k] for k in range(1,self.numberOfFinancialAsstValues+1)) == 1, name = "6e_"+str(j)) m.update() #set objective lastLandownerIndex = self.nOwners m.setObjective(quicksum(quicksum(w[lastLandownerIndex, k, n] for k in range(1,self.numberOfFinancialAsstValues+1)) for n in range(1,self.nScenario+1)), GRB.MINIMIZE) m.update() m.optimize() if m.status == GRB.Status.OPTIMAL: print ('\nOBJECTIVE VALUE: %g' % m.objVal) for v in m.getVars(): print('%s %g' % (v.varName, v.x)) m.write('toy results.lp') return m
def netshield_mo(adj, e_delta): """ Perform the NetShield multiobjective algorithm via the epsilon constraint method. Epsilon values used range from 0 to sum of all degrees of the vertices in the input graph Parameters ---------- A: 2D numpy array Adjancency matrix of graph to be immunised. e_delta: Integer By how much to increase the epsilon value after each step. Returns -------- List of dictionaries that form the approximated Pareto front. Dictionaries have the following keys: solution: 1D numpy array indices of selectec vertices evaluation: tuple of (float,int) eigendrop, cost. """ eigval, eigvec = utils.get_max_eigen(adj) degrees = adj.sum(axis=0) max_cost = degrees.sum() n = adj.shape[0] e_delta = min(max(e_delta, 1), max_cost) m = Model("qp") m.setParam('OutputFlag', False) variables = [ m.addVar(name="x_{}".format(i), vtype=GRB.BINARY) for i in range(n) ] obj = _build_objective_qd(adj, variables, eigval, eigvec) constr = LinExpr() constr.addTerms(degrees, variables) m.setObjective(obj, GRB.MAXIMIZE) solutions = [{'solution': np.array([]), 'evaluation': (0, 0)}] unique = set() for i in range(int(np.ceil(max_cost / e_delta)) + 1): epsilon = min(i * e_delta, max_cost) print(epsilon) epsilon_constr = m.addConstr(constr <= epsilon, "c1") m.optimize() out = np.array([i for i, v in enumerate(m.getVars()) if v.x == 1]) if out.shape[0] > 0 and out.tobytes() not in unique: adj_pert = np.array(adj) adj_pert[out, :] = 0 adj_pert[:, out] = 0 eig_drop = eigval - utils.get_max_eigenvalue(adj_pert) cost = degrees[out].sum() solution = {'solution': out, 'evaluation': (eig_drop, cost)} solutions.append(solution) unique.add(out.tobytes()) m.remove(epsilon_constr) return _get_non_dominated(solutions)
class GurobiWrapper(SolverWrapper): def __init__(self): self.model = Model() def solve(self): self.model.optimize() def add_variable(self, name, lb, ub, vtype): args = {'name': name} if ub is not None: args['ub'] = ub if lb is not None: args['lb'] = lb if vtype is not None: args['vtype'] = self._var_types_mapping(vtype) self.model.addVar(**args) def add_variables(self, name, lb, ub, vtype): args = {'name': name} if ub is not None: args['ub'] = ub if lb is not None: args['lb'] = lb if vtype is not None: args['vtype'] = [self._var_types_mapping(t) for t in vtype] self.model.addVars(len(name), **args) def add_constraint(self, var, coeff, sense, rs): args = { 'lhs': LinExpr(coeff, self._gurobi_variables(var)), 'sense': self._sense_mapping(sense), 'rhs': rs } self.model.addConstr(**args) def add_constraints(self, var, coeff, sense, rs): for constr in zip(var, coeff, sense, rs): self.add_constraint(*constr) def set_objective_sense(self, sense): mapping = { Objective.maximize: GRB.MAXIMIZE, Objective.minimize: GRB.MINIMIZE } self.model.ModelSense = mapping[sense] def set_objective(self, var, coeff): lin_expr = LinExpr(coeff, self._gurobi_variables(var)) self.model.setObjective(lin_expr) def write_to_file(self, name): self.model.write(name) def get_solution_status(self): """ :type solution_type: SolutionType :type additional_data: Dict[{'status', 'status_str'}] :return solution_type, additional_data: """ status = self.model.Status solution_type = SolutionType.feasible if status == 1 else SolutionType.infeasible additional_data = { 'status': status, 'status_str': self._solution_strings()[status] } return solution_type, additional_data def get_objective_value(self): return self.model.ObjVal def get_solution(self): return {var.VarName: var.X for var in self.model.getVars()} def _gurobi_variable(self, name): return self.model.getVarByName(name) def _gurobi_variables(self, names): return [self._gurobi_variable(n) for n in names] @staticmethod def _sense_mapping(sense): mapping = { Sense.lt: GRB.LESS_EQUAL, Sense.gt: GRB.GREATER_EQUAL, Sense.eq: GRB.EQUAL } return mapping[sense] @staticmethod def _var_types_mapping(vtype): mapping = { VariableTypes.int: GRB.INTEGER, VariableTypes.continuous: GRB.CONTINUOUS } return mapping[vtype] @staticmethod def _solution_strings(): return { 1: 'LOADED', 2: 'OPTIMAL', 3: 'INFEASIBLE', 4: 'INF_OR_UNBD', 5: 'UNBOUNDED', 6: 'CUTOFF', 7: 'ITERATION_LIMIT', 8: 'NODE_LIMIT', 9: 'TIME_LIMIT', 10: 'SOLUTION_LIMIT', 11: 'INTERRUPTED', 12: 'NUMERIC', 13: 'SUBOPTIMAL', 14: 'INPROGRESS', 15: 'USER_OBJ_LIMIT' }
def begin(self): M = GRB.INFINITY n, m, Q = self.ins.n, self.ins.m, self.ins.Q q, s, T = self.ins.get_q(), self.ins.get_s(), self.ins.get_t() W, R, tau = self.ins.get_W(), self.ins.get_R(), self.ins.get_tau() T_max = self.ins.T arcos = tau.keys() origens, destinos, locais = self.ins.get_O(), self.ins.get_D(), self.ins.get_V() veiculos = self.ins.get_K() mod = Model("Roteamento") mod.params.MIPGap = 0.1 mod.params.TimeLimit = 20*60 viagens = {(i,j,k):0 for (i,j) in tau.keys() for k in veiculos} instantes = {(i,k):0 for i in locais for k in veiculos} carga = {(i,k):0 for i in locais for k in veiculos} x = mod.addVars(viagens, vtype=GRB.BINARY, name="x") t = mod.addVars(instantes, lb=0.0, vtype=GRB.CONTINUOUS, name="t") u = mod.addVars(carga, lb=0.0, vtype=GRB.INTEGER, name="u") exp = 0 exp += self.C0*quicksum( x[ijk] * tau[ij] for ijk in viagens for ij in arcos if ijk[0] == ij[0] and ijk[1] == ij[1]) exp += self.C1*quicksum( (t[ik] - T[i]) for i in origens for ik in instantes if ik[0] == i) exp += self.C2*quicksum( (t[(i+n,k)] - t[(i,k)]) for i in origens for k in veiculos) mod.setObjective(exp, GRB.MINIMIZE) for i in locais: delta_mais = [a for (a,b) in arcos if b == i] delta_menos = [b for (a,b) in arcos if a == i] n_visitas = quicksum(x[ijk] for ijk in viagens if ijk[1] in delta_menos and ijk[0] == i) if i == 0: mod.addConstr( n_visitas == m, name = "n_visitas_depo") elif i != 2*n+1: mod.addConstr( n_visitas == 1, name = "n_visitas_{}".format(i)) else: pass for k in veiculos: ik = (i,k) sum_entrada = quicksum( x[ijk] for ijk in [(j,i,k) for j in delta_mais] ) sum_saida = quicksum( x[ijk] for ijk in [(i,j,k) for j in delta_menos] ) if i == 2*n+1: mod.addConstr( sum_saida - sum_entrada == -1, name = "fluxo_{}_{}".format(i,k)) elif i == 0: mod.addConstr( sum_saida - sum_entrada == 1, name = "fluxo_{}_{}".format(i,k) ) else: mod.addConstr( sum_saida - sum_entrada == 0, name = "fluxo_{}_{}".format(i,k) ) if i in origens: delta_menos_destino = [b for (a,b) in arcos if a == i+n] n_visitas = quicksum(x[ijk] for ijk in viagens if ijk[0] == i and ijk[1] in delta_menos and ijk[2] == k) n_visitas_destino = quicksum(x[ijk] for ijk in viagens if ijk[1] in delta_menos_destino and ijk[0] == i+n and ijk[2] == k) dk = (i+n,k) mod.addConstr( n_visitas == n_visitas_destino, name = "consistencia_{}_{}".format(i,k) ) mod.addConstr( t[ik] >= T[i], name = "inicio_desejado_viagem_{}_{}".format(i,k)) mod.addConstr( t[dk] >= t[ik], name = "fim_apos_inicio_viagem_{}_{}".format(i,k) ) mod.addConstr( T_max >= t[dk], name = "fim_antes_total_viagem_{}_{}".format(i,k)) mod.addConstr( u[ik] >= q[i], name = "partida_maior_demanda_carga_{}_{}".format(i,k) ) mod.addConstr( Q >= u[ik], name = "partida_menor_capacidade_carga_{}_{}".format(i,k)) for ij in arcos: i, j = ij[0], ij[1] iin = (i,i+n) idp = (i,2*n+1) ind = (i+n,2*n+1) for k in veiculos: ik, jk = (i,k), (j,k) ijk = (i,j,k) jik = (j,i,k) #motivo do try abaixo try: mod.addConstr( u[ik] + q[j] - u[jk] - (q[i] + q[j])*x[jik] <= (1 - x[ijk] - x[jik])*Q, name = "elimina_subrota_capacidade_lifted_{}_{}_{}".format(i,j,k) ) except KeyError: mod.addConstr( u[ik] + q[j] - u[jk] <= (1 - x[ijk])*Q, name = "elimina_subrota_capacidade_{}_{}_{}".format(i,j,k) ) try: if j in [_+1 for _ in range(n)]: mod.addConstr( t[ik] + s[j] + tau[ij] - t[jk] - (s[j] + tau[ij] - tau[iin] - s[i+n] - tau[ind])*x[jik] <= (1 - x[ijk])*T_max, name = "elimina_subrota_temporal_lifted_{}_{}_{}".format(i,j,k)) else: mod.addConstr( t[ik] + s[j] + tau[ij] - t[jk] - (s[j] + tau[ij] - tau[idp])*x[jik] <= (1 - x[ijk])*T_max, name = "elimina_subrota_temporal_lifted_{}_{}_{}".format(i,j,k)) except KeyError: mod.addConstr( t[ik] + s[j] + tau[ij] - t[jk] <= (1 - x[ijk])*T_max, name = "elimina_subrota_temporal_{}_{}_{}".format(i,j,k) ) for k in veiculos: mod.addConstr( u[(2*n+1,k)] == 0 ) # Não há restrições para 'saidas' de # veículos de 2n+1, portanto carga # poderia ser qualquer valor. # Agora não. # with open('var.txt', 'r') as file: # for line in file: # l = line.split(' ') # r_hand = float(l[-1].replace('\n','')) # l_hand = l[0].split('_') # var = l_hand[0] # if var == 'x': # index = (int(l_hand[1]),int(l_hand[2]),int(l_hand[3])) # mod.addConstr( x[index] == r_hand ) # elif var in ['t', 'u']: # index = (int(l_hand[1]),int(l_hand[2])) # if var == 't': # mod.addConstr( t[index] == r_hand ) # else: # mod.addConstr( u[index] == r_hand ) # else: # pass mod.optimize() # mod.computeIIS() # exit() if self.save_data_DB: try: if mod.objVal <= 100000 : # print('Obj: %g' %mod.objVal) # print('Runtime: %g' %mod.runtime) for v in mod.getVars(): self.res.add_trip('{}={}'.format(v.varName, v.x)) self.res.fig_requests() self.res.fig_routes() self.res.result_data_DB(mod.runtime, mod.objVal) else : self.res.reset_data_DB() except AttributeError: self.res.reset_data_DB() else: for v in mod.getVars(): self.res.add_trip('{}={}'.format(v.varName, v.x)) if self.save_lp: mod.write('temp.lp') f1 = open('temp.lp', 'r') f2 = open(self.output_lp_name, 'w') for line in f1: l = line.replace('[','_') l = l.replace(',','_') l = l.replace(']','') f2.write(l) f1.close() f2.close()
class SQModel(object): ''' classdocs ''' # Private model object __model = [] # Private model variables __z0 = {} __z = {} __q = {} # Private model parameters __BackupCapacity = {} __bBackupLink = {} __links = [] __nodes = [] __capacity = [] __epsilon = 1 __impSample = {} __N = 1 def __init__(self,imp_samp,nodes,links,capacity,epsilon,N,backup_link,link_capacity): ''' Constructor ''' self.__links = links self.__nodes = nodes self.__capacity = capacity self.__epsilon = epsilon self.__N = N self.__loadModel(imp_samp,backup_link,link_capacity) def __loadModel(self,imp_samp, backup_link,link_capacity): # Create optimization model self.__model = Model('Backup') for i,j in self.__links: for k in range(self.__N): 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() for i,j in self.__links: self.__q[i,j] = self.__model.addVar(lb=-GRB.INFINITY,name='q[%s][%s]' %(i,j)) self.__model.update() self.__model.modelSense = GRB.MINIMIZE self.__model.setObjective(quicksum(self.__q[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/(self.__N*self.__epsilon)*quicksum(self.__z[k,i,j]*imp_samp[k] for (k) in range(self.__N)) <= self.__q[i,j],'[CONST]Buffer_Prob_I[%s][%s]'%(i,j)) self.__model.update() # Link capacity constraints for i,j in self.__links: for k in range(self.__N): self.__model.addConstr((quicksum(backup_link[i,j,s,d]*self.__capacity[k,s,d] for s,d in self.__links) - link_capacity[i,j] - self.__z0[i,j]) <= 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(self.__N): self.__model.addConstr(self.__z[k,i,j] >= 0,'[CONST]Buffer_Prob_III[%s][%s][%s]' % (k,i,j)) self.__model.update() def optimize(self,MipGap, TimeLimit, LogLevel = None): self.__model.write('quantile.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: #SuperQuantileSolution = self.__model.getAttr('x', self.__z0) SuperQuantileSolution = {} OptimalZnot = {} for i,j in self.__links: name='q[%s][%s]'%(i,j) v = self.__model.getVarByName(name) SuperQuantileSolution[i,j]=v.x name='z0[%s][%s]'%(i,j) v = self.__model.getVarByName(name) OptimalZnot[i,j]=v.x if LogLevel == 1: for v in self.__model.getVars(): print('%s %g' % (v.varName, v.x)) else: print('Optimal value not found!\n') SuperQuantileSolution = {} OptimalZnot={} return SuperQuantileSolution, OptimalZnot def reset(self): ''' Reset model solution ''' self.__model.reset()
class HarmonyModel: def __init__(self, length): """Initialize model, note and chord variables, and constraints for notes and chord constraints.""" self.model = Model("harmony") self.length = length config = load_source("config", join(abspath(dirname(__file__)), "config.py")) config.length = self.length config.model = self.model self.notes = Notes(config) config.notes = self.notes self.chords = Chords(config) def ensure_melody(self, melody): """Ensure that the four-part harmony has a complete or partial melody as its soprano line.""" for t, note in enumerate(melody): if not note: continue constraint = self.notes[denote(note), 3, t] == 1 self.model.addConstr(constraint, "melody_t" + str(t)) self.model.update() def ensure_harmony(self, harmony): """Ensure that the four-part harmony uses certain chords (and the correct inversion) at each time step.""" for t, chord in enumerate(harmony): if not chord: continue for c in self.chords.chord_notes.keys(): if c == chord: continue for d in self.chords.chord_doublings[c]: constraint = self.chords[c, d, t] == 0 self.model.addConstr(constraint, "harmony_c" + c + "_d" + str(d) + "_t" + str(t)) self.model.update() def write(self): """Write out LP file of generated model (for debugging).""" self.model.write("model.lp") def solve(self): """Solve the model and provide the solution's notes (x variables) and chords (y variables).""" self.model.optimize() self.solution = [] try: for var in self.model.getVars(): if var.x == 1 and var.varName[0] in {"x", "y"}: self.solution.append(var.varName) return self.solution except: return [] def lilypond_export(self): """Return a Lilypond file to generate a human-readable score based on the IP solution.""" letter = ("c", "cis", "d", "dis", "e", "f", "fis", "g", "gis", "a", "ais", "b") notes = {} chords = {} max_time = 0 for var in self.solution: if var[0] == "x": _, pitch, voice, time = var.split("_") pitch = int(pitch[1:]) time = int(time[1:]) voice = int(voice[1:]) octave = [",", "", "'", "''", "'''"][(pitch - pitch % 12) / 12] notes[voice, time] = letter[(pitch % 12)] + octave elif var[0] == "y": # chord _, chord, double, time = var.split("_") time = int(time[1:]) chords[time] = chord max_time = max(max_time, time) notestrings = ["", "", "", ""] chordstring = "" for time in range(max_time+1): chord = chords[time] for c, char in enumerate(chords[time]): superscript = "" subscript = "" try: int(char) superscript = char try: int(chords[time][c + 1]) subscript = chords[time][c + 1] except: pass chord = chord.replace(superscript + subscript, "\\small \\super{\\column {\\general-align #Y #-0.2 \"" + superscript + "\" \\general-align #Y #-3.2 \"" + subscript + "\"}}") break except: pass chord.replace("vii", "vii\xc2") # diminished symbol chordstring += " \markup{" + chord + "}" for voice in range(4): notestrings[voice] += " " + notes[voice, time] return \ """\t\header { tagline = "" } global = { \\key c \\major \\time 4/4 } Soprano = \\absolute { """ + notestrings[3] + """ } Alto = \\absolute { """ + notestrings[2] + """ } Tenor = \\absolute { """ + notestrings[1] + """ } Bass = \\absolute { """ + notestrings[0] + """ } Chords = \\lyrics { """ + chordstring + """
def solve(n, width, height, startNodes, targetNodes, startTimes, endTimes): model = Model("BoatSolver") def toGrid(val, y=0): if isinstance(val, list): return val[0] + val[1] * width return val + y * width T = max(endTimes) x = {} wait = {} for i, j, t in itertools.product(range(n), range(width * height), range(T)): x[i, j, t] = model.addVar(name="x_%d_%d_%d" % (i+1, j+1, t+1), vtype="b", obj=1) wait[i, j, t] = model.addVar(name="wait_%d_%d_%d" % (i+1, j+1, t+1), vtype="i", obj=-1) model.modelSense = GRB.MINIMIZE model.update() # Force startpositions for i, (sN, sT) in enumerate(zip(startNodes, startTimes)): for t in range(sT): for j in range(width * height): if j == toGrid(sN - 1) and t == sT - 1: logging.debug("start: %s == 1", x[i, j, t].varName) model.addConstr(x[i, j, t] == 1) else: logging.debug("start: %s == 0", x[i, j, t].varName) model.addConstr(x[i, j, t] == 0) # Force endpositions for i, (eN, eT) in enumerate(zip(targetNodes, endTimes)): j = toGrid(eN - 1) logging.debug("end: %s == 1", x[i, j, eT - 1].varName) model.addConstr(x[i, j, eT - 1] == 1) # Container vanishes after endTime for t in range(eT, T): logging.debug("end: %s == 0", x[i, j, t].varName) model.addConstr(x[i, j, t] == 0) # single container per node for j, t in itertools.product(range(width * height), range(T)): logging.debug("%s <= 1", [x[i, j, t].varName for i in range(n)]) model.addConstr(quicksum(x[i, j, t] for i in range(n)) <= 1) # Force valid container movement for w, h in itertools.product(range(width), range(height)): vals = [toGrid(w, h)] if h >= 1: vals += [toGrid(w, h - 1)] if w >= 1: vals += [toGrid(w - 1, h)] if h+1 < height: vals += [toGrid(w, h + 1)] if w+1 < width: vals += [toGrid(w + 1, h)] for i, t in itertools.product(range(n), range(1, T)): if endTimes[i] > t and startTimes[i] <= t: logging.debug("sum(%s) >= %s", [x[i, j, t].varName for j in vals], x[i, toGrid(w, h), t - 1].varName) model.addConstr(quicksum(x[i, j, t] for j in vals) >= x[i, toGrid(w, h), t - 1]) else: logging.debug("skipped(%s) >= %s", [x[i, j, t].varName for j in vals], x[i, toGrid(w, h), t - 1].varName) for i, t in itertools.product(range(n), range(1, T)): logging.debug("sum(%s) <= 1", [x[i, j, t].varName for j in vals]) model.addConstr(quicksum(x[i, j, t] for j in vals) <= 1) # Force continous line through grid for i, t in itertools.product(range(n), range(0, T)): if endTimes[i] > t and startTimes[i] <= t + 1: logging.debug("sum(%s) == 1", [x[i, j, t].varName for j in range(width * height)]) model.addConstr(quicksum(x[i, j, t] for j in range(width * height)) == 1) else: logging.debug("sum(%s) == 0", [x[i, j, t].varName for j in range(width * height)]) model.addConstr(quicksum(x[i, j, t] for j in range(width * height)) == 0) # Prevent ships from passing over same link for t in range(1, T): for w, h in itertools.product(range(width - 1), range(height)): for i in range(n): for k in range(i+1, n): model.addConstr(x[i, toGrid(w, h), t - 1] + x[i, toGrid(w + 1, h), t] + x[k, toGrid(w, h), t] + x[k, toGrid(w + 1, h), t - 1] <= 3) model.addConstr(x[i, toGrid(w, h), t] + x[i, toGrid(w + 1, h), t - 1] + x[k, toGrid(w, h), t - 1] + x[k, toGrid(w + 1, h), t] <= 3) for w, h in itertools.product(range(width), range(height - 1)): for i in range(n): for k in range(i+1, n): model.addConstr(x[i, toGrid(w, h), t - 1] + x[i, toGrid(w, h + 1), t] + x[k, toGrid(w, h), t] + x[k, toGrid(w, h + 1), t - 1] <= 3) model.addConstr(x[i, toGrid(w, h), t] + x[i, toGrid(w, h + 1), t - 1] + x[k, toGrid(w, h), t - 1] + x[k, toGrid(w, h + 1), t] <= 3) # Allow free waiting for i, j, t in itertools.product(range(n), range(width * height), range(0, T)): if t < startTimes[i]: model.addConstr(x[i, j, t] == wait[i, j, t]) else: model.addConstr(x[i, j, t - 1] + x[i, j, t] - 1 <= wait[i, j, t]) model.addConstr(x[i, j, t - 1] >= wait[i, j, t]) model.addConstr(x[i, j, t] >= wait[i, j, t]) model.optimize() for y in model.getVars(): if y.x: logging.warning("%s = %d", y.varName, y.x) return model
def solve_sonata_lp(): name = "sonata" try: # Create a new model m = Model(name) # create table tuples tables = {} table_2_qid = {} table_2_d = {} table_2_last = {} for qid in query_2_tables: table_2_last[qid] = {} table_2_d[qid] = {} for tid in query_2_tables[qid]: table_2_qid[tid] = qid # add a binary decision variable d var_name = "d_" + str(tid) table_2_d[qid][tid] = m.addVar(lb=0, ub=1, vtype=GRB.BINARY, name=var_name) # add a binary decision variable last var_name = "last_" + str(tid) table_2_last[qid][tid] = m.addVar(lb=0, ub=1, vtype=GRB.BINARY, name=var_name) for tid in table_2_bits.keys(): tables[tid] = {} qid = table_2_qid[tid] tables[tid]["qid"] = qid tables[tid]["d"] = table_2_d[qid][tid] tables[tid]["last"] = table_2_last[qid][tid] # print (tables) # satisfy the `last` variable constraint for each query qid_2_last = {} for qid in Q: var_name = "qid_last_" + str(qid) qid_2_last[qid] = m.addVar(lb=0, ub=1, vtype=GRB.BINARY, name=var_name) tmp = [table_2_last[qid][tid] for tid in query_2_tables[qid]] m.addConstr(sum(tmp) == qid_2_last[qid]) # relate d & last variables for qid in Q: ind = 1 for tid in query_2_tables[qid]: tmp = [ table_2_d[qid][tid1] for tid1 in query_2_tables[qid][:ind] ] m.addConstr(sum(tmp) >= table_2_last[qid][tid] * ind) ind += 1 # Enumerate powerset for queries G = list(powerset(Q))[:-1] print(G) # compute the cardinality of elements in G gid_2_doubleD = {} gid = 0 for g in G: output_set = set() for qid in g: output_set = output_set.union(query_2_D[qid]) gid_2_doubleD[gid] = output_set gid += 1 print(gid_2_doubleD) # create A variables A = {} # Add pipeline specific variables pipeline_2_I = {} pipeline_2_O = {} pipeline_2_A = {} for pid in Q: pipeline_2_O[pid] = {} pipeline_2_I[pid] = {} pipeline_2_A[pid] = {} # create A variables for gid in range(len(G)): var_name = "A_" + str(pid) + "_" + str(gid) pipeline_2_A[pid][gid] = m.addVar(lb=0, ub=1, vtype=GRB.BINARY, name=var_name) # create I variables for qid in Q: var_name = "I_" + str(pid) + "_" + str(qid) pipeline_2_I[pid][qid] = m.addVar(lb=0, ub=1, vtype=GRB.BINARY, name=var_name) # create O variables for qid1 in Q: pipeline_2_O[pid][qid1] = {} for qid2 in Q: if qid1 != qid2: var_name = "O_" + str(pid) + "_" + str( qid1) + "_" + str(qid2) pipeline_2_O[pid][qid1][qid2] = m.addVar( lb=0, ub=1, vtype=GRB.BINARY, name=var_name) # complimentary O constraint for pid in Q: for qid1 in Q: for qid2 in Q: if qid1 != qid2: m.addConstr(pipeline_2_O[pid][qid1][qid2] + pipeline_2_O[pid][qid2][qid1] <= 1) # if I1 & I2 then O12+O21 m.addConstr(pipeline_2_O[pid][qid1][qid2] + pipeline_2_O[pid][qid2][qid1] >= pipeline_2_I[pid][qid1] + pipeline_2_I[pid][qid2] - 1) # if (1-I1) or (1-I2) then !(O12+O21) m.addConstr(pipeline_2_O[pid][qid1][qid2] + pipeline_2_O[pid][qid2][qid1] <= 0.5 * (pipeline_2_I[pid][qid1] + pipeline_2_I[pid][qid2])) # create an indicator variable for pipelines pipeline_2_ind = {} for pid in Q: var_name = "P_ind_" + str(pid) pipeline_2_ind[pid] = m.addVar(lb=0, ub=1, vtype=GRB.BINARY, name=var_name) for qid in Q: m.addConstr(pipeline_2_I[pid][qid] <= pipeline_2_ind[pid]) I_for_P = [pipeline_2_I[pid][qid] for qid in Q] m.addConstr(pipeline_2_ind[pid] <= sum(I_for_P)) # # satisfy the constraint, sum(A) == sum(p_ind) # all_a = [A[gid] for gid in range(len(G))] # all_p = [pipeline_2_ind[pid] for pid in Q] # m.addConstr(sum(all_a) == sum(all_p)) for qid in Q: I_for_P = [pipeline_2_I[pid][qid] for pid in Q] m.addConstr(sum(I_for_P) <= 1) for gid in range(len(G)): A_for_P = [pipeline_2_A[pid][gid] for pid in Q] m.addConstr(sum(A_for_P) <= 1) # relate A and I variables for pid in Q: for gid in range(len(G)): g = G[gid] for qid in g: m.addGenConstrIndicator(pipeline_2_A[pid][gid], True, pipeline_2_I[pid][qid] == 1) for pid in Q: for qid in Q: tmp = [] for gid in range(len(G)): g = G[gid] if qid in g: tmp.append(pipeline_2_A[pid][gid]) m.addConstr(sum(tmp) == pipeline_2_I[pid][qid]) # objective objective_expr = ([ table_2_bits[tid] * tables[tid]["last"] for tid in table_2_bits.keys() ] + [1000 * (1 - qid_2_last[qid]) for qid in Q]) m.setObjective(sum(objective_expr), GRB.MINIMIZE) # satisfy the constraints on I variable for qid in Q: tmp = [pipeline_2_I[pid][qid] for pid in Q] m.addConstr(sum(tmp) == 1) # satisfy mirroring overhead constraint total_packets_expr_list = [] for pid in Q: for gid in range(len(G)): print(gid, gid_2_doubleD[gid], len(gid_2_doubleD[gid])) total_packets_expr_list.append(pipeline_2_A[pid][gid] * len(gid_2_doubleD[gid])) # Add cloned packet variable C = m.addVar(lb=0, ub=clone_max, vtype=GRB.INTEGER, name="Clone") m.addConstr(C == sum(total_packets_expr_list) - len(D)) m.addConstr(C <= clone_max) table_2_stageE = {} table_2_stageF = {} for pid in Q: table_2_stageE[pid] = {} table_2_stageF[pid] = {} for qid in Q: table_2_stageE[pid][qid] = {} table_2_stageF[pid][qid] = {} for tid in query_2_tables[qid]: var_name = "SE_" + str(pid) + "_" + str(qid) + "_" + str( tid) table_2_stageE[pid][qid][tid] = m.addVar(lb=0, ub=sigma_max, vtype=GRB.INTEGER, name=var_name) m.addGenConstrIndicator(pipeline_2_I[pid][qid], False, table_2_stageE[pid][qid][tid] <= 0) m.addGenConstrIndicator(pipeline_2_I[pid][qid], True, table_2_stageE[pid][qid][tid] >= 1) var_name = "SF_" + str(pid) + "_" + str(qid) + "_" + str( tid) table_2_stageF[pid][qid][tid] = m.addVar(lb=0, ub=sigma_max, vtype=GRB.INTEGER, name=var_name) m.addGenConstrIndicator(pipeline_2_I[pid][qid], False, table_2_stageF[pid][qid][tid] <= 0) m.addGenConstrIndicator(pipeline_2_I[pid][qid], True, table_2_stageF[pid][qid][tid] >= 1) m.addConstr(table_2_stageF[pid][qid][tid] <= table_2_stageE[pid][qid][tid]) # Apply intra-query dependencies for pid in Q: for qid in Q: for (tid1, tid2) in zip(query_2_tables[qid][:-1], query_2_tables[qid][1:]): #m.addConstr(table_2_stage[pid][qid][tid2] - 1 - table_2_stage[pid][qid][tid1] >= 0) m.addGenConstrIndicator( pipeline_2_I[pid][qid], True, table_2_stageF[pid][qid][tid2] - table_2_stageE[pid][qid][tid1] >= 1) # create sigma variables pid_2_sigma = {} for pid in Q: var_name = "sigma_" + str(pid) pid_2_sigma[pid] = m.addVar(lb=0, ub=sigma_max, vtype=GRB.INTEGER, name=var_name) # relate sigma with I for pid in Q: I_for_pid = [(len(query_2_tables[qid]) * pipeline_2_I[pid][qid]) for qid in Q] m.addConstr(sum(I_for_pid) == pid_2_sigma[pid]) # apply inter-query dependencies for pid in Q: for qid1 in Q: last_tid_1 = query_2_tables[qid1][-1] first_tid_1 = query_2_tables[qid1][0] for qid2 in Q: if qid1 != qid2: last_tid_2 = query_2_tables[qid2][-1] first_tid_2 = query_2_tables[qid2][0] m.addGenConstrIndicator( pipeline_2_O[pid][qid1][qid2], True, table_2_stageF[pid][qid2][first_tid_2] - table_2_stageE[pid][qid1][last_tid_1] >= 1) m.addGenConstrIndicator( pipeline_2_O[pid][qid2][qid1], True, table_2_stageF[pid][qid1][first_tid_1] - table_2_stageE[pid][qid2][last_tid_2] >= 1) # create W variable W = {} for pid in Q: W[pid] = {} for qid in Q: W[pid][qid] = {} for tid in query_2_tables[qid]: W[pid][qid][tid] = {} for sid in range(1, 1 + sigma_max): var_name = "W_" + str(pid) + "_" + str( qid) + "_" + str(tid) + "_" + str(sid) W[pid][qid][tid][sid] = m.addVar(lb=0, ub=table_2_bits[tid], vtype=GRB.INTEGER, name=var_name) m.addGenConstrIndicator(pipeline_2_I[pid][qid], False, W[pid][qid][tid][sid] == 0) # apply assignment constraint for qid in Q: for tid in query_2_tables[qid]: for pid in Q: tmp = [ W[pid][qid][tid][sid] for sid in range(1, 1 + sigma_max) ] var_name = "tmp_y_" + str(qid) + "_" + str(tid) + str(pid) tmp_y = m.addVar(lb=0, ub=1, vtype=GRB.BINARY, name=var_name) m.addConstr( tmp_y >= pipeline_2_I[pid][qid] + tables[tid]["d"] - 1) m.addGenConstrIndicator(tmp_y, True, sum(tmp) >= table_2_bits[tid]) # apply memory constraint for sid in range(1, 1 + sigma_max): W_for_S = [] for pid in Q: for qid in Q: for tid in query_2_tables[qid]: W_for_S.append(W[pid][qid][tid][sid]) m.addConstr(sum(W_for_S) <= bits_max) # relate W and stageE and stageF variables for pid in Q: for qid in Q: for tid in query_2_tables[qid]: for sid in range(1, 1 + sigma_max): # if W[pid][qid][tid][sid] > 0 then, # table_2_stageF[pid][qid][tid] <= sid and table_2_stageE[pid][qid][tid] >= sid # create a new indicator variable var_name = "fin_ind_" + str(pid) + "_" + str( qid) + "_" + str(tid) + "_" + str(sid) tmp_ind = m.addVar(lb=0, ub=1, vtype=GRB.BINARY, name=var_name) m.addGenConstrIndicator(tmp_ind, False, W[pid][qid][tid][sid] == 0) m.addGenConstrIndicator( tmp_ind, True, table_2_stageF[pid][qid][tid] <= sid) m.addGenConstrIndicator( tmp_ind, True, table_2_stageE[pid][qid][tid] >= sid) m.write(name + ".lp") m.optimize() print('Obj:', m.objVal) for v in m.getVars(): print(v.varName, v.x) out_str = "Stages" for sid in range(1, sigma_max + 1): out_str += "|" + str(sid) out_str += "\n" for pid in Q: out_str += "P" + str(pid) + "|" for sid in range(1, sigma_max + 1): out_sid = "" if pipeline_2_ind[pid].x > 0: for qid in Q: if pipeline_2_I[pid][qid].x > 0: for tid in query_2_tables[qid]: if W[pid][qid][tid][sid].x > 0: out_sid += "(S" + str(sid) + ",Q" + str( qid) + ",T" + str(tid) + ",B=" + str( W[pid][qid][tid][sid].x) + ")," out_sid = out_sid[:-1] if out_sid == "": out_sid = "XXXX" out_str += out_sid + "|" out_str += "\n" print(out_str) except GurobiError: print('Error reported', GurobiError.message)
def from_gurobipy(model: Model) -> QuadraticProgram: """Translate a gurobipy model into a quadratic program. Note that this supports only basic functions of gurobipy as follows: - quadratic objective function - linear / quadratic constraints - binary / integer / continuous variables Args: model: The gurobipy model to be loaded. Returns: The quadratic program corresponding to the model. Raises: QiskitOptimizationError: if the model contains unsupported elements. MissingOptionalLibraryError: if gurobipy is not installed. """ _check_gurobipy_is_installed("from_gurobipy") if not isinstance(model, Model): raise QiskitOptimizationError(f"The model is not compatible: {model}") quadratic_program = QuadraticProgram() # Update the model to make sure everything works as expected model.update() # get name quadratic_program.name = model.ModelName # get variables # keep track of names separately, since gurobipy allows to have None names. var_names = {} for x in model.getVars(): if x.vtype == gp.GRB.CONTINUOUS: x_new = quadratic_program.continuous_var(x.lb, x.ub, x.VarName) elif x.vtype == gp.GRB.BINARY: x_new = quadratic_program.binary_var(x.VarName) elif x.vtype == gp.GRB.INTEGER: x_new = quadratic_program.integer_var(x.lb, x.ub, x.VarName) else: raise QiskitOptimizationError( f"Unsupported variable type: {x.VarName} {x.vtype}") var_names[x] = x_new.name # objective sense minimize = model.ModelSense == gp.GRB.MINIMIZE # Retrieve the objective objective = model.getObjective() has_quadratic_objective = False # Retrieve the linear part in case it is a quadratic objective if isinstance(objective, gp.QuadExpr): linear_part = objective.getLinExpr() has_quadratic_objective = True else: linear_part = objective # Get the constant constant = linear_part.getConstant() # get linear part of objective linear = {} for i in range(linear_part.size()): linear[var_names[linear_part.getVar(i)]] = linear_part.getCoeff(i) # get quadratic part of objective quadratic = {} if has_quadratic_objective: for i in range(objective.size()): x = var_names[objective.getVar1(i)] y = var_names[objective.getVar2(i)] v = objective.getCoeff(i) quadratic[x, y] = v # set objective if minimize: quadratic_program.minimize(constant, linear, quadratic) else: quadratic_program.maximize(constant, linear, quadratic) # check whether there are any general constraints if model.NumSOS > 0 or model.NumGenConstrs > 0: raise QiskitOptimizationError( "Unsupported constraint: SOS or General Constraint") # get linear constraints for constraint in model.getConstrs(): name = constraint.ConstrName sense = constraint.Sense left_expr = model.getRow(constraint) rhs = constraint.RHS lhs = {} for i in range(left_expr.size()): lhs[var_names[left_expr.getVar(i)]] = left_expr.getCoeff(i) if sense == gp.GRB.EQUAL: quadratic_program.linear_constraint(lhs, "==", rhs, name) elif sense == gp.GRB.GREATER_EQUAL: quadratic_program.linear_constraint(lhs, ">=", rhs, name) elif sense == gp.GRB.LESS_EQUAL: quadratic_program.linear_constraint(lhs, "<=", rhs, name) else: raise QiskitOptimizationError( f"Unsupported constraint sense: {constraint}") # get quadratic constraints for constraint in model.getQConstrs(): name = constraint.QCName sense = constraint.QCSense left_expr = model.getQCRow(constraint) rhs = constraint.QCRHS linear = {} quadratic = {} linear_part = left_expr.getLinExpr() for i in range(linear_part.size()): linear[var_names[linear_part.getVar(i)]] = linear_part.getCoeff(i) for i in range(left_expr.size()): x = var_names[left_expr.getVar1(i)] y = var_names[left_expr.getVar2(i)] v = left_expr.getCoeff(i) quadratic[x, y] = v if sense == gp.GRB.EQUAL: quadratic_program.quadratic_constraint(linear, quadratic, "==", rhs, name) elif sense == gp.GRB.GREATER_EQUAL: quadratic_program.quadratic_constraint(linear, quadratic, ">=", rhs, name) elif sense == gp.GRB.LESS_EQUAL: quadratic_program.quadratic_constraint(linear, quadratic, "<=", rhs, name) else: raise QiskitOptimizationError( f"Unsupported constraint sense: {constraint}") return quadratic_program
def populate_dual_subproblem(data, upper_cost=None, flow_cost=None): """ Function that populates the Benders Dual Subproblem, as suggested by the paper "Minimal Infeasible Subsystems and Bender's cuts" by Fischetti, Salvagnin and Zanette. :param data: Problem data structure :param upper_cost: Link setup decisions fixed in the master :param flow_cost: This is the cost of the continuous variables of the master problem, as explained in the paper :return: Numpy array of Gurobi model objects """ # Gurobi model objects subproblems = np.empty(shape=(data.periods, data.commodities), dtype=object) # Construct model for period/commodity 0. # Then, copy this and change the coefficients dual_subproblem = Model('dual_subproblem_(0,0)') # Ranges we are going to need arcs, periods, commodities = xrange(data.arcs.size), xrange( data.periods), xrange(data.commodities) # Origins and destinations of commodities origins, destinations = data.origins, data.destinations # We use arrays to store variable indexes and variable objects. Why use # both? Gurobi wont let us get the values of individual variables # within a callback.. We just get the values of a large array of # variables, in the order they were initially defined. To separate them # in variable categories, we will have to use index arrays flow_index = np.zeros(shape=data.nodes, dtype=int) flow_duals = np.empty_like(flow_index, dtype=object) ubounds_index = np.zeros(shape=len(arcs), dtype=int) ubounds_duals = np.empty_like(ubounds_index, dtype=object) # Makes sure we don't add variables more than once flow_duals_names = set() if upper_cost is None: upper_cost = np.zeros(shape=(len(periods), len(arcs)), dtype=float) if flow_cost is None: flow_cost = np.zeros(shape=(len(periods), len(commodities)), dtype=float) # Populate all variables in one loop, keep track of their indexes # Data for period = 0, com = 0 count = 0 for arc in arcs: ubounds_duals[arc] = dual_subproblem.addVar( obj=-upper_cost[0, arc], lb=0., name='ubound_dual_a{}'.format(arc)) ubounds_index[arc] = count count += 1 start_node, end_node = get_2d_index(data.arcs[arc], data.nodes) start_node, end_node = start_node - 1, end_node - 1 for node in (start_node, end_node): var_name = 'flow_dual_n{}'.format(node) if var_name not in flow_duals_names: flow_duals_names.add(var_name) obj, ub = 0., GRB.INFINITY if data.origins[0] == node: obj = 1. if data.destinations[0] == node: obj = -1. ub = 0. flow_duals[node] = \ dual_subproblem.addVar( obj=obj, lb=0., name=var_name) flow_index[node] = count count += 1 opt_var = dual_subproblem.addVar(obj=-flow_cost[0, 0], lb=0., name='optimality_var') dual_subproblem.params.threads = 2 dual_subproblem.params.LogFile = "" dual_subproblem.update() # Add constraints demand = data.demand[0, 0] for arc in arcs: start_node, end_node = get_2d_index(data.arcs[arc], data.nodes) start_node, end_node = start_node - 1, end_node - 1 lhs = flow_duals[start_node] - flow_duals[end_node] \ - ubounds_duals[arc] - \ opt_var * data.variable_cost[arc] * demand dual_subproblem.addConstr(lhs <= 0., name='flow_a{}'.format(arc)) # Original Fischetti model lhs = quicksum(ubounds_duals) + opt_var dual_subproblem.addConstr(lhs == 1, name='normalization_constraint') # Store variable indices dual_subproblem._ubounds_index = ubounds_index dual_subproblem._flow_index = flow_index dual_subproblem._all_variables = np.array(dual_subproblem.getVars()) dual_subproblem._flow_duals = np.take(dual_subproblem._all_variables, flow_index) dual_subproblem._ubound_duals = np.take(dual_subproblem._all_variables, ubounds_index) dual_subproblem.setParam('OutputFlag', 0) dual_subproblem.modelSense = GRB.MAXIMIZE dual_subproblem.update() subproblems[0, 0] = dual_subproblem for period, com in product(periods, commodities): if (period, com) != (0, 0): model = dual_subproblem.copy() optimality_var = model.getVarByName('optimality_var') optimality_var.Obj = -flow_cost[period, com] demand = data.demand[period, com] for node in xrange(data.nodes): variable = model.getVarByName('flow_dual_n{}'.format(node)) if origins[com] == node: obj = 1. elif destinations[com] == node: obj = -1. else: obj = 0. variable.obj = obj for arc in arcs: variable = model.getVarByName('ubound_dual_a{}'.format(arc)) variable.Obj = -np.sum(upper_cost[:period + 1, arc]) constraint = model.getConstrByName('flow_a{}'.format(arc)) model.chgCoeff(constraint, optimality_var, -demand * data.variable_cost[arc]) model._all_variables = np.array(model.getVars()) model.update() subproblems[period, com] = model return subproblems
for h in T if h <= t + 3 * (31 - F[0])) for i in I for j in I for t in T if j != i), name="R13") m.addConstrs((a[i, f] <= a[i, f - 1] for i in I for f in F if f > F[0]), name="R15") m.addConstrs( (d[i, f] <= 1 - p[i, t, f - 1] + quicksum(p[j, h, f - 1] for h in T if h >= t + 3 * (31 - f)) for i in I for j in I for t in T for f in F if f > F[0] and j != i), name="R16") m.addConstrs((d[i, F[0]] <= 1 - E[i][t] + quicksum(E[j][h] for h in T if h >= t + 3 * (31 - F[0])) for i in I for j in I for t in T if j != i), name="R17") m.addConstrs((d[i, f] <= d[i, f - 1] for i in I for f in F if f > F[0]), name="R18") m.setObjective( quicksum(quicksum(V[f] * (a[i, f] + d[i, f]) for i in I) for f in F), GRB.MAXIMIZE) m.optimize() parse_output(m.getVars(), matches)
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 populate_master(data, open_arcs=None): """ Function that populates the Benders Master problem :param data: Problem data structure :param open_arcs: If given, it is a MIP start feasible solution :rtype: Gurobi model object """ master = Model('master-model') arcs, periods = xrange(data.arcs.size), xrange(data.periods) commodities = xrange(data.commodities) graph, origins, destinations = data.graph, data.origins, data.destinations variables = np.empty(shape=(data.periods, data.arcs.size), dtype=object) bin_vars_idx = np.empty_like(variables, dtype=int) continuous_variables = np.empty(shape=(len(periods), len(commodities)), dtype=object) cont_vars_idx = np.empty_like(continuous_variables, dtype=int) start_given = open_arcs is not None count = 0 # length of shortest path, shortest path itself arc_com, arc_obj = [], [] lbs = [ shortest_path_length(graph, origins[com], destinations[com], 'weight') for com in commodities ] sps = [ shortest_path(graph, origins[com], destinations[com], 'weight') for com in commodities ] # resolve sp by removing one arc, check the increase in value for com in commodities: incr, best_arc = 0., 0 for n1, n2 in zip(sps[com], sps[com][1:]): weight = graph[n1][n2]['weight'] graph[n1][n2]['weight'] = 10000. * weight spl = shortest_path_length(graph, origins[com], destinations[com], 'weight') if spl > incr: incr = spl best_arc = graph[n1][n2]['arc_id'] graph[n1][n2]['weight'] = weight arc_com.append(best_arc) arc_obj.append(spl) # Add variables for period in periods: for arc in arcs: # Binary arc variables variables[period, arc] = master.addVar(vtype=GRB.BINARY, obj=data.fixed_cost[period, arc], name='arc_open{}_{}'.format( period, arc)) bin_vars_idx[period, arc] = count count += 1 for com in commodities: lb = lbs[com] * data.demand[period, com] # Continuous flow_cost variables (eta) continuous_variables[period, com] = master.addVar( lb=lb, obj=1., vtype=GRB.CONTINUOUS, name='flow_cost{}'.format((period, com))) cont_vars_idx[period, com] = count count += 1 master.update() # If feasible solution is given, use it as a start if start_given: for period in periods: for arc in arcs: # variables[period, arc].start = open_arcs[period, arc] variables[period, arc].VarHintVal = open_arcs[period, arc] variables[period, arc].VarHintPri = 1 # Add constraints # Add Origin - Destination Cuts for each Commodity cuts_org, cuts_dest = set(), set() for commodity in commodities: arc_origin = data.origins[commodity] arc_destination = data.destinations[commodity] if arc_origin not in cuts_org: out_origin = get_2d_index(data.arcs, data.nodes)[0] - 1 == arc_origin master.addConstr(lhs=np.sum(variables[0, out_origin]), rhs=1., sense=GRB.GREATER_EQUAL, name='origins_c{}'.format(commodity)) cuts_org.add(arc_origin) if arc_destination not in cuts_dest: in_dest = get_2d_index(data.arcs, data.nodes)[1] - 1 == arc_destination master.addConstr(lhs=np.sum(variables[0, in_dest]), rhs=1., sense=GRB.GREATER_EQUAL, name='destinations_c{}'.format(commodity)) cuts_dest.add(arc_destination) # Add that an arc can open at most once for arc in arcs: master.addSOS(GRB.SOS_TYPE1, variables[:, arc].tolist(), list(periods)[::-1]) # Add extra constraints for lower bound improvement for com in commodities: arc = arc_com[com] base_coeffs = lbs[com] - arc_obj[com] for period in periods: lhs = LinExpr() coeffs = [ cf * data.demand[period, com] for cf in [base_coeffs] * (period + 1) ] lhs.addTerms(coeffs, variables[:period + 1, arc].tolist()) lhs.add(-continuous_variables[period, com]) lhs.addConstant(arc_obj[com] * data.demand[period, com]) master.addConstr(lhs, sense=GRB.LESS_EQUAL, rhs=0, name='strengthening_{}{}'.format(period, com)) master.params.LazyConstraints = 1 # Find feasible solutions quickly, works better master.params.TimeLimit = 7200 master.params.threads = 2 master.params.BranchDir = 1 # Store the variables inside the model, we cannot access them later! master._variables = np.array(master.getVars()) master._cont_vars_idx = cont_vars_idx master._bin_vars_idx = bin_vars_idx return master
def tsp_gurobi(edges): """ Modeled using GUROBI python example. """ from gurobipy import Model, GRB, quicksum edges = populate_edge_weights(edges) incoming, outgoing, nodes = node_to_edge(edges) idx = dict((n, i) for i, n in enumerate(nodes)) nedges = len(edges) n = len(nodes) m = Model() step = lambda x: "u_{0}".format(x) # Create variables vars = {} for i, (a, b, w) in enumerate(edges): vars[i] = m.addVar(obj=w, vtype=GRB.BINARY, name=str(i)) for u in nodes[1:]: u = step(u) vars[u] = m.addVar(obj=0, vtype=GRB.INTEGER, name=u) m.update() # Bounds for step variables for u in nodes[1:]: u = step(u) vars[u].lb = 1 vars[u].ub = n - 1 # Add degree constraint for v in nodes: incoming_edges = incoming[v] outgoing_edges = outgoing[v] m.addConstr(quicksum(vars[x] for x in incoming_edges) == 1) m.addConstr(quicksum(vars[x] for x in outgoing_edges) == 1) # Subtour elimination edge_store = dict(((idx[a], idx[b]), i) for i, (a, b, w) in enumerate(edges)) # Given a list of edges, finds the shortest subtour def subtour(s_edges): visited = [False] * n cycles = [] lengths = [] selected = [[] for i in range(n)] for x, y in s_edges: selected[x].append(y) while True: current = visited.index(False) thiscycle = [current] while True: visited[current] = True neighbors = [x for x in selected[current] if not visited[x]] if len(neighbors) == 0: break current = neighbors[0] thiscycle.append(current) cycles.append(thiscycle) lengths.append(len(thiscycle)) if sum(lengths) == n: break return cycles[lengths.index(min(lengths))] def subtourelim(model, where): if where != GRB.callback.MIPSOL: return selected = [] # make a list of edges selected in the solution sol = model.cbGetSolution([model._vars[i] for i in range(nedges)]) selected = [edges[i] for i, x in enumerate(sol) if x > .5] selected = [(idx[a], idx[b]) for a, b, w in selected] # find the shortest cycle in the selected edge list tour = subtour(selected) if len(tour) == n: return # add a subtour elimination constraint c = tour incident = [edge_store[a, b] for a, b in pairwise(c + [c[0]])] model.cbLazy(quicksum(model._vars[x] for x in incident) <= len(tour) - 1) m.update() m._vars = vars m.params.LazyConstraints = 1 m.optimize(subtourelim) selected = [v.varName for v in m.getVars() if v.x > .5] selected = [int(x) for x in selected if x[:2] != "u_"] results = sorted(x for i, x in enumerate(edges) if i in selected) \ if selected else None return results
def generateInstance(self): # Check that store has been intialized correctly if not all([x in self.store for x in ["Timehorizon", "h", "K", "a", "d", "s", "st"]]): logging.error('Store is not initialized correctly. Check for completeness of input-file.') return None model = Model("LotSolver") tHor = self.store["Timehorizon"] nPr = self.store["nProducts"] timeRange = range(1, tHor + 1) prodRange = range(1, nPr + 1) # Assume that production of products costs at least 1h, so a max of K products can be produced per period bigM = max(self.store["K"]) # generate Variables # boolean production bx = {} # lager l = {} # production x = {} for t in timeRange: for p in prodRange: x[p, t] = model.addVar(name="x_%d_%d" % (p, t), vtype="i") bx[p, t] = model.addVar(name="bx_%d_%d" % (p, t), vtype="b") for t in range(0, tHor + 1): for p in prodRange: l[p, t] = model.addVar(name="l_%d_%d" % (p, t), vtype="i", obj=float(self.store["h"][p-1])) # switch costs s = {} for t in range(0, tHor+1): for p1 in prodRange: for p2 in prodRange: # Switching to the same product does not cost anything - even if the file may say otherwise objective = float(self.store["s"][p1-1][p2-1]) if p1 != p2 else 0 s[p1, p2, t] = model.addVar(name="s_%d_%d_%d" % (p1, p2, t), vtype="b", obj=objective) model.modelSense = GRB.MINIMIZE model.update() for y in model.getVars(): logging.debug("%s obj %s", y.varName, y.obj) # Constraints # Initially only allow a single product logging.debug("%s == 1", [s[key].varName for key in s if key[2] == 0]) model.addConstr(quicksum(s[key] for key in s if key[2] == 0) == 1, name="single_switch_" + str(t)) # Only allow products in each period that actually has been switched to for t in timeRange: for p in prodRange: logging.debug("(%s) == %s", [s[key].varName for key in s if key[2] == t and (key[1] == p or key[0] == p)], bx[p, t].varName) model.addConstr(quicksum(s[key] for key in s if key[2] == t and (key[1] == p or key[0] == p)) >= bx[p,t], name="single_switch_" + str(t)) # Force bx = 1 iff x != 0 model.addConstr(x[p,t] >= bx[p,t]) model.addConstr(x[p,t] <= bigM * bx[p,t]) for t in timeRange: # Allow only a single switch each period logging.debug('Single switch constraint for ' + str([s[key].varName for key in s if key[2] == t])) model.addConstr(quicksum(s[key] for key in s if key[2] == t) == 1, name="single_switch_" + str(t)) # Only allow connected switches between t-1 and t for p in prodRange: logging.debug('valid_switch for ' + str([s[key].varName for key in s if key[2] == (t-1) and key[1] == p]) + " and " + str([s[key].varName for key in s if key[2] == t and key[0] == p])) model.addConstr(quicksum(s[key] for key in s if key[2] == (t-1) and key[1] == p) == quicksum(s[key] for key in s if key[2] == t and key[0] == p), name="valid_switch_%d_%d" % (p, t)) # Machine can't be occupied for more then K hours / period for t in timeRange: logging.debug("sum {} + sum {} <= {}".format([x[key].varName + "*" + str(self.store["a"][key[0]-1]) for key in x if key[1] == t], [s[key].varName + "*" + str(self.store["st"][key[0]-1][key[1]-1]) for key in s if key[2] == t], self.store["K"][t-1])) model.addConstr(quicksum(x[key]*self.store["a"][key[0]-1] for key in x if key[1] == t) + quicksum(s[key]*self.store["st"][key[0]-1][key[1]-1] for key in s if key[2] == t) <= self.store["K"][t-1]) # Initial warehouse stock for p in prodRange: logging.debug("%s == %s", l[p, 0].varName, self.store["l"][p-1]) model.addConstr(l[p, 0] == self.store["l"][p-1]) # Update warehouse stock inbetween periods + enforce demand to be met for t in range(1, tHor+1): for p in prodRange: logging.debug("{} = {} + {} - {}".format(l[p, t].varName, l[p, t-1].varName, x[p, t].varName, self.store["d"][p-1][t-1])) model.addConstr(l[p, t] == l[p, t-1] + x[p, t] - self.store["d"][p-1][t-1]) # solve it model.optimize() # Debugging printouts for y in model.getVars(): if y.x >= 0.001: logging.debug("%s = %s cost %d", y.varName, y.x, y.x*y.obj) for t in timeRange: logging.debug("%s + %s", (["{}[{}] * {}".format(x[key].x, x[key].varName, self.store["a"][key[0]-1]) for key in x if key[1] == t]), ([str(s[key].varName) + "*" + str(self.store["st"][key[0]-1][key[1]-1]) for key in s if key[2] == t and s[key].x >= 0.001])) self.model = model