Spaces:
Sleeping
Sleeping
| import networkx as nx | |
| from networkx.utils.decorators import not_implemented_for, py_random_state | |
| __all__ = ["randomized_partitioning", "one_exchange"] | |
| 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}) | |
| 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 | |