Yog.Flow.MinCut (YogEx v0.97.0)

Copy Markdown View Source

Global minimum cut algorithms for undirected graphs.

This module finds the global minimum cut in an undirected weighted graph - the partition of nodes into two non-empty sets that minimizes the total weight of edges crossing between the sets.

Algorithm Summary

AlgorithmFunctionComplexityBest For
Stoer-Wagnerglobal_min_cut/2O(V³)Dense undirected graphs, exact result
Karger-Steinkarger_stein/2O(V² log³ V)Large graphs, randomized approach
Gomory-Hu Treegomory_hu_tree/1O(V · MaxFlow)All-pairs min-cut analysis

Key Concepts

  • Global Min-Cut: The minimum cut over all possible partitions of the graph.
  • s-t Cut: A cut that separates specific nodes s and t.
  • Maximum Adjacency Search: Orders vertices by strength of connection to the current set (used by Stoer-Wagner).
  • Edge Contraction: Merging two nodes while preserving total edge weight to other nodes (used by Karger-Stein).

Gomory-Hu Trees

The Gomory-Hu tree is a powerful structure that encodes all-pairs min-cuts using only V-1 max-flow computations. In the tree, the min-cut value between any two nodes u and v is the minimum weight on the unique tree path between them.

Use gomory_hu_tree/1 to build the tree and min_cut_query/3 to extract values and partitions.

graph G { bgcolor="transparent"; node [shape=circle, fontname="inherit"]; edge [fontname="inherit", fontsize=10]; rankdir=LR; 1 -- 2 [label="7"]; 2 -- 3 [label="5"]; 2 -- 4 [label="6"]; label="Example Gomory-Hu Tree"; fontsize=12; }

Randomized Algorithms

For very large graphs where exact algorithms (O(V³)) might be slow, karger_stein/2 provides a randomized approach based on edge contraction. It uses recursive branching to achieve a high probability of success.

Comparison with s-t Min-Cut

For finding a cut between specific source and sink nodes, use Yog.Flow.MaxFlow or the convenience s_t_min_cut/4:

  • s_t_min_cut(graph, s, t, :dinic): Efficiently finds the cut separating s and t.
  • global_min_cut(graph): Finds the minimum weight cut across any possible partition.

Examples

Global Minimum Cut (Stoer-Wagner)

iex> graph = Yog.from_edges(:undirected, [{1, 2, 5}, {2, 3, 3}, {1, 3, 2}])
iex> result = Yog.Flow.MinCut.global_min_cut(graph)
iex> result.cut_value
5

All-Pairs Analysis (Gomory-Hu)

iex> graph = Yog.from_edges(:undirected, [{1, 2, 3}, {1, 3, 4}, {2, 3, 2}, {2, 4, 5}, {3, 4, 1}])
iex> tree = Yog.Flow.MinCut.gomory_hu_tree(graph)
iex> {cut_value, _s, _t} = Yog.Flow.MinCut.min_cut_query(tree, 1, 4)
iex> cut_value
6

References

Summary

Functions

Finds the global minimum cut of an undirected weighted graph.

Builds a Gomory-Hu tree representing all-pairs min-cuts in the graph.

Finds the global minimum cut using the randomized Karger-Stein algorithm.

Queries the min-cut value and partitions between two nodes using a Gomory-Hu tree.

Computes the minimum s-t cut using a max-flow algorithm.

Functions

global_min_cut(graph, opts \\ [])

@spec global_min_cut(
  Yog.graph(),
  keyword()
) :: Yog.Flow.MinCutResult.t()

Finds the global minimum cut of an undirected weighted graph.

This implementation uses the Stoer-Wagner algorithm. It repeatedly finds an s-t min-cut in a phase using Maximum Adjacency Search and then contracts the nodes s and t. The global minimum cut is the minimum of all phase cuts.

Time Complexity: O(V³) (O(V² log V) with priority queue optimization)

Examples

Simple triangle graph:

iex> {:ok, graph} = Yog.undirected()
...>   |> Yog.add_node(1, "A")
...>   |> Yog.add_node(2, "B")
...>   |> Yog.add_node(3, "C")
...>   |> Yog.add_edges([{1, 2, 5}, {2, 3, 3}, {1, 3, 2}])
iex> result = Yog.Flow.MinCut.global_min_cut(graph)
iex> result.cut_value
5
iex> result.source_side_size + result.sink_side_size
3

Parameters

  • graph - The undirected weighted graph
  • opts - Options:
    • :track_partitions - If true, populates the source_side and sink_side fields in the result. (default: false)

Notes

gomory_hu_tree(graph)

@spec gomory_hu_tree(Yog.graph()) :: Yog.graph()

Builds a Gomory-Hu tree representing all-pairs min-cuts in the graph.

The Gomory-Hu tree is a weighted tree on the same vertex set where the minimum edge weight on the path between any two nodes equals their min-cut value in the original graph. This implementation uses Gusfield's algorithm, requiring only V-1 max-flow computations.

Examples

iex> graph = Yog.from_edges(:undirected, [{1, 2, 3}, {1, 3, 4}, {2, 3, 2}, {2, 4, 5}, {3, 4, 1}])
iex> tree = Yog.Flow.MinCut.gomory_hu_tree(graph)
iex> length(Yog.Model.all_edges(tree))
3

karger_stein(graph, opts \\ [])

@spec karger_stein(
  Yog.graph(),
  keyword()
) :: Yog.Flow.MinCutResult.t()

Finds the global minimum cut using the randomized Karger-Stein algorithm.

Karger-Stein uses repeated random edge contraction with recursive branching to achieve high success probability. It is particularly effective on large graphs where the exact Stoer-Wagner algorithm may be slower, as the randomized approach can often find the global minimum cut with very few iterations.

Parameters

  • graph - The undirected weighted graph
  • opts - Options:
    • :iterations - Number of independent runs of the recursive fast-cut procedure (default: max(1, trunc(n * log2(n + 1)))). Increasing the number of iterations improves the success probability.

Examples

iex> graph = Yog.from_edges(:undirected, [{1, 2, 5}, {2, 3, 3}, {1, 3, 2}])
iex> result = Yog.Flow.MinCut.karger_stein(graph)
iex> result.cut_value
5

min_cut_query(tree, node_a, node_b)

@spec min_cut_query(Yog.graph(), Yog.node_id(), Yog.node_id()) ::
  {number(), MapSet.t(Yog.node_id()), MapSet.t(Yog.node_id())}

Queries the min-cut value and partitions between two nodes using a Gomory-Hu tree.

Returns {cut_value, partition_s, partition_t} where cut_value is the min-cut between node_a and node_b in the original graph, and the partitions are the two sides of that cut.

Examples

iex> graph = Yog.from_edges(:undirected, [{1, 2, 3}, {1, 3, 4}, {2, 3, 2}, {2, 4, 5}, {3, 4, 1}])
iex> tree = Yog.Flow.MinCut.gomory_hu_tree(graph)
iex> {cut_value, _s, _t} = Yog.Flow.MinCut.min_cut_query(tree, 1, 4)
iex> cut_value
6

s_t_min_cut(graph, source, sink, algorithm \\ :edmonds_karp)

@spec s_t_min_cut(Yog.graph(), Yog.node_id(), Yog.node_id(), atom()) ::
  Yog.Flow.MinCutResult.t()

Computes the minimum s-t cut using a max-flow algorithm.

This is a convenience wrapper that delegates to Yog.Flow.MaxFlow.max_flow/4 and extracts the corresponding min-cut from the residual graph.

Parameters

  • graph - The flow network
  • source - Source node ID
  • sink - Sink node ID
  • algorithm - Algorithm to use: :edmonds_karp (default), :dinic, or :push_relabel

Examples

iex> {:ok, graph} = Yog.directed()
...>   |> Yog.add_node(1, "s")
...>   |> Yog.add_node(2, "a")
...>   |> Yog.add_node(3, "t")
...>   |> Yog.add_edges([{1, 2, 10}, {2, 3, 5}])
iex> result = Yog.Flow.MinCut.s_t_min_cut(graph, 1, 3)
iex> result.cut_value
5