1-- Lifting even sets and even covers from the contraction of an edge e: an2-- even set of the contraction lifts with or without e, and when e lies in a3-- cut of two edges an even cover of the contraction lifts to one of the4-- graph.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.Lifting11import Contraction1213-- An even set of the contraction lifts to the graph, with or without e: the14-- two ends of e have degrees of equal parity in it.15theorem contraction.lift_even (V E leftEnd rightEnd e F : Set)16requires graph : Graph(V, E, leftEnd, rightEnd)17requires finiteVertices : Finite(V)18requires edge : e ∈ E19requires even : EvenEdgeSet(contractionPartition(V, leftEnd, rightEnd, e),20 contractedLeft(V, E, leftEnd, rightEnd, e),21 contractedRight(V, E, leftEnd, rightEnd, e), F)22requires edges : F ⊆ E ∖ {e}23shows EvenEdgeSet(V, leftEnd, rightEnd, F) ∨24 EvenEdgeSet(V, leftEnd, rightEnd, F ∪ {e})25proof26obtain⟨finite, degrees⟩:= even27obtain⟨leftIn, rightIn⟩:= Graph.ends with graph, e, edge28have partition := contractionPartition.partition with graph, edge29have endClass : {leftEnd(e), rightEnd(e)} ∈30 contractionPartition(V, leftEnd, rightEnd, e)31rw← contraction.class_end with graph, edge32exact (classOf.member with partition, leftIn).left33-- Away from the ends of e a vertex is its own class, with its own degree.34have away : ∀ v ∈ V, v ≠ leftEnd(e) → v ≠ rightEnd(e) →35 Even(degreeIn(leftEnd, rightEnd, F, v))36intros v hv leftright37have single := contraction.class_apart with graph, edge, hv, left, right38haveclass : {v} ∈ contractionPartition(V, leftEnd, rightEnd, e)39rw← single40exact (classOf.member with partition, hv).left41rw← degreeIn.contraction_singleton with graph, edge, edges, class42exact degrees with {v}, class43 by_cases loop : leftEnd(e) = rightEnd(e)44 . -- A loop merges nothing, so F itself is even.45left46refine⟨finite, _⟩47intros v hv48 by_cases atEnd : v = leftEnd(e)49 . rw [← loop, pair.self] at endClass50rw atEnd51rw← degreeIn.contraction_singleton with graph, edge, edges, endClass52exact degrees with {leftEnd(e)}, endClass53 . have atRight : v ≠ rightEnd(e) bycc54exact away with v, hv, atEnd, atRight55 . -- The class of the two ends has the sum of their degrees, so the two56-- degrees have the same parity.57have sum := degreeIn.contraction_pair58with graph, edge, finite, edges, loop59have evenSum := degrees with {leftEnd(e), rightEnd(e)}, endClass60rw sum at evenSum61have parity := (Even.add_iff at degreeIn(leftEnd, rightEnd, F, leftEnd(e)),62 degreeIn(leftEnd, rightEnd, F, rightEnd(e))).forward with evenSum63 by_cases evenLeft : Even(degreeIn(leftEnd, rightEnd, F, leftEnd(e)))64 . left65have evenRight := parity.forward with evenLeft66refine⟨finite, _⟩67intros v hv68 by_cases atLeft : v = leftEnd(e)69 . rw atLeft70exact evenLeft71 . by_cases atRight : v = rightEnd(e)72 . rw atRight73exact evenRight74 . exact away with v, hv, atLeft, atRight75 . -- Both degrees are odd, and e adds one end at each of them.76right77have oddLeft := (Odd.iff_not_even78at degreeIn(leftEnd, rightEnd, F, leftEnd(e))).backward with evenLeft79have notRight : ¬Even(degreeIn(leftEnd, rightEnd, F, rightEnd(e)))80intro evenRight81exact evenLeft with (parity.backward with evenRight)82have oddRight := (Odd.iff_not_even83at degreeIn(leftEnd, rightEnd, F, rightEnd(e))).backward with notRight84have absent : ¬e ∈ F85intro inF86have other := edges with e, inF87simpat other88have apart : Disjoint(F, {e}) bysimp [Disjoint.iff, absent]89refine⟨(Finite.union with finite, Finite.singleton), _⟩90intros v hv91rw degreeIn.union_disjoint with finite, Finite.singleton, apart92 by_cases atLeft : v = leftEnd(e)93 . rw [atLeft, (degreeIn.end_left with loop, rfl), Even.add_one_iff]94exact oddLeft95 . by_cases atRight : v = rightEnd(e)96 . rw [atRight, (degreeIn.end_right with loop, rfl), Even.add_one_iff]97exact oddRight98 . have leftAway : leftEnd(e) ≠ v bycc99have rightAway : rightEnd(e) ≠ v bycc100have zero : degreeIn(leftEnd, rightEnd, F, v) +0=101 degreeIn(leftEnd, rightEnd, F, v) byring102rw [(degreeIn.absent with leftAway, rightAway), zero]103exact away with v, hv, atLeft, atRight104105-- The lift of an even set F of the contraction: F itself when that is even106-- in the graph, and otherwise F with e.107def liftedSet (V leftEnd rightEnd e F : Set) : Set:=108 F ∪ { x ∈ {e} |¬EvenEdgeSet(V, leftEnd, rightEnd, F) }109110theorem liftedSet.cases (V leftEnd rightEnd e F : Set)111shows (EvenEdgeSet(V, leftEnd, rightEnd, F) ∧112 liftedSet(V, leftEnd, rightEnd, e, F) = F) ∨113 (¬EvenEdgeSet(V, leftEnd, rightEnd, F) ∧114 liftedSet(V, leftEnd, rightEnd, e, F) = F ∪ {e})115proof116unfold liftedSet117 by_cases even : EvenEdgeSet(V, leftEnd, rightEnd, F)118 . left119refine⟨even, _⟩120have none : liftedSet.family(V, leftEnd, rightEnd, e, F) =∅121ext x122simp [liftedSet.family, even]123rw [none, union2.right_empty]124 . right125refine⟨even, _⟩126have all : liftedSet.family(V, leftEnd, rightEnd, e, F) = {e}127ext x128simp [liftedSet.family, even]129rw all130131theorem liftedSet.even (V E leftEnd rightEnd e F : Set)132requires graph : Graph(V, E, leftEnd, rightEnd)133requires finiteVertices : Finite(V)134requires edge : e ∈ E135requires even : EvenEdgeSet(contractionPartition(V, leftEnd, rightEnd, e),136 contractedLeft(V, E, leftEnd, rightEnd, e),137 contractedRight(V, E, leftEnd, rightEnd, e), F)138requires edges : F ⊆ E ∖ {e}139shows EvenEdgeSet(V, leftEnd, rightEnd, liftedSet(V, leftEnd, rightEnd, e, F))140∧ F ⊆ liftedSet(V, leftEnd, rightEnd, e, F)141∧ liftedSet(V, leftEnd, rightEnd, e, F) ⊆ E142proof143have lifted := contraction.lift_even144with graph, finiteVertices, edge, even, edges145havecases:= liftedSet.cases at V, leftEnd, rightEnd, e, F146have edgesE : F ⊆ E := Subset.transitive with edges, difference.subset_left147rcasescaseswith⟨evenF, same⟩|⟨oddF, same⟩148 . rw same149exact⟨evenF, Subset.reflexive, edgesE⟩150 . rw same151have evenUnion : EvenEdgeSet(V, leftEnd, rightEnd, F ∪ {e})152rcases lifted with evenF | evenUnion153 . exfalso154exact oddF with evenF155 . exact evenUnion156have inE : {e} ⊆ E := singleton.subset_iff.backward with edge157refine⟨evenUnion, union2.subset_left, _⟩158exact Subset.union2_iff.backward with⟨edgesE, inE⟩159160-- When e lies in a cut {e, f} of the graph, every lifted even set holding f161-- holds e, so a cover of the contraction lifts to a cover of the graph.162theorem contraction.lift_cover (V E leftEnd rightEnd e f X F : Set)163requires graph : Graph(V, E, leftEnd, rightEnd)164requires finiteVertices : Finite(V)165requires finiteEdges : Finite(E)166requires cut : X ⊆ V ∧ crossing(leftEnd, rightEnd, E, X) = {e, f} ∧167 e ≠ f168requires cover : EvenCover(contractionPartition(V, leftEnd, rightEnd, e),169 E ∖ {e}, contractedLeft(V, E, leftEnd, rightEnd, e),170 contractedRight(V, E, leftEnd, rightEnd, e), F)171shows∃ G, EvenCover(V, E, leftEnd, rightEnd, G)172proof173obtain⟨bound, cutEdges, distinct⟩:= cut174obtain⟨function, even, covers⟩:= cover175have endsE := Graph.ends with graph176have cutInE := crossing.subset at leftEnd, rightEnd, E, X177have eInCut : e ∈ crossing(leftEnd, rightEnd, E, X)178rw cutEdges179exact pair.left180have fInCut : f ∈ crossing(leftEnd, rightEnd, E, X)181rw cutEdges182exact pair.right183have eInE := cutInE with e, eInCut184have fNotE : ¬f ∈ {e}185intro same186rw singleton.membership at same187cc188have fOther : f ∈ E ∖ {e} :=189 difference.membership.backward with (cutInE with f, fInCut), fNotE190-- Every coordinate lifts to an even set of the graph inside E.191have lifts : ∀ i ∈3,192 EvenEdgeSet(V, leftEnd, rightEnd,193 liftedSet(V, leftEnd, rightEnd, e, F(i)))194∧ F(i) ⊆ liftedSet(V, leftEnd, rightEnd, e, F(i))195∧ liftedSet(V, leftEnd, rightEnd, e, F(i)) ⊆ E196intros i hi197have edgesI : F(i) ⊆ E ∖ {e} := powerset.membership_iff.forward198with (FunctionBetween.apply_closed with function, hi)199exact liftedSet.even200with graph, finiteVertices, eInE, (even with i, hi), edgesI201have zero : 0∈3bysimp [membership.three]202have one : 1∈3bysimp [membership.three]203have two : 2∈3bysimp [membership.three]204have mem0 : liftedSet(V, leftEnd, rightEnd, e, F(0)) ∈𝒫(E) :=205 powerset.membership_iff.backward with (lifts with0, zero).right.right206have mem1 : liftedSet(V, leftEnd, rightEnd, e, F(1)) ∈𝒫(E) :=207 powerset.membership_iff.backward with (lifts with1, one).right.right208have mem2 : liftedSet(V, leftEnd, rightEnd, e, F(2)) ∈𝒫(E) :=209 powerset.membership_iff.backward with (lifts with2, two).right.right210have values := tripleMap.value with mem0, mem1, mem2211have valueAt : ∀ i ∈3,212 tripleMap(𝒫(E), liftedSet(V, leftEnd, rightEnd, e, F(0)),213 liftedSet(V, leftEnd, rightEnd, e, F(1)),214 liftedSet(V, leftEnd, rightEnd, e, F(2)))(i) =215 liftedSet(V, leftEnd, rightEnd, e, F(i))216intros i hi217havecases:= membership.three.forward with hi218rcasescaseswithrfl|rfl|rfl219 . exact values.left220 . exact values.right.left221 . exact values.right.right222witness tripleMap(𝒫(E), liftedSet(V, leftEnd, rightEnd, e, F(0)),223 liftedSet(V, leftEnd, rightEnd, e, F(1)),224 liftedSet(V, leftEnd, rightEnd, e, F(2)))225refine⟨(tripleMap.function with mem0, mem1, mem2), _, _⟩226 . intros i hi227have value := valueAt with i, hi228rw value229exact (lifts with i, hi).left230 . intros g hg231 by_cases same : g = e232 . -- The lifted set holding f is even and meets the cut {e, f} in f, so233-- it holds e as well.234obtain⟨i, hi, inF⟩:= covers with f, fOther235obtain⟨evenI, growI, inI⟩:= lifts with i, hi236have value := valueAt with i, hi237refine⟨i, hi, _⟩238rw [value, same]239have both := EvenEdgeSet.two_cut240with finiteVertices, evenI, bound, inI, endsE, cutEdges, distinct241exact both.backward with (growI with f, inF)242 . have gNotE : ¬g ∈ {e}243intro inE244rw singleton.membership at inE245exact same with inE246obtain⟨i, hi, inF⟩:=247 covers with g, (difference.membership.backward with hg, gNotE)248have value := valueAt with i, hi249refine⟨i, hi, _⟩250rw value251exact (lifts with i, hi).right.left with g, inF252