1-- The expansion of a bridgeless graph is bridgeless, and an even double2-- cover of the expansion projects along the spokes to an even double cover3-- of the graph.4-- Part of Cumulus, the Grace17 mathematics library.5-- Copyright (c) 2026 Grant Passmore.6-- Released under the Apache License 2.0. See LICENSE in the repository root.7-- Authors: Grant Passmore89module Grace.Cumulus.GraphTheory.DoubleCover.Projection10import Expansion1112-- Section: Bridgelessness.1314-- A set with one element has a member that every member equals.15theorem cardinality.member_of_one (A : Set)16requires finite : Finite(A)17requires one : cardinality(A) =118shows∃ a ∈ A, ∀ x ∈ A, x = a19proof20have inhabited : A ≠∅21intro empty22rw [empty, cardinality.empty] at one23contradiction24obtain⟨a, ha⟩:= Nonempty.of_ne_empty with inhabited25have count := cardinality.remove_add_one with finite, ha26have restFinite := Finite.difference at A, {a} with finite27have zero : cardinality(A ∖ {a}) =0byarith28have rest := cardinality.eq_empty_of_zero with restFinite, zero29refine⟨a, ha, _⟩30intros x hx31by_contra different32have outside : x ∈ A ∖ {a} bysimp [hx, different]33rw rest at outside34simpat outside3536-- A vertex of degree one has a single end (e, i), and e is then the one37-- edge leaving {v}: a bridge. So a bridgeless graph has no such vertex.38theorem Bridgeless.degrees (V E leftEnd rightEnd : Set)39requires graph : Graph(V, E, leftEnd, rightEnd)40requires finiteEdges : Finite(E)41requires bridgeless : Bridgeless(V, E, leftEnd, rightEnd)42shows∀ v ∈ V, degreeIn(leftEnd, rightEnd, E, v) ≠143proof44intros v hv one45unfold degreeIn at one46have finiteEnds := incidentEnds.finite at leftEnd, rightEnd, E, v47with finiteEdges48obtain⟨p, hp, only⟩:= cardinality.member_of_one with finiteEnds, one49obtain⟨e, he, i, hi, rfl⟩:= incidentEnds.shape with hp50-- An edge leaving {v} has an end at v, so it is e; and e does leave {v},51-- since its other end is not at v.52have cut : crossing(leftEnd, rightEnd, E, {v}) = {e}53ext f54constructor55 . intro hf56obtain⟨inE, crosses⟩:= hf57simpat crosses58cases crosses with atLeft | atRight59 . haveend : (f, 0) ∈ incidentEnds(leftEnd, rightEnd, E, v)60simp [incidentEnds.pair, inE, atLeft]61have same := only with (f, 0), end62obtain⟨rfl, _⟩:= orderedPair.injective with same63simp64 . haveend : (f, 1) ∈ incidentEnds(leftEnd, rightEnd, E, v)65simp [incidentEnds.pair, inE, atRight]66have same := only with (f, 1), end67obtain⟨rfl, _⟩:= orderedPair.injective with same68simp69 . intro hf70simpat hf71rw hf72refine⟨he, _⟩73have sides := (incidentEnds.pair.forward with hp).right74rcases sides with⟨rfl, atLeft⟩|⟨rfl, atRight⟩75 . have notRight : rightEnd(e) ≠ v76intro atRight77haveend : (e, 1) ∈ incidentEnds(leftEnd, rightEnd, E, v)78simp [incidentEnds.pair, he, atRight]79have same := only with (e, 1), end80have oneZero := (orderedPair.injective with same).right81contradiction82simp [atLeft, notRight]83 . have notLeft : leftEnd(e) ≠ v84intro atLeft85haveend : (e, 0) ∈ incidentEnds(leftEnd, rightEnd, E, v)86simp [incidentEnds.pair, he, atLeft]87have same := only with (e, 0), end88have oneZero := (orderedPair.injective with same).right89contradiction90simp [atRight, notLeft]91have inV : {v} ⊆ V := singleton.subset_iff.backward with hv92have bridge := bridgeless with {v}, inV93rw [cut, cardinality.singleton] at bridge94exact bridge withrfl9596-- The vertices all of whose ends lie in a set X of ends.97def enclosed (V E leftEnd rightEnd X : Set) : Set:=98 { v ∈ V | incidentEnds(leftEnd, rightEnd, E, v) ⊆ X }99100-- When X holds all or none of the ends at each vertex, an end of e lies in X101-- exactly when its vertex is enclosed.102theorem enclosed.left (V E leftEnd rightEnd X e : Set)103requires graph : Graph(V, E, leftEnd, rightEnd)104requires edge : e ∈ E105requires whole : ∀ v ∈ V, ∀ h ∈ incidentEnds(leftEnd, rightEnd, E, v),106 h ∈ X →∀ k ∈ incidentEnds(leftEnd, rightEnd, E, v), k ∈ X107shows (e, 0) ∈ X ↔ leftEnd(e) ∈ enclosed(V, E, leftEnd, rightEnd, X)108proof109have inV := (Graph.ends with graph, e, edge).left110have atLeft : (e, 0) ∈ incidentEnds(leftEnd, rightEnd, E, leftEnd(e))111simp [incidentEnds.pair, edge]112constructor113 . intro inX114exact⟨inV, (whole with leftEnd(e), inV, (e, 0), atLeft, inX)⟩115 . intro inside116exact inside.right with (e, 0), atLeft117118theorem enclosed.right (V E leftEnd rightEnd X e : Set)119requires graph : Graph(V, E, leftEnd, rightEnd)120requires edge : e ∈ E121requires whole : ∀ v ∈ V, ∀ h ∈ incidentEnds(leftEnd, rightEnd, E, v),122 h ∈ X →∀ k ∈ incidentEnds(leftEnd, rightEnd, E, v), k ∈ X123shows (e, 1) ∈ X ↔ rightEnd(e) ∈ enclosed(V, E, leftEnd, rightEnd, X)124proof125have inV := (Graph.ends with graph, e, edge).right126have atRight : (e, 1) ∈ incidentEnds(leftEnd, rightEnd, E, rightEnd(e))127simp [incidentEnds.pair, edge]128constructor129 . intro inX130exact⟨inV, (whole with rightEnd(e), inV, (e, 1), atRight, inX)⟩131 . intro inside132exact inside.right with (e, 1), atRight133134-- When no ring edge leaves X, the edges of the expansion leaving X are the135-- spokes of the edges leaving the enclosed vertices.136theorem enclosed.crossing (V E leftEnd rightEnd σ X : Set)137requires graph : Graph(V, E, leftEnd, rightEnd)138requires rotation : RotationSystem(V, E, leftEnd, rightEnd, σ)139requires stable : ∀ h ∈ halfEdges(E), (h ∈ X ↔ σ(h) ∈ X)140requires whole : ∀ v ∈ V, ∀ h ∈ incidentEnds(leftEnd, rightEnd, E, v),141 h ∈ X →∀ k ∈ incidentEnds(leftEnd, rightEnd, E, v), k ∈ X142shows crossing(expandedLeft(E, σ), expandedRight(E, σ),143 expandedEdges(E), X) =144 {0} × crossing(leftEnd, rightEnd, E, enclosed(V, E, leftEnd, rightEnd, X))145proof146have function := RotationSystem.function with rotation147ext x148constructor149 . intro hx150obtain⟨inExpanded, crosses⟩:= hx151havesplit:= expandedEdges.cases with inExpanded152rcasessplitwith⟨e, he, rfl⟩|⟨h, hh, rfl⟩153 . rw [(expandedLeft.spoke with he),154 (expandedRight.spoke with function, he),155 (enclosed.left with graph, he, whole),156 (enclosed.right with graph, he, whole)] at crosses157apply product.pair_membership.backward158constructor159 . simp160 . exact⟨he, crosses⟩161 . rw [(expandedLeft.ring with hh),162 (expandedRight.ring with function, hh)] at crosses163have same := stable with h, hh164exfalso165tauto166 . intro hx167obtain⟨_, z, hz, e, he, rfl⟩:= product.membership.forward with hx168simpat hz169rw hz170obtain⟨inE, crosses⟩:= he171refine⟨(spokes.edge with inE), _⟩172rw [(expandedLeft.spoke with inE),173 (expandedRight.spoke with function, inE),174 (enclosed.left with graph, inE, whole),175 (enclosed.right with graph, inE, whole)]176exact crosses177178-- A cut of the expansion crossed by one edge is crossed by no ring edge, as179-- the ring edges form an even edge set; so it holds all or none of the ends180-- at each vertex, and pulling the ends of each vertex together gives a cut181-- of the graph crossed by one edge.182theorem expansion.bridgeless (V E leftEnd rightEnd σ : Set)183requires graph : Graph(V, E, leftEnd, rightEnd)184requires finiteVertices : Finite(V)185requires finiteEdges : Finite(E)186requires rotation : RotationSystem(V, E, leftEnd, rightEnd, σ)187requires bridgeless : Bridgeless(V, E, leftEnd, rightEnd)188shows Bridgeless(halfEdges(E), expandedEdges(E),189 expandedLeft(E, σ), expandedRight(E, σ))190proof191intros X subset one192have function := RotationSystem.function with rotation193have finiteRingCut : Finite(crossing(expandedLeft(E, σ),194 expandedRight(E, σ), rings(E), X)) :=195 crossing.finite with (rings.finite with finiteEdges)196-- No ring edge leaves X: an even number of them do, and at most one.197have evenCount := EvenEdgeSet.crossing_even198with (halfEdges.finite with finiteEdges),199 (rings.even with finiteEdges, rotation.left), subset200have ringsInside : rings(E) ⊆ expandedEdges(E)201unfold expandedEdges202exact union2.subset_right203have ringCut :204 crossing(expandedLeft(E, σ), expandedRight(E, σ), rings(E), X) ⊆205 crossing(expandedLeft(E, σ), expandedRight(E, σ), expandedEdges(E), X) :=206 crossing.monotone with ringsInside207have bound := cardinality.monotone208with (crossing.finite with (expandedEdges.finite with finiteEdges)),209 ringCut210rw one at bound211obtain⟨m, hm, double⟩:= evenCount212have zero : cardinality(crossing(expandedLeft(E, σ), expandedRight(E, σ),213 rings(E), X)) =0214rw double at bound215rw double216arith217have noRing := cardinality.eq_empty_of_zero with finiteRingCut, zero218have stable : ∀ h ∈ halfEdges(E), (h ∈ X ↔ σ(h) ∈ X)219intros h hh220by_contra221have crosses : (1, h) ∈ crossing(expandedLeft(E, σ),222 expandedRight(E, σ), rings(E), X)223refine⟨(rings.member with hh), _⟩224rw [(expandedLeft.ring with hh), (expandedRight.ring with function, hh)]225tauto226rw noRing at crosses227simpat crosses228-- So X holds all the ends at a vertex or none: σ runs through them all.229have whole : ∀ v ∈ V, ∀ h ∈ incidentEnds(leftEnd, rightEnd, E, v),230 h ∈ X →∀ k ∈ incidentEnds(leftEnd, rightEnd, E, v), k ∈ X231intros v hv h hh inX k hk232obtain⟨n, hn, reach⟩:= rotation.right.right with v, hv, h, hh, k, hk233have closed : ∀ x ∈ X, σ(x) ∈ X234intros x hx235exact (stable with x, (subset with x, hx)).forward with hx236rw← reach237exact orbitStep.closed with closed, inX238-- The enclosed vertices are then left by exactly one edge of the graph.239have enclosedSubset : enclosed(V, E, leftEnd, rightEnd, X) ⊆ V240intros v hv241exact hv.left242rw [(enclosed.crossing with graph, rotation, stable, whole),243 (cardinality.singleton_product244with (crossing.finite with finiteEdges))] at one245exact bridgeless with enclosed(V, E, leftEnd, rightEnd, X),246 enclosedSubset, one247248-- Section: Projection.249250-- The projection of an edge set of the expansion: the edges whose spokes it251-- holds.252def projected (E F : Set) : Set:= { e ∈ E | (0, e) ∈ F }253254theorem projected.subset (E F : Set)255shows projected(E, F) ⊆ E256proof257intros e he258exact he.left259260-- The edges of F leaving the ends at v are the spokes of the edges of the261-- projection leaving v: a ring edge has both ends at one vertex.262theorem projected.crossing (V E leftEnd rightEnd σ F v : Set)263requires graph : Graph(V, E, leftEnd, rightEnd)264requires rotation : RotationSystem(V, E, leftEnd, rightEnd, σ)265requires edges : F ⊆ expandedEdges(E)266requires vertex : v ∈ V267shows crossing(expandedLeft(E, σ), expandedRight(E, σ), F,268 incidentEnds(leftEnd, rightEnd, E, v)) =269 {0} × crossing(leftEnd, rightEnd, projected(E, F), {v})270proof271have function := RotationSystem.function with rotation272ext x273constructor274 . intro hx275obtain⟨inF, crosses⟩:= hx276havesplit:= expandedEdges.cases with (edges with x, inF)277rcasessplitwith⟨e, he, rfl⟩|⟨h, hh, rfl⟩278 . rw [(expandedLeft.spoke with he), (expandedRight.spoke with function, he),279 (incidentEnds.left with he), (incidentEnds.right with he)] at crosses280apply product.pair_membership.backward281constructor282 . simp283 . have inProjection : e ∈ projected(E, F) :=⟨he, inF⟩284refine⟨inProjection, _⟩285simp286 . rw [(expandedLeft.ring with hh),287 (expandedRight.ring with function, hh)] at crosses288have same := RotationSystem.at_vertex with graph, rotation, vertex, hh289exfalso290tauto291 . intro hx292obtain⟨_, z, hz, e, he, rfl⟩:= product.membership.forward with hx293simpat hz294rw hz295obtain⟨inProjection, crosses⟩:= he296obtain⟨inE, inF⟩:= inProjection297refine⟨inF, _⟩298rw [(expandedLeft.spoke with inE), (expandedRight.spoke with function, inE),299 (incidentEnds.left with inE), (incidentEnds.right with inE)]300simpat crosses301tauto302303-- The projection of an even edge set is even: the edges of the projection304-- leaving v are counted by the edges of F leaving the ends at v, an even305-- number.306theorem projected.even (V E leftEnd rightEnd σ F : Set)307requires graph : Graph(V, E, leftEnd, rightEnd)308requires finiteEdges : Finite(E)309requires rotation : RotationSystem(V, E, leftEnd, rightEnd, σ)310requires edges : F ⊆ expandedEdges(E)311requires even : EvenEdgeSet(halfEdges(E), expandedLeft(E, σ),312 expandedRight(E, σ), F)313shows EvenEdgeSet(V, leftEnd, rightEnd, projected(E, F))314proof315have finiteProjected : Finite(projected(E, F)) :=316 Finite.subset with finiteEdges, projected.subset317constructor318 . exact finiteProjected319 . intros v hv320have finiteEnds := halfEdges.finite with finiteEdges321have finitePoint : Finite({v}) := Finite.singleton322have subset := incidentEnds.subset_halfEdges at leftEnd, rightEnd, E, v323have evenCut := EvenEdgeSet.crossing_even with finiteEnds, even, subset324rw [(projected.crossing with graph, rotation, edges, hv),325 (cardinality.singleton_product326with (crossing.finite with finiteProjected)),327 (crossing.parity with finitePoint, finiteProjected)] at evenCut328have inSingleton : v ∈ {v} bysimp329have weight := degreeWeights.value330at {v}, leftEnd, rightEnd, projected(E, F), v331with finiteProjected, inSingleton332have natural :333 degreeWeights({v}, leftEnd, rightEnd, projected(E, F))(v) ∈ ℕ334rw weight335exact degreeIn.natural with finiteProjected336rw [(natSum.singleton with natural), weight] at evenCut337exact evenCut338339-- The projection of a family of edge sets, member by member.340def projectedFamily (E H I : Set) : Set:=341 { p ∈ I ×𝒫(E) |∃ i ∈ I, p = (i, projected(E, H(i))) }342343theorem projectedFamily.function (E H I : Set)344shows projectedFamily(E, H, I) : I →𝒫(E)345proof346constructor347 . intros p member348exact member.left349constructor350 . intros x y relatedY z relatedZ351obtain⟨_, a, _, shapeY⟩:= relatedY352obtain⟨_, b, _, shapeZ⟩:= relatedZ353obtain⟨sameA, valueY⟩:= orderedPair.injective with shapeY354obtain⟨sameB, valueZ⟩:= orderedPair.injective with shapeZ355cc356 . intros i hi357have inside : projected(E, H(i)) ∈𝒫(E) :=358 powerset.membership.backward with projected.subset359refine⟨projected(E, H(i)), inside, _⟩360exact projectedFamily.membership.backward361with⟨(product.pair with hi, inside), i, hi, rfl⟩362363theorem projectedFamily.value (E H I i : Set)364requires index : i ∈ I365shows projectedFamily(E, H, I)(i) = projected(E, H(i))366proof367have inside : projected(E, H(i)) ∈𝒫(E) :=368 powerset.membership.backward with projected.subset369have related : relates(projectedFamily(E, H, I), i, projected(E, H(i))) :=370 projectedFamily.membership.backward371with⟨(product.pair with index, inside), i, index, rfl⟩372exact FunctionBetween.apply_value373with projectedFamily.function, index, related374375-- The members of the projected family holding e are those holding its spoke.376theorem projected.holding (E H I e : Set)377requires edge : e ∈ E378shows holding(projectedFamily(E, H, I), I, e) = holding(H, I, (0, e))379proof380ext i381 by_cases hi : i ∈ I382 . have value := projectedFamily.value at E, H, I, i with hi383simp [holding, projected, value, hi, edge]384 . simp [holding, hi]385386-- An even double cover of the expansion projects to one of the graph: each387-- member projects to an even edge set, and an edge is held as often as its388-- spoke.389theorem projected.double_cover (V E leftEnd rightEnd σ H I : Set)390requires graph : Graph(V, E, leftEnd, rightEnd)391requires finiteEdges : Finite(E)392requires rotation : RotationSystem(V, E, leftEnd, rightEnd, σ)393requires cover : EvenDoubleCover(halfEdges(E), expandedEdges(E),394 expandedLeft(E, σ), expandedRight(E, σ), H, I)395shows EvenDoubleCover(V, E, leftEnd, rightEnd, projectedFamily(E, H, I), I)396proof397obtain⟨finiteIndex, family, evens, twice⟩:= cover398refine⟨finiteIndex, projectedFamily.function, _, _⟩399 . intros i hi400rw projectedFamily.value with hi401have edges : H(i) ⊆ expandedEdges(E) :=402 powerset.membership.forward403with (FunctionBetween.apply_closed with family, hi)404exact projected.even405with graph, finiteEdges, rotation, edges, (evens with i, hi)406 . intros e he407have spoke := twice with (0, e), (spokes.edge with he)408unfold multiplicity at spoke409unfold multiplicity410rw projected.holding with he411exact spoke412