149 Networks
149.1 Networks
A transportation network: goods are produced at the sources, consumed at the sinks, and shipped along the arcs, each with a maximum throughput.
! Missing from Mathlib (0 hits for flow/network/capacity). Capacity is carried as a function cap : V \(\to \) V \(\to \) \(\mathbb {N}\), with cap u v = 0 encoding "no arc \(u \to v\)"; this makes \(f^{+}\)/\(f^{-}\) plain Finset.sums. ! It cannot represent parallel arcs, which is a real restriction — lemma 11.4 is about a network in which every arc has unit capacity, and B&M’s digraphs may have several arcs between the same pair.
The structure carries both \(X\), \(Y\) (the source/sink sets of §11.1) and the distinguished \(x\), \(y\) used from §11.2 onward. That is because the book reduces the first to the second: *adjoin two new vertices \(x\) and \(y\); join \(x\) to each vertex in \(X\) by an arc of capacity \(\infty \); join each vertex in \(Y\) to \(y\) by an arc of capacity \(\infty \); designate \(x\) as the source and \(y\) as the sink of \(N'\)* — after which *throughout the next three sections, we shall confine our attention to networks that have a single source \(x\) and a single sink \(y\)*. That reduction is exercise 11.1.4, which is deferred here (it needs an \(\mathbb {N}\infty \)-capacity parallel carrier), so the two are simply both recorded in the structure.
! Structural defect: \(x\), \(y\) are unrelated to \(X\), \(Y\). Nothing in the structure requires N.x \(\in \) N.X, let alone N.X = {N.x}. But val is defined over the set \(X\) while every §11.2–§11.3 result is about cuts separating the single \(x\) from the single \(y\). The two therefore measure different things, and lemma 11.1, theorem 11.1 in both forms, corollary 11.1 and theorem 11.3 are all false as stated.
Counterexample (one network refutes all of them). \(V = {x_{1}, x_{2}, y_{1}}\), \(X = {x_{1}, x_{2}}\), \(Y = {y_{1}}\), N.x = x\(_{1}\), N.y = y\(_{1}\); capacities \(c(x_{1},y_{1}) = c(x_{2},y_{1}) = 1\) and \(0\) elsewhere. Then \(I = \emptyset \), so any \(f\) within capacity is a flow; take \(f(x_{1},y_{1}) = f(x_{2},y_{1}) = 1\). val f = f\(^{+}\)(X) - f\(^{-}\)(X) = 2. \(S = {x_{1}}\) is a cut (\(x_{1} \in S\), \(y_{1} \notin S\)), with \(f^{+}(S) - f^{-}(S) = 1\) and cap S = 1. So lemma 11.1 asserts \(2 = 1\); theorem 11.1 asserts \(2 \le 1\). Max flow value is \(2\), minimum cut capacity is \(1\), so theorem 11.3 asserts \(2 = 1\). Corollary 11.1 fails too: \(f'(x_{1},y_{1}) = 1\), \(f'(x_{2},y_{1}) = 0\) has val f’ = 1 = cap{x\(_{1}\)}, yet \(f'\) is not a maximum flow.
The repair is to add the fields hx : N.X = {N.x} and hy : N.Y = {N.y} to the structure (the book’s standing convention for §§11.2–11.4), or equivalently to add them as hypotheses on the affected theorems. The §11.1 results — exercises 11.1.2 and 11.1.3 — are unaffected and should keep the general \(X\), \(Y\).
The transit points of the network, which neither produce nor consume. The conservation condition (11.2) applies exactly here — what flows in must flow out — and that is what makes val f well defined (exercise 11.1.3).
Finset.univ \{} (X \(\cup \) Y), so \(I\) is a Finset and membership is decidable — needed by IsFlow’s second clause.
The total flow leaving \(S\) — sum over every arc with tail inside \(S\) and head outside. ! This is not the sum of the \(f^{+}(v)\) over \(v \in S\): arcs internal to \(S\) are counted there but not here. Exercise 11.1.2 makes the exact relationship precise, and it is the difference \(f^{+} - f^{-}\) that behaves well.
! Missing from Mathlib. A double Finset.sum over \(S\) and \(S^{c}\), which the capacity-as-a-function carrier makes possible; \(f u v = 0\) for a non-arc contributes nothing.
The total flow entering \(S\). Conservation forces the resultant flow out of every intermediate vertex to vanish, which is what makes the resultant flow out of \(X\) equal the resultant flow into \(Y\) (exercise 11.1.3) and hence val f well defined.
The mirror of fOut with the two sums swapped.
Nothing over-loaded, nothing accumulating. The zero flow’s existence is what makes exists_maxFlow non-vacuous.
The lower bound \(0 \le f(a)\) of (11.1) is free: \(f\) is \(\mathbb {N}\)-valued. Conservation is stated as fIn f {v} = fOut f {v} on singletons, which unfolds to the book’s \(f^{-}(v) = f^{+}(v)\) — note fIn/fOut on a singleton are genuinely the per-vertex quantities, since there are no arcs internal to a singleton.
The net rate at which the commodity travels from producers to consumers. Conservation at the intermediate vertices is what makes the two ways of measuring it agree.
! \(\mathbb {Z}\)-valued, and this is load-bearing. In \(\mathbb {N}\) the truncated subtraction would make exercise 11.1.2 — the identity the whole chapter rests on — false, since individual terms \(f^{+}(v) - f^{-}(v)\) are genuinely negative at vertices absorbing more than they emit. Every \(f^{+} - f^{-}\) in this file is therefore cast to \(\mathbb {Z}\) before subtracting.
A way of severing the network so the source is on one side and the sink on the other. Every unit of flow must cross every cut, which is why cuts bound flows from above (theorem 11.1) — and, more surprisingly, why the best cut exactly matches the best flow (theorem 11.3).
! Missing from Mathlib. Identified with the vertex set \(S\) rather than the arc set \((S, \bar{S})\), since \(S\) determines the arcs and is far easier to quantify over. capOf then computes the arc set’s capacity. Note \(y \notin S\) is the book’s \(y \in \bar{S}\).
The total throughput of the severed arcs — how much traffic could at most cross that divide. Since all the flow must pass through, it bounds val f above.
! Missing from Mathlib. Structurally identical to fOut with cap in place of \(f\), which is exactly why theorem 11.1’s proof is a two-line comparison.
Ship as much as the network allows. Theorem 11.2 characterises these as exactly the flows admitting no incrementing path — the flow-theoretic analogue of Berge’s theorem 5.1 for matchings.
"No flow of larger value" is stated positively as \(\forall \) f’, IsFlow f’ \(\to \) val f’ \(\le \) val f, which is the form every consumer wants.
The cheapest way to sever the network — the bottleneck. Theorem 11.3 says its capacity is exactly the maximum throughput. B&M record the easy half first: If f* is a maximum flow and \(\tilde{K}\) is a minimum cut, we have, as a special case of theorem 11.1, that val f* \(\le \) cap \(\tilde{K}\) (11.8).
As with IsMaxFlow, stated positively.
A route from source to sink along which the flow can still be pushed up. Crucially it may travel against an arc — a reverse arc — provided that arc currently carries positive flow, which can then be cancelled. This is what lets the algorithm undo earlier bad choices, exactly as an augmenting path in matching theory rearranges an existing matching; B&M make the analogy explicit: *the rôle played by incrementing paths in flow theory is analogous to that of augmenting paths in matching theory* (compare theorem 5.1). The book’s example is figure 11.5(a), where \(P = xv_{1}v_{2}v_{3}y\) is \(f\)-incrementing with \(\iota (P) = 2\).
! Missing from Mathlib; an honest, complete inductive family — static, not procedural. nil starts at N.x; fwd extends along an \(f\)-unsaturated arc (f u v < cap u v); back extends against an \(f\)-positive arc (\(0 \lt f v u\)). The index is the current endpoint, so N.IncPath f N.y is exactly an \(f\)-incrementing path.
! This is a directed walk — repeated vertices are allowed — not a path. That is deliberate and is what theorem 11.2’s proof actually uses: the set \(S\) of vertices reachable by \(f\)-unsaturated walks is what the cut is built from, and restricting to paths would complicate the reachability closure for no gain.
The bottleneck along the path. A forward arc has room \(c(a) - f(a)\) left; a reverse arc can give back at most the \(f(a)\) it currently carries. The smallest of these slacks is how much extra can be pushed through in one go.
! Defective: this definition has a sorry body. \(\iota (P)\) is therefore an opaque natural number, not the bottleneck of anything. Consequences: exercise 11.3.1 (revisedFlow_isFlow_and_val) asserts val \(\hat{f}\) = val f + \(\iota \)(P) about two opaque constants and so says nothing, and the forward direction of theorem 11.2 — which needs \(\iota (P) \gt 0\) to get a strictly better flow — has no content to appeal to. This also violates the project convention (.claude/CLAUDE.md): *never sorry in a def*.
The repair is a structural recursion over the IncPath family, carrying the running minimum:
iota nil = \(\top \) (or: recurse with an accumulator seeded at the first arc) iota (fwd P h) = min (iota P) (cap u v - f u v) iota (back P h) = min (iota P) (f v u)
The only wrinkle is nil, which has no arcs and so no minimum; either return a sentinel and prove 0 < iota P for non-nil paths, or index the recursion by a running minimum passed in. The second is cleaner and avoids \(\mathbb {N}\infty \).
Push \(\iota (P)\) more along every forward arc of the path and take \(\iota (P)\) back off every reverse arc. Conservation survives because at each interior vertex the increase in and the increase out match; and the value rises by exactly \(\iota (P)\) (exercise 11.3.1). This is the engine of the labelling method: repeatedly find an incrementing path and revise, until none exists — at which point theorem 11.2 certifies maximality.
! Defective: this definition has a sorry body. \(\hat{f}\) is an opaque function, so exercise 11.3.1 — the only statement about it — is vacuous, and theorem 11.2’s forward direction has nothing to revise with. Same convention violation as iota.
The repair is a structural recursion over IncPath mirroring iota’s, adjusting one arc per constructor:
revisedFlow nil = f revisedFlow (fwd P _) = Function.update\(_{2}\) (revisedFlow P) u v (f u v + iota P) revisedFlow (back P _)= Function.update\(_{2}\) (revisedFlow P) v u (f v u - iota P)
! Note iota P must be the bottleneck of the whole path, not of the prefix, or the capacity constraint fails on early arcs — so iota should be computed once and threaded, rather than recomputed at each step. That coupling is the reason both definitions were deferred together, and it is why repairing iota first is the right order.
Corollary 11.5 relates it to edge-disjoint paths: \(G\) is \(k\)-edge-connected exactly when any two distinct vertices are joined by \(k\) edge-disjoint paths — the global connectivity number turned into a local path count.
A minimal local copy; the real one lives in TCSlib.GraphTheory.Connectivity, deliberately not imported so this file stands alone. ! sInf \(\emptyset \) = 0, so a graph with no edge cut (a one-vertex graph) gets \(\kappa ' = 0\) — a boundary case that will bite corollary 11.5 exactly as it bit chapter 10’s associatedDigraph_isKArcConnected_iff.
Corollary 11.7 relates it to internally-disjoint paths: \(G\) with \(\nu \ge k + 1\) is \(k\)-connected exactly when any two distinct vertices are joined by \(k\) internally-disjoint paths. This is the form of Menger’s theorem §3.2 announced without proof.
A minimal local copy, as for edgeConnectivity. The \(\nu - 1\) branch is the book’s convention for graphs with no vertex cut (complete graphs). ! Both sInf conventions bite at the boundaries — see the outline.
The paths share only their endpoints. This is the notion in which Menger’s vertex theorem 11.7 and corollary 11.7 are phrased, and — via the vertex splitting of theorem 11.6 — it is what arc-disjointness in the split digraph corresponds to.
A minimal local copy (the repo’s is TwoConnected.lean:58), stated for a pair of walks. ! Menger’s theorem needs internal disjointness of a whole family; extending this pairwise predicate to families is part of what maxInternallyDisjointPaths must do, and is one reason that count was stubbed.
For a unit-capacity network this equals the value of a maximum flow: each path carries one unit, and arc-disjointness is exactly the capacity constraint.
! sorry body. Repair: sSup over \(k\) such that there are \(k\) directed \((x,y)\)-paths in the underlying digraph (arcs = pairs with 0 < cap u v) that are pairwise arc-disjoint. Needs a directed-path notion; see the section note.
For a unit-capacity network this equals the value of a maximum flow: each path carries one unit, and arc-disjointness is exactly the capacity constraint.
! sorry body. Repair: sSup over \(k\) such that there are \(k\) directed \((x,y)\)-paths in the underlying digraph (arcs = pairs with 0 < cap u v) that are pairwise arc-disjoint. Needs a directed-path notion; see the section note.
The left-hand side of Menger’s arc theorem 11.4: how many routes from \(x\) to \(y\) can run simultaneously without any two sharing an arc.
! sorry body. Repair: sSup over \(k\) admitting \(k\) pairwise arc-disjoint directed \((x,y)\)-paths. Needs a directed-path notion (Digraph.IsDirectedPath in the ch-10 file) and an arc-list, which is arcsOf there — itself sorry-bodied. Of the twelve, this is the one with the deepest dependency.
The left-hand side of Menger’s arc theorem 11.4: how many routes from \(x\) to \(y\) can run simultaneously without any two sharing an arc.
! sorry body. Repair: sSup over \(k\) admitting \(k\) pairwise arc-disjoint directed \((x,y)\)-paths. Needs a directed-path notion (Digraph.IsDirectedPath in the ch-10 file) and an arc-list, which is arcsOf there — itself sorry-bodied. Of the twelve, this is the one with the deepest dependency.
The right-hand side of Menger’s arc theorem 11.4: how few arcs must be cut to sever \(x\) from \(y\) entirely.
! sorry body. Repair: sInf {k | \(\exists \) Z : Finset (V \(\times \) V), Z.card = k \(\land \) \(\lnot \) Relation.ReflTransGen (fun u v => D.Adj u v \(\land \) (u,v) \(\notin \) Z) x y}.
— reachability suffices.
The left-hand side of Menger’s vertex theorem 11.6 — routes sharing no intermediate vertex, so destroying any one interior station leaves the others intact.
! sorry body. Repair: as for the arc version but with internal-vertex disjointness, which needs only the paths’ vertex lists (Quiver.Path.vertices), not arcsOf — so it is easier than maxArcDisjointDirectedPaths.
The left-hand side of Menger’s edge theorem 11.5, the undirected counterpart of theorem 11.4.
! sorry body — definable today. Repair: sSup {k | \(\exists \) ps : Fin k \(\to \) G.Walk x y, (\(\forall \) i, (ps i).IsPath) \(\land \) \(\forall \) i j, i \(\ne \) j \(\to \) List.Disjoint (ps i).edges (ps j).edges}. Every ingredient (Walk, IsPath, Walk.edges, List.Disjoint) is already imported.
The left-hand side of Menger’s edge theorem 11.5, the undirected counterpart of theorem 11.4.
! sorry body — definable today. Repair: sSup {k | \(\exists \) ps : Fin k \(\to \) G.Walk x y, (\(\forall \) i, (ps i).IsPath) \(\land \) \(\forall \) i j, i \(\ne \) j \(\to \) List.Disjoint (ps i).edges (ps j).edges}. Every ingredient (Walk, IsPath, Walk.edges, List.Disjoint) is already imported.
The right-hand side of Menger’s edge theorem 11.5.
! sorry body — definable today. Repair: sInf {k | \(\exists \) F : Finset (Sym2 V), F.card = k \(\land \) \(\lnot \) (G.deleteEdges ↑F).Reachable x y}. deleteEdges and Reachable are already imported.
The left-hand side of Menger’s vertex theorem 11.7 — the form quoted back in §3.2, where it generalises Whitney’s theorem 3.2 from \(k = 2\) to all \(k\).
! sorry body — definable today. Repair: as maxEdgeDisjointPaths but with \(\forall \) i j, i \(\ne \) j \(\to \) InternallyDisjoint (ps i) (ps j), using the local pairwise InternallyDisjoint above.
The "fan" or set-to-set form of Menger’s theorem, where the endpoints are not fixed but merely constrained to lie in prescribed sets. This is the form exercise 11.4.4 (Dirac) actually consumes.
! sorry body — definable today. Repair: sSup over \(k\) admitting \(k\) paths, each with one end in \(S\) and one in \(T\), pairwise vertex-disjoint (not merely internally disjoint — the endpoints must differ too, which is why this is not a special case of maxInternallyDisjointPaths). A \(\Sigma \)-typed family Fin k \(\to \) \(\Sigma \) u \(\in \) S, \(\Sigma \) v \(\in \) T, G.Walk u v handles the varying endpoints.
The "fan" or set-to-set form of Menger’s theorem, where the endpoints are not fixed but merely constrained to lie in prescribed sets. This is the form exercise 11.4.4 (Dirac) actually consumes.
! sorry body — definable today. Repair: sSup over \(k\) admitting \(k\) paths, each with one end in \(S\) and one in \(T\), pairwise vertex-disjoint (not merely internally disjoint — the endpoints must differ too, which is why this is not a special case of maxInternallyDisjointPaths). A \(\Sigma \)-typed family Fin k \(\to \) \(\Sigma \) u \(\in \) S, \(\Sigma \) v \(\in \) T, G.Walk u v handles the varying endpoints.
Make every street two-way. B&M call it a simple trick: it is how theorems 11.5 and 11.7 are deduced from their directed counterparts 11.4 and 11.6, since paths in \(G\) correspond exactly to directed paths in \(D(G)\).
One line — G.Adj is already symmetric, so it is the arc relation. A local copy of chapter 10’s SimpleGraph.associatedDigraph; the path correspondence that makes the trick work is that file’s associatedDigraph_pathEquiv, which is itself sorry-bodied there.
Each vertex becomes a tiny one-way corridor \(v' \to v''\), so *passing through* \(v\) now costs an arc. This converts vertex-destruction into arc-destruction, letting the vertex form of Menger’s theorem be read off from the arc form: *two directed \((x,y)\)-paths in \(D'\) are arc-disjoint if and only if the corresponding paths in \(D\) are internally-disjoint.*
! Missing from Mathlib. Carrier \(V \oplus V\), with inl v = v’ and inr v = v”; internal arcs are inl u \(\to \) inr v when \(u = v\), and original arcs become inr u \(\to \) inl v.
! Simplified: it does not special-case \(x\) and \(y\). The book splits only \(V \ {x, y}\), leaving the endpoints intact; this splits every vertex. The consequence is that \(x\) and \(y\) also acquire internal arcs, so a destroying set in \(D'\) could cut \(x\)’s or \(y\)’s own corridor — which corresponds to deleting \(x\) or \(y\) themselves, something the book’s vertex-destruction forbids. Statements about splitDigraph therefore address Sum.inr x and Sum.inl y (the far ends of those corridors), which sidesteps the issue for exercise 11.4.1; but the simplification should be checked before it is relied on elsewhere.
for supplies \(\sigma \) and demands dem (B&M’s \(\partial \)). ! MISSING. Honest def.
Nobody ships more than they can produce, and everybody receives at least what they ordered. Gale’s theorem 11.8 characterises existence: for every \(S\), the capacity out of \(S\) must cover the net demand of \(\bar{S}\).
! Missing from Mathlib. dem is B&M’s \(\partial \). Both conditions are cast to \(\mathbb {Z}\) before subtracting, for the reason recorded under val. Supplies and demands are \(V \to \mathbb {N}\) total functions, with the conditions quantified only over \(X\) and \(Y\), so their values elsewhere are irrelevant.
Can two prescribed lists of degrees occur as the two sides of a bipartite graph? The book’s \(p = (3,2,2,2,1)\), \(q = (3,3,2,1,1)\) is realisable (figure 11.12), whereas \(p = q = (5,4,4,2,1)\) is not (exercise 11.5.2) even though the sums agree.
! Missing from Mathlib (0 hits for Gale–Ryser). Carried as a \((0,1)\)-matrix B : Fin m \(\to \) Fin n \(\to \) Bool rather than a bipartite SimpleGraph, following the book’s own closing remark: *With each simple bipartite graph \(G\) …we can associate an \(m \times n\) matrix \(B\) in which \(b_ij = 1\) or \(0\), depending on whether \(x_{i}y_{j}\) is an edge of \(G\) or not. Conversely, every \(m \times n\) \((0,1)\)-matrix corresponds in this way to a simple bipartite graph.* The two are equivalent and the matrix avoids constructing a graph on Fin m \(\oplus \) Fin n with a bipartition proof. Due to Ryser (1957).
Make every edge one-way so each vertex ends up receiving exactly \(m\) arrows, or exactly \(n\). Since \(G\) is \((m+n)\)-regular, indegree \(m\) forces outdegree \(n\) and conversely, so an orientation splits the vertices into two classes. Exercise 11.5.5(a) characterises orientability by a cut condition, and (b) shows the classes can always be rebalanced one step towards each other.
! Missing from Mathlib (0 hits for "orientable"). The orientation is spelled out inline as a Digraph D with three clauses — \(D \subseteq G\), \(D\) never two-way, \(D\) covers every edge — rather than reusing chapter 10’s IsOrientationOf, which this file does not import. The fourth clause is the indegree condition. Note the \((m+n)\)-regularity is not part of this definition; it appears as a hypothesis on the theorems that use it.
The size of the undirected edge cut at \(S\) — how many edges would have to be severed to separate \(S\) from the rest. In exercise 11.5.5(a) it is the capacity available to carry the imbalance the prescribed indegrees force across \(S\)’s boundary.
A double sum of indicators rather than a Finset.card, matching the shape of fOut/capOf so the three compare directly. Since G.Adj is symmetric and the sum runs over \(S \times S^{c}\), each crossing edge is counted once.
Summing the net outflow over the vertices of \(S\) gives the net outflow of \(S\) as a whole. The book flags the trap: *in general, \(\sum _{v \in S} f^{+}(v) \ne f^{+}(S)\) and \(\sum _{v \in S} f^{-}(v) \ne f^{-}(S)\)* — only the difference behaves, and only because the internal arcs cancel.
* Build this first — lemma 11.1 and theorem 11.1 both rest on it, and it is where the \(\mathbb {Z}\)-valuedness of val earns its keep: in \(\mathbb {N}\) step 3’s cancellation is false, since \(f^{+}{v} - f^{-}{v}\) truncates at each vertex individually. Note it needs no IsFlow hypothesis: it is pure bookkeeping about an arbitrary \(f\).
Whatever leaves the producers must arrive at the consumers. This is what makes val f well defined — the two natural ways to measure throughput agree, and the book defines val f as the first only after asserting they coincide.
Step 4’s \(f^{+}(S) = f^{-}(S^{c})\) is worth an explicit simp lemma; it recurs throughout the chapter. Step 3 is where N.hdisj is spent.
The value of a flow can be measured across any cut, not just at the source: all the material has to cross somewhere, and nothing is lost in between. This is the observation from which theorem 11.1 immediately follows.
! Statement defect. This is false as stated — the seam between §11.1’s multi-source setting and §11.2’s single-source one. B&M close it by fiat (*throughout the next three sections, we shall confine our attention to networks that have a single source \(x\) and a single sink \(y\)*), but the Network structure here relates \(x\), \(y\) to \(X\), \(Y\) in no way at all, so val (defined over \(X\)) and the cut (separating \(x\) from \(y\)) measure different things. The three-vertex counterexample is worked out in full in the Network docstring above. The repair is the hypothesis N.X = {N.x} (with N.Y = {N.y}), either as a structure field or on this statement. The skeleton assumes it — step 1 is not derivable without it.
Every unit shipped from \(x\) to \(y\) must squeeze through the cut, so no flow can exceed the cut’s throughput. This weak-duality bound is half of the max-flow min-cut theorem; the surprise of theorem 11.3 is that it is always attained. B&M record the special case immediately: val f* \(\le \) cap \(\tilde{K}\) (11.8).
The cut is a genuine bottleneck precisely when it runs at full capacity forwards and carries nothing backwards. This characterisation is exactly what the proof of theorem 11.2 verifies for the cut it constructs, which is why the equality condition is worth stating separately rather than folding into theorem 11.1.
The standard "weak duality certifies optimality" argument, the exact analogue of lemma 5.3 for matchings and coverings. It is what makes the labelling method self-verifying: when the algorithm stops it produces a matching flow and cut, and their equality proves both optimal.
(assumed silently by the book).
Nothing deep: finitely many flows, so a best one. Worth stating separately because corollary 11.1 and theorem 11.3 both open by invoking it, and because the zero flow is the only reason the set is nonempty.
Step 1 is where the \(\mathbb {N}\)-valued \(f\) and finite \(V\) pay off; note theorem 11.1’s bound is not needed — finiteness alone suffices, which is simpler than the book’s implicit reasoning and avoids the \(X\)/\(x\) defect.
(assumed silently by the book).
Finitely many subsets, at least one of them a cut, so a cheapest one.
! Step 1 needs N.x \(\ne \) N.y, which the Network structure does not provide — hdisj separates \(X\) from \(Y\) but says nothing about \(x\) and \(y\). This is a smaller instance of the structural gap recorded in the Network docstring, and the same repair (\(hx\), \(hy\) tying \(x\), \(y\) to \(X\), \(Y\)) supplies it, since hdisj then forces \(x \ne y\). Without it the statement is false for a network with \(x = y\), where no cut exists.
If the sink cannot be reached at all, nothing can be shipped and nothing needs to be cut.
! Step 4 uses theorem 11.1, so it inherits the \(X\)/\(x\) defect recorded in the Network docstring; with the repair N.X = {N.x} it goes through. The hypothesis is phrased with ReflTransGen over positive-capacity arcs rather than as "no directed \((x,y)\)-path", which is the same thing and needs no path API.
The minimum cuts form a lattice. A consequence is that there is a unique smallest minimum cut and a unique largest one, which is useful algorithmically.
Unaffected by the \(X\)/\(x\) defect — the argument is entirely about capOf and IsCut, never about val. Step 2 is a good candidate to prove first and independently.
B&M stress the analogy: *the rôle played by incrementing paths in flow theory is analogous to that of augmenting paths in matching theory* — compare Berge’s theorem 5.1.
Note steps 2–4 are exactly where IncPath being a walk rather than a path is convenient: \(S\) is a reachability closure, and closure under fwd and back is immediate for walks. ! Step 5 uses theorem 11.1 and corollary 11.1, so it inherits the \(X\)/\(x\) defect.
*If \(N\) contains no \(f\)-incrementing path, then there is a cut \(K\) with val f = cap K.*
The constructive core of theorem 11.2’s converse: the cut built from the \(f\)-unsaturated reachability set has capacity exactly val f.
* This has to be extracted separately because theorem 11.2’s statement asserts only maximality and discards the cut, while theorem 11.3 needs the cut itself. Fill this one first and derive theorem 11.2’s converse from it, rather than the other way round — otherwise the reachability construction has to be written twice.
Theorem 11.1 gave the easy half — val f \(\le \) cap K for every flow and cut; this says the bound is always achieved, so the bottleneck is not merely an upper limit but the exact answer. B&M call it *of central importance in graph theory: many results on graphs turn out to be easy consequences of this theorem as applied to suitably chosen networks*, as §§11.4 and 11.5 demonstrate with Menger’s theorems and the Gale–Ryser criterion.
The labelling method (Ford and Fulkerson, 1957), which the constructive proof yields: start from the zero flow and repeatedly grow an \(f\)-unsaturated tree from \(x\), until either it reaches \(y\) (breakthrough, giving an incrementing path to revise along) or it stops growing (certifying maximality by theorem 11.2). B&M note it is not a good algorithm — figure 11.9 gives a network needing \(2m + 1\) iterations for arbitrary \(m\) — but Edmonds and Karp (1970) showed that scanning "first-labelled first-scanned", i.e. always taking a shortest incrementing path, makes it good.
Steps 1–4 are all already-stated results, so this theorem is five lines once its inputs are filled — but it sits at the top of the dependency chain and inherits every defect below it, including the sorry-bodied \(\iota \) and revisedFlow via step 2.
With unit capacities a flow is a packing of arc-disjoint routes, each carrying one unit. This lemma is the bridge from flow theory to Menger.
! Two imported dependencies, both currently defective: step 1 needs chapter 10’s exercise 10.3.3, whose statement there mentions the sorry-bodied arcsOf; and B&M’s proof of that exercise adds \(l\) parallel arcs, which neither Digraph nor this file’s cap : V \(\to \) V \(\to \) \(\mathbb {N}\) carrier can express. ! Also note hunit : \(\forall \) u v, cap u v \(\le \) 1 permits cap = 0, i.e. absent arcs, which is what the book means by "each arc has unit capacity"; that reading is correct here.
With part (a) and the max-flow min-cut theorem, this immediately yields Menger’s arc theorem 11.4 — the whole of §11.4 rests on these two halves.
! Step 1 uses that with unit capacities cap S counts arcs; this needs hunit and that every counted arc actually exists (cap u v = 1, not \(0\)), so the sum-to-cardinality step deserves care.
The number of independent routes you can run equals the number of links an adversary must cut to stop you. This is the first of the four Menger theorems the chapter derives — arc/edge and vertex versions, for digraphs and graphs — two of which were quoted without proof back in §3.2.
! Steps 2 and 3 are not free: the network-level counts (Network.maxArcDisjointPaths) and the digraph-level ones (maxArcDisjointDirectedPaths) are separate stubbed definitions, so once both are repaired a lemma identifying them across the construction of step 1 will be needed. Defining the network-level pair in terms of the digraph-level pair applied to the underlying digraph would make steps 2–3 definitional and is the better design.
The undirected Menger theorem quoted in §3.2 as the edge analogue of Whitney’s theorem 3.2.
Step 2’s caveat is the one place where "a simple trick immediately yields" is doing real work; budget for it.
\(k\)-edge-connectedness says no \(k - 1\) edges disconnect the graph; by theorem 11.5 the minimum number of edges separating a specific pair equals the maximum number of edge-disjoint paths between them. Minimising over pairs converts the global statement into the local one. This is the edge form of Menger’s theorem quoted without proof in §3.2, generalising exercise 3.2.1 (\(k = 2\)) to all \(k\).
Uses the local edgeConnectivity copy. ! Watch the sInf \(\emptyset \) = 0 boundary flagged there: on a one-vertex graph no edge cut exists, so edgeConnectivity = 0, while the right-hand side is vacuously true for every \(k\) (there is no pair \(u \ne v\)). So the \(\leftrightarrow \) fails at \(k \ge 1\), card V \(\le \) 1 — a [Nontrivial V] hypothesis is the fix, exactly as in chapter 10’s associatedDigraph_isKArcConnected_iff.
! The hypothesis \(\lnot \) D.Adj x y is load-bearing: an arc \((x, y)\) cannot be destroyed by deleting intermediate vertices, so without it the right-hand side would be unattainable while the left is at least \(1\).
! Step 1 must contend with splitDigraph splitting \(x\) and \(y\) as well, contrary to the book — see that definition’s docstring. Concretely, a \(D'\)-path from inr x to inl y never traverses \(x\)’s or \(y\)’s corridor, so the correspondence is unharmed; but that fact needs stating rather than assuming.
The most quoted form of Menger’s theorem, and the one §3.2 announced without proof. The number of independent routes between two stations equals the number of intermediate stations an adversary must destroy to sever them — the vertex analogue of max-flow min-cut duality, specialising at \(k = 2\) to Whitney’s theorem 3.2.
Note step 2 is genuinely easier than the corresponding step of theorem 11.5, so this is the better of the two undirected Menger theorems to attempt first.
\(k\)-connectivity says no \(k - 1\) vertices disconnect the graph; theorem 11.7 converts the local separation number for a nonadjacent pair into a path count, and minimising over pairs converts global into local.
! B&M call this immediate; it is not — step 2 is genuine work, and the \(k = 2\) case alone is a full proof in the repo (TwoConnected.lean:537). Uses the local vertexConnectivity, whose \(\nu - 1\) fallback for complete graphs interacts with step 2 (a complete graph has only adjacent pairs), so check that boundary. h : k + 1 \(\le \) card V is the book’s \(\nu \ge k + 1\).
High connectivity forces any prescribed set of \(k\) vertices onto a single cycle. For \(k = 2\) this is corollary 3.2.1 — in a 2-connected graph any two vertices lie on a common cycle. One of the classic applications of Menger’s theorem, illustrating B&M’s remark that *many results on graphs turn out to be easy consequences* of max-flow min-cut.
Depends on exercise 11.4.3, hence on two sorry-bodied definitions; but note the statement here mentions none of them — it is about Walk/IsCycle only, so it is well-formed and would be meaningful once its dependency is repaired. Among the §11.4 items, this is the one whose statement is already honest.
A feasible flow exists exactly when, for every way of splitting the vertices, the capacity available for shipping into \(\bar{S}\) covers the net demand there — the demand of the sinks in \(\bar{S}\) less whatever supply already sits inside \(\bar{S}\). Necessity is obvious (that much material must cross the boundary); the content is sufficiency.
! Steps 3–4 use corollary 11.1 and theorem 11.3, both currently false for want of the N.X = {N.x} link — though note \(N'\) is built with a genuine single source and sink, so the repair is satisfied there; the defect bites only if one tries to apply those results to \(N\) itself. Step 1’s construction is the largest single piece of work in §11.5.
Equal sums (11.16) are necessary — both count the edges — but not sufficient, as \(p = q = (5,4,4,2,1)\) shows. Condition (11.18) adds that the \(k\) largest demands can actually be met: each \(x_{i}\) can supply at most min{p\(_{i}\), k} of them, having only \(p_{i}\) edges and only \(k\) targets.
Matrix form. Let \(B*\) have its first \(p_{i}\) entries of row \(i\) equal to \(1\), and let \(p*\) be its column sums — the conjugate of \(p\) (that of \((5,4,4,2,1)\) is \((5,4,3,3,1)\)). Row \(i\) contributes min{p\(_{i}\), k} to \(\sum _{j\le k} p*_{j}\), so (11.18) says exactly \(\sum _{j\le k} p*_{j} \ge \sum _{j\le k} q_{j}\) — the conjugate of \(p\) dominates \(q\). Due to Ryser (1957).
The chapter’s hardest item. \(k\) is a Fin n and the book’s \(1 \le k \le n\) becomes k.val + 1 in the min, so check the off-by-one against the book when filling. The \((0,1)\)-matrix carrier is used rather than a bipartite-graph predicate; see RealisableBipartite.
The bipartite analogue of the Havel–Hakimi reduction for degree sequences (exercise 1.5.7): the vertex \(x_{1}\) may as well spend its \(p_{1}\) edges on the \(p_{1}\) highest-demand vertices of \(Y\). Part (b) — dropped here as procedural — turns this into a construction algorithm.
! Two departures, both flagged in the source comment. (i) \(q'\) uses truncated natural subtraction (\(q j - 1\) is \(0\) when \(q j = 0\)), which is harmless only because a realisable \(q\) has \(q j \ge 1\) wherever row \(0\) puts an edge — worth checking rather than assuming. (ii) B&M’s \(q'\) is re-sorted into nonincreasing order, which this statement elides; without re-sorting, \(q'\) need not satisfy (11.17), so this reduction cannot be chained with theorem 11.9 as the book intends. If the intent is to iterate the reduction, the re-sorting must be restored.
An \((m+n)\)-regular graph is to be oriented so every indegree is \(m\) or \(n\). The partition names in advance which vertices get which, and the inequality is a feasibility condition in Gale’s sense.
! Step 2 needs an eulerian orientation, which comes from chapters 4 and 10 (every graph with all degrees even has an Euler tour; orient along it) — a genuine import, absent from this file. Note \((m+n)\)-regular forces every degree even only when \(m + n\) is even, so the eulerian step may itself need the odd-degree patch of chapter 10’s exercise 10.1.10. The absolute value is written as a two-sided bound to avoid abs and keep the arithmetic in \(\mathbb {Z}\).
The two permitted indegrees can always be moved one step closer together. Iterating, an \((m,n)\)-orientable graph is \((m',n')\)-orientable for every admissible pair with \(m' + n' = m + n\) and \(|m' - n'| \le |m - n|\) — in particular the most balanced orientation is always available.
A short deduction given part (a), which is the starred and substantial half. Step 2’s "scales down" should be checked at the sign: the bound is two-sided, so both directions shrink only because \(|m - n - 2| \le |m - n|\) when \(m - n \ge 1\).