123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- """Functions for finding and evaluating cuts in a graph.
- """
- from itertools import chain
- import networkx as nx
- __all__ = [
- "boundary_expansion",
- "conductance",
- "cut_size",
- "edge_expansion",
- "mixing_expansion",
- "node_expansion",
- "normalized_cut_size",
- "volume",
- ]
- # TODO STILL NEED TO UPDATE ALL THE DOCUMENTATION!
- @nx._dispatch
- def cut_size(G, S, T=None, weight=None):
- """Returns the size of the cut between two sets of nodes.
- A *cut* is a partition of the nodes of a graph into two sets. The
- *cut size* is the sum of the weights of the edges "between" the two
- sets of nodes.
- Parameters
- ----------
- G : NetworkX graph
- S : collection
- A collection of nodes in `G`.
- T : collection
- A collection of nodes in `G`. If not specified, this is taken to
- be the set complement of `S`.
- weight : object
- Edge attribute key to use as weight. If not specified, edges
- have weight one.
- Returns
- -------
- number
- Total weight of all edges from nodes in set `S` to nodes in
- set `T` (and, in the case of directed graphs, all edges from
- nodes in `T` to nodes in `S`).
- Examples
- --------
- In the graph with two cliques joined by a single edges, the natural
- bipartition of the graph into two blocks, one for each clique,
- yields a cut of weight one::
- >>> G = nx.barbell_graph(3, 0)
- >>> S = {0, 1, 2}
- >>> T = {3, 4, 5}
- >>> nx.cut_size(G, S, T)
- 1
- Each parallel edge in a multigraph is counted when determining the
- cut size::
- >>> G = nx.MultiGraph(["ab", "ab"])
- >>> S = {"a"}
- >>> T = {"b"}
- >>> nx.cut_size(G, S, T)
- 2
- Notes
- -----
- In a multigraph, the cut size is the total weight of edges including
- multiplicity.
- """
- edges = nx.edge_boundary(G, S, T, data=weight, default=1)
- if G.is_directed():
- edges = chain(edges, nx.edge_boundary(G, T, S, data=weight, default=1))
- return sum(weight for u, v, weight in edges)
- @nx._dispatch
- def volume(G, S, weight=None):
- """Returns the volume of a set of nodes.
- The *volume* of a set *S* is the sum of the (out-)degrees of nodes
- in *S* (taking into account parallel edges in multigraphs). [1]
- Parameters
- ----------
- G : NetworkX graph
- S : collection
- A collection of nodes in `G`.
- weight : object
- Edge attribute key to use as weight. If not specified, edges
- have weight one.
- Returns
- -------
- number
- The volume of the set of nodes represented by `S` in the graph
- `G`.
- See also
- --------
- conductance
- cut_size
- edge_expansion
- edge_boundary
- normalized_cut_size
- References
- ----------
- .. [1] David Gleich.
- *Hierarchical Directed Spectral Graph Partitioning*.
- <https://www.cs.purdue.edu/homes/dgleich/publications/Gleich%202005%20-%20hierarchical%20directed%20spectral.pdf>
- """
- degree = G.out_degree if G.is_directed() else G.degree
- return sum(d for v, d in degree(S, weight=weight))
- @nx._dispatch
- def normalized_cut_size(G, S, T=None, weight=None):
- """Returns the normalized size of the cut between two sets of nodes.
- The *normalized cut size* is the cut size times the sum of the
- reciprocal sizes of the volumes of the two sets. [1]
- Parameters
- ----------
- G : NetworkX graph
- S : collection
- A collection of nodes in `G`.
- T : collection
- A collection of nodes in `G`.
- weight : object
- Edge attribute key to use as weight. If not specified, edges
- have weight one.
- Returns
- -------
- number
- The normalized cut size between the two sets `S` and `T`.
- Notes
- -----
- In a multigraph, the cut size is the total weight of edges including
- multiplicity.
- See also
- --------
- conductance
- cut_size
- edge_expansion
- volume
- References
- ----------
- .. [1] David Gleich.
- *Hierarchical Directed Spectral Graph Partitioning*.
- <https://www.cs.purdue.edu/homes/dgleich/publications/Gleich%202005%20-%20hierarchical%20directed%20spectral.pdf>
- """
- if T is None:
- T = set(G) - set(S)
- num_cut_edges = cut_size(G, S, T=T, weight=weight)
- volume_S = volume(G, S, weight=weight)
- volume_T = volume(G, T, weight=weight)
- return num_cut_edges * ((1 / volume_S) + (1 / volume_T))
- @nx._dispatch
- def conductance(G, S, T=None, weight=None):
- """Returns the conductance of two sets of nodes.
- The *conductance* is the quotient of the cut size and the smaller of
- the volumes of the two sets. [1]
- Parameters
- ----------
- G : NetworkX graph
- S : collection
- A collection of nodes in `G`.
- T : collection
- A collection of nodes in `G`.
- weight : object
- Edge attribute key to use as weight. If not specified, edges
- have weight one.
- Returns
- -------
- number
- The conductance between the two sets `S` and `T`.
- See also
- --------
- cut_size
- edge_expansion
- normalized_cut_size
- volume
- References
- ----------
- .. [1] David Gleich.
- *Hierarchical Directed Spectral Graph Partitioning*.
- <https://www.cs.purdue.edu/homes/dgleich/publications/Gleich%202005%20-%20hierarchical%20directed%20spectral.pdf>
- """
- if T is None:
- T = set(G) - set(S)
- num_cut_edges = cut_size(G, S, T, weight=weight)
- volume_S = volume(G, S, weight=weight)
- volume_T = volume(G, T, weight=weight)
- return num_cut_edges / min(volume_S, volume_T)
- @nx._dispatch
- def edge_expansion(G, S, T=None, weight=None):
- """Returns the edge expansion between two node sets.
- The *edge expansion* is the quotient of the cut size and the smaller
- of the cardinalities of the two sets. [1]
- Parameters
- ----------
- G : NetworkX graph
- S : collection
- A collection of nodes in `G`.
- T : collection
- A collection of nodes in `G`.
- weight : object
- Edge attribute key to use as weight. If not specified, edges
- have weight one.
- Returns
- -------
- number
- The edge expansion between the two sets `S` and `T`.
- See also
- --------
- boundary_expansion
- mixing_expansion
- node_expansion
- References
- ----------
- .. [1] Fan Chung.
- *Spectral Graph Theory*.
- (CBMS Regional Conference Series in Mathematics, No. 92),
- American Mathematical Society, 1997, ISBN 0-8218-0315-8
- <http://www.math.ucsd.edu/~fan/research/revised.html>
- """
- if T is None:
- T = set(G) - set(S)
- num_cut_edges = cut_size(G, S, T=T, weight=weight)
- return num_cut_edges / min(len(S), len(T))
- @nx._dispatch
- def mixing_expansion(G, S, T=None, weight=None):
- """Returns the mixing expansion between two node sets.
- The *mixing expansion* is the quotient of the cut size and twice the
- number of edges in the graph. [1]
- Parameters
- ----------
- G : NetworkX graph
- S : collection
- A collection of nodes in `G`.
- T : collection
- A collection of nodes in `G`.
- weight : object
- Edge attribute key to use as weight. If not specified, edges
- have weight one.
- Returns
- -------
- number
- The mixing expansion between the two sets `S` and `T`.
- See also
- --------
- boundary_expansion
- edge_expansion
- node_expansion
- References
- ----------
- .. [1] Vadhan, Salil P.
- "Pseudorandomness."
- *Foundations and Trends
- in Theoretical Computer Science* 7.1–3 (2011): 1–336.
- <https://doi.org/10.1561/0400000010>
- """
- num_cut_edges = cut_size(G, S, T=T, weight=weight)
- num_total_edges = G.number_of_edges()
- return num_cut_edges / (2 * num_total_edges)
- # TODO What is the generalization to two arguments, S and T? Does the
- # denominator become `min(len(S), len(T))`?
- @nx._dispatch
- def node_expansion(G, S):
- """Returns the node expansion of the set `S`.
- The *node expansion* is the quotient of the size of the node
- boundary of *S* and the cardinality of *S*. [1]
- Parameters
- ----------
- G : NetworkX graph
- S : collection
- A collection of nodes in `G`.
- Returns
- -------
- number
- The node expansion of the set `S`.
- See also
- --------
- boundary_expansion
- edge_expansion
- mixing_expansion
- References
- ----------
- .. [1] Vadhan, Salil P.
- "Pseudorandomness."
- *Foundations and Trends
- in Theoretical Computer Science* 7.1–3 (2011): 1–336.
- <https://doi.org/10.1561/0400000010>
- """
- neighborhood = set(chain.from_iterable(G.neighbors(v) for v in S))
- return len(neighborhood) / len(S)
- # TODO What is the generalization to two arguments, S and T? Does the
- # denominator become `min(len(S), len(T))`?
- @nx._dispatch
- def boundary_expansion(G, S):
- """Returns the boundary expansion of the set `S`.
- The *boundary expansion* is the quotient of the size
- of the node boundary and the cardinality of *S*. [1]
- Parameters
- ----------
- G : NetworkX graph
- S : collection
- A collection of nodes in `G`.
- Returns
- -------
- number
- The boundary expansion of the set `S`.
- See also
- --------
- edge_expansion
- mixing_expansion
- node_expansion
- References
- ----------
- .. [1] Vadhan, Salil P.
- "Pseudorandomness."
- *Foundations and Trends in Theoretical Computer Science*
- 7.1–3 (2011): 1–336.
- <https://doi.org/10.1561/0400000010>
- """
- return len(nx.node_boundary(G, S)) / len(S)
|