from networkx.exception import NetworkXError from networkx.utils import not_implemented_for from networkx.algorithms.approximation import local_node_connectivity from networkx.algorithms.connectivity import \ local_node_connectivity as exact_local_node_connectivity from networkx.algorithms.connectivity import build_auxiliary_node_connectivity from networkx.algorithms.flow import build_residual_network __author__ = """\n""".join(['Jordi Torrents <*****@*****.**>']) __all__ = ['k_components'] not_implemented_for('directed') def k_components(G, min_density=0.95): r"""Returns the approximate k-component structure of a graph G. A `k`-component is a maximal subgraph of a graph G that has, at least, node connectivity `k`: we need to remove at least `k` nodes to break it into more components. `k`-components have an inherent hierarchical structure because they are nested in terms of connectivity: a connected graph can contain several 2-components, each of which can contain one or more 3-components, and so forth. This implementation is based on the fast heuristics to approximate the `k`-component sturcture of a graph [1]_. Which, in turn, it is based on a fast approximation algorithm for finding good lower bounds of the number of node independent paths between two nodes [2]_.
import networkx as nx from networkx.exception import NetworkXError from networkx.utils import not_implemented_for from networkx.algorithms.approximation import local_node_connectivity from networkx.algorithms.connectivity import \ local_node_connectivity as exact_local_node_connectivity __author__ = """\n""".join(['Jordi Torrents <*****@*****.**>']) __all__ = ['k_components'] not_implemented_for('directed') def k_components(G, min_density=0.95): r"""Returns the approximate k-component structure of a graph G. A `k`-component is a maximal subgraph of a graph G that has, at least, node connectivity `k`: we need to remove at least `k` nodes to break it into more components. `k`-components have an inherent hierarchical structure because they are nested in terms of connectivity: a connected graph can contain several 2-components, each of which can contain one or more 3-components, and so forth. This implementation is based on the fast heuristics to approximate the `k`-component structure of a graph [1]_. Which, in turn, it is based on a fast approximation algorithm for finding good lower bounds of the number
def construct(EdgeComponentAuxGraph, G): """Builds an auxiliary graph encoding edge-connectivity between nodes. Notes ----- Given G=(V, E), initialize an empty auxiliary graph A. Choose an arbitrary source node s. Initialize a set N of available nodes (that can be used as the sink). The algorithm picks an arbitrary node t from N - {s}, and then computes the minimum st-cut (S, T) with value w. If G is directed the the minimum of the st-cut or the ts-cut is used instead. Then, the edge (s, t) is added to the auxiliary graph with weight w. The algorithm is called recursively first using S as the available nodes and s as the source, and then using T and t. Recursion stops when the source is the only available node. Parameters ---------- G : NetworkX graph """ # workaround for classmethod decorator not_implemented_for('multigraph')(lambda G: G)(G) def _recursive_build(H, A, source, avail): # Terminate once the flow has been compute to every node. if {source} == avail: return # pick an arbitrary node as the sink sink = arbitrary_element(avail - {source}) # find the minimum cut and its weight value, (S, T) = nx.minimum_cut(H, source, sink) if H.is_directed(): # check if the reverse direction has a smaller cut value_, (T_, S_) = nx.minimum_cut(H, sink, source) if value_ < value: value, S, T = value_, S_, T_ # add edge with weight of cut to the aux graph A.add_edge(source, sink, weight=value) # recursively call until all but one node is used _recursive_build(H, A, source, avail.intersection(S)) _recursive_build(H, A, sink, avail.intersection(T)) # Copy input to ensure all edges have unit capacity H = G.__class__() H.add_nodes_from(G.nodes()) H.add_edges_from(G.edges(), capacity=1) # A is the auxiliary graph to be constructed # It is a weighted undirected tree A = nx.Graph() # Pick an arbitrary node as the source if H.number_of_nodes() > 0: source = arbitrary_element(H.nodes()) # Initialize a set of elements that can be chosen as the sink avail = set(H.nodes()) # This constructs A _recursive_build(H, A, source, avail) # This class is a container the holds the auxiliary graph A and # provides access the the k_edge_components function. self = EdgeComponentAuxGraph() self.A = A self.H = H return self
import networkx as nx from networkx.exception import NetworkXError from networkx.utils import not_implemented_for from networkx.algorithms.approximation import local_node_connectivity from networkx.algorithms.connectivity import local_node_connectivity as exact_local_node_connectivity from networkx.algorithms.connectivity import build_auxiliary_node_connectivity from networkx.algorithms.flow import build_residual_network __author__ = """\n""".join(["Jordi Torrents <*****@*****.**>"]) __all__ = ["k_components"] not_implemented_for("directed") def k_components(G, min_density=0.95): r"""Returns the approximate k-component structure of a graph G. A `k`-component is a maximal subgraph of a graph G that has, at least, node connectivity `k`: we need to remove at least `k` nodes to break it into more components. `k`-components have an inherent hierarchical structure because they are nested in terms of connectivity: a connected graph can contain several 2-components, each of which can contain one or more 3-components, and so forth. This implementation is based on the fast heuristics to approximate the `k`-component sturcture of a graph [1]_. Which, in turn, it is based on a fast approximation algorithm for finding good lower bounds of the number
""" Fast approximation for k-component structure """ import itertools from collections import defaultdict from collections.abc import Mapping import networkx as nx from networkx.exception import NetworkXError from networkx.utils import not_implemented_for from networkx.algorithms.approximation import local_node_connectivity __all__ = ["k_components"] not_implemented_for("directed") def k_components(G, min_density=0.95): r"""Returns the approximate k-component structure of a graph G. A `k`-component is a maximal subgraph of a graph G that has, at least, node connectivity `k`: we need to remove at least `k` nodes to break it into more components. `k`-components have an inherent hierarchical structure because they are nested in terms of connectivity: a connected graph can contain several 2-components, each of which can contain one or more 3-components, and so forth. This implementation is based on the fast heuristics to approximate the `k`-component structure of a graph [1]_. Which, in turn, it is based on a fast approximation algorithm for finding good lower bounds of the number of node independent paths between two nodes [2]_.
w = sum(d.get(weight, 1) for d in G[u][v].values()) else: w = G[u][v].get(weight, 1) except KeyError: w = 0 gain.append((delta[u] + delta[v] - 2 * w, u, v)) if len(gain) == 0: break maxg, u, v = max(gain, key=itemgetter(0)) swapped |= {u, v} gains.append((maxg, u, v)) delta = _update_delta(delta, G, A - swapped, B - swapped, u, v, weight) return gains [docs]@not_implemented_for('directed') def kernighan_lin_bisection(G, partition=None, max_iter=10, weight='weight'): """Partition a graph into two blocks using the Kernighan–Lin algorithm. This algorithm paritions a network into two sets by iteratively swapping pairs of nodes to reduce the edge cut between the two sets. Parameters ---------- G : graph partition : tuple Pair of iterables containing an intial partition. If not specified, a random balanced partition is used.