def kantorovich(): """ Simple implementation of the compact formulation from Kantorovich for the problem """ N = 10 # maximum number of bars L = 250 # bar length m = 4 # number of requests w = [187, 119, 74, 90] # size of each item b = [1, 2, 2, 1] # demand for each item # creating the model (note that the linear relaxation is solved) model = Model(SOLVER) x = {(i, j): model.add_var(obj=0, var_type=CONTINUOUS, name="x[%d,%d]" % (i, j)) for i in range(m) for j in range(N)} y = {j: model.add_var(obj=1, var_type=CONTINUOUS, name="y[%d]" % j) for j in range(N)} # constraints for i in range(m): model.add_constr(xsum(x[i, j] for j in range(N)) >= b[i]) for j in range(N): model.add_constr(xsum(w[i] * x[i, j] for i in range(m)) <= L * y[j]) # additional constraint to reduce symmetry for j in range(1, N): model.add_constr(y[j - 1] >= y[j]) # optimizing the model and printing solution model.optimize() print_solution(model)
def solve_tsp_by_mip(tsp_matrix): start = time() matrix_of_distances = get_matrix_of_distances(tsp_matrix) length = len(tsp_matrix) model = Model(solver_name='gurobi') model.verbose = 1 x = [[model.add_var(var_type=BINARY) for j in range(length)] for i in range(length)] y = [model.add_var() for i in range(length)] model.objective = xsum(matrix_of_distances[i][j] * x[i][j] for j in range(length) for i in range(length)) for i in range(length): model += xsum(x[j][i] for j in range(length) if j != i) == 1 model += xsum(x[i][j] for j in range(length) if j != i) == 1 for i in range(1, length): for j in [x for x in range(1, length) if x != i]: model += y[i] - (length + 1) * x[i][j] >= y[j] - length model.optimize(max_seconds=300) arcs = [(i, j) for i in range(length) for j in range(length) if x[i][j].x >= 0.99] best_distance = calculate_total_dist_by_arcs(matrix_of_distances, arcs) time_diff = time() - start return arcs, time_diff, best_distance
def build_model(self, fixed=False, u_fixed=None): for t in self.period: for g in self.generators.index: if fixed: self.u[t, g] = self.model.add_var(lb=u_fixed[t, g], ub=u_fixed[t, g]) else: self.u[t, g] = self.model.add_var(var_type=BINARY) self.p[t, g] = self.model.add_var() # Max/min power for t in self.period: for g in self.generators.index: self.model.add_constr( self.p[t, g] <= self.generators.loc[g, 'p_max'] * self.u[t, g], name=f'pmax_constr[{t},{g}]') self.model.add_constr( self.p[t, g] >= self.generators.loc[g, 'p_min'] * self.u[t, g], name=f'pmin_constr[{t},{g}]') # Power balance for t in self.period: self.model.add_constr(xsum( self.p[t, g] for g in self.generators.index) == self.demand.loc[t, 'demand'], name=f'power_bal_constr[{t}]') # Min on for t in self.period[1:]: for g in self.generators.index: min_on_time = min(t + self.generators.loc[g, 'min_on'] - 1, len(self.period)) for tau in range(t, min_on_time + 1): self.model.add_constr( self.u[tau, g] >= self.u[t, g] - self.u[t - 1, g], name=f'min_on_constr[{t},{g}]') # Min off for t in self.period[1:]: for g in self.generators.index: min_off_time = min(t + self.generators.loc[g, 'min_off'] - 1, len(self.period)) for tau in range(t, min_off_time + 1): self.model.add_constr( 1 - self.u[tau, g] >= self.u[t - 1, g] - self.u[t, g], name=f'min_off_constr[{t},{g}]') # Objective function self.model.objective = minimize( xsum( xsum(self.p[t, g] * self.generators.loc[g, 'c_var'] + self.u[t, g] * self.generators.loc[g, 'c_fix'] for g in self.generators.index) for t in self.period))
def test_queens(solver: str): """MIP model n-queens""" n = 50 announce_test("n-Queens", solver) queens = Model('queens', MAXIMIZE, solver_name=solver) queens.verbose = 0 x = [[ queens.add_var('x({},{})'.format(i, j), var_type=BINARY) for j in range(n) ] for i in range(n)] # one per row for i in range(n): queens += xsum(x[i][j] for j in range(n)) == 1, 'row({})'.format(i) # one per column for j in range(n): queens += xsum(x[i][j] for i in range(n)) == 1, 'col({})'.format(j) # diagonal \ for p, k in enumerate(range(2 - n, n - 2 + 1)): queens += xsum(x[i][j] for i in range(n) for j in range(n) if i - j == k) <= 1, 'diag1({})'.format(p) # diagonal / for p, k in enumerate(range(3, n + n)): queens += xsum(x[i][j] for i in range(n) for j in range(n) if i + j == k) <= 1, 'diag2({})'.format(p) queens.optimize() check_result("model status", queens.status == OptimizationStatus.OPTIMAL) # querying problem variables and checking opt results total_queens = 0 for v in queens.vars: # basic integrality test assert v.x <= 0.0001 or v.x >= 0.9999 total_queens += v.x # solution feasibility rows_with_queens = 0 for i in range(n): if abs(sum(x[i][j].x for j in range(n)) - 1) <= 0.001: rows_with_queens += 1 check_result("feasible solution", abs(total_queens - n) <= 0.001 and rows_with_queens == n) print('')
def solve_tsp_by_mip_with_sub_cycles_2(tsp_matrix): start = time() matrix_of_distances = get_matrix_of_distances(tsp_matrix) total_length = len(tsp_matrix) best_distance = sys.float_info.max found_cycles = [] arcs = [(i, i + 1) for i in range(total_length - 1)] iteration = 0 model = Model(solver_name='gurobi') model.verbose = 0 x = [[model.add_var(var_type=BINARY) for j in range(total_length)] for i in range(total_length)] y = [model.add_var() for i in range(total_length)] model.objective = xsum(matrix_of_distances[i][j] * x[i][j] for j in range(total_length) for i in range(total_length)) for i in range(total_length): model += (xsum(x[i][j] for j in range(0, i)) + xsum(x[j][i] for j in range(i + 1, total_length))) == 2 while len(found_cycles) != 1: model.optimize(max_seconds=300) arcs = [(i, j) for i in range(total_length) for j in range(total_length) if x[i][j].x >= 0.99] best_distance = calculate_total_dist_by_arcs(matrix_of_distances, arcs) found_cycles = get_cycle(arcs) for cycle in found_cycles: points = {} for arc in cycle: points = {*points, arc[0]} points = {*points, arc[1]} cycle_len = len(cycle) model += xsum(x[arc[0]][arc[1]] for arc in permutations(points, 2)) <= cycle_len - 1 # plot_connected_tsp_points_from_arcs(tsp_matrix, arcs, '../images/mip_xql662/{}'.format(iteration)) print(iteration) iteration += 1 time_diff = time() - start return arcs, time_diff, best_distance
def generate_constrs(self, model: Model): G = nx.DiGraph() r = [(v, v.x) for v in model.vars if v.name.startswith('x(')] U = [v.name.split('(')[1].split(',')[0] for v, f in r] V = [v.name.split(')')[0].split(',')[1] for v, f in r] N = list(set(U + V)) cp = CutPool() for i in range(len(U)): G.add_edge(U[i], V[i], capacity=r[i][1]) for (u, v) in product(N, N): if u == v: continue val, (S, NS) = nx.minimum_cut(G, u, v) if val <= 0.99: arcsInS = [(v, f) for i, (v, f) in enumerate(r) if U[i] in S and V[i] in S] if sum(f for v, f in arcsInS) >= (len(S) - 1) + 1e-4: cut = xsum(1.0 * v for v, fm in arcsInS) <= len(S) - 1 cp.add(cut) if len(cp.cuts) > 256: for cut in cp.cuts: model.add_cut(cut) return for cut in cp.cuts: model.add_cut(cut) return
def simplex_to_ILP(c, A_eq, b_eq, sense="maximize"): if sense == "maximize": m = model.Model(sense=model.MAXIMIZE, solver_name=model.CBC) else: m = model.Model(sense=model.MINIMIZE, solver_name=model.CBC) m.verbose = 0 number_of_variables = A_eq.shape[1] y = [m.add_var(var_type=model.BINARY) for i in range(number_of_variables)] for row, b in zip(A_eq, b_eq): m += model.xsum(row[i] * y[i] for i in range(number_of_variables)) == b m.objective = model.xsum(c[i] * y[i] for i in range(number_of_variables)) m.max_mip_gap_abs = 0.05 status = m.optimize(max_seconds=300) assert status == model.OptimizationStatus.OPTIMAL or status == model.OptimizationStatus.FEASIBLE, "Could not find feasible solution" solution = [v.x for v in m.vars] return solution, m.objective_value, status
def generate_cuts(self, model: Model): G = nx.DiGraph() r = [(v, v.x) for v in model.vars if v.name.startswith('x(')] U = [int(v.name.split('(')[1].split(',')[0]) for v, f in r] V = [int(v.name.split(')')[0].split(',')[1]) for v, f in r] for v in model.vars: print('{} = {} '.format(v.name, v.x), end='') print() input() cp = CutPool() for i in range(len(U)): G.add_edge(U[i], V[i], capacity=r[i][1]) for (u, v) in F: if u not in U or v not in V: continue val, (S, NS) = nx.minimum_cut(G, u, v) if val <= 0.99: arcsInS = [(v, f) for i, (v, f) in enumerate(r) if U[i] in S and V[i] in S] if sum(f for v, f in arcsInS) >= (len(S) - 1) + 1e-4: cut = xsum(1.0 * v for v, fm in arcsInS) <= len(S) - 1 cp.add(cut) if len(cp.cuts) > 256: for cut in cp.cuts: model.add_cut(cut) return for cut in cp.cuts: model.add_cut(cut) return
def generate_cuts(self, model: Model): def row(vname: str) -> str: return int(vname.split('(')[1].split(',')[0].split(')')[0]) def col(vname: str) -> str: return int(vname.split('(')[1].split(',')[1].split(')')[0]) x = {(row(v.name), col(v.name)): v for v in model.vars} for p, k in enumerate(range(2 - n, n - 2 + 1)): cut = xsum(x[i, j] for i in range(n) for j in range(n) if i - j == k) <= 1 if cut.violation > 0.001: model.add_cut(cut) for p, k in enumerate(range(3, n + n)): cut = xsum(x[i, j] for i in range(n) for j in range(n) if i + j == k) <= 1 if cut.violation > 0.001: model.add_cut(cut)
def get_pricing(m, w, L): # creating the pricing problem pricing = Model() # creating pricing variables a = [] for i in range(m): a.append( pricing.add_var(obj=0, var_type=INTEGER, name='a_%d' % (i + 1))) # creating pricing constraint pricing.add_constr(xsum(w[i] * a[i] for i in range(m)) <= L, 'bar_length') pricing.write('pricing.lp') return a, pricing
def optimize(self, objective_coefficients, zp_nl_mask, solved): model = self._model # add objective model.objective = mip.xsum(x_i * w_i for x_i, w_i in zip(objective_coefficients, self._w)) # add constraints model.remove([constr for constr in model.constrs]) constraints_mask = zp_nl_mask constraints_mask[solved] = True constraints_to_add = self._constraints_buff[constraints_mask] for constraint in constraints_to_add: model.add_constr(constraint) # optimize status = model.optimize(max_seconds=self.MAX_OPT_SECONDS) if status == mip.OptimizationStatus.OPTIMAL: print('Optimal solution cost {} found'.format( model.objective_value)) elif status == mip.OptimizationStatus.FEASIBLE: print('Sol.cost {} found, best possible: {}'.format( model.objective_value, model.objective_bound)) elif status == mip.OptimizationStatus.NO_SOLUTION_FOUND: print('No feasible solution found, lower bound is: {}'.format( model.objective_bound)) else: print('Optimization FAILED: {}'.format(status)) if status == mip.OptimizationStatus.OPTIMAL or status == mip.OptimizationStatus.FEASIBLE: schema_vec = np.array([v.x for v in model.vars]) else: schema_vec = None return schema_vec
print('solving TSP with {} cities'.format(len(N))) model = Model() # binary variables indicating if arc (i,j) is used on the route or not x = { a: model.add_var('x({},{})'.format(a[0], a[1]), var_type=BINARY) for a in A } # continuous variable to prevent subtours: each # city will have a different "identifier" in the planned route y = {i: model.add_var(name='y({})') for i in N} # objective function: minimize the distance model.objective = minimize(xsum(A[a] * x[a] for a in A)) # constraint : enter each city coming from another city for i in N: model += xsum(x[a] for a in OUT[i]) == 1 # constraint : leave each city coming from another city for i in N: model += xsum(x[a] for a in IN[i]) == 1 # no subtours of size 2 for a in A: if (a[1], a[0]) in A.keys(): model += x[a] + x[a[1], a[0]] <= 1 # computing farthest point for each point
def cg(): """ Simple column generation implementation for a Cutting Stock Problem """ L = 250 # bar length m = 4 # number of requests w = [187, 119, 74, 90] # size of each item b = [1, 2, 2, 1] # demand for each item # creating models and auxiliary lists master = Model() lambdas = [] constraints = [] # creating an initial pattern (which cut one item per bar) # to provide the restricted master problem with a feasible solution for i in range(m): lambdas.append(master.add_var(obj=1, name='lambda_%d' % (len(lambdas) + 1))) # creating constraints for i in range(m): constraints.append(master.add_constr(lambdas[i] >= b[i], name='i_%d' % (i + 1))) # creating the pricing problem pricing = Model(SOLVER) # creating pricing variables a = [] for i in range(m): a.append(pricing.add_var(obj=0, var_type=INTEGER, name='a_%d' % (i + 1))) # creating pricing constraint pricing.add_constr(xsum(w[i] * a[i] for i in range(m)) <= L, 'bar_length') pricing.write('pricing.lp') new_vars = True while new_vars: ########## # STEP 1: solving restricted master problem ########## master.optimize() # printing dual values print_solution(master) print('pi = ', end='') print([constraints[i].pi for i in range(m)]) print('') ########## # STEP 2: updating pricing objective with dual values from master ########## pricing.objective = 1 for i in range(m): a[i].obj = -constraints[i].pi # solving pricing problem pricing.optimize() # printing pricing solution z_val = pricing.objective_value print('Pricing:') print(' z = {z_val}'.format(**locals())) print(' a = ', end='') print([v.x for v in pricing.vars]) print('') ########## # STEP 3: adding the new columns ########## # checking if columns with negative reduced cost were produced and # adding them into the restricted master problem if 1 + pricing.objective_value < - EPS: coeffs = [a[i].x for i in range(m)] column = Column(constraints, coeffs) lambdas.append(master.add_var(obj=1, column=column, name='lambda_%d' % (len(lambdas) + 1))) print('new pattern = {coeffs}'.format(**locals())) # if no column with negative reduced cost was produced, then linear # relaxation of the restricted master problem is solved else: new_vars = False pricing.write('pricing.lp') print_solution(master)
model.add_cut(cut) return inst = TSPData(argv[1]) n, d = inst.n, inst.d model = Model() x = [[ model.add_var(name='x({},{})'.format(i, j), var_type=BINARY) for j in range(n) ] for i in range(n)] y = [model.add_var(name='y({})'.format(i), lb=0.0, ub=n) for i in range(n)] model.objective = xsum(d[i][j] * x[i][j] for j in range(n) for i in range(n)) for i in range(n): model += xsum(x[j][i] for j in range(n) if j != i) == 1 model += xsum(x[i][j] for j in range(n) if j != i) == 1 for (i, j) in [(i, j) for (i, j) in product(range(1, n), range(1, n)) if i != j]: model += y[i] - (n + 1) * x[i][j] >= y[j] - n F = [] for i in range(n): (md, dp) = (0, -1) for j in [k for k in range(n) if k != i]: if d[i][j] > md: (md, dp) = (d[i][j], j) F.append((i, dp))
# binary variables indicating if arc (i,j) is used on the route or not x = {a: model.add_var('x({},{})'.format(a[0], a[1]), var_type=BINARY) for a in A.keys()} # continuous variable to prevent subtours: each # city will have a different "identifier" in the planned route y = {i: model.add_var(name='y({})') for i in N} # continuous variable to prevent subtours: each # city will have a different "identifier" in the planned route y = {i: model.add_var(name='y({})') for i in N} # objective function: minimize the distance model.objective = minimize( xsum(A[a]*x[a] for a in A.keys())) # constraint : enter each city coming from another city for i in N: model += xsum(x[a] for a in OUT[i]) == 1 # constraint : leave each city coming from another city for i in N: model += xsum(x[a] for a in IN[i]) == 1 # (weak) subtour elimination for (i, j) in [a for a in A.keys() if n0 not in [a[0], a[1]]]: model += \ y[i] - (n+1)*x[(i, j)] >= y[j]-n, 'noSub({},{})'.format(i, j) # no subtours of size 2
if cut.violation > 0.001: model.add_cut(cut) # number of queens n = 60 queens = Model('queens', MAXIMIZE) x = [[ queens.add_var('x({},{})'.format(i, j), var_type=BINARY) for j in range(n) ] for i in range(n)] # one per row for i in range(n): queens += xsum(x[i][j] for j in range(n)) == 1, 'row({})'.format(i) # one per column for j in range(n): queens += xsum(x[i][j] for i in range(n)) == 1, 'col({})'.format(j) queens.cuts_generator = DiagonalCutGenerator() queens.cuts_generator.lazy_constraints = True queens.optimize() stdout.write('\n') for i, v in enumerate(queens.vars): stdout.write('O ' if v.x >= 0.99 else '. ') if i % n == n - 1: stdout.write('\n')
"""0/1 Knapsack example""" from mip.model import Model, xsum, maximize from mip.constants import BINARY p = [10, 13, 18, 31, 7, 15] w = [11, 15, 20, 35, 10, 33] c = 47 n = len(w) m = Model('knapsack') x = [m.add_var(var_type=BINARY) for i in range(n)] m.objective = maximize(xsum(p[i] * x[i] for i in range(n))) m += xsum(w[i] * x[i] for i in range(n)) <= c m.optimize() selected = [i for i in range(n) if x[i].x >= 0.99] print('selected items: {}'.format(selected))
from sys import stdout from mip.model import Model, xsum from mip.constants import MAXIMIZE, BINARY # number of queens n = 75 queens = Model('queens', MAXIMIZE) x = [[ queens.add_var('x({},{})'.format(i, j), var_type=BINARY) for j in range(n) ] for i in range(n)] # one per row for i in range(n): queens += xsum(x[i][j] for j in range(n)) == 1, 'row({})'.format(i) # one per column for j in range(n): queens += xsum(x[i][j] for i in range(n)) == 1, 'col({})'.format(j) # diagonal \ for p, k in enumerate(range(2 - n, n - 2 + 1)): queens += xsum(x[i][j] for i in range(n) for j in range(n) if i - j == k) <= 1, 'diag1({})'.format(p) # diagonal / for p, k in enumerate(range(3, n + n)): queens += xsum(x[i][j] for i in range(n) for j in range(n) if i + j == k) <= 1, 'diag2({})'.format(p)
[5, 2], [2, 5], [0, 0]] c = [6, 8] S = [[0, 1], [0, 2], [0, 3], [1, 4], [1, 5], [2, 9], [2, 10], [3, 8], [4, 6], [4, 7], [5, 9], [5, 10], [6, 8], [6, 9], [7, 8], [8, 11], [9, 11], [10, 11]] (R, J, T) = (range(len(c)), range(len(p)), range(sum(p))) model = Model() x = [[model.add_var(name='x({},{})'.format(j, t), var_type=BINARY) for t in T] for j in J] model.objective = xsum(x[len(J) - 1][t] * t for t in T) for j in J: model += xsum(x[j][t] for t in T) == 1 for (r, t) in product(R, T): model += xsum(u[j][r] * x[j][t2] for j in J for t2 in range(max(0, t - p[j] + 1), t + 1)) <= c[r] for (j, s) in S: model += xsum(t * x[s][t] - t * x[j][t] for t in T) >= p[j] model.optimize() print('Schedule: ') for (j, t) in product(J, T):
def test_tsp_mipstart(solver: str): """tsp related tests""" announce_test("TSP - MIPStart", solver) N = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] n = len(N) i0 = N[0] A = { ('a', 'd'): 56, ('d', 'a'): 67, ('a', 'b'): 49, ('b', 'a'): 50, ('d', 'b'): 39, ('b', 'd'): 37, ('c', 'f'): 35, ('f', 'c'): 35, ('g', 'b'): 35, ('b', 'g'): 25, ('a', 'c'): 80, ('c', 'a'): 99, ('e', 'f'): 20, ('f', 'e'): 20, ('g', 'e'): 38, ('e', 'g'): 49, ('g', 'f'): 37, ('f', 'g'): 32, ('b', 'e'): 21, ('e', 'b'): 30, ('a', 'g'): 47, ('g', 'a'): 68, ('d', 'c'): 37, ('c', 'd'): 52, ('d', 'e'): 15, ('e', 'd'): 20 } # input and output arcs per node Aout = {n: [a for a in A if a[0] == n] for n in N} Ain = {n: [a for a in A if a[1] == n] for n in N} m = Model(solver_name=solver) m.verbose = 0 x = { a: m.add_var(name='x({},{})'.format(a[0], a[1]), var_type=BINARY) for a in A } m.objective = xsum(c * x[a] for a, c in A.items()) for i in N: m += xsum(x[a] for a in Aout[i]) == 1, 'out({})'.format(i) m += xsum(x[a] for a in Ain[i]) == 1, 'in({})'.format(i) # continuous variable to prevent subtours: each # city will have a different "identifier" in the planned route y = {i: m.add_var(name='y({})'.format(i), lb=0.0) for i in N} # subtour elimination for (i, j) in A: if i0 not in [i, j]: m.add_constr(y[i] - (n + 1) * x[(i, j)] >= y[j] - n) route = ['a', 'g', 'f', 'c', 'd', 'e', 'b', 'a'] m.start = [(x[route[i - 1], route[i]], 1.0) for i in range(1, len(route))] m.optimize() check_result("mip model status", m.status == OptimizationStatus.OPTIMAL) check_result("mip model objective", (abs(m.objective_value - 262)) <= 0.0001) print('')
def get_objective(self) -> LinExpr: obj = cbclib.Cbc_getObjCoefficients(self._model) if obj == ffi.NULL: raise Exception("Error getting objective function coefficients") return xsum(obj[j] * self.vars[j] for j in range(self.num_cols()) if abs(obj[j]) >= 1e-15)
data = bmcp_data.read('P1.col') N, r, d = data.N, data.r, data.d S = bmcp_greedy.build(data) C, U = S.C, [i for i in range(S.u_max + 1)] m = Model(sense=MINIMIZE) x = [[m.add_var('x({},{})'.format(i, c), var_type=BINARY) for c in U] for i in N] z = m.add_var('z') m.objective = minimize(z) for i in N: m += xsum(x[i][c] for c in U) == r[i] for i, j, c1, c2 in product(N, N, U, U): if i != j and c1 <= c2 < c1 + d[i][j]: m += x[i][c1] + x[j][c2] <= 1 for i, c1, c2 in product(N, U, U): if c1 < c2 < c1 + d[i][i]: m += x[i][c1] + x[i][c2] <= 1 for i, c in product(N, U): m += z >= (c + 1) * x[i][c] m.start = [(x[i][c], 1.0) for i in N for c in C[i]] m.optimize(max_seconds=100)