コード例 #1
0
def mst_dfs_solve(list_of_locations,
                  list_of_homes,
                  starting_car_location,
                  adjacency_matrix,
                  existing_mst=None,
                  params=[]):

    if not existing_mst:
        G, _ = adjacency_matrix_to_graph(adjacency_matrix)
        mst = nx.minimum_spanning_tree(G)
    else:
        mst = existing_mst

    seen = set()
    traversal = []

    def dfs(u):
        if u not in seen:
            traversal.append(u)
            seen.add(u)
            for v in mst.neighbors(u):
                if v not in seen:
                    dfs(v)
                    traversal.append(u)

    dfs(list_of_locations.index(starting_car_location))

    dropoffs = {home: [home] for home in list_of_homes}
    dropoffs = {
        list_of_locations.index(key):
        convert_locations_to_indices(dropoffs[key], list_of_locations)
        for key in dropoffs
    }
    return traversal, dropoffs
コード例 #2
0
 def __init__(self, adj_matrix, homes_arr, soda_loc, locs):
     self.graph = util170.adjacency_matrix_to_graph(adj_matrix)[
         0]  ## maybe we want a graph object from network x instead
     mapping = dict(zip(self.graph, locs))
     self.graph = netx.relabel_nodes(self.graph, mapping)
     self.distanceMemo = dict()
     self.start_loc = soda_loc
     self.homes = homes_arr
コード例 #3
0
 def __init__(self, num_of_locations, num_houses, list_of_locations,
              list_of_houses, starting_car_location, adjacency_matrix):
     self.number_of_locations = num_of_locations
     self.number_of_homes = num_houses
     self.list_of_locations = list_of_locations
     self.list_of_houses = list_of_houses
     self.starting_car_location = starting_car_location
     self.adjacency_matrix = adjacency_matrix
     self.G = adjacency_matrix_to_graph(self.adjacency_matrix)[0]
コード例 #4
0
 def __init__(self, adj_matrix, homes_arr, soda_loc, locs):
     self.graph = util170.adjacency_matrix_to_graph(adj_matrix)[0]
     mapping = dict(zip(self.graph, locs))
     self.netx_graph = netx.relabel_nodes(self.graph, mapping)
     self.distanceMemo = dict()
     self.start_loc = soda_loc
     self.homes = homes_arr
     homes_to_visit = self.homes.copy()
     homes_to_visit.append(self.start_loc)
     self.steiner_tree = steiner_tree(self.netx_graph, homes_to_visit, weight='weight')
コード例 #5
0
def solve(list_of_locations,
          list_of_homes,
          starting_car_location,
          adjacency_matrix,
          input_file,
          params=[]):
    """
    Write your algorithm here.
    Input:
        list_of_locations: A list of locations such that node i of the graph corresponds to name at index i of the list
        list_of_homes: A list of homes
        starting_car_location: The name of the starting location for the car
        adjacency_matrix: The adjacency matrix from the input file
    Output:
        A list of locations representing the car path
        A dictionary mapping drop-off location to a list of homes of TAs that got off at that particular location
        NOTE: both outputs should be in terms of indices not the names of the locations themselves
    """
    start_idx = list_of_locations.index(starting_car_location)
    homes_idx = [list_of_locations.index(h) for h in list_of_homes]
    new_homes_idx = convert_homes_idx(start_idx, homes_idx)
    graph, msg = student_utils.adjacency_matrix_to_graph(adjacency_matrix)

    #nn_output_directory = 'nearest_neighbor_algo/outputs'
    #nn_output_directory = 'local_search/outputs'
    #nn_output_directory = 'mst_2_approximation/outputs'
    #nn_output_directory = 'local_search2run/outputs'
    #nn_output_file = utils.input_to_output(input_file, nn_output_directory)
    #nn_output_data = utils.read_file(nn_output_file)
    #car_cycle = nn_output_data[0]
    #car_cycle_idx = student_utils.convert_locations_to_indices(car_cycle, list_of_locations)
    car_cycle_idx = new_homes_idx

    shortest_paths = nx.floyd_warshall(graph, weight='weight')
    new_car_cycle_idx = local_search(car_cycle_idx, shortest_paths)

    #final_path
    final_cycle = []
    for i in range(len(new_car_cycle_idx) - 1):
        shortest_path = nx.shortest_path(graph,
                                         new_car_cycle_idx[i],
                                         new_car_cycle_idx[i + 1],
                                         weight='weight')
        shortest_path.pop()
        final_cycle.extend(shortest_path)
    final_cycle.append(new_car_cycle_idx[-1])
    dropoffs = get_valid_dropoffs(final_cycle, homes_idx)
    return final_cycle, dropoffs
コード例 #6
0
    def __init__(self, adj_matrix, homes_arr, soda_loc, locs):
        self.graph = util170.adjacency_matrix_to_graph(adj_matrix)[
            0]  ## maybe we want a graph object from network x instead
        mapping = dict(zip(self.graph, locs))
        self.graph = netx.relabel_nodes(self.graph, mapping)
        self.start_loc = soda_loc
        self.homes = homes_arr
        self.locs = locs
        self.distanceMemo = dict()

        self.distancePathMemo = dict(
            netx.algorithms.shortest_paths.all_pairs_dijkstra_path(self.graph))
        self.distanceLengthMemo = dict(
            netx.algorithms.shortest_paths.all_pairs_dijkstra_path_length(
                self.graph))
        print("finished_memoizing_shortest_paths")
コード例 #7
0
def findtour(inputfile):
    data = read_file(inputfile)
    numl, numh, listl, listh, start, matrix = data_parser(data)
    G, message = adjacency_matrix_to_graph(matrix)
    nodes = G.__iter__()
    nodedict = {}
    numdict = {}
    for i in range(numl):
        nextnode = next(nodes)
        nodedict[listl[i]] = nextnode
        numdict[nextnode] = listl[i]
    paths = []
    graphs = []
    distances = []
    disttonode = {}
    nodetodist = {}
    list_home_nodes = []
    for home in listh:
        homenode = nodedict.get(home)
        distance, shortestpath = nx.single_source_dijkstra(
            G, homenode, nodedict.get(start))
        paths += [shortestpath]
        shortestgraph = nx.path_graph(shortestpath)
        graphs += [shortestgraph]
        distances.append(distance)
        if not distance in disttonode:
            disttonode[distance] = [homenode]
        else:
            disttonode[distance].append(homenode)
        nodetodist[homenode] = distance
        list_home_nodes += [homenode]
    distances.sort(reverse=False)
    mst = nx.compose_all(graphs)
    leaves = [x for x in mst.nodes() if mst.degree(x) == 1]
    visited = []
    drive = []
    adjlist = mst._adj
    startnode = nodedict.get(start)
    dropdict = {}
    tour, dropdict = traverse(startnode, visited, leaves, drive, distances,
                              adjlist, nodedict, disttonode, nodetodist, G,
                              startnode, mst, list_home_nodes, dropdict)
    tour = [
        tour[i] for i in range(len(tour)) if (i == 0) or tour[i] != tour[i - 1]
    ]
    return tour, dropdict, numdict
コード例 #8
0
def find_optimal_dropoff_within_cluster(list_of_homes, adjacency_matrix,
                                        community_mappings):
    # returns one optimal drop off within a cluster

    graph = student_utils.adjacency_matrix_to_graph(adjacency_matrix)[0]

    dropoffs = {}

    print(community_mappings)
    print(list_of_homes)
    for label in community_mappings.keys():
        curr_homes = []
        curr_locations = community_mappings[label]
        # find the homes within the current community
        for node in curr_locations:
            if str(node) in list_of_homes:
                curr_homes.append(node)

        neighbors = {}
        curr_neighbors = []
        # create a mapping between nodes and their neighbors
        # nodes are mapped to a list of tuples that contains the neighboring node and the weight
        for node in curr_locations:
            for i in range(len(adjacency_matrix[node])):
                if type(adjacency_matrix[node][i]) != str:
                    curr_neighbors.append((i, adjacency_matrix[node][i]))

            neighbors[node] = curr_neighbors

        # find the costs of dropping off at each location
        dropoff_costs = find_cost_of_dropoff_within_cluster(
            graph, curr_homes, curr_locations, neighbors)

        # find the minimum cost dropoff
        min_drop_cost = float("inf")
        min_drop = None
        for key in dropoff_costs.keys():
            if dropoff_costs[key] < min_drop_cost:
                min_drop_cost = dropoff_costs[key]
                min_drop = key

        dropoffs[label] = min_drop

    return dropoffs
コード例 #9
0
def solve_from_file_score(input_file, output_directory, params=[]):
    print('Processing', input_file)

    input_data = utils.read_file(input_file)
    num_of_locations, num_houses, list_locations, list_houses, starting_car_location, adjacency_matrix = data_parser(
        input_data)
    car_path, drop_offs = solve(list_locations,
                                list_houses,
                                starting_car_location,
                                adjacency_matrix,
                                params=params)

    basename, filename = os.path.split(input_file)
    if not os.path.exists(output_directory):
        os.makedirs(output_directory)
    output_file = utils.input_to_output(input_file, output_directory)
    G = student_utils.adjacency_matrix_to_graph(adjacency_matrix)[0]
    #convertToFile(car_path, drop_offs, output_file, list_locations)
    return G, car_path, drop_offs
コード例 #10
0
def preProcess(list_of_locations, list_of_homes, starting_car_location,
               adjacency_matrix):

    G = student_utils.adjacency_matrix_to_graph(adjacency_matrix)

    location_dict = {}
    list_of_homes_int = []
    list_of_locations_int = [_ for _ in range(len(list_of_locations))]
    for j in range(len(list_of_locations)):
        location_dict[j] = list_of_locations[j]
        if list_of_locations[j] == starting_car_location:
            car_start_int = j
        for _ in list_of_homes:
            if _ == list_of_locations[j]:
                list_of_homes_int += [j]

    for i in list_of_homes_int:
        if G[0].degree[i] == 1:
            list_of_homes_int[i] = G.edges[i][0]

    return list_of_locations, list_of_homes, starting_car_location, adjacency_matrix
コード例 #11
0
def greedy_shortest_path_solve(list_of_locations,
                               list_of_homes,
                               starting_car_location,
                               adjacency_matrix,
                               verbose=False,
                               params=[]):
    G, _ = adjacency_matrix_to_graph(adjacency_matrix)
    source_idx = list_of_locations.index(starting_car_location)
    num_locs = len(G)

    home_idxs = set([list_of_locations.index(h) for h in list_of_homes])
    paths, all_pairs_dists = nx.floyd_warshall_predecessor_and_distance(
        G, weight='weight')

    def reconstruct_path(source, target, predecessors):
        if source == target:
            return []
        prev = predecessors[source]
        curr = prev[target]
        path = [target, curr]
        while curr != source:
            curr = prev[curr]
            path.append(curr)
        return list(reversed(path))

    traversal = [source_idx]

    # Find distances to previous node traversed
    dists = [(all_pairs_dists[traversal[-1]][h], h) for h in home_idxs]

    while dists:
        n = min(dists, key=lambda x: x[0])
        dists.remove(n)
        n = n[1]
        traversal.extend(reconstruct_path(traversal[-1], n, paths)[1:])
        dists = [(all_pairs_dists[traversal[-1]][r], r) for _, r in dists]

    traversal.extend(reconstruct_path(traversal[-1], source_idx, paths)[1:])

    return traversal, assign_dropoffs(G, traversal, home_idxs, all_pairs_dists)
コード例 #12
0
ファイル: findtour-david.py プロジェクト: panerdavid/170proj
def findtour(inputfile):
    data = read_file(inputfile)
    # need this to create output file
    name = inputfile.name
    numl, numh, listl, listh, start, matrix = data_parser(data)
    G, message = adjacency_matrix_to_graph(matrix)
    nodes = G.__iter__()
    nodedict = {}
    for i in range(numl):
        nodedict[listl[i]] = next(nodes)
    paths = []
    graphs = []
    distances = []
    disttonode = {}
    nodetodist = {}
    for home in listh:
        homenode = nodedict.get(home)
        distance, shortestpath = nx.single_source_dijkstra(
            G, homenode, nodedict.get(start))
        paths += [shortestpath]
        shortestgraph = nx.path_graph(shortestpath)
        graphs += [shortestgraph]
        distances.append(distance)
        # fix duplicate keys
        if not distance in disttonode:
            disttonode[distance] = [homenode]
        else:
            disttonode[distance].append(homenode)
        nodetodist[homenode] = distance
    distances.sort(reverse=True)
    mst = nx.compose_all(graphs)
    leaves = [x for x in mst.nodes() if mst.degree(x) == 1]
    visited = []
    drive = []
    adjlist = mst._adj
    startnode = nodedict.get(start)
    tour = traverse(startnode, visited, leaves, drive, distances,
                    adjlist, nodedict, disttonode, nodetodist, G, startnode, mst, [], listh)
    return tour
コード例 #13
0
def visualize_communities_and_dropoffs(list_of_locations, list_of_homes,
                                       starting_car_location,
                                       adjacency_matrix):
    # draw each community in a different color with its dropoff node
    G = student_utils.adjacency_matrix_to_graph(adjacency_matrix)[0]
    comm_mappings = find_community_mappings(list_of_homes, adjacency_matrix)
    comm_dropoffs = find_dropoff_locations(list_of_homes, adjacency_matrix,
                                           starting_car_location,
                                           comm_mappings)
    color_map = [0 for n in range(len(list_of_locations))]
    current_color = 0
    for comm_label in comm_mappings:
        locs = comm_mappings[comm_label]
        for loc in locs:
            color_map[loc] = current_color
        current_color += 1.0 / len(comm_mappings.keys())
    color_map[int(starting_car_location)] = 1
    labels = nx.get_edge_attributes(G, 'weight')
    nx.draw(G, node_color=color_map, with_labels=True, font_weight='bold')
    nx.draw_networkx_edge_labels(G,
                                 pos=nx.spring_layout(G),
                                 edge_labels=labels)
    plt.show()
コード例 #14
0
def plot_graph(filepath,
               layout_style=nx.spring_layout,
               show_labels=True,
               show_edge_weights=False,
               edges_to_draw=None,
               directed=False):

    if isinstance(filepath, str):
        (num_locations, num_houses, location_names, house_names, source,
         adj) = parse_input(filepath)
        G, _ = adjacency_matrix_to_graph(adj)
    else:
        raise NotImplementedError

    if directed:
        G = G.to_directed()

    plt.figure(figsize=(10, 10))
    pos = layout_style(G)
    colormap = [('yellow' if str(i) in house_names else 'red')
                for i in range(num_locations)]
    source_index = location_names.index(source)
    colormap[source_index] = 'blue'

    nx.draw(G, pos=pos, node_color=colormap, with_labels=show_labels)
    if show_edge_weights:
        labels = nx.get_edge_attributes(G, 'weight')
        nx.draw_networkx_edge_labels(G, pos=pos, edge_labels=labels)

    if edges_to_draw:
        nx.draw_networkx_edges(G,
                               pos=pos,
                               edgelist=edges_to_draw,
                               edge_color='green')

    plt.show()
コード例 #15
0
def solve(list_of_locations,
          list_of_homes,
          starting_car_location,
          adjacency_matrix,
          params=[]):
    """
    Write your algorithm here.
    Input:
        list_of_locations: A list of locations such that node i of the graph corresponds to name at index i of the list
        list_of_homes: A list of homes
        starting_car_location: The name of the starting location for the car
        adjacency_matrix: The adjacency matrix from the input file
    Output:
        A list of locations representing the car path
        A dictionary mapping drop-off location to a list of homes of TAs that got off at that particular location
        NOTE: both outputs should be in terms of indices not the names of the locations themselves
    """
    """list_of_locations, list_of_homes_int, starting_car_location, \
    adjacency_matrix = preProcess(list_of_locations, list_of_homes, starting_car_location, adjacency_matrix)"""

    if len(list_of_locations) == 0:
        return [], {}

    #Do not delete next line
    # graphModifier.graphClusterer(list_of_locations, list_of_homes, starting_car_location, adjacency_matrix)
    location_dict = {}
    car_start_int = 0

    list_of_homes_int = []
    list_of_locations_int = [_ for _ in range(len(list_of_locations))]
    for j in range(len(list_of_locations)):
        location_dict[j] = list_of_locations[j]
        if list_of_locations[j] == starting_car_location:
            car_start_int = j
        for _ in list_of_homes:
            if _ == list_of_locations[j]:
                list_of_homes_int += [j]

    #preProcess(list_of_locations, list_of_homes, starting_car_location, adjacency_matrix)
    G = student_utils.adjacency_matrix_to_graph(adjacency_matrix)[0]
    B = clusterGraph(list_of_locations_int, list_of_homes_int, car_start_int,
                     G)
    returner = practiceSolver.tspRepeats(B, car_start_int)
    if len(returner) == 0:
        returner = [car_start_int]

    finalList = [returner[0]]
    for i in range(len(returner) - 1):
        finalList += nx.shortest_path(G,
                                      returner[i],
                                      returner[i + 1],
                                      weight='weight')[1:]
    finalList += nx.shortest_path(G,
                                  returner[-1],
                                  returner[0],
                                  weight='weight')[1:]

    all_distances = dict(nx.floyd_warshall(G))
    returnMapping = {}
    for i in list_of_homes_int:
        minDist = float('inf')
        home_map = 999
        for j in finalList:
            if all_distances[i][j] < minDist:
                minDist = all_distances[i][j]
                home_map = j
        if home_map != 999:
            if not home_map in returnMapping:
                returnMapping[home_map] = [i]
            else:
                returnMapping[home_map] = returnMapping[home_map] + [i]

    #clustering_approach.visualize_communities_and_dropoffs(list_of_locations, list_of_homes, starting_car_location, adjacency_matrix)
    returnList = []
    for i in finalList:
        returnList.append(location_dict[i])

    print(cost_of_solution(G, [int(_) for _ in finalList], returnMapping)[0])
    return [int(_) for _ in finalList], returnMapping
コード例 #16
0
def trivial_output_solver(list_of_locations,
                          list_of_homes,
                          starting_car_location,
                          adjacency_matrix,
                          params=[]):
    G = student_utils.adjacency_matrix_to_graph(adjacency_matrix)[0]

    # helper function with access to G
    def distance_between_locations(a, b):
        path_dist = nx.shortest_path_length(G, a, b)
        # print("distance from " + str(a) + " to " + str(b) +  ": ", path_dist)
        return path_dist

    # either proceed linearly through list of homes or through shuffled list of homes
    randomized_homes = np.random.shuffle(list_of_homes)
    homes = list_of_homes

    # using approximated average clustering for G:
    clustering_coeffs = nx.clustering(G)
    print("approximated average clustering coefficient:", clustering_coeffs)
    home_coeffs = {int(h): clustering_coeffs[int(h)] for h in homes}
    print("home clustering coeffs:", home_coeffs)

    # using the Girvan–Newman method to find communities of graphs
    # define custom function for how to select edges to remove in the algorithm
    def most_central_edge(G):
        centrality = nx.edge_betweenness_centrality(G,
                                                    normalized=False,
                                                    weight='weight')
        max_cent = max(centrality.values())
        # Scale the centrality values so they are between 0 and 1,
        # and add some random noise.
        centrality = {e: c / max_cent for e, c in centrality.items()}
        # Add some random noise.
        centrality = {e: c + np.random.random() for e, c in centrality.items()}
        return max(centrality, key=centrality.get)

    # get only the first k tuples of communities
    k = 10

    comp = algos.community.centrality.girvan_newman(
        G, most_valuable_edge=most_central_edge)
    for communities in itertools.islice(comp, k):
        print("communities: ", tuple(sorted(c) for c in communities))

    # using A* from start to each node
    total_path = []
    current_home = homes[0]
    total_path += nx.astar_path(G, int(starting_car_location),
                                int(current_home), distance_between_locations)
    for next_home in homes[1:]:
        # print("finding path between " + str(current_home) + " and " + str(next_home))
        path_between = nx.astar_path(G, int(starting_car_location),
                                     int(current_home),
                                     distance_between_locations)
        total_path += path_between
        current_home = next_home
    total_path += nx.astar_path(G, int(current_home),
                                int(starting_car_location),
                                distance_between_locations)
    print("total super shitty path: " + str(total_path))

    # locs = []
    # for i in list_of_locations:
    #     locs.append(int(i))
    #
    # homes = []
    # for i in list_of_homes:
    #     homes.append(int(i))

    # # first, find a node that is a neighbor of the start
    # dropOffIndex = None
    # for i in range(len(adjacency_matrix[0])):
    #     if adjacency_matrix[0][i] == 1:
    #         dropOffIndex = i
    #
    # dropOffNode = list_of_locations[dropOffIndex]

    graph_maker.print_trivial_output(len(list_of_locations),
                                     starting_car_location, list_of_homes)

    start = list_of_locations[int(starting_car_location)]
    # dropOffNode = list_of_locations[int(dropOffNode)]

    start = int(start)
    # dropOffNode = int(dropOffNode)
    return [start], {start: homes}
コード例 #17
0
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Parsing arguments')
    parser.add_argument('locations', type=int)
    parser.add_argument('tas', type=int)
    args = parser.parse_args()

    while True:
        write_to_file(
            str(args.locations) + ".in",
            generate_input(args.locations, args.tas))
        input_file = str(args.locations) + ".in"
        input_data = utils.read_file(input_file)
        num_of_locations, num_houses, list_locations, list_houses, starting_car_location, adjacency_matrix = data_parser(
            input_data)
        G, adj_message = adjacency_matrix_to_graph(adjacency_matrix)
        if not is_metric(G):
            print("not metric!")
            continue

        car_path, drop_offs = solve(list_locations,
                                    list_houses,
                                    starting_car_location,
                                    adjacency_matrix,
                                    params=[])

        seen = []
        duplicate_found = False
        for nxt in car_path[1:-1]:
            if nxt in seen:
                print("duplicate city found!", nxt)
コード例 #18
0
    def solve(self,
              list_of_locations,
              list_of_homes,
              starting_car_location,
              adjacency_matrix,
              params=[]):
        """
        Write your algorithm here.
        Input:
            list_of_locations: A list of locations such that node i of the graph corresponds to name at index i of the list
            list_of_homes: A list of homes
            starting_car_location: The name of the starting location for the car
            adjacency_matrix: The adjacency matrix from the input file
        Output:
            A list of locations representing the car path
            A list of (location, [homes]) representing drop-offs
        """
        adj = adjacency_matrix

        s = starting_car_location
        L = list_of_locations
        homes_numbered = [L.index(i) for i in list_of_homes]
        self.homes = homes_numbered
        G = student_utils.adjacency_matrix_to_graph(adj)[0]
        # show_graph(G)
        s = L.index(s)

        H = [L.index(i) for i in list_of_homes] + [s]

        G_steinertree = (steinertree.steiner_tree(G, H))
        directed_steinertree = nx.dfs_tree(G_steinertree, s)

        self.prune_tree(directed_steinertree, s)

        drop_off_locs = set(self.drop_off.values())
        pruned_homes = set(self.drop_off.keys())

        for home in homes_numbered:
            if not (home in pruned_homes):
                drop_off_locs.add(home)

        p, d = nx.floyd_warshall_predecessor_and_distance(G)

        path = (self.nearest_neighbors(drop_off_locs, d, s, p))
        # pos = hierarchy_pos(directed_steinertree, s)
        # nx.draw(directed_steinertree, pos=pos, with_labels=True)
        # plt.show()

        final_dict = {i: [] for i in drop_off_locs}
        for i in homes_numbered:
            if i in drop_off_locs:
                final_dict[i].append(i)
            else:
                final_dict[self.drop_off[i]].append(i)

        with_steiner = path, final_dict
        without_steiner_path = (self.nearest_neighbors(H, d, s, p))
        without_steiner_dict = {i: [i] for i in homes_numbered}
        self.drop_off = {}
        self.prune_tree(directed_steinertree, s)
        # pos = hierarchy_pos(directed_steinertree, s)
        # nx.draw(directed_steinertree, pos=pos, with_labels=True)
        # plt.show()
        drop_off_locs = set(self.drop_off.values())
        pruned_homes = set(self.drop_off.keys())

        for home in homes_numbered:
            if not (home in pruned_homes):
                drop_off_locs.add(home)

        p, d = nx.floyd_warshall_predecessor_and_distance(G)

        path_double_pruned = (self.nearest_neighbors(drop_off_locs, d, s, p))

        final_dict_double_pruned = {i: [] for i in drop_off_locs}
        for i in homes_numbered:
            if i in drop_off_locs:
                final_dict_double_pruned[i].append(i)
            else:
                final_dict_double_pruned[self.drop_off[i]].append(i)

        return min([
            with_steiner, (without_steiner_path, without_steiner_dict),
            (path_double_pruned, final_dict_double_pruned)
        ],
                   key=lambda x: cost_of_solution(G, x[0], x[1]))
コード例 #19
0
def flp_solve(list_of_locations,
                  list_of_homes,
                  starting_car_location,
                  adjacency_matrix,
                  solve,
                  params=[]):
    mapping = defaultdict(int)
    for i in range(len(list_of_locations)):
        mapping[list_of_locations[i]] = i
    G, _ = adjacency_matrix_to_graph(adjacency_matrix)
    U = list_of_homes
    facilities = list_of_locations
    start = starting_car_location
    paths, distances = nx.floyd_warshall_predecessor_and_distance(G, weight='weight')
#     print(distances)
#     print(paths)
# print("ran all pairs")
    # Builds set S in polynomial time as opposed to powerset (exponential)
    def buildS():
        res = []
        for f in facilities:
            for s in range(1, len(U)):
                sorted_dist = sorted([(target, distances[mapping[f]][mapping[target]]) for target in U], key=lambda x: x[1])
                sorted_dist = sorted_dist[:s]
                A = set([t for t, _ in sorted_dist])
                cost = sum([s[1] for s in sorted_dist]) + (2/3) * distances[mapping[start]][mapping[f]]
                elem = {'facility': f, 
                        'A': A, 
                        'count': s, 
                        'cost': cost
                       } # facility, dictionary to see which elements are present, num elements, cost
                res.append(elem)
        return res
    S = buildS()
   # print("Built S")
    uncovered = set(U)
    lst = [(s['cost']/s['count'], hash(s['facility'] + str(s['count'])), s) for s in S]
    result = set([])
    dropoff_mapping = defaultdict(list)
    while uncovered and lst:
        smallest = min(lst, key = lambda x: x[0])
        lst.remove(smallest)
        smallest = smallest[2]
        result.add(smallest['facility'])
        dropoff_mapping[smallest['facility']] = list(smallest['A'])
        uncovered = uncovered.difference(smallest['A'])
        new_lst = []
        for _, h, elem in lst:
            if solve == 1:
                if elem['facility'] in result:
                    elem['cost'] -= distances[mapping[start]][mapping[elem['facility']]]
            if solve == 2:
                if elem['facility'] not in result:
                    elem['cost'] = sum([distances[mapping[s]][mapping[elem['facility']]] for s in elem['A']]) + (1/4) * sum([distances[mapping[r]][mapping[elem['facility']]] for r in result if r != start])
            intersect = len(elem['A'].intersection(uncovered))
            new_cost = float('inf')
            if intersect > 0:
                new_cost = elem['cost']/intersect
            new_lst.append((new_cost, h, elem))
        lst = new_lst
   # print("computed dropoffs")
    #finding path between all
    traversal = [mapping[start]]
    dists = [(distances[traversal[-1]][mapping[r]], mapping[r]) for r in list(result) if r != start]
    dropoffs = [mapping[start]] if start in result else []
   # print("computing traversal")
    def reconstruct_path(source, target, predecessors):
        if source == target:
            return []
        prev = predecessors[source]
        curr = prev[target]
        path = [target, curr]
        while curr != source:
            curr = prev[curr]
            path.append(curr)
        return list(reversed(path))
        
    while dists:
        n = min(dists, key= lambda x: x[0])
        dists.remove(n)
        n = n[1]
        dropoffs.append(n)
        traversal.extend(reconstruct_path(traversal[-1], n, paths)[1:])
        dists = [(distances[traversal[-1]][r], r) for _, r in dists]
    traversal.extend(reconstruct_path(traversal[-1], mapping[start], paths)[1:]) 
   # print("done")
#     dropoffs_dict = {key: dropoff_mapping[key] for key in dropoff_mapping}
    dropoffs_dict = defaultdict(list)
    for h in convert_locations_to_indices(list_of_homes, list_of_locations):
        minValue = float('inf')
        minVertex = mapping[start]
        for i in traversal:
            if distances[h][i] < minValue:
                minValue = distances[h][i]
                minVertex = i
        dropoffs_dict[minVertex].append(h)
    dropoffs_dict = {key: dropoffs_dict[key] for key in dropoffs_dict}
    return traversal, dropoffs_dict
コード例 #20
0
                f'Local search terminated with solution (cost={current_cost}): {current_solution}'
            )
            evaluate(G, current_solution, home_idxs, verbose=True)
            return current_solution, assign_dropoffs(G, current_solution,
                                                     home_idxs)
        i += 1
        epsilon *= epsilon_decay_factor
        end_iter = time.time()
        # print(f'Iteration took {end_iter - start_iter} s')

if __name__ == '__main__':
    # input_path = '../phase1/100.in'
    input_path = '../phase2/test_inputs/branching_20v_5h.in'
    (num_locations, num_houses, location_names, house_names, source,
     adj) = parse_input(input_path)
    G, _ = adjacency_matrix_to_graph(adj)
    # path = dijkstra_greedy_solve(location_names, house_names, source, adj)
    path, best_cost = local_search_solve(location_names, house_names, source,
                                         adj)

    edges_to_draw = []
    for i in range(len(path) - 1):
        u, v = path[i], path[i + 1]
        edges_to_draw.append((u, v))
    print(edges_to_draw)
    plot_graph(input_path,
               layout_style=nx.kamada_kawai_layout,
               show_edge_weights=True,
               edges_to_draw=edges_to_draw,
               directed=True)
コード例 #21
0
def complete_home_graph_generator_from_file(input_file, params=[]):
    input_data = utils.read_file(input_file)
    old_num_of_locations, old_num_houses, old_list_locations, old_list_houses, old_starting_car_location, old_adjacency_matrix = su.data_parser(
        input_data)

    # make a old graph from file
    old_graph, old_adj_message = su.adjacency_matrix_to_graph(old_adjacency_matrix)

    new_num_of_locations = -1
    new_list_locations = []

    new_num_houses = old_num_houses
    new_list_houses = old_list_houses
    new_starting_car_location = old_starting_car_location
    new_adjacency_matrix = None  # Flag
    shortest_paths_between_homes = None

    message = ''
    error = False
    old_starting_point_index = old_list_locations.index(old_starting_car_location)

    # Make complete_home_graph
    is_sp_home = None
    if old_starting_car_location in new_list_houses:
        is_sp_home = True
    if is_sp_home:
        print(" Sp is home, Complete Graph size = num_houses")
        complete_home_graph = nx.complete_graph(new_num_houses)
        new_num_of_locations = old_num_houses
        new_list_locations = old_list_houses
    else:
        # + 1 for the starting point
        print(" Sp is not home, Complete Graph size = num_houses + 1")
        complete_home_graph = nx.complete_graph(new_num_houses + 1)
        new_num_of_locations = old_num_houses + 1
        new_list_locations = old_list_houses.copy()
        new_list_locations.insert(0, old_starting_car_location)

    # For debugging
    # nx.draw(complete_home_graph)
    # plt.show()

    give_nodes_names(is_sp_home, complete_home_graph, new_num_houses, new_list_houses, new_starting_car_location)
    shortest_paths_between_homes = give_edges_weights(complete_home_graph, old_graph, old_list_locations)

    new_adjacency_matrix = nx.to_numpy_array(complete_home_graph)

    # tests
    if not all(name.isalnum() and len(name) <= MAX_NAME_LENGTH for name in new_list_locations):
        message += f'One or more of the names of your locations are either not alphanumeric or are above the max length of {MAX_NAME_LENGTH}.\n'
        error = True

    # check counts
    if len(new_list_locations) != new_num_of_locations:
        message += f'The number of locations you listed ({len(new_list_locations)}) differs from the number you gave on the first line ({new_num_of_locations}).\n'
        error = True

    if len(new_list_houses) != new_num_houses:
        message += f'The number of homes you listed ({len(new_list_houses)}) differs from the number you gave on the first line ({new_num_houses}).\n'
        error = True

    # # no more needed because in the new complete_home_graph, the number of houses = the number of locatinos
    # if num_of_locations < num_houses:
    #     message += f'The number of houses must be less than or equal to the number of locations.\n'
    #     error = True

    # check containment
    if any(house not in new_list_locations for house in new_list_houses):
        message += f'You listed at least one house that is not an actual location. Ahh!\n'
        error = True

    if new_starting_car_location not in new_list_locations:
        message += f'You listed a starting car location that is not an actual location.\n'
        error = True

    # check distinct
    if not len(set(new_list_locations)) == len(new_list_locations):
        message += 'The names of your locations are not distinct.\n'
        error = True

    if not len(set(new_list_houses)) == len(new_list_houses):
        message += 'The names of your houses are not distinct.\n'
        error = True
    # check adjacency matrix
    if not len(new_adjacency_matrix) == len(new_adjacency_matrix[0]) == new_num_of_locations:
        message += f'The dimensions of your adjacency matrix do not match the number of locations you provided.\n'
        error = True

    if not all(
            entry == 'x' or (type(entry) is float and entry > 0 and entry <= 2e9 and su.decimal_digits_check(entry)) for
            row in new_adjacency_matrix for entry in row):
        message += f'Your adjacency matrix may only contain the character "x", or strictly positive integers less than 2e+9, or strictly positive floats with less than 5 decimal digits.\n'
        error = True

    # if not square, terminate
    if len(set(map(len, new_adjacency_matrix))) != 1 or len(new_adjacency_matrix[0]) != len(new_adjacency_matrix):
        message += f'Your adjacency matrix must be square.\n'
        error = True
        return message, error

    new_adjacency_matrix_numpy = np.matrix(new_adjacency_matrix)

    # check requirements on square matrix
    if not np.all(new_adjacency_matrix_numpy.T == new_adjacency_matrix_numpy):
        message += f'Your adjacency matrix is not symmetric.\n'
        error = True

    if not nx.is_connected(complete_home_graph):
        message += 'Your new complete_home_graph is not connected.\n'
        error = True

    if not su.is_metric(complete_home_graph):
        message += 'Your new complete_home_graph is not metric.\n'
        error = True

    if not message:
        message = "If you've received no other error messages, then your complete_home_graph is valid!\n\n\n"

    # print for debugging
    print("\n old_num_of_locations : " + str(old_num_of_locations))
    print(" old_num_houses : " + str(old_num_houses))
    print(" old_list_locations names: " + str(old_list_locations))
    print(" old_list_houses names : " + str(old_list_houses))
    print(" Old Starting Point name(Str) : " + old_starting_car_location)
    print(" Old Starting Point index     : " + str(old_starting_point_index))

    print("\n New Complete Graph Generated")
    print(" new_num_of_locations names: " + str(new_num_of_locations))
    print(" new_num_houses names: " + str(new_num_houses))
    print(" new_list_locations names: " + str(new_list_locations))
    print(" new_list_houses: " + str(new_list_locations))
    new_starting_point_index = 0
    print(" New Starting Point name(Str) : " + old_starting_car_location)
    print(" ** New Starting Point index: " + str(new_starting_point_index))

    # print(" new_adjacency_matrix:")
    # print(new_adjacency_matrix)
    # print(" shortest_paths_between_homes: \n" + str(shortest_paths_between_homes))
    print("\n")
    # for edge in shortest_paths_between_homes:
    #     print(edge, ':', shortest_paths_between_homes[edge])
    # print("\n")
    return message, error, new_num_of_locations, new_num_houses, old_list_locations, new_list_locations, new_list_houses, \
           new_starting_car_location, new_adjacency_matrix, shortest_paths_between_homes, complete_home_graph, old_graph, new_starting_point_index
コード例 #22
0
def naiveSolve(list_of_locations, list_of_homes, starting_car_location, adjacency_matrix, params=[]):
    G = student_utils.adjacency_matrix_to_graph(adjacency_matrix)
    print(G)
    return 0
コード例 #23
0
def local_search_solve(list_of_locations,
                       list_of_homes,
                       starting_car_location,
                       adjacency_matrix,
                       initial_solver=mst_dfs_solve,
                       initial_solution=None,
                       params=[]):

    start = time.time()
    # Generate initial solution (random or greedy algorithm)
    if not initial_solution:
        current_solution, _ = initial_solver(list_of_locations,
                                             list_of_homes,
                                             starting_car_location,
                                             adjacency_matrix,
                                             params=params)
    else:
        current_solution = initial_solution

    G, _ = adjacency_matrix_to_graph(adjacency_matrix)

    home_idxs = [list_of_locations.index(h) for h in list_of_homes]
    all_pairs_dists = nx.floyd_warshall(G, weight='weight')

    def get_neighbors(G, path):
        """
        Returns "1-change" neighbors, which are all paths that:
            Either include a vertex that is not visited in path
            Include a vertex visited in path
            Swap a vertex that is visited with a vertex not visited
        """
        visited = set(path)
        unvisited = set(range(len(G))) - visited

        occurences = collections.Counter(path)

        neighbors = []

        # Exclude a vertex
        for vertex_to_exclude in visited - {0}:
            new_path = path.copy()
            #         print(f'VERTEX TO EXCLUDE: {vertex_to_exclude}')

            for i in range(occurences[vertex_to_exclude]):
                idx = new_path.index(vertex_to_exclude)
                prev, nxt = new_path[idx - 1], new_path[idx + 1]
                if prev == nxt:  # Able to skip over visiting
                    new_path.pop(idx)
                    new_path.pop(idx)
                else:
                    two_shortest = k_shortest_paths(G,
                                                    source=prev,
                                                    target=nxt,
                                                    k=2,
                                                    weight='weight')
                    for alt_path in two_shortest:
                        if alt_path != path[
                                idx - 1:idx +
                                2] and vertex_to_exclude not in alt_path:
                            new_path.pop(idx)
                            new_path = new_path[:idx -
                                                1] + alt_path + new_path[idx +
                                                                         1:]
                            break
                if vertex_to_exclude not in new_path:
                    #                     print(f'REMOVING {vertex_to_exclude}: {new_path}')
                    neighbors.append(new_path)

        # Include a vertex
        for vertex_to_include in unvisited:
            new_path = path.copy()

            one_away = []
            for v in visited:
                if vertex_to_include in G.neighbors(v):
                    one_away.append(v)
            if not one_away:
                continue

    #         print(f'\nVERTEX TO INCLUDE: {vertex_to_include}')
            closest_neighbor = min(
                one_away, key=lambda n: G[vertex_to_include][n]['weight'])
            # Get the index of the closest neighbor, check if a path exists between
            # the vertex being added and the next vertex in the path. If so, a better
            # detour exists than the trivial path to the new vertex and directly back.
            closest_idx = new_path.index(closest_neighbor)
            # Make sure that the closest_idx is not the last node, otherwise this would
            # go out of bounds
            if closest_idx + 1 < len(new_path) and G.has_edge(
                    vertex_to_include, new_path[closest_idx + 1]):
                new_path.insert(closest_idx + 1, vertex_to_include)
            else:
                new_path.insert(closest_idx + 1, closest_neighbor)
                new_path.insert(closest_idx + 1, vertex_to_include)
#             print(f'ADDING {vertex_to_include}: {new_path}')
            neighbors.append(new_path)

        # Handle cycles

        # Swap a vertex (maybe add this)

        return neighbors

    def assign_dropoffs(G, path, home_idxs):
        """
        Returns the dictionary of all dropoffs along this path.
        """
        locations_on_path = set(path)
        dropoffs = collections.defaultdict(list)
        #     print(locations_on_path)
        for h in home_idxs:
            #         print(f'DISTANCES FOR {h}', all_pairs_dists[h])
            closest_loc_on_path = min(locations_on_path,
                                      key=lambda loc: all_pairs_dists[h][loc])
            dropoffs[closest_loc_on_path].append(h)
        return dropoffs

    def evaluate(G, path, home_idxs, verbose=False):
        """
        Assigns optimal dropoff locations for each TA, given a path that the car
        is going to take, and calculate the total energy expended. This is the
        metric that neighbors are going to be evaluated on.
        """
        dropoffs = assign_dropoffs(G, path, home_idxs)
        cost, msg = cost_of_solution(G,
                                     path,
                                     dropoffs,
                                     shortest=all_pairs_dists)
        if verbose:
            print(msg)

        return cost


#     print(get_neighbors(G, current_solution))
#     print(assign_dropoffs(G, current_solution, home_idxs))

    i = 0
    current_cost = evaluate(G, current_solution, home_idxs)

    #     epsilon = 0.1
    epsilon = 0
    epsilon_decay_factor = 0.95
    while True:  # TODO(justinvyu): Add a timeout
        start_iter = time.time()
        neighbors = get_neighbors(G, current_solution.copy())

        # Take a random action with epsilon probability, decaying over time
        if np.random.rand() < epsilon:
            current_solution = neighbors[np.random.randint(len(neighbors))]
            current_cost = evaluate(G, current_solution, home_idxs)
            print(f'=== Iteration #{i}, Epsilon = {epsilon} ==='
                  f'\n Picked a RANDOM neighbor, Cost = {current_cost}')
            epsilon *= epsilon_decay_factor

        # print(f'\nSearching over {len(neighbors)} neighbors...')
        best_neighbor = min(
            neighbors,
            key=(lambda neighbor_sol: evaluate(G, neighbor_sol, home_idxs)))
        best_cost = evaluate(G, best_neighbor, home_idxs, verbose=False)
        if best_cost < current_cost:
            # print(f'=== Iteration #{i}, Epsilon = {epsilon} === \n Improved Cost = {best_cost}')
            current_solution = best_neighbor
            current_cost = best_cost
        else:
            print(f'Local search took: {time.time() - start} seconds')
            print(
                f'Local search terminated with solution (cost={current_cost}): {current_solution}'
            )
            evaluate(G, current_solution, home_idxs, verbose=True)
            return current_solution, assign_dropoffs(G, current_solution,
                                                     home_idxs)
        i += 1
        epsilon *= epsilon_decay_factor
        end_iter = time.time()
コード例 #24
0
ファイル: edges.py プロジェクト: ricksurya/project-fa19
             ['point146', 62, 11, False], ['point147', 63, 0, False],
             ['point148', 63, 7, True], ['point149', 65, 7, True],
             ['point150', 65, 10, False], ['point151', 66, 6, True],
             ['point152', 66, 8, True], ['point153', 66, 10, True],
             ['point154', 67, 4, False], ['point155', 60, 23, True],
             ['point156', 60, 31, False], ['point157', 61, 24, True],
             ['point158', 62, 21, True], ['point159', 62, 25, False],
             ['point160', 64, 31, True], ['point161', 64, 33, False],
             ['point162', 65, 20, True], ['point163', 65, 23, True],
             ['point164', 67, 23, False], ['point165', 68, 25, False],
             ['point166', 69, 30, False], ['point167', 62, 49, False],
             ['point168', 63, 52, False], ['point169', 64, 48, False],
             ['point170', 65, 40, False], ['point171', 65, 44, False],
             ['point172', 65, 48, True], ['point173', 66, 43, False],
             ['point174', 66, 47, False], ['point175', 67, 40, False],
             ['point176', 67, 48, False], ['point177', 69, 40, True],
             ['point178', 69, 43, False], ['point179', 60, 64, True],
             ['point180', 60, 67, True], ['point181', 61, 63, False],
             ['point182', 61, 71, False], ['point183', 62, 62, True],
             ['point184', 63, 70, True], ['point185', 64, 66, True],
             ['point186', 64, 70, False], ['point187', 66, 71, True],
             ['point188', 67, 60, False], ['point189', 67, 65, False],
             ['point190', 67, 66, False]]

matrix = connectNodes(nodeLarge)
graph = student_utils.adjacency_matrix_to_graph(matrix)[0]
# nx.draw(graph)
# plt.show()
print(student_utils.is_metric(graph))
writeToInput(nodeLarge, matrix)