def multi_root_forest_arborescence(g, nodes): #Input: 1. An undirected graph 2. Subset of nodes #Output: An undirected graph containing collection of arborescence rooted at the given subset of nodes and the set of # nodes partitioned according to shortest distance to the root nodes (ties handled in the order of rooted node indices supplied) #NOTE: Assumes edge length in both directions is same TODO: Relax this assumption h = nx.DiGraph() h.add_nodes_from(nodes) for i in h.nodes(): h.node[i] = g.node[i] n = len(g.nodes()) lens = [] paths = [] for i in nodes: l, p = nxsh.single_source_dijkstra(g, i, weight='length') lens.append(l) paths.append(p) for k in range(n): min_len = np.inf min_id = n for i in range(len(lens)): if lens[i][k] < min_len: min_len = lens[i][k] min_id = i path = paths[min_id][k] if len(path) > 1: for j in range(len(path) - 1): h.add_edge(path[j], path[j + 1]) h.edge[path[j]][path[j + 1]] = g.edge[path[j]][path[j + 1]] h.edge[path[j + 1]][path[j]] = g.edge[path[j + 1]][path[j]] return h
def find_shortest_path(g, src, target): try: path_sum, sp = single_source_dijkstra(g, src, target, weight='weight') except: raise ValueError("No such path exists, try different nodes") from None print("Found shortest path between {} and {}!".format(src, target)) path = "" for node in sp: path += node + "->" print("Path (displayed in red): {}".format(path[:-2])) print("Path weight: {}".format(path_sum)) return sp
def get_arborescence(g, node): h = nx.DiGraph() h.add_nodes_from(g) for i in g.nodes(): h.node[i] = g.node[i] _, paths = nxsh.single_source_dijkstra(g, node, weight='length') for p in paths: if len(paths[p]) > 1: for i in range(len(paths[p]) - 1): h.add_edge(paths[p][i], paths[p][i + 1]) h.edge[paths[p][i]][paths[p][i + 1]] = g.edge[paths[p][i]][ paths[p][i + 1]] h.add_edge(paths[p][i + 1], paths[p][i]) h.edge[paths[p][i + 1]][paths[p][i]] = g.edge[paths[p][i + 1]][ paths[p][i]] return h
def puzzle_1(field, portals, portal_map, graph): final_graph = nx.Graph() for p1 in portals: for p2 in portals: if p1 != p2: for p1_pos in portal_map[p1]: for p2_pos in portal_map[p2]: # Combine the two portals by using the same name and create a new graph that removes the "portal" and # directly connects all nodes to each other. Just a normal graph now, that we can throw Dijkstra on. if nx.has_path(graph, p1_pos, p2_pos) and not final_graph.has_edge(p1, p2): final_graph.add_edge(p1, p2, weight=nx.shortest_path_length(graph, p1_pos, p2_pos)) step_count, steps = single_source_dijkstra(final_graph, "AA", "ZZ") return step_count + len(steps)-2
def find_reachable(self, source, node_list): """ :param source: starting node hash local env :param node_list: list of nodes from local env that we want to find shortest path to :return: A list of the the same size as node_list containing the shortest path in local env from start or None if doesn't exist """ # get the subgraph # I choose here a random node, but other options will be better and slower passable_subgraph = self.local_environment.get_passable_subgraph( keep_nodes=[source]) shortest_paths = single_source_dijkstra(passable_subgraph, source)[1] shortest_paths = { node: path for node, path in shortest_paths.items() if node in set(node_list) } return shortest_paths
def test_shortestPathCompare6(self): """Runs the shortestPath method from this project's algo, and runs it also through netWorkX, to compare results and performance. runs on graph: G_30000_240000_1.json """ print("reading from file...", self.algo.load_from_json("G_30000_240000_1.json")) graphnx6 = nx.DiGraph() for nodeKey in self.algo.myGraph._nodes.keys(): graphnx6.add_node(nodeKey) for src in self.algo.myGraph._edges.keys(): for dest in self.algo.myGraph._edges.get(src).keys(): graphnx6.add_edge( src, dest, weight=self.algo.myGraph._edges.get(src).get(dest)) self.startTime = time.time() print("shortestPath is ", self.algo.shortest_path(0, 4)) print("Networx: ") print(single_source_dijkstra(graphnx6, 0, 4))
def puzzle_2(field, portals, portal_map, graph): final_graph = nx.Graph() # If using all levels we can at maximum go down half of all portals and half up again...? # Could be wrong, then remove the //2, but seems to work for this problem. for level in range(len(portals)//2): for p1 in portals: for p2 in portals: if p1 != p2: # Only the first level has AA and ZZ. if level > 0 and (p1 in ["AA", "ZZ"] or p2 in ["AA", "ZZ"]): continue for p1_pos in portal_map[p1]: # The name is now unique for portals depending on level and inner/outer status! outer_p1 = is_outer(field, p1_pos) new_name_p1 = p1 + ("o" if outer_p1 else "i") + ("-" * level) for p2_pos in portal_map[p2]: # The name is now unique for portals depending on level and inner/outer status! outer_p2 = is_outer(field, p2_pos) new_name_p2 = p2 + ("o" if outer_p2 else "i") + ("-" * level) if nx.has_path(graph, p1_pos, p2_pos): final_graph.add_edge(new_name_p1, new_name_p2, weight=nx.shortest_path_length(graph, p1_pos, p2_pos)) # Portals going up if outer_p1 and level > 0: final_graph.add_edge(new_name_p1, new_name_p1.replace("o", "i")[:-1], weight=1) # Portals going down if not outer_p1 and p1 not in ["AA", "ZZ"]: final_graph.add_edge(new_name_p1, new_name_p1.replace("i", "o") + "-", weight=1) # Go from the outer ports (though there are no inner) from AA to ZZ. step_count, steps = single_source_dijkstra(final_graph, "AAo", "ZZo") return step_count
def single_flip_contiguous(partition): """ Check if swapping the given node from its old assignment disconnects the old assignment class. :parition: Current :class:`.Partition` object. :flips: Dictionary of proposed flips, with `(nodeid: new_assignment)` pairs. If `flips` is `None`, then fallback to the :func:`.contiguous` check. :returns: True if contiguous, and False otherwise. We assume that `removed_node` belonged to an assignment class that formed a connected subgraph. To see if its removal left the subgraph connected, we check that the neighbors of the removed node are still connected through the changed graph. """ parent = partition.parent flips = partition.flips if not flips or not parent: return contiguous(partition) graph = partition.graph assignment_dict = parent.assignment def proposed_assignment(node): """Return the proposed assignment of the given node.""" if node in flips: return flips[node] return assignment_dict[node] def partition_edge_weight(start_node, end_node, edge_attrs): """ Compute the district edge weight, which is 1 if the nodes have the same assignment, and infinity otherwise. """ if proposed_assignment(start_node) != proposed_assignment(end_node): return float("inf") return 1 for changed_node, _ in flips.items(): old_neighbors = [] old_assignment = assignment_dict[changed_node] for node in graph.neighbors(changed_node): if proposed_assignment(node) == old_assignment: old_neighbors.append(node) if not old_neighbors: # Under our assumptions, if there are no old neighbors, then the # old_assignment district has vanished. It is trivially connected. return True start_neighbor = random.choice(old_neighbors) for neighbor in old_neighbors: try: distance, _ = nx_path.single_source_dijkstra( graph, start_neighbor, neighbor, weight=partition_edge_weight) if not (distance < float("inf")): return False except NetworkXNoPath: return False # All neighbors of all changed nodes are connected, so the new graph is # connected. return True
def _update_path(self): dist, path = single_source_dijkstra( self.G, source=self.current_path[-1], target=self.current_node ) self.current_path += path[1:] return dist
flattened_list.append(y) #clean up the path and add up the weights of the set of nodes res_path = [x[0] for x in groupby(flattened_list)] res_weight = sum(res_weight) print("The shortest route from " + list_of_nodes_to_dest[0] + " to " + list_of_nodes_to_dest[-1] + " is:\n" + str(res_path)) print("The total weight is " + str(res_weight)) # <h2> Validate the result </h2> #use networkx to create an edgelist (for validating the results) G = nx.from_pandas_edgelist(df, 'source', 'target', edge_attr='weight') #run the below function to find the shortest path for a set of nodes(for validating the results) single_source_dijkstra(G, '21', '22') # <h2> Visualization of the graph </h2> #read the node informtion data df_data = pd.read_csv('node_information_file.csv') #convert the latitudes and logitudes in proper format by dividing them by 1000000 #store the latitude and logitude of the source, must-pass and destination nodes in a list location_latlongs = [] for x in list_of_nodes_to_dest: location_latlong = [] location_latlong.append( float(df_data["Longitude"].iloc[int(x) - 1]) / 1000000) location_latlong.append( float(df_data["Latitude"].iloc[int(x) - 1]) / 1000000)