1-- Cycles in even edge sets: a cycle is a nonempty even edge set with every2-- degree 0 or 2 whose edges are joined to one another, every nonempty even3-- edge set contains a cycle, and a finite even edge set splits into cycles.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.Cycles10import Covers11import Cardinal.FiniteUnion1213-- Section: Cycles in even sets.1415-- A cycle: a nonempty even edge set in which every vertex has degree 0 or 216-- and whose edges are all joined to one another.17predicate Cycle (V leftEnd rightEnd C : Set) :=18 C ≠∅∧ EvenEdgeSet(V, leftEnd, rightEnd, C) ∧19 (∀ v ∈ V, degreeIn(leftEnd, rightEnd, C, v) =0∨20 degreeIn(leftEnd, rightEnd, C, v) =2) ∧21 (∀ e ∈ C, ∀ f ∈ C,22 Joined(leftEnd, rightEnd, C, leftEnd(e), leftEnd(f)))2324-- A nonempty even edge set that is not a cycle has a proper nonempty even25-- subset: the edges into one component when two edges are not joined, and26-- a path closed by two edges at a vertex of degree other than two.2728-- The edges of C whose left end lies in A. When A is closed under C they29-- carry every end of C at a vertex of A and none elsewhere.30def edgesInto (leftEnd C A : Set) : Set:= { e ∈ C | leftEnd(e) ∈ A }3132theorem edgesInto.subset (leftEnd C A : Set)33shows edgesInto(leftEnd, C, A) ⊆ C34proof35intros e he36exact he.left3738theorem edgesInto.ends_inside (leftEnd rightEnd C A v : Set)39requires closed : ClosedUnder(leftEnd, rightEnd, C, A)40requires member : v ∈ A41shows incidentEnds(leftEnd, rightEnd, edgesInto(leftEnd, C, A), v) =42 incidentEnds(leftEnd, rightEnd, C, v)43proof44apply Subset.antisymmetric45 . exact incidentEnds.monotone with edgesInto.subset46 . intros p hp47obtain⟨e, he, i, hi, rfl⟩:= incidentEnds.shape with hp48have sides := (incidentEnds.pair.forward with hp).right49have balanced := closed with e, he50have inside : leftEnd(e) ∈ A51rcases sides with⟨_, atLeft⟩|⟨_, atRight⟩52 . rw atLeft53exact member54 . rw atRight at balanced55exact balanced.backward with member56exact incidentEnds.pair.backward with⟨⟨he, inside⟩, sides⟩5758theorem edgesInto.ends_outside (leftEnd rightEnd C A v : Set)59requires closed : ClosedUnder(leftEnd, rightEnd, C, A)60requires outside : ¬v ∈ A61shows incidentEnds(leftEnd, rightEnd, edgesInto(leftEnd, C, A), v) =∅62proof63apply Subset.antisymmetric64 . intros p hp65obtain⟨e, he, i, hi, rfl⟩:= incidentEnds.shape with hp66have sides := (incidentEnds.pair.forward with hp).right67have balanced := closed with e, he.left68have inside := he.right69exfalso70apply outside71rcases sides with⟨_, atLeft⟩|⟨_, atRight⟩72 . rw← atLeft73exact inside74 . rw← atRight75exact balanced.forward with inside76 . exact empty.subset7778theorem edgesInto.even (V leftEnd rightEnd C A : Set)79requires even : EvenEdgeSet(V, leftEnd, rightEnd, C)80requires closed : ClosedUnder(leftEnd, rightEnd, C, A)81shows EvenEdgeSet(V, leftEnd, rightEnd, edgesInto(leftEnd, C, A))82proof83constructor84 . exact Finite.subset with even.left, edgesInto.subset85 . intros v hv86have evenV := even.right with v, hv87unfold degreeIn at evenV88unfold degreeIn89 by_cases member : v ∈ A90 . rw edgesInto.ends_inside with closed, member91exact evenV92 . rw [(edgesInto.ends_outside with closed, member), cardinality.empty]93exact Even.zero9495-- Two edges of an even set not joined through it: the edges into the96-- component of the first form a proper nonempty even subset.97theorem EvenEdgeSet.smaller_of_apart (V leftEnd rightEnd C e f : Set)98requires ends : ∀ g ∈ C, leftEnd(g) ∈ V ∧ rightEnd(g) ∈ V99requires even : EvenEdgeSet(V, leftEnd, rightEnd, C)100requires edges : e ∈ C ∧ f ∈ C101requires apart : ¬Joined(leftEnd, rightEnd, C, leftEnd(e), leftEnd(f))102shows∃ B ⊆ C, B ≠∅∧ B ≠ C ∧ EvenEdgeSet(V, leftEnd, rightEnd, B)103proof104have closed := componentBy.closed at V, leftEnd, rightEnd, C, leftEnd(e)105with ends106have leftIn := (ends with e, edges.left).left107have inside : e ∈ edgesInto(leftEnd, C,108 componentBy(V, leftEnd, rightEnd, C, leftEnd(e))) :=109⟨edges.left, (componentBy.self with leftIn)⟩110have outside : ¬f ∈ edgesInto(leftEnd, C,111 componentBy(V, leftEnd, rightEnd, C, leftEnd(e)))112intro member113exact apart with member.right.right114refine⟨edgesInto(leftEnd, C,115 componentBy(V, leftEnd, rightEnd, C, leftEnd(e))),116 edgesInto.subset, ?_, ?_, (edgesInto.even with even, closed)⟩117 . intro empty118rw empty at inside119simpat inside120 . intro same121rw same at outside122exact outside with edges.right123124-- The edges of C not at v; v is isolated in them.125def avoiding (leftEnd rightEnd C v : Set) : Set:=126 { g ∈ C | leftEnd(g) ≠ v ∧ rightEnd(g) ≠ v }127128theorem avoiding.subset (leftEnd rightEnd C v : Set)129shows avoiding(leftEnd, rightEnd, C, v) ⊆ C130proof131intros g hg132exact hg.left133134theorem avoiding.degree (leftEnd rightEnd C v Q : Set)135requires subset : Q⊆ avoiding(leftEnd, rightEnd, C, v)136shows degreeIn(leftEnd, rightEnd, Q, v) =0137proof138have none : incidentEnds(leftEnd, rightEnd, Q, v) =∅139apply Subset.antisymmetric140 . intros p hp141obtain⟨g, hg, i, hi, rfl⟩:= incidentEnds.shape with hp142have sides := (incidentEnds.pair.forward with hp).right143have away := (subset with g, hg).right144exfalso145tauto146 . exact empty.subset147unfold degreeIn148rw none149exact cardinality.empty150151-- A vertex other than v is not joined to v by the edges avoiding v.152theorem avoiding.not_joined (V leftEnd rightEnd C v a : Set)153requires ends : ∀ g ∈ C, leftEnd(g) ∈ V ∧ rightEnd(g) ∈ V154requires vertex : a ∈ V155requires distinct : a ≠ v156shows¬Joined(leftEnd, rightEnd, avoiding(leftEnd, rightEnd, C, v), a, v)157proof158intro joined159have closed : ClosedUnder(leftEnd, rightEnd,160 avoiding(leftEnd, rightEnd, C, v), V ∖ {v})161intros g hg162have bounds := ends with g, hg.left163have away := hg.right164simp [bounds.left, bounds.right, away.left, away.right]165have start : a ∈ V ∖ {v} bysimp [vertex, distinct]166have reached := joined with V ∖ {v}, start, closed167simpat reached168169-- An edge at v that is not a loop has its other end elsewhere in V.170theorem edge.other_end (V leftEnd rightEnd e v : Set)171requires ends : leftEnd(e) ∈ V ∧ rightEnd(e) ∈ V172requires loop : leftEnd(e) ≠ rightEnd(e)173requires atV : leftEnd(e) = v ∨ rightEnd(e) = v174shows∃ a ∈ V, a ≠ v ∧ ((leftEnd(e) = v ∧ rightEnd(e) = a) ∨175 (leftEnd(e) = a ∧ rightEnd(e) = v))176proof177cases atV with atLeft | atRight178 . refine⟨rightEnd(e), ends.right, ?_, ?_⟩179 . cc180 . left181exact⟨atLeft, rfl⟩182 . refine⟨leftEnd(e), ends.left, ?_, ?_⟩183 . cc184 . right185exact⟨rfl, atRight⟩186187theorem Disjoint.singleton_of_fresh (A x : Set)188requires fresh : ¬x ∈ A189shows Disjoint(A, {x})190proof191simp [Disjoint.iff, fresh]192193-- An edge with the two distinct ends v and a has odd degree exactly there.194theorem degreeIn.single_parity_ends (leftEnd rightEnd e v a : Set)195requires shape : (leftEnd(e) = v ∧ rightEnd(e) = a) ∨196 (leftEnd(e) = a ∧ rightEnd(e) = v)197requires distinct : a ≠ v198shows∀ w, (Even(degreeIn(leftEnd, rightEnd, {e}, w)) ↔ (w ≠ v ∧ w ≠ a))199proof200intro w201have loop : leftEnd(e) ≠ rightEnd(e)202rcases shape with⟨l, r⟩|⟨l, r⟩203 . rw [l, r]204cc205 . rw [l, r]206cc207have single := degreeIn.single_parity with loop, w208rcases shape with⟨l, r⟩|⟨l, r⟩209 . rw [l, r] at single210exact single211 . rw [l, r] at single212tauto213214-- A path from a to b closed by an edge va and an edge vb is even: at each215-- vertex the three degrees have an even sum.216theorem EvenEdgeSet.of_path_two_edges (V leftEnd rightEnd Q e f v a b : Set)217requires finite : Finite(Q)218requires fresh : ¬e ∈ Q ∧¬f ∈ Q ∧ e ≠ f219requires shapeE : (leftEnd(e) = v ∧ rightEnd(e) = a) ∨220 (leftEnd(e) = a ∧ rightEnd(e) = v)221requires shapeF : (leftEnd(f) = v ∧ rightEnd(f) = b) ∨222 (leftEnd(f) = b ∧ rightEnd(f) = v)223requires distinct : a ≠ v ∧ b ≠ v224requires path : ∀ w ∈ V,225 (Even(degreeIn(leftEnd, rightEnd, Q, w)) ↔ (w = a ↔ w = b))226shows EvenEdgeSet(V, leftEnd, rightEnd, (Q ∪ {e}) ∪ {f})227proof228obtain⟨eFresh, fFresh, different⟩:= fresh229obtain⟨notA, notB⟩:= distinct230have apartE := Disjoint.singleton_of_fresh with eFresh231have fOutside : ¬f ∈ Q ∪ {e} bysimp [fFresh, different]232have apartF := Disjoint.singleton_of_fresh with fOutside233have finiteE : Finite(Q ∪ {e}) := Finite.union with finite, Finite.singleton234have parityE := degreeIn.single_parity_ends with shapeE, notA235have parityF := degreeIn.single_parity_ends with shapeF, notB236constructor237 . exact Finite.union with finiteE, Finite.singleton238 . intros w hw239rw [(degreeIn.union_disjoint with finiteE, Finite.singleton, apartF),240 (degreeIn.union_disjoint with finite, Finite.singleton, apartE),241 Even.add_iff, Even.add_iff, (path with w, hw), (parityE with w),242 (parityF with w)]243have notBothA : ¬(w = v ∧ w = a)244intro both245have same : a = v bycc246exact notA with same247have notBothB : ¬(w = v ∧ w = b)248intro both249have same : b = v bycc250exact notB with same251tauto252253-- A vertex of degree other than 0 and 2 in an even set gives a proper254-- nonempty even subset: a loop by itself, or else an edge e = va at v, a255-- second edge f = vb of the cut at the component of a away from v, and a256-- path from a to b avoiding v, which together have degree two at v.257theorem EvenEdgeSet.smaller_of_degree (V leftEnd rightEnd C v : Set)258requires finiteVertices : Finite(V)259requires ends : ∀ g ∈ C, leftEnd(g) ∈ V ∧ rightEnd(g) ∈ V260requires even : EvenEdgeSet(V, leftEnd, rightEnd, C)261requires vertex : v ∈ V262requires notZero : degreeIn(leftEnd, rightEnd, C, v) ≠0263requires notTwo : degreeIn(leftEnd, rightEnd, C, v) ≠2264shows∃ B ⊆ C, B ≠∅∧ B ≠ C ∧ EvenEdgeSet(V, leftEnd, rightEnd, B)265proof266have finite := even.left267 by_cases loops : ∃ g ∈ C, leftEnd(g) = rightEnd(g)268 . -- A loop is an even set by itself, of degree 0 or 2 at v.269obtain⟨g, hg, loop⟩:= loops270refine⟨{g}, (singleton.subset_iff.backward with hg),271 singleton.ne_empty, ?_, (EvenEdgeSet.loop with loop)⟩272intro same273rw← same at notZero, notTwo274 by_cases atV : leftEnd(g) = v275 . haveright : rightEnd(g) = v bycc276exact notTwo with (degreeIn.loop with atV, right)277 . haveright : rightEnd(g) ≠ v bycc278exact notZero with (degreeIn.absent with atV, right)279 . have noLoop : ∀ g ∈ C, leftEnd(g) ≠ rightEnd(g)280intros g hg same281exact loops with⟨g, hg, same⟩282-- An edge e at v, with other end a.283have inhabited : incidentEnds(leftEnd, rightEnd, C, v) ≠∅284intro empty285apply notZero286unfold degreeIn287rw [empty, cardinality.empty]288obtain⟨p, hp⟩:= Nonempty.of_ne_empty with inhabited289obtain⟨e, he, i, hi, rfl⟩:= incidentEnds.shape with hp290have sides := (incidentEnds.pair.forward with hp).right291have atV : leftEnd(e) = v ∨ rightEnd(e) = v bytauto292have loopE := noLoop with e, he293obtain⟨a, aIn, aNotV, shapeE⟩:=294 edge.other_end with (ends with e, he), loopE, atV295-- The component A of a in the edges avoiding v, which v lies outside.296have subsetS := avoiding.subset at leftEnd, rightEnd, C, v297have finiteS := Finite.subset with finite, subsetS298have endsS := ends_in.subset with ends, subsetS299have closed := componentBy.closed at V, leftEnd, rightEnd,300 avoiding(leftEnd, rightEnd, C, v), a with endsS301have aInA := componentBy.self at V, leftEnd, rightEnd,302 avoiding(leftEnd, rightEnd, C, v), a with aIn303have vOut : ¬v ∈ componentBy(V, leftEnd, rightEnd,304 avoiding(leftEnd, rightEnd, C, v), a)305intro member306exact avoiding.not_joined with ends, aIn, aNotV, member.right307-- The cut at A holds e, so it holds a second edge f.308have eCrosses : e ∈ crossing(leftEnd, rightEnd, C,309 componentBy(V, leftEnd, rightEnd, avoiding(leftEnd, rightEnd, C, v), a))310refine⟨he, ?_⟩311rcases shapeE with⟨l, r⟩|⟨l, r⟩312 . right313rw [l, r]314exact⟨aInA, vOut⟩315 . left316rw [l, r]317exact⟨aInA, vOut⟩318have notSingle := EvenEdgeSet.crossing_ne_singleton at V, leftEnd,319 rightEnd, C, componentBy(V, leftEnd, rightEnd,320 avoiding(leftEnd, rightEnd, C, v), a), e321with finiteVertices, even, componentBy.subset322have second : ∃ f ∈ crossing(leftEnd, rightEnd, C,323 componentBy(V, leftEnd, rightEnd,324 avoiding(leftEnd, rightEnd, C, v), a)), f ≠ e325by_contra none326apply notSingle327ext g328rw singleton.membership329constructor330 . intro hg331by_contra other332exact none with⟨g, hg, other⟩333 . intro same334rw same335exact eCrosses336obtain⟨f, fCrosses, fNotE⟩:= second337have hf : f ∈ C := fCrosses.left338have fSides := fCrosses.right339-- f is at v, since A is closed under the edges avoiding v, and its other340-- end b lies in A.341have fAtV : leftEnd(f) = v ∨ rightEnd(f) = v342by_contra away343have both : leftEnd(f) ≠ v ∧ rightEnd(f) ≠ v bytauto344have balanced := closed with f, ⟨hf, both⟩345tauto346have loopF := noLoop with f, hf347obtain⟨b, bIn, bNotV, shapeF⟩:=348 edge.other_end with (ends with f, hf), loopF, fAtV349have bInA : b ∈ componentBy(V, leftEnd, rightEnd,350 avoiding(leftEnd, rightEnd, C, v), a)351rcases shapeF with⟨l, r⟩|⟨l, r⟩352 . rw [l, r] at fSides353tauto354 . rw [l, r] at fSides355tauto356-- A path from a to b through the edges avoiding v.357have pathExists : ∃ Q ⊆ avoiding(leftEnd, rightEnd, C, v), ∀ w ∈ V,358 (Even(degreeIn(leftEnd, rightEnd, Q, w)) ↔ (w = a ↔ w = b))359 by_cases same : a = b360 . refine⟨∅, empty.subset, ?_⟩361intros w hw362rw [degreeIn.empty, same]363simp [Even.zero]364 . have joined := componentBy.joined with bInA365obtain⟨Q, inS, path⟩:=366 Joined.path with finiteS, endsS, same, joined367refine⟨Q, inS, ?_⟩368intros w hw369rw (path with w, hw)370have notBoth : ¬(w = a ∧ w = b)371intro both372have equal : a = b bycc373exact same with equal374tauto375obtain⟨Q, QinS, path⟩:= pathExists376have finiteQ := Finite.subset with finiteS, QinS377have eFresh : ¬e ∈ Q378intro inQ379have away := (QinS with e, inQ).right380tauto381have fFresh : ¬f ∈ Q382intro inQ383have away := (QinS with f, inQ).right384tauto385have eNotF : e ≠ f bycc386have evenB := EvenEdgeSet.of_path_two_edges with finiteQ,387⟨eFresh, fFresh, eNotF⟩, shapeE, shapeF, ⟨aNotV, bNotV⟩, path388have QsubC := Subset.transitive with QinS, subsetS389have QeSub : Q∪ {e} ⊆ C := Subset.union2_iff.backward390with⟨QsubC, (singleton.subset_iff.backward with he)⟩391have BsubC : (Q ∪ {e}) ∪ {f} ⊆ C := Subset.union2_iff.backward392with⟨QeSub, (singleton.subset_iff.backward with hf)⟩393refine⟨(Q ∪ {e}) ∪ {f}, BsubC, ?_, ?_, evenB⟩394 . intro empty395have inB : e ∈ (Q ∪ {e}) ∪ {f} bysimp396rw empty at inB397simpat inB398 . -- The degree at v is two in the new set and not in C.399intro same400apply notTwo401rw← same402have apartE := Disjoint.singleton_of_fresh with eFresh403have fOutside : ¬f ∈ Q ∪ {e} bysimp [fFresh, fNotE]404have apartF := Disjoint.singleton_of_fresh with fOutside405have finiteQe : Finite(Q ∪ {e}) :=406 Finite.union with finiteQ, Finite.singleton407rw [(degreeIn.union_disjoint with finiteQe, Finite.singleton, apartF),408 (degreeIn.union_disjoint with finiteQ, Finite.singleton, apartE),409 (avoiding.degree with QinS), (degreeIn.end with loopE, atV),410 (degreeIn.end with loopF, fAtV)]411compute412413-- A nonempty even edge set is a cycle or has a proper nonempty even subset.414theorem EvenEdgeSet.cycle_or_smaller (V leftEnd rightEnd C : Set)415requires finiteVertices : Finite(V)416requires ends : ∀ g ∈ C, leftEnd(g) ∈ V ∧ rightEnd(g) ∈ V417requires even : EvenEdgeSet(V, leftEnd, rightEnd, C)418requires nonempty : C ≠∅419shows Cycle(V, leftEnd, rightEnd, C) ∨420 (∃ B ⊆ C, B ≠∅∧ B ≠ C ∧ EvenEdgeSet(V, leftEnd, rightEnd, B))421proof422 by_cases degrees : ∀ v ∈ V, degreeIn(leftEnd, rightEnd, C, v) =0∨423 degreeIn(leftEnd, rightEnd, C, v) =2424 . by_cases joined : ∀ e ∈ C, ∀ f ∈ C,425 Joined(leftEnd, rightEnd, C, leftEnd(e), leftEnd(f))426 . left427exact⟨nonempty, even, degrees, joined⟩428 . right429have found : ∃ e ∈ C, ∃ f ∈ C,430¬Joined(leftEnd, rightEnd, C, leftEnd(e), leftEnd(f))431by_contra none432apply joined433intros e he f hf434by_contra apart435exact none with⟨e, he, f, hf, apart⟩436obtain⟨e, he, f, hf, apart⟩:= found437exact EvenEdgeSet.smaller_of_apart with ends, even, ⟨he, hf⟩, apart438 . right439have found : ∃ v ∈ V, degreeIn(leftEnd, rightEnd, C, v) ≠0∧440 degreeIn(leftEnd, rightEnd, C, v) ≠2441by_contra none442apply degrees443intros v hv444by_contra neither445have both : degreeIn(leftEnd, rightEnd, C, v) ≠0∧446 degreeIn(leftEnd, rightEnd, C, v) ≠2bytauto447exact none with⟨v, hv, both⟩448obtain⟨v, hv, notZero, notTwo⟩:= found449exact EvenEdgeSet.smaller_of_degree450with finiteVertices, ends, even, hv, notZero, notTwo451452-- A proper subset of a finite set is strictly smaller.453theorem cardinality.proper (B C : Set)454requires finite : Finite(C)455requires subset : B ⊆ C456requires proper : B ≠ C457shows cardinality(B) < cardinality(C)458proof459have missing : ∃ a ∈ C, ¬a ∈ B460by_contra none461apply proper462apply Subset.antisymmetric463 . exact subset464 . intros a ha465by_contra outside466exact none with⟨a, ha, outside⟩467obtain⟨a, ha, outside⟩:= missing468exact cardinality.strict with finite, subset, ha, outside469470-- Every nonempty even edge set contains a cycle: by induction on the number471-- of edges, a nonempty even set is a cycle or has a smaller nonempty even472-- subset.473theorem EvenEdgeSet.cycle_of_size (V leftEnd rightEnd F : Set, n : Nat)474requires finiteVertices : Finite(V)475requires ends : ∀ e ∈ F, leftEnd(e) ∈ V ∧ rightEnd(e) ∈ V476shows∀ C ⊆ F, cardinality(C) ≤ n → C ≠∅→477 EvenEdgeSet(V, leftEnd, rightEnd, C) →478∃ D ⊆ C, Cycle(V, leftEnd, rightEnd, D)479proof480induction n481| zero =>482intros C bound size nonempty even483have finiteC := even.left484have zero : cardinality(C) =0byarith485exfalso486exact nonempty with (cardinality.eq_empty_of_zero with finiteC, zero)487| succ(k) using ih =>488intros C bound size nonempty even489have finiteC := even.left490have endsC := ends_in.subset with ends, bound491havesplit:= EvenEdgeSet.cycle_or_smaller492with finiteVertices, endsC, even, nonempty493casessplitwith cycle | smaller494 . exact⟨C, Subset.reflexive, cycle⟩495 . obtain⟨B, inC, nonemptyB, proper, evenB⟩:= smaller496have finiteB := evenB.left497have less := cardinality.proper with finiteC, inC, proper498have smallerSize : cardinality(B) ≤ k byarith499obtain⟨D, inB, cycle⟩:= ih with B,500 (Subset.transitive with inC, bound), smallerSize, nonemptyB, evenB501exact⟨D, (Subset.transitive with inB, inC), cycle⟩502503theorem EvenEdgeSet.contains_cycle (V leftEnd rightEnd F : Set)504requires finiteVertices : Finite(V)505requires ends : ∀ e ∈ F, leftEnd(e) ∈ V ∧ rightEnd(e) ∈ V506requires even : EvenEdgeSet(V, leftEnd, rightEnd, F)507requires nonempty : F ≠∅508shows∃ C ⊆ F, Cycle(V, leftEnd, rightEnd, C)509proof510have finite := even.left511have bound : cardinality(F) ≤ cardinality(F) byarith512exact EvenEdgeSet.cycle_of_size513at V, leftEnd, rightEnd, F, cardinality(F)514with finiteVertices, ends, F, Subset.reflexive, bound, nonempty, even515516-- Section: Decomposition.517518-- Splitting an even edge set into cycles: remove a cycle and split the519-- rest, which is even as its symmetric difference with the cycle is the520-- whole set. The empty set splits into no cycles.521theorem cycleDecomposition.empty (V leftEnd rightEnd C : Set)522requires empty : C =∅523shows∃ D, Finite(D) ∧ (∀ K ∈ D, Cycle(V, leftEnd, rightEnd, K)) ∧524 (∀ K ∈ D, ∀ B ∈ D, K ≠ B → Disjoint(K, B)) ∧⋃(D) = C525proof526refine⟨∅, Finite.empty, ?_, ?_, ?_⟩527 . intros K hK528simpat hK529 . intros K hK530simpat hK531 . rw [union.empty, empty]532533theorem EvenEdgeSet.decomposition_of_size (V leftEnd rightEnd F : Set, n : Nat)534requires finiteVertices : Finite(V)535requires ends : ∀ e ∈ F, leftEnd(e) ∈ V ∧ rightEnd(e) ∈ V536shows∀ C ⊆ F, cardinality(C) ≤ n →537 EvenEdgeSet(V, leftEnd, rightEnd, C) →538∃ D, Finite(D) ∧ (∀ K ∈ D, Cycle(V, leftEnd, rightEnd, K)) ∧539 (∀ K ∈ D, ∀ B ∈ D, K ≠ B → Disjoint(K, B)) ∧⋃(D) = C540proof541induction n542| zero =>543intros C bound size even544have finiteC := even.left545have zero : cardinality(C) =0byarith546exact cycleDecomposition.empty547with (cardinality.eq_empty_of_zero with finiteC, zero)548| succ(k) using ih =>549intros C bound size even550have finiteC := even.left551 by_cases empty : C =∅552 . exact cycleDecomposition.empty with empty553 . have endsC := ends_in.subset with ends, bound554obtain⟨K, inC, cycle⟩:=555 EvenEdgeSet.contains_cycle with finiteVertices, endsC, even, empty556-- The rest C ∖ K is even and smaller.557have restSubset := difference.subset_left at C, K558have restFinite := Finite.subset with finiteC, restSubset559have restored : K △ (C ∖ K) = C byext x; simp560have evenWhole : EvenEdgeSet(V, leftEnd, rightEnd, K △ (C ∖ K))561rw restored562exact even563have evenRest := EvenEdgeSet.of_symmetricDifference564with cycle.right.left, restFinite, evenWhole565have less : cardinality(C ∖ K) < cardinality(C)566obtain⟨a, ha⟩:= Nonempty.of_ne_empty with cycle.left567have outside : ¬a ∈ C ∖ K bysimp [ha]568exact cardinality.strict with finiteC, restSubset, (inC with a, ha),569 outside570have smallerSize : cardinality(C ∖ K) ≤ k byarith571obtain⟨D, finiteD, cycles, apart, covers⟩:= ih with C ∖ K,572 (Subset.transitive with restSubset, bound), smallerSize, evenRest573-- Adjoin K to the decomposition of the rest, which it misses.574have inRest : ∀ B ∈ D, B ⊆ C ∖ K575intros B hB576rw← covers577exact union.subset_of_member with hB578have apartK : ∀ B ∈ D, Disjoint(B, K)579intros B hB580exact Disjoint.of_subset_left with Disjoint.difference_left,581 (inRest with B, hB)582refine⟨D ∪ {K}, (Finite.union with finiteD, Finite.singleton),583 ?_, ?_, ?_⟩584 . intros B hB585simpat hB586rcases hB with inD |rfl587 . exact cycles with B, inD588 . exact cycle589 . intros B hB A hA different590simpat hB, hA591rcases hB with inD |rfl592 . rcases hA with inD2 |rfl593 . exact apart with B, inD, A, inD2, different594 . exact apartK with B, inD595 . rcases hA with inD2 |rfl596 . exact Disjoint.symmetric with (apartK with A, inD2)597 . exfalso598exact different withrfl599 . rw [union.union2, union.singleton, covers]600ext x601have fromK : x ∈ K → x ∈ C := inC with x602simp [difference.membership]603604theorem EvenEdgeSet.cycle_decomposition (V leftEnd rightEnd F : Set)605requires finiteVertices : Finite(V)606requires ends : ∀ e ∈ F, leftEnd(e) ∈ V ∧ rightEnd(e) ∈ V607requires even : EvenEdgeSet(V, leftEnd, rightEnd, F)608shows∃ D, Finite(D) ∧ (∀ C ∈ D, Cycle(V, leftEnd, rightEnd, C)) ∧609 (∀ C ∈ D, ∀ B ∈ D, C ≠ B → Disjoint(C, B)) ∧⋃(D) = F610proof611have finite := even.left612have bound : cardinality(F) ≤ cardinality(F) byarith613exact EvenEdgeSet.decomposition_of_size614at V, leftEnd, rightEnd, F, cardinality(F)615with finiteVertices, ends, F, Subset.reflexive, bound, even616