示例#1
0
def sort_quanta(distances):
    """
    Solves the travelling salesman problem, with a magic zero-point, to
    find the shortest Hamiltonian path through the points. Returns the
    indices of the points in their sorted order.

    Call via get_codebook.

    Args:
        distances (ndarray): The distance matrix from ``get_distances()``.

    Returns:
        ndarray. A 1D array of size (n_colours).
    """
    # Set up the file describing the problem.
    outf = "/tmp/route.tsp"
    with open(outf, 'w') as f:
        f.write(dumps_matrix(distances, name="Route"))

    # Run the solver.
    tour = run(outf, start=0, solver="LKH")
    result = np.array(tour['tour'])

    # Slice off the initial value and the last value to account for the added
    # colours. Then subtract one to shift indices back to proper range.
    return result[1:-1] - 1
示例#2
0
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
示例#3
0
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
示例#4
0
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)
示例#5
0
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
示例#6
0
 def tsp(self, start_coord):
     out_f = "./tsp_dist.tsp"
     with open(out_f, 'w') as dest:
         dest.write(dumps_matrix(self.dist_matrix, name="TSP_Route"))
     tour = run(out_f, start=self.back_coords[start_coord], solver="lkh")
     return tour
示例#7
0
def solve(list_of_kingdom_names,
          starting_kingdom,
          adjacency_matrix,
          params=[]):
    """
    Write your algorithm here.
    Input:
        list_of_kingdom_names: An list of kingdom names such that node i of the graph corresponds to name index i in the list
        starting_kingdom: The name of the starting kingdom for the walk
        adjacency_matrix: The adjacency matrix from the input file

    Output:
        Return 2 things. The first is a list of kingdoms representing the walk, and the second is the set of kingdoms that are conquered
    """

    split_size = 15
    subgraph = nx.Graph()
    last_node = None

    starting_status = [0 for _ in list_of_kingdom_names]
    sublist = []

    starting_index = list_of_kingdom_names.index(starting_kingdom)
    N = len(list_of_kingdom_names)
    H = adjacency_matrix_to_graph(adjacency_matrix)

    result = []
    closed_walk, conquered_kingdoms = [], []

    stack = []
    known = set()
    stack.append((None, starting_index))
    while stack:
        prev, node = stack.pop()
        if node in known:
            continue
        sublist.append(node)
        known.add(node)
        flag = False

        if len(sublist) == 1:
            subgraph.add_node(0)
        elif prev in sublist:
            subgraph.add_edge(sublist.index(prev),
                              len(sublist) - 1,
                              weight=H[prev][node]['weight'])
        else:
            flag = True
            sublist.pop()

        if flag or len(sublist) == split_size or len(known) == N:
            sub_starting_status = [starting_status[node] for node in sublist]

            sub_result = solver_helper(sublist, subgraph, sub_starting_status,
                                       adjacency_matrix)
            for i in range(len(sub_result)):
                if sub_result[i] == 2:
                    conquered_kingdoms.append(sublist[i])
                    for nbr in H.adj[sublist[i]]:
                        starting_status[nbr] = 1
            subgraph = nx.Graph()
            sublist = []
        if flag:
            subgraph.add_node(0)
            sublist.append(node)

        # Need to fix the order the neigbhors being added: too costly
        adjs = list(H.adj[node])
        avg = sum([H[node][nbr]['weight'] for nbr in adjs]) / len(adjs)
        adjs = sorted(adjs,
                      key=lambda nbr: abs(H[node][nbr]['weight'] - avg),
                      reverse=True)
        for nbr in adjs:
            stack.append((node, nbr))
    if sublist != []:
        sub_starting_status = [starting_status[node] for node in sublist]
        sub_result = solver_helper(sublist, subgraph, sub_starting_status,
                                   adjacency_matrix)
        for i in range(len(sub_result)):
            if sub_result[i] == 2:
                conquered_kingdoms.append(sublist[i])

    tmp_conquered = [(-adjacency_matrix[c][c], c) for c in conquered_kingdoms]

    while tmp_conquered != []:
        c = heappop(tmp_conquered)[1]
        conquered_kingdoms.remove(c)
        if not nx.is_dominating_set(H, conquered_kingdoms):
            conquered_kingdoms.append(c)

    conquered = list(conquered_kingdoms)

    if starting_index not in conquered:
        conquered.append(starting_index)

    C = len(conquered)
    if C == 1:
        return [starting_kingdom], [starting_kingdom]
    elif C == 2:
        if starting_index == conquered[0]:
            start, next = conquered
        else:
            next, start = conquered
        _, path = nx.bidirectional_dijkstra(H, start, next)
        path = [list_of_kingdom_names[c] for c in path]
        return path + path[::-1][1:], [
            list_of_kingdom_names[c] for c in conquered_kingdoms
        ]
    else:
        matrix = np.zeros((C, C))
        paths = dict()
        for i in range(C):
            for j in range(i + 1, C):
                matrix[i, j], path = nx.bidirectional_dijkstra(
                    H, conquered[i], conquered[j])
                paths[(i, j)] = path
                paths[(j, i)] = path[::-1]
        matrix = matrix + matrix.T

        if np.max(matrix) >= 10e6:
            matrix = matrix / 10e6
        outf = "/tmp/myroute.tsp"
        with open(outf, 'w') as dest:
            dest.write(dumps_matrix(matrix, name="My Route"))

        tour = run(outf, start=conquered.index(starting_index), solver="LKH")

        tour_path = tour['tour']
        for i in range(len(tour_path)):
            cur = tour_path[i]
            if i == len(tour_path) - 1:
                dest = conquered.index(starting_index)
            else:
                dest = tour_path[i + 1]
            closed_walk.append(paths[(cur, dest)])

        final_walk = []

        for i in range(len(closed_walk)):
            data = closed_walk[i]

            if i == 0:
                for j in data:
                    final_walk.append(list_of_kingdom_names[j])
            else:
                for j in data[1:]:
                    final_walk.append(list_of_kingdom_names[j])

        return final_walk, [
            list_of_kingdom_names[c] for c in conquered_kingdoms
        ]
示例#8
0
from pytsp import atsp_tsp, run, dumps_matrix
# import os

if __name__ == "__main__":
    matrix = [[0, 2910, 4693], [2903, 0, 5839], [4695, 5745, 0]]

    matrix_sym = atsp_tsp(matrix, strategy="avg")
    # path = os.path.abspath("cs170-proj")
    outf = "/tmp/myroute.tsp"
    with open(outf, 'w') as dest:
        dest.write(dumps_matrix(matrix_sym, name="My Route"))
    tour = run(outf, start=1, solver="concorde")
    print(tour)
示例#9
0
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))