1-- The compatibility condition as a parity system: the unknowns are the2-- coordinates of the vertex vectors and one switch per edge, the rows the3-- coordinates of the edges, and a solution gives a compatible assignment.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.CompatibilitySystem10import Labels1112-- The parity system of the compatibility condition: unknowns are the13-- coordinates (v, i) of the vertex vectors and one switch (e, 3) per edge,14-- tagged so that it never coincides with a vertex coordinate; rows are the15-- coordinates (e, i) of the edges.16def compatibilityMatrix (V E leftEnd rightEnd F : Set) : Set:=17 { p ∈ (E ×3) × ((V ×3) ∪ (E × {3})) |∃ e ∈ E, ∃ i ∈3,18 p = ((e, i), (leftEnd(e), i)) ∨ p = ((e, i), (rightEnd(e), i)) ∨19 (i ∈ flowValue(F, e) ∧ p = ((e, i), (e, 3))) }2021def compatibilitySide (E d : Set) : Set:=22 { p ∈ E ×3|∃ e ∈ E, ∃ i ∈3, i ∈ d(e) ∧ p = (e, i) }2324-- A coordinate of 3 is not the tag 3.25theorem membership.three.ne (i : Set)26requires coordinate : i ∈327shows i ≠328proof29havecases:= membership.three.forward with coordinate30rcasescaseswithrfl|rfl|rfl31 . simp32 . simp33 . simp3435-- The row (e, i) of the matrix meets the two vertex columns of the ends of36-- e and, when i lies in the value of e, the switch column of e.37theorem compatibilityMatrix.row (V E leftEnd rightEnd F e i c : Set)38requires graph : Graph(V, E, leftEnd, rightEnd)39requires edge : e ∈ E40requires coordinate : i ∈341shows ((e, i), c) ∈ compatibilityMatrix(V, E, leftEnd, rightEnd, F) ↔42 (c = (leftEnd(e), i) ∨ c = (rightEnd(e), i) ∨43 (i ∈ flowValue(F, e) ∧ c = (e, 3)))44proof45have ends := Graph.ends with graph46obtain⟨vertexL, vertexR⟩:= ends with e, edge47constructor48 . intro hp49obtain⟨_, x, hx, j, hj, shape⟩:= hp50rcases shape with h | h | h51 . have parts := orderedPair.injective with h52have inner := orderedPair.injective with parts.left53left54cc55 . have parts := orderedPair.injective with h56have inner := orderedPair.injective with parts.left57right58left59cc60 . have parts := orderedPair.injective with h.right61have inner := orderedPair.injective with parts.left62have value := h.left63right64right65constructor66 . cc67 . cc68 . intro hc69have row : (e, i) ∈ E ×3:= product.pair with edge, coordinate70have column : c ∈ (V ×3) ∪ (E × {3})71rcases hc with h | h | h72 . rw h73simp [product.pair_membership, vertexL, coordinate]74 . rw h75simp [product.pair_membership, vertexR, coordinate]76 . rw h.right77simp [product.pair_membership, edge]78have shape : ((e, i), c) = ((e, i), (leftEnd(e), i)) ∨79 ((e, i), c) = ((e, i), (rightEnd(e), i)) ∨80 (i ∈ flowValue(F, e) ∧ ((e, i), c) = ((e, i), (e, 3)))81rcases hc with h | h | h82 . left83cc84 . right85left86cc87 . right88right89constructor90 . exact h.left91 . cc92apply compatibilityMatrix.membership.backward93exact⟨(product.pair with row, column), e, edge, i, coordinate, shape⟩9495-- The entries of the row (e, i): the column of either end of e, and the96-- switch column of e exactly when i lies in the value of e.97theorem compatibilityMatrix.end (V E leftEnd rightEnd F e i v : Set)98requires graph : Graph(V, E, leftEnd, rightEnd)99requires edge : e ∈ E100requires coordinate : i ∈3101requires incident : leftEnd(e) = v ∨ rightEnd(e) = v102shows ((e, i), (v, i)) ∈ compatibilityMatrix(V, E, leftEnd, rightEnd, F)103proof104rw compatibilityMatrix.row with graph, edge, coordinate105rcases incident with h | h106 . left107cc108 . right109left110cc111112theorem compatibilityMatrix.switch (V E leftEnd rightEnd F e i : Set)113requires graph : Graph(V, E, leftEnd, rightEnd)114requires edge : e ∈ E115requires coordinate : i ∈3116shows ((e, i), (e, 3)) ∈ compatibilityMatrix(V, E, leftEnd, rightEnd, F) ↔117 i ∈ flowValue(F, e)118proof119have tag := membership.three.ne with coordinate120have notL : (e, 3) ≠ (leftEnd(e), i)121intro same122apply tag123 symm124exact (orderedPair.injective with same).right125have notR : (e, 3) ≠ (rightEnd(e), i)126intro same127apply tag128 symm129exact (orderedPair.injective with same).right130rw compatibilityMatrix.row with graph, edge, coordinate131simp [notL, notR]132133theorem compatibilitySide.pair (E d e i : Set)134requires edge : e ∈ E135requires coordinate : i ∈3136shows (e, i) ∈ compatibilitySide(E, d) ↔ i ∈ d(e)137proof138constructor139 . intro hp140obtain⟨_, x, hx, j, hj, value, shape⟩:= hp141have parts := orderedPair.injective with shape142cc143 . intro value144apply compatibilitySide.membership.backward145exact⟨(product.pair with edge, coordinate), e, edge, i, coordinate,146 value, rfl⟩147148-- The vertex vectors read off a solution t: v ↦ {i ∈ 3 | (v, i) ∈ t}; the149-- switch of e is value(e) when (e, 3) ∈ t and ∅ otherwise.150def coordinates (t v : Set) : Set:= { i ∈3| (v, i) ∈ t }151152def vertexVectors (V t : Set) : Set:=153 { p ∈ V ×𝒫(3) |∃ v ∈ V, p = (v, coordinates(t, v)) }154155def switch (F t e : Set) : Set:= { i ∈ flowValue(F, e) | (e, 3) ∈ t }156157theorem coordinates.subset (t v : Set)158shows coordinates(t, v) ⊆3159proof160intros i hi161exact hi.left162163theorem vertexVectors.function (V t : Set)164shows vertexVectors(V, t) : V →𝒫(3)165proof166constructor167 . intros p member168exact member.left169 . constructor170 . intros x y xy z xz171obtain⟨_, a, _, shapeY⟩:= xy172obtain⟨_, b, _, shapeZ⟩:= xz173obtain⟨sameA, valueY⟩:= orderedPair.injective with shapeY174obtain⟨sameB, valueZ⟩:= orderedPair.injective with shapeZ175cc176 . intros v hv177have inside : coordinates(t, v) ∈𝒫(3) :=178 powerset.membership_iff.backward with coordinates.subset179refine⟨coordinates(t, v), inside, _⟩180exact vertexVectors.membership.backward181with⟨(product.pair with hv, inside), v, hv, rfl⟩182183theorem vertexVectors.value (V t v : Set)184requires member : v ∈ V185shows vertexVectors(V, t)(v) = coordinates(t, v)186proof187have inside : coordinates(t, v) ∈𝒫(3) :=188 powerset.membership_iff.backward with coordinates.subset189have related : relates(vertexVectors(V, t), v, coordinates(t, v)) :=190 vertexVectors.membership.backward191with⟨(product.pair with member, inside), v, member, rfl⟩192exact FunctionBetween.apply_value193with vertexVectors.function, member, related194195theorem switch.span (F t e : Set)196shows switch(F, t, e) ∈ span(flowValue(F, e))197proof198rw span.membership199 by_cases on : (e, 3) ∈ t200 . right201ext i202simp [switch.membership, on]203 . left204ext i205simp [switch.membership, on]206207-- A solution of the compatibility system gives compatible vertex vectors:208-- the row (e, i) says that t differs at (leftEnd(e), i) and (rightEnd(e), i)209-- exactly when i ∈ d(e), corrected by the switch when i ∈ value(e).210theorem Compatible.of_solution (V E leftEnd rightEnd F d t : Set)211requires graph : Graph(V, E, leftEnd, rightEnd)212requires cubic : Cubic(V, E, leftEnd, rightEnd)213requires side : FunctionBetween(d, E, 𝒫(3))214requires solution : Solves(compatibilityMatrix(V, E, leftEnd, rightEnd, F),215 E ×3, (V ×3) ∪ (E × {3}), compatibilitySide(E, d), t)216shows∃ u, Compatible(V, E, leftEnd, rightEnd, F, u, d)217proof218have ends := Graph.ends with graph219witness vertexVectors(V, t)220refine⟨vertexVectors.function, ?_⟩221intros e he222obtain⟨vertexL, vertexR⟩:= ends with e, he223have loopless := cubic.right with e, he224have inside : d(e) ⊆3:= powerset.membership_iff.forward225with (FunctionBetween.apply_closed with side, he)226witness switch(F, t, e)227refine⟨switch.span, ?_⟩228rw [vertexVectors.value with vertexL, vertexVectors.value with vertexR]229ext i230rw [symmetricDifference.membership, symmetricDifference.membership]231 by_cases hi : i ∈3232 . -- The row (e, i) of the system, read on the three columns it can meet.233have row : (e, i) ∈ E ×3:= product.pair with he, hi234have parity := solution.right with (e, i), row235rw compatibilitySide.pair with he, hi at parity236have tag := membership.three.ne with hi237have apartLR : (leftEnd(e), i) ≠ (rightEnd(e), i)238intro same239exact loopless with (orderedPair.injective with same).left240have apartRS : (rightEnd(e), i) ≠ (e, 3)241intro same242exact tag with (orderedPair.injective with same).right243have apartLS : (leftEnd(e), i) ≠ (e, 3)244intro same245exact tag with (orderedPair.injective with same).right246have apart : (leftEnd(e), i) ≠ (rightEnd(e), i) ∧247 (rightEnd(e), i) ≠ (e, 3) ∧ (leftEnd(e), i) ≠ (e, 3) :=248⟨apartLR, apartRS, apartLS⟩249have columns : fiber(compatibilityMatrix(V, E, leftEnd, rightEnd, F),250 (V ×3) ∪ (E × {3}), (e, i)) ∩ t ⊆251 ({(leftEnd(e), i)} ∪ {(rightEnd(e), i)}) ∪ {(e, 3)}252intros c hc253have entry := hc.left.right254rw compatibilityMatrix.row with graph, he, hi at entry255simp256rw EvenSet.of_three with apart, columns at parity257have columnL : (leftEnd(e), i) ∈ (V ×3) ∪ (E × {3})258bysimp [product.pair_membership, vertexL, hi]259have columnR : (rightEnd(e), i) ∈ (V ×3) ∪ (E × {3})260bysimp [product.pair_membership, vertexR, hi]261have columnS : (e, 3) ∈ (V ×3) ∪ (E × {3})262bysimp [product.pair_membership, he]263have atL : leftEnd(e) = leftEnd(e) ∨ rightEnd(e) = leftEnd(e) bysimp264have atR : leftEnd(e) = rightEnd(e) ∨ rightEnd(e) = rightEnd(e) bysimp265have entryL : ((e, i), (leftEnd(e), i)) ∈266 compatibilityMatrix(V, E, leftEnd, rightEnd, F) :=267 compatibilityMatrix.end with graph, he, hi, atL268have entryR : ((e, i), (rightEnd(e), i)) ∈269 compatibilityMatrix(V, E, leftEnd, rightEnd, F) :=270 compatibilityMatrix.end with graph, he, hi, atR271have entryS : ((e, i), (e, 3)) ∈272 compatibilityMatrix(V, E, leftEnd, rightEnd, F) ↔273 i ∈ flowValue(F, e) :=274 compatibilityMatrix.switch with graph, he, hi275simp [fiber.membership, columnL, columnR, columnS, entryL, entryR,276 entryS] at parity277simp [coordinates.membership, switch.membership, hi]278 . -- Outside 3 none of the four sets holds i.279have notD : ¬i ∈ d(e)280intro h281exact hi with (inside with i, h)282simp [coordinates.membership, switch.membership, flowValue, hi, notD]283