1-- Every finite bridgeless multigraph has an even cover: the eight-flow2-- theorem of Jaeger and Kilpatrick, by induction on the number of vertices3-- through cuts of size zero and two, with three spanning trees in the4-- 3-edge-connected case.5-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.GraphTheory.Flows.EightFlow11import Splits1213-- Section: The cases of the induction.1415-- A bridgeless graph that is neither split nor 3-edge-connected has a cut of16-- exactly two edges, and both of its edges are proper.17theorem Bridgeless.two_cut (V E leftEnd rightEnd : Set)18requires graph : Graph(V, E, leftEnd, rightEnd)19requires finiteVertices : Finite(V)20requires finiteEdges : Finite(E)21requires bridgeless : Bridgeless(V, E, leftEnd, rightEnd)22requires unsplit : ∀ X ⊆ V, X ≠∅→ X ≠ V →23 crossing(leftEnd, rightEnd, E, X) ≠∅24requires loose : ¬EdgeConnected(V, E, leftEnd, rightEnd, 3)25shows∃ X, ∃ e ∈ E, ∃ f ∈ E, X ⊆ V ∧ e ≠ f ∧26 crossing(leftEnd, rightEnd, E, X) = {e, f}27proof28-- Some nonempty proper vertex set is left by fewer than three edges.29have witnessX : ∃ X ⊆ V, X ≠∅∧ X ≠ V ∧30¬(3≤ cardinality(crossing(leftEnd, rightEnd, E, X)))31by_contra none32apply loose33intros X bound nonempty proper34by_contra few35exact none with⟨X, bound, nonempty, proper, few⟩36obtain⟨X, bound, nonempty, proper, few⟩:= witnessX37have finiteCut := crossing.finite at leftEnd, rightEnd, E, X with finiteEdges38have natCut := cardinality.nat with finiteCut39have notOne := bridgeless with X, bound40have notZero : cardinality(crossing(leftEnd, rightEnd, E, X)) ≠041intro zero42exact unsplit with X, bound, nonempty, proper,43 (cardinality.eq_empty_of_zero with finiteCut, zero)44-- Neither zero, one, nor three or more: the cut has exactly two edges.45have less := Less.of_not_LessEqual with few46have upper : cardinality(crossing(leftEnd, rightEnd, E, X)) ≤2byarith47have lower : 2≤ cardinality(crossing(leftEnd, rightEnd, E, X))48havecases:= natural.zero_one_or_above_one49at cardinality(crossing(leftEnd, rightEnd, E, X))50rcasescaseswith zero | one | above51 . exfalso52exact notZero with zero53 . exfalso54exact notOne with one55 . have strict := Less.of_membership with above56arith57have two := LessEqual.antisymmetric with upper, lower58-- One edge of the cut, and the rest is a single other edge.59have positive : 0 < cardinality(crossing(leftEnd, rightEnd, E, X)) byarith60obtain⟨e, he⟩:= cardinality.member_of_positive with finiteCut, positive61have removed := cardinality.remove_add_one with finiteCut, he62have oneLeft : cardinality(crossing(leftEnd, rightEnd, E, X) ∖ {e}) =163arith64have finiteRest := Finite.difference65at crossing(leftEnd, rightEnd, E, X), {e} with finiteCut66have oneIff := cardinality.one_iff with finiteRest67obtain⟨f, single⟩:= oneIff.forward with oneLeft68have fMember : f ∈ crossing(leftEnd, rightEnd, E, X) ∖ {e}69rw single70exact singleton.self71obtain⟨fIn, fNotE⟩:= difference.membership.forward with fMember72have distinct : e ≠ f73intro same74apply fNotE75rw same76exact singleton.self77have cutEdges := crossing.subset at leftEnd, rightEnd, E, X78refine⟨X, e, (cutEdges with e, he), f, (cutEdges with f, fIn),79 bound, distinct, _⟩80ext g81constructor82 . intro hg83 by_cases ge : g = e84 . simp [ge]85 . have inRest : g ∈ crossing(leftEnd, rightEnd, E, X) ∖ {e}86simp [hg, ge]87rw single at inRest88simpat inRest89simp [inRest]90 . intro hg91simpat hg92rcases hg withrfl|rfl93 . exact he94 . exact fIn9596-- One vertex: every edge is a loop and E itself is an even set.97theorem EvenCover.single_vertex (V E leftEnd rightEnd : Set)98requires graph : Graph(V, E, leftEnd, rightEnd)99requires finiteEdges : Finite(E)100requires single : ∃ v, V = {v}101shows∃ F, EvenCover(V, E, leftEnd, rightEnd, F)102proof103obtain⟨v, rfl⟩:= single104have endsE := Graph.ends with graph105have vertex : v ∈ {v} := singleton.self106-- Every edge is a loop at v, so E is even: its degree at v is 2|E|.107have even : EvenEdgeSet({v}, leftEnd, rightEnd, E)108constructor109 . exact finiteEdges110 . intros w hw111rw singleton.membership at hw112rw hw113have sum := degreeIn.handshake114with (Finite.singleton at v), finiteEdges, endsE115have weights := degreeWeights.natural at {v}, leftEnd, rightEnd, E116with finiteEdges117rw [(natSum.singleton with (weights with v, vertex)),118 (degreeWeights.value with finiteEdges, vertex)] at sum119rw sum120exact Even.two_mul121have member : E ∈𝒫(E) :=122 powerset.membership_iff.backward with Subset.reflexive123have values := tripleMap.value with member, member, member124have zero : 0∈3bysimp [membership.three]125witness tripleMap(𝒫(E), E, E, E)126refine⟨(tripleMap.function with member, member, member), _, _⟩127 . intros i hi128havecases:= membership.three.forward with hi129rcasescaseswithrfl|rfl|rfl130 . rw values.left131exact even132 . rw values.right.left133exact even134 . rw values.right.right135exact even136 . intros e he137refine⟨0, zero, _⟩138rw values.left139exact he140141-- Without vertices there are no edges, and the empty triple is a cover.142theorem EvenCover.of_no_vertices (V E leftEnd rightEnd : Set)143requires graph : Graph(V, E, leftEnd, rightEnd)144requires noVertices : V =∅145shows∃ F, EvenCover(V, E, leftEnd, rightEnd, F)146proof147have noEdges : E =∅148ext e149constructor150 . intro he151have inV := (Graph.ends with graph, e, he).left152rw noVertices at inV153simpat inV154 . intro he155simpat he156have member : ∅∈𝒫(E) :=157 powerset.membership_iff.backward with empty.subset158have values := tripleMap.value with member, member, member159witness tripleMap(𝒫(E), ∅, ∅, ∅)160refine⟨(tripleMap.function with member, member, member), _, _⟩161 . intros i hi162havecases:= membership.three.forward with hi163rcasescaseswithrfl|rfl|rfl164 . rw values.left165exact EvenEdgeSet.empty166 . rw values.right.left167exact EvenEdgeSet.empty168 . rw values.right.right169exact EvenEdgeSet.empty170 . intros e he171rw noEdges at he172simpat he173174-- Section: The eight-flow theorem.175176-- A side of a split, with the ends restricted to its inside, is a finite177-- bridgeless graph on fewer vertices; the induction hypothesis covers it, and178-- the cover is one for the original ends.179theorem eightFlow.side (V E leftEnd rightEnd X : Set, n : Nat)180requires graph : Graph(V, E, leftEnd, rightEnd)181requires finiteVertices : Finite(V)182requires finiteEdges : Finite(E)183requires bridgeless : Bridgeless(V, E, leftEnd, rightEnd)184requiressplit : X ⊆ V ∧ crossing(leftEnd, rightEnd, E, X) =∅185requires proper : X ≠ V186requires bound : cardinality(V) ≤ n +1187requires ih : ∀ W, ∀ D, ∀ leftW, ∀ rightW,188 Graph(W, D, leftW, rightW) → Finite(W) → Finite(D) →189 Bridgeless(W, D, leftW, rightW) → cardinality(W) ≤ n →190∃ F, EvenCover(W, D, leftW, rightW, F)191shows∃ F, EvenCover(X, inside(leftEnd, rightEnd, E, X), leftEnd, rightEnd,192 F)193proof194have edges := inside.subset at leftEnd, rightEnd, E, X195have sideGraph := inside.graph with graph, split.left196have sideBridgeless := inside.bridgeless with graph, split, bridgeless197have finiteX := Finite.subset with finiteVertices, split.left198have finiteInside := Finite.subset with finiteEdges, edges199have less := cardinality.strict_of_ne with finiteVertices, split.left, proper200have smaller : cardinality(X) ≤ n byarith201have recursive := ih with X, inside(leftEnd, rightEnd, E, X),202 restrict(leftEnd, inside(leftEnd, rightEnd, E, X)),203 restrict(rightEnd, inside(leftEnd, rightEnd, E, X))204obtain⟨F, cover⟩:= recursive205with sideGraph, finiteX, finiteInside, sideBridgeless, smaller206exact⟨F, (EvenCover.of_restricted with graph, edges, cover)⟩207208-- The theorem, by induction on the number of vertices: a split joins the209-- covers of its two sides, a cut of two edges contracts one of them to a210-- graph with one vertex fewer, and otherwise the graph is 3-edge-connected.211theorem eightFlow.of_vertex_count (n : Nat)212shows∀ V, ∀ E, ∀ leftEnd, ∀ rightEnd,213 Graph(V, E, leftEnd, rightEnd) → Finite(V) → Finite(E) →214 Bridgeless(V, E, leftEnd, rightEnd) → cardinality(V) ≤ n →215∃ F, EvenCover(V, E, leftEnd, rightEnd, F)216proof217induction n218| zero =>219intros V E leftEnd rightEnd graph finiteVertices finiteEdges bridgeless220 bound221have natV := cardinality.nat with finiteVertices222have zero : cardinality(V) =0byarith223exact EvenCover.of_no_vertices224with graph, (cardinality.eq_empty_of_zero with finiteVertices, zero)225| k +1using ih =>226intros V E leftEnd rightEnd graph finiteVertices finiteEdges bridgeless227 bound228have endsE := Graph.ends with graph229have natV := cardinality.nat with finiteVertices230 by_cases nonempty : V =∅231 . exact EvenCover.of_no_vertices with graph, nonempty232 by_cases unsplit : ∀ X ⊆ V, X ≠∅→ X ≠ V →233 crossing(leftEnd, rightEnd, E, X) ≠∅234 . by_cases connected : EdgeConnected(V, E, leftEnd, rightEnd, 3)235 . exact EvenCover.of_three_edge_connected236with graph, finiteVertices, finiteEdges, nonempty, connected237 . -- A cut of two edges: contract one of them and lift the cover.238obtain⟨X, e, eInE, f, fInE, subset, distinct, cut⟩:=239 Bridgeless.two_cut with graph, finiteVertices, finiteEdges,240 bridgeless, unsplit, connected241have eInCut : e ∈ crossing(leftEnd, rightEnd, E, X)242rw cut243exact pair.left244have proper : leftEnd(e) ≠ rightEnd(e)245intro same246rcases eInCut.right with⟨leftX, rightX⟩|⟨rightX, leftX⟩247 . rw same at leftX248exact rightX with leftX249 . rw same at leftX250exact leftX with rightX251have count := contraction.vertex_count252with graph, finiteVertices, eInE, proper253have finiteClasses :254 Finite(contractionPartition(V, leftEnd, rightEnd, e))255unfold contractionPartition256exact componentsBy.finite with finiteVertices257have natClasses := cardinality.nat with finiteClasses258have smaller :259 cardinality(contractionPartition(V, leftEnd, rightEnd, e)) ≤ k260arith261have recursive := ih262with contractionPartition(V, leftEnd, rightEnd, e), E ∖ {e},263 contractedLeft(V, E, leftEnd, rightEnd, e),264 contractedRight(V, E, leftEnd, rightEnd, e)265obtain⟨F, cover⟩:= recursive266with (contraction.graph with graph, eInE), finiteClasses,267 (Finite.difference with finiteEdges),268 (contraction.bridgeless with graph, finiteEdges, eInE, bridgeless),269 smaller270exact contraction.lift_cover with graph, finiteVertices, finiteEdges,271⟨subset, cut, distinct⟩, cover272 . -- A nonempty proper vertex set left by no edge: cover each side.273have witnessX : ∃ X ⊆ V, X ≠∅∧ X ≠ V ∧274 crossing(leftEnd, rightEnd, E, X) =∅275by_contra none276apply unsplit277intros X inV nonemptyX properX split278exact none with⟨X, inV, nonemptyX, properX, split⟩279obtain⟨X, subsetX, nonemptyX, properX, none⟩:= witnessX280have complement : V ∖ X ⊆ V ∧281 crossing(leftEnd, rightEnd, E, V ∖ X) =∅282refine⟨difference.subset_left, _⟩283rw crossing.complement with endsE284exact none285have properY : V ∖ X ≠ V286intro same287obtain⟨v, hv⟩:= Nonempty.of_ne_empty with nonemptyX288have inV := subsetX with v, hv289rw← same at inV290exact (difference.membership.forward with inV).right with hv291obtain⟨F, coverX⟩:= eightFlow.side with graph, finiteVertices,292 finiteEdges, bridgeless, ⟨subsetX, none⟩, properX, bound, ih293obtain⟨G, coverY⟩:= eightFlow.side with graph, finiteVertices,294 finiteEdges, bridgeless, complement, properY, bound, ih295exact EvenCover.join with graph, ⟨subsetX, none⟩, coverX, coverY296297theorem eightFlow (V E leftEnd rightEnd : Set)298requires graph : Graph(V, E, leftEnd, rightEnd)299requires finiteVertices : Finite(V)300requires finiteEdges : Finite(E)301requires bridgeless : Bridgeless(V, E, leftEnd, rightEnd)302shows∃ F, EvenCover(V, E, leftEnd, rightEnd, F)303proof304have natV := cardinality.nat with finiteVertices305have all := eightFlow.of_vertex_count at cardinality(V)306exact all with V, E, leftEnd, rightEnd, graph, finiteVertices, finiteEdges,307 bridgeless, (LessEqual.reflexive at cardinality(V))308