1-- The dual obstruction computation: a left-kernel vector of the2-- compatibility system gives at each edge a vector orthogonal to its value,3-- the odd ends regroup over the vertices into an even set, and so no4-- left-kernel vector sees an odd right-hand side.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.DoubleCover.Obstruction11import CompatibilitySystem1213-- Parity of a subset of 3 through its three membership bits.14theorem EvenSet.three_bits (X Y : Set)15requires inside : X ⊆316shows EvenSet(X ∩ Y) ↔17 (((0∈ X ∧0∈ Y) ↔ (1∈ X ∧1∈ Y)) ↔¬(2∈ X ∧2∈ Y))18proof19have apart : 0≠1∧1≠2∧0≠2bysimp20have cover : X ∩ Y ⊆ ({0} ∪ {1}) ∪ {2}21intros z hz22have hz3 := inside with z, hz.left23rw membership.three at hz324simp25rw EvenSet.of_three with apart, cover26simp [intersection.membership]2728theorem subset_three.empty_iff (X : Set)29requires inside : X ⊆330shows X =∅↔ (¬0∈ X ∧¬1∈ X ∧¬2∈ X)31proof32constructor33 . intro empty34rw empty35simp36 . intro bits37ext z38constructor39 . intro hz40have hz3 := inside with z, hz41rw membership.three at hz342exfalso43rcases hz3 withrfl|rfl|rfl44 . exact bits.left with hz45 . exact bits.right.left with hz46 . exact bits.right.right with hz47 . intro hz48simpat hz4950theorem subset_three.eq_iff (X Y : Set)51requires insideX : X ⊆352requires insideY : Y ⊆353shows X = Y ↔ ((0∈ X ↔0∈ Y) ∧ (1∈ X ↔1∈ Y) ∧ (2∈ X ↔2∈ Y))54proof55constructor56 . intro same57rw same58tauto59 . intro bits60ext z61 by_cases hz : z ∈362 . rw membership.three at hz63rcases hz withrfl|rfl|rfl64 . exact bits.left65 . exact bits.right.left66 . exact bits.right.right67 . have notX : ¬z ∈ X68intro h69exact hz with (insideX with z, h)70have notY : ¬z ∈ Y71intro h72exact hz with (insideY with z, h)73tauto7475-- The vertex computation of the paper, in the two-element field with three76-- coordinates: at a vertex the three vectors h(e), h(f), h(g) = h(e) △ h(f)77-- are each orthogonal to the matching value, and the values are nonzero and78-- distinct with value(g) = value(e) △ value(f). Then h(e) · value(f) is odd79-- exactly when an odd number of the three h are nonzero.80theorem vertex.parity (he hf hg ve vf vg : Set)81requires insideE : he ⊆382requires insideF : hf ⊆383requires valueE : ve ⊆384requires valueF : vf ⊆385requires sumH : hg = he △ hf86requires sumV : vg = ve △ vf87requires nonzeroE : ve ≠∅88requires nonzeroF : vf ≠∅89requires distinct : ve ≠ vf90requires orthogonalE : EvenSet(he ∩ ve)91requires orthogonalF : EvenSet(hf ∩ vf)92requires orthogonalG : EvenSet(hg ∩ vg)93shows EvenSet(he ∩ vf) ↔ ((he ≠∅↔ hf ≠∅) ↔ hg =∅)94proof95have insideG : hg ⊆396rw sumH97exact symmetricDifference.subset with insideE, insideF98have bitsG : ∀ i, (i ∈ hg ↔¬(i ∈ he ↔ i ∈ hf))99intro i100rw sumH101exact symmetricDifference.membership102have bitsV : ∀ i, (i ∈ vg ↔¬(i ∈ ve ↔ i ∈ vf))103intro i104rw sumV105exact symmetricDifference.membership106have g0 := bitsG with0107have g1 := bitsG with1108have g2 := bitsG with2109have v0 := bitsV with0110have v1 := bitsV with1111have v2 := bitsV with2112rw EvenSet.three_bits with insideE at orthogonalE113rw EvenSet.three_bits with insideF at orthogonalF114rw EvenSet.three_bits with insideG at orthogonalG115rw EvenSet.three_bits with insideE116rw subset_three.empty_iff with valueE at nonzeroE117rw subset_three.empty_iff with valueF at nonzeroF118rw subset_three.eq_iff with valueE, valueF at distinct119rw [subset_three.empty_iff with insideE, subset_three.empty_iff with insideF,120 subset_three.empty_iff with insideG]121tauto122123-- The vector h(e) of a left-kernel vector y at the edge e.124def rowSet (y e : Set) : Set:= { i ∈3| (e, i) ∈ y }125126theorem rowSet.subset (y e : Set)127shows rowSet(y, e) ⊆3128proof129intros i hi130exact hi.left131132theorem rowSet.finite (y e : Set)133shows Finite(rowSet(y, e))134proof135exact Finite.subset with Finite.natural, rowSet.subset136137-- The switch column of e: y meets it in {e} × (h(e) ∩ value(e)), so h(e) is138-- orthogonal to value(e).139theorem Obstructs.switch (V E leftEnd rightEnd F d y e : Set)140requires graph : Graph(V, E, leftEnd, rightEnd)141requires edge : e ∈ E142requires obstruction : Obstructs(143 compatibilityMatrix(V, E, leftEnd, rightEnd, F), E ×3,144 (V ×3) ∪ (E × {3}), compatibilitySide(E, d), y)145shows EvenSet(rowSet(y, e) ∩ flowValue(F, e))146proof147have column : (e, 3) ∈ (V ×3) ∪ (E × {3})148bysimp [product.pair_membership, edge]149have even := obstruction.right.left with (e, 3), column150have finite : Finite(rowSet(y, e) ∩ flowValue(F, e)) :=151 Finite.subset with rowSet.finite, intersection.subset_left152have block : cofiber(compatibilityMatrix(V, E, leftEnd, rightEnd, F),153 E ×3, (e, 3)) ∩ y = {e} × (rowSet(y, e) ∩ flowValue(F, e))154ext p155constructor156 . intro hp157obtain⟨⟨row, entry⟩, hy⟩:= hp158obtain⟨_, x, hx, j, hj, rfl⟩:= product.membership.forward with row159rw compatibilityMatrix.row with graph, hx, hj at entry160have tag := membership.three.ne with hj161rcases entry with h | h | h162 . exfalso163have parts := orderedPair.injective with h164apply tag165cc166 . exfalso167have parts := orderedPair.injective with h168apply tag169cc170 . have parts := orderedPair.injective with h.right171have xe : x = e bycc172rw xe at hy, h173rw xe174have inRow : j ∈ rowSet(y, e) ∩ flowValue(F, e) :=⟨⟨hj, hy⟩, h.left⟩175exact product.pair with singleton.self, inRow176 . intro hp177obtain⟨_, x, hx, j, hj, rfl⟩:= product.membership.forward with hp178have xe := singleton.membership.forward with hx179rw xe180obtain⟨⟨hj3, hy⟩, value⟩:= hj181have entry : ((e, j), (e, 3)) ∈182 compatibilityMatrix(V, E, leftEnd, rightEnd, F) :=183 compatibilityMatrix.switch.backward with graph, edge, hj3, value184exact⟨⟨(product.pair with edge, hj3), entry⟩, hy⟩185rw block at even186unfold EvenSet at even187rw cardinality.singleton_product with finite at even188exact even189190-- A vertex column (v, i) at the vertex v with edges e, f, g: y meets it in191-- the rows (e, i), (f, i), (g, i) it holds, so h(g) = h(e) △ h(f) at v.192theorem Obstructs.vertex (V E leftEnd rightEnd F d y v e f g i : Set)193requires graph : Graph(V, E, leftEnd, rightEnd)194requires cubic : Cubic(V, E, leftEnd, rightEnd)195requires vertex : v ∈ V196requires edges : e ∈ E ∧ f ∈ E ∧ g ∈ E197requires incident : (leftEnd(e) = v ∨ rightEnd(e) = v) ∧198 (leftEnd(f) = v ∨ rightEnd(f) = v) ∧199 (leftEnd(g) = v ∨ rightEnd(g) = v)200requires distinct : e ≠ f ∧ f ≠ g ∧ e ≠ g201requires coordinate : i ∈3202requires obstruction : Obstructs(203 compatibilityMatrix(V, E, leftEnd, rightEnd, F), E ×3,204 (V ×3) ∪ (E × {3}), compatibilitySide(E, d), y)205shows i ∈ rowSet(y, g) ↔¬(i ∈ rowSet(y, e) ↔ i ∈ rowSet(y, f))206proof207have column : (v, i) ∈ (V ×3) ∪ (E × {3})208bysimp [product.pair_membership, vertex, coordinate]209have even := obstruction.right.left with (v, i), column210have apartEF : (e, i) ≠ (f, i)211intro same212exact distinct.left with (orderedPair.injective with same).left213have apartFG : (f, i) ≠ (g, i)214intro same215exact distinct.right.left with (orderedPair.injective with same).left216have apartEG : (e, i) ≠ (g, i)217intro same218exact distinct.right.right with (orderedPair.injective with same).left219have apart : (e, i) ≠ (f, i) ∧ (f, i) ≠ (g, i) ∧ (e, i) ≠ (g, i) :=220⟨apartEF, apartFG, apartEG⟩221have tag := membership.three.ne with coordinate222-- A row meeting the column (v, i) is (x, i) for an edge x at v, hence one223-- of e, f, g.224have inside : cofiber(compatibilityMatrix(V, E, leftEnd, rightEnd, F),225 E ×3, (v, i)) ∩ y ⊆ ({(e, i)} ∪ {(f, i)}) ∪ {(g, i)}226intros p hp227obtain⟨⟨row, entry⟩, _⟩:= hp228obtain⟨_, x, hx, j, hj, rfl⟩:= product.membership.forward with row229rw compatibilityMatrix.row with graph, hx, hj at entry230have located : (leftEnd(x) = v ∨ rightEnd(x) = v) ∧ j = i231rcases entry with h | h | h232 . have parts := orderedPair.injective with h233constructor234 . left235cc236 . cc237 . have parts := orderedPair.injective with h238constructor239 . right240cc241 . cc242 . exfalso243have parts := orderedPair.injective with h.right244apply tag245cc246havecases:= Cubic.among247with cubic, vertex, edges, incident, distinct, hx, located.left248rw located.right249simp250rw EvenSet.of_three with apart, inside at even251have entryE : ((e, i), (v, i)) ∈252 compatibilityMatrix(V, E, leftEnd, rightEnd, F) :=253 compatibilityMatrix.end with graph, edges.left, coordinate, incident.left254have entryF : ((f, i), (v, i)) ∈255 compatibilityMatrix(V, E, leftEnd, rightEnd, F) :=256 compatibilityMatrix.end257with graph, edges.right.left, coordinate, incident.right.left258have entryG : ((g, i), (v, i)) ∈259 compatibilityMatrix(V, E, leftEnd, rightEnd, F) :=260 compatibilityMatrix.end261with graph, edges.right.right, coordinate, incident.right.right262have memberE : (e, i) ∈263 cofiber(compatibilityMatrix(V, E, leftEnd, rightEnd, F),264 E ×3, (v, i)) ∩ y ↔ (e, i) ∈ y265constructor266 . intro hp267exact hp.right268 . intro hy269exact⟨⟨(product.pair with edges.left, coordinate), entryE⟩, hy⟩270have memberF : (f, i) ∈271 cofiber(compatibilityMatrix(V, E, leftEnd, rightEnd, F),272 E ×3, (v, i)) ∩ y ↔ (f, i) ∈ y273constructor274 . intro hp275exact hp.right276 . intro hy277exact⟨⟨(product.pair with edges.right.left, coordinate), entryF⟩, hy⟩278have memberG : (g, i) ∈279 cofiber(compatibilityMatrix(V, E, leftEnd, rightEnd, F),280 E ×3, (v, i)) ∩ y ↔ (g, i) ∈ y281constructor282 . intro hp283exact hp.right284 . intro hy285exact⟨⟨(product.pair with edges.right.right, coordinate), entryG⟩, hy⟩286rw [memberE, memberF, memberG] at even287unfold rowSet288tauto289290-- Parity of a set partitioned by a finite index: the members of S covered291-- by the indices of G, through a relation P pairing indices with members.292def covered (P S G : Set) : Set:= { x ∈ S |∃ i ∈ G, (i, x) ∈ P }293294theorem covered.subset (P S G : Set)295shows covered(P, S, G) ⊆ S296proof297intros x hx298exact hx.left299300theorem covered.empty (P S : Set)301shows covered(P, S, ∅) =∅302proof303ext x304simp [covered.membership]305306theorem covered.insert (P S G a : Set)307shows covered(P, S, G ∪ {a}) = covered(P, S, G) ∪ fiber(P, S, a)308proof309ext x310havesplit : x ∈ covered(P, S, G) ∪ fiber(P, S, a) ↔311 (x ∈ covered(P, S, G) ∨ x ∈ fiber(P, S, a))312bysimp313rwsplit314constructor315 . intro hx316obtain⟨hs, i, hi, related⟩:= hx317simpat hi318rcases hi with inG | same319 . left320exact⟨hs, i, inG, related⟩321 . right322rw same at related323exact⟨hs, related⟩324 . intro hx325rcases hx with inG | inA326 . obtain⟨hs, i, hi, related⟩:= inG327have hi2 : i ∈ G ∪ {a} bysimp [hi]328exact⟨hs, i, hi2, related⟩329 . have ha : a ∈ G ∪ {a} bysimp330exact⟨inA.left, a, ha, inA.right⟩331332-- When every member has one index, the part of a fresh index is disjoint333-- from the members covered so far.334theorem covered.disjoint (I P S G a : Set)335requires unique : ∀ i ∈ I, ∀ j ∈ I, ∀ x, (i, x) ∈ P → (j, x) ∈ P → i = j336requires inside : G ⊆ I337requires member : a ∈ I338requires fresh : ¬a ∈ G339shows Disjoint(covered(P, S, G), fiber(P, S, a))340proof341apply Disjoint.iff.backward342intros x hx hx2343obtain⟨_, i, hi, related⟩:= hx344have same := unique with i, (inside with i, hi), a, member, x, related,345 hx2.right346rw same at hi347exact fresh with hi348349theorem covered.parity (I S T P Q : Set)350requires finiteIndex : Finite(I)351requires finiteS : Finite(S)352requires finiteT : Finite(T)353requires uniqueP : ∀ i ∈ I, ∀ j ∈ I, ∀ x, (i, x) ∈ P → (j, x) ∈ P → i = j354requires uniqueQ : ∀ i ∈ I, ∀ j ∈ I, ∀ x, (i, x) ∈ Q → (j, x) ∈ Q → i = j355requires parts : ∀ i ∈ I, (EvenSet(fiber(P, S, i)) ↔ EvenSet(fiber(Q, T, i)))356shows EvenSet(covered(P, S, I)) ↔ EvenSet(covered(Q, T, I))357proof358induction finiteIndex with G a359| empty =>360rw [covered.empty, covered.empty]361| insert using ih =>362rw [covered.insert, covered.insert]363have finiteGS : Finite(covered(P, S, G)) :=364 Finite.subset with finiteS, covered.subset365have finiteGT : Finite(covered(Q, T, G)) :=366 Finite.subset with finiteT, covered.subset367have finiteAS : Finite(fiber(P, S, a)) := fiber.finite with finiteS368have finiteAT : Finite(fiber(Q, T, a)) := fiber.finite with finiteT369have apartS := covered.disjoint at _, _, S, _, _370with uniqueP, GSubset, aMember, aFresh371have apartT := covered.disjoint at _, _, T, _, _372with uniqueQ, GSubset, aMember, aFresh373rw [(EvenSet.union_disjoint with finiteGS, finiteAS, apartS),374 (EvenSet.union_disjoint with finiteGT, finiteAT, apartT)]375have part := parts with a, aMember376tauto377378-- Two finite sets partitioned by the same finite index set, with parts of379-- equal parity index by index, have the same parity.380theorem EvenSet.of_parts (I S T P Q : Set)381requires finiteIndex : Finite(I)382requires finiteS : Finite(S)383requires finiteT : Finite(T)384requires coverS : ∀ x ∈ S, ∃ i ∈ I, (i, x) ∈ P385requires coverT : ∀ x ∈ T, ∃ i ∈ I, (i, x) ∈ Q386requires uniqueP : ∀ i ∈ I, ∀ j ∈ I, ∀ x, (i, x) ∈ P → (j, x) ∈ P → i = j387requires uniqueQ : ∀ i ∈ I, ∀ j ∈ I, ∀ x, (i, x) ∈ Q → (j, x) ∈ Q → i = j388requires parts : ∀ i ∈ I, (EvenSet(fiber(P, S, i)) ↔ EvenSet(fiber(Q, T, i)))389shows EvenSet(S) ↔ EvenSet(T)390proof391have wholeS : covered(P, S, I) = S392ext x393constructor394 . intro hx395exact hx.left396 . intro hx397exact⟨hx, (coverS with x, hx)⟩398have wholeT : covered(Q, T, I) = T399ext x400constructor401 . intro hx402exact hx.left403 . intro hx404exact⟨hx, (coverT with x, hx)⟩405rw [← wholeS, ← wholeT]406exact covered.parity407with finiteIndex, finiteS, finiteT, uniqueP, uniqueQ, parts408409-- The two index relations: a pair of I × X indexed by its first entry, and410-- an end indexed by its vertex.411def byFirst (I X : Set) : Set:= { q ∈ I × X | fst(snd(q)) = fst(q) }412413def atVertex (V E leftEnd rightEnd : Set) : Set:=414 { q ∈ V × (E ×2) | snd(q) ∈ incidentEnds(leftEnd, rightEnd, E, fst(q)) }415416theorem byFirst.pair (I X i x : Set)417shows (i, x) ∈ byFirst(I, X) ↔ (i ∈ I ∧ x ∈ X ∧ fst(x) = i)418proof419simp [byFirst.membership, product.pair_membership, fst.pair, snd.pair]420421-- A pair (e, j) of E × X is indexed by e.422theorem byFirst.of_pair (E X e j : Set)423requires edge : e ∈ E424requires member : (e, j) ∈ E × X425shows (e, (e, j)) ∈ byFirst(E, E × X)426proof427rw byFirst.pair428exact⟨edge, member, fst.pair⟩429430theorem atVertex.pair (V E leftEnd rightEnd v p : Set)431shows (v, p) ∈ atVertex(V, E, leftEnd, rightEnd) ↔432 (v ∈ V ∧ p ∈ E ×2∧ p ∈ incidentEnds(leftEnd, rightEnd, E, v))433proof434simp [atVertex.membership, product.pair_membership, fst.pair, snd.pair]435436theorem byFirst.unique (I X : Set)437shows∀ i ∈ I, ∀ j ∈ I, ∀ x,438 (i, x) ∈ byFirst(I, X) → (j, x) ∈ byFirst(I, X) → i = j439proof440intros i hi j hj x hix hjx441rw byFirst.pair at hix, hjx442cc443444-- Every pair of E × X is indexed by an edge.445theorem byFirst.cover (E X p : Set)446requires member : p ∈ E × X447shows∃ e ∈ E, (e, p) ∈ byFirst(E, E × X)448proof449obtain⟨_, e, he, j, hj, rfl⟩:= product.membership.forward with member450exact⟨e, he, (byFirst.of_pair with he, member)⟩451452-- An end lies at one vertex.453theorem incidentEnds.vertex_unique (leftEnd rightEnd E v w p : Set)454requires first : p ∈ incidentEnds(leftEnd, rightEnd, E, v)455requires second : p ∈ incidentEnds(leftEnd, rightEnd, E, w)456shows v = w457proof458obtain⟨e, he, j, hj, rfl⟩:= incidentEnds.shape with first459have sidesV := (incidentEnds.pair.forward with first).right460have sidesW := (incidentEnds.pair.forward with second).right461have apart : 0≠1bysimp462rcases sidesV with⟨h0, atL⟩|⟨h1, atR⟩463 . rcases sidesW with⟨_, atL2⟩|⟨h1, _⟩464 . cc465 . exfalso466apply apart467cc468 . rcases sidesW with⟨h0, _⟩|⟨_, atR2⟩469 . exfalso470apply apart471cc472 . cc473474theorem atVertex.unique (V E leftEnd rightEnd : Set)475shows∀ v ∈ V, ∀ w ∈ V, ∀ p, (v, p) ∈ atVertex(V, E, leftEnd, rightEnd) →476 (w, p) ∈ atVertex(V, E, leftEnd, rightEnd) → v = w477proof478intros v hv w hw p hvp hwp479rw atVertex.pair at hvp, hwp480exact incidentEnds.vertex_unique with hvp.right.right, hwp.right.right481482-- Every end of E lies at a vertex of V.483theorem atVertex.cover (V E leftEnd rightEnd p : Set)484requires ends : ∀ e ∈ E, leftEnd(e) ∈ V ∧ rightEnd(e) ∈ V485requires member : p ∈ E ×2486shows∃ v ∈ V, (v, p) ∈ atVertex(V, E, leftEnd, rightEnd)487proof488obtain⟨_, e, he, j, hj, rfl⟩:= product.membership.forward with member489obtain⟨vertexL, vertexR⟩:= ends with e, he490havecases:= membership.two.forward with hj491rcasescaseswithrfl|rfl492 . refine⟨leftEnd(e), vertexL, ?_⟩493rw atVertex.pair494refine⟨vertexL, member, ?_⟩495simp [incidentEnds.pair, he]496 . refine⟨rightEnd(e), vertexR, ?_⟩497rw atVertex.pair498refine⟨vertexR, member, ?_⟩499simp [incidentEnds.pair, he]500501-- The part of a set of pairs at the index v, through atVertex, is its502-- intersection with the ends at v.503theorem atVertex.fiber (V E leftEnd rightEnd S v : Set)504requires vertex : v ∈ V505requires pairs : S ⊆ E ×2506shows fiber(atVertex(V, E, leftEnd, rightEnd), S, v) =507 S ∩ incidentEnds(leftEnd, rightEnd, E, v)508proof509ext p510constructor511 . intro hp512have related := hp.right513rw atVertex.pair at related514exact⟨hp.left, related.right.right⟩515 . intro hp516have related : (v, p) ∈ atVertex(V, E, leftEnd, rightEnd)517rw atVertex.pair518exact⟨vertex, (pairs with p, hp.left), hp.right⟩519exact⟨hp.left, related⟩520521-- Parity of a subset of a two-element set, and of an intersection with a522-- symmetric difference.523theorem EvenSet.of_two (S a b : Set)524requires apart : a ≠ b525requires inside : S ⊆ {a} ∪ {b}526shows EvenSet(S) ↔ (¬a ∈ S ↔¬b ∈ S)527proof528have whole : S ∩ ({a} ∪ {b}) = S := intersection.eq_left_of_subset with inside529have freshB : ¬b ∈ {a} bysimp530have stepB := EvenSet.intersection_union_part531at S, {a}, {b}, b with Finite.singleton, Subset.reflexive, freshB532have stepA : EvenSet(S ∩ {a}) ↔¬a ∈ S533rw intersection.commutative534exact EvenSet.singleton_intersection535rw whole at stepB536rw [stepB, stepA]537simp538539theorem EvenSet.intersection_symmetricDifference (X A B : Set)540requires finiteX : Finite(X)541requires finiteA : Finite(A)542requires finiteB : Finite(B)543shows EvenSet(X ∩ (A △ B)) ↔ (EvenSet(X ∩ A) ↔ EvenSet(X ∩ B))544proof545have step := dot.symmetricDifference with finiteA, finiteB, finiteX546unfold dot at step547unfold EvenSet548rw [intersection.commutative, (intersection.commutative at X, A),549 (intersection.commutative at X, B)]550exact step551552-- The ends whose edge has a nonzero vector h, the vertices at which an odd553-- number of them meet, and the ends at those vertices.554def nonzeroEnds (E y : Set) : Set:= { p ∈ E ×2| rowSet(y, fst(p)) ≠∅ }555556predicate OddVertex (E leftEnd rightEnd y v : Set) :=557¬EvenSet(nonzeroEnds(E, y) ∩ incidentEnds(leftEnd, rightEnd, E, v))558559def oddEnds (V E leftEnd rightEnd y : Set) : Set:=560 { p ∈ E ×2|∃ v ∈ V, p ∈ incidentEnds(leftEnd, rightEnd, E, v) ∧561 OddVertex(E, leftEnd, rightEnd, y, v) }562563theorem nonzeroEnds.subset (E y : Set)564shows nonzeroEnds(E, y) ⊆ E ×2565proof566intros p hp567exact hp.left568569theorem oddEnds.subset (V E leftEnd rightEnd y : Set)570shows oddEnds(V, E, leftEnd, rightEnd, y) ⊆ E ×2571proof572intros p hp573exact hp.left574575-- At a cubic vertex with edges e, f, g the parity of the nonzero ends is576-- read off the three vectors.577theorem OddVertex.of_three (V E leftEnd rightEnd y v e f g : Set)578requires cubic : Cubic(V, E, leftEnd, rightEnd)579requires vertex : v ∈ V580requires edges : e ∈ E ∧ f ∈ E ∧ g ∈ E581requires incident : (leftEnd(e) = v ∨ rightEnd(e) = v) ∧582 (leftEnd(f) = v ∨ rightEnd(f) = v) ∧583 (leftEnd(g) = v ∨ rightEnd(g) = v)584requires distinct : e ≠ f ∧ f ≠ g ∧ e ≠ g585shows OddVertex(E, leftEnd, rightEnd, y, v) ↔586¬((¬rowSet(y, e) ≠∅↔¬rowSet(y, f) ≠∅) ↔¬rowSet(y, g) ≠∅)587proof588obtain⟨i, hi, j, hj, k, hk, apart, shape⟩:=589 Cubic.ends_of_three with cubic, vertex, edges, incident, distinct590have endE : (e, i) ∈ incidentEnds(leftEnd, rightEnd, E, v) byrw shape; simp591have endF : (f, j) ∈ incidentEnds(leftEnd, rightEnd, E, v) byrw shape; simp592have endG : (g, k) ∈ incidentEnds(leftEnd, rightEnd, E, v) byrw shape; simp593have pairE : (e, i) ∈ E ×2:= product.pair with edges.left, hi594have pairF : (f, j) ∈ E ×2:= product.pair with edges.right.left, hj595have pairG : (g, k) ∈ E ×2:= product.pair with edges.right.right, hk596have inside : nonzeroEnds(E, y) ∩ incidentEnds(leftEnd, rightEnd, E, v) ⊆597 ({(e, i)} ∪ {(f, j)}) ∪ {(g, k)}598rw← shape599intros p hp600exact hp.right601unfold OddVertex602rw EvenSet.of_three with apart, inside603simp [nonzeroEnds.membership, intersection.membership, pairE, pairF, pairG,604 endE, endF, endG, fst.pair]605606-- The vertex computation for an obstruction: at v with the distinct edges607-- e, x, z, the vector of e is orthogonal to the value of x exactly when an608-- even number of the three vectors are nonzero.609theorem Obstructs.triple_parity (V E leftEnd rightEnd F d y v e x z : Set)610requires graph : Graph(V, E, leftEnd, rightEnd)611requires cubic : Cubic(V, E, leftEnd, rightEnd)612requires cover : EvenCover(V, E, leftEnd, rightEnd, F)613requires vertex : v ∈ V614requires edges : e ∈ E ∧ x ∈ E ∧ z ∈ E615requires incident : (leftEnd(e) = v ∨ rightEnd(e) = v) ∧616 (leftEnd(x) = v ∨ rightEnd(x) = v) ∧617 (leftEnd(z) = v ∨ rightEnd(z) = v)618requires distinct : e ≠ x ∧ x ≠ z ∧ e ≠ z619requires obstruction : Obstructs(620 compatibilityMatrix(V, E, leftEnd, rightEnd, F), E ×3,621 (V ×3) ∪ (E × {3}), compatibilitySide(E, d), y)622shows EvenSet(rowSet(y, e) ∩ flowValue(F, x)) ↔623¬OddVertex(E, leftEnd, rightEnd, y, v)624proof625-- The three vectors sum to zero at v, and so do the three values.626have sumH : rowSet(y, z) = rowSet(y, e) △ rowSet(y, x)627ext i628rw symmetricDifference.membership629 by_cases hi : i ∈3630 . exact Obstructs.vertex631with graph, cubic, vertex, edges, incident, distinct, hi, obstruction632 . simp [rowSet, hi]633have triple := flowValue.cubic_vertex634with graph, cubic, cover, vertex, edges, incident, distinct635have nonzeroE := flowValue.nonzero with cover, edges.left636have nonzeroX := flowValue.nonzero with cover, edges.right.left637have orthogonalE := Obstructs.switch with graph, edges.left, obstruction638have orthogonalX :=639 Obstructs.switch with graph, edges.right.left, obstruction640have orthogonalZ :=641 Obstructs.switch with graph, edges.right.right, obstruction642have parity := vertex.parity643at rowSet(y, e), rowSet(y, x), rowSet(y, z),644 flowValue(F, e), flowValue(F, x), flowValue(F, z)645with rowSet.subset, rowSet.subset, flowValue.subset, flowValue.subset,646 sumH, triple.right, nonzeroE, nonzeroX, triple.left,647 orthogonalE, orthogonalX, orthogonalZ648rw [parity,649 (OddVertex.of_three with cubic, vertex, edges, incident, distinct)]650tauto651652-- The same for any two distinct edges e, x at v.653theorem Obstructs.end_parity (V E leftEnd rightEnd F d y v e x : Set)654requires graph : Graph(V, E, leftEnd, rightEnd)655requires cubic : Cubic(V, E, leftEnd, rightEnd)656requires cover : EvenCover(V, E, leftEnd, rightEnd, F)657requires vertex : v ∈ V658requires edge : e ∈ E659requires incident : leftEnd(e) = v ∨ rightEnd(e) = v660requires other : x ∈ E ∧ x ≠ e ∧ (leftEnd(x) = v ∨ rightEnd(x) = v)661requires obstruction : Obstructs(662 compatibilityMatrix(V, E, leftEnd, rightEnd, F), E ×3,663 (V ×3) ∪ (E × {3}), compatibilitySide(E, d), y)664shows EvenSet(rowSet(y, e) ∩ flowValue(F, x)) ↔665¬OddVertex(E, leftEnd, rightEnd, y, v)666proof667obtain⟨f, hf, g, hg, distinct, atF, atG⟩:=668 Cubic.others with cubic, vertex, edge, incident669have edges : e ∈ E ∧ f ∈ E ∧ g ∈ E :=⟨edge, hf, hg⟩670have incident3 : (leftEnd(e) = v ∨ rightEnd(e) = v) ∧671 (leftEnd(f) = v ∨ rightEnd(f) = v) ∧672 (leftEnd(g) = v ∨ rightEnd(g) = v) :=673⟨incident, atF, atG⟩674havecases:= Cubic.among with cubic, vertex, edges, incident3, distinct,675 other.left, other.right.right676rcasescaseswith same | same | same677 . exfalso678exact other.right.left with same679 . rw same680exact Obstructs.triple_parity with graph, cubic, cover, vertex, edges,681 incident3, distinct, obstruction682 . rw same683have edgesG : e ∈ E ∧ g ∈ E ∧ f ∈ E :=⟨edge, hg, hf⟩684have incidentG : (leftEnd(e) = v ∨ rightEnd(e) = v) ∧685 (leftEnd(g) = v ∨ rightEnd(g) = v) ∧686 (leftEnd(f) = v ∨ rightEnd(f) = v) :=687⟨incident, atG, atF⟩688have gf : g ≠ f bycc689have distinctG : e ≠ g ∧ g ≠ f ∧ e ≠ f :=690⟨distinct.right.right, gf, distinct.left⟩691exact Obstructs.triple_parity with graph, cubic, cover, vertex, edgesG,692 incidentG, distinctG, obstruction693694-- The parts of the odd ends and of the nonzero ends at a vertex v: all three695-- ends or none, and the nonzero ends at v.696theorem oddEnds.fiber (V E leftEnd rightEnd y v : Set)697requires cubic : Cubic(V, E, leftEnd, rightEnd)698requires vertex : v ∈ V699shows EvenSet(fiber(atVertex(V, E, leftEnd, rightEnd),700 oddEnds(V, E, leftEnd, rightEnd, y), v)) ↔701¬OddVertex(E, leftEnd, rightEnd, y, v)702proof703have pairs : oddEnds(V, E, leftEnd, rightEnd, y) ⊆ E ×2:= oddEnds.subset704rw atVertex.fiber with vertex, pairs705 by_cases odd : OddVertex(E, leftEnd, rightEnd, y, v)706 . -- Every end at v is odd, and there are three of them.707have whole : oddEnds(V, E, leftEnd, rightEnd, y) ∩708 incidentEnds(leftEnd, rightEnd, E, v) =709 incidentEnds(leftEnd, rightEnd, E, v)710ext p711constructor712 . intro hp713exact hp.right714 . intro hp715have product := incidentEnds.subset_product at leftEnd, rightEnd, E, v716have pair : p ∈ E ×2:= product with p, hp717exact⟨⟨pair, v, vertex, hp, odd⟩, hp⟩718rw whole719obtain⟨e, he, f, hf, g, hg, distinct, atE, atF, atG⟩:=720 Cubic.ends_at with cubic, vertex721have edges : e ∈ E ∧ f ∈ E ∧ g ∈ E :=⟨he, hf, hg⟩722have incident : (leftEnd(e) = v ∨ rightEnd(e) = v) ∧723 (leftEnd(f) = v ∨ rightEnd(f) = v) ∧724 (leftEnd(g) = v ∨ rightEnd(g) = v) :=725⟨atE, atF, atG⟩726obtain⟨i, hi, j, hj, k, hk, apart, shape⟩:=727 Cubic.ends_of_three with cubic, vertex, edges, incident, distinct728have inside : incidentEnds(leftEnd, rightEnd, E, v) ⊆729 ({(e, i)} ∪ {(f, j)}) ∪ {(g, k)}730rw shape731exact Subset.reflexive732rw [(EvenSet.of_three with apart, inside), shape]733simp [odd]734 . -- No end at v is odd.735have none : oddEnds(V, E, leftEnd, rightEnd, y) ∩736 incidentEnds(leftEnd, rightEnd, E, v) =∅737ext p738constructor739 . intro hp740obtain⟨⟨_, w, hw, atW, oddW⟩, atV⟩:= hp741have same := incidentEnds.vertex_unique with atV, atW742rw same at odd743exfalso744exact odd with oddW745 . intro hp746simpat hp747rw none748simp [EvenSet.empty, odd]749750theorem nonzeroEnds.fiber (V E leftEnd rightEnd y v : Set)751requires vertex : v ∈ V752shows EvenSet(fiber(atVertex(V, E, leftEnd, rightEnd), nonzeroEnds(E, y), v))753↔¬OddVertex(E, leftEnd, rightEnd, y, v)754proof755have pairs : nonzeroEnds(E, y) ⊆ E ×2:= nonzeroEnds.subset756rw atVertex.fiber with vertex, pairs757unfold OddVertex758tauto759760-- The nonzero ends are even in number: each edge contributes both its ends761-- or neither.762theorem nonzeroEnds.even (E y : Set)763requires finiteEdges : Finite(E)764shows EvenSet(nonzeroEnds(E, y))765proof766have finiteEnds : Finite(E ×2) :=767 Finite.product with finiteEdges, Finite.natural768have finite : Finite(nonzeroEnds(E, y)) :=769 Finite.subset with finiteEnds, nonzeroEnds.subset770have cover : ∀ p ∈ nonzeroEnds(E, y), ∃ e ∈ E, (e, p) ∈ byFirst(E, E ×2)771intros p hp772exact byFirst.cover with hp.left773have coverEmpty : ∀ p ∈∅, ∃ e ∈ E, (e, p) ∈ byFirst(E, ∅)774intros p hp775simpat hp776-- The part at e is both ends of e or neither.777have parts : ∀ e ∈ E,778 (EvenSet(fiber(byFirst(E, E ×2), nonzeroEnds(E, y), e)) ↔779 EvenSet(fiber(byFirst(E, ∅), ∅, e)))780intros e he781have empty : fiber(byFirst(E, ∅), ∅, e) =∅782ext p783constructor784 . intro hp785exact hp.left786 . intro hp787simpat hp788rw empty789simp [EvenSet.empty]790 by_cases nonzero : rowSet(y, e) ≠∅791 . have whole : fiber(byFirst(E, E ×2), nonzeroEnds(E, y), e) = {e} ×2792ext p793constructor794 . intro hp795have related := hp.right796rw byFirst.pair at related797obtain⟨_, x, hx, j, hj, rfl⟩:=798 product.membership.forward with hp.left.left799rw fst.pair at related800rw related.right.right801exact product.pair with singleton.self, hj802 . intro hp803obtain⟨_, x, hx, j, hj, rfl⟩:= product.membership.forward with hp804have xe := singleton.membership.forward with hx805rw xe806have pair : (e, j) ∈ E ×2:= product.pair with he, hj807have member : (e, j) ∈ nonzeroEnds(E, y)808apply nonzeroEnds.membership.backward809rw fst.pair810exact⟨pair, nonzero⟩811exact⟨member, (byFirst.of_pair with he, pair)⟩812rw whole813unfold EvenSet814rw [(cardinality.singleton_product with (Finite.natural at2)),815 (cardinality.natural at2)]816exact Even.two817 . have none : fiber(byFirst(E, E ×2), nonzeroEnds(E, y), e) =∅818ext p819constructor820 . intro hp821have related := hp.right822rw byFirst.pair at related823have value := hp.left.right824rw related.right.right at value825exfalso826exact nonzero with value827 . intro hp828simpat hp829rw none830exact EvenSet.empty831have step := EvenSet.of_parts832at E, nonzeroEnds(E, y), ∅, byFirst(E, E ×2), byFirst(E, ∅)833with finiteEdges, finite, Finite.empty, cover, coverEmpty,834 byFirst.unique, byFirst.unique, parts835rw step836exact EvenSet.empty837838-- At an edge e: the part of y ∩ side is {e} × (h(e) ∩ d(e)), whose parity839-- is h(e)·a + h(e)·b for base points a, b at the two ends of e; the part of840-- the odd ends holds the ends of e at odd vertices. Both parities agree.841theorem Obstructs.edge_parity (V E leftEnd rightEnd F d y e : Set)842requires graph : Graph(V, E, leftEnd, rightEnd)843requires cubic : Cubic(V, E, leftEnd, rightEnd)844requires cover : EvenCover(V, E, leftEnd, rightEnd, F)845requires base : FunctionBetween(d, E, 𝒫(3)) ∧ (∀ e ∈ E, ∃ a, ∃ b,846 BasePoint(V, E, leftEnd, rightEnd, F, leftEnd(e), e, a) ∧847 BasePoint(V, E, leftEnd, rightEnd, F, rightEnd(e), e, b) ∧ d(e) = a △ b)848requires obstruction : Obstructs(849 compatibilityMatrix(V, E, leftEnd, rightEnd, F), E ×3,850 (V ×3) ∪ (E × {3}), compatibilitySide(E, d), y)851requires edge : e ∈ E852shows EvenSet(fiber(byFirst(E, E ×3), y ∩ compatibilitySide(E, d), e)) ↔853 EvenSet(fiber(byFirst(E, E ×2), oddEnds(V, E, leftEnd, rightEnd, y), e))854proof855have ends := Graph.ends with graph856obtain⟨vertexL, vertexR⟩:= ends with e, edge857have atL : leftEnd(e) = leftEnd(e) ∨ rightEnd(e) = leftEnd(e) bysimp858have atR : leftEnd(e) = rightEnd(e) ∨ rightEnd(e) = rightEnd(e) bysimp859-- The part of y ∩ side at e.860haveleft : fiber(byFirst(E, E ×3), y ∩ compatibilitySide(E, d), e) =861 {e} × (rowSet(y, e) ∩ d(e))862ext p863constructor864 . intro hp865obtain⟨⟨hy, hside⟩, related⟩:= hp866rw byFirst.pair at related867obtain⟨_, x, hx, i, hi, rfl⟩:=868 product.membership.forward with related.right.left869rw fst.pair at related870have xe := related.right.right871rw xe at hy, hside872rw xe873rw compatibilitySide.pair with edge, hi at hside874have inRow : i ∈ rowSet(y, e) ∩ d(e) :=⟨⟨hi, hy⟩, hside⟩875exact product.pair with singleton.self, inRow876 . intro hp877obtain⟨_, x, hx, i, hi, rfl⟩:= product.membership.forward with hp878have xe := singleton.membership.forward with hx879rw xe880obtain⟨⟨hi3, hy⟩, value⟩:= hi881have hside : (e, i) ∈ compatibilitySide(E, d)882rw compatibilitySide.pair with edge, hi3883exact value884have pair : (e, i) ∈ E ×3:= product.pair with edge, hi3885exact⟨⟨hy, hside⟩, (byFirst.of_pair with edge, pair)⟩886have finiteRow : Finite(rowSet(y, e) ∩ d(e)) :=887 Finite.subset with rowSet.finite, intersection.subset_left888have leftParity : EvenSet({e} × (rowSet(y, e) ∩ d(e))) ↔889 EvenSet(rowSet(y, e) ∩ d(e))890unfold EvenSet891rw cardinality.singleton_product with finiteRow892rw [left, leftParity]893-- d(e) is the sum of base points a = value(x) at the left end and894-- b = value(z) at the right end.895obtain⟨a, b, baseA, baseB, sumD⟩:= base.right with e, edge896obtain⟨x, hx, xe, xv, rfl⟩:= baseA897obtain⟨z, hz, ze, zv, rfl⟩:= baseB898rw sumD899have finiteH := rowSet.finite at y, e900have finiteX := flowValue.finite at F, x901have finiteZ := flowValue.finite at F, z902rw EvenSet.intersection_symmetricDifference with finiteH, finiteX, finiteZ903have otherX : x ∈ E ∧ x ≠ e ∧904 (leftEnd(x) = leftEnd(e) ∨ rightEnd(x) = leftEnd(e)) :=⟨hx, xe, xv⟩905have otherZ : z ∈ E ∧ z ≠ e ∧906 (leftEnd(z) = rightEnd(e) ∨ rightEnd(z) = rightEnd(e)) :=⟨hz, ze, zv⟩907rw [(Obstructs.end_parity908with graph, cubic, cover, vertexL, edge, atL, otherX, obstruction),909 (Obstructs.end_parity910with graph, cubic, cover, vertexR, edge, atR, otherZ, obstruction)]911-- The part of the odd ends at e: among (e, 0) and (e, 1).912have apart : (e, 0) ≠ (e, 1)913intro same914have parts := orderedPair.injective with same915have zeroOne : 0≠1bysimp916exact zeroOne with parts.right917have inside : fiber(byFirst(E, E ×2), oddEnds(V, E, leftEnd, rightEnd, y), e)918⊆ {(e, 0)} ∪ {(e, 1)}919intros p hp920have related := hp.right921rw byFirst.pair at related922obtain⟨_, w, hw, j, hj, rfl⟩:=923 product.membership.forward with related.right.left924rw fst.pair at related925have we := related.right.right926havecases:= membership.two.forward with hj927rw we928rcasescaseswithrfl|rfl929 . simp930 . simp931rw EvenSet.of_two with apart, inside932have end0 : (e, 0) ∈ incidentEnds(leftEnd, rightEnd, E, leftEnd(e))933bysimp [incidentEnds.pair, edge]934have end1 : (e, 1) ∈ incidentEnds(leftEnd, rightEnd, E, rightEnd(e))935bysimp [incidentEnds.pair, edge]936have zero : 0∈2bysimp [membership.two]937have one : 1∈2bysimp [membership.two]938have pair0 : (e, 0) ∈ E ×2:= product.pair with edge, zero939have pair1 : (e, 1) ∈ E ×2:= product.pair with edge, one940have member0 : (e, 0) ∈941 fiber(byFirst(E, E ×2), oddEnds(V, E, leftEnd, rightEnd, y), e) ↔942 OddVertex(E, leftEnd, rightEnd, y, leftEnd(e))943constructor944 . intro hp945obtain⟨⟨_, w, hw, atW, oddW⟩, _⟩:= hp946have same := incidentEnds.vertex_unique with atW, end0947rw same at oddW948exact oddW949 . intro odd950exact⟨⟨pair0, leftEnd(e), vertexL, end0, odd⟩,951 (byFirst.of_pair with edge, pair0)⟩952have member1 : (e, 1) ∈953 fiber(byFirst(E, E ×2), oddEnds(V, E, leftEnd, rightEnd, y), e) ↔954 OddVertex(E, leftEnd, rightEnd, y, rightEnd(e))955constructor956 . intro hp957obtain⟨⟨_, w, hw, atW, oddW⟩, _⟩:= hp958have same := incidentEnds.vertex_unique with atW, end1959rw same at oddW960exact oddW961 . intro odd962exact⟨⟨pair1, rightEnd(e), vertexR, end1, odd⟩,963 (byFirst.of_pair with edge, pair1)⟩964rw [member0, member1]965tauto966967-- The dual obstruction computation: a left-kernel vector y gives vectors968-- h(e) with h(g) = h(e) △ h(f) at each vertex and h(e) ⊥ value(e); then969-- h(e) · (base point at v) is odd exactly when v is an odd vertex, so y ∩970-- side has the parity of the odd ends, which regroup over the vertices into971-- the nonzero ends, an even set. So y · side is even and y does not obstruct.972theorem compatibility.unobstructed (V E leftEnd rightEnd F d : Set)973requires graph : Graph(V, E, leftEnd, rightEnd)974requires finiteVertices : Finite(V)975requires finiteEdges : Finite(E)976requires cubic : Cubic(V, E, leftEnd, rightEnd)977requires cover : EvenCover(V, E, leftEnd, rightEnd, F)978requires base : FunctionBetween(d, E, 𝒫(3)) ∧ (∀ e ∈ E, ∃ a, ∃ b,979 BasePoint(V, E, leftEnd, rightEnd, F, leftEnd(e), e, a) ∧980 BasePoint(V, E, leftEnd, rightEnd, F, rightEnd(e), e, b) ∧ d(e) = a △ b)981shows¬(∃ y, Obstructs(compatibilityMatrix(V, E, leftEnd, rightEnd, F),982 E ×3, (V ×3) ∪ (E × {3}), compatibilitySide(E, d), y))983proof984intro obstructed985obtain⟨y, obstruction⟩:= obstructed986have ends := Graph.ends with graph987have rows := obstruction.left988have finiteRows : Finite(E ×3) :=989 Finite.product with finiteEdges, Finite.natural990have finiteEnds : Finite(E ×2) :=991 Finite.product with finiteEdges, Finite.natural992have finiteSide : Finite(y ∩ compatibilitySide(E, d)) :=993 Finite.subset with (Finite.subset with finiteRows, rows),994 intersection.subset_left995have finiteOdd : Finite(oddEnds(V, E, leftEnd, rightEnd, y)) :=996 Finite.subset with finiteEnds, oddEnds.subset997have finiteNonzero : Finite(nonzeroEnds(E, y)) :=998 Finite.subset with finiteEnds, nonzeroEnds.subset999-- Over the edges: y ∩ side has the parity of the odd ends.1000have coverSide : ∀ p ∈ y ∩ compatibilitySide(E, d), ∃ e ∈ E,1001 (e, p) ∈ byFirst(E, E ×3)1002intros p hp1003exact byFirst.cover with (rows with p, hp.left)1004have coverOdd : ∀ p ∈ oddEnds(V, E, leftEnd, rightEnd, y), ∃ e ∈ E,1005 (e, p) ∈ byFirst(E, E ×2)1006intros p hp1007exact byFirst.cover with hp.left1008have partsEdges : ∀ e ∈ E,1009 (EvenSet(fiber(byFirst(E, E ×3), y ∩ compatibilitySide(E, d), e)) ↔1010 EvenSet(fiber(byFirst(E, E ×2),1011 oddEnds(V, E, leftEnd, rightEnd, y), e)))1012intros e he1013exact Obstructs.edge_parity1014with graph, cubic, cover, base, obstruction, he1015have stepEdges := EvenSet.of_parts1016at E, y ∩ compatibilitySide(E, d), oddEnds(V, E, leftEnd, rightEnd, y),1017 byFirst(E, E ×3), byFirst(E, E ×2)1018with finiteEdges, finiteSide, finiteOdd, coverSide, coverOdd,1019 byFirst.unique, byFirst.unique, partsEdges1020-- Over the vertices: the odd ends have the parity of the nonzero ends.1021have coverOddV : ∀ p ∈ oddEnds(V, E, leftEnd, rightEnd, y), ∃ v ∈ V,1022 (v, p) ∈ atVertex(V, E, leftEnd, rightEnd)1023intros p hp1024exact atVertex.cover with ends, hp.left1025have coverNonzeroV : ∀ p ∈ nonzeroEnds(E, y), ∃ v ∈ V,1026 (v, p) ∈ atVertex(V, E, leftEnd, rightEnd)1027intros p hp1028exact atVertex.cover with ends, hp.left1029have partsVertices : ∀ v ∈ V,1030 (EvenSet(fiber(atVertex(V, E, leftEnd, rightEnd),1031 oddEnds(V, E, leftEnd, rightEnd, y), v)) ↔1032 EvenSet(fiber(atVertex(V, E, leftEnd, rightEnd), nonzeroEnds(E, y), v)))1033intros v hv1034rw [(oddEnds.fiber with cubic, hv), (nonzeroEnds.fiber with hv)]1035have stepVertices := EvenSet.of_parts1036at V, oddEnds(V, E, leftEnd, rightEnd, y), nonzeroEnds(E, y),1037 atVertex(V, E, leftEnd, rightEnd), atVertex(V, E, leftEnd, rightEnd)1038with finiteVertices, finiteOdd, finiteNonzero, coverOddV, coverNonzeroV,1039 atVertex.unique, atVertex.unique, partsVertices1040have even := nonzeroEnds.even at E, y with finiteEdges1041have evenOdd := stepVertices.backward with even1042have evenSide := stepEdges.backward with evenOdd1043exact obstruction.right.right with evenSide1044