def jsp_disjuntivo_manne(tempo, ordem, tempo_max=3600, fl_inteiro=True): if not jsp_checar_tempo_ordem(tempo, ordem): print("Matrizes de TEMPO e ORDEM incorretas!") # Criando parâmetros ###################################################### # Número de máquinas e jobs m, n = jsp_get_dimensoes(tempo) # Criando conjunto de máquinas e jobs Maquinas = range(m) Jobs = range(n) ########################################################################### # Criando dicionario do Problema ########################################## Problema = montar_dic_problema(m, n, Maquinas, Jobs, tempo, ordem, fl_inteiro) ########################################################################### # Criando instancia do modelo ############################################# modelo = Model(name='manne') modelo.parameters.timelimit = tempo_max ########################################################################### # Criando variáveis de decisão ############################################ x = jsp_manne_var_x(modelo, Problema) # início do job j na máquina i z = jsp_manne_var_z(modelo, Problema) # 1 se j precede a k na máquina i cmax = jsp_manne_var_cmax(modelo, Problema) # makespan y = None ########################################################################### # Restrições ############################################################## jsp_manne_rest_ordem_maq_job(modelo, x, z, cmax, y, Problema) jsp_manne_rest_precedencia(modelo, x, z, cmax, y, Problema) jsp_manne_rest_makespan(modelo, x, z, cmax, y, Problema) ########################################################################### # Função objetivo: jsp_fo_makespan(modelo, x, z, cmax, y, Problema) ########################################################################### return modelo
def weigh_data_to_match_preferences(data_pool, user_preferences, min_weight=.01): # DataFrames zu Vektoren input_matrix = to_numpy(data_pool, is_matrix=True) target_vector = to_numpy(user_preferences) # definiere das Model: # finde eine Gewichtung, sodass der Abstand der gewichteten ETFs zu den Präferenzen minimal ist # unter der Bedingung, dass die Gewichte null oder zwischen min_weight und eins liegen und zusammen eins ergeben model = Model() weights = np.array( model.semicontinuous_var_list(len(input_matrix), lb=min_weight, ub=1)) model.minimize(objective_function(weights, input_matrix, target_vector)) model.add_constraint(sum(weights) == 1) # löse das Modell result = model.solve() return { "result": indices_to_tickers(result.as_index_dict(), data_pool), "deviance": result.get_objective_value(), "status_code": model.solve_details.status_code }
def run_GAP_model(As, Bs, Cs, url=None, key=None, **kwargs): with Model('GAP per Wolsey -without- Lagrangian Relaxation', **kwargs) as mdl: print("#As={}, #Bs={}, #Cs={}".format(len(As), len(Bs), len(Cs))) number_of_cs = len(C) # variables x_vars = [mdl.binary_var_list(c, name=None) for c in Cs] # constraints mdl.add_constraints(mdl.sum(xv) <= 1 for xv in x_vars) mdl.add_constraints(mdl.sum(x_vars[ii][j] * As[ii][j] for ii in range(number_of_cs)) <= bs for j, bs in enumerate(Bs)) # objective total_profit = mdl.sum(mdl.scal_prod(x_i, c_i) for c_i, x_i in zip(Cs, x_vars)) mdl.maximize(total_profit) # mdl.print_information() s = mdl.solve(url=url, key=key) assert s is not None obj = s.objective_value print("* GAP with no relaxation run OK, best objective is: {:g}".format(obj)) return obj
def test_qubo_gas_int_paper_example(self): """Test the example from https://arxiv.org/abs/1912.04088.""" # Input. model = Model() x_0 = model.binary_var(name='x0') x_1 = model.binary_var(name='x1') x_2 = model.binary_var(name='x2') model.minimize(-x_0+2*x_1-3*x_2-2*x_0*x_2-1*x_1*x_2) op = QuadraticProgram() op.from_docplex(model) # Get the optimum key and value. n_iter = 10 gmf = GroverOptimizer(6, num_iterations=n_iter, quantum_instance=self.q_instance) results = gmf.solve(op) self.validate_results(op, results)
def to_quadratic_program(self) -> QuadraticProgram: """Convert a number partitioning problem instance into a :class:`~qiskit_optimization.problems.QuadraticProgram` Returns: The :class:`~qiskit_optimization.problems.QuadraticProgram` created from the number partitioning problem instance. """ mdl = Model(name="Number partitioning") x = { i: mdl.binary_var(name=f"x_{i}") for i in range(len(self._number_set)) } mdl.add_constraint( mdl.sum(num * (-2 * x[i] + 1) for i, num in enumerate(self._number_set)) == 0) op = from_docplex_mp(mdl) return op
def to_quadratic_program(self) -> QuadraticProgram: """Convert an SK model problem instance into a :class:`~qiskit_optimization.problems.QuadraticProgram`. Returns: The :class:`~qiskit_optimization.problems.QuadraticProgram` created from the SK problem instance. """ mdl = Model(name="SK-model") x = mdl.binary_var_list(self._graph.number_of_nodes()) objective = mdl.sum( -1 / np.sqrt(self._num_sites) * self._graph.edges[i, j]["weight"] * (2 * x[i] - 1) * (2 * x[j] - 1) for i, j in self._graph.edges) # we converted the standard H(x)=-1/\sqrt{n} \sum w_{ij}x_ix_j, where x_i\in\pm 1 to binary. mdl.minimize(objective) return from_docplex_mp(mdl)
def test_qubo_gas_int_paper_example(self, simulator): """ Test the example from https://arxiv.org/abs/1912.04088 using the state vector simulator and the qasm simulator """ # Input. model = Model() x_0 = model.binary_var(name="x0") x_1 = model.binary_var(name="x1") x_2 = model.binary_var(name="x2") model.minimize(-x_0 + 2 * x_1 - 3 * x_2 - 2 * x_0 * x_2 - 1 * x_1 * x_2) op = from_docplex_mp(model) # Get the optimum key and value. q_instance = self.sv_simulator if simulator == "sv" else self.qasm_simulator gmf = GroverOptimizer(6, num_iterations=self.n_iter, quantum_instance=q_instance) results = gmf.solve(op) self.validate_results(op, results)
def to_quadratic_program(self) -> QuadraticProgram: """Convert a Max-cut problem instance into a :class:`~qiskit_optimization.problems.QuadraticProgram` Returns: The :class:`~qiskit_optimization.problems.QuadraticProgram` created from the Max-cut problem instance. """ mdl = Model(name='Max-cut') x = {i: mdl.binary_var(name='x_{0}'.format(i)) for i in range(self._graph.number_of_nodes())} for w, v in self._graph.edges: self._graph.edges[w, v].setdefault('weight', 1) objective = mdl.sum(self._graph.edges[i, j]['weight'] * x[i] * (1 - x[j]) + self._graph.edges[i, j]['weight'] * x[j] * (1 - x[i]) for i, j in self._graph.edges) mdl.maximize(objective) op = QuadraticProgram() op.from_docplex(mdl) return op
def test_continuous_variable_decode(self): """Test decode func of IntegerToBinaryConverter for continuous variables""" mdl = Model("test_continuous_varable_decode") c = mdl.continuous_var(lb=0, ub=10.9, name="c") x = mdl.binary_var(name="x") mdl.maximize(c + x * x) op = from_docplex_mp(mdl) converter = IntegerToBinary() op = converter.convert(op) admm_params = ADMMParameters() qubo_optimizer = MinimumEigenOptimizer(NumPyMinimumEigensolver()) continuous_optimizer = CplexOptimizer() solver = ADMMOptimizer( qubo_optimizer=qubo_optimizer, continuous_optimizer=continuous_optimizer, params=admm_params, ) result = solver.solve(op) new_x = converter.interpret(result.x) self.assertEqual(new_x[0], 10.9)
def test_docplex_constant_and_quadratic_terms_in_object_function(self): # Create an Ising Homiltonian with docplex laplacian = np.array([[-3., 1., 1., 1.], [1., -2., 1., -0.], [1., 1., -3., 1.], [1., -0., 1., -2.]]) mdl = Model() n = laplacian.shape[0] bias = [0] * 4 x = {i: mdl.binary_var(name='x_{0}'.format(i)) for i in range(n)} couplers_func = mdl.sum(2 * laplacian[i, j] * (2 * x[i] - 1) * (2 * x[j] - 1) for i in range(n - 1) for j in range(i, n)) bias_func = mdl.sum(float(bias[i]) * x[i] for i in range(n)) ising_func = couplers_func + bias_func mdl.minimize(ising_func) qubitOp, offset = docplex.get_qubitops(mdl) ee = ExactEigensolver(qubitOp, k=1) result = ee.run() expected_result = -22 # Compare objective self.assertEqual(result['energy'] + offset, expected_result)
def test_integer_variables(self): """Tests ADMM with integer variables.""" mdl = Model("integer-variables") v = mdl.integer_var(lb=5, ub=20, name="v") w = mdl.continuous_var(name="w", lb=0.0) mdl.minimize(v + w) op = from_docplex_mp(mdl) solver = ADMMOptimizer() solution = solver.solve(op) self.assertIsNotNone(solution) self.assertIsInstance(solution, ADMMOptimizationResult) self.assertIsNotNone(solution.x) np.testing.assert_almost_equal([5.0, 0.0], solution.x, 3) self.assertIsNotNone(solution.fval) np.testing.assert_almost_equal(5.0, solution.fval, 3) self.assertIsNotNone(solution.state) self.assertIsInstance(solution.state, ADMMState)
def test_integer_variables(self): """Tests ADMM with integer variables.""" mdl = Model('integer-variables') v = mdl.integer_var(lb=5, ub=20, name='v') w = mdl.continuous_var(name='w', lb=0.) mdl.minimize(v + w) op = QuadraticProgram() op.from_docplex(mdl) solver = ADMMOptimizer() solution = solver.solve(op) self.assertIsNotNone(solution) self.assertIsInstance(solution, ADMMOptimizationResult) self.assertIsNotNone(solution.x) np.testing.assert_almost_equal([5., 0.], solution.x, 3) self.assertIsNotNone(solution.fval) np.testing.assert_almost_equal(5., solution.fval, 3) self.assertIsNotNone(solution.state) self.assertIsInstance(solution.state, ADMMState)
def test_admm_maximization(self): """Tests a simple maximization problem using ADMM optimizer""" mdl = Model('simple-max') c = mdl.continuous_var(lb=0, ub=10, name='c') x = mdl.binary_var(name='x') mdl.maximize(c + x * x) op = QuadraticProgram() op.from_docplex(mdl) admm_params = ADMMParameters() solver = ADMMOptimizer(params=admm_params, continuous_optimizer=CobylaOptimizer()) solution = solver.solve(op) self.assertIsNotNone(solution) self.assertIsInstance(solution, ADMMOptimizationResult) self.assertIsNotNone(solution.x) np.testing.assert_almost_equal([10, 0], solution.x, 3) self.assertIsNotNone(solution.fval) np.testing.assert_almost_equal(10, solution.fval, 3) self.assertIsNotNone(solution.state) self.assertIsInstance(solution.state, ADMMState)
def max_cut_qp(adjacency_matrix: np.ndarray) -> QuadraticProgram: """ Creates the max-cut instance based on the adjacency graph. """ size = len(adjacency_matrix) mdl = Model() x = [mdl.binary_var('x%s' % i) for i in range(size)] objective_terms = [] for i in range(size): for j in range(size): if adjacency_matrix[i, j] != 0.: objective_terms.append( adjacency_matrix[i, j] * x[i] * (1 - x[j])) objective = mdl.sum(objective_terms) mdl.maximize(objective) q_p = QuadraticProgram() q_p.from_docplex(mdl) return q_p
def test_continuous_variable_decode(self): """ Test decode func of IntegerToBinaryConverter for continuous variables""" try: mdl = Model('test_continuous_varable_decode') c = mdl.continuous_var(lb=0, ub=10.9, name='c') x = mdl.binary_var(name='x') mdl.maximize(c + x * x) op = QuadraticProgram() op.from_docplex(mdl) converter = IntegerToBinary() op = converter.convert(op) admm_params = ADMMParameters() qubo_optimizer = MinimumEigenOptimizer(NumPyMinimumEigensolver()) continuous_optimizer = CplexOptimizer() solver = ADMMOptimizer( qubo_optimizer=qubo_optimizer, continuous_optimizer=continuous_optimizer, params=admm_params, ) result = solver.solve(op) new_x = converter.interpret(result.x) self.assertEqual(new_x[0], 10.9) except MissingOptionalLibraryError as ex: self.skipTest(str(ex))
def make_cutstock_pattern_generation_model(items, roll_width, **kwargs): gen_model = Model(name='cutstock_generate_patterns', **kwargs) # store data gen_model.items = items gen_model.roll_width = roll_width # default values gen_model.duals = [1] * len(items) # 1. create variables: one per item gen_model.use_vars = gen_model.integer_var_list(keys=items, ub=999999, name='use') # 2 setup constraint: # --- sum of item usage times item sizes must be less than roll width gen_model.add( gen_model.dot(gen_model.use_vars, (it.size for it in items)) <= roll_width) # store dual expression for dynamic edition gen_model.use_dual_expr = 1 - gen_model.dot(gen_model.use_vars, gen_model.duals) # minimize gen_model.minimize(gen_model.use_dual_expr) return gen_model
def no_linearization(quad, **kwargs): """ Solve a problem using the solver's default approach to quadratics (for cplex, this is the std linearization) """ n = quad.n c = quad.c m = Model(name='no_linearization') x = m.binary_var_list(n, name="binary_var") if type(quad) is Knapsack: #HSP and UQP don't have cap constraint #add capacity constraint(s) for k in range(quad.m): m.add_constraint(m.sum(x[i]*quad.a[k][i] for i in range(n)) <= quad.b[k]) #k_item constraint if necessary (if KQKP or HSP) if quad.num_items > 0: m.add_constraint(m.sum(x[i] for i in range(n)) == quad.num_items) #compute quadratic values contirbution to obj quadratic_values = 0 for i in range(n): for j in range(i+1,n): quadratic_values = quadratic_values + (x[i]*x[j]*quad.C[i,j]) #set objective function linear_values = m.sum(x[i]*c[i] for i in range(n)) m.maximize(linear_values + quadratic_values) return [m, 0]
def qsap_ss(qsap, **kwargs): """ Sherali-Smith Linear Formulation for the quadratic semi-assignment problem """ n = qsap.n m = qsap.m e = qsap.e c = qsap.c #create model and add variables mdl = Model(name='qsap_ss') x = mdl.binary_var_matrix(m,n,name="binary_var") s = mdl.continuous_var_matrix(m,n) y = mdl.continuous_var_matrix(m,n) mdl.add_constraints((sum(x[i,k] for k in range(n)) == 1) for i in range(m)) start = timer() U = np.zeros((m,n)) L = np.zeros((m,n)) bound_mdl = Model(name='upper_bound_model') bound_x = bound_mdl.continuous_var_matrix(keys1=m,keys2=n,ub=1,lb=0) bound_mdl.add_constraints((sum(bound_x[i,k] for k in range(n)) == 1) for i in range(m)) for i in range(m-1): for k in range(n): # solve for upper bound bound_mdl.set_objective(sense="max", expr=sum(sum(c[i,k,j,l]*bound_x[j,l] for l in range(n)) for j in range(i+1,m))) bound_mdl.solve() U[i,k] = bound_mdl.objective_value # solve for lower bound bound_mdl.set_objective(sense="min", expr=sum(sum(c[i,k,j,l]*bound_x[j,l] for l in range(n)) for j in range(i+1,m))) bound_mdl.solve() L[i,k] = bound_mdl.objective_value # end bound model bound_mdl.end() end = timer() setup_time = end-start #add auxiliary constraints for i in range(m-1): for k in range(n): mdl.add_constraint(sum(sum(c[i,k,j,l]*x[j,l] for j in range(i+1,m)) for l in range(n))-s[i,k]-L[i,k]==y[i,k]) mdl.add_constraint(y[i,k] <= (U[i,k]-L[i,k])*(1-x[i,k])) mdl.add_constraint(s[i,k] <= (U[i,k]-L[i,k])*x[i,k]) #set objective function linear_values = sum(sum(e[i,k]*x[i,k] for i in range(m)) for k in range(n)) mdl.maximize(linear_values + sum(sum(s[i,k]+(x[i,k]*L[i,k]) for i in range(m-1)) for k in range(n))) #return model + setup time return [mdl, setup_time]
def qsap_elf(qsap, **kwargs): """ extended linear formulation for the quadratic semi-assignment problem """ n = qsap.n m = qsap.m e = qsap.e c = qsap.c mdl = Model(name='qsap_elf') x = mdl.binary_var_matrix(m,n,name="binary_var") z = np.array([[[[[[mdl.continuous_var() for i in range(n)]for j in range(m)] for k in range(n)]for l in range(m)] for s in range(n)] for t in range(m)]) mdl.add_constraints((sum(x[i,k] for k in range(n)) == 1) for i in range(m)) #add auxiliary constraints for i in range(m-1): for j in range(i+1,m): for k in range(n): for l in range(n): mdl.add_constraint(z[i,k,i,k,j,l] + z[j,l,i,k,j,l] <= 1) mdl.add_constraint(x[i,k] + z[i,k,i,k,j,l] <= 1) mdl.add_constraint(x[j,l] + z[j,l,i,k,j,l] <= 1) mdl.add_constraint(x[i,k] + z[i,k,i,k,j,l] + z[j,l,i,k,j,l] >= 1) mdl.add_constraint(x[j,l] + z[i,k,i,k,j,l] + z[j,l,i,k,j,l] >= 1) #compute quadratic values contirbution to obj constant = 0 quadratic_values = 0 for i in range(m-1): for j in range(i+1,m): for k in range(n): for l in range(n): constant = constant + c[i,k,j,l] quadratic_values = quadratic_values + (c[i,k,j,l]*(z[i,k,i,k,j,l]+z[j,l,i,k,j,l])) linear_values = mdl.sum(x[i,k]*e[i,k] for k in range(n) for i in range(m)) mdl.maximize(linear_values + constant - quadratic_values) #return model + setup time=0 return [mdl, 0]
def build_sports(context=None): print("* building sport scheduling model instance") mdl = Model('sportSchedCPLEX', context=context) nb_teams_in_division, nb_intra_divisional, nb_inter_divisional = nbs assert len(team_div1) == len(team_div2) mdl.teams = list(team_div1 | team_div2) # team index ranges from 1 to 2N team_range = range(1, 2 * nb_teams_in_division + 1) # Calculate the number of weeks necessary. nb_weeks = (nb_teams_in_division - 1) * nb_intra_divisional + nb_teams_in_division * nb_inter_divisional weeks = range(1, nb_weeks + 1) mdl.weeks = weeks print("{0} games, {1} intradivisional, {2} interdivisional" .format(nb_weeks, (nb_teams_in_division - 1) * nb_intra_divisional, nb_teams_in_division * nb_inter_divisional)) # Season is split into two halves. first_half_weeks = range(1, nb_weeks // 2 + 1) nb_first_half_games = nb_weeks // 3 # All possible matches (pairings) and whether of not each is intradivisional. matches = [Match(t1, t2, 1 if (t2 <= nb_teams_in_division or t1 > nb_teams_in_division) else 0) for t1 in team_range for t2 in team_range if t1 < t2] mdl.matches = matches # Number of games to play between pairs depends on # whether the pairing is intradivisional or not. nb_play = {m: nb_intra_divisional if m.is_divisional == 1 else nb_inter_divisional for m in matches} plays = mdl.binary_var_matrix(keys1=matches, keys2=weeks, name=lambda mw: "play_%d_%d_w%d" % (mw[0].team1, mw[0].team2, mw[1])) mdl.plays = plays for m in matches: mdl.add_constraint(mdl.sum(plays[m, w] for w in weeks) == nb_play[m], "correct_nb_games_%d_%d" % (m.team1, m.team2)) for w in weeks: # Each team must play exactly once in a week. for t in team_range: max_teams_in_division = (plays[m, w] for m in matches if m.team1 == t or m.team2 == t) mdl.add_constraint(mdl.sum(max_teams_in_division) == 1, "plays_exactly_once_%d_%s" % (w, t)) # Games between the same teams cannot be on successive weeks. for m in matches: if w < nb_weeks: mdl.add_constraint(plays[m, w] + plays[m, w + 1] <= 1) # Some intradivisional games should be in the first half. for t in team_range: max_teams_in_division = [plays[m, w] for w in first_half_weeks for m in matches if m.is_divisional == 1 and (m.team1 == t or m.team2 == t)] mdl.add_constraint(mdl.sum(max_teams_in_division) >= nb_first_half_games, "in_division_first_half_%s" % t) # postpone divisional matches as much as possible # we weight each play variable with the square of w. mdl.maximize(mdl.sum(plays[m, w] * w * w for w in weeks for m in matches if m.is_divisional)) return mdl
def solve(dat, out, err, progress): assert isinstance(progress, Progress) assert isinstance(out, LogFile) and isinstance(err, LogFile) assert dataFactory.good_tic_dat_object(dat) assert not dataFactory.find_foreign_key_failures(dat) assert not dataFactory.find_data_type_failures(dat) out.write("COG output log\n%s\n\n" % time_stamp()) err.write("COG error log\n%s\n\n" % time_stamp()) def get_distance(x, y): if (x, y) in dat.distance: return dat.distance[x, y]["distance"] if (y, x) in dat.distance: return dat.distance[y, x]["distance"] return float("inf") def can_assign(x, y): return dat.sites[y]["center_status"] == "Can Be Center" \ and get_distance(x,y)<float("inf") unassignables = [ n for n in dat.sites if not any(can_assign(n, y) for y in dat.sites) and dat.sites[n]["demand"] > 0 ] if unassignables: # Infeasibility detected. Generate an error table and return None err.write("The following sites have demand, but can't be " + "assigned to anything.\n") err.log_table("Un-assignable Demand Points", [["Site"]] + [[_] for _ in unassignables]) return useless = [ n for n in dat.sites if not any(can_assign(y, n) for y in dat.sites) and dat.sites[n]["demand"] == 0 ] if useless: # Log in the error table as a warning, but can still try optimization. err.write( "The following sites have no demand, and can't serve as the " + "center point for any assignments.\n") err.log_table("Useless Sites", [["Site"]] + [[_] for _ in useless]) progress.numerical_progress("Feasibility Analysis", 100) m = Model("cog") assign_vars = {(n, assigned_to): m.binary_var(name="%s_%s" % (n, assigned_to)) for n in dat.sites for assigned_to in dat.sites if can_assign(n, assigned_to)} open_vars = { n: m.binary_var(name="open_%s" % n) for n in dat.sites if dat.sites[n]["center_status"] == "Can Be Center" } if not open_vars: err.write("Nothing can be a center!\n") # Infeasibility detected. return progress.numerical_progress("Core Model Creation", 50) assign_slicer = Slicer(assign_vars) for n, r in dat.sites.items(): if r["demand"] > 0: m.add_constraint(m.sum( assign_vars[n, assign_to] for _, assign_to in assign_slicer.slice(n, "*")) == 1, ctname="must_assign_%s" % n) crippledfordemo = "formulation" in dat.parameters and \ dat.parameters["formulation"]["value"] == "weak" for assigned_to, r in dat.sites.items(): if r["center_status"] == "Can Be Center": _assign_vars = [ assign_vars[n, assigned_to] for n, _ in assign_slicer.slice("*", assigned_to) ] if crippledfordemo: m.add_constraint(m.sum(_assign_vars) <= len(_assign_vars) * open_vars[assigned_to], ctname="weak_force_open%s" % assigned_to) else: for var in _assign_vars: m.add_constraint(var <= open_vars[assigned_to], ctname="strong_force_open_%s" % assigned_to) number_of_centroids = dat.parameters["Number of Centroids"]["value"] \ if "Number of Centroids" in dat.parameters else 1 if number_of_centroids <= 0: err.write("Need to specify a positive number of centroids\n" ) # Infeasibility detected. return m.add_constraint(m.sum(v for v in open_vars.values()) == number_of_centroids, ctname="numCentroids") if "mipGap" in dat.parameters: m.parameters.mip.tolerances.mipgap = dat.parameters["mipGap"]["value"] progress.numerical_progress("Core Model Creation", 100) m.minimize( m.sum(var * get_distance(n, assigned_to) * dat.sites[n]["demand"] for (n, assigned_to), var in assign_vars.items())) progress.add_cplex_listener("COG Optimization", m) if m.solve(): progress.numerical_progress("Core Optimization", 100) cplex_soln = m.solution sln = solutionFactory.TicDat() # see code trick http://ibm.co/2aQwKYG if m.solve_details.status == 'optimal': sln.parameters["Lower Bound"] = cplex_soln.get_objective_value() else: sln.parameters["Lower Bound"] = m.solve_details.get_best_bound() sln.parameters["Upper Bound"] = cplex_soln.get_objective_value() out.write('Upper Bound: %g\n' % sln.parameters["Upper Bound"]["value"]) out.write('Lower Bound: %g\n' % sln.parameters["Lower Bound"]["value"]) def almostone(x): return abs(x - 1) < 0.0001 for (n, assigned_to), var in assign_vars.items(): if almostone(cplex_soln.get_value(var)): sln.assignments[n, assigned_to] = {} for n, var in open_vars.items(): if almostone(cplex_soln.get_value(var)): sln.openings[n] = {} out.write('Number Centroids: %s\n' % len(sln.openings)) progress.numerical_progress("Full Cog Solve", 100) return sln
def test_admm_ex6_max(self): """Example 6 as maximization""" try: mdl = Model('ex6-max') # pylint:disable=invalid-name v = mdl.binary_var(name='v') w = mdl.binary_var(name='w') t = mdl.binary_var(name='t') u = mdl.continuous_var(name='u') # mdl.minimize(v + w + t + 5 * (u - 2) ** 2) mdl.maximize(-v - w - t - 5 * (u - 2)**2) mdl.add_constraint(v + 2 * w + t + u <= 3, "cons1") mdl.add_constraint(v + w + t >= 1, "cons2") mdl.add_constraint(v + w == 1, "cons3") op = QuadraticProgram() op.from_docplex(mdl) qubo_optimizer = CplexOptimizer() continuous_optimizer = CplexOptimizer() admm_params = ADMMParameters(rho_initial=1001, beta=1000, factor_c=900, max_iter=100, three_block=True, tol=1.e-6) solver = ADMMOptimizer(params=admm_params, qubo_optimizer=qubo_optimizer, continuous_optimizer=continuous_optimizer) solution = solver.solve(op) self.assertIsNotNone(solution) self.assertIsInstance(solution, ADMMOptimizationResult) self.assertIsNotNone(solution.x) np.testing.assert_almost_equal([1., 0., 0., 2.], solution.x, 3) self.assertIsNotNone(solution.fval) np.testing.assert_almost_equal(-1., solution.fval, 3) self.assertIsNotNone(solution.state) self.assertIsInstance(solution.state, ADMMState) except NameError as ex: self.skipTest(str(ex))
def make_custstock_master_model(item_table, pattern_table, fill_table, roll_width, **kwargs): m = Model(name='custock_master', **kwargs) # store data as properties m.items = [TItem.make(it_row) for it_row in item_table] m.items_by_id = {it.id: it for it in m.items} m.patterns = [TPattern(*pattern_row) for pattern_row in pattern_table] m.patterns_by_id = {pat.id: pat for pat in m.patterns} m.max_pattern_id = max(pt.id for pt in m.patterns) # build a dictionary storing how much each pattern fills each item. m.pattern_item_filled = {(m.patterns_by_id[p], m.items_by_id[i]): f for (p, i, f) in fill_table} m.roll_width = roll_width # --- variables # one cut var per pattern... m.MAX_CUT = 9999 m.cut_vars = m.continuous_var_dict(m.patterns, lb=0, ub=m.MAX_CUT, name='cut') # --- add fill constraints # all_patterns = m.patterns all_items = m.items m.item_fill_cts = [] for item in all_items: item_fill_ct = m.sum( m.cut_vars[p] * m.pattern_item_filled.get((p, item), 0) for p in all_patterns) >= item.demand item_fill_ct.name = 'ct_fill_{0!s}'.format(item) m.item_fill_cts.append(item_fill_ct) m.add_constraints(m.item_fill_cts) # --- minimize total cut stock m.total_cutting_cost = m.sum(m.cut_vars[p] * p.cost for p in all_patterns) m.minimize(m.total_cutting_cost) return m
def build_production_problem(products, resources, consumptions, context=None): """ Takes as input: - a list of product tuples (name, demand, inside, outside) - a list of resource tuples (name, capacity) - a list of consumption tuples (product_name, resource_named, consumed) """ mdl = Model('production', context=context) # --- decision variables --- mdl.inside_vars = mdl.continuous_var_dict(products, name='inside') mdl.outside_vars = mdl.continuous_var_dict(products, name='outside') # --- constraints --- # demand satisfaction for prod in products: mdl.add_constraint(mdl.inside_vars[prod] + mdl.outside_vars[prod] >= prod[1]) # --- resource capacity --- for res in resources: mdl.add_constraint(mdl.sum([mdl.inside_vars[p] * consumptions[p[0], res[0]] for p in products]) <= res[1]) # --- objective --- mdl.total_inside_cost = mdl.sum(mdl.inside_vars[p] * p[2] for p in products) mdl.total_outside_cost = mdl.sum(mdl.outside_vars[p] * p[3] for p in products) mdl.minimize(mdl.total_inside_cost + mdl.total_outside_cost) return mdl
def run_GAP_model(As, Bs, Cs, context=None, **kwargs): mdl = Model('GAP per Wolsey -without- Lagrangian Relaxation', context=context) print("#As={}, #Bs={}, #Cs={}".format(len(As), len(Bs), len(Cs))) number_of_cs = len(C) # variables x_vars = [mdl.binary_var_list(c, name=None) for c in Cs] # constraints for xv in x_vars: mdl.add_constraint(mdl.sum(xv) <= 1) for j, bs in enumerate(Bs): mdl.add_constraint(mdl.sum(x_vars[ii][j] * As[ii][j] for ii in range(number_of_cs)) <= bs) # objective total_profit = mdl.sum(mdl.sum(c_ij * x_ij for c_ij, x_ij in zip(c_i, x_i)) for c_i, x_i in zip(Cs, x_vars)) mdl.maximize(total_profit) mdl.print_information() assert mdl.solve(**kwargs) obj = mdl.objective_value mdl.print_information() print("* GAP with no relaxation run OK, best objective is: {:g}".format(obj)) mdl.end() return obj
def build_diet_model(**kwargs): # Create tuples with named fields for foods and nutrients Food = namedtuple("Food", ["name", "unit_cost", "qmin", "qmax"]) food = [Food(*f) for f in FOODS] Nutrient = namedtuple("Nutrient", ["name", "qmin", "qmax"]) nutrients = [Nutrient(*row) for row in NUTRIENTS] food_nutrients = {(fn[0], nutrients[n].name): fn[1 + n] for fn in FOOD_NUTRIENTS for n in range(len(NUTRIENTS))} # Model mdl = Model("diet", **kwargs) # Decision variables, limited to be >= Food.qmin and <= Food.qmax qty = dict((f, mdl.continuous_var(f.qmin, f.qmax, f.name)) for f in food) # Limit range of nutrients, and mark them as KPIs for n in nutrients: amount = mdl.sum(qty[f] * food_nutrients[f.name, n.name] for f in food) mdl.add_range(n.qmin, amount, n.qmax) mdl.add_kpi(amount, publish_name="Total %s" % n.name) # Minimize cost mdl.minimize(mdl.sum(qty[f] * f.unit_cost for f in food)) mdl.print_information() return mdl
def run_GAP_model_with_Lagrangian_relaxation(As, Bs, Cs, max_iters=101, context=None, **kwargs): mdl = Model('GAP per Wolsey -with- Lagrangian Relaxation', context=context) print("#As={}, #Bs={}, #Cs={}".format(len(As), len(Bs), len(Cs))) c_range = range(len(Cs)) # variables x_vars = [mdl.binary_var_list(c, name=None) for c in Cs] p_vars = [mdl.continuous_var(lb=0) for _ in Cs] # new for relaxation for (xv, pv) in izip(x_vars, p_vars): # was mdl.add_constraint(mdl.sum(xVars[i]) <= 1) mdl.add_constraint(mdl.sum(xv) == 1 - pv) for j, bs in enumerate(Bs): mdl.add_constraint(mdl.sum(x_vars[ii][j] * As[ii][j] for ii in c_range) <= bs) # lagrangian relaxation loop eps = 1e-6 loop_count = 0 best = 0 initial_multiplier = 1 multipliers = [initial_multiplier] * len(Cs) total_profit = mdl.sum(mdl.sum(c_ij * x_ij for c_ij, x_ij in zip(c_i, x_i)) for c_i, x_i in zip(Cs, x_vars)) mdl.add_kpi(total_profit, "Total profit") while loop_count <= max_iters: loop_count += 1 # rebuilt at each loop iteration total_penalty = mdl.sum(p_vars[i] * multipliers[i] for i in c_range) mdl.maximize(total_profit + total_penalty) ok = mdl.solve(**kwargs) if not ok: print("*** solve fails, stopping at iteration: %d" % loop_count) break best = mdl.objective_value penalties = [pv.solution_value for pv in p_vars] print('%d> new lagrangian iteration, obj=%g, m=%s, p=%s' % (loop_count, best, str(multipliers), str(penalties))) do_stop = True justifier = 0 for k in c_range: penalized_violation = penalties[k] * multipliers[k] if penalized_violation >= eps: do_stop = False justifier = penalized_violation break if do_stop: print("* Lagrangian relaxation succeeds, best={:g}, penalty={:g}, #iterations={}" .format(best, total_penalty.solution_value, loop_count)) break else: # update multipliers and start loop again. scale_factor = 1.0 / float(loop_count) multipliers = [max(multipliers[i] - scale_factor * penalties[i], 0.) for i in c_range] print('{}> -- loop continues, m={}, justifier={:g}'.format(loop_count, str(multipliers), justifier)) return best
def test_admm_ex6(self): """Example 6 as a unit test. Example 6 is reported in: Gambella, C., & Simonetto, A. (2020). Multi-block ADMM Heuristics for Mixed-Binary Optimization on Classical and Quantum Computers. arXiv preprint arXiv:2001.02069.""" try: mdl = Model('ex6') # pylint:disable=invalid-name v = mdl.binary_var(name='v') w = mdl.binary_var(name='w') t = mdl.binary_var(name='t') u = mdl.continuous_var(name='u') mdl.minimize(v + w + t + 5 * (u - 2)**2) mdl.add_constraint(v + 2 * w + t + u <= 3, "cons1") mdl.add_constraint(v + w + t >= 1, "cons2") mdl.add_constraint(v + w == 1, "cons3") op = QuadraticProgram() op.from_docplex(mdl) qubo_optimizer = CplexOptimizer() continuous_optimizer = CplexOptimizer() admm_params = ADMMParameters(rho_initial=1001, beta=1000, factor_c=900, max_iter=100, three_block=True, tol=1.e-6) solver = ADMMOptimizer(params=admm_params, qubo_optimizer=qubo_optimizer, continuous_optimizer=continuous_optimizer) solution = solver.solve(op) self.assertIsNotNone(solution) self.assertIsInstance(solution, ADMMOptimizationResult) self.assertIsNotNone(solution.x) np.testing.assert_almost_equal([1., 0., 0., 2.], solution.x, 3) self.assertIsNotNone(solution.fval) np.testing.assert_almost_equal(1., solution.fval, 3) self.assertIsNotNone(solution.state) self.assertIsInstance(solution.state, ADMMState) except NameError as ex: self.skipTest(str(ex))
def glovers_linearization(quad, bounds="tight", constraints="original", lhs_constraints=False, use_diagonal=False, **kwargs): """ Apply glovers linearization to a QP and return resulting model """ n = quad.n c = quad.c C = quad.C a = quad.a b = quad.b #put linear terms along diagonal of quadratic matrix. set linear terms to zero if use_diagonal: for i in range(n): C[i,i] = c[i] c[i] = 0 #create model and add variables m = Model(name='glovers_linearization_'+bounds+'_'+constraints) x = m.binary_var_list(n, name="binary_var") if type(quad) is Knapsack: #HSP and UQP don't have cap constraint #add capacity constraint(s) for k in range(quad.m): m.add_constraint(m.sum(x[i]*a[k][i] for i in range(n)) <= b[k]) #k_item constraint if necessary (if KQKP or HSP) if quad.num_items > 0: m.add_constraint(m.sum(x[i] for i in range(n)) == quad.num_items) #determine bounds for each column of C #U1,L1 must take item at index j, U0,L0 must not take U1 = np.zeros(n) L0 = np.zeros(n) U0 = np.zeros(n) L1 = np.zeros(n) start = timer() if(bounds=="original" or type(quad)==UQP): for j in range(n): col = C[:, j] pos_take_vals = col > 0 pos_take_vals[j] = True U1[j] = np.sum(col[pos_take_vals]) neg_take_vals = col < 0 neg_take_vals[j] = False L0[j] = np.sum(col[neg_take_vals]) if lhs_constraints: U0[j] = U1[j] - col[j] L1[j] = L0[j] + col[j] elif(bounds=="tight" or bounds=="tighter"): bound_m = Model(name='bound_model') if bounds == "tight": #for tight bounds solve for upper bound of col w/ continuous vars bound_x = bound_m.continuous_var_list(n, ub=1, lb=0) elif bounds == "tighter": #for even tighter bounds, instead use binary vars bound_x = bound_m.binary_var_list(n, ub=1, lb=0) if type(quad) is Knapsack: for k in range(quad.m): #add capacity constraints bound_m.add_constraint(bound_m.sum(bound_x[i]*a[k][i] for i in range(n)) <= b[k]) if quad.num_items > 0: bound_m.add_constraint(bound_m.sum(bound_x[i] for i in range(n)) == quad.num_items) for j in range(n): # solve for upper bound U1 bound_m.set_objective(sense="max", expr=bound_m.sum(C[i,j]*bound_x[i] for i in range(n))) u_con = bound_m.add_constraint(bound_x[j]==1) bound_m.solve() if "OPTIMAL_SOLUTION" not in str(bound_m.get_solve_status()): bound_m.remove_constraint(u_con) bound_m.add_constraint(bound_x[j]==0) m.add_constraint(x[j]==0) bound_m.solve() else: bound_m.remove_constraint(u_con) U1[j] = bound_m.objective_value # solve for lower bound L0 bound_m.set_objective(sense="min", expr=bound_m.sum(C[i,j]*bound_x[i] for i in range(n))) l_con = bound_m.add_constraint(bound_x[j]==0) bound_m.solve() if "OPTIMAL_SOLUTION" not in str(bound_m.get_solve_status()): bound_m.remove_constraint(l_con) bound_m.add_constraint(bound_x[j]==1) m.add_constraint(x[j]==1) bound_m.solve() else: bound_m.remove_constraint(l_con) L0[j] = bound_m.objective_value if lhs_constraints: # solve for upper bound U0 bound_m.set_objective(sense="max", expr=bound_m.sum(C[i,j]*bound_x[i] for i in range(n))) u_con = bound_m.add_constraint(bound_x[j] == 0) bound_m.solve() if "OPTIMAL_SOLUTION" not in str(bound_m.get_solve_status()): bound_m.remove_constraint(u_con) bound_m.add_constraint(bound_x[j]==1) m.add_constraint(x[j]==1) bound_m.solve() else: bound_m.remove_constraint(u_con) U0[j] = bound_m.objective_value # solve for lower bound L1 bound_m.set_objective(sense="min", expr=bound_m.sum(C[i,j]*bound_x[i] for i in range(n))) l_con = bound_m.add_constraint(bound_x[j] == 1) bound_m.solve() if "OPTIMAL_SOLUTION" not in str(bound_m.get_solve_status()): bound_m.remove_constraint(l_con) bound_m.add_constraint(bound_x[j]==0) m.add_constraint(x[j]==0) bound_m.solve() else: bound_m.remove_constraint(l_con) L1[j] = bound_m.objective_value #end bound model bound_m.end() else: raise Exception(bounds + " is not a valid bound type for glovers") end = timer() setup_time = end-start #add auxiliary constrains if(constraints=="original"): #original glovers constraints z = m.continuous_var_list(keys=n,lb=-m.infinity) m.add_constraints(z[j] <= U1[j]*x[j] for j in range(n)) if lhs_constraints: m.add_constraints(z[j] >= L1[j]*x[j] for j in range(n)) for j in range(n): tempsum = sum(C[i,j]*x[i] for i in range(n)) m.add_constraint(z[j] <= tempsum - L0[j]*(1-x[j])) if lhs_constraints: m.add_constraint(z[j] >= tempsum - U0[j]*(1-x[j])) m.maximize(m.sum(c[j]*x[j] + z[j] for j in range(n))) elif(constraints=="sub1" or constraints=="sub2"): #can make one of 2 substitutions using slack variables to further reduce # of constraints s = m.continuous_var_list(keys=n,lb=0) for j in range(n): tempsum = sum(C[i,j]*x[i] for i in range(n)) if constraints=="sub1": m.add_constraint(s[j] >= U1[j]*x[j] - tempsum + L0[j]*(1-x[j])) else: m.add_constraint(s[j] >= -U1[j]*x[j] + tempsum - L0[j]*(1-x[j])) if constraints=="sub1": m.maximize(m.sum(c[i]*x[i] + (U1[i]*x[i]-s[i]) for i in range(n))) else: m.maximize(sum(c[j]*x[j] for j in range(n)) + sum(sum(C[i,j]*x[i] for i in range(n))-L0[j]*(1-x[j])-s[j] for j in range(n))) else: raise Exception(constraints + " is not a valid constraint type for glovers") #return model return [m,setup_time]
def get_operator(mdl: Model, auto_penalty: bool = True, default_penalty: float = 1e5) -> Tuple[PauliSumOp, float]: """Generate Ising Hamiltonian from a model of DOcplex. Args: mdl: A model of DOcplex for a optimization problem. auto_penalty: If true, the penalty coefficient is automatically defined by "_auto_define_penalty()". default_penalty: The default value of the penalty coefficient for the constraints. This value is used if "auto_penalty" is False. Returns: Operator for the Hamiltonian and a constant shift for the obj function. """ _validate_input_model(mdl) # set the penalty coefficient by _auto_define_penalty() or manually. if auto_penalty: penalty = _auto_define_penalty(mdl, default_penalty) else: penalty = default_penalty # set a sign corresponding to a maximized or minimized problem. # sign == 1 is for minimized problem. sign == -1 is for maximized problem. sign = 1 if mdl.is_maximized(): sign = -1 # assign variables of the model to qubits. q_d = {} index = 0 for i in mdl.iter_variables(): if i in q_d: continue q_d[i] = index index += 1 # initialize Hamiltonian. num_nodes = len(q_d) pauli_list = [] shift = 0. zero = np.zeros(num_nodes, dtype=np.bool) # convert a constant part of the object function into Hamiltonian. shift += mdl.get_objective_expr().get_constant() * sign # convert linear parts of the object function into Hamiltonian. l_itr = mdl.get_objective_expr().iter_terms() for j in l_itr: z_p = np.zeros(num_nodes, dtype=np.bool) index = q_d[j[0]] weight = j[1] * sign / 2 z_p[index] = True pauli_list.append([-weight, Pauli(z_p, zero)]) shift += weight # convert quadratic parts of the object function into Hamiltonian. q_itr = mdl.get_objective_expr().iter_quads() for i in q_itr: index1 = q_d[i[0][0]] index2 = q_d[i[0][1]] weight = i[1] * sign / 4 if index1 == index2: shift += weight else: z_p = np.zeros(num_nodes, dtype=np.bool) z_p[index1] = True z_p[index2] = True pauli_list.append([weight, Pauli(z_p, zero)]) z_p = np.zeros(num_nodes, dtype=np.bool) z_p[index1] = True pauli_list.append([-weight, Pauli(z_p, zero)]) z_p = np.zeros(num_nodes, dtype=np.bool) z_p[index2] = True pauli_list.append([-weight, Pauli(z_p, zero)]) shift += weight # convert constraints into penalty terms. for constraint in mdl.iter_constraints(): right_cst = constraint.get_right_expr().get_constant() left_cst = constraint.get_left_expr().get_constant() constant = float(right_cst - left_cst) # constant parts of penalty*(Constant-func)**2: penalty*(Constant**2) shift += penalty * constant**2 # linear parts of penalty*(Constant-func)**2: penalty*(-2*Constant*func) for __l in _iter_net_linear_coeffs(constraint): z_p = np.zeros(num_nodes, dtype=np.bool) index = q_d[__l[0]] weight = __l[1] z_p[index] = True pauli_list.append([penalty * constant * weight, Pauli(z_p, zero)]) shift += -penalty * constant * weight # quadratic parts of penalty*(Constant-func)**2: penalty*(func**2) for __l in _iter_net_linear_coeffs(constraint): for l_2 in _iter_net_linear_coeffs(constraint): index1 = q_d[__l[0]] index2 = q_d[l_2[0]] weight1 = __l[1] weight2 = l_2[1] penalty_weight1_weight2 = penalty * weight1 * weight2 / 4 if index1 == index2: shift += penalty_weight1_weight2 else: z_p = np.zeros(num_nodes, dtype=np.bool) z_p[index1] = True z_p[index2] = True pauli_list.append( [penalty_weight1_weight2, Pauli(z_p, zero)]) z_p = np.zeros(num_nodes, dtype=np.bool) z_p[index1] = True pauli_list.append([-penalty_weight1_weight2, Pauli(z_p, zero)]) z_p = np.zeros(num_nodes, dtype=np.bool) z_p[index2] = True pauli_list.append([-penalty_weight1_weight2, Pauli(z_p, zero)]) shift += penalty_weight1_weight2 # Remove paulis whose coefficients are zeros. opflow_list = [(pauli[1].to_label(), pauli[0]) for pauli in pauli_list] qubit_op = PauliSumOp.from_list(opflow_list) return qubit_op, shift
def qsap_standard(qsap, lhs_constraints=False, **kwargs): """ standard linearization for the quadratic semi-assignment problem """ n = qsap.n m = qsap.m e = qsap.e c = qsap.c #create model and add variables mdl = Model(name='qsap_standard_linearization') x = mdl.binary_var_matrix(m,n,name="binary_var") w = np.array([[[[mdl.continuous_var() for i in range(n)]for j in range(m)] for k in range(n)]for l in range(m)]) mdl.add_constraints((sum(x[i,k] for k in range(n)) == 1) for i in range(m)) #add auxiliary constraints for i in range(m-1): for k in range(n): for j in range(i+1,m): for l in range(n): if lhs_constraints: if c[i,k,j,l]+c[j,l,i,k] > 0: mdl.add_constraint(w[i,k,j,l] <= x[i,k]) mdl.add_constraint(w[i,k,j,l] <= x[j,l]) else: mdl.add_constraint(x[i,k] + x[j,l] - 1 <= w[i,k,j,l]) mdl.add_constraint(w[i,k,j,l] >= 0) else: mdl.add_constraint(w[i,k,j,l] <= x[i,k]) mdl.add_constraint(w[i,k,j,l] <= x[j,l]) mdl.add_constraint(x[i,k] + x[j,l] - 1 <= w[i,k,j,l]) mdl.add_constraint(w[i,k,j,l] >= 0) #TODO make sure this works w/ lhs, mixed sign and non ut #compute quadratic values contirbution to obj quadratic_values = 0 for i in range(m-1): for k in range(n): for j in range(i+1,m): for l in range(n): quadratic_values = quadratic_values + ((c[i,k,j,l]+c[j,l,i,k])*(w[i,k,j,l])) linear_values = mdl.sum(x[i,k]*e[i,k] for k in range(n) for i in range(m)) mdl.maximize(linear_values + quadratic_values) #return model. no setup time for std return [mdl, 0]
nb_ambulances = int(read[1][0]) accidents = pd.read_csv("predicted-accidents.csv", engine='c', header=0, skipinitialspace=True) locations_prob = { NamedPoint(float(t.LONGITUDE), float(t.LATITUDE)): float(t.accident_prob) for t in accidents.itertuples(index=False) } from docplex.mp.model import Model mdl = Model("accidents") locations = locations_prob.keys() ambulance_locations = locations ambulance_vars = mdl.binary_var_dict(ambulance_locations) link_vars = mdl.binary_var_matrix(ambulance_locations, locations) # 1st constraint: each library must be linked to a coffee shop that is open. mdl.add_constraints(link_vars[c_loc, b] <= ambulance_vars[c_loc] for b in locations for c_loc in ambulance_locations) # 2nd constraint: each library is linked to exactly one coffee shop. mdl.add_constraints( mdl.sum(link_vars[c_loc, b] for c_loc in ambulance_locations) == 1 for b in locations)
def qsap_glovers(qsap, bounds="original", constraints="original", lhs_constraints=False, **kwargs): n = qsap.n m = qsap.m e = qsap.e c = qsap.c mdl = Model(name='qsap_glovers') x = mdl.binary_var_matrix(keys1=m,keys2=n,name="binary_var") mdl.add_constraints((sum(x[i,k] for k in range(n)) == 1) for i in range(m)) U1 = np.zeros((m,n)) L0 = np.zeros((m,n)) U0 = np.zeros((m,n)) L1 = np.zeros((m,n)) start = timer() if bounds=="original": for j in range(m): for l in range(n): col = c[:,:,j,l] pos_take_vals = col > 0 pos_take_vals[j,l] = True U1[j,l] = np.sum(col[pos_take_vals]) neg_take_vals = col < 0 neg_take_vals[j,l] = False L0[j,l] = np.sum(col[neg_take_vals]) if lhs_constraints: U0[j,l] = U1[j,l] - col[j,l] L1[j,l] = L0[j,l] + col[j,l] elif bounds=="tight" or bounds=="tighter": bound_mdl = Model(name="u_bound_m") if bounds=="tight": bound_x = bound_mdl.continuous_var_matrix(keys1=m,keys2=n,ub=1,lb=0) elif bounds == "tighter": bound_x = bound_mdl.binary_var_matrix(keys1=m,keys2=n) bound_mdl.add_constraints((sum(bound_x[i,k] for k in range(n)) == 1) for i in range(m)) for j in range(m): for l in range(n): # solve for upper bound U1 bound_mdl.set_objective(sense="max", expr=sum(c[i,k,j,l]*bound_x[i,k] for i in range(m) for k in range(n) if i != j)) u_con = bound_mdl.add_constraint(bound_x[j,l]==1) bound_mdl.solve() U1[j,l] = bound_mdl.objective_value bound_mdl.remove_constraint(u_con) # solve for lower bound L0 bound_mdl.set_objective(sense="min", expr=sum(c[i,k,j,l]*bound_x[i,k] for i in range(m) for k in range(n) if i != j)) l_con = bound_mdl.add_constraint(bound_x[j,l]==0) bound_mdl.solve() L0[j,l] = bound_mdl.objective_value bound_mdl.remove_constraint(l_con) if lhs_constraints: # solve for upper bound U0 bound_mdl.set_objective(sense="max", expr=sum(c[i,k,j,l]*bound_x[i,k] for i in range(m) for k in range(n) if i != j)) u_con = bound_mdl.add_constraint(bound_x[j,l] == 0) bound_mdl.solve() bound_mdl.remove_constraint(u_con) U0[i,k] = bound_mdl.objective_value # solve for lower bound L1 bound_mdl.set_objective(sense="min", expr=sum(c[i,k,j,l]*bound_x[i,k] for i in range(m) for k in range(n) if i != j)) l_con = bound_mdl.add_constraint(bound_x[j,l] == 1) bound_mdl.solve() L1[i,k] = bound_mdl.objective_value bound_mdl.remove_constraint(l_con) # end bound model bound_mdl.end() else: raise Exception(bounds + " is not a valid bound type for glovers") end = timer() setup_time = end-start #add auxiliary constrains if constraints=="original": z = mdl.continuous_var_matrix(keys1=m,keys2=n,lb=-mdl.infinity) mdl.add_constraints(z[j,l] <= x[j,l]*U1[j,l] for j in range(m) for l in range(n)) mdl.add_constraints(z[j,l] <= sum(c[i,k,j,l]*x[i,k] for i in range(m) for k in range(n) if i != j)-L0[j,l]*(1-x[j,l]) for j in range(m) for l in range(n)) if lhs_constraints: mdl.add_constraints(z[j,l] >= x[j,l]*L1[j,l] for i in range(m) for k in range(n)) mdl.add_constraints(z[j,l] >= sum(sum(c[i,k,j,l]*x[i,k] for l in range(n)) for j in range(m)) -U0[j,l]*(1-x[j,l]) for i in range(m) for k in range(n)) mdl.maximize(sum(sum(e[i,k]*x[i,k] + z[i,k] for k in range(n)) for i in range(m))) elif constraints=="sub1": s = mdl.continuous_var_matrix(keys1=m,keys2=n,lb=0) mdl.add_constraints(s[j,l] >= U1[j,l]*x[j,l]+L0[j,l]*(1-x[j,l])-sum(c[i,k,j,l]*x[i,k] for i in range(m) for k in range(n) if i != j) for l in range(n) for j in range(m)) mdl.maximize(sum(e[i,k]*x[i,k] for k in range(n) for i in range(m)) + sum(U1[i,k]*x[i,k]-s[i,k] for k in range(n) for i in range(m))) elif constraints=="sub2": s = mdl.continuous_var_matrix(keys1=m,keys2=n,lb=0) mdl.add_constraints(s[j,l] >= -L0[j,l]*(1-x[j,l])-(x[j,l]*U1[j,l])+sum(c[i,k,j,l]*x[i,k] for i in range(m) for k in range(n) if i != j) for j in range(m) for l in range(n)) mdl.maximize(sum(sum(e[j,l]*x[j,l] for l in range(n))for j in range(m)) + sum(sum(-s[j,l]-(L0[j,l]*(1-x[j,l])) + sum(sum(c[i,k,j,l]*x[i,k] for k in range(n)) for i in range(m)) for l in range(n)) for j in range(m))) else: raise Exception(constraints + " is not a valid constraint type for glovers") #return model return [mdl,setup_time]
def build_diet_model(**kwargs): # Create tuples with named fields for foods and nutrients food = [Food(*f) for f in FOODS] nutrients = [Nutrient(*row) for row in NUTRIENTS] food_nutrients = {(fn[0], nutrients[n].name): fn[1 + n] for fn in FOOD_NUTRIENTS for n in range(len(NUTRIENTS))} # Model mdl = Model(name='diet', **kwargs) # Decision variables, limited to be >= Food.qmin and <= Food.qmax qty = { f: mdl.continuous_var(lb=f.qmin, ub=f.qmax, name=f.name) for f in food } # Limit range of nutrients, and mark them as KPIs for n in nutrients: amount = mdl.sum(qty[f] * food_nutrients[f.name, n.name] for f in food) mdl.add_range(n.qmin, amount, n.qmax) mdl.add_kpi(amount, publish_name="Total %s" % n.name) # Minimize cost mdl.minimize(mdl.sum(qty[f] * f.unit_cost for f in food)) mdl.print_information() return mdl
def rlt1_qsap(qsap): n = qsap.n m = qsap.m e = qsap.e c = qsap.c #create model and add variables mdl = Model(name='qsap_rlt1_linearization') x = mdl.continuous_var_matrix(m,n,name="binary_var", lb=0, ub=1) w = np.array([[[[mdl.continuous_var() for i in range(n)]for j in range(m)] for k in range(n)]for l in range(m)]) # Include the original assignment constraints mdl.add_constraints((sum(x[i,k] for k in range(n)) == 1) for i in range(m)) # Multiply each assignment constraint by each x_jl for j in range(m): for l in range(n): for i in range(m): if i == j: continue mdl.add_constraint(sum(w[i,k,j,l] for k in range(n)) == x[j,l]) # Add symmetry constraints for i in range(m-1): for k in range(n): for j in range(i+1,m): for l in range(n): const_name = 'sym_' + str(i) + '_' + str(k) + '_' + str(j)+ '_' + str(l) mdl.add_constraint(w[i,k,j,l] == w[j,l,i,k], ctname = const_name) # Construct objective value quadratic_values = 0 for i in range(m): for j in range(m): for k in range(n): for l in range(n): quadratic_values = quadratic_values + c[i,k,j,l]*w[i,k,j,l] linear_values = mdl.sum(x[i,k]*e[i,k] for k in range(n) for i in range(m)) mdl.maximize(linear_values + quadratic_values) # Return model return mdl