def constructProblem(self): self.instance.print() self.model = Model('flow') self.fIdx = [[ self.model.add_var('f({},{})'.format(i + 1, t), var_type='B') for i in range(self.instance.m()) ] for t in range(self.instance.h())] self.xIdx = [[[ self.model.add_var('x({},{},{})'.format(i + 1, j + 1, t)) for t in range(self.instance.est(i, j), self.instance.lst(i, j) + 1) ] for i in range(self.instance.m())] for j in range(self.instance.n())] self.eIdx = [[[ self.model.add_var('e({},{},{})'.format(i + 1, j + 1, t)) for t in range(self.instance.est(i, j), self.instance.lst(i, j) + 1) ] for i in range(self.instance.m())] for j in range(self.instance.n())] self.cIdx = self.model.add_var('C', var_type='I') for aux in self.fIdx: for f in aux: print(f.name, " ", end='') print() for aux in self.xIdx: for aux2 in aux: for x in aux2: print(x.name, " ", end='') print() for aux in self.xIdx: for aux2 in aux: for e in aux2: print(e.name, " ", end='') print()
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_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 __init__(self, generators, demand): self.generators = generators self.demand = demand self.period = range(1, len(self.demand) + 1) self.model = Model(name='UnitCommitment') self.p, self.u = {}, {}
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 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 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 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 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('')
"""Job Shop Scheduling Problem Python-MIP exaxmple To execute it on the example instance ft03.jssp call python jssp.py ft03.jssp by Victor Silva""" from itertools import product from sys import argv from jssp_instance import JSSPInstance from mip.model import Model from mip.constants import BINARY inst = JSSPInstance(argv[1]) n, m, machines, times, M = inst.n, inst.m, inst.machines, inst.times, inst.M model = Model('JSSP') c = model.add_var(name="C") x = [[model.add_var(name='x({},{})'.format(j + 1, i + 1)) for i in range(m)] for j in range(n)] y = [[[ model.add_var(var_type=BINARY, name='y({},{},{})'.format(j + 1, k + 1, i + 1)) for i in range(m) ] for k in range(n)] for j in range(n)] model.objective = c for (j, i) in product(range(n), range(1, m)): model += x[j][machines[j][i]] - x[j][machines[j][i-1]] >= \ times[j][machines[j][i-1]]
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 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
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('')
to solve P1 instance (included in the examples) call python bmcp.py P1.col """ from itertools import product import bmcp_data import bmcp_greedy from mip.model import Model, xsum, minimize from mip.constants import MINIMIZE, BINARY 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):
from tspdata import TSPData from sys import argv from mip.model import Model from mip.constants import * from matplotlib.pyplot import plot if len(argv) <= 1: print('enter instance name.') exit(1) inst = TSPData(argv[1]) n = inst.n d = inst.d print('solving TSP with {} cities'.format(inst.n)) model = Model() # binary variables indicating if arc (i,j) is used on the route or not x = [[model.add_var(type=BINARY) for j in range(n)] for i in range(n)] # continuous variable to prevent subtours: each # city will have a different "identifier" in the planned route y = [model.add_var(name='y({})'.format(i), lb=0.0, ub=n) for i in range(n)] # objective funtion: minimize the distance model += sum(d[i][j] * x[i][j] for j in range(n) for i in range(n)) # constraint : enter each city coming from another city for i in range(n): model += sum(x[j][i] for j in range(n) if j != i) == 1, 'enter({})'.format(i)
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)
# set of edges leaving a node OUT = defaultdict(set) # set of edges entering a node IN = defaultdict(set) # an arbitrary initial point n0 = min(i for i in N) for a in A: OUT[a[0]].add(a) IN[a[1]].add(a) 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
# set of edges leaving a node OUT = defaultdict(set) # set of edges entering a node IN = defaultdict(set) # an arbitrary initial point n0 = min(i for i in N) for a in A: OUT[a[0]].add(a) IN[a[1]].add(a) 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.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} # 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
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)
from mip.constants import BINARY p = [0, 3, 2, 5, 4, 2, 3, 4, 2, 4, 6, 0] u = [[0, 0], [5, 1], [0, 4], [1, 4], [1, 3], [3, 2], [3, 1], [2, 4], [4, 0], [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]
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) # 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
"""Example of a solver to the n-queens problem: n chess queens should be placed in a n x n chess board so that no queen can attack another, i.e., just one queen per line, column and diagonal. """ 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)
"""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))
class UnitCommitment: def __init__(self, generators, demand): self.generators = generators self.demand = demand self.period = range(1, len(self.demand) + 1) self.model = Model(name='UnitCommitment') self.p, self.u = {}, {} 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 optimize(self): self.model.optimize() return self.u, self.p, self.model.objective.x, self.model.status.name def get_prices(self): u_fixed = {(t, g): self.u[t, g].x for g in self.generators.index for t in self.period} self.model.clear() self.build_model(fixed=True, u_fixed=u_fixed) self.optimize() return [ self.model.constr_by_name(f'power_bal_constr[{t}]').pi for t in self.period ]