123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812 |
- """
- Flow based connectivity algorithms
- """
- import itertools
- from operator import itemgetter
- import networkx as nx
- # Define the default maximum flow function to use in all flow based
- # connectivity algorithms.
- from networkx.algorithms.flow import (
- boykov_kolmogorov,
- build_residual_network,
- dinitz,
- edmonds_karp,
- shortest_augmenting_path,
- )
- default_flow_func = edmonds_karp
- from .utils import build_auxiliary_edge_connectivity, build_auxiliary_node_connectivity
- __all__ = [
- "average_node_connectivity",
- "local_node_connectivity",
- "node_connectivity",
- "local_edge_connectivity",
- "edge_connectivity",
- "all_pairs_node_connectivity",
- ]
- def local_node_connectivity(
- G, s, t, flow_func=None, auxiliary=None, residual=None, cutoff=None
- ):
- r"""Computes local node connectivity for nodes s and t.
- Local node connectivity for two non adjacent nodes s and t is the
- minimum number of nodes that must be removed (along with their incident
- edges) to disconnect them.
- This is a flow based implementation of node connectivity. We compute the
- maximum flow on an auxiliary digraph build from the original input
- graph (see below for details).
- Parameters
- ----------
- G : NetworkX graph
- Undirected graph
- s : node
- Source node
- t : node
- Target node
- flow_func : function
- A function for computing the maximum flow among a pair of nodes.
- The function has to accept at least three parameters: a Digraph,
- a source node, and a target node. And return a residual network
- that follows NetworkX conventions (see :meth:`maximum_flow` for
- details). If flow_func is None, the default maximum flow function
- (:meth:`edmonds_karp`) is used. See below for details. The choice
- of the default function may change from version to version and
- should not be relied on. Default value: None.
- auxiliary : NetworkX DiGraph
- Auxiliary digraph to compute flow based node connectivity. It has
- to have a graph attribute called mapping with a dictionary mapping
- node names in G and in the auxiliary digraph. If provided
- it will be reused instead of recreated. Default value: None.
- residual : NetworkX DiGraph
- Residual network to compute maximum flow. If provided it will be
- reused instead of recreated. Default value: None.
- cutoff : integer, float, or None (default: None)
- If specified, the maximum flow algorithm will terminate when the
- flow value reaches or exceeds the cutoff. This only works for flows
- that support the cutoff parameter (most do) and is ignored otherwise.
- Returns
- -------
- K : integer
- local node connectivity for nodes s and t
- Examples
- --------
- This function is not imported in the base NetworkX namespace, so you
- have to explicitly import it from the connectivity package:
- >>> from networkx.algorithms.connectivity import local_node_connectivity
- We use in this example the platonic icosahedral graph, which has node
- connectivity 5.
- >>> G = nx.icosahedral_graph()
- >>> local_node_connectivity(G, 0, 6)
- 5
- If you need to compute local connectivity on several pairs of
- nodes in the same graph, it is recommended that you reuse the
- data structures that NetworkX uses in the computation: the
- auxiliary digraph for node connectivity, and the residual
- network for the underlying maximum flow computation.
- Example of how to compute local node connectivity among
- all pairs of nodes of the platonic icosahedral graph reusing
- the data structures.
- >>> import itertools
- >>> # You also have to explicitly import the function for
- >>> # building the auxiliary digraph from the connectivity package
- >>> from networkx.algorithms.connectivity import build_auxiliary_node_connectivity
- ...
- >>> H = build_auxiliary_node_connectivity(G)
- >>> # And the function for building the residual network from the
- >>> # flow package
- >>> from networkx.algorithms.flow import build_residual_network
- >>> # Note that the auxiliary digraph has an edge attribute named capacity
- >>> R = build_residual_network(H, "capacity")
- >>> result = dict.fromkeys(G, dict())
- >>> # Reuse the auxiliary digraph and the residual network by passing them
- >>> # as parameters
- >>> for u, v in itertools.combinations(G, 2):
- ... k = local_node_connectivity(G, u, v, auxiliary=H, residual=R)
- ... result[u][v] = k
- ...
- >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2))
- True
- You can also use alternative flow algorithms for computing node
- connectivity. For instance, in dense networks the algorithm
- :meth:`shortest_augmenting_path` will usually perform better than
- the default :meth:`edmonds_karp` which is faster for sparse
- networks with highly skewed degree distributions. Alternative flow
- functions have to be explicitly imported from the flow package.
- >>> from networkx.algorithms.flow import shortest_augmenting_path
- >>> local_node_connectivity(G, 0, 6, flow_func=shortest_augmenting_path)
- 5
- Notes
- -----
- This is a flow based implementation of node connectivity. We compute the
- maximum flow using, by default, the :meth:`edmonds_karp` algorithm (see:
- :meth:`maximum_flow`) on an auxiliary digraph build from the original
- input graph:
- For an undirected graph G having `n` nodes and `m` edges we derive a
- directed graph H with `2n` nodes and `2m+n` arcs by replacing each
- original node `v` with two nodes `v_A`, `v_B` linked by an (internal)
- arc in H. Then for each edge (`u`, `v`) in G we add two arcs
- (`u_B`, `v_A`) and (`v_B`, `u_A`) in H. Finally we set the attribute
- capacity = 1 for each arc in H [1]_ .
- For a directed graph G having `n` nodes and `m` arcs we derive a
- directed graph H with `2n` nodes and `m+n` arcs by replacing each
- original node `v` with two nodes `v_A`, `v_B` linked by an (internal)
- arc (`v_A`, `v_B`) in H. Then for each arc (`u`, `v`) in G we add one arc
- (`u_B`, `v_A`) in H. Finally we set the attribute capacity = 1 for
- each arc in H.
- This is equal to the local node connectivity because the value of
- a maximum s-t-flow is equal to the capacity of a minimum s-t-cut.
- See also
- --------
- :meth:`local_edge_connectivity`
- :meth:`node_connectivity`
- :meth:`minimum_node_cut`
- :meth:`maximum_flow`
- :meth:`edmonds_karp`
- :meth:`preflow_push`
- :meth:`shortest_augmenting_path`
- References
- ----------
- .. [1] Kammer, Frank and Hanjo Taubig. Graph Connectivity. in Brandes and
- Erlebach, 'Network Analysis: Methodological Foundations', Lecture
- Notes in Computer Science, Volume 3418, Springer-Verlag, 2005.
- http://www.informatik.uni-augsburg.de/thi/personen/kammer/Graph_Connectivity.pdf
- """
- if flow_func is None:
- flow_func = default_flow_func
- if auxiliary is None:
- H = build_auxiliary_node_connectivity(G)
- else:
- H = auxiliary
- mapping = H.graph.get("mapping", None)
- if mapping is None:
- raise nx.NetworkXError("Invalid auxiliary digraph.")
- kwargs = {"flow_func": flow_func, "residual": residual}
- if flow_func is shortest_augmenting_path:
- kwargs["cutoff"] = cutoff
- kwargs["two_phase"] = True
- elif flow_func is edmonds_karp:
- kwargs["cutoff"] = cutoff
- elif flow_func is dinitz:
- kwargs["cutoff"] = cutoff
- elif flow_func is boykov_kolmogorov:
- kwargs["cutoff"] = cutoff
- return nx.maximum_flow_value(H, f"{mapping[s]}B", f"{mapping[t]}A", **kwargs)
- def node_connectivity(G, s=None, t=None, flow_func=None):
- r"""Returns node connectivity for a graph or digraph G.
- Node connectivity is equal to the minimum number of nodes that
- must be removed to disconnect G or render it trivial. If source
- and target nodes are provided, this function returns the local node
- connectivity: the minimum number of nodes that must be removed to break
- all paths from source to target in G.
- Parameters
- ----------
- G : NetworkX graph
- Undirected graph
- s : node
- Source node. Optional. Default value: None.
- t : node
- Target node. Optional. Default value: None.
- flow_func : function
- A function for computing the maximum flow among a pair of nodes.
- The function has to accept at least three parameters: a Digraph,
- a source node, and a target node. And return a residual network
- that follows NetworkX conventions (see :meth:`maximum_flow` for
- details). If flow_func is None, the default maximum flow function
- (:meth:`edmonds_karp`) is used. See below for details. The
- choice of the default function may change from version
- to version and should not be relied on. Default value: None.
- Returns
- -------
- K : integer
- Node connectivity of G, or local node connectivity if source
- and target are provided.
- Examples
- --------
- >>> # Platonic icosahedral graph is 5-node-connected
- >>> G = nx.icosahedral_graph()
- >>> nx.node_connectivity(G)
- 5
- You can use alternative flow algorithms for the underlying maximum
- flow computation. In dense networks the algorithm
- :meth:`shortest_augmenting_path` will usually perform better
- than the default :meth:`edmonds_karp`, which is faster for
- sparse networks with highly skewed degree distributions. Alternative
- flow functions have to be explicitly imported from the flow package.
- >>> from networkx.algorithms.flow import shortest_augmenting_path
- >>> nx.node_connectivity(G, flow_func=shortest_augmenting_path)
- 5
- If you specify a pair of nodes (source and target) as parameters,
- this function returns the value of local node connectivity.
- >>> nx.node_connectivity(G, 3, 7)
- 5
- If you need to perform several local computations among different
- pairs of nodes on the same graph, it is recommended that you reuse
- the data structures used in the maximum flow computations. See
- :meth:`local_node_connectivity` for details.
- Notes
- -----
- This is a flow based implementation of node connectivity. The
- algorithm works by solving $O((n-\delta-1+\delta(\delta-1)/2))$
- maximum flow problems on an auxiliary digraph. Where $\delta$
- is the minimum degree of G. For details about the auxiliary
- digraph and the computation of local node connectivity see
- :meth:`local_node_connectivity`. This implementation is based
- on algorithm 11 in [1]_.
- See also
- --------
- :meth:`local_node_connectivity`
- :meth:`edge_connectivity`
- :meth:`maximum_flow`
- :meth:`edmonds_karp`
- :meth:`preflow_push`
- :meth:`shortest_augmenting_path`
- References
- ----------
- .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms.
- http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
- """
- if (s is not None and t is None) or (s is None and t is not None):
- raise nx.NetworkXError("Both source and target must be specified.")
- # Local node connectivity
- if s is not None and t is not None:
- if s not in G:
- raise nx.NetworkXError(f"node {s} not in graph")
- if t not in G:
- raise nx.NetworkXError(f"node {t} not in graph")
- return local_node_connectivity(G, s, t, flow_func=flow_func)
- # Global node connectivity
- if G.is_directed():
- if not nx.is_weakly_connected(G):
- return 0
- iter_func = itertools.permutations
- # It is necessary to consider both predecessors
- # and successors for directed graphs
- def neighbors(v):
- return itertools.chain.from_iterable([G.predecessors(v), G.successors(v)])
- else:
- if not nx.is_connected(G):
- return 0
- iter_func = itertools.combinations
- neighbors = G.neighbors
- # Reuse the auxiliary digraph and the residual network
- H = build_auxiliary_node_connectivity(G)
- R = build_residual_network(H, "capacity")
- kwargs = {"flow_func": flow_func, "auxiliary": H, "residual": R}
- # Pick a node with minimum degree
- # Node connectivity is bounded by degree.
- v, K = min(G.degree(), key=itemgetter(1))
- # compute local node connectivity with all its non-neighbors nodes
- for w in set(G) - set(neighbors(v)) - {v}:
- kwargs["cutoff"] = K
- K = min(K, local_node_connectivity(G, v, w, **kwargs))
- # Also for non adjacent pairs of neighbors of v
- for x, y in iter_func(neighbors(v), 2):
- if y in G[x]:
- continue
- kwargs["cutoff"] = K
- K = min(K, local_node_connectivity(G, x, y, **kwargs))
- return K
- def average_node_connectivity(G, flow_func=None):
- r"""Returns the average connectivity of a graph G.
- The average connectivity `\bar{\kappa}` of a graph G is the average
- of local node connectivity over all pairs of nodes of G [1]_ .
- .. math::
- \bar{\kappa}(G) = \frac{\sum_{u,v} \kappa_{G}(u,v)}{{n \choose 2}}
- Parameters
- ----------
- G : NetworkX graph
- Undirected graph
- flow_func : function
- A function for computing the maximum flow among a pair of nodes.
- The function has to accept at least three parameters: a Digraph,
- a source node, and a target node. And return a residual network
- that follows NetworkX conventions (see :meth:`maximum_flow` for
- details). If flow_func is None, the default maximum flow function
- (:meth:`edmonds_karp`) is used. See :meth:`local_node_connectivity`
- for details. The choice of the default function may change from
- version to version and should not be relied on. Default value: None.
- Returns
- -------
- K : float
- Average node connectivity
- See also
- --------
- :meth:`local_node_connectivity`
- :meth:`node_connectivity`
- :meth:`edge_connectivity`
- :meth:`maximum_flow`
- :meth:`edmonds_karp`
- :meth:`preflow_push`
- :meth:`shortest_augmenting_path`
- References
- ----------
- .. [1] Beineke, L., O. Oellermann, and R. Pippert (2002). The average
- connectivity of a graph. Discrete mathematics 252(1-3), 31-45.
- http://www.sciencedirect.com/science/article/pii/S0012365X01001807
- """
- if G.is_directed():
- iter_func = itertools.permutations
- else:
- iter_func = itertools.combinations
- # Reuse the auxiliary digraph and the residual network
- H = build_auxiliary_node_connectivity(G)
- R = build_residual_network(H, "capacity")
- kwargs = {"flow_func": flow_func, "auxiliary": H, "residual": R}
- num, den = 0, 0
- for u, v in iter_func(G, 2):
- num += local_node_connectivity(G, u, v, **kwargs)
- den += 1
- if den == 0: # Null Graph
- return 0
- return num / den
- def all_pairs_node_connectivity(G, nbunch=None, flow_func=None):
- """Compute node connectivity between all pairs of nodes of G.
- Parameters
- ----------
- G : NetworkX graph
- Undirected graph
- nbunch: container
- Container of nodes. If provided node connectivity will be computed
- only over pairs of nodes in nbunch.
- flow_func : function
- A function for computing the maximum flow among a pair of nodes.
- The function has to accept at least three parameters: a Digraph,
- a source node, and a target node. And return a residual network
- that follows NetworkX conventions (see :meth:`maximum_flow` for
- details). If flow_func is None, the default maximum flow function
- (:meth:`edmonds_karp`) is used. See below for details. The
- choice of the default function may change from version
- to version and should not be relied on. Default value: None.
- Returns
- -------
- all_pairs : dict
- A dictionary with node connectivity between all pairs of nodes
- in G, or in nbunch if provided.
- See also
- --------
- :meth:`local_node_connectivity`
- :meth:`edge_connectivity`
- :meth:`local_edge_connectivity`
- :meth:`maximum_flow`
- :meth:`edmonds_karp`
- :meth:`preflow_push`
- :meth:`shortest_augmenting_path`
- """
- if nbunch is None:
- nbunch = G
- else:
- nbunch = set(nbunch)
- directed = G.is_directed()
- if directed:
- iter_func = itertools.permutations
- else:
- iter_func = itertools.combinations
- all_pairs = {n: {} for n in nbunch}
- # Reuse auxiliary digraph and residual network
- H = build_auxiliary_node_connectivity(G)
- mapping = H.graph["mapping"]
- R = build_residual_network(H, "capacity")
- kwargs = {"flow_func": flow_func, "auxiliary": H, "residual": R}
- for u, v in iter_func(nbunch, 2):
- K = local_node_connectivity(G, u, v, **kwargs)
- all_pairs[u][v] = K
- if not directed:
- all_pairs[v][u] = K
- return all_pairs
- def local_edge_connectivity(
- G, s, t, flow_func=None, auxiliary=None, residual=None, cutoff=None
- ):
- r"""Returns local edge connectivity for nodes s and t in G.
- Local edge connectivity for two nodes s and t is the minimum number
- of edges that must be removed to disconnect them.
- This is a flow based implementation of edge connectivity. We compute the
- maximum flow on an auxiliary digraph build from the original
- network (see below for details). This is equal to the local edge
- connectivity because the value of a maximum s-t-flow is equal to the
- capacity of a minimum s-t-cut (Ford and Fulkerson theorem) [1]_ .
- Parameters
- ----------
- G : NetworkX graph
- Undirected or directed graph
- s : node
- Source node
- t : node
- Target node
- flow_func : function
- A function for computing the maximum flow among a pair of nodes.
- The function has to accept at least three parameters: a Digraph,
- a source node, and a target node. And return a residual network
- that follows NetworkX conventions (see :meth:`maximum_flow` for
- details). If flow_func is None, the default maximum flow function
- (:meth:`edmonds_karp`) is used. See below for details. The
- choice of the default function may change from version
- to version and should not be relied on. Default value: None.
- auxiliary : NetworkX DiGraph
- Auxiliary digraph for computing flow based edge connectivity. If
- provided it will be reused instead of recreated. Default value: None.
- residual : NetworkX DiGraph
- Residual network to compute maximum flow. If provided it will be
- reused instead of recreated. Default value: None.
- cutoff : integer, float, or None (default: None)
- If specified, the maximum flow algorithm will terminate when the
- flow value reaches or exceeds the cutoff. This only works for flows
- that support the cutoff parameter (most do) and is ignored otherwise.
- Returns
- -------
- K : integer
- local edge connectivity for nodes s and t.
- Examples
- --------
- This function is not imported in the base NetworkX namespace, so you
- have to explicitly import it from the connectivity package:
- >>> from networkx.algorithms.connectivity import local_edge_connectivity
- We use in this example the platonic icosahedral graph, which has edge
- connectivity 5.
- >>> G = nx.icosahedral_graph()
- >>> local_edge_connectivity(G, 0, 6)
- 5
- If you need to compute local connectivity on several pairs of
- nodes in the same graph, it is recommended that you reuse the
- data structures that NetworkX uses in the computation: the
- auxiliary digraph for edge connectivity, and the residual
- network for the underlying maximum flow computation.
- Example of how to compute local edge connectivity among
- all pairs of nodes of the platonic icosahedral graph reusing
- the data structures.
- >>> import itertools
- >>> # You also have to explicitly import the function for
- >>> # building the auxiliary digraph from the connectivity package
- >>> from networkx.algorithms.connectivity import build_auxiliary_edge_connectivity
- >>> H = build_auxiliary_edge_connectivity(G)
- >>> # And the function for building the residual network from the
- >>> # flow package
- >>> from networkx.algorithms.flow import build_residual_network
- >>> # Note that the auxiliary digraph has an edge attribute named capacity
- >>> R = build_residual_network(H, "capacity")
- >>> result = dict.fromkeys(G, dict())
- >>> # Reuse the auxiliary digraph and the residual network by passing them
- >>> # as parameters
- >>> for u, v in itertools.combinations(G, 2):
- ... k = local_edge_connectivity(G, u, v, auxiliary=H, residual=R)
- ... result[u][v] = k
- >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2))
- True
- You can also use alternative flow algorithms for computing edge
- connectivity. For instance, in dense networks the algorithm
- :meth:`shortest_augmenting_path` will usually perform better than
- the default :meth:`edmonds_karp` which is faster for sparse
- networks with highly skewed degree distributions. Alternative flow
- functions have to be explicitly imported from the flow package.
- >>> from networkx.algorithms.flow import shortest_augmenting_path
- >>> local_edge_connectivity(G, 0, 6, flow_func=shortest_augmenting_path)
- 5
- Notes
- -----
- This is a flow based implementation of edge connectivity. We compute the
- maximum flow using, by default, the :meth:`edmonds_karp` algorithm on an
- auxiliary digraph build from the original input graph:
- If the input graph is undirected, we replace each edge (`u`,`v`) with
- two reciprocal arcs (`u`, `v`) and (`v`, `u`) and then we set the attribute
- 'capacity' for each arc to 1. If the input graph is directed we simply
- add the 'capacity' attribute. This is an implementation of algorithm 1
- in [1]_.
- The maximum flow in the auxiliary network is equal to the local edge
- connectivity because the value of a maximum s-t-flow is equal to the
- capacity of a minimum s-t-cut (Ford and Fulkerson theorem).
- See also
- --------
- :meth:`edge_connectivity`
- :meth:`local_node_connectivity`
- :meth:`node_connectivity`
- :meth:`maximum_flow`
- :meth:`edmonds_karp`
- :meth:`preflow_push`
- :meth:`shortest_augmenting_path`
- References
- ----------
- .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms.
- http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
- """
- if flow_func is None:
- flow_func = default_flow_func
- if auxiliary is None:
- H = build_auxiliary_edge_connectivity(G)
- else:
- H = auxiliary
- kwargs = {"flow_func": flow_func, "residual": residual}
- if flow_func is shortest_augmenting_path:
- kwargs["cutoff"] = cutoff
- kwargs["two_phase"] = True
- elif flow_func is edmonds_karp:
- kwargs["cutoff"] = cutoff
- elif flow_func is dinitz:
- kwargs["cutoff"] = cutoff
- elif flow_func is boykov_kolmogorov:
- kwargs["cutoff"] = cutoff
- return nx.maximum_flow_value(H, s, t, **kwargs)
- def edge_connectivity(G, s=None, t=None, flow_func=None, cutoff=None):
- r"""Returns the edge connectivity of the graph or digraph G.
- The edge connectivity is equal to the minimum number of edges that
- must be removed to disconnect G or render it trivial. If source
- and target nodes are provided, this function returns the local edge
- connectivity: the minimum number of edges that must be removed to
- break all paths from source to target in G.
- Parameters
- ----------
- G : NetworkX graph
- Undirected or directed graph
- s : node
- Source node. Optional. Default value: None.
- t : node
- Target node. Optional. Default value: None.
- flow_func : function
- A function for computing the maximum flow among a pair of nodes.
- The function has to accept at least three parameters: a Digraph,
- a source node, and a target node. And return a residual network
- that follows NetworkX conventions (see :meth:`maximum_flow` for
- details). If flow_func is None, the default maximum flow function
- (:meth:`edmonds_karp`) is used. See below for details. The
- choice of the default function may change from version
- to version and should not be relied on. Default value: None.
- cutoff : integer, float, or None (default: None)
- If specified, the maximum flow algorithm will terminate when the
- flow value reaches or exceeds the cutoff. This only works for flows
- that support the cutoff parameter (most do) and is ignored otherwise.
- Returns
- -------
- K : integer
- Edge connectivity for G, or local edge connectivity if source
- and target were provided
- Examples
- --------
- >>> # Platonic icosahedral graph is 5-edge-connected
- >>> G = nx.icosahedral_graph()
- >>> nx.edge_connectivity(G)
- 5
- You can use alternative flow algorithms for the underlying
- maximum flow computation. In dense networks the algorithm
- :meth:`shortest_augmenting_path` will usually perform better
- than the default :meth:`edmonds_karp`, which is faster for
- sparse networks with highly skewed degree distributions.
- Alternative flow functions have to be explicitly imported
- from the flow package.
- >>> from networkx.algorithms.flow import shortest_augmenting_path
- >>> nx.edge_connectivity(G, flow_func=shortest_augmenting_path)
- 5
- If you specify a pair of nodes (source and target) as parameters,
- this function returns the value of local edge connectivity.
- >>> nx.edge_connectivity(G, 3, 7)
- 5
- If you need to perform several local computations among different
- pairs of nodes on the same graph, it is recommended that you reuse
- the data structures used in the maximum flow computations. See
- :meth:`local_edge_connectivity` for details.
- Notes
- -----
- This is a flow based implementation of global edge connectivity.
- For undirected graphs the algorithm works by finding a 'small'
- dominating set of nodes of G (see algorithm 7 in [1]_ ) and
- computing local maximum flow (see :meth:`local_edge_connectivity`)
- between an arbitrary node in the dominating set and the rest of
- nodes in it. This is an implementation of algorithm 6 in [1]_ .
- For directed graphs, the algorithm does n calls to the maximum
- flow function. This is an implementation of algorithm 8 in [1]_ .
- See also
- --------
- :meth:`local_edge_connectivity`
- :meth:`local_node_connectivity`
- :meth:`node_connectivity`
- :meth:`maximum_flow`
- :meth:`edmonds_karp`
- :meth:`preflow_push`
- :meth:`shortest_augmenting_path`
- :meth:`k_edge_components`
- :meth:`k_edge_subgraphs`
- References
- ----------
- .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms.
- http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
- """
- if (s is not None and t is None) or (s is None and t is not None):
- raise nx.NetworkXError("Both source and target must be specified.")
- # Local edge connectivity
- if s is not None and t is not None:
- if s not in G:
- raise nx.NetworkXError(f"node {s} not in graph")
- if t not in G:
- raise nx.NetworkXError(f"node {t} not in graph")
- return local_edge_connectivity(G, s, t, flow_func=flow_func, cutoff=cutoff)
- # Global edge connectivity
- # reuse auxiliary digraph and residual network
- H = build_auxiliary_edge_connectivity(G)
- R = build_residual_network(H, "capacity")
- kwargs = {"flow_func": flow_func, "auxiliary": H, "residual": R}
- if G.is_directed():
- # Algorithm 8 in [1]
- if not nx.is_weakly_connected(G):
- return 0
- # initial value for \lambda is minimum degree
- L = min(d for n, d in G.degree())
- nodes = list(G)
- n = len(nodes)
- if cutoff is not None:
- L = min(cutoff, L)
- for i in range(n):
- kwargs["cutoff"] = L
- try:
- L = min(L, local_edge_connectivity(G, nodes[i], nodes[i + 1], **kwargs))
- except IndexError: # last node!
- L = min(L, local_edge_connectivity(G, nodes[i], nodes[0], **kwargs))
- return L
- else: # undirected
- # Algorithm 6 in [1]
- if not nx.is_connected(G):
- return 0
- # initial value for \lambda is minimum degree
- L = min(d for n, d in G.degree())
- if cutoff is not None:
- L = min(cutoff, L)
- # A dominating set is \lambda-covering
- # We need a dominating set with at least two nodes
- for node in G:
- D = nx.dominating_set(G, start_with=node)
- v = D.pop()
- if D:
- break
- else:
- # in complete graphs the dominating sets will always be of one node
- # thus we return min degree
- return L
- for w in D:
- kwargs["cutoff"] = L
- L = min(L, local_edge_connectivity(G, v, w, **kwargs))
- return L
|