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 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 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('')