Skip to content

Commit 00a393d

Browse files
atomassiAndrea Tomassilli
authored andcommitted
added multiway cut
1 parent fb5225c commit 00a393d

1 file changed

Lines changed: 60 additions & 5 deletions

File tree

networkx/algorithms/approximation/kcutsets.py

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Functions involving natural generalizations of the minimum cut problem."""
22

3+
import itertools
34
import networkx as nx
45
from networkx.utils import not_implemented_for
56

@@ -55,7 +56,11 @@ def minimum_multiway_cut(G, terminals, weight=None):
5556
Raises
5657
------
5758
NetworkXNotImplemented
58-
If G is directed.
59+
If G is directed or a mutigraph
60+
NetworkXError
61+
If G is empty or
62+
If G is not connected or
63+
If the number of terminals is smaller than 2.
5964
6065
References
6166
----------
@@ -64,7 +69,53 @@ def minimum_multiway_cut(G, terminals, weight=None):
6469
.. [2] Dahlhaus, Elias, et al. *The complexity of multiway cuts*.
6570
Proceedings of the twenty-fourth annual ACM symposium on Theory of computing. 1992
6671
"""
67-
pass
72+
if not G:
73+
raise nx.NetworkXError("Expected non-empty NetworkX graph!")
74+
if not nx.is_connected(G):
75+
raise nx.NetworkXError("Graph not connected.")
76+
# convert to a set
77+
terminals = set(terminals)
78+
# only consider the terminals in G
79+
terminals = terminals & G.nodes()
80+
# raise an error if less than two terminal have been provided
81+
if len(terminals & G.nodes()) < 2:
82+
raise nx.NetworkXError("At least two terminals should be provided.")
83+
84+
# extract edges weight, and set edges weights with no attribute to 1
85+
edges_weights = G.edges(data=weight, default=1)
86+
# create a new Graph G2
87+
G2 = nx.Graph()
88+
G2.add_weighted_edges_from(edges_weights, weight="capacity")
89+
90+
# take a non-existing node of G to be the sink
91+
sink = next(u for u in range(len(G) + 1) if u not in G)
92+
# add edges from the terminals to the sink node
93+
G2.add_edges_from([(u, sink) for u in terminals], capacity=float("inf"))
94+
95+
# compute the minimum weight cut for each terminal to all the others
96+
all_cuts = []
97+
for u in terminals:
98+
# remove the edge to the sink
99+
G2.remove_edge(u, sink)
100+
# get the cut value and the 2 partitions of nodes
101+
value_cut, (p1, p2) = nx.minimum_cut(G2, u, sink)
102+
# get the edges crossing the cut
103+
edges_cut = set(nx.edge_boundary(G2, p1, p2))
104+
# add to the result
105+
all_cuts.append((edges_cut, value_cut))
106+
# re-add the edge to the sink
107+
G2.add_edge(u, sink, capacity=float("inf"))
108+
109+
# discard the heaviest cut and take the union of the rest
110+
cutset = set(
111+
itertools.chain.from_iterable(
112+
el[0] for el in sorted(all_cuts, key=lambda x: x[1])[:-1]
113+
)
114+
)
115+
# compute the cut value
116+
cut_value = sum(G2.edges[u, v]["capacity"] for u, v in cutset)
117+
118+
return cut_value, cutset
68119

69120

70121
@not_implemented_for("directed")
@@ -116,9 +167,11 @@ def minimum_k_cut(G, k, weight=None):
116167
Raises
117168
------
118169
NetworkXNotImplemented
170+
If G is directed or a mutigraph
171+
NetworkXError
172+
If G is empty or
119173
If G is not connected or
120-
If k is smaller than 1 or
121-
If k is greater than the number of nodes of G.
174+
If k is smaller than 1 or greater than the number of nodes of G.
122175
123176
Notes
124177
-----
@@ -136,6 +189,8 @@ def minimum_k_cut(G, k, weight=None):
136189
.. [1] Vazirani, Vijay V. *Approximation algorithms*.
137190
Springer Science & Business Media, 2013.
138191
"""
192+
if not G:
193+
raise nx.NetworkXError("Expected non-empty NetworkX graph!")
139194
if not nx.is_connected(G):
140195
raise nx.NetworkXError("Graph not connected.")
141196
if not 1 <= k <= len(G):
@@ -164,7 +219,7 @@ def minimum_k_cut(G, k, weight=None):
164219
# re-add (u,v) to the tree
165220
T.add_edge(u, v)
166221

167-
# compute the cut_value, each
222+
# compute the cut_value
168223
cut_value = sum(G2.edges[u, v]["capacity"] for u, v in cutset)
169224

170225
return cut_value, cutset

0 commit comments

Comments
 (0)