# 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 F = [] G = nx.DiGraph() for ((i, j), d) in A.items(): G.add_edge(i, j, weight=d) for i in N: P, D = nx.dijkstra_predecessor_and_distance(G, source=i) DS = list(D.items()) DS.sort(key=lambda x: x[1]) F.append((i, DS[-1][0])) model.cuts_generator = SubTourCutGenerator(F) model.lazy_constrs_generator = SubTourCutGenerator(F) model.optimize() print(model.status) print('best route found has length {}'.format(model.objective_value)) arcs = [a for a in A.keys() if x[a].x >= 0.99] print('optimal route : {}'.format(arcs))
def test_tsp_cuts(solver: str): """tsp related tests""" announce_test("TSP - Branch & Cut", 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) m.cuts_generator = SubTourCutGenerator() # tiny model, should be enough to find the optimal m.max_seconds = 10 m.max_nodes = 100 m.max_solutions = 1000 m.optimize() check_result("mip model status", m.status == OptimizationStatus.OPTIMAL) check_result("mip model objective", (abs(m.objective_value - 262)) <= 0.0001) print('')
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')