def solution_from_path(fname, solver=None, verbose=False): """ Load a problem and solve it """ if verbose: solver = solver or TSPSolver.from_tspfile(fname) return solver.solve() else: with suppress.HiddenPrints(): solver = solver or TSPSolver.from_tspfile(fname) return solver.solve()
def exact(tsp): points = tsp.points * 1000 n, d = points.shape if d != 2: raise Exception(f"Concorde solver currently only supports 2D points. {d}D points given.") xs = points[:, 0] ys = points[:, 1] norm_type = "EUC_2D" with stdout_redirected(), stderr_redirected(): concorde_tsp_instance = TSPSolver.from_data(xs, ys, norm_type) tour, val, success, foundtour, hit_timebound = concorde_tsp_instance.solve() if not success: print("WARNING: Concorde solver failed.") if not foundtour: print("WARNING: Concorde solver did not find a tour.") if hit_timebound: print("WARNING: Concorde solver ran out of time.") tour = tour.tolist() tour.append(tour[0]) tour_len = tsp.tour_length(tour) return tour, tour_len
def generate_data(self, num_samples, num_nodes, num_neighbors=-1, file_name=None, seed=0): """ return graph dataset """ np.random.seed(seed) set_nodes_coord = np.random.random([num_samples, num_nodes, 2]) graphs, labels = [], [] start_time = time.time() for nodes_coord in set_nodes_coord: #compute complete graph g = dgl.transform.knn_graph(th.tensor(nodes_coord), num_nodes) solver = TSPSolver.from_data(nodes_coord[:, 0], nodes_coord[:, 1], norm="GEO") solution = solver.solve() nodes_coord = th.tensor(nodes_coord).float() g.ndata['coord'] = nodes_coord graphs.append(g) labels.append(solution.tour) graph_labels = {'tsp_tours': th.tensor(labels).long()} save_graphs(file_name, graphs, graph_labels) end_time = time.time() - start_time print( f"Completed generation of {num_samples} samples of TSP{num_nodes}." ) print(f"Total time: {end_time/60:.1f}min") print(f"Average time: {(end_time/60)/num_samples:.2f}min") print(f"Saved at {file_name}") return graphs, graph_labels
def solve_it(input_data): lines = input_data.split('\n') node_count = int(lines[0]) if node_count > 1500: return solve_it_ortools(input_data) a = [] b = [] for line in lines[1:-1]: # skipping last line which is blank in data files node1, node2 = line.split() a.append(float(node1)) b.append(float(node2)) data = pd.DataFrame({"A": a, "B": b}) # data.index += 1 # Instantiate solver solver = TSPSolver.from_data(data.A, data.B, norm="EUC_2D") tour_data = solver.solve() assert tour_data.success solution = data.iloc[tour_data.tour] out = ' '.join(str(solution.index[i]) for i in range(len(solution))) output_data = f"{tour_data.optimal_value} {0}\n" output_data += f"{out}" return output_data
def solve_tsp(df, start_pt): df_r = df.copy() to_begin(df_r, start_pt) solver = TSPSolver.from_data(df_r.X, df_r.Y, norm="EUC_2D") tour_c = solver.solve(time_bound=60.0, verbose=True, random_seed=44) for j in range(len(df)): df.iloc[j] = df_r.iloc[tour_c[0][j]]
def compute_example(self): """ Compute pairs (Adjacency, Optimal Tour) """ try: g, W = GENERATOR_FUNCTIONS[self.generative_model](self.n_vertices) except KeyError: raise ValueError('Generative model {} not supported'.format( self.generative_model)) xs = [g.nodes[node]['pos'][0] for node in g.nodes] ys = [g.nodes[node]['pos'][1] for node in g.nodes] problem = TSPSolver.from_data( [self.coeff * elt for elt in xs], [self.coeff * elt for elt in ys], self.distance ) #1e8 because Concorde truncates the distance to the nearest integer solution = problem.solve(verbose=False) assert solution.success, "Couldn't find solution!" #print(W) B = distance_matrix_tensor_representation(W) SOL = torch.zeros((self.n_vertices, self.n_vertices), dtype=torch.int64) prec = solution.tour[-1] for i in range(self.n_vertices): curr = solution.tour[i] SOL[curr, prec] = 1 SOL[prec, curr] = 1 prec = curr return (B, SOL, (xs, ys))
def concorde_tsp(points, time_bound=3.0, return_ids=False): """ Calculate TSP route using pyconcorde. args: points: (N, 2) numpy array return_ids: bool - also return route node ids returns: tour_points: (N, 2) numpy array tour_ids: ordering of points """ norm = "EUC_2D" solver = TSPSolver.from_data(points[:, 0], points[:, 1], norm) solution = solver.solve(time_bound=time_bound, verbose=False) tour_ids = solution.tour tour_points = [] for idx in tour_ids: tour_points.append(points[idx, :]) tour_points = np.array(tour_points) if return_ids: return tour_points, tour_ids else: return tour_points
def computeTsp(n_trees, points): generateFile("trees.tsp", n_trees, points) solver = TSPSolver.from_tspfile( "/Users/Alessandro/Documents/Pyworkspace/trees.tsp") solution = solver.solve() sol = solution.tour fo = computeFo(sol, points) return fo, sol
def solve_tsp(dat_file, time_bound=60, verbose=True, norm="EUC_2D", seed=42): image_np = np.load(dat_file) cities = pd.DataFrame(image_np, columns=["X", "Y"]) # solve the TSP. solver = TSPSolver.from_data(cities.X, cities.Y, norm="EUC_2D") t = time.time() tour_data = solver.solve(time_bound=60, verbose=True, random_seed=42) print(f"Finding solution took: {time.time()-t}") print(f"Found Tour: {tour_data.found_tour}") return cities, tour_data
def pool_operation(input_b, it): from concorde.tsp import TSPSolver import os # Concorde solver = TSPSolver.from_data(input_b[it, :, 0] * 1000, input_b[it, :, 1] * 1000, norm="EUC_2D") # Find tour solution = solver.solve() return solution.tour
def _tsp_solver_factory(edge_weights: List, dimension: int, edge_weight_format: str): with tempfile.NamedTemporaryFile() as file: tsplib95.models.StandardProblem( type="TSP", dimension=dimension, edge_weight_type=_EDGE_WEIGHT_TYPE, edge_weight_format=edge_weight_format, edge_weights=edge_weights, ).save(file.name) return TSPSolver.from_tspfile(file.name)
def generate_data(self, num_samples, num_nodes, node_dim=2, num_neighbors=-1, file_name=None, seed=0): """ return graph dataset """ np.random.seed(seed) set_nodes_coord = np.random.random([num_samples, num_nodes, node_dim]) graphs, labels = [], [] start_time = time.time() for nodes_coord in set_nodes_coord: #compute complete graph g = dgl.transform.knn_graph(th.tensor(nodes_coord), num_nodes) solver = TSPSolver.from_data(nodes_coord[:, 0], nodes_coord[:, 1], norm="GEO") solution = solver.solve() nodes_coord = th.tensor(nodes_coord).float() g.ndata['coord'] = nodes_coord g.apply_edges(fn.u_sub_v('coord', 'coord', 'e')) #distance g.edata['e'] = th.norm(g.edata['e'], dim=1) #neighbors embedding e_tags = th.zeros(g.number_of_edges(), 3).float() e_tags[:, 0] = 1. if num_neighbors != -1: knn = dgl.transform.knn_graph(nodes_coord, num_neighbors) #remove self loop knn = dgl.transform.remove_self_loop(knn) src, dst = knn.edges() edge_nb = g.edge_ids(src, dst) e_tags[edge_nb, :] = th.tensor([0., 1., 0.]) #for self loop self_loop_id = g.edge_ids(list(range(num_nodes)), list(range(num_nodes))) e_tags[self_loop_id, :] = th.tensor([0., 0., 1.]) g.edata['e'] = th.cat((g.edata['e'].unsqueeze(1), e_tags), dim=1) graphs.append(g) labels.append(solution.tour) graph_labels = {'tsp_tours': th.tensor(labels).long()} save_graphs(file_name, graphs, graph_labels) end_time = time.time() - start_time print( f"Completed generation of {num_samples} samples of TSP{num_nodes}." ) print(f"Total time: {end_time/60:.1f}min") print(f"Average time: {(end_time/60)/num_samples:.2f}min") print(f"Saved at {file_name}") return graphs, graph_labels
def solve(inst): # precision factor pr = 1 if np.mean(np.abs(np.array(inst))) < 100: pr = 1e-3 # solve inst = np.array(inst) slr = TSPSolver.from_data(inst[:, 0] / pr, inst[:, 1] / pr, 'EUC_2D') res = slr.solve(verbose=False) return res.tour, res.optimal_value
def solve_batch_graphs(batch, first_cities, tmp_name='tmpname'): def create_concorde_file_xy_coord(arr, name="route", template=''): n_cities = arr.shape[0] assert len(arr.shape) == 2 # space delimited string matrix_s = "" for i, row in enumerate(arr.tolist()): # print(row) matrix_s += "".join("{} {} {}".format(i, row[0], row[1])) # print(matrix_s) # print('-------------') matrix_s += "\n" # print(template.format(**{'name': name, # 'n_cities': n_cities, # 'matrix_s': matrix_s})) return template.format(**{'name': name, 'n_cities': n_cities, 'matrix_s': matrix_s}) def write_file(outf, x, template): with open(outf, 'w') as dest: dest.write(create_concorde_file_xy_coord(x, name="My Route", template=template)) # 100*x.squeeze(0) return Trajectory = C.namedtuple('Trajectory', 'costs actions') actions = torch.zeros((batch.size(0), batch.size(1))) costs = [] M = 100000000 for i, x in enumerate(batch.cpu().numpy()): template = "NAME: {name}\nTYPE: TSP\nCOMMENT: {name}\nDIMENSION: {n_cities}\nEDGE_WEIGHT_TYPE: EUC_2D\nNODE_COORD_SECTION\n{matrix_s}EOF" x = M * x x = x.astype(int) outf = "/tmp/{}.tsp".format(tmp_name) write_file(outf, x, template) solver = TSPSolver.from_tspfile(outf) solution = solver.solve() #print(list(solution.tour)) if first_cities[i] not in list(solution.tour): print('----') print(first_cities[i]) print(list(solution.tour)) actions[i] = torch.from_numpy( np.roll(solution.tour, solution.tour.shape[0] - list(solution.tour).index(first_cities[i]))) costs.append(solution.optimal_value / M) return (Trajectory(costs=costs, actions=actions))
def solve(Ma, Mw): write_graph(Ma, Mw, [], 'tmp', int_weights=True) redirector_stdout = Redirector(fd=STDOUT) redirector_stderr = Redirector(fd=STDERR) redirector_stderr.start() redirector_stdout.start() solver = TSPSolver.from_tspfile('tmp') solution = solver.solve(verbose=False) redirector_stderr.stop() redirector_stdout.stop() return solution.tour if solution.found_tour else []
def run(filename, is_plot=True): datapath = get_example_path() filepath = os.path.join(datapath, filename) problem = tsplib95.load(filepath) start = time() solver = TSPSolver.from_tspfile(filepath) solution = solver.solve() end = time() print("Time spent to solve {}s".format(end - start)) print("Optimal value: ", solution.optimal_value) tour = solution.tour tour = [t + 1 for t in tour] plot(problem, tour)
def test_from_data(self): # Given xs = [1, 2, 3] ys = [4, 5, 6] name = "testdataset" norm = "EUC_2D" # When datagroup = TSPSolver.from_data(xs, ys, norm, name) # Then self.assertIsNotNone(datagroup._data) self.assertEqual(datagroup._ncount, 3) nptest.assert_allclose(datagroup.x, xs) nptest.assert_allclose(datagroup.y, ys)
def test_solve(self): # Given fname = get_dataset_path('berlin52') expected_tour, expected_opt_value = get_solution_data('berlin52') datagroup = TSPSolver.from_tspfile(fname) # When tour, val, success, foundtour, hit_timebound = datagroup.solve() # Then nptest.assert_array_equal(tour, expected_tour) self.assertAlmostEqual(val, expected_opt_value) self.assertTrue(success) self.assertTrue(foundtour) self.assertFalse(hit_timebound)
def generate_data(self): points_list = [] solutions = [] opt_dists = [] data_iter = tqdm(range(self.data_size), unit='data') for i, _ in enumerate(data_iter): data_iter.set_description('Generating data points %i/%i' % (i + 1, self.data_size)) points = np.array(self.data[i]) points_list.append(points) # solutions_iter: for tqdm solutions_iter = tqdm(points_list, unit='solve') if self.solve: for i, points in enumerate(solutions_iter): solutions_iter.set_description('Solved %i/%i' % (i + 1, len(points_list))) points_scaled = points * 10000 solver = TSPSolver.from_data(points_scaled[:, 0], points_scaled[:, 1], 'EUC_2D') sol = solver.solve(time_bound=-1, verbose=False) opt_tour, opt_dist = sol.tour, sol.optimal_value / 10000 solutions.append(opt_tour) opt_dists.append(opt_dist) else: solutions = None opt_dists = None if self.solve: print(' [*] Avg Optimal Tour {:.5f} +- {:.5f}'.format( np.mean(opt_dists), 2 * np.std(opt_dists) / np.sqrt(len(opt_dists)))) data = { 'Points': points_list, 'OptTour': solutions, 'OptDistance': opt_dists } df = pd.DataFrame(data) df.to_json(path_or_buf='data/att-TSP' + str(self.n_points) + '-data-test' + '.json')
def computeTsp(filename): solver = TSPSolver.from_tspfile(getCurrWDir() + "/inputs/" + filename) start_time = time.time() solution = solver.solve() eval_time = time.time() - start_time print(colored("--- %s seconds ---" % eval_time)) print(colored("Outcome TSP:", "red")) print(solution.found_tour) print(colored("With optimal value [m]:", "red")) print(solution.optimal_value / 100) return solution, eval_time
def solve(inst): # precision factor pr = 1e-3 # # shut output, not working # stdout = sys.stdout # sys.stdout = open(os.devnull, 'w') # solve slr = TSPSolver.from_data(inst[:, 0] / pr, inst[:, 1] / pr, 'EUC_2D') res = slr.solve(verbose=False) # # redirect output # sys.stdout = stdout return res.tour, res.optimal_value
def concorde(self, time): """ Solve the problem with concorde solver. Without penalization of prime cities. """ x = [c.x for c in self.stops[:-1]] y = [c.y for c in self.stops[:-1]] # Instantiate solver solver = TSPSolver.from_data(x, y, norm="EUC_2D") # solve tour_data = solver.solve(time_bound=float(time), verbose=True, random_seed=42) # Reorder the route with concorde solution order = np.append(tour_data.tour,[0]) new_route = [self.stops[i] for i in order] self.stops = new_route
def test_module(): gs = GeneticSolver(gene_type=OptimizableTour, N=200, mutation_rate=0.2) places = gs.population[0].places xs = [p.x for p in places] ys = [p.x for p in places] print(xs) print(ys) solver = TSPSolver.from_data(xs=xs, ys=ys, norm="EUC_2D") solution = solver.solve() print(solution.optimal_value) print(solution.tour) for i in range(1000): gs.evolve() ff = [f.fitness() for f in gs.population] print(ff)
def solve(Ma, Mw): """ Invokes Concorde to solve a TSP instance Uses Python's Redirector library to prevent Concorde from printing unsufferably verbose messages """ STDOUT = 1 STDERR = 2 redirector_stdout = Redirector(fd=STDOUT) redirector_stderr = Redirector(fd=STDERR) # Write graph on a temporary file write_graph(Ma, Mw, filepath='tmp', int_weights=True) redirector_stderr.start() redirector_stdout.start() # Solve TSP on graph solver = TSPSolver.from_tspfile('tmp') # Get solution solution = solver.solve(verbose=False) redirector_stderr.stop() redirector_stdout.stop() """ Concorde solves only symmetric TSP instances. To circumvent this, we fill inexistent edges with large weights. Concretely, an inexistent edge is assigned with the strictest upper limit to the cost of an optimal tour, which is n (the number of nodes) times 1 (the maximum weight). If one of these edges is used in the optimal solution, we can deduce that no valid tour exists (as just one of these edges costs more than all the others combined). OBS. in this case the maximum weight 1 is multiplied by 'bins' because we are converting from floating point to integers """ if any([ Ma[i, j] == 0 for (i, j) in zip(list(solution.tour), list(solution.tour)[1:] + list(solution.tour)[:1]) ]): return None else: return list(solution.tour)
def generate_data(self): points_list = [] solutions = [] opt_dists = [] data_iter = tqdm(range(self.data_size), unit='data') for i, _ in enumerate(data_iter): data_iter.set_description('Generating data points %i/%i' % (i + 1, self.data_size)) points = np.random.random((self.n_points, 2)) points_list.append(points) # solutions_iter: for tqdm solutions_iter = tqdm(points_list, unit='solve') if self.solve: for i, points in enumerate(solutions_iter): solutions_iter.set_description('Solved %i/%i' % (i + 1, len(points_list))) points_scaled = points * 10000 solver = TSPSolver.from_data(points_scaled[:, 0], points_scaled[:, 1], 'EUC_2D') sol = solver.solve(time_bound=-1, verbose=True) opt_tour, opt_dist = sol.tour, sol.optimal_value / 10000 solutions.append(opt_tour) opt_dists.append(opt_dist) else: solutions = None opt_dists = None data = { 'Points': points_list, 'OptTour': solutions, 'OptDistance': opt_dists } df = pd.DataFrame(data) df.to_json(path_or_buf='data/data_test' + str(self.n_points) + '.json')
def generate_data(num_samples: int, graph_size: int, dataset_name: str): points_list = [] solutions = [] opt_dists = [] data_iter = tqdm(range(num_samples), unit="data") for i, _ in enumerate(data_iter): data_iter.set_description("Generating data points %i/%i" % (i + 1, num_samples)) points = torch.empty(size=(graph_size, 2)).uniform_(0, 1) points_list.append(points) # solutions_iter: for tqdm solutions_iter = tqdm(points_list, unit="solve") for i, points in enumerate(solutions_iter): solutions_iter.set_description("Solved %i/%i" % (i + 1, len(points_list))) points_scaled = points.numpy() * FLOAT_SCALE solver = TSPSolver.from_data(points_scaled[:, 0], points_scaled[:, 1], "EUC_2D") sol = solver.solve(time_bound=-1, verbose=False) opt_tour, opt_dist = sol.tour, sol.optimal_value / FLOAT_SCALE solutions.append(opt_tour) opt_dists.append(opt_dist) data = { "Points": points_list, "OptTour": solutions, "OptDistance": opt_dists } file_name = f"tsp_{graph_size}_{dataset_name}_{num_samples}.pt" path = os.path.join(os.getcwd(), file_name) torch.save(data, path)
def pyconcorde(self): # Edge case: check for no stitches if len(self.multi_node_graph) == 0: return 0 # Create tsp file filename = 'embroidery.tsp' file_write = open(filename, 'w') file_write.write('NAME: Embroidery Reduction\n') file_write.write('TYPE: TSP\n') file_write.write( 'COMMENT: Concorde on a reduction from the embroidery problem\n') file_write.write('DIMENSION: ' + str(len(self.multi_node_graph)) + '\n') file_write.write('EDGE_WEIGHT_TYPE: EXPLICIT\n') file_write.write('EDGE_WEIGHT_FORMAT: FULL_MATRIX\n') file_write.write('EDGE_WEIGHT_SECTION\n') # Go through each row of the matrix, round up value, write to file for row in self.multi_node_graph: to_add = '' for val in row: to_add += str(math.ceil(val)) + ' ' file_write.write(to_add + '\n') file_write.write('EOF') file_write.close() # Solve instances solver = TSPSolver.from_tspfile(filename) solution = solver.solve() # Calculate excess distance -- every duplicate node needs distance excess = 0 for v in self.pattern: excess += 2 * len(self.pattern[v]) return solution.optimal_value - excess
print('testing') sys.stdout.flush() idx = 0 inst_idx = 1 for g, fname in tqdm(TestSet(), 'Solving instance no. {}'.format(inst_idx)): inst_idx += 1 testset_name = TESTSET if TESTSET != 'tsp2d' else "tsp2d_" + opt[ 'g_type'] inst_name = fname if TESTSET != 'tsp2d' else "inst_" + str(idx) inst_key = os.path.basename(inst_name)[:-4] if eval_concorde and inst_key not in all_results[ 'concorde'].keys(): # Concorde: # fname = get_dataset_path("berlin52") solver = TSPSolver.from_tspfile(fname) t3 = time.time() solution = solver.solve(verbose=False) t4 = time.time() # print 'Concorde sol val:' , solution.optimal_value # 1000000.0 is a normalization factor of s2v in TestSet above. # concorde_sol.append(solution.optimal_value / 1000000.0) # concorde_time.append(t4-t3) all_results['concorde'][inst_key] = { 'len': solution.optimal_value / 1000000.0, 'time': t4 - t3 } if inst_key not in all_results[model_name].keys(): api.InsertGraph(g, is_test=True) t1 = time.time() val, sol = api.GetSol(idx, nx.number_of_nodes(g))
def nearest_point(df,mean): obj= [] for i in range(len(df)) : obj.append(distance(df.iloc[i][['X','Y']],mean)) dest=df.iloc[obj.index(min(obj))]['CityId'] print('min=',dest) return dest north_pole = df[df['CityId']==0] n_p=north_pole[['mclust','X','Y']] route=n_p.append(centers,ignore_index=True) route=route.append(n_p,ignore_index=True) centers = pd.concat([centers,pd.DataFrame(columns=['start_point','end_point'])],sort=False) solver = TSPSolver.from_data( route.X, route.Y, norm="EUC_2D" ) #--------------- solver the tsp for centers --------------------- tour_data = solver.solve(time_bound = 60.0, verbose = True, random_seed = 42) centers_c=centers.copy() for i in range(len(centers)): print (tour_data[0][i+1]-1) centers.iloc[i]=centers_c.iloc[tour_data[0][i+1]-1] for i in range(1,n_cluster): a=int(centers.iloc[i].mclust) b=int(centers.iloc[i-1].mclust) print ('a',a,'b',b) coord=nearest_point(df[df['mclust']==a],centers.iloc[b][['X','Y']]) centers.loc[i,'start_point']=coord
from concorde.tsp import TSPSolver from matplotlib import collections as mc import numpy as np import pandas as pd import time import pylab as pl cities = pd.read_csv('../input/cities.csv') # Instantiate solver solver = TSPSolver.from_data(cities.X, cities.Y, norm="EUC_2D") t = time.time() tour_data = solver.solve( time_bound=60.0, verbose=True, random_seed=42 ) # solve() doesn't seem to respect time_bound for certain values? print(time.time() - t) print(tour_data.found_tour) pd.DataFrame({ 'Path': np.append(tour_data.tour, [0]) }).to_csv('submission.csv', index=False) # Plot tour lines = [[(cities.X[tour_data.tour[i]], cities.Y[tour_data.tour[i]]), (cities.X[tour_data.tour[i + 1]], cities.Y[tour_data.tour[i + 1]])] for i in range(0, len(cities) - 1)] lc = mc.LineCollection(lines, linewidths=2) fig, ax = pl.subplots(figsize=(20, 20)) ax.set_aspect('equal') ax.add_collection(lc) ax.autoscale()