def run(self, terminals, epsilon=3.0, effort=100): # type: (Optional[int]) -> Dict """Run the fair resource allocation algorithm. For each resource, in round robin fashion, allocate 1/effort of the capacity of an approximate Steiner tree. Finally in the randomization step choose one of the candidate trees.""" self.epsilon = float(epsilon) self.terminals = { k: frozenset(self.nodetoi[n] for n in v) for k, v in terminals.items() } self.term_clusters = dict() for node, tset in terminals.items(): clusters = [] for conncomp in nx.connected_components( self.orig_graph.subgraph(tset)): clusters.append(frozenset(self.nodetoi[n] for n in conncomp)) self.term_clusters[node] = clusters self._initialize_weights() candidatetrees = defaultdict(Counter) convex_result = dict() steiner_tree = self._steiner_func # self._astar_heuristic = dict(nx.all_pairs_dijkstra_path_length(self.wgraph)) if not self.terminals: return {} term_clusters = self.term_clusters #prepare_heuristic if self._heuristic: heur_dist = dict() for k, clusters in term_clusters.items(): for cluster in clusters: distances = nx.multi_source_dijkstra_path_length( self.weights_graph, cluster) heur_dist[cluster] = distances else: heur_dist = None for _ in range(effort): for node, terminals in self.terminals.items(): newtree = steiner_tree(self.weights_graph, term_clusters[node], heuristic=heur_dist) candidatetrees[node][newtree] += 1 self._increase_weights(newtree) # get convex sum of candidate trees for node in self.terminals.keys(): convex_result[node] = [ (t, float(q) / effort) for t, q in candidatetrees[node].most_common() ] self.randomize(convex_result, effort) return self.result
def generate_rate_card(rate_card_csv_path, graph) -> tuple: """ Convert rate card csv into hash table that gives the costs of different infrastructure types. For variable cost structures, returns a min_weights dict that gives the minimum distances between certain infrastructure types to all other nodes :param rate_card_csv_path: path to rate card csv file :type rate_card_csv_path: str, Path :param graph: full graph of nodes and edges :type graph: networkx.Graph :return: rate_card, min_weights :rtype: tuple """ # initialise rate_card and min_weights hash tables rate_card = {} min_weights = {} # open rate card with open(rate_card_csv_path) as csvfile: rate_card_csv = csv.reader(csvfile, delimiter=',') # skip header of file next(rate_card_csv, None) # iterate through rate card items for item, cost in rate_card_csv: # strip whitespace from cost cost = cost.strip() # check if cost is based on multiplier if 'x' in cost: # find the source to find the min distance from _, source = cost.split('x') # use djikstras algorithm to find minimum weights between nodes of type source and all other nodes # save in hash table for fast look up and so we don't have to calculate again source = source.lower() if source not in min_weights.keys(): min_weights[source] = multi_source_dijkstra_path_length( graph, get_nodes(graph, source), weight='length') # raise error if cost is not a number elif not cost.isnumeric(): raise NotImplementedError( f"Rate card gave a cost in an unknown format. Must be a number or a string " f"in the form<number>x<node_type>. Given cost was: {cost}") # find the name of item (the text inside the parentheses if an edge, otherwise just the item) name = re.findall( r'\((.*?)\)', item)[0].lower() if "/m" in item else item.lower() # add item to rate card rate_card[name] = cost return rate_card, min_weights
def filter_out_unreachable(graph: nx.DiGraph, nodes, roots): """Filters (separates) reachable nodes from unreachable nodes Returns a tuple of sets, one for the reachable nodes, one for the unreachable ones A node is reachable if there exists a path from any (*not* all) root. :arg graph: the graph to operate on :arg nodes: the nodes of interest to filter :arg roots: the root nodes """ shortest_paths = nx.multi_source_dijkstra_path_length(graph, roots) reachable = [] unreachable = [] for node in nodes: if node not in shortest_paths: unreachable.append(node) else: reachable.append(node) return reachable, unreachable
def boundary_dists(metric): """ Input: metric; a NetworkX.Graph object, consisting of vertices, edges and weights. Output: a dictionary mapping vertices of the graph to distances calculated using a multi-source Dijkstra algorithm from all of the metric boundary vertices to the vertex in question. Note: The boundary vertices in the metric do not correspond to the boundary vertices on the final graph. To produce boundary vertices for the metric, we clone vertices that have weight-one syndromes caused by first-order (probability p) errors in the model. These vertices are never placed in the syndrome graph on which an MWPM is calculated. Rather, a vertex is created for every syndrome change, and connected to a new vertex by an edge with weight given by this function's output. """ b_nodes = [v for v in metric.nodes() if 'B' in v] dist_iter = nx.multi_source_dijkstra_path_length(metric, b_nodes) return list(dist_iter)
def ctv_expansion(G, label_map: LabelMap, cutoff: int): """Runs the CTV expansion algorithm to grow the CTV. Parameters: G (nx.Graph): The graph representation of the label map to expand. label_map: The label map to expand. cutoff: Maximum distance that will be checked for CTV expansion. """ gtv_nodes = label_map.get_voxels_for_structure('gtv') all_length = nx.multi_source_dijkstra_path_length(G, gtv_nodes, cutoff=cutoff) ctv_indices = list(all_length.keys()) ctv_indices = set(ctv_indices).difference(set(gtv_nodes)) label_map_with_ctv = copy.deepcopy(label_map) label_map_with_ctv.names[999] = 'CTV' for index in ctv_indices: label_map_with_ctv.array[index] = all_length[index] return label_map_with_ctv
def test_simple_paths(self): G = nx.path_graph(4) lengths = nx.multi_source_dijkstra_path_length(G, [0]) assert lengths == {n: n for n in G} paths = nx.multi_source_dijkstra_path(G, [0]) assert paths == {n: list(range(n + 1)) for n in G}
def test_path_length_no_sources(self): with pytest.raises(ValueError): nx.multi_source_dijkstra_path_length(nx.Graph(), {})
def test_simple_paths(self): G = nx.path_graph(4) lengths = nx.multi_source_dijkstra_path_length(G, [0]) assert_equal(lengths, {n: n for n in G}) paths = nx.multi_source_dijkstra_path(G, [0]) assert_equal(paths, {n: list(range(n + 1)) for n in G})
def test_path_length_no_sources(self): nx.multi_source_dijkstra_path_length(nx.Graph(), {})
def group_closeness_centrality(G, S, weight=None): r"""Compute the group closeness centrality for a group of nodes. Group closeness centrality of a group of nodes $S$ is a measure of how close the group is to the other nodes in the graph. .. math:: c_{close}(S) = \frac{|V-S|}{\sum_{v \in V-S} d_{S, v}} d_{S, v} = min_{u \in S} (d_{u, v}) where $V$ is the set of nodes, $d_{S, v}$ is the distance of the group $S$ from $v$ defined as above. ($V-S$ is the set of nodes in $V$ that are not in $S$). Parameters ---------- G : graph A NetworkX graph. S : list or set S is a group of nodes which belong to G, for which group closeness centrality is to be calculated. weight : None or string, optional (default=None) If None, all edge weights are considered equal. Otherwise holds the name of the edge attribute used as weight. Raises ------ NodeNotFound If node(s) in S are not present in G. Returns ------- closeness : float Group closeness centrality of the group S. See Also -------- closeness_centrality Notes ----- The measure was introduced in [1]_. The formula implemented here is described in [2]_. Higher values of closeness indicate greater centrality. It is assumed that 1 / 0 is 0 (required in the case of directed graphs, or when a shortest path length is 0). The number of nodes in the group must be a maximum of n - 1 where `n` is the total number of nodes in the graph. For directed graphs, the incoming distance is utilized here. To use the outward distance, act on `G.reverse()`. For weighted graphs the edge weights must be greater than zero. Zero edge weights can produce an infinite number of equal length paths between pairs of nodes. References ---------- .. [1] M G Everett and S P Borgatti: The Centrality of Groups and Classes. Journal of Mathematical Sociology. 23(3): 181-201. 1999. http://www.analytictech.com/borgatti/group_centrality.htm .. [2] J. Zhao et. al.: Measuring and Maximizing Group Closeness Centrality over Disk Resident Graphs. WWWConference Proceedings, 2014. 689-694. http://wwwconference.org/proceedings/www2014/companion/p689.pdf """ if G.is_directed(): G = G.reverse() # reverse view closeness = 0 # initialize to 0 V = set(G) # set of nodes in G S = set(S) # set of nodes in group S V_S = V - S # set of nodes in V but not S shortest_path_lengths = nx.multi_source_dijkstra_path_length(G, S, weight=weight) # accumulation for v in V_S: try: closeness += shortest_path_lengths[v] except KeyError: # no path exists closeness += 0 try: closeness = len(V_S) / closeness except ZeroDivisionError: # 1 / 0 assumed as 0 closeness = 0 return closeness
def test_path_length_no_sources(self): nx.multi_source_dijkstra_path_length(nx.Graph(), {})
def _remove_unreachable_actions(graph, roots): # Remove all nodes that are not reachable from one of the roots shortest_paths = nx.multi_source_dijkstra_path_length(graph, roots) for node in list(graph.nodes): if node not in shortest_paths: graph.remove_node(node)
def test_simple_paths(self): G = nx.path_graph(4) lengths = nx.multi_source_dijkstra_path_length(G, [0]) assert_equal(lengths, dict((n, n) for n in G)) paths = nx.multi_source_dijkstra_path(G, [0]) assert_equal(paths, dict((n, list(range(n + 1))) for n in G))
def make_lm_embeddings(graph_id, NOISE_FEATS, N_LANDMARKS=32, LM_NOISE=0.2, OPTIMIZATION_TRIES=64): symmetric = True if 'ASYM' in graph_id: symmetric = False G = nx.read_edgelist('{}{}.edgelist'.format( graph_id, 'connected' if symmetric else ''), nodetype=int, data=(('weight', float), ), create_using=nx.DiGraph()) if symmetric: G = G.to_undirected() else: Grev = G.reverse() nodes = np.array(G.nodes()) def keywithmaxval(d): """ a) create a list of the dict's keys and values; b) return the key with the max value""" v = list(d.values()) k = list(d.keys()) return k[v.index(max(v))] # Collect landmarks landmarks = deque(np.random.choice(nodes, (1, ), replace=False), N_LANDMARKS) for i in tqdm.tqdm(range(OPTIMIZATION_TRIES)): dists = nx.multi_source_dijkstra_path_length(G, landmarks) landmarks.append(keywithmaxval(dists)) landmark_dists = [ nx.single_source_dijkstra_path_length(G, l) for l in landmarks ] if not symmetric: landmark_dists += [ nx.single_source_dijkstra_path_length(Grev, l) for l in landmarks ] N_LANDMARKS = 2 * N_LANDMARKS # Get landmark stats for normalization lm_dists = [list(landmark_dists[i].values()) for i in range(N_LANDMARKS)] lm_dists = np.array(lm_dists) lm_mean = np.mean(lm_dists) lm_std = np.std(lm_dists) # Collect embeddings based on landmarks, normalizing each embs = {} for i in nodes: if LM_NOISE: lm_noise = np.random.normal(scale=LM_NOISE, size=[N_LANDMARKS]) else: lm_noise = 0. lm_feats = (np.array( [landmark_dists[lm][i] for lm in range(N_LANDMARKS)]) - lm_mean) / lm_std + lm_noise noise_feats = np.random.normal(size=[NOISE_FEATS]) embs[i] = np.concatenate([lm_feats, noise_feats]) if not symmetric: N_LANDMARKS = N_LANDMARKS // 2 # Save embs to disk with open( '{}_lm_{}n{}-{}_emb_dict.pickle'.format(graph_id, N_LANDMARKS, LM_NOISE, NOISE_FEATS), 'wb') as f: pickle.dump(embs, f)
def most_distant_node(G, sources): dists = nx.multi_source_dijkstra_path_length(G, sources) n, d = max(dists.items(), key=lambda item: item[1]) return n if d > 0 else None