FindMaximumFlow¶
Status: Stable
documented, exercised by the test suite and/or worked examples, with no known limitations recorded.
Description¶
FindMaximumFlow[g, s, t]
gives the value of a maximum flow from s to t (s and t may be lists of sources and sinks). FindMaximumFlow[g, s, t, "prop"] gives "FlowValue", "FlowMatrix" (dense n x n matrix of edge flows) or "EdgeList" (edges carrying flow, oriented along it). Capacities come from the EdgeCapacity -> {c1, ...} option (EdgeList order), else from g's own EdgeCapacity, else 1; EdgeWeight is ignored; VertexCapacity -> {c1, ...} caps the flow through each vertex. Undirected edges carry flow either way. Dinic's algorithm; exact for integer capacities.
Examples (17)¶
Every input below was run against the current Mathilda build and its output recorded.
Basic examples (3)¶
In[1]:= FindMaximumFlow[CompleteGraph[4], 1, 4]
Out[1]= 3
In[2]:= FindMaximumFlow[CycleGraph[6], 1, 4, "EdgeList"]
Out[2]= {1 <-> 2, 1 <-> 6, 2 <-> 3, 3 <-> 4, 5 <-> 4, 6 <-> 5}
In[3]:= FindMaximumFlow[CycleGraph[6], {1, 2}, {4, 5}]
Out[3]= 2
Scope (1)¶
Options (10)¶
In[5]:= FindMaximumFlow[Graph[{1->2,2->3,1->3}], 1, 3, EdgeCapacity -> {2, 3, 1}]
Out[5]= 3
In[6]:= FindMaximumFlow[Graph[{1->2,2->3,1->3}], 1, 3, "FlowMatrix", EdgeCapacity -> {2, 3, 1}]
Out[6]= {{0, 2, 1}, {0, 0, 2}, {0, 0, 0}}
In[7]:= FindMaximumFlow[Graph[{1->2,2->3,1->3}], 1, 3, EdgeCapacity -> {1/2, 3, 1}]
Out[7]= 1.5
In[8]:= FindMaximumFlow[Graph[{1->2, 2->3, 1->3}, EdgeCapacity -> {2, 3, 4}], 1, 3]
Out[8]= 6
In[9]:= FindMaximumFlow[Graph[{1,2,3},{1->2,2->3,1->3}, EdgeWeight->{5,5,5}], 1, 3]
Out[9]= 2
In[10]:= FindMaximumFlow[Graph[{1->2,2->3,1->3}], 1, 3, EdgeCapacity -> {Infinity, 3, 1}]
Out[10]= 4
In[11]:= FindMaximumFlow[Graph[{1->2,2->3,1->3}], 1, 3, EdgeCapacity -> {-1, 3, 1}]
Out[11]= FindMaximumFlow[Graph[<3 vertices, 3 edges>], 1, 3, EdgeCapacity -> {-1, 3, 1}]
In[12]:= FindMaximumFlow[PathGraph[{1, 2, 3}], 1, 3, EdgeCapacity -> {10, 10}, VertexCapacity -> {2, 10, 10}]
Out[12]= 2
In[13]:= FindMaximumFlow[CompleteGraph[4], {1, 2}, {3, 4}, VertexCapacity -> {3, 1, 1, 5}]
Out[13]= 3
In[14]:= FindMaximumFlow[PathGraph[{1, 2, 3}], 1, 3, VertexCapacity -> {1, 1/2, 1}]
Out[14]= 0.5
Applications (3)¶
Direct 3 plus 1 through vertex 2
In[15]:= FindMaximumFlow[Graph[{1, 2, 3}, {1 -> 2, 2 -> 3, 1 -> 3}, EdgeCapacity -> {2, 1, 3}], 1, 3]
Out[15]= 4
Unit capacities: three edge-disjoint paths
Bottlenecked by the middle edges
In[17]:= FindMaximumFlow[Graph[{1, 2, 3, 4}, {1 -> 2, 1 -> 3, 2 -> 4, 3 -> 4}, EdgeCapacity -> {3, 2, 2, 3}], 1, 4]
Out[17]= 4
Options & behaviour¶
EdgeWeight is not a capacity, an infinite capacity is allowed, s == t gives
0, and a negative capacity or a non-graph leaves the call unevaluated:
Implementation notes¶
Algorithm. builtin_find_maximum_flow computes the value of a maximum flow
from s to t (either may be a list of sources/sinks) with Dinic's
algorithm. A fourth argument selects the property: "FlowValue" (default),
"FlowMatrix" (a dense n x n matrix of per-edge flows), or "EdgeList" (the
edges carrying flow, oriented along it, in flow-matrix row-major order).
Capacities come from EdgeCapacity -> {c1, ...} (else the graph's own
EdgeCapacity, else 1); EdgeWeight is ignored. A VertexCapacity option
caps the flow through each vertex, modelled by the split-vertex construction
(v_in -> v_out). Several sources/sinks are wired to a super-source/super-sink.
An undirected edge carries flow either way up to its capacity; a directed edge
only forwards.
Data structures. Capacities are parsed into a scaled-int64 GfCap (exact
integers; reals scaled by a shared power of two; Infinity as a finite stand-in
above every finite sum) ā including a packed-buffer fast path that reads an
NDArray capacity list without unpacking. The network is a GfNet CSR residual
graph (adjacent forward/reverse arc pairs) with level-BFS truncated at the sink's
level and an iterative current-arc blocking-flow search. The flow matrix is
offered to the packer (pack_offer).
Complexity / limits. O(E sqrt(E)) on unit capacities; a handful of phases
in practice. Exact Integer for integer capacities, Real otherwise, Infinity
when the flow reaches the Infinity stand-in. A negative or symbolic capacity
leaves the call unevaluated.
- Part of the graph-algorithm family (flows, cuts, matchings, covers, cliques,
independent sets, Hamiltonian cycles, isomorphism, planarity) implemented in
src/graph/galg_*.c, declared insrc/graph/graph_algos.hand registered bygraph_algos_init(). Every head in the family reads graphs through the validated-graph memo, so on a graph built byGraph[...]it starts from pre-resolved integer endpoints. Every head isProtected, stays unevaluated on a non-graph (the*Qpredicates giveFalse), and returns a fresh value. Semantics and output forms were checked against Mathematica 15 by a randomized differential test (benchmarks/95-graph-algorithms/diff_mathematica.py, about 12k cases, 0 failures); where the answer is unique the outputs are identical. sandtmay be lists of sources / sinks;s == tgives0."FlowValue"is the default."FlowMatrix"is a densen x nmatrix of edge flows (packed); Mathematica returns aSparseArray, which Mathilda does not have."EdgeList"gives the edges carrying flow, oriented along the flow, in flow-matrix row order.- Options:
EdgeCapacity -> {c1, ...}(inEdgeListorder) andVertexCapacity -> {c1, ...}(inVertexListorder). Sources and sinks are capped by their own vertex capacity too, as in Mathematica. The two lists are parsed together onto one exact scale, so an exactEdgeCapacitymixes with a Rational/RealVertexCapacity(Mathematica leaves a non-integerVertexCapacityunevaluated). Matches Mathematica on 160 random vertex-capacitated instances (single and multiple terminals, directed and undirected). Where every capacity on the source side isInfinity, Mathematica 15 answers0; Mathilda gives the true value (Infinity, or the finite bottleneck). - Capacities ignore
EdgeWeight, exactly as Mathematica does. With noEdgeCapacityoption (orEdgeCapacity -> Automatic) the capacities are the graph's ownEdgeCapacitywhen it was built with one (Graph[e, EdgeCapacity -> {...}]), else 1 for every edge ā Mathematica's documented rule. An explicit option wins over the stored list. An undirected edge carries flow either way. - Numbers (shared by the whole flow/cut family): integer capacities/weights give
exact Integers; Rational or Real ones give a Real (as Mathematica);
Infinityis an allowed capacity; a negative or symbolic one leaves the call unevaluated. Internally everything is int64: reals are scaled by a common power of two, so the max flow of machine-real capacities is computed exactly. - Algorithm: Dinic (BFS levels truncated at the sink, iterative blocking flow with current-arc pointers) on a CSR residual network.
Attributes: Protected.
References¶
See also: SparseArray, EdgeList, VertexList, EdgeWeight
- E. A. Dinic, Algorithm for solution of a problem of maximum flow in a network with power estimation, Soviet Math. Dokl. 11 (1970) 1277-1280.
- Source:
src/graph/galg_flow.c - Specification:
docs/spec/builtins/graphs.md - Tests:
tests/test_graph.c - Tests:
tests/test_graph_algos.c
Notes & additional examples¶
Notes¶
The flow value is capacity-limited: capacities come from the EdgeCapacity
option (EdgeList order), defaulting to 1 per edge when none is given, and
EdgeWeight plays no part. With integer capacities the answer is exact.
A fourth argument requests "FlowValue", "FlowMatrix", or "EdgeList".
Sources and sinks may each be a list, and VertexCapacity bounds the flow
through individual vertices. An undirected edge can carry flow in either
direction; a directed edge only forwards.