def calculate_route(matrix): matrix_sym = atsp_tsp(matrix, strategy="avg") # write temporary file in the `tsp` format outf = "myroute_concorde.tsp" silentremove(outf) silentremove("myroute_concorde.mas") silentremove("myroute_concorde.pul") silentremove("myroute_concorde.sav") silentremove("myroute_concorde.sol") silentremove("o.txt") silentremove("o2.txt") silentremove("Omyroute_concorde.mas") silentremove("Omyroute_concorde.pul") silentremove("Omyroute_concorde.sav") with open(outf, 'w') as dest: dest.write(dumps_matrix(matrix_sym, name="My Route")) # print(dumps_matrix(matrix_sym, name="My Route")) # run the optimization with concorde tour = run_concorde(outf, start=0, solver="concorde") # or with LKH # tour = run(outf, start=10, solver="LKH") tour['tour'].append(tour['tour'][0]) return tour
def test_tour_LKH(matrix): matrix_sym = atsp_tsp(matrix, strategy="avg") outf = "/tmp/myroute_lkh.tsp" with open(outf, 'w') as dest: dest.write(dumps_matrix(matrix_sym, name="My Route")) tour = run(outf, start=10, solver="lkh") assert tour['solution'] == 102975 assert tour['tour'][0] == 10
matrix = [[0, 2910, 4693], [2903, 0, 5839], [4695, 5745, 0]] from pytsp import atsp_tsp, run, dumps_matrix matrix_sym = atsp_tsp(matrix, strategy="avg") outf = "./tsp_dist.tsp" with open(outf, 'w') as dest: dest.write(dumps_matrix(matrix_sym, name="My Route")) tour = run(outf, start=None, solver="lkh") print("tour", tour)
def lkh_TSP(list_of_kingdom_names, starting_kingdom, adjacency_matrix, conquered_kingdoms_indices, N, dict_kingdom_index_to_name, dict_kingdom_name_to_index, tuples_kingdom_name_to_cost, starting_kingdom_index, dict_kingdom_index_to_cost, adjacency_lists): # Build TSP Distance matrix special_nodes = conquered_kingdoms_indices if starting_kingdom_index not in special_nodes: special_nodes.append(starting_kingdom_index) G = adjacency_matrix_to_graph(adjacency_matrix) shortest_lengths = dict(nx.shortest_path_length(G, weight="weight")) shortest_paths = dict(nx.shortest_path(G, weight="weight")) # print(shortest_lengths) N_TSP = len(special_nodes) dict_TSP_index_to_index = { TSP_index: index for TSP_index, index in enumerate(special_nodes) } dict_index_to_TSP_index = { index: TSP_index for TSP_index, index in enumerate(special_nodes) } distance_matrix = [[0 for _ in range(N_TSP)] for _ in range(N_TSP)] # print(special_nodes) # upper_bound = 2**31 for i in range(N_TSP): for j in range(N_TSP): if i != j: edge_weight = int( round(shortest_lengths[dict_TSP_index_to_index[i]][ dict_TSP_index_to_index[j]] + 1)) # distance_matrix[i][j] = min(edge_weight, upper_bound) distance_matrix[i][j] = edge_weight else: distance_matrix[i][j] = 0 # print(distance_matrix) # run TSP concorde matrix_sym = atsp_tsp(distance_matrix, strategy="avg") outf = "/tmp/myroute.tsp" with open(outf, 'w') as dest: dest.write(dumps_matrix(matrix_sym, name="My Route")) try: tour = run(outf, start=dict_index_to_TSP_index[starting_kingdom_index], solver="lkh") # convert to original indices tour_G = [ dict_TSP_index_to_index[TSP_index] for TSP_index in tour["tour"] ] # print(tour_G) # stitch path together edge_list = tour_to_list_of_edges(tour_G) # print(edge_list) stiched_tour = [edge_list[0][0]] # starting node edge_list.append((edge_list[-1][1], starting_kingdom_index)) for i, j in edge_list: stiched_tour.extend(shortest_paths[i][j][1:]) closed_walk = [ dict_kingdom_index_to_name[index] for index in stiched_tour ] except: closed_walk = "Error" # print(closed_walk) return closed_walk
def optimal_tour(features, mode, profile, out_points, solver): """ A command line interface for solving the traveling salesman problem Input geojson features with point geometries and output the optimal tour as geojson feature collection. \b $ optimal_tour waypoints.geojson | geojson-summary 19 points and 1 line If using geodesic or directions modes, input must be in lonlat coordinates Directions mode requires a Mapbox account and a valid token set as the MAPBOX_ACCESS_TOKEN environment variable. """ log("Get point features") features = [f for f in features if f['geometry']['type'] == 'Point'] if len(features) <= 2: raise click.UsageError( "Need at least 3 point features to create route") if mode != 'cartesian' and not is_lonlat(features): raise click.UsageError( "For this {} mode, input must be in lonlat coordinates".format( mode)) log("Create travel cost matrix") if mode == 'cartesian': matrix = local_matrix(features, 'cartesian') elif mode == 'geodesic': matrix = local_matrix(features, 'geodesic') elif mode == 'directions': dist_api = mapbox.Distance() res = dist_api.distances(features, profile=profile) if res.status_code == 200: matrix = res.json()['durations'] else: raise Exception( "Got a {0} error from the Distances API: {1}".format( res.status_code, res.content)) log("Prep data") matrix_sym = atsp_tsp(matrix, strategy="avg") outf = "/tmp/myroute.tsp" with open(outf, 'w') as dest: dest.write(dumps_matrix(matrix_sym, name="My Route")) log("Run TSP solver") tour = run(outf, start=0, solver=solver) order = tour['tour'] features_ordered = [features[i] for i in order] log("Create lines connecting the tour") if mode == 'directions': # gather geojson linestring features along actual route via directions directions_api = mapbox.Directions() route_features = [] for chunk in split_overlap(features_ordered + [features_ordered[0]], 24): res = directions_api.directions(chunk, profile='mapbox.' + profile) if res.status_code == 200: route_features.append(res.geojson()['features'][0]) else: raise Exception( "Got a {0} error from the Directions API: {1}".format( res.status_code, res.content)) else: # Alternative, straight line distance between points route_coords = [f['geometry']['coordinates'] for f in features_ordered] route_coords.append(features_ordered[0]['geometry']['coordinates']) route_features = [{ 'type': 'Feature', 'properties': { 'tour': tour }, 'geometry': { 'type': 'LineString', 'coordinates': route_coords } }] # meld into one geojson feature collection log("Output feature collection") out_features = route_features if out_points: out_features += features_ordered collection = {'type': 'FeatureCollection', 'features': out_features} click.echo(json.dumps(collection))