123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- import networkx as nx
- from networkx.utils.decorators import not_implemented_for, py_random_state
- __all__ = ["randomized_partitioning", "one_exchange"]
- @not_implemented_for("directed", "multigraph")
- @py_random_state(1)
- def randomized_partitioning(G, seed=None, p=0.5, weight=None):
- """Compute a random partitioning of the graph nodes and its cut value.
- A partitioning is calculated by observing each node
- and deciding to add it to the partition with probability `p`,
- returning a random cut and its corresponding value (the
- sum of weights of edges connecting different partitions).
- Parameters
- ----------
- G : NetworkX graph
- seed : integer, random_state, or None (default)
- Indicator of random number generation state.
- See :ref:`Randomness<randomness>`.
- p : scalar
- Probability for each node to be part of the first partition.
- Should be in [0,1]
- weight : object
- Edge attribute key to use as weight. If not specified, edges
- have weight one.
- Returns
- -------
- cut_size : scalar
- Value of the minimum cut.
- partition : pair of node sets
- A partitioning of the nodes that defines a minimum cut.
- """
- cut = {node for node in G.nodes() if seed.random() < p}
- cut_size = nx.algorithms.cut_size(G, cut, weight=weight)
- partition = (cut, G.nodes - cut)
- return cut_size, partition
- def _swap_node_partition(cut, node):
- return cut - {node} if node in cut else cut.union({node})
- @not_implemented_for("directed", "multigraph")
- @py_random_state(2)
- def one_exchange(G, initial_cut=None, seed=None, weight=None):
- """Compute a partitioning of the graphs nodes and the corresponding cut value.
- Use a greedy one exchange strategy to find a locally maximal cut
- and its value, it works by finding the best node (one that gives
- the highest gain to the cut value) to add to the current cut
- and repeats this process until no improvement can be made.
- Parameters
- ----------
- G : networkx Graph
- Graph to find a maximum cut for.
- initial_cut : set
- Cut to use as a starting point. If not supplied the algorithm
- starts with an empty cut.
- seed : integer, random_state, or None (default)
- Indicator of random number generation state.
- See :ref:`Randomness<randomness>`.
- weight : object
- Edge attribute key to use as weight. If not specified, edges
- have weight one.
- Returns
- -------
- cut_value : scalar
- Value of the maximum cut.
- partition : pair of node sets
- A partitioning of the nodes that defines a maximum cut.
- """
- if initial_cut is None:
- initial_cut = set()
- cut = set(initial_cut)
- current_cut_size = nx.algorithms.cut_size(G, cut, weight=weight)
- while True:
- nodes = list(G.nodes())
- # Shuffling the nodes ensures random tie-breaks in the following call to max
- seed.shuffle(nodes)
- best_node_to_swap = max(
- nodes,
- key=lambda v: nx.algorithms.cut_size(
- G, _swap_node_partition(cut, v), weight=weight
- ),
- default=None,
- )
- potential_cut = _swap_node_partition(cut, best_node_to_swap)
- potential_cut_size = nx.algorithms.cut_size(G, potential_cut, weight=weight)
- if potential_cut_size > current_cut_size:
- cut = potential_cut
- current_cut_size = potential_cut_size
- else:
- break
- partition = (cut, G.nodes - cut)
- return current_cut_size, partition
|