示例#1
0
    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
示例#2
0
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
示例#3
0
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)
示例#5
0
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
示例#6
0
 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}
示例#7
0
 def test_path_length_no_sources(self):
     with pytest.raises(ValueError):
         nx.multi_source_dijkstra_path_length(nx.Graph(), {})
示例#8
0
 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})
示例#9
0
 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
示例#11
0
 def test_path_length_no_sources(self):
     nx.multi_source_dijkstra_path_length(nx.Graph(), {})
示例#12
0
 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))
示例#14
0
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)
示例#15
0
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