1-- Labels from a compatible assignment: the local base point of an edge end2-- is the value of another edge at that vertex, and vertex vectors whose3-- differences along the edges are compatible with the base points give4-- two-element labels with even local multiplicity, hence an even double5-- cover.6-- Part of Cumulus, the Grace17 mathematics library.7-- Copyright (c) 2026 Grant Passmore.8-- Released under the Apache License 2.0. See LICENSE in the repository root.9-- Authors: Grant Passmore1011module Grace.Cumulus.GraphTheory.DoubleCover.Labels12import CubicVertex1314-- The local base point of an end: the value of one other edge at that vertex,15-- determined up to the span of the edge's own value.16predicate BasePoint (V E leftEnd rightEnd F v e c : Set) :=17∃ f ∈ E, f ≠ e ∧ (leftEnd(f) = v ∨ rightEnd(f) = v) ∧18 c = flowValue(F, f)1920-- Vertex vectors t with t(u) △ t(v) ∈ d(e) + span(value(e)) for every edge21-- e = uv, where d(e) is the sum of the two base points of e.22predicate Compatible (V E leftEnd rightEnd F t d : Set) :=23 FunctionBetween(t, V, 𝒫(3)) ∧24 (∀ e ∈ E, ∃ s ∈ span(flowValue(F, e)),25 t(leftEnd(e)) △ t(rightEnd(e)) = d(e) △ s)2627-- Sums in the two-element field cancel.28theorem symmetricDifference.cancel_right (A B : Set)29shows (A △ B) △ B = A30proof31ext z32simp3334theorem symmetricDifference.cancel_left (A B C : Set)35requires same : A △ B = A △ C36shows B = C37proof38ext z39have bit := symmetricDifference.membership at z, A, B40rw [same, symmetricDifference.membership] at bit41tauto4243-- Moving x to y by (a △ b) △ s moves x △ u to y △ w by the corrections44-- a △ u and b △ w and s.45theorem symmetricDifference.shift (x y u w a b s : Set)46requires move : x △ y = (a △ b) △ s47shows y △ w = (x △ u) △ (((a △ u) △ (b △ w)) △ s)48proof49ext z50have bit := symmetricDifference.membership at z, x, y51rw move at bit52simp [symmetricDifference.membership]5354-- A base point of e at v, the value of some other edge x there, differs from55-- the value of a fixed other edge f by an element of the span of value(e):56-- either x = f, or e, x, f are the three edges at v.57theorem BasePoint.span (V E leftEnd rightEnd F v e f c : Set)58requires graph : Graph(V, E, leftEnd, rightEnd)59requires cubic : Cubic(V, E, leftEnd, rightEnd)60requires cover : EvenCover(V, E, leftEnd, rightEnd, F)61requires vertex : v ∈ V62requires edge : e ∈ E63requires incident : leftEnd(e) = v ∨ rightEnd(e) = v64requires other : f ∈ E ∧ f ≠ e ∧ (leftEnd(f) = v ∨ rightEnd(f) = v)65requires base : BasePoint(V, E, leftEnd, rightEnd, F, v, e, c)66shows c △ flowValue(F, f) ∈ span(flowValue(F, e))67proof68obtain⟨x, hx, xe, xv, rfl⟩:= base69rw span.membership70 by_cases same : x = f71 . left72rw same73exact symmetricDifference.self74 . right75have edges : e ∈ E ∧ x ∈ E ∧ f ∈ E :=⟨edge, hx, other.left⟩76have incident3 : (leftEnd(e) = v ∨ rightEnd(e) = v) ∧77 (leftEnd(x) = v ∨ rightEnd(x) = v) ∧78 (leftEnd(f) = v ∨ rightEnd(f) = v) :=79⟨incident, xv, other.right.right⟩80have ex : e ≠ x bycc81have ef : e ≠ f bycc82have distinct : e ≠ x ∧ x ≠ f ∧ e ≠ f :=⟨ex, same, ef⟩83have triple := flowValue.cubic_vertex84with graph, cubic, cover, vertex, edges, incident3, distinct85rw triple.right86ext z87simp8889-- The labels of e read at its end v: t(v) △ value(x) for the other edges90-- x at v. The label pair of e is read at its left end.91def labelsAt (E leftEnd rightEnd F t v e : Set) : Set:=92 { q ∈𝒫(3) |∃ x ∈ E, x ≠ e ∧ (leftEnd(x) = v ∨ rightEnd(x) = v) ∧93 q = t(v) △ flowValue(F, x) }9495def labelPairs (E leftEnd rightEnd F t : Set) : Set:=96 { p ∈ E ×𝒫(𝒫(3)) |∃ e ∈ E,97 p = (e, labelsAt(E, leftEnd, rightEnd, F, t, leftEnd(e), e)) }9899theorem labelsAt.subset (E leftEnd rightEnd F t v e : Set)100shows labelsAt(E, leftEnd, rightEnd, F, t, v, e) ⊆𝒫(3)101proof102intros q hq103exact hq.left104105theorem labelPairs.function (E leftEnd rightEnd F t : Set)106shows labelPairs(E, leftEnd, rightEnd, F, t) : E →𝒫(𝒫(3))107proof108constructor109 . intros p member110exact member.left111 . constructor112 . intros x y xy z xz113obtain⟨_, a, _, shapeY⟩:= xy114obtain⟨_, b, _, shapeZ⟩:= xz115obtain⟨sameA, valueY⟩:= orderedPair.injective with shapeY116obtain⟨sameB, valueZ⟩:= orderedPair.injective with shapeZ117cc118 . intros e he119have inside :120 labelsAt(E, leftEnd, rightEnd, F, t, leftEnd(e), e) ∈𝒫(𝒫(3)) :=121 powerset.membership_iff.backward with labelsAt.subset122refine⟨labelsAt(E, leftEnd, rightEnd, F, t, leftEnd(e), e), inside, _⟩123exact labelPairs.membership.backward124with⟨(product.pair with he, inside), e, he, rfl⟩125126theorem labelPairs.value (E leftEnd rightEnd F t e : Set)127requires member : e ∈ E128shows labelPairs(E, leftEnd, rightEnd, F, t)(e) =129 labelsAt(E, leftEnd, rightEnd, F, t, leftEnd(e), e)130proof131have inside :132 labelsAt(E, leftEnd, rightEnd, F, t, leftEnd(e), e) ∈𝒫(𝒫(3)) :=133 powerset.membership_iff.backward with labelsAt.subset134have related : relates(labelPairs(E, leftEnd, rightEnd, F, t), e,135 labelsAt(E, leftEnd, rightEnd, F, t, leftEnd(e), e)) :=136 labelPairs.membership.backward137with⟨(product.pair with member, inside), e, member, rfl⟩138exact FunctionBetween.apply_value139with labelPairs.function, member, related140141-- With the other edges f, g at v, the labels of e at v are t(v) △ value(f)142-- and t(v) △ value(g).143theorem labelsAt.pair (V E leftEnd rightEnd F t v e f g : Set)144requires cubic : Cubic(V, E, leftEnd, rightEnd)145requires vertex : v ∈ V146requires function : FunctionBetween(t, V, 𝒫(3))147requires edges : e ∈ E ∧ f ∈ E ∧ g ∈ E148requires incident : (leftEnd(e) = v ∨ rightEnd(e) = v) ∧149 (leftEnd(f) = v ∨ rightEnd(f) = v) ∧150 (leftEnd(g) = v ∨ rightEnd(g) = v)151requires distinct : e ≠ f ∧ f ≠ g ∧ e ≠ g152shows labelsAt(E, leftEnd, rightEnd, F, t, v, e) =153 {t(v) △ flowValue(F, f), t(v) △ flowValue(F, g)}154proof155have vector : t(v) ⊆3:= powerset.membership_iff.forward156with (FunctionBetween.apply_closed with function, vertex)157have insideF : t(v) △ flowValue(F, f) ∈𝒫(3) :=158 powerset.membership_iff.backward159with (symmetricDifference.subset with vector, flowValue.subset)160have insideG : t(v) △ flowValue(F, g) ∈𝒫(3) :=161 powerset.membership_iff.backward162with (symmetricDifference.subset with vector, flowValue.subset)163have fe : f ≠ e bycc164have ge : g ≠ e bycc165ext q166simp [pair.membership]167constructor168 . intro hq169obtain⟨_, x, hx, xe, xv, rfl⟩:= hq170havecases:=171 Cubic.among with cubic, vertex, edges, incident, distinct, hx, xv172rcasescaseswith hxe | hxf | hxg173 . exfalso174exact xe with hxe175 . left176cc177 . right178cc179 . intro hq180rcases hq withrfl|rfl181 . exact⟨insideF, f, edges.right.left, fe, incident.right.left, rfl⟩182 . exact⟨insideG, g, edges.right.right, ge, incident.right.right, rfl⟩183184-- The labels of e read at either end agree: compatibility moves t across e185-- by the sum of two base points and an element of the span of value(e),186-- and each base point differs from the chosen other value by such an187-- element too.188theorem labelsAt.ends (V E leftEnd rightEnd F t d e : Set)189requires graph : Graph(V, E, leftEnd, rightEnd)190requires cubic : Cubic(V, E, leftEnd, rightEnd)191requires cover : EvenCover(V, E, leftEnd, rightEnd, F)192requires base : FunctionBetween(d, E, 𝒫(3)) ∧ (∀ e ∈ E, ∃ a, ∃ b,193 BasePoint(V, E, leftEnd, rightEnd, F, leftEnd(e), e, a) ∧194 BasePoint(V, E, leftEnd, rightEnd, F, rightEnd(e), e, b) ∧ d(e) = a △ b)195requires compatible : Compatible(V, E, leftEnd, rightEnd, F, t, d)196requires edge : e ∈ E197shows labelsAt(E, leftEnd, rightEnd, F, t, rightEnd(e), e) =198 labelsAt(E, leftEnd, rightEnd, F, t, leftEnd(e), e)199proof200have ends := Graph.ends with graph201obtain⟨vertexL, vertexR⟩:= ends with e, edge202have atL : leftEnd(e) = leftEnd(e) ∨ rightEnd(e) = leftEnd(e) bysimp203have atR : leftEnd(e) = rightEnd(e) ∨ rightEnd(e) = rightEnd(e) bysimp204obtain⟨f, hf, g, hg, distinctL, atF, atG⟩:=205 Cubic.others with cubic, vertexL, edge, atL206obtain⟨f2, hf2, g2, hg2, distinctR, atF2, atG2⟩:=207 Cubic.others with cubic, vertexR, edge, atR208have edgesL : e ∈ E ∧ f ∈ E ∧ g ∈ E :=⟨edge, hf, hg⟩209have incidentL : (leftEnd(e) = leftEnd(e) ∨ rightEnd(e) = leftEnd(e)) ∧210 (leftEnd(f) = leftEnd(e) ∨ rightEnd(f) = leftEnd(e)) ∧211 (leftEnd(g) = leftEnd(e) ∨ rightEnd(g) = leftEnd(e)) :=212⟨atL, atF, atG⟩213have edgesR : e ∈ E ∧ f2 ∈ E ∧ g2 ∈ E :=⟨edge, hf2, hg2⟩214have incidentR : (leftEnd(e) = rightEnd(e) ∨ rightEnd(e) = rightEnd(e)) ∧215 (leftEnd(f2) = rightEnd(e) ∨ rightEnd(f2) = rightEnd(e)) ∧216 (leftEnd(g2) = rightEnd(e) ∨ rightEnd(g2) = rightEnd(e)) :=217⟨atR, atF2, atG2⟩218rw [(labelsAt.pair219with cubic, vertexL, compatible.left, edgesL, incidentL, distinctL),220 (labelsAt.pair221with cubic, vertexR, compatible.left, edgesR, incidentR, distinctR)]222-- At each end the second label is the first shifted by value(e).223have tripleL := flowValue.cubic_vertex224with graph, cubic, cover, vertexL, edgesL, incidentL, distinctL225have tripleR := flowValue.cubic_vertex226with graph, cubic, cover, vertexR, edgesR, incidentR, distinctR227have secondL : t(leftEnd(e)) △ flowValue(F, g) =228 (t(leftEnd(e)) △ flowValue(F, f)) △ flowValue(F, e)229rw tripleL.right230ext z231simp232have secondR : t(rightEnd(e)) △ flowValue(F, g2) =233 (t(rightEnd(e)) △ flowValue(F, f2)) △ flowValue(F, e)234rw tripleR.right235ext z236simp237-- The first label at the right end is the first at the left end shifted238-- by (a △ value(f)) △ (b △ value(f2)) △ s, a sum of three elements of239-- the span of value(e).240obtain⟨s, hs, equation⟩:= compatible.right with e, edge241obtain⟨a, b, baseA, baseB, sumD⟩:= base.right with e, edge242have fe : f ≠ e bycc243have f2e : f2 ≠ e bycc244have otherF : f ∈ E ∧ f ≠ e ∧245 (leftEnd(f) = leftEnd(e) ∨ rightEnd(f) = leftEnd(e)) :=⟨hf, fe, atF⟩246have otherF2 : f2 ∈ E ∧ f2 ≠ e ∧247 (leftEnd(f2) = rightEnd(e) ∨ rightEnd(f2) = rightEnd(e)) :=248⟨hf2, f2e, atF2⟩249have spanA := BasePoint.span250with graph, cubic, cover, vertexL, edge, atL, otherF, baseA251have spanB := BasePoint.span252with graph, cubic, cover, vertexR, edge, atR, otherF2, baseB253have inSpan := span.sum with (span.sum with spanA, spanB), hs254have move : t(leftEnd(e)) △ t(rightEnd(e)) = (a △ b) △ s255rw [equation, sumD]256have shift := symmetricDifference.shift257at t(leftEnd(e)), t(rightEnd(e)), flowValue(F, f), flowValue(F, f2),258 a, b, s with move259rw [secondL, secondR, shift]260rw span.membership at inSpan261rcases inSpan with zero | full262 . rw [zero, symmetricDifference.empty]263 . rw [full, symmetricDifference.cancel_right]264exact pair.commutative265266-- From compatible vertex vectors, the label pair of an edge e = uv is267-- {t(u) △ c, t(u) △ c △ value(e)} for a base point c of u at e; the pair268-- is independent of the end and the base point, and at each vertex every269-- label is carried by an even number of the three ends.270theorem Compatible.labels (V E leftEnd rightEnd F t d : Set)271requires graph : Graph(V, E, leftEnd, rightEnd)272requires finiteEdges : Finite(E)273requires cubic : Cubic(V, E, leftEnd, rightEnd)274requires cover : EvenCover(V, E, leftEnd, rightEnd, F)275requires base : FunctionBetween(d, E, 𝒫(3)) ∧ (∀ e ∈ E, ∃ a, ∃ b,276 BasePoint(V, E, leftEnd, rightEnd, F, leftEnd(e), e, a) ∧277 BasePoint(V, E, leftEnd, rightEnd, F, rightEnd(e), e, b) ∧ d(e) = a △ b)278requires compatible : Compatible(V, E, leftEnd, rightEnd, F, t, d)279shows∃ P, FunctionBetween(P, E, 𝒫(𝒫(3))) ∧280 (∀ e ∈ E, cardinality(P(e)) =2) ∧281 (∀ v ∈ V, ∀ s ∈𝒫(3),282 EvenSet(labelledEnds(leftEnd, rightEnd, E, P, v, s)))283proof284have ends := Graph.ends with graph285have function := labelPairs.function at E, leftEnd, rightEnd, F, t286-- The label pair of an edge x, read at either end v of x.287have atEnd : ∀ v ∈ V, ∀ x ∈ E, (leftEnd(x) = v ∨ rightEnd(x) = v) →288 labelPairs(E, leftEnd, rightEnd, F, t)(x) =289 labelsAt(E, leftEnd, rightEnd, F, t, v, x)290intros v hv x hx xv291rw labelPairs.value with hx292have same := labelsAt.ends with graph, cubic, cover, base, compatible, hx293cases xv with atLeft | atRight294 . cc295 . cc296witness labelPairs(E, leftEnd, rightEnd, F, t)297refine⟨function, ?_, ?_⟩298 . -- Two labels per edge: the other two edges at its left end have299-- distinct values.300intros e he301obtain⟨vertexL, _⟩:= ends with e, he302have atL : leftEnd(e) = leftEnd(e) ∨ rightEnd(e) = leftEnd(e) bysimp303obtain⟨f, hf, g, hg, distinct, atF, atG⟩:=304 Cubic.others with cubic, vertexL, he, atL305have edges : e ∈ E ∧ f ∈ E ∧ g ∈ E :=⟨he, hf, hg⟩306have incident : (leftEnd(e) = leftEnd(e) ∨ rightEnd(e) = leftEnd(e)) ∧307 (leftEnd(f) = leftEnd(e) ∨ rightEnd(f) = leftEnd(e)) ∧308 (leftEnd(g) = leftEnd(e) ∨ rightEnd(g) = leftEnd(e)) :=309⟨atL, atF, atG⟩310rw [(atEnd with leftEnd(e), vertexL, e, he, atL),311 (labelsAt.pair312with cubic, vertexL, compatible.left, edges, incident, distinct)]313have values : flowValue(F, f) ≠ flowValue(F, g) :=314 flowValue.cubic_distinct with graph, cubic, cover, vertexL,315⟨hf, hg⟩, ⟨atF, atG⟩, distinct.right.left316have different :317 t(leftEnd(e)) △ flowValue(F, f) ≠ t(leftEnd(e)) △ flowValue(F, g)318intro same319exact values with (symmetricDifference.cancel_left with same)320exact cardinality.pair with different321 . -- At a vertex with edges e, f, g, the label t(v) △ value(x) is carried322-- by the two ends other than that of x, and no other label is carried.323intros v hv s hs324obtain⟨e, he, f, hf, g, hg, distinct, atE, atF, atG⟩:=325 Cubic.ends_at with cubic, hv326have edges : e ∈ E ∧ f ∈ E ∧ g ∈ E :=⟨he, hf, hg⟩327have incident : (leftEnd(e) = v ∨ rightEnd(e) = v) ∧328 (leftEnd(f) = v ∨ rightEnd(f) = v) ∧329 (leftEnd(g) = v ∨ rightEnd(g) = v) :=330⟨atE, atF, atG⟩331obtain⟨i, hi, j, hj, k, hk, apart, shape⟩:=332 Cubic.ends_of_three with cubic, hv, edges, incident, distinct333have inside : labelledEnds(leftEnd, rightEnd, E,334 labelPairs(E, leftEnd, rightEnd, F, t), v, s) ⊆335 ({(e, i)} ∪ {(f, j)}) ∪ {(g, k)}336rw← shape337intros p hp338exact hp.left339rw EvenSet.of_three with apart, inside340have endE : (e, i) ∈ incidentEnds(leftEnd, rightEnd, E, v) byrw shape; simp341have endF : (f, j) ∈ incidentEnds(leftEnd, rightEnd, E, v) byrw shape; simp342have endG : (g, k) ∈ incidentEnds(leftEnd, rightEnd, E, v) byrw shape; simp343-- The three label pairs, read at v.344have fe : f ≠ e bycc345have ge : g ≠ e bycc346have gf : g ≠ f bycc347have edgesF : f ∈ E ∧ e ∈ E ∧ g ∈ E :=⟨hf, he, hg⟩348have incidentF : (leftEnd(f) = v ∨ rightEnd(f) = v) ∧349 (leftEnd(e) = v ∨ rightEnd(e) = v) ∧350 (leftEnd(g) = v ∨ rightEnd(g) = v) :=351⟨atF, atE, atG⟩352have distinctF : f ≠ e ∧ e ≠ g ∧ f ≠ g :=353⟨fe, distinct.right.right, distinct.right.left⟩354have edgesG : g ∈ E ∧ e ∈ E ∧ f ∈ E :=⟨hg, he, hf⟩355have incidentG : (leftEnd(g) = v ∨ rightEnd(g) = v) ∧356 (leftEnd(e) = v ∨ rightEnd(e) = v) ∧357 (leftEnd(f) = v ∨ rightEnd(f) = v) :=358⟨atG, atE, atF⟩359have distinctG : g ≠ e ∧ e ≠ f ∧ g ≠ f :=⟨ge, distinct.left, gf⟩360have pairE : labelPairs(E, leftEnd, rightEnd, F, t)(e) =361 {t(v) △ flowValue(F, f), t(v) △ flowValue(F, g)}362rw atEnd with v, hv, e, he, atE363exact labelsAt.pair364with cubic, hv, compatible.left, edges, incident, distinct365have pairF : labelPairs(E, leftEnd, rightEnd, F, t)(f) =366 {t(v) △ flowValue(F, e), t(v) △ flowValue(F, g)}367rw atEnd with v, hv, f, hf, atF368exact labelsAt.pair369with cubic, hv, compatible.left, edgesF, incidentF, distinctF370have pairG : labelPairs(E, leftEnd, rightEnd, F, t)(g) =371 {t(v) △ flowValue(F, e), t(v) △ flowValue(F, f)}372rw atEnd with v, hv, g, hg, atG373exact labelsAt.pair374with cubic, hv, compatible.left, edgesG, incidentG, distinctG375-- The three labels are distinct, as the three values are.376have neEF := flowValue.cubic_distinct377with graph, cubic, cover, hv, ⟨he, hf⟩, ⟨atE, atF⟩, distinct.left378have neFG := flowValue.cubic_distinct379with graph, cubic, cover, hv, ⟨hf, hg⟩, ⟨atF, atG⟩, distinct.right.left380have neEG := flowValue.cubic_distinct381with graph, cubic, cover, hv, ⟨he, hg⟩, ⟨atE, atG⟩, distinct.right.right382have apartEF : t(v) △ flowValue(F, e) ≠ t(v) △ flowValue(F, f)383intro same384exact neEF with (symmetricDifference.cancel_left with same)385have apartFG : t(v) △ flowValue(F, f) ≠ t(v) △ flowValue(F, g)386intro same387exact neFG with (symmetricDifference.cancel_left with same)388have apartEG : t(v) △ flowValue(F, e) ≠ t(v) △ flowValue(F, g)389intro same390exact neEG with (symmetricDifference.cancel_left with same)391simp [labelledEnds.membership, endE, endF, endG, fst.pair,392 pairE, pairF, pairG, pair.membership]393