cuts.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. """
  2. Flow based cut algorithms
  3. """
  4. import itertools
  5. import networkx as nx
  6. # Define the default maximum flow function to use in all flow based
  7. # cut algorithms.
  8. from networkx.algorithms.flow import build_residual_network, edmonds_karp
  9. from .utils import build_auxiliary_edge_connectivity, build_auxiliary_node_connectivity
  10. default_flow_func = edmonds_karp
  11. __all__ = [
  12. "minimum_st_node_cut",
  13. "minimum_node_cut",
  14. "minimum_st_edge_cut",
  15. "minimum_edge_cut",
  16. ]
  17. @nx._dispatchable(
  18. graphs={"G": 0, "auxiliary?": 4},
  19. preserve_edge_attrs={"auxiliary": {"capacity": float("inf")}},
  20. preserve_graph_attrs={"auxiliary"},
  21. )
  22. def minimum_st_edge_cut(G, s, t, flow_func=None, auxiliary=None, residual=None):
  23. """Returns the edges of the cut-set of a minimum (s, t)-cut.
  24. This function returns the set of edges of minimum cardinality that,
  25. if removed, would destroy all paths among source and target in G.
  26. Edge weights are not considered. See :meth:`minimum_cut` for
  27. computing minimum cuts considering edge weights.
  28. Parameters
  29. ----------
  30. G : NetworkX graph
  31. s : node
  32. Source node for the flow.
  33. t : node
  34. Sink node for the flow.
  35. auxiliary : NetworkX DiGraph
  36. Auxiliary digraph to compute flow based node connectivity. It has
  37. to have a graph attribute called mapping with a dictionary mapping
  38. node names in G and in the auxiliary digraph. If provided
  39. it will be reused instead of recreated. Default value: None.
  40. flow_func : function
  41. A function for computing the maximum flow among a pair of nodes.
  42. The function has to accept at least three parameters: a Digraph,
  43. a source node, and a target node. And return a residual network
  44. that follows NetworkX conventions (see :meth:`maximum_flow` for
  45. details). If flow_func is None, the default maximum flow function
  46. (:meth:`edmonds_karp`) is used. See :meth:`node_connectivity` for
  47. details. The choice of the default function may change from version
  48. to version and should not be relied on. Default value: None.
  49. residual : NetworkX DiGraph
  50. Residual network to compute maximum flow. If provided it will be
  51. reused instead of recreated. Default value: None.
  52. Returns
  53. -------
  54. cutset : set
  55. Set of edges that, if removed from the graph, will disconnect it.
  56. See also
  57. --------
  58. :meth:`minimum_cut`
  59. :meth:`minimum_node_cut`
  60. :meth:`minimum_edge_cut`
  61. :meth:`stoer_wagner`
  62. :meth:`node_connectivity`
  63. :meth:`edge_connectivity`
  64. :meth:`maximum_flow`
  65. :meth:`edmonds_karp`
  66. :meth:`preflow_push`
  67. :meth:`shortest_augmenting_path`
  68. Examples
  69. --------
  70. This function is not imported in the base NetworkX namespace, so you
  71. have to explicitly import it from the connectivity package:
  72. >>> from networkx.algorithms.connectivity import minimum_st_edge_cut
  73. We use in this example the platonic icosahedral graph, which has edge
  74. connectivity 5.
  75. >>> G = nx.icosahedral_graph()
  76. >>> len(minimum_st_edge_cut(G, 0, 6))
  77. 5
  78. If you need to compute local edge cuts on several pairs of
  79. nodes in the same graph, it is recommended that you reuse the
  80. data structures that NetworkX uses in the computation: the
  81. auxiliary digraph for edge connectivity, and the residual
  82. network for the underlying maximum flow computation.
  83. Example of how to compute local edge cuts among all pairs of
  84. nodes of the platonic icosahedral graph reusing the data
  85. structures.
  86. >>> import itertools
  87. >>> # You also have to explicitly import the function for
  88. >>> # building the auxiliary digraph from the connectivity package
  89. >>> from networkx.algorithms.connectivity import build_auxiliary_edge_connectivity
  90. >>> H = build_auxiliary_edge_connectivity(G)
  91. >>> # And the function for building the residual network from the
  92. >>> # flow package
  93. >>> from networkx.algorithms.flow import build_residual_network
  94. >>> # Note that the auxiliary digraph has an edge attribute named capacity
  95. >>> R = build_residual_network(H, "capacity")
  96. >>> result = dict.fromkeys(G, dict())
  97. >>> # Reuse the auxiliary digraph and the residual network by passing them
  98. >>> # as parameters
  99. >>> for u, v in itertools.combinations(G, 2):
  100. ... k = len(minimum_st_edge_cut(G, u, v, auxiliary=H, residual=R))
  101. ... result[u][v] = k
  102. >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2))
  103. True
  104. You can also use alternative flow algorithms for computing edge
  105. cuts. For instance, in dense networks the algorithm
  106. :meth:`shortest_augmenting_path` will usually perform better than
  107. the default :meth:`edmonds_karp` which is faster for sparse
  108. networks with highly skewed degree distributions. Alternative flow
  109. functions have to be explicitly imported from the flow package.
  110. >>> from networkx.algorithms.flow import shortest_augmenting_path
  111. >>> len(minimum_st_edge_cut(G, 0, 6, flow_func=shortest_augmenting_path))
  112. 5
  113. """
  114. if flow_func is None:
  115. flow_func = default_flow_func
  116. if auxiliary is None:
  117. H = build_auxiliary_edge_connectivity(G)
  118. else:
  119. H = auxiliary
  120. kwargs = {"capacity": "capacity", "flow_func": flow_func, "residual": residual}
  121. cut_value, partition = nx.minimum_cut(H, s, t, **kwargs)
  122. reachable, non_reachable = partition
  123. # Any edge in the original graph linking the two sets in the
  124. # partition is part of the edge cutset
  125. cutset = set()
  126. for u, nbrs in ((n, G[n]) for n in reachable):
  127. cutset.update((u, v) for v in nbrs if v in non_reachable)
  128. return cutset
  129. @nx._dispatchable(
  130. graphs={"G": 0, "auxiliary?": 4},
  131. preserve_node_attrs={"auxiliary": {"id": None}},
  132. preserve_graph_attrs={"auxiliary"},
  133. )
  134. def minimum_st_node_cut(G, s, t, flow_func=None, auxiliary=None, residual=None):
  135. r"""Returns a set of nodes of minimum cardinality that disconnect source
  136. from target in G.
  137. This function returns the set of nodes of minimum cardinality that,
  138. if removed, would destroy all paths among source and target in G.
  139. Parameters
  140. ----------
  141. G : NetworkX graph
  142. s : node
  143. Source node.
  144. t : node
  145. Target node.
  146. flow_func : function
  147. A function for computing the maximum flow among a pair of nodes.
  148. The function has to accept at least three parameters: a Digraph,
  149. a source node, and a target node. And return a residual network
  150. that follows NetworkX conventions (see :meth:`maximum_flow` for
  151. details). If flow_func is None, the default maximum flow function
  152. (:meth:`edmonds_karp`) is used. See below for details. The choice
  153. of the default function may change from version to version and
  154. should not be relied on. Default value: None.
  155. auxiliary : NetworkX DiGraph
  156. Auxiliary digraph to compute flow based node connectivity. It has
  157. to have a graph attribute called mapping with a dictionary mapping
  158. node names in G and in the auxiliary digraph. If provided
  159. it will be reused instead of recreated. Default value: None.
  160. residual : NetworkX DiGraph
  161. Residual network to compute maximum flow. If provided it will be
  162. reused instead of recreated. Default value: None.
  163. Returns
  164. -------
  165. cutset : set
  166. Set of nodes that, if removed, would destroy all paths between
  167. source and target in G.
  168. Returns an empty set if source and target are either in different
  169. components or are directly connected by an edge, as no node removal
  170. can destroy the path.
  171. Examples
  172. --------
  173. This function is not imported in the base NetworkX namespace, so you
  174. have to explicitly import it from the connectivity package:
  175. >>> from networkx.algorithms.connectivity import minimum_st_node_cut
  176. We use in this example the platonic icosahedral graph, which has node
  177. connectivity 5.
  178. >>> G = nx.icosahedral_graph()
  179. >>> len(minimum_st_node_cut(G, 0, 6))
  180. 5
  181. If you need to compute local st cuts between several pairs of
  182. nodes in the same graph, it is recommended that you reuse the
  183. data structures that NetworkX uses in the computation: the
  184. auxiliary digraph for node connectivity and node cuts, and the
  185. residual network for the underlying maximum flow computation.
  186. Example of how to compute local st node cuts reusing the data
  187. structures:
  188. >>> # You also have to explicitly import the function for
  189. >>> # building the auxiliary digraph from the connectivity package
  190. >>> from networkx.algorithms.connectivity import build_auxiliary_node_connectivity
  191. >>> H = build_auxiliary_node_connectivity(G)
  192. >>> # And the function for building the residual network from the
  193. >>> # flow package
  194. >>> from networkx.algorithms.flow import build_residual_network
  195. >>> # Note that the auxiliary digraph has an edge attribute named capacity
  196. >>> R = build_residual_network(H, "capacity")
  197. >>> # Reuse the auxiliary digraph and the residual network by passing them
  198. >>> # as parameters
  199. >>> len(minimum_st_node_cut(G, 0, 6, auxiliary=H, residual=R))
  200. 5
  201. You can also use alternative flow algorithms for computing minimum st
  202. node cuts. For instance, in dense networks the algorithm
  203. :meth:`shortest_augmenting_path` will usually perform better than
  204. the default :meth:`edmonds_karp` which is faster for sparse
  205. networks with highly skewed degree distributions. Alternative flow
  206. functions have to be explicitly imported from the flow package.
  207. >>> from networkx.algorithms.flow import shortest_augmenting_path
  208. >>> len(minimum_st_node_cut(G, 0, 6, flow_func=shortest_augmenting_path))
  209. 5
  210. Notes
  211. -----
  212. This is a flow based implementation of minimum node cut. The algorithm
  213. is based in solving a number of maximum flow computations to determine
  214. the capacity of the minimum cut on an auxiliary directed network that
  215. corresponds to the minimum node cut of G. It handles both directed
  216. and undirected graphs. This implementation is based on algorithm 11
  217. in [1]_.
  218. See also
  219. --------
  220. :meth:`minimum_node_cut`
  221. :meth:`minimum_edge_cut`
  222. :meth:`stoer_wagner`
  223. :meth:`node_connectivity`
  224. :meth:`edge_connectivity`
  225. :meth:`maximum_flow`
  226. :meth:`edmonds_karp`
  227. :meth:`preflow_push`
  228. :meth:`shortest_augmenting_path`
  229. References
  230. ----------
  231. .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms.
  232. http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
  233. """
  234. if auxiliary is None:
  235. H = build_auxiliary_node_connectivity(G)
  236. else:
  237. H = auxiliary
  238. mapping = H.graph.get("mapping", None)
  239. if mapping is None:
  240. raise nx.NetworkXError("Invalid auxiliary digraph.")
  241. if G.has_edge(s, t) or G.has_edge(t, s):
  242. return set()
  243. kwargs = {"flow_func": flow_func, "residual": residual, "auxiliary": H}
  244. # The edge cut in the auxiliary digraph corresponds to the node cut in the
  245. # original graph.
  246. edge_cut = minimum_st_edge_cut(H, f"{mapping[s]}B", f"{mapping[t]}A", **kwargs)
  247. # Each node in the original graph maps to two nodes of the auxiliary graph
  248. node_cut = {H.nodes[node]["id"] for edge in edge_cut for node in edge}
  249. return node_cut - {s, t}
  250. @nx._dispatchable
  251. def minimum_node_cut(G, s=None, t=None, flow_func=None):
  252. r"""Returns a set of nodes of minimum cardinality that disconnects G.
  253. If source and target nodes are provided, this function returns the
  254. set of nodes of minimum cardinality that, if removed, would destroy
  255. all paths among source and target in G. If not, it returns a set
  256. of nodes of minimum cardinality that disconnects G.
  257. Parameters
  258. ----------
  259. G : NetworkX graph
  260. s : node
  261. Source node. Optional. Default value: None.
  262. t : node
  263. Target node. Optional. Default value: None.
  264. flow_func : function
  265. A function for computing the maximum flow among a pair of nodes.
  266. The function has to accept at least three parameters: a Digraph,
  267. a source node, and a target node. And return a residual network
  268. that follows NetworkX conventions (see :meth:`maximum_flow` for
  269. details). If flow_func is None, the default maximum flow function
  270. (:meth:`edmonds_karp`) is used. See below for details. The
  271. choice of the default function may change from version
  272. to version and should not be relied on. Default value: None.
  273. Returns
  274. -------
  275. cutset : set
  276. Set of nodes that, if removed, would disconnect G. If source
  277. and target nodes are provided, the set contains the nodes that
  278. if removed, would destroy all paths between source and target.
  279. Examples
  280. --------
  281. >>> # Platonic icosahedral graph has node connectivity 5
  282. >>> G = nx.icosahedral_graph()
  283. >>> node_cut = nx.minimum_node_cut(G)
  284. >>> len(node_cut)
  285. 5
  286. You can use alternative flow algorithms for the underlying maximum
  287. flow computation. In dense networks the algorithm
  288. :meth:`shortest_augmenting_path` will usually perform better
  289. than the default :meth:`edmonds_karp`, which is faster for
  290. sparse networks with highly skewed degree distributions. Alternative
  291. flow functions have to be explicitly imported from the flow package.
  292. >>> from networkx.algorithms.flow import shortest_augmenting_path
  293. >>> node_cut == nx.minimum_node_cut(G, flow_func=shortest_augmenting_path)
  294. True
  295. If you specify a pair of nodes (source and target) as parameters,
  296. this function returns a local st node cut.
  297. >>> len(nx.minimum_node_cut(G, 3, 7))
  298. 5
  299. If you need to perform several local st cuts among different
  300. pairs of nodes on the same graph, it is recommended that you reuse
  301. the data structures used in the maximum flow computations. See
  302. :meth:`minimum_st_node_cut` for details.
  303. Notes
  304. -----
  305. This is a flow based implementation of minimum node cut. The algorithm
  306. is based in solving a number of maximum flow computations to determine
  307. the capacity of the minimum cut on an auxiliary directed network that
  308. corresponds to the minimum node cut of G. It handles both directed
  309. and undirected graphs. This implementation is based on algorithm 11
  310. in [1]_.
  311. See also
  312. --------
  313. :meth:`minimum_st_node_cut`
  314. :meth:`minimum_cut`
  315. :meth:`minimum_edge_cut`
  316. :meth:`stoer_wagner`
  317. :meth:`node_connectivity`
  318. :meth:`edge_connectivity`
  319. :meth:`maximum_flow`
  320. :meth:`edmonds_karp`
  321. :meth:`preflow_push`
  322. :meth:`shortest_augmenting_path`
  323. References
  324. ----------
  325. .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms.
  326. http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
  327. """
  328. if (s is not None and t is None) or (s is None and t is not None):
  329. raise nx.NetworkXError("Both source and target must be specified.")
  330. # Local minimum node cut.
  331. if s is not None and t is not None:
  332. if s not in G:
  333. raise nx.NetworkXError(f"node {s} not in graph")
  334. if t not in G:
  335. raise nx.NetworkXError(f"node {t} not in graph")
  336. return minimum_st_node_cut(G, s, t, flow_func=flow_func)
  337. # Global minimum node cut.
  338. # Analog to the algorithm 11 for global node connectivity in [1].
  339. if G.is_directed():
  340. if not nx.is_weakly_connected(G):
  341. raise nx.NetworkXError("Input graph is not connected")
  342. iter_func = itertools.permutations
  343. def neighbors(v):
  344. return itertools.chain.from_iterable([G.predecessors(v), G.successors(v)])
  345. else:
  346. if not nx.is_connected(G):
  347. raise nx.NetworkXError("Input graph is not connected")
  348. iter_func = itertools.combinations
  349. neighbors = G.neighbors
  350. # Reuse the auxiliary digraph and the residual network.
  351. H = build_auxiliary_node_connectivity(G)
  352. R = build_residual_network(H, "capacity")
  353. kwargs = {"flow_func": flow_func, "auxiliary": H, "residual": R}
  354. # Choose a node with minimum degree.
  355. v = min(G, key=G.degree)
  356. # Initial node cutset is all neighbors of the node with minimum degree.
  357. min_cut = set(G[v])
  358. # Compute st node cuts between v and all its non-neighbors nodes in G.
  359. for w in set(G) - set(neighbors(v)) - {v}:
  360. this_cut = minimum_st_node_cut(G, v, w, **kwargs)
  361. if len(min_cut) >= len(this_cut):
  362. min_cut = this_cut
  363. # Also for non adjacent pairs of neighbors of v.
  364. for x, y in iter_func(neighbors(v), 2):
  365. if y in G[x]:
  366. continue
  367. this_cut = minimum_st_node_cut(G, x, y, **kwargs)
  368. if len(min_cut) >= len(this_cut):
  369. min_cut = this_cut
  370. return min_cut
  371. @nx._dispatchable
  372. def minimum_edge_cut(G, s=None, t=None, flow_func=None):
  373. r"""Returns a set of edges of minimum cardinality that disconnects G.
  374. If source and target nodes are provided, this function returns the
  375. set of edges of minimum cardinality that, if removed, would break
  376. all paths among source and target in G. If not, it returns a set of
  377. edges of minimum cardinality that disconnects G.
  378. Parameters
  379. ----------
  380. G : NetworkX graph
  381. s : node
  382. Source node. Optional. Default value: None.
  383. t : node
  384. Target node. Optional. Default value: None.
  385. flow_func : function
  386. A function for computing the maximum flow among a pair of nodes.
  387. The function has to accept at least three parameters: a Digraph,
  388. a source node, and a target node. And return a residual network
  389. that follows NetworkX conventions (see :meth:`maximum_flow` for
  390. details). If flow_func is None, the default maximum flow function
  391. (:meth:`edmonds_karp`) is used. See below for details. The
  392. choice of the default function may change from version
  393. to version and should not be relied on. Default value: None.
  394. Returns
  395. -------
  396. cutset : set
  397. Set of edges that, if removed, would disconnect G. If source
  398. and target nodes are provided, the set contains the edges that
  399. if removed, would destroy all paths between source and target.
  400. Examples
  401. --------
  402. >>> # Platonic icosahedral graph has edge connectivity 5
  403. >>> G = nx.icosahedral_graph()
  404. >>> len(nx.minimum_edge_cut(G))
  405. 5
  406. You can use alternative flow algorithms for the underlying
  407. maximum flow computation. In dense networks the algorithm
  408. :meth:`shortest_augmenting_path` will usually perform better
  409. than the default :meth:`edmonds_karp`, which is faster for
  410. sparse networks with highly skewed degree distributions.
  411. Alternative flow functions have to be explicitly imported
  412. from the flow package.
  413. >>> from networkx.algorithms.flow import shortest_augmenting_path
  414. >>> len(nx.minimum_edge_cut(G, flow_func=shortest_augmenting_path))
  415. 5
  416. If you specify a pair of nodes (source and target) as parameters,
  417. this function returns the value of local edge connectivity.
  418. >>> nx.edge_connectivity(G, 3, 7)
  419. 5
  420. If you need to perform several local computations among different
  421. pairs of nodes on the same graph, it is recommended that you reuse
  422. the data structures used in the maximum flow computations. See
  423. :meth:`local_edge_connectivity` for details.
  424. Notes
  425. -----
  426. This is a flow based implementation of minimum edge cut. For
  427. undirected graphs the algorithm works by finding a 'small' dominating
  428. set of nodes of G (see algorithm 7 in [1]_) and computing the maximum
  429. flow between an arbitrary node in the dominating set and the rest of
  430. nodes in it. This is an implementation of algorithm 6 in [1]_. For
  431. directed graphs, the algorithm does n calls to the max flow function.
  432. The function raises an error if the directed graph is not weakly
  433. connected and returns an empty set if it is weakly connected.
  434. It is an implementation of algorithm 8 in [1]_.
  435. See also
  436. --------
  437. :meth:`minimum_st_edge_cut`
  438. :meth:`minimum_node_cut`
  439. :meth:`stoer_wagner`
  440. :meth:`node_connectivity`
  441. :meth:`edge_connectivity`
  442. :meth:`maximum_flow`
  443. :meth:`edmonds_karp`
  444. :meth:`preflow_push`
  445. :meth:`shortest_augmenting_path`
  446. References
  447. ----------
  448. .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms.
  449. http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
  450. """
  451. if (s is not None and t is None) or (s is None and t is not None):
  452. raise nx.NetworkXError("Both source and target must be specified.")
  453. # reuse auxiliary digraph and residual network
  454. H = build_auxiliary_edge_connectivity(G)
  455. R = build_residual_network(H, "capacity")
  456. kwargs = {"flow_func": flow_func, "residual": R, "auxiliary": H}
  457. # Local minimum edge cut if s and t are not None
  458. if s is not None and t is not None:
  459. if s not in G:
  460. raise nx.NetworkXError(f"node {s} not in graph")
  461. if t not in G:
  462. raise nx.NetworkXError(f"node {t} not in graph")
  463. return minimum_st_edge_cut(H, s, t, **kwargs)
  464. # Global minimum edge cut
  465. # Analog to the algorithm for global edge connectivity
  466. if G.is_directed():
  467. # Based on algorithm 8 in [1]
  468. if not nx.is_weakly_connected(G):
  469. raise nx.NetworkXError("Input graph is not connected")
  470. # Initial cutset is all edges of a node with minimum degree
  471. node = min(G, key=G.degree)
  472. min_cut = set(G.edges(node))
  473. nodes = list(G)
  474. n = len(nodes)
  475. for i in range(n):
  476. try:
  477. this_cut = minimum_st_edge_cut(H, nodes[i], nodes[i + 1], **kwargs)
  478. if len(this_cut) <= len(min_cut):
  479. min_cut = this_cut
  480. except IndexError: # Last node!
  481. this_cut = minimum_st_edge_cut(H, nodes[i], nodes[0], **kwargs)
  482. if len(this_cut) <= len(min_cut):
  483. min_cut = this_cut
  484. return min_cut
  485. else: # undirected
  486. # Based on algorithm 6 in [1]
  487. if not nx.is_connected(G):
  488. raise nx.NetworkXError("Input graph is not connected")
  489. # Initial cutset is all edges of a node with minimum degree
  490. node = min(G, key=G.degree)
  491. min_cut = set(G.edges(node))
  492. # A dominating set is \lambda-covering
  493. # We need a dominating set with at least two nodes
  494. for node in G:
  495. D = nx.dominating_set(G, start_with=node)
  496. v = D.pop()
  497. if D:
  498. break
  499. else:
  500. # in complete graphs the dominating set will always be of one node
  501. # thus we return min_cut, which now contains the edges of a node
  502. # with minimum degree
  503. return min_cut
  504. for w in D:
  505. this_cut = minimum_st_edge_cut(H, v, w, **kwargs)
  506. if len(this_cut) <= len(min_cut):
  507. min_cut = this_cut
  508. return min_cut