Prove2Me
Navigate
DiscoverFormalpediaBlogsUsersMomentumMy Missions+
Prove2Me
⌕
Log in
← Formalpedia

Finite maps, list colorings, and chord-side cut data

Definition
P2MAssembly_Chapter35Plane_Part1

by xiangyazi24 · Sep 12, 2026 · Mathlib c5ea003 (Lean v4.30.0)

book-chapter-39combinatorial-mapsgraph-theorylean4proofs-from-the-book

A finite map is encoded by an edge involution and vertex rotation on darts, with orbit vertices, edges, and faces. This part contains sphere and simplicity conditions, boundary cycles and near-triangulations, permutation deletion, fan and list-coloring data, chord recursion, orbit/component counts, retained submaps, and first-side face and anchor classifications. It also retains the operation adjoining two new darts to a kept map: the new edge involution is exactly freshAlpha, as expressed by the original definitional equality freshMap_alpha. These local constructions retain their declared involution, fixed-point-free, anchor-distinctness, and map hypotheses. The plane simple graph structure is defined in this part, including its connected simple graph and compatible dart representation.

Definition code
import Init
import Mathlib
import Mathlib.Analysis.LocallyConvex.Separation
import Mathlib.Analysis.InnerProductSpace.Dual
import Mathlib.Analysis.Convex.Topology
import Mathlib.Analysis.Convex.Combination
import Mathlib.Data.Finset.Basic
set_option autoImplicit true


/- Original source header (imports hoisted):
import Mathlib
-/
/- Source module: ProofsInTheBook.PlanarMap -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

/-- A combinatorial (orientable) map on a finite dart set `D`:
edge involution `α` (fixed-point-free) and vertex rotation `σ`. -/
structure CombMap (D : Type*) [Fintype D] [DecidableEq D] where
  /-- Edge involution: pairs each dart with its reverse. -/
  α : Equiv.Perm D
  /-- Vertex rotation: cyclic order of darts around each vertex. -/
  σ : Equiv.Perm D
  /-- `α` is an involution. -/
  α_invol : α * α = 1
  /-- `α` has no fixed dart (every edge has two distinct darts). -/
  α_no_fixed : ∀ d, α d ≠ d

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

/-- Face permutation `φ = σ ∘ α`. Its orbits are the faces. -/
def φ (M : CombMap D) : Equiv.Perm D := M.σ * M.α

/-- The `SameCycle` equivalence of a permutation, as a `Setoid` on the dart set.
Its classes are the orbits (cycles, including fixed points). -/
def cycleSetoid (p : Equiv.Perm D) : Setoid D where
  r := p.SameCycle
  iseqv := ⟨fun x => Equiv.Perm.SameCycle.refl p x, fun h => h.symm, fun h h' => h.trans h'⟩

instance (p : Equiv.Perm D) : DecidableRel (cycleSetoid p).r :=
  (inferInstance : DecidableRel p.SameCycle)

instance (p : Equiv.Perm D) : Fintype (Quotient (cycleSetoid p)) :=
  Quotient.fintype (cycleSetoid p)

/-- Number of vertices: the number of `σ`-orbits. -/
def V (M : CombMap D) : ℕ := Fintype.card (Quotient (cycleSetoid M.σ))

/-- Number of edges: the number of `α`-orbits. -/
def E (M : CombMap D) : ℕ := Fintype.card (Quotient (cycleSetoid M.α))

/-- Number of faces: the number of `φ`-orbits. -/
def F (M : CombMap D) : ℕ := Fintype.card (Quotient (cycleSetoid M.φ))

/-- The Euler characteristic `V - E + F`. -/
def eulerChar (M : CombMap D) : ℤ := (V M : ℤ) - (E M : ℤ) + (F M : ℤ)

/-- Adjacency of the underlying multigraph on darts: same vertex, or joined by an edge. -/
def dartStep (M : CombMap D) (a b : D) : Prop :=
  M.σ.SameCycle a b ∨ b = M.α a

/-- The map is connected if every two darts are linked by a chain of `dartStep`s. -/
def Connected (M : CombMap D) : Prop :=
  ∀ a b : D, Relation.ReflTransGen M.dartStep a b

/-- A **plane (sphere) map**: connected and of Euler characteristic `2` (genus zero).
The faithful combinatorial definition of a planar graph embedding; NOT an inductive build
certificate, so theorems proved for `IsSphereMap` are about all plane graphs. -/
def IsSphereMap (M : CombMap D) : Prop :=
  M.Connected ∧ M.eulerChar = 2

/-- A power of an involution is either the identity or the involution itself. -/
lemma zpow_involution (α : Equiv.Perm D) (h : α * α = 1) (i : ℤ) :
    α ^ i = 1 ∨ α ^ i = α := by
  have hsq : α ^ (2 : ℤ) = 1 := by
    have h2 : α ^ (2 : ℤ) = α * α := by
      rw [show (2 : ℤ) = 1 + 1 from rfl, zpow_add, zpow_one]
    rw [h2, h]
  rcases Int.even_or_odd i with ⟨r, hr⟩ | ⟨k, hk⟩
  · left
    rw [show i = 2 * r by omega, zpow_mul, hsq, one_zpow]
  · right
    rw [hk, zpow_add, zpow_mul, hsq, one_zpow, one_mul, zpow_one]

/-- The edge containing a dart `d` is exactly `{d, α d}`: the `α`-orbit of any dart has
the two darts of its edge and no more. -/
lemma alpha_sameCycle_iff (M : CombMap D) (d x : D) :
    M.α.SameCycle d x ↔ x = d ∨ x = M.α d := by
  constructor
  · rintro ⟨i, rfl⟩
    rcases zpow_involution M.α M.α_invol i with h1 | h1
    · left; rw [h1]; rfl
    · right; rw [h1]
  · rintro (rfl | rfl)
    · exact ⟨0, by simp⟩
    · exact ⟨1, by simp⟩

/-- Every `α`-class (edge) has exactly two darts. -/
lemma alpha_class_card (M : CombMap D)
    (q : Quotient (cycleSetoid M.α)) :
    (Finset.univ.filter (fun x => Quotient.mk (cycleSetoid M.α) x = q)).card = 2 := by
  obtain ⟨d, rfl⟩ := q.exists_rep
  have hset :
      (Finset.univ.filter
          (fun x => Quotient.mk (cycleSetoid M.α) x = Quotient.mk (cycleSetoid M.α) d))
        = {d, M.α d} := by
    ext x
    simp only [Finset.mem_filter, Finset.mem_univ, true_and, Finset.mem_insert,
      Finset.mem_singleton, Quotient.eq]
    show M.α.SameCycle x d ↔ x = d ∨ x = M.α d
    constructor
    · intro h; exact (alpha_sameCycle_iff M d x).mp h.symm
    · intro h; exact ((alpha_sameCycle_iff M d x).mpr h).symm
  rw [hset, Finset.card_insert_of_notMem (by
    simp only [Finset.mem_singleton]
    exact fun hcontra => M.α_no_fixed d hcontra.symm), Finset.card_singleton]

/-- Every edge has exactly two darts: `2 * E = |D|`. -/
lemma two_mul_E_eq_card (M : CombMap D) : 2 * M.E = Fintype.card D := by
  have hsum : Fintype.card D
      = ∑ q : Quotient (cycleSetoid M.α),
          (Finset.univ.filter (fun x => Quotient.mk (cycleSetoid M.α) x = q)).card := by
    rw [← Finset.card_univ]
    exact Finset.card_eq_sum_card_fiberwise (fun x _ => Finset.mem_univ _)
  rw [hsum, Finset.sum_congr rfl (fun q _ => alpha_class_card M q),
      Finset.sum_const, Finset.card_univ, smul_eq_mul, E, Nat.mul_comm]

/-- Orbit sizes of any permutation sum to the dart count. -/
lemma sum_class_card (p : Equiv.Perm D) :
    ∑ Q : Quotient (cycleSetoid p),
        (Finset.univ.filter (fun x => Quotient.mk (cycleSetoid p) x = Q)).card
      = Fintype.card D := by
  rw [← Finset.card_univ]
  exact (Finset.card_eq_sum_card_fiberwise (fun x _ => Finset.mem_univ _)).symm













end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMap
-/
/- Source module: ProofsInTheBook.PlaneSimpleGraph -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open ProofsInTheBook.PlanarMap

/-- A finite simple graph with a cellular sphere embedding given by a rotation system on darts. -/
structure PlaneSimpleGraph (V D : Type*) [Fintype V] [DecidableEq V]
    [Fintype D] [DecidableEq D] where
  /-- The underlying simple graph. -/
  G : SimpleGraph V
  /-- Tail vertex of a dart. -/
  tail : D → V
  /-- Head vertex of a dart. -/
  head : D → V
  /-- Edge involution. -/
  α : Equiv.Perm D
  /-- Vertex rotation. -/
  σ : Equiv.Perm D
  α_invol : α * α = 1
  α_no_fixed : ∀ d, α d ≠ d
  reverse_tail : ∀ d, tail (α d) = head d
  reverse_head : ∀ d, head (α d) = tail d
  dart_edge : ∀ d, G.Adj (tail d) (head d)
  edge_darts : ∀ {u v : V}, G.Adj u v → ∃! d : D, tail d = u ∧ head d = v
  σ_preserves_tail : ∀ d, tail (σ d) = tail d
  σ_vertex_cycle : ∀ d e : D, tail d = tail e → σ.SameCycle d e
  connected : G.Connected

namespace PlaneSimpleGraph

variable {V D : Type*} [Fintype V] [DecidableEq V] [Fintype D] [DecidableEq D]

/-- The underlying combinatorial map (forgetting the simple-graph layer). -/
def toCombMap (M : PlaneSimpleGraph V D) : CombMap D where
  α := M.α
  σ := M.σ
  α_invol := M.α_invol
  α_no_fixed := M.α_no_fixed

/-- Number of vertices (of the simple graph). -/
def numVertices (M : PlaneSimpleGraph V D) : ℕ := Fintype.card V

/-- Number of edges = darts / 2. -/
def numEdges (M : PlaneSimpleGraph V D) : ℕ := Fintype.card D / 2

/-- Number of faces = number of `φ = σ * α` orbits. -/
def numFaces (M : PlaneSimpleGraph V D) : ℕ := M.toCombMap.F

/-- Euler characteristic of the embedding. -/
def eulerChar (M : PlaneSimpleGraph V D) : ℤ :=
  (M.numVertices : ℤ) - (M.numEdges : ℤ) + (M.numFaces : ℤ)

/-- The embedding is a sphere (plane) embedding: Euler characteristic `2`. -/
def IsSphereMap (M : PlaneSimpleGraph V D) : Prop :=
  M.eulerChar = 2

end PlaneSimpleGraph

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMap
-/
/- Source module: ProofsInTheBook.PlanarMapEuler -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap.CombMap

open ProofsInTheBook.PlanarMap

variable {D : Type*} [Fintype D] [DecidableEq D]



/-- Length of a face = number of darts in its `φ`-orbit. -/
def faceLen (M : CombMap D) (Q : Quotient (cycleSetoid M.φ)) : ℕ :=
  (Finset.univ.filter (fun x => Quotient.mk (cycleSetoid M.φ) x = Q)).card

/-- Every face has length at least `k` (a simple plane map satisfies this with `k = 3`). -/
def FaceLengthGe (M : CombMap D) (k : ℕ) : Prop :=
  ∀ Q : Quotient (cycleSetoid M.φ), k ≤ M.faceLen Q



/-- The face lengths sum to `2E`. -/
lemma sum_faceLen (M : CombMap D) :
    ∑ Q : Quotient (cycleSetoid M.φ), M.faceLen Q = 2 * M.E := by
  rw [two_mul_E_eq_card]; exact sum_class_card M.φ







end ProofsInTheBook.PlanarMap.CombMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapEuler
-/
/- Source module: ProofsInTheBook.PlanarMapSimple -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

/-- Vertices are `σ`-orbits of darts. -/
abbrev Vertex (M : CombMap D) : Type _ :=
  Quotient (cycleSetoid M.σ)

/-- Faces are `φ`-orbits of darts. -/
abbrev Face (M : CombMap D) : Type _ :=
  Quotient (cycleSetoid M.φ)

/-- The vertex at the tail of a dart. -/
def tail (M : CombMap D) (d : D) : M.Vertex :=
  Quotient.mk (cycleSetoid M.σ) d

/-- The vertex at the head of a dart, i.e. the tail of its reverse dart. -/
def head (M : CombMap D) (d : D) : M.Vertex :=
  Quotient.mk (cycleSetoid M.σ) (M.α d)

/-- The face containing a dart. -/
def dartFace (M : CombMap D) (d : D) : M.Face :=
  Quotient.mk (cycleSetoid M.φ) d

/-- The unoriented graph edge represented by a dart. -/
def dartEdge (M : CombMap D) (d : D) : Sym2 M.Vertex :=
  s(M.tail d, M.head d)

lemma alpha_alpha (M : CombMap D) (d : D) : M.α (M.α d) = d := by
  have h := congrArg (fun f : Equiv.Perm D => f d) M.α_invol
  simpa [Equiv.Perm.coe_mul, Function.comp_apply] using h

@[simp]
lemma tail_sigma (M : CombMap D) (d : D) : M.tail (M.σ d) = M.tail d := by
  exact Quotient.sound ⟨-1, by simp⟩

@[simp]
lemma tail_phi (M : CombMap D) (d : D) : M.tail (M.φ d) = M.head d := by
  unfold tail head
  exact Quotient.sound ⟨-1, by simp [φ, Equiv.Perm.coe_mul, Function.comp_apply]⟩

@[simp]
lemma tail_alpha (M : CombMap D) (d : D) : M.tail (M.α d) = M.head d :=
  rfl

@[simp]
lemma head_alpha (M : CombMap D) (d : D) : M.head (M.α d) = M.tail d := by
  unfold head tail
  rw [M.alpha_alpha d]

@[simp]
lemma dartEdge_alpha (M : CombMap D) (d : D) : M.dartEdge (M.α d) = M.dartEdge d := by
  simp [dartEdge, Sym2.eq_swap]

/-- Vertex adjacency induced by the map darts, before deleting loops. -/
def Adj (M : CombMap D) (u v : M.Vertex) : Prop :=
  ∃ d : D, M.dartEdge d = s(u, v)

lemma adj_symm (M : CombMap D) {u v : M.Vertex} (h : M.Adj u v) : M.Adj v u := by
  rcases h with ⟨d, hd⟩
  exact ⟨d, by simpa [Sym2.eq_swap] using hd⟩

lemma adj_of_dart (M : CombMap D) (d : D) : M.Adj (M.tail d) (M.head d) :=
  ⟨d, rfl⟩

/-- The underlying `SimpleGraph` on vertex quotients.  Its adjacency is dart
adjacency with loops removed. -/
def toSimpleGraph (M : CombMap D) : SimpleGraph M.Vertex where
  Adj u v := u ≠ v ∧ M.Adj u v
  symm := by
    intro u v h
    exact ⟨h.1.symm, M.adj_symm h.2⟩
  loopless := ⟨by
    intro u h
    exact h.1 rfl⟩

@[simp]
lemma toSimpleGraph_adj (M : CombMap D) (u v : M.Vertex) :
    M.toSimpleGraph.Adj u v ↔ u ≠ v ∧ M.Adj u v :=
  Iff.rfl

/-- No loops and no parallel edges in the quotient graph carried by the map. -/
structure IsSimpleGraph (M : CombMap D) : Prop where
  /-- No dart has equal endpoint vertices. -/
  no_loop : ∀ d : D, M.tail d ≠ M.head d
  /-- Two darts with the same unordered endpoint pair are the same map edge. -/
  no_parallel : ∀ {d e : D}, M.dartEdge d = M.dartEdge e → M.α.SameCycle d e

lemma toSimpleGraph_adj_of_dart (M : CombMap D) (hM : M.IsSimpleGraph) (d : D) :
    M.toSimpleGraph.Adj (M.tail d) (M.head d) :=
  ⟨hM.no_loop d, M.adj_of_dart d⟩



/-- Dart-representative form of `NoLoopAt`, compatible with `vertexDarts` from
`PlanarMapDelete` without importing that file here. -/
lemma noLoopAt_dart_of_isSimpleGraph (M : CombMap D) (hM : M.IsSimpleGraph) (v d : D)
    (hd : M.σ.SameCycle v d) :
    ¬ M.σ.SameCycle v (M.α d) := by
  intro hαd
  have htail : M.tail v = M.tail d := Quotient.sound hd
  have hhead : M.tail v = M.head d := Quotient.sound hαd
  exact hM.no_loop d (htail.symm.trans hhead)

lemma alpha_sameCycle_of_dartEdge_eq (M : CombMap D) (hM : M.IsSimpleGraph)
    {d e : D} (h : M.dartEdge d = M.dartEdge e) :
    M.α.SameCycle d e :=
  hM.no_parallel h

lemma alpha_sameCycle_of_same_endpoints (M : CombMap D) (hM : M.IsSimpleGraph)
    {d e : D} (htail : M.tail d = M.tail e) (hhead : M.head d = M.head e) :
    M.α.SameCycle d e := by
  exact hM.no_parallel (by simp [dartEdge, htail, hhead])

lemma alpha_sameCycle_of_same_endpoints_symm (M : CombMap D) (hM : M.IsSimpleGraph)
    {d e : D} (htail : M.tail d = M.head e) (hhead : M.head d = M.tail e) :
    M.α.SameCycle d e := by
  exact hM.no_parallel (by simp [dartEdge, htail, hhead, Sym2.eq_swap])

/-- Three darts form a triangular face boundary in cyclic order. -/
def IsFaceTriangle (M : CombMap D) (d₀ d₁ d₂ : D) : Prop :=
  M.φ d₀ = d₁ ∧ M.φ d₁ = d₂ ∧ M.φ d₂ = d₀

lemma dartEdge_eq_mk_tail_tail_phi (M : CombMap D) (d : D) :
    M.dartEdge d = s(M.tail d, M.tail (M.φ d)) := by
  simp [dartEdge]

lemma isFaceTriangle_vertices_pairwiseDistinct (M : CombMap D) (hM : M.IsSimpleGraph)
    {d₀ d₁ d₂ : D} (htri : M.IsFaceTriangle d₀ d₁ d₂) :
    M.tail d₀ ≠ M.tail d₁ ∧
      M.tail d₁ ≠ M.tail d₂ ∧
      M.tail d₂ ≠ M.tail d₀ := by
  rcases htri with ⟨h₀₁, h₁₂, h₂₀⟩
  constructor
  · intro h
    apply hM.no_loop d₀
    have hnext : M.tail d₁ = M.head d₀ := by
      rw [← h₀₁]
      simp
    exact h.trans hnext
  constructor
  · intro h
    apply hM.no_loop d₁
    have hnext : M.tail d₂ = M.head d₁ := by
      rw [← h₁₂]
      simp
    exact h.trans hnext
  · intro h
    apply hM.no_loop d₂
    have hnext : M.tail d₀ = M.head d₂ := by
      rw [← h₂₀]
      simp
    exact h.trans hnext



end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapEuler
-/
/- Source module: ProofsInTheBook.PlanarMapDelete -/
section
set_option autoImplicit true




namespace Equiv.Perm

open Equiv

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace DeleteSet

omit [DecidableEq D] in
/-- There is always a positive iterate of `p` from a surviving point back to a
surviving point: `orderOf p` returns to the starting point. -/
lemma exists_pos_pow_notMem (p : Equiv.Perm D) (S : Finset D) (x : {d : D // d ∉ S}) :
    ∃ n : ℕ, 0 < n ∧ (p ^ n) x.1 ∉ S := by
  refine ⟨orderOf p, orderOf_pos p, ?_⟩
  simpa using x.2

/-- The first positive `p`-iterate of `x` outside `S`. -/
noncomputable def firstOutside (p : Equiv.Perm D) (S : Finset D)
    (x : {d : D // d ∉ S}) : ℕ :=
  Nat.find (exists_pos_pow_notMem p S x)

lemma firstOutside_spec (p : Equiv.Perm D) (S : Finset D)
    (x : {d : D // d ∉ S}) :
    0 < firstOutside p S x ∧ (p ^ firstOutside p S x) x.1 ∉ S :=
  Nat.find_spec (exists_pos_pow_notMem p S x)

lemma firstOutside_pos (p : Equiv.Perm D) (S : Finset D)
    (x : {d : D // d ∉ S}) :
    0 < firstOutside p S x :=
  (firstOutside_spec p S x).1

lemma firstOutside_notMem (p : Equiv.Perm D) (S : Finset D)
    (x : {d : D // d ∉ S}) :
    (p ^ firstOutside p S x) x.1 ∉ S :=
  (firstOutside_spec p S x).2

lemma firstOutside_min (p : Equiv.Perm D) (S : Finset D)
    (x : {d : D // d ∉ S}) {m : ℕ}
    (hm : m < firstOutside p S x) :
    ¬ (0 < m ∧ (p ^ m) x.1 ∉ S) :=
  Nat.find_min (exists_pos_pow_notMem p S x) hm

/-- The underlying function of `deleteSet`: move to the first surviving forward
iterate. -/
noncomputable def deleteSetFun (p : Equiv.Perm D) (S : Finset D)
    (x : {d : D // d ∉ S}) : {d : D // d ∉ S} :=
  ⟨(p ^ firstOutside p S x) x.1, firstOutside_notMem p S x⟩

@[simp]
lemma deleteSetFun_coe (p : Equiv.Perm D) (S : Finset D)
    (x : {d : D // d ∉ S}) :
    (deleteSetFun p S x : D) = (p ^ firstOutside p S x) x.1 :=
  rfl

lemma firstOutside_inv_deleteSetFun (p : Equiv.Perm D) (S : Finset D)
    (x : {d : D // d ∉ S}) :
    firstOutside p⁻¹ S (deleteSetFun p S x) = firstOutside p S x := by
  classical
  let n := firstOutside p S x
  have hnpos : 0 < n := firstOutside_pos p S x
  have hnnot : (p ^ n) x.1 ∉ S := firstOutside_notMem p S x
  refine (Nat.find_eq_iff (exists_pos_pow_notMem p⁻¹ S (deleteSetFun p S x))).2 ?_
  constructor
  · constructor
    · exact hnpos
    · have hpow : ((p⁻¹) ^ n) ((deleteSetFun p S x : {d : D // d ∉ S}) : D) = x.1 := by
        simp only [deleteSetFun_coe]
        rw [inv_pow]
        change (p ^ n).symm ((p ^ n) x.1) = x.1
        exact Equiv.symm_apply_apply (p ^ n) x.1
      simpa [hpow] using x.2
  · intro m hm
    rintro ⟨hmpos, hmnot⟩
    have hmn : m < n := hm
    have hsubpos : 0 < n - m := Nat.sub_pos_of_lt hmn
    have hsub_lt : n - m < n := Nat.sub_lt hnpos hmpos
    have hforward :
        (p ^ (n - m)) x.1 =
          ((p⁻¹) ^ m) ((deleteSetFun p S x : {d : D // d ∉ S}) : D) := by
      simp only [deleteSetFun_coe]
      rw [inv_pow]
      have hle : m ≤ n := le_of_lt hmn
      have hperm : (p ^ m)⁻¹ * p ^ n = p ^ (n - m) := by
        have hpown : p ^ n = p ^ m * p ^ (n - m) := by
          have hadd : m + (n - m) = n := Nat.add_sub_of_le hle
          calc
            p ^ n = p ^ (m + (n - m)) := by rw [hadd]
            _ = p ^ m * p ^ (n - m) := by rw [pow_add]
        calc
          (p ^ m)⁻¹ * p ^ n = (p ^ m)⁻¹ * (p ^ m * p ^ (n - m)) := by
            rw [hpown]
          _ = p ^ (n - m) := by
            rw [← mul_assoc, inv_mul_cancel, one_mul]
      calc
        (p ^ (n - m)) x.1 = ((p ^ m)⁻¹ * (p ^ n)) x.1 := by
          rw [hperm]
        _ = ((p ^ m)⁻¹) ((p ^ n) x.1) := rfl
        _ = ((p⁻¹) ^ m) ((p ^ n) x.1) := by rw [inv_pow]
    have hbad : 0 < n - m ∧ (p ^ (n - m)) x.1 ∉ S := by
      exact ⟨hsubpos, by simpa [hforward] using hmnot⟩
    exact firstOutside_min p S x hsub_lt hbad

lemma deleteSetFun_inv_apply (p : Equiv.Perm D) (S : Finset D)
    (x : {d : D // d ∉ S}) :
    deleteSetFun p⁻¹ S (deleteSetFun p S x) = x := by
  classical
  apply Subtype.ext
  rw [deleteSetFun_coe, firstOutside_inv_deleteSetFun p S x, deleteSetFun_coe]
  rw [inv_pow]
  change (p ^ firstOutside p S x).symm ((p ^ firstOutside p S x) x.1) = x.1
  exact Equiv.symm_apply_apply (p ^ firstOutside p S x) x.1

end DeleteSet

open DeleteSet

/-- Delete a finite set from the cycles of a permutation, reconnecting the
surviving points by skipping deleted points. -/
noncomputable def deleteSet (p : Equiv.Perm D) (S : Finset D) :
    Equiv.Perm {d : D // d ∉ S} where
  toFun := deleteSetFun p S
  invFun := deleteSetFun p⁻¹ S
  left_inv := deleteSetFun_inv_apply p S
  right_inv := by
    intro x
    simpa using deleteSetFun_inv_apply p⁻¹ S x

@[simp]
lemma deleteSet_apply_coe (p : Equiv.Perm D) (S : Finset D)
    (x : {d : D // d ∉ S}) :
    ((deleteSet p S x : {d : D // d ∉ S}) : D) =
      (p ^ firstOutside p S x) x.1 :=
  rfl

lemma sameCycle_deleteSet_imp (p : Equiv.Perm D) (S : Finset D)
    {x y : {d : D // d ∉ S}} :
    (deleteSet p S).SameCycle x y → p.SameCycle x.1 y.1 := by
  classical
  intro hxy
  obtain ⟨m, hm⟩ :=
    Equiv.Perm.SameCycle.exists_nat_pow_eq (f := deleteSet p S) hxy
  clear hxy
  revert x
  induction m with
  | zero =>
      intro x hm
      simp only [pow_zero, Equiv.Perm.coe_one, id_eq] at hm
      exact (congrArg Subtype.val hm).sameCycle p
  | succ m ih =>
      intro x hm
      let z : {d : D // d ∉ S} := deleteSet p S x
      have hstep : p.SameCycle x.1 z.1 := by
        refine ⟨(firstOutside p S x : ℤ), ?_⟩
        rw [zpow_natCast]
        rfl
      have htail : ((deleteSet p S) ^ m) z = y := by
        simpa [z, pow_succ, Equiv.Perm.coe_mul, Function.comp_apply] using hm
      exact hstep.trans (ih (x := z) htail)

lemma sameCycle_deleteSet_of_pow (p : Equiv.Perm D) (S : Finset D) :
    ∀ m : ℕ, ∀ x y : {d : D // d ∉ S},
      (p ^ m) x.1 = y.1 → (deleteSet p S).SameCycle x y := by
  classical
  intro m
  induction m using Nat.strong_induction_on with
  | h m ih =>
      intro x y hxy
      by_cases hm0 : m = 0
      · subst hm0
        apply (Subtype.ext ?_).sameCycle
        simpa using hxy
      · have hmpos : 0 < m := Nat.pos_of_ne_zero hm0
        let n := firstOutside p S x
        have hnpos : 0 < n := firstOutside_pos p S x
        have hnot_lt : ¬ m < n := by
          intro hmn
          have hbad : 0 < m ∧ (p ^ m) x.1 ∉ S := by
            exact ⟨hmpos, by simpa [hxy] using y.2⟩
          exact firstOutside_min p S x hmn hbad
        have hnm : n ≤ m := le_of_not_gt hnot_lt
        let z : {d : D // d ∉ S} := deleteSet p S x
        have hxz : z.1 = (p ^ n) x.1 := rfl
        have hstep : (deleteSet p S).SameCycle x z := by
          refine ⟨1, ?_⟩
          change deleteSet p S x = z
          rfl
        by_cases hnm_eq : n = m
        · have hzy : z = y := by
            apply Subtype.ext
            rw [hxz, hnm_eq, hxy]
          simpa [hzy] using hstep
        · have hlt : m - n < m := Nat.sub_lt hmpos hnpos
          have hpow : (p ^ (m - n)) z.1 = y.1 := by
            rw [hxz]
            rw [← mul_apply, ← pow_add]
            have hadd : m - n + n = m := Nat.sub_add_cancel hnm
            rw [hadd, hxy]
          exact hstep.trans (ih (m - n) hlt z y hpow)

lemma sameCycle_deleteSet_iff (p : Equiv.Perm D) (S : Finset D)
    (x y : {d : D // d ∉ S}) :
    (deleteSet p S).SameCycle x y ↔ p.SameCycle x.1 y.1 := by
  classical
  constructor
  · exact sameCycle_deleteSet_imp p S
  · intro h
    obtain ⟨m, hm⟩ := Equiv.Perm.SameCycle.exists_nat_pow_eq (f := p) h
    exact sameCycle_deleteSet_of_pow p S m x y hm

end Equiv.Perm

namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

/-- The darts in the `σ`-orbit of a dart representative `v`. -/
def vertexDarts (M : CombMap D) (v : D) : Finset D :=
  Finset.univ.filter (fun d => M.σ.SameCycle v d)

/-- Degree of the vertex represented by `v`, as a dart count. -/
def dartVertexDegree (M : CombMap D) (v : D) : ℕ :=
  (M.vertexDarts v).card

/-- No loop based at the vertex represented by `v`: the edge reverse of a dart
at `v` is not also a dart at `v`.  This is needed for the simple edge-count
formula `E' = E - deg(v)`. -/
def NoLoopAt (M : CombMap D) (v : D) : Prop :=
  ∀ d : D, d ∈ M.vertexDarts v → M.α d ∉ M.vertexDarts v

@[simp]
lemma mem_vertexDarts (M : CombMap D) (v d : D) :
    d ∈ M.vertexDarts v ↔ M.σ.SameCycle v d := by
  simp [vertexDarts]



/-- The closed dart star of `v`: the darts at `v` and their edge reverses.
This is the set that is actually stable under `α`, hence the one on which
`α` can be restricted after deleting a vertex and all incident edges. -/
def deleteVertexSet (M : CombMap D) (v : D) : Finset D :=
  M.vertexDarts v ∪ (M.vertexDarts v).image M.α.toEmbedding

lemma mem_deleteVertexSet_iff (M : CombMap D) (v d : D) :
    d ∈ M.deleteVertexSet v ↔ d ∈ M.vertexDarts v ∨ M.α d ∈ M.vertexDarts v := by
  classical
  constructor
  · intro hd
    rw [deleteVertexSet, Finset.mem_union, Finset.mem_image] at hd
    rcases hd with hd | ⟨x, hx, hxd⟩
    · exact Or.inl hd
    · right
      have : M.α d = x := by
        rw [← hxd]
        have hα : M.α * M.α = 1 := M.α_invol
        have happ := congrArg (fun f : Equiv.Perm D => f x) hα
        simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
      simpa [this] using hx
  · intro hd
    rw [deleteVertexSet, Finset.mem_union, Finset.mem_image]
    rcases hd with hd | hd
    · exact Or.inl hd
    · right
      refine ⟨M.α d, hd, ?_⟩
      have hα : M.α * M.α = 1 := M.α_invol
      have happ := congrArg (fun f : Equiv.Perm D => f d) hα
      simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ

lemma alpha_mem_deleteVertexSet_iff (M : CombMap D) (v d : D) :
    M.α d ∈ M.deleteVertexSet v ↔ d ∈ M.deleteVertexSet v := by
  classical
  rw [mem_deleteVertexSet_iff, mem_deleteVertexSet_iff]
  have hαd : M.α (M.α d) = d := by
    have hα : M.α * M.α = 1 := M.α_invol
    have happ := congrArg (fun f : Equiv.Perm D => f d) hα
    simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
  simp [hαd, or_comm]

/-- Restrict the edge involution to the complement of an `α`-stable deleted set. -/
noncomputable def alphaDeleteVertex (M : CombMap D) (v : D) :
    Equiv.Perm {d : D // d ∉ M.deleteVertexSet v} :=
  M.α.subtypePerm (fun d => by
    constructor
    · intro hd hdel
      exact hd ((alpha_mem_deleteVertexSet_iff M v d).2 hdel)
    · intro hd hdel
      exact hd ((alpha_mem_deleteVertexSet_iff M v d).1 hdel))

@[simp]
lemma alphaDeleteVertex_apply_coe (M : CombMap D) (v : D)
    (d : {d : D // d ∉ M.deleteVertexSet v}) :
    (M.alphaDeleteVertex v d : D) = M.α d.1 := by
  simp [alphaDeleteVertex]

/-- Delete the closed dart star of `v`.  The vertex rotation skips all deleted
darts; the edge involution is the restriction of `α` to the surviving darts. -/
noncomputable def deleteVertex (M : CombMap D) (v : D) :
    CombMap {d : D // d ∉ M.deleteVertexSet v} where
  α := M.alphaDeleteVertex v
  σ := M.σ.deleteSet (M.deleteVertexSet v)
  α_invol := by
    ext d
    simp [alphaDeleteVertex, Equiv.Perm.subtypePerm_apply]
    have hα : M.α * M.α = 1 := M.α_invol
    have happ := congrArg (fun f : Equiv.Perm D => f d.1) hα
    simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
  α_no_fixed := by
    intro d h
    exact M.α_no_fixed d.1 (by
      have := congrArg Subtype.val h
      simpa [alphaDeleteVertex] using this)

@[simp]
lemma deleteVertex_alpha_apply_coe (M : CombMap D) (v : D)
    (d : {d : D // d ∉ M.deleteVertexSet v}) :
    ((M.deleteVertex v).α d : D) = M.α d.1 :=
  rfl

@[simp]
lemma deleteVertex_sigma_sameCycle_iff (M : CombMap D) (v : D)
    (x y : {d : D // d ∉ M.deleteVertexSet v}) :
    (M.deleteVertex v).σ.SameCycle x y ↔ M.σ.SameCycle x.1 y.1 := by
  simpa [deleteVertex] using Equiv.Perm.sameCycle_deleteSet_iff M.σ (M.deleteVertexSet v) x y

lemma deleteVertexSet_card_eq_two_mul_degree (M : CombMap D) (v : D)
    (hloop : M.NoLoopAt v) :
    (M.deleteVertexSet v).card = 2 * M.dartVertexDegree v := by
  classical
  have hdisj :
      Disjoint (M.vertexDarts v) ((M.vertexDarts v).image M.α.toEmbedding) := by
    rw [Finset.disjoint_left]
    intro d hd hdi
    rw [Finset.mem_image] at hdi
    obtain ⟨x, hx, hxd⟩ := hdi
    exact hloop x hx (by simpa [← hxd] using hd)
  rw [deleteVertexSet, Finset.card_union_of_disjoint hdisj]
  have himg :
      ((M.vertexDarts v).image M.α.toEmbedding).card = (M.vertexDarts v).card := by
    simpa using
      Finset.card_image_of_injective (M.vertexDarts v) M.α.injective
  rw [himg]
  simp [dartVertexDegree, Nat.two_mul]

lemma fintype_card_compl_finset (S : Finset D) :
    Fintype.card {d : D // d ∉ S} = Fintype.card D - S.card := by
  classical
  rw [Fintype.card_subtype_compl (fun d : D => d ∈ S)]
  rw [Fintype.card_coe S]

/-- Vertex-count reduction, factored through the exact quotient equivalence
that remains to be proved for the chosen deletion set.

For the closed-star deletion used by `deleteVertex`, this equivalence is not
automatic from `Perm.deleteSet`: deleting the opposite darts of incident edges
also removes darts from neighboring `σ`-orbits.  One must prove that every
nondeleted vertex orbit has a surviving representative and that the deleted
orbit of `v` has none. -/
lemma deleteVertex_V_of_orbitEquiv (M : CombMap D) (v : D)
    (hQ :
      Quotient (cycleSetoid (M.deleteVertex v).σ) ≃
        {Q : Quotient (cycleSetoid M.σ) //
          Q ≠ Quotient.mk (cycleSetoid M.σ) v}) :
    (M.deleteVertex v).V = M.V - 1 := by
  classical
  let qv : Quotient (cycleSetoid M.σ) := Quotient.mk (cycleSetoid M.σ) v
  have hcard :
      Fintype.card {Q : Quotient (cycleSetoid M.σ) // Q ≠ qv}
        = Fintype.card (Quotient (cycleSetoid M.σ)) - 1 := by
    rw [Fintype.card_subtype_compl (fun Q : Quotient (cycleSetoid M.σ) => Q = qv)]
    rw [Fintype.card_subtype_eq qv]
  have hcongr := Fintype.card_congr hQ
  change
      Fintype.card (Quotient (cycleSetoid (M.deleteVertex v).σ)) =
        Fintype.card {Q : Quotient (cycleSetoid M.σ) //
          Q ≠ Quotient.mk (cycleSetoid M.σ) v} at hcongr
  simpa [V, qv] using hcongr.trans hcard

lemma deleteVertex_E (M : CombMap D) (v : D) (hloop : M.NoLoopAt v) :
    (M.deleteVertex v).E = M.E - M.dartVertexDegree v := by
  classical
  let M' := M.deleteVertex v
  have h2E : 2 * M.E = Fintype.card D := two_mul_E_eq_card M
  have h2E' : 2 * M'.E = Fintype.card {d : D // d ∉ M.deleteVertexSet v} :=
    two_mul_E_eq_card M'
  have hcard :
      Fintype.card {d : D // d ∉ M.deleteVertexSet v}
        = Fintype.card D - 2 * M.dartVertexDegree v := by
    rw [fintype_card_compl_finset, deleteVertexSet_card_eq_two_mul_degree M v hloop]
  have h2 : 2 * M'.E = 2 * (M.E - M.dartVertexDegree v) := by
    rw [h2E', hcard, ← h2E]
    omega
  exact Nat.eq_of_mul_eq_mul_left (by norm_num : 0 < 2) h2

/-- The faces of `M` touched by the vertex represented by `v`, recorded as
`φ`-orbit quotients. -/
noncomputable def vertexFaces (M : CombMap D) (v : D) :
    Finset (Quotient (cycleSetoid M.φ)) :=
  (M.vertexDarts v).image (fun d => Quotient.mk (cycleSetoid M.φ) d)

/-- The local simple-boundary condition that each dart at `v` lies on a
different face.  Without it, a cut vertex or bridge can make the same face
appear more than once around `v`, so the connected face-count formula is not
`F' = F - deg(v) + 1`. -/
def VertexFacesDistinct (M : CombMap D) (v : D) : Prop :=
  Set.InjOn (fun d => Quotient.mk (cycleSetoid M.φ) d) (M.vertexDarts v : Set D)

lemma vertexFaces_card_eq_degree (M : CombMap D) (v : D)
    (hdistinct : M.VertexFacesDistinct v) :
    (M.vertexFaces v).card = M.dartVertexDegree v := by
  classical
  rw [vertexFaces, dartVertexDegree]
  exact Finset.card_image_of_injOn hdistinct

/-- The quotient-level face model for connected vertex deletion: all faces not
incident with `v` survive, while the faces incident with `v` are replaced by
one merged boundary face.  The hard topological boundary lemma is precisely an
equivalence from the actual deleted-map face quotients to this model. -/
abbrev deleteVertexFaceModel (M : CombMap D) (v : D) :=
  {Q : Quotient (cycleSetoid M.φ) // Q ∉ M.vertexFaces v} ⊕ Unit

/-- Quotient-level statement of the deleted-star boundary lemma for the
connected case. -/
def DeleteVertexFacesMerge (M : CombMap D) (v : D) : Prop :=
  Nonempty
    (Quotient (cycleSetoid (M.deleteVertex v).φ) ≃ M.deleteVertexFaceModel v)



lemma deleteVertexFaceModel_card (M : CombMap D) (v : D)
    (hdistinct : M.VertexFacesDistinct v) :
    Fintype.card (M.deleteVertexFaceModel v) =
      M.F - M.dartVertexDegree v + 1 := by
  classical
  have hcard := vertexFaces_card_eq_degree M v hdistinct
  change
    Fintype.card
        ({Q : Quotient (cycleSetoid M.φ) // Q ∉ M.vertexFaces v} ⊕ Unit) =
      M.F - M.dartVertexDegree v + 1
  rw [Fintype.card_sum, Fintype.card_unit,
    Fintype.card_subtype_compl (fun Q : Quotient (cycleSetoid M.φ) =>
      Q ∈ M.vertexFaces v),
    Fintype.card_coe, F, hcard]



lemma deleteVertex_F_of_facesMerge (M : CombMap D) (v : D)
    (hdistinct : M.VertexFacesDistinct v)
    (hmerge : M.DeleteVertexFacesMerge v) :
    (M.deleteVertex v).F = M.F - M.dartVertexDegree v + 1 := by
  classical
  rcases hmerge with ⟨e⟩
  change
    Fintype.card (Quotient (cycleSetoid (M.deleteVertex v).φ)) =
      M.F - M.dartVertexDegree v + 1
  exact (Fintype.card_congr e).trans (deleteVertexFaceModel_card M v hdistinct)

lemma dartVertexDegree_le_E (M : CombMap D) (v : D) (hloop : M.NoLoopAt v) :
    M.dartVertexDegree v ≤ M.E := by
  classical
  have hsubset : M.deleteVertexSet v ⊆ Finset.univ := by
    intro d _; exact Finset.mem_univ d
  have hcardle : (M.deleteVertexSet v).card ≤ Fintype.card D := by
    rw [← Finset.card_univ]
    exact Finset.card_le_card hsubset
  have hdel := deleteVertexSet_card_eq_two_mul_degree M v hloop
  have h2E := two_mul_E_eq_card M
  have hmul : 2 * M.dartVertexDegree v ≤ 2 * M.E := by
    rw [← hdel, h2E]
    exact hcardle
  omega

lemma dartVertexDegree_le_F_of_vertexFacesDistinct (M : CombMap D) (v : D)
    (hdistinct : M.VertexFacesDistinct v) :
    M.dartVertexDegree v ≤ M.F := by
  classical
  have hcard := vertexFaces_card_eq_degree M v hdistinct
  have hsubset : M.vertexFaces v ⊆ Finset.univ := by
    intro Q _; exact Finset.mem_univ Q
  have hle : (M.vertexFaces v).card ≤
      Fintype.card (Quotient (cycleSetoid M.φ)) := by
    rw [← Finset.card_univ]
    exact Finset.card_le_card hsubset
  simpa [F, hcard] using hle

lemma one_le_V_of_dart (M : CombMap D) (v : D) : 1 ≤ M.V := by
  classical
  have hpos : 0 < Fintype.card (Quotient (cycleSetoid M.σ)) :=
    Fintype.card_pos_iff.mpr ⟨Quotient.mk (cycleSetoid M.σ) v⟩
  simpa [V] using hpos

lemma deleteVertex_eulerChar_of_facesMerge (M : CombMap D) (v : D)
    (hsphereEuler : M.eulerChar = 2) (hloop : M.NoLoopAt v)
    (hQ :
      Quotient (cycleSetoid (M.deleteVertex v).σ) ≃
        {Q : Quotient (cycleSetoid M.σ) //
          Q ≠ Quotient.mk (cycleSetoid M.σ) v})
    (hdistinct : M.VertexFacesDistinct v)
    (hmerge : M.DeleteVertexFacesMerge v) :
    (M.deleteVertex v).eulerChar = 2 := by
  classical
  have hV := deleteVertex_V_of_orbitEquiv M v hQ
  have hE := deleteVertex_E M v hloop
  have hF := deleteVertex_F_of_facesMerge M v hdistinct hmerge
  have hVle : 1 ≤ M.V := one_le_V_of_dart M v
  have hdegE : M.dartVertexDegree v ≤ M.E := dartVertexDegree_le_E M v hloop
  have hdegF : M.dartVertexDegree v ≤ M.F :=
    dartVertexDegree_le_F_of_vertexFacesDistinct M v hdistinct
  unfold eulerChar
  rw [hV, hE, hF]
  unfold eulerChar at hsphereEuler
  omega

/-- Connected-case vertex deletion: assuming the remaining vertex quotient is
exactly the old vertex quotient with `v` removed, and assuming the deleted-star
face quotient really is the connected face-merge model, Euler characteristic is
preserved.  The final `hconn` is the graph-theoretic connectedness of the
deleted map. -/
theorem deleteVertex_isSphereMap (M : CombMap D) (v : D) (hsphere : M.IsSphereMap)
    (hloop : M.NoLoopAt v)
    (hQ :
      Quotient (cycleSetoid (M.deleteVertex v).σ) ≃
        {Q : Quotient (cycleSetoid M.σ) //
          Q ≠ Quotient.mk (cycleSetoid M.σ) v})
    (hdistinct : M.VertexFacesDistinct v)
    (hmerge : M.DeleteVertexFacesMerge v)
    (hconn : (M.deleteVertex v).Connected) :
    (M.deleteVertex v).IsSphereMap := by
  exact
    ⟨hconn,
      deleteVertex_eulerChar_of_facesMerge M v hsphere.2 hloop hQ hdistinct hmerge⟩



section TwoEdgePathObstruction























end TwoEdgePathObstruction

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapSimple
-/
/- Source module: ProofsInTheBook.PlanarMapBoundary -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

/-- Cyclic successor on a nonempty finite index type. -/
def cyclicNext {n : ℕ} (h : 0 < n) (i : Fin n) : Fin n :=
  ⟨(i.1 + 1) % n, Nat.mod_lt _ h⟩



/-- The dart set of a face, as a finite orbit set. -/
def faceOrbitFinset (M : CombMap D) (f : M.Face) : Finset D :=
  Finset.univ.filter fun d => M.dartFace d = f

@[simp]
lemma mem_faceOrbitFinset_iff (M : CombMap D) (f : M.Face) (d : D) :
    d ∈ faceOrbitFinset M f ↔ M.dartFace d = f := by
  simp [faceOrbitFinset]

/-- A normalized cyclic dart list for a selected face orbit.

The `root` chooses one representative and fixes the cyclic rotation.  The
`toFinset_eq` field says the list enumerates exactly the selected `φ`-orbit.
-/
structure NormalizedCyclicDartList (M : CombMap D) (f : M.Face)
    (root : D) (darts : List D) : Prop where
  head_eq : darts.head? = some root
  root_face : M.dartFace root = f
  nodup : darts.Nodup
  length_pos : 0 < darts.length
  toFinset_eq : darts.toFinset = faceOrbitFinset M f

/-- A boundary arc/path between two boundary vertices. -/
structure BoundaryPath (M : CombMap D) (u v : M.Vertex) where
  /-- Vertices in path order, including both endpoints. -/
  vertices : List M.Vertex
  /-- Edges in path order.  For boundary arcs these are boundary-cycle edges. -/
  edges : List (Sym2 M.Vertex)
  /-- The first listed vertex is the initial endpoint. -/
  starts_at : vertices.head? = some u
  /-- The last listed vertex is the terminal endpoint. -/
  ends_at : vertices.getLast? = some v
  /-- The arc is simple as a vertex list. -/
  simple : vertices.Nodup

namespace BoundaryPath

variable {M : CombMap D} {u v : M.Vertex}

/-- Interior vertices of a path: endpoints removed. -/
def internalVertices (P : BoundaryPath M u v) : List M.Vertex :=
  P.vertices.tail.dropLast

/-- A path has at least one internal vertex. -/
def HasInternalVertex (P : BoundaryPath M u v) : Prop :=
  P.internalVertices ≠ []

@[simp]
lemma hasInternalVertex_iff (P : BoundaryPath M u v) :
    P.HasInternalVertex ↔ P.internalVertices ≠ [] :=
  Iff.rfl





end BoundaryPath

/-- The two boundary arcs determined by a pair of distinct boundary vertices. -/
structure BoundaryArcSplit (M : CombMap D)
    (boundaryVertices : List M.Vertex) (boundaryEdges : List (Sym2 M.Vertex))
    (u v : M.Vertex) where
  /-- The arc from `u` to `v`. -/
  path₁ : BoundaryPath M u v
  /-- The complementary arc from `v` back to `u`. -/
  path₂ : BoundaryPath M v u
  /-- `path₁` uses only boundary vertices. -/
  path₁_boundary_vertices :
    ∀ ⦃w : M.Vertex⦄, w ∈ path₁.vertices → w ∈ boundaryVertices
  /-- `path₂` uses only boundary vertices. -/
  path₂_boundary_vertices :
    ∀ ⦃w : M.Vertex⦄, w ∈ path₂.vertices → w ∈ boundaryVertices
  /-- Together the two arcs cover the boundary vertex list. -/
  boundary_vertices_covered :
    ∀ w : M.Vertex, w ∈ boundaryVertices ↔ w ∈ path₁.vertices ∨ w ∈ path₂.vertices
  /-- The internal vertices of the two arcs are disjoint. -/
  internally_disjoint :
    ∀ ⦃w : M.Vertex⦄,
      w ∈ path₁.internalVertices → w ∈ path₂.internalVertices → False
  /-- The first arc is nontrivial when the endpoint pair is not a boundary edge.
  (One-directional: a *proper* — non-adjacent — pair forces an internal vertex.  The
  converse `HasInternalVertex → proper` is intentionally NOT required: for a *consecutive*
  pair the long complementary arc must still carry the cycle's other vertices internally,
  so demanding `↔` would make `BoundaryArcSplit`, hence `BoundaryCycle`/`NearTriangulation`,
  uninhabited whenever the cycle has a third vertex.  See `ZinanCh35VacuityObstruction`.) -/
  path₁_internal_of_proper :
    s(u, v) ∉ boundaryEdges → path₁.HasInternalVertex
  /-- The second arc is nontrivial when the endpoint pair is not a boundary edge
  (one-directional, same rationale as `path₁_internal_of_proper`). -/
  path₂_internal_of_proper :
    s(u, v) ∉ boundaryEdges → path₂.HasInternalVertex

/-- The orbit-algebraic **core** of a boundary cycle — every field except the
`arcSplit` certificate.  Split out (2026-06-15) so the universal arc-split
(`arcSplit_of_nodup`, derivable from `VertexNodup`) can be proved over the core and
installed into the full `BoundaryCycle` without the `boundaryCycleOfFace ↔ arcSplit`
self-reference.  See `HANDOFF/ch35-arcsplit-core-refactor.md`. -/
structure BoundaryCycleData (M : CombMap D) (f : M.Face) where
  /-- Chosen dart representative fixing the cyclic rotation. -/
  root : D
  /-- Normalized cyclic dart list enumerating the selected face orbit. -/
  darts : List D
  /-- Cyclic boundary vertex list. -/
  vertices : List M.Vertex
  /-- Cyclic boundary edge list. -/
  edges : List (Sym2 M.Vertex)
  /-- The dart list is normalized and exactly enumerates the selected face orbit. -/
  normalized : NormalizedCyclicDartList M f root darts
  /-- Boundary vertices are the tails of the cyclic dart list. -/
  vertices_eq : vertices = darts.map M.tail
  /-- Boundary edges are the graph edges represented by the cyclic dart list. -/
  edges_eq : edges = darts.map M.dartEdge
  /-- The cyclic order agrees with the face permutation. -/
  consecutive_phi :
    ∀ i : Fin darts.length,
      darts.get (cyclicNext normalized.length_pos i) = M.φ (darts.get i)
  /-- Consecutive boundary darts match at their common boundary vertex. -/
  consecutive_vertex :
    ∀ i : Fin darts.length,
      M.tail (darts.get (cyclicNext normalized.length_pos i)) = M.head (darts.get i)

/-- A boundary cycle for the selected face `f`: the orbit-algebraic core
(`BoundaryCycleData`) together with the arc-splitting certificate.

The dart list is a normalized cyclic enumeration of the `φ`-orbit of `f`.
The vertex and edge lists are exposed so later files can reason about the
boundary without repeatedly unfolding quotient-orbit facts.
-/
structure BoundaryCycle (M : CombMap D) (f : M.Face) extends BoundaryCycleData M f where
  /-- Arc-splitting certificate for any two distinct listed boundary vertices. -/
  arcSplit :
    ∀ ⦃u v : M.Vertex⦄,
      u ≠ v → u ∈ vertices → v ∈ vertices →
        BoundaryArcSplit M vertices edges u v

namespace BoundaryCycle

variable {M : CombMap D} {f : M.Face}

/-- Boundary vertices are represented by the exposed cyclic vertex list. -/
def IsBoundaryVertex (C : BoundaryCycle M f) (v : M.Vertex) : Prop :=
  v ∈ C.vertices

/-- Boundary edges are represented by the exposed cyclic edge list. -/
def IsBoundaryEdge (C : BoundaryCycle M f) (e : Sym2 M.Vertex) : Prop :=
  e ∈ C.edges



/-- The boundary vertex list is simple. -/
def VertexNodup (C : BoundaryCycle M f) : Prop :=
  C.vertices.Nodup



/-- Boundary length, measured in darts/edges. -/
def length (C : BoundaryCycle M f) : ℕ :=
  C.darts.length



lemma darts_nodup (C : BoundaryCycle M f) : C.darts.Nodup :=
  C.normalized.nodup

lemma darts_length_pos (C : BoundaryCycle M f) : 0 < C.darts.length :=
  C.normalized.length_pos





lemma mem_darts_iff (C : BoundaryCycle M f) (d : D) :
    d ∈ C.darts ↔ M.dartFace d = f := by
  rw [← List.mem_toFinset, C.normalized.toFinset_eq]
  simp

lemma dartFace_of_mem_darts (C : BoundaryCycle M f) {d : D} (hd : d ∈ C.darts) :
    M.dartFace d = f :=
  (C.mem_darts_iff d).mp hd





lemma vertices_length (C : BoundaryCycle M f) :
    C.vertices.length = C.length := by
  simp [length, C.vertices_eq]





/-- A boundary chord is an ambient graph edge between boundary vertices that is
not one of the boundary-cycle edges. -/
structure Chord (C : BoundaryCycle M f) (u v : M.Vertex) : Prop where
  endpoints_ne : u ≠ v
  left_boundary : C.IsBoundaryVertex u
  right_boundary : C.IsBoundaryVertex v
  adj : M.toSimpleGraph.Adj u v
  not_boundary_edge : ¬ C.IsBoundaryEdge s(u, v)

namespace Chord

variable {C : BoundaryCycle M f} {u v : M.Vertex}



end Chord

end BoundaryCycle



/-- A boundary is chordless if no boundary chord exists. -/
def BoundaryChordless {M : CombMap D} {f : M.Face} (C : BoundaryCycle M f) : Prop :=
  ∀ ⦃u v : M.Vertex⦄, ¬ C.Chord u v

namespace BoundaryArcSplit

variable {M : CombMap D} {f : M.Face} {C : BoundaryCycle M f} {u v : M.Vertex}









end BoundaryArcSplit



namespace BoundaryCycle

variable {M : CombMap D} {f : M.Face} {C : BoundaryCycle M f} {u v : M.Vertex}











end BoundaryCycle



end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapBoundary
-/
/- Source module: ProofsInTheBook.PlanarMapNearTriangulation -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

/-- A near-triangulation is a simple sphere map with one distinguished simple
outer boundary cycle of length at least three; every other face has length
three. -/
structure NearTriangulation (M : CombMap D) where
  sphere : M.IsSphereMap
  simpleGraph : M.IsSimpleGraph
  outerFace : M.Face
  outerCycle : BoundaryCycle M outerFace
  outer_simple : outerCycle.VertexNodup
  outer_len : 3 ≤ outerCycle.length
  inner_tri : ∀ f : M.Face, f ≠ outerFace → M.faceLen f = 3

@[simp]
lemma dartFace_phi (M : CombMap D) (d : D) :
    M.dartFace (M.φ d) = M.dartFace d := by
  unfold dartFace
  exact Quotient.sound ⟨-1, by simp⟩

@[simp]
lemma dartFace_phi_symm (M : CombMap D) (d : D) :
    M.dartFace (M.φ.symm d) = M.dartFace d := by
  unfold dartFace
  exact Quotient.sound ⟨1, by simp⟩

lemma phi_ne_self_of_isSimpleGraph (M : CombMap D) (hM : M.IsSimpleGraph) (d : D) :
    M.φ d ≠ d := by
  intro h
  have htail : M.head d = M.tail d := by
    calc
      M.head d = M.tail (M.φ d) := (M.tail_phi d).symm
      _ = M.tail d := by rw [h]
  exact hM.no_loop d htail.symm



lemma faceLen_dartFace_eq_card_support_cycleOf (M : CombMap D) {d : D}
    (hφ : M.φ d ≠ d) :
    M.faceLen (M.dartFace d) = (M.φ.cycleOf d).support.card := by
  have hset :
      (Finset.univ.filter
          (fun x => Quotient.mk (cycleSetoid M.φ) x = M.dartFace d))
        = (M.φ.cycleOf d).support := by
    ext x
    simp only [Finset.mem_filter, Finset.mem_univ, true_and, dartFace,
      Equiv.Perm.mem_support_cycleOf_iff' hφ, Quotient.eq]
    exact Equiv.Perm.sameCycle_comm
  simpa [faceLen] using congrArg Finset.card hset

lemma card_support_cycleOf_eq_two_of_apply_apply_eq_self
    (p : Equiv.Perm D) {d : D} (hp : p d ≠ d) (h2 : p (p d) = d) :
    (p.cycleOf d).support.card = 2 := by
  have hc : Equiv.Perm.IsCycle (p.cycleOf d) :=
    Equiv.Perm.isCycle_cycleOf p hp
  have hcd : p.cycleOf d d = p d :=
    Equiv.Perm.cycleOf_apply_self p d
  have hcpd : p.cycleOf d (p d) = d := by
    have hsc : p.SameCycle d (p d) := by
      simpa using (Equiv.Perm.sameCycle_apply_right (f := p) (x := d) (y := d)).2
        Equiv.Perm.SameCycle.rfl
    simp [h2, hsc.cycleOf_apply]
  have hcd_ne : p.cycleOf d d ≠ d := by
    simpa [hcd] using hp
  have hcycle2 : p.cycleOf d (p.cycleOf d d) = d := by
    simpa [hcd] using hcpd
  have hswap := hc.eq_swap_of_apply_apply_eq_self hcd_ne hcycle2
  rw [hswap, Equiv.Perm.card_support_swap hcd_ne.symm]

namespace BoundaryCycle

variable {M : CombMap D} {f : M.Face}

lemma faceLen_eq_length (C : BoundaryCycle M f) :
    M.faceLen f = C.length := by
  have hcard := congrArg Finset.card C.normalized.toFinset_eq
  have horbit : (faceOrbitFinset M f).card = M.faceLen f := by
    rfl
  rw [List.toFinset_card_of_nodup C.normalized.nodup, horbit] at hcard
  exact hcard.symm

lemma tail_injective_on_darts (C : BoundaryCycle M f) (hC : C.VertexNodup)
    {d e : D} (hd : d ∈ C.darts) (he : e ∈ C.darts)
    (htail : M.tail d = M.tail e) :
    d = e := by
  have hmap : (C.darts.map M.tail).Nodup := by
    simpa [BoundaryCycle.VertexNodup, C.vertices_eq] using hC
  exact List.inj_on_of_nodup_map hmap hd he htail

end BoundaryCycle

lemma faceLen_three_phi_cube_eq_self (M : CombMap D) (hM : M.IsSimpleGraph)
    {d : D} (hlen : M.faceLen (M.dartFace d) = 3) :
    (M.φ ^ 3) d = d := by
  have hφ : M.φ d ≠ d := phi_ne_self_of_isSimpleGraph M hM d
  have hcard : (M.φ.cycleOf d).support.card = 3 := by
    rw [← faceLen_dartFace_eq_card_support_cycleOf M hφ, hlen]
  have hpow := Equiv.Perm.pow_mod_card_support_cycleOf_self_apply M.φ 3 d
  rw [hcard] at hpow
  simpa using hpow.symm

lemma faceLen_three_isFaceTriangle (M : CombMap D) (hM : M.IsSimpleGraph)
    {d : D} (hlen : M.faceLen (M.dartFace d) = 3) :
    M.IsFaceTriangle d (M.φ d) (M.φ (M.φ d)) := by
  refine ⟨rfl, rfl, ?_⟩
  have hcube := faceLen_three_phi_cube_eq_self M hM hlen
  simpa [pow_succ, Equiv.Perm.coe_mul, Function.comp_apply] using hcube

lemma faceLen_three_vertices_pairwiseDistinct (M : CombMap D) (hM : M.IsSimpleGraph)
    {d : D} (hlen : M.faceLen (M.dartFace d) = 3) :
    M.tail d ≠ M.tail (M.φ d) ∧
      M.tail (M.φ d) ≠ M.tail (M.φ (M.φ d)) ∧
      M.tail (M.φ (M.φ d)) ≠ M.tail d := by
  exact M.isFaceTriangle_vertices_pairwiseDistinct hM
    (faceLen_three_isFaceTriangle M hM hlen)

namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)





lemma boundary_dart_sigma_ne {d : D} (hd : d ∈ hNT.outerCycle.darts) :
    M.σ d ≠ d := by
  intro hσ
  have hdface : M.dartFace d = hNT.outerFace :=
    (hNT.outerCycle.mem_darts_iff d).mp hd
  have hp : M.φ.symm d ∈ hNT.outerCycle.darts := by
    rw [hNT.outerCycle.mem_darts_iff]
    simp [hdface]
  have hq : M.φ d ∈ hNT.outerCycle.darts := by
    rw [hNT.outerCycle.mem_darts_iff]
    simp [hdface]
  have hαp : M.α (M.φ.symm d) = d := by
    apply M.σ.injective
    change M.φ (M.φ.symm d) = M.σ d
    rw [Equiv.apply_symm_apply, hσ]
  have hp_eq_alpha : M.φ.symm d = M.α d := by
    rw [← M.alpha_alpha (M.φ.symm d), hαp]
  have htail : M.tail (M.φ.symm d) = M.tail (M.φ d) := by
    rw [hp_eq_alpha]
    simp
  have hpq : M.φ.symm d = M.φ d :=
    hNT.outerCycle.tail_injective_on_darts hNT.outer_simple hp hq htail
  have hφ2 : M.φ (M.φ d) = d := by
    simpa using (congrArg M.φ hpq).symm
  have hφ : M.φ d ≠ d :=
    phi_ne_self_of_isSimpleGraph M hNT.simpleGraph d
  have hcard2 :
      (M.φ.cycleOf d).support.card = 2 :=
    card_support_cycleOf_eq_two_of_apply_apply_eq_self M.φ hφ hφ2
  have hface2 : M.faceLen hNT.outerFace = 2 := by
    have hsupport := faceLen_dartFace_eq_card_support_cycleOf M hφ
    rw [hdface, hcard2] at hsupport
    exact hsupport
  have hlen2 : hNT.outerCycle.length = 2 :=
    hNT.outerCycle.faceLen_eq_length.symm.trans hface2
  have hge : 3 ≤ hNT.outerCycle.length := hNT.outer_len
  omega



lemma inner_faceLen_eq_three {f : M.Face} (hf : f ≠ hNT.outerFace) :
    M.faceLen f = 3 :=
  hNT.inner_tri f hf







lemma inner_face_isFaceTriangle {d : D}
    (hd : M.dartFace d ≠ hNT.outerFace) :
    M.IsFaceTriangle d (M.φ d) (M.φ (M.φ d)) := by
  exact faceLen_three_isFaceTriangle M hNT.simpleGraph (hNT.inner_tri (M.dartFace d) hd)

lemma inner_face_vertices_pairwiseDistinct {d : D}
    (hd : M.dartFace d ≠ hNT.outerFace) :
    M.tail d ≠ M.tail (M.φ d) ∧
      M.tail (M.φ d) ≠ M.tail (M.φ (M.φ d)) ∧
      M.tail (M.φ (M.φ d)) ≠ M.tail d := by
  exact faceLen_three_vertices_pairwiseDistinct M hNT.simpleGraph
    (hNT.inner_tri (M.dartFace d) hd)









end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapNearTriangulation
import ProofsInTheBook.PlanarMapDelete
-/
/- Source module: ProofsInTheBook.PlanarMapFilteredRotation -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace FilteredRotation

variable {D : Type*} [Fintype D] [DecidableEq D]



/-- The **filtered cyclic rotation** of a permutation `σ` relative to a deleted
set `Del`: the permutation of the kept subtype `{d // d ∉ Del}` that advances
along `σ` to the first surviving dart.  Thin wrapper around
`Equiv.Perm.deleteSet`, fixed here so the surgery files share one name. -/
noncomputable def filteredRotation (σ : Equiv.Perm D) (Del : Finset D) :
    Equiv.Perm {d : D // d ∉ Del} :=
  σ.deleteSet Del

@[simp]
lemma filteredRotation_apply_coe (σ : Equiv.Perm D) (Del : Finset D)
    (x : {d : D // d ∉ Del}) :
    ((filteredRotation σ Del x : {d : D // d ∉ Del}) : D) =
      (σ ^ Equiv.Perm.DeleteSet.firstOutside σ Del x) x.1 :=
  rfl

/-- The number of `σ`-steps the filtered rotation takes from `x` is `1`
precisely when the immediate `σ`-successor of `x` is also kept. -/
lemma firstOutside_eq_one_of_next_notMem (σ : Equiv.Perm D) (Del : Finset D)
    (x : {d : D // d ∉ Del}) (h : σ x.1 ∉ Del) :
    Equiv.Perm.DeleteSet.firstOutside σ Del x = 1 := by
  have hpos : 0 < Equiv.Perm.DeleteSet.firstOutside σ Del x :=
    Equiv.Perm.DeleteSet.firstOutside_pos σ Del x
  -- `1` satisfies the search predicate, so the minimum is `≤ 1`.
  have hle : Equiv.Perm.DeleteSet.firstOutside σ Del x ≤ 1 := by
    by_contra hcon
    push_neg at hcon
    have h1 : (1 : ℕ) < Equiv.Perm.DeleteSet.firstOutside σ Del x := hcon
    have hbad := Equiv.Perm.DeleteSet.firstOutside_min σ Del x h1
    apply hbad
    refine ⟨one_pos, ?_⟩
    simpa using h
  omega

/-- **Consecutive-successor fact.**  If the `σ`-successor of a kept dart `x` is
again kept, then the filtered successor of `x` is exactly `σ x`.  This is the
local statement that, on a contiguous run of kept darts, the filtered rotation
agrees with `σ`. -/
lemma filteredRotation_apply_of_next_kept (σ : Equiv.Perm D) (Del : Finset D)
    (x : {d : D // d ∉ Del}) (h : σ x.1 ∉ Del) :
    (filteredRotation σ Del x : {d : D // d ∉ Del}).1 = σ x.1 := by
  rw [filteredRotation_apply_coe, firstOutside_eq_one_of_next_notMem σ Del x h,
    pow_one]





/-- **Orbit trace.**  The filtered rotation's orbit through a kept dart is the
trace of `σ`'s orbit on the kept subtype: two kept darts are in the same
filtered cycle iff they are in the same `σ`-cycle. -/
lemma filteredRotation_sameCycle_iff (σ : Equiv.Perm D) (Del : Finset D)
    (x y : {d : D // d ∉ Del}) :
    (filteredRotation σ Del).SameCycle x y ↔ σ.SameCycle x.1 y.1 :=
  Equiv.Perm.sameCycle_deleteSet_iff σ Del x y







namespace ContiguousInterval

variable {σ : Equiv.Perm D} {Del : Finset D} {n : ℕ}

















end ContiguousInterval



section FreshDart

variable {K : Type*} [Fintype K] [DecidableEq K]



/-- **Fresh edge involution.**  Swaps the two fresh darts and acts as `β` on the
kept summand.  Built as a sum of equivalences, hence automatically a
permutation. -/
def freshAlpha (β : Equiv.Perm K) : Equiv.Perm (K ⊕ Fin 2) :=
  Equiv.sumCongr β (Equiv.swap (0 : Fin 2) 1)

@[simp]
lemma freshAlpha_inl (β : Equiv.Perm K) (k : K) :
    freshAlpha β (Sum.inl k) = Sum.inl (β k) := rfl

@[simp]
lemma freshAlpha_inr (β : Equiv.Perm K) (j : Fin 2) :
    freshAlpha β (Sum.inr j) = Sum.inr (Equiv.swap (0 : Fin 2) 1 j) := rfl

/-- `freshAlpha β` is an involution when `β` is. -/
lemma freshAlpha_involutive (β : Equiv.Perm K) (hβ : β * β = 1) :
    freshAlpha β * freshAlpha β = 1 := by
  ext x
  cases x with
  | inl k =>
      simp only [Equiv.Perm.coe_mul, Function.comp_apply, freshAlpha_inl,
        Equiv.Perm.coe_one, id_eq]
      have := congrArg (fun f : Equiv.Perm K => f k) hβ
      simpa [Equiv.Perm.coe_mul, Function.comp_apply] using this
  | inr j =>
      simp only [Equiv.Perm.coe_mul, Function.comp_apply, freshAlpha_inr,
        Equiv.Perm.coe_one, id_eq, Equiv.swap_apply_self]

/-- `freshAlpha β` is fixed-point free when `β` is.  (The fresh darts are swapped
to one another, so they too are not fixed.) -/
lemma freshAlpha_no_fixed (β : Equiv.Perm K) (hβ : ∀ k, β k ≠ k) :
    ∀ x, freshAlpha β x ≠ x := by
  intro x
  cases x with
  | inl k =>
      simp only [freshAlpha_inl, ne_eq, Sum.inl.injEq]
      exact hβ k
  | inr j =>
      simp only [freshAlpha_inr, ne_eq, Sum.inr.injEq]
      fin_cases j <;> decide



variable (ρ : Equiv.Perm K) (a₀ a₁ : K)

/-- Forward map of the spliced rotation. -/
def freshSigmaFun (x : K ⊕ Fin 2) : K ⊕ Fin 2 :=
  match x with
  | Sum.inr j =>
      if j = 0 then Sum.inl (ρ a₀) else Sum.inl (ρ a₁)
  | Sum.inl k =>
      if k = a₀ then Sum.inr 0
      else if k = a₁ then Sum.inr 1
      else Sum.inl (ρ k)

/-- Inverse map of the spliced rotation. -/
def freshSigmaInv (x : K ⊕ Fin 2) : K ⊕ Fin 2 :=
  match x with
  | Sum.inr j =>
      if j = 0 then Sum.inl a₀ else Sum.inl a₁
  | Sum.inl k =>
      if k = ρ a₀ then Sum.inr 0
      else if k = ρ a₁ then Sum.inr 1
      else Sum.inl (ρ⁻¹ k)

variable {ρ a₀ a₁}

lemma freshSigma_left_inv (hne : a₀ ≠ a₁) (x : K ⊕ Fin 2) :
    freshSigmaInv ρ a₀ a₁ (freshSigmaFun ρ a₀ a₁ x) = x := by
  have hρne : ρ a₀ ≠ ρ a₁ := fun h => hne (ρ.injective h)
  cases x with
  | inr j =>
      by_cases hj : j = 0
      · subst hj; simp [freshSigmaFun, freshSigmaInv]
      · have hj1 : j = 1 := by omega
        subst hj1; simp [freshSigmaFun, freshSigmaInv, hρne.symm]
  | inl k =>
      by_cases h0 : k = a₀
      · subst h0; simp [freshSigmaFun, freshSigmaInv]
      · by_cases h1 : k = a₁
        · subst h1; simp [freshSigmaFun, freshSigmaInv, h0]
        · have hk0 : ρ k ≠ ρ a₀ := fun h => h0 (ρ.injective h)
          have hk1 : ρ k ≠ ρ a₁ := fun h => h1 (ρ.injective h)
          simp [freshSigmaFun, freshSigmaInv, h0, h1, hk0, hk1]

lemma freshSigma_right_inv (hne : a₀ ≠ a₁) (x : K ⊕ Fin 2) :
    freshSigmaFun ρ a₀ a₁ (freshSigmaInv ρ a₀ a₁ x) = x := by
  have hρne : ρ a₀ ≠ ρ a₁ := fun h => hne (ρ.injective h)
  cases x with
  | inr j =>
      by_cases hj : j = 0
      · subst hj; simp [freshSigmaFun, freshSigmaInv]
      · have hj1 : j = 1 := by omega
        subst hj1; simp [freshSigmaFun, freshSigmaInv, hne.symm]
  | inl k =>
      by_cases h0 : k = ρ a₀
      · subst h0; simp [freshSigmaFun, freshSigmaInv]
      · by_cases h1 : k = ρ a₁
        · subst h1; simp [freshSigmaFun, freshSigmaInv, h0]
        · have hk0 : ρ.symm k ≠ a₀ := by
            intro h; apply h0; rw [← h]; simp
          have hk1 : ρ.symm k ≠ a₁ := by
            intro h; apply h1; rw [← h]; simp
          simp [freshSigmaFun, freshSigmaInv, h0, h1, hk0, hk1]

variable (ρ a₀ a₁)

/-- **Fresh spliced rotation.**  The rotation `ρ` with `c₀` inserted after `a₀`
and `c₁` inserted after `a₁`.  A permutation of `K ⊕ Fin 2`. -/
def freshSigma (hne : a₀ ≠ a₁) : Equiv.Perm (K ⊕ Fin 2) where
  toFun := freshSigmaFun ρ a₀ a₁
  invFun := freshSigmaInv ρ a₀ a₁
  left_inv := freshSigma_left_inv hne
  right_inv := freshSigma_right_inv hne

@[simp]
lemma freshSigma_apply (hne : a₀ ≠ a₁) (x : K ⊕ Fin 2) :
    freshSigma ρ a₀ a₁ hne x = freshSigmaFun ρ a₀ a₁ x := rfl

/-- The anchor `a₀` now points to the fresh dart `c₀`. -/
@[simp]
lemma freshSigma_anchor_zero (hne : a₀ ≠ a₁) :
    freshSigma ρ a₀ a₁ hne (Sum.inl a₀) = Sum.inr 0 := by
  simp [freshSigma, freshSigmaFun]

/-- The anchor `a₁` now points to the fresh dart `c₁`. -/
@[simp]
lemma freshSigma_anchor_one (hne : a₀ ≠ a₁) :
    freshSigma ρ a₀ a₁ hne (Sum.inl a₁) = Sum.inr 1 := by
  simp [freshSigma, freshSigmaFun, hne.symm]

/-- The fresh dart `c₀` points to the old `ρ`-successor of `a₀`: the new cycle
through `c₀` visits `c₀` then the old cycle segment starting at `ρ a₀`. -/
@[simp]
lemma freshSigma_fresh_zero (hne : a₀ ≠ a₁) :
    freshSigma ρ a₀ a₁ hne (Sum.inr 0) = Sum.inl (ρ a₀) := by
  simp [freshSigma, freshSigmaFun]

/-- The fresh dart `c₁` points to the old `ρ`-successor of `a₁`. -/
@[simp]
lemma freshSigma_fresh_one (hne : a₀ ≠ a₁) :
    freshSigma ρ a₀ a₁ hne (Sum.inr 1) = Sum.inl (ρ a₁) := by
  simp [freshSigma, freshSigmaFun]

/-- Away from the two anchors, the spliced rotation is the old rotation. -/
lemma freshSigma_other (hne : a₀ ≠ a₁) {k : K} (h0 : k ≠ a₀) (h1 : k ≠ a₁) :
    freshSigma ρ a₀ a₁ hne (Sum.inl k) = Sum.inl (ρ k) := by
  simp only [freshSigma_apply, freshSigmaFun, if_neg h0, if_neg h1]

variable {ρ a₀ a₁}

/-- **The fresh CombMap adjunction.**  Given a fixed-point-free involution `β`
and a rotation `ρ` on the kept type `K`, with two distinct anchors, the pair
`(freshAlpha β, freshSigma ρ a₀ a₁)` is a `CombMap` on `K ⊕ Fin 2`. -/
def freshMap (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
    (a₀ a₁ : K) (hne : a₀ ≠ a₁) : CombMap (K ⊕ Fin 2) where
  α := freshAlpha β
  σ := freshSigma ρ a₀ a₁ hne
  α_invol := freshAlpha_involutive β hβinv
  α_no_fixed := freshAlpha_no_fixed β hβfix

@[simp]
lemma freshMap_alpha (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
    (a₀ a₁ : K) (hne : a₀ ≠ a₁) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).α = freshAlpha β := rfl

@[simp]
lemma freshMap_sigma (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
    (a₀ a₁ : K) (hne : a₀ ≠ a₁) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ = freshSigma ρ a₀ a₁ hne := rfl

end FreshDart

end FilteredRotation

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFilteredRotation
-/
/- Source module: ProofsInTheBook.PlanarMapChordSplitData -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)



section ChordDarts

variable {u v : M.Vertex} (h : hNT.outerCycle.Chord u v)

/-- A dart realizing the chord edge `s(u, v)` in the ambient map. -/
noncomputable def chordDart : D :=
  let c₀ := (h.adj.2).choose
  if M.tail c₀ = u then c₀ else M.α c₀

/-- The chosen chord dart has unoriented endpoints `s(u, v)`. -/
lemma chordDart_edge : M.dartEdge (hNT.chordDart h) = s(u, v) := by
  classical
  let c₀ := (h.adj.2).choose
  have hedge : M.dartEdge c₀ = s(u, v) := (h.adj.2).choose_spec
  by_cases htail : M.tail c₀ = u
  · simp [chordDart, c₀, htail, hedge]
  · simp [chordDart, c₀, htail, M.dartEdge_alpha, hedge]

/-- The chosen chord dart is oriented from the first endpoint to the second. -/
lemma chordDart_tail : M.tail (hNT.chordDart h) = u := by
  classical
  let c₀ := (h.adj.2).choose
  have hedge : M.dartEdge c₀ = s(u, v) := (h.adj.2).choose_spec
  have hxy : s(M.tail c₀, M.head c₀) = s(u, v) := hedge
  rcases Sym2.eq_iff.mp hxy with ⟨ht, hh⟩ | ⟨ht, hh⟩
  · simp [chordDart, c₀, ht]
  · have htail_ne : M.tail c₀ ≠ u := by
      intro htu
      exact h.endpoints_ne ((ht.symm.trans htu).symm)
    simp [chordDart, c₀, htail_ne, M.tail_alpha, hh]

/-- The chosen chord dart is oriented from the first endpoint to the second. -/
lemma chordDart_head : M.head (hNT.chordDart h) = v := by
  classical
  let c₀ := (h.adj.2).choose
  have hedge : M.dartEdge c₀ = s(u, v) := (h.adj.2).choose_spec
  have hxy : s(M.tail c₀, M.head c₀) = s(u, v) := hedge
  rcases Sym2.eq_iff.mp hxy with ⟨ht, hh⟩ | ⟨ht, hh⟩
  · simp [chordDart, c₀, ht, hh]
  · have htail_ne : M.tail c₀ ≠ u := by
      intro htu
      exact h.endpoints_ne ((ht.symm.trans htu).symm)
    simp [chordDart, c₀, ht, h.endpoints_ne.symm, M.head_alpha]

/-- The chord's `α`-image dart has the same unoriented endpoints. -/
lemma chordDart_alpha_edge : M.dartEdge (M.α (hNT.chordDart h)) = s(u, v) := by
  rw [M.dartEdge_alpha, hNT.chordDart_edge h]

/-- The chord dart does **not** lie in the outer face: otherwise its edge would be
a boundary edge, contradicting the chord hypothesis. -/
lemma chordDart_not_outer :
    M.dartFace (hNT.chordDart h) ≠ hNT.outerFace := by
  intro hface
  apply h.not_boundary_edge
  have hmem : hNT.chordDart h ∈ hNT.outerCycle.darts :=
    (hNT.outerCycle.mem_darts_iff _).2 hface
  show s(u, v) ∈ hNT.outerCycle.edges
  rw [← hNT.chordDart_edge h, hNT.outerCycle.edges_eq]
  exact List.mem_map_of_mem hmem

/-- The chord's `α`-image dart does **not** lie in the outer face either. -/
lemma chordDart_alpha_not_outer :
    M.dartFace (M.α (hNT.chordDart h)) ≠ hNT.outerFace := by
  intro hface
  apply h.not_boundary_edge
  have hmem : M.α (hNT.chordDart h) ∈ hNT.outerCycle.darts :=
    (hNT.outerCycle.mem_darts_iff _).2 hface
  show s(u, v) ∈ hNT.outerCycle.edges
  rw [← hNT.chordDart_alpha_edge h, hNT.outerCycle.edges_eq]
  exact List.mem_map_of_mem hmem



/-- Both chord-incident faces are triangular. -/
lemma chord_incident_face_isFaceTriangle :
    M.IsFaceTriangle (hNT.chordDart h)
        (M.φ (hNT.chordDart h)) (M.φ (M.φ (hNT.chordDart h))) :=
  hNT.inner_face_isFaceTriangle (hNT.chordDart_not_outer h)

end ChordDarts



/-- Two faces are **chord-split adjacent** (relative to the chord `s(u, v)`) when
they share an edge that is neither a boundary edge nor the chord itself.  This is
the dual adjacency restricted to non-boundary, non-chord edges; reachability
across it never touches the outer face. -/
def ChordSplitAdj (u v : M.Vertex) (f g : M.Face) : Prop :=
  ∃ d : D,
    M.dartFace d = f ∧ M.dartFace (M.α d) = g ∧
      ¬ hNT.outerCycle.IsBoundaryEdge (M.dartEdge d) ∧
      M.dartEdge d ≠ s(u, v)

/-- The adjacency relation is symmetric. -/
lemma chordSplitAdj_symm {u v : M.Vertex} {f g : M.Face}
    (hfg : hNT.ChordSplitAdj u v f g) : hNT.ChordSplitAdj u v g f := by
  obtain ⟨d, hdf, hdg, hbe, hch⟩ := hfg
  refine ⟨M.α d, ?_, ?_, ?_, ?_⟩
  · exact hdg
  · rw [M.alpha_alpha]; exact hdf
  · rwa [M.dartEdge_alpha]
  · rwa [M.dartEdge_alpha]

/-- Across a chord-split adjacency, the second face is non-outer: if it were the
outer face, the shared edge would be a boundary edge. -/
lemma chordSplitAdj_target_not_outer {u v : M.Vertex} {f g : M.Face}
    (hfg : hNT.ChordSplitAdj u v f g) : g ≠ hNT.outerFace := by
  obtain ⟨d, _, hdg, hbe, _⟩ := hfg
  intro hg
  apply hbe
  have hmem : M.α d ∈ hNT.outerCycle.darts :=
    (hNT.outerCycle.mem_darts_iff _).2 (hdg.trans hg)
  show M.dartEdge d ∈ hNT.outerCycle.edges
  rw [← M.dartEdge_alpha d, hNT.outerCycle.edges_eq]
  exact List.mem_map_of_mem hmem



/-- A **side** is the set of faces reachable from a seed face through the
chord-split adjacency relation (the reflexive–transitive closure). -/
def Side (u v : M.Vertex) (seed : M.Face) : Set M.Face :=
  {g | Relation.ReflTransGen (hNT.ChordSplitAdj u v) seed g}

/-- The seed face belongs to its own side. -/
lemma seed_mem_side {u v : M.Vertex} (seed : M.Face) :
    seed ∈ hNT.Side u v seed :=
  Relation.ReflTransGen.refl

/-- A side is closed under chord-split adjacency. -/
lemma side_closed {u v : M.Vertex} {seed f g : M.Face}
    (hf : f ∈ hNT.Side u v seed) (hfg : hNT.ChordSplitAdj u v f g) :
    g ∈ hNT.Side u v seed :=
  Relation.ReflTransGen.tail hf hfg

/-- Every face reached from a non-outer seed is non-outer.  (Non-outerness of any
face reached by at least one step is automatic from
`chordSplitAdj_target_not_outer`; combined with the seed being non-outer this
covers the whole side.) -/
lemma side_subset_nonouter {u v : M.Vertex} {seed : M.Face}
    (hseed : seed ≠ hNT.outerFace) {g : M.Face} (hg : g ∈ hNT.Side u v seed) :
    g ≠ hNT.outerFace := by
  induction hg with
  | refl => exact hseed
  | tail _ hstep _ => exact hNT.chordSplitAdj_target_not_outer hstep



/-- The set of darts whose face lies in a side. -/
def sideFaceDarts (u v : M.Vertex) (seed : M.Face) : Set D :=
  {d | M.dartFace d ∈ hNT.Side u v seed}

/-- The named planarity keystone, deferred to the side-map file (file 6).

`SidesDisjoint h` says the two side face-components are disjoint, i.e. neither
chord-incident face is reachable from the other through the non-outer adjacency.
This is the Jordan/Euler separation input (combinatorially: the chord together
with a boundary arc separates the inner faces, equivalently `F₁ + F₂ = F + 1`
once the side maps exist).  It is not derivable at this pre-construction layer;
the side-map file establishes it from the side face classification.  All
disjointness-dependent conclusions here are stated conditionally on it. -/
def SidesDisjoint {u v : M.Vertex} (h : hNT.outerCycle.Chord u v) : Prop :=
  Disjoint
    (hNT.Side u v (M.dartFace (hNT.chordDart h)))
    (hNT.Side u v (M.dartFace (M.α (hNT.chordDart h))))

/-- All chord-split data for a near-triangulation `M` and a boundary chord `uv`.

This bundles the proven (unconditional) facts.  The single deferred planarity
input is carried as the field `sides_disjoint : hNT.SidesDisjoint h`, supplied by
the caller (file 6) once the side maps make it available; the partition lemma
below consumes it. -/
structure ChordSplitData (u v : M.Vertex) where
  /-- The chord. -/
  chord : hNT.outerCycle.Chord u v
  /-- The two boundary arcs determined by the chord endpoints. -/
  arc : BoundaryArcSplit M hNT.outerCycle.vertices hNT.outerCycle.edges u v
  /-- The first arc has an internal (strictly-between) boundary vertex. -/
  arc₁_internal : arc.path₁.HasInternalVertex
  /-- The second arc has an internal (strictly-between) boundary vertex. -/
  arc₂_internal : arc.path₂.HasInternalVertex

namespace ChordSplitData

variable {hNT} {u v : M.Vertex}

/-- The chord dart for the data bundle. -/
noncomputable def dart (data : hNT.ChordSplitData u v) : D :=
  hNT.chordDart data.chord

/-- The first chord-incident (non-outer, triangular) face. -/
noncomputable def face₁ (data : hNT.ChordSplitData u v) : M.Face :=
  M.dartFace data.dart

/-- The second chord-incident (non-outer, triangular) face. -/
noncomputable def face₂ (data : hNT.ChordSplitData u v) : M.Face :=
  M.dartFace (M.α data.dart)

/-- The face-set of the first side (reachability closure from `face₁`). -/
def side₁ (data : hNT.ChordSplitData u v) : Set M.Face :=
  hNT.Side u v data.face₁

/-- The face-set of the second side (reachability closure from `face₂`). -/
def side₂ (data : hNT.ChordSplitData u v) : Set M.Face :=
  hNT.Side u v data.face₂

/-- The dart-set of the first side. -/
def sideDarts₁ (data : hNT.ChordSplitData u v) : Set D :=
  hNT.sideFaceDarts u v data.face₁

/-- The dart-set of the second side. -/
def sideDarts₂ (data : hNT.ChordSplitData u v) : Set D :=
  hNT.sideFaceDarts u v data.face₂



/-- The first chord-incident face is non-outer. -/
lemma face₁_not_outer (data : hNT.ChordSplitData u v) :
    data.face₁ ≠ hNT.outerFace :=
  hNT.chordDart_not_outer data.chord

/-- The second chord-incident face is non-outer. -/
lemma face₂_not_outer (data : hNT.ChordSplitData u v) :
    data.face₂ ≠ hNT.outerFace :=
  hNT.chordDart_alpha_not_outer data.chord

/-- The first chord-incident face is triangular. -/
lemma face₁_isFaceTriangle (data : hNT.ChordSplitData u v) :
    M.IsFaceTriangle data.dart (M.φ data.dart) (M.φ (M.φ data.dart)) :=
  hNT.chord_incident_face_isFaceTriangle data.chord

/-- The seed `face₁` belongs to side 1. -/
lemma face₁_mem_side₁ (data : hNT.ChordSplitData u v) :
    data.face₁ ∈ data.side₁ :=
  hNT.seed_mem_side _

/-- The seed `face₂` belongs to side 2. -/
lemma face₂_mem_side₂ (data : hNT.ChordSplitData u v) :
    data.face₂ ∈ data.side₂ :=
  hNT.seed_mem_side _

/-- Side 1 is closed under the chord-split adjacency relation. -/
lemma side₁_closed (data : hNT.ChordSplitData u v) {f g : M.Face}
    (hf : f ∈ data.side₁) (hfg : hNT.ChordSplitAdj u v f g) : g ∈ data.side₁ :=
  hNT.side_closed hf hfg

/-- Side 2 is closed under the chord-split adjacency relation. -/
lemma side₂_closed (data : hNT.ChordSplitData u v) {f g : M.Face}
    (hf : f ∈ data.side₂) (hfg : hNT.ChordSplitAdj u v f g) : g ∈ data.side₂ :=
  hNT.side_closed hf hfg

/-- Every face of side 1 is non-outer. -/
lemma side₁_subset_nonouter (data : hNT.ChordSplitData u v) {g : M.Face}
    (hg : g ∈ data.side₁) : g ≠ hNT.outerFace :=
  hNT.side_subset_nonouter data.face₁_not_outer hg

/-- Every face of side 2 is non-outer. -/
lemma side₂_subset_nonouter (data : hNT.ChordSplitData u v) {g : M.Face}
    (hg : g ∈ data.side₂) : g ≠ hNT.outerFace :=
  hNT.side_subset_nonouter data.face₂_not_outer hg











end ChordSplitData







end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapChordSplitData
-/
/- Source module: ProofsInTheBook.PlanarMapChordSplit -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



/-- Under `Nodup`, the last element of a list does not occur in its `dropLast`. -/
lemma getLast_notMem_dropLast {α : Type*} {l : List α} (hl : l ≠ [])
    (hnd : l.Nodup) : l.getLast hl ∉ l.dropLast := by
  have hsplit : l.dropLast ++ [l.getLast hl] = l := List.dropLast_append_getLast hl
  have hnd' : (l.dropLast ++ [l.getLast hl]).Nodup := by rw [hsplit]; exact hnd
  intro hmem
  exact (List.disjoint_of_nodup_append hnd') hmem (by simp)

/-- A generic list fact: if `l.head? = some a` and `l.Nodup`, then `a ∉ l.tail`. -/
lemma head?_notMem_tail {α : Type*} {a : α} {l : List α}
    (hh : l.head? = some a) (hnd : l.Nodup) : a ∉ l.tail := by
  cases l with
  | nil => simp at hh
  | cons b t =>
      simp only [List.head?_cons, Option.some.injEq] at hh
      subst hh
      simpa using (List.nodup_cons.mp hnd).1

/-- A generic list fact: if `l.getLast? = some a` and `l.tail ≠ []`, then `a` is
the last element of `l.tail`. -/
lemma getLast_tail_of_getLast? {α : Type*} {a : α} {l : List α}
    (hl : l.getLast? = some a) (ht : l.tail ≠ []) :
    l.tail.getLast ht = a := by
  cases l with
  | nil => exact absurd rfl ht
  | cons b s =>
      simp only [List.tail_cons] at ht ⊢
      have hs : (b :: s).getLast? = some a := hl
      rw [List.getLast?_eq_some_getLast (by simp)] at hs
      simp only [Option.some.injEq] at hs
      rw [← hs, List.getLast_cons ht]

namespace BoundaryPath

variable {M : CombMap D} {u v : M.Vertex}



/-- An internal vertex is distinct from the initial endpoint. -/
lemma internalVertex_ne_start (P : BoundaryPath M u v) {w : M.Vertex}
    (hw : w ∈ P.internalVertices) : w ≠ u := by
  -- `u` is the head, so `u ∉ tail ⊇ dropLast tail ∋ w`.
  have hutail : u ∉ P.vertices.tail :=
    head?_notMem_tail P.starts_at P.simple
  have hwtail : w ∈ P.vertices.tail := List.dropLast_subset _ hw
  intro hwu; subst hwu; exact hutail hwtail

/-- An internal vertex is distinct from the terminal endpoint. -/
lemma internalVertex_ne_end (P : BoundaryPath M u v) {w : M.Vertex}
    (hw : w ∈ P.internalVertices) : w ≠ v := by
  have hwtail_dropLast : w ∈ P.vertices.tail.dropLast := hw
  have htail_ne : P.vertices.tail ≠ [] := fun h => by rw [h] at hwtail_dropLast; simp at hwtail_dropLast
  have hnodup_tail : P.vertices.tail.Nodup := P.simple.sublist (List.tail_sublist _)
  -- `v` is the last of the tail, and the last is not in `dropLast` under nodup.
  have hlast_tail : P.vertices.tail.getLast htail_ne = v :=
    getLast_tail_of_getLast? P.ends_at htail_ne
  have hnotmem : P.vertices.tail.getLast htail_ne ∉ P.vertices.tail.dropLast :=
    getLast_notMem_dropLast htail_ne hnodup_tail
  intro hwv; subst hwv
  -- `w = v = getLast tail`, and `w ∈ dropLast tail`, contradiction.
  exact hnotmem (hlast_tail.symm ▸ hwtail_dropLast)



end BoundaryPath

namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)

namespace ChordSplitData

variable {hNT} {u v : M.Vertex}

















/-- **`α`-closure away from the seam (side 1).**  If a side-1 dart `e` (its face
lies in side 1) has an edge that is neither a boundary edge nor the chord, then
`α e` is again a side-1 dart.  In other words, the *only* edges along which side
1 can leak are boundary edges and the chord. -/
lemma alpha_mem_side₁_of_interior (data : hNT.ChordSplitData u v) {e : D}
    (he : M.dartFace e ∈ data.side₁)
    (hb : ¬ hNT.outerCycle.IsBoundaryEdge (M.dartEdge e))
    (hc : M.dartEdge e ≠ s(u, v)) :
    M.dartFace (M.α e) ∈ data.side₁ := by
  have hadj : hNT.ChordSplitAdj u v (M.dartFace e) (M.dartFace (M.α e)) :=
    ⟨e, rfl, rfl, hb, by
      -- rewrite the chord edge `s(u,v)` against `data.chord`'s endpoints
      simpa using hc⟩
  exact data.side₁_closed he hadj

/-- **`α`-closure away from the seam (side 2).** -/
lemma alpha_mem_side₂_of_interior (data : hNT.ChordSplitData u v) {e : D}
    (he : M.dartFace e ∈ data.side₂)
    (hb : ¬ hNT.outerCycle.IsBoundaryEdge (M.dartEdge e))
    (hc : M.dartEdge e ≠ s(u, v)) :
    M.dartFace (M.α e) ∈ data.side₂ := by
  have hadj : hNT.ChordSplitAdj u v (M.dartFace e) (M.dartFace (M.α e)) :=
    ⟨e, rfl, rfl, hb, by simpa using hc⟩
  exact data.side₂_closed he hadj



/-- Side membership is symmetric: `g ∈ Side f ↔ f ∈ Side g`.  (Reflexive–
transitive closure of a symmetric relation is symmetric.) -/
lemma side_mem_symm {seed g : M.Face}
    (h : g ∈ hNT.Side u v seed) : seed ∈ hNT.Side u v g :=
  Relation.ReflTransGen.symmetric (fun _ _ => hNT.chordSplitAdj_symm) h

/-- **The chord-split separation predicate.**  `Separates data` says the second
chord-incident face is not reachable from the first through the non-outer
adjacency.  This is the sharp, single-non-reachability form of the file-5
planarity keystone `SidesDisjoint`; it is the genuine Jordan/Euler separation
input for the chord split and is *not* derivable at the combinatorial-map level
(see the module docstring).  It is the one isolated classification input. -/
def Separates (data : hNT.ChordSplitData u v) : Prop :=
  data.face₂ ∉ data.side₁

/-- **The separation predicate is equivalent to the file-5 keystone
`SidesDisjoint`.**  This is a genuine reduction: the full disjointness of the two
side face-components reduces, via symmetry of reachability, to the single
non-reachability `face₂ ∉ side₁`.  Thus a downstream separation theorem need
only establish `Separates` to discharge `SidesDisjoint` (and hence the partition
lemma `chordSplit_side_darts_partition`). -/
theorem separates_iff_sidesDisjoint (data : hNT.ChordSplitData u v) :
    data.Separates ↔ hNT.SidesDisjoint data.chord := by
  constructor
  · -- `face₂ ∉ side₁` ⇒ the two sides are disjoint.
    intro hsep
    rw [SidesDisjoint, Set.disjoint_left]
    intro f hf1 hf2
    -- `f ∈ side₁` and `f ∈ side₂`; show `face₂ ∈ side₁`, contradicting `hsep`.
    -- `f ∈ side₂` means `face₂ ∈ Side f` (symmetry), and `f ∈ side₁` chains.
    have hf2' : data.face₂ ∈ hNT.Side u v f := side_mem_symm hf2
    -- `Side` is transitive: `face₁ ⇝ f ⇝ face₂`, so `face₂ ∈ side₁`.
    have : data.face₂ ∈ data.side₁ :=
      Relation.ReflTransGen.trans hf1 hf2'
    exact hsep this
  · -- `SidesDisjoint` ⇒ `face₂ ∉ side₁`.
    intro hdisj hmem
    -- `face₂ ∈ side₁` and `face₂ ∈ side₂` (seed), contradicting disjointness.
    rw [SidesDisjoint, Set.disjoint_left] at hdisj
    exact hdisj hmem data.face₂_mem_side₂























/-- The outer-face darts whose `α`-reverse is an inner dart of side 1. -/
def outerArc₁ (data : hNT.ChordSplitData u v) : Set D :=
  {b | M.dartFace b = hNT.outerFace ∧ M.dartFace (M.α b) ∈ data.side₁}

/-- The outer-face darts whose `α`-reverse is an inner dart of side 2. -/
def outerArc₂ (data : hNT.ChordSplitData u v) : Set D :=
  {b | M.dartFace b = hNT.outerFace ∧ M.dartFace (M.α b) ∈ data.side₂}

/-- The faithful kept dart set of side 1: inner side-1 darts together with the
matching outer boundary darts, minus the original chord dart. -/
def keptSet₁ (data : hNT.ChordSplitData u v) : Set D :=
  (data.sideDarts₁ ∪ data.outerArc₁) \ {data.dart}

/-- The faithful kept dart set of side 2 (the chord *reverse* `α dart` is the
side-2 seam dart that is removed). -/
def keptSet₂ (data : hNT.ChordSplitData u v) : Set D :=
  (data.sideDarts₂ ∪ data.outerArc₂) \ {M.α data.dart}

/-- The chord edge has exactly the two darts `dart` and `α dart`: any dart whose
unoriented endpoints are `s(u, v)` is `α.SameCycle` with the chord dart, hence
equal to it or its reverse.  UNCONDITIONAL (uses only graph simplicity). -/
lemma chord_edge_darts (data : hNT.ChordSplitData u v) {e : D}
    (he : M.dartEdge e = s(u, v)) : e = data.dart ∨ e = M.α data.dart := by
  have hedge : M.dartEdge e = M.dartEdge data.dart := by
    rw [he]; exact (hNT.chordDart_edge data.chord).symm
  have hsc : M.α.SameCycle e data.dart :=
    M.alpha_sameCycle_of_dartEdge_eq hNT.simpleGraph hedge
  rcases (M.alpha_sameCycle_iff data.dart e).mp hsc.symm with h | h
  · exact Or.inl h
  · exact Or.inr h

/-- For a boundary edge, at least one of its two darts lies on the outer face.
UNCONDITIONAL.  (A boundary edge is the `dartEdge` of some outer-cycle dart; the
two darts of an edge are `b` and `α b` by simplicity.) -/
lemma boundaryEdge_dart_outer (_data : hNT.ChordSplitData u v) {e : D}
    (hbe : hNT.outerCycle.IsBoundaryEdge (M.dartEdge e)) :
    M.dartFace e = hNT.outerFace ∨ M.dartFace (M.α e) = hNT.outerFace := by
  -- `dartEdge e ∈ edges = darts.map dartEdge`, so some outer dart `b` has the
  -- same `dartEdge`; by simplicity `α.SameCycle e b`, i.e. `e = b` or `e = α b`.
  rw [BoundaryCycle.IsBoundaryEdge, hNT.outerCycle.edges_eq, List.mem_map] at hbe
  obtain ⟨b, hb, hbe⟩ := hbe
  have hbface : M.dartFace b = hNT.outerFace := (hNT.outerCycle.mem_darts_iff b).mp hb
  have hsc : M.α.SameCycle e b :=
    M.alpha_sameCycle_of_dartEdge_eq hNT.simpleGraph hbe.symm
  rcases (M.alpha_sameCycle_iff b e).mp hsc.symm with h | h
  · exact Or.inl (by rw [h]; exact hbface)
  · right; rw [h, M.alpha_alpha]; exact hbface

/-- Under `Separates`, the chord *reverse* `α dart` is not in the side-1 kept set
(its face `face₂` is outside side 1, and it is not an outer dart). -/
lemma alphaDart_notMem_keptSet₁ (data : hNT.ChordSplitData u v)
    (hsep : data.Separates) : M.α data.dart ∉ data.keptSet₁ := by
  rintro ⟨hU, _⟩
  rcases hU with h1 | h2
  · -- `α dart ∈ sideDarts₁` means `face₂ ∈ side₁`, contradicting `Separates`.
    exact hsep h1
  · -- `α dart ∈ outerArc₁` needs `dartFace (α dart) = outerFace`, but it is `face₂`.
    exact data.face₂_not_outer h2.1

/-- **The side-1 kept set is closed under `α`** (conditional on `Separates`).
Away from the chord (removed) and the boundary edges (outer dart kept in
`outerArc₁`), `α` maps `keptSet₁` into itself. -/
theorem alpha_keptSet₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    {e : D} (he : e ∈ data.keptSet₁) : M.α e ∈ data.keptSet₁ := by
  classical
  obtain ⟨heU, hene⟩ := he
  simp only [Set.mem_singleton_iff] at hene
  -- `α e ≠ dart`: else `e = α dart ∉ keptSet₁`, contradicting `e ∈ keptSet₁`.
  have hαe_ne : M.α e ≠ data.dart := by
    intro hcontra
    have he_eq : e = M.α data.dart := by
      have := congrArg M.α hcontra; rwa [M.alpha_alpha] at this
    exact data.alphaDart_notMem_keptSet₁ hsep (he_eq ▸ ⟨heU, by
      simp only [Set.mem_singleton_iff]; exact hene⟩)
  refine ⟨?_, by simp only [Set.mem_singleton_iff]; exact hαe_ne⟩
  rcases heU with hin | hout
  · have hface_e : M.dartFace e ∈ data.side₁ := hin
    have he_not_outer : M.dartFace e ≠ hNT.outerFace :=
      data.side₁_subset_nonouter hface_e
    by_cases hbe : hNT.outerCycle.IsBoundaryEdge (M.dartEdge e)
    · right
      have hαe_outer : M.dartFace (M.α e) = hNT.outerFace := by
        rcases data.boundaryEdge_dart_outer hbe with h | h
        · exact absurd h he_not_outer
        · exact h
      exact ⟨hαe_outer, by rw [M.alpha_alpha]; exact hface_e⟩
    · left
      have hch : M.dartEdge e ≠ s(u, v) := by
        intro hchord
        rcases data.chord_edge_darts hchord with h | h
        · exact hene h
        · -- `e = α dart`, so `dartFace e = face₂`; `hin` says `face₂ ∈ side₁`.
          apply hsep
          show M.dartFace (M.α data.dart) ∈ data.side₁
          rw [← h]; exact hin
      exact data.alpha_mem_side₁_of_interior hface_e hbe hch
  · left; exact hout.2

/-- `Separates` is symmetric across the two sides: it also gives `face₁ ∉ side₂`.
(Via symmetry of reachability: `face₁ ∈ side₂` would force `face₂ ∈ side₁`.) -/
lemma separates_symm (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    data.face₁ ∉ data.side₂ := by
  intro hmem
  -- `face₁ ∈ Side face₂` ⇒ `face₂ ∈ Side face₁ = side₁`, contradicting `Separates`.
  exact hsep (side_mem_symm hmem)

/-- Under `Separates`, the chord dart `dart` is not in the side-2 kept set. -/
lemma dart_notMem_keptSet₂ (data : hNT.ChordSplitData u v)
    (hsep : data.Separates) : data.dart ∉ data.keptSet₂ := by
  rintro ⟨hU, _⟩
  rcases hU with h1 | h2
  · -- `dart ∈ sideDarts₂` means `face₁ ∈ side₂`, contradicting `separates_symm`.
    exact data.separates_symm hsep h1
  · -- `dart ∈ outerArc₂` needs `dartFace dart = outerFace`, but it is `face₁`.
    exact data.face₁_not_outer h2.1

/-- **The side-2 kept set is closed under `α`** (conditional on `Separates`). -/
theorem alpha_keptSet₂ (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    {e : D} (he : e ∈ data.keptSet₂) : M.α e ∈ data.keptSet₂ := by
  classical
  obtain ⟨heU, hene⟩ := he
  simp only [Set.mem_singleton_iff] at hene
  have hαe_ne : M.α e ≠ M.α data.dart := by
    intro hcontra
    have he_eq : e = data.dart := M.α.injective hcontra
    exact data.dart_notMem_keptSet₂ hsep (he_eq ▸ ⟨heU, by
      simp only [Set.mem_singleton_iff]; exact hene⟩)
  refine ⟨?_, by simp only [Set.mem_singleton_iff]; exact hαe_ne⟩
  rcases heU with hin | hout
  · have hface_e : M.dartFace e ∈ data.side₂ := hin
    have he_not_outer : M.dartFace e ≠ hNT.outerFace :=
      data.side₂_subset_nonouter hface_e
    by_cases hbe : hNT.outerCycle.IsBoundaryEdge (M.dartEdge e)
    · right
      have hαe_outer : M.dartFace (M.α e) = hNT.outerFace := by
        rcases data.boundaryEdge_dart_outer hbe with h | h
        · exact absurd h he_not_outer
        · exact h
      exact ⟨hαe_outer, by rw [M.alpha_alpha]; exact hface_e⟩
    · left
      have hch : M.dartEdge e ≠ s(u, v) := by
        intro hchord
        rcases data.chord_edge_darts hchord with h | h
        · -- `e = dart`, so `dartFace e = face₁`; `hin` says `face₁ ∈ side₂`.
          apply data.separates_symm hsep
          show M.dartFace data.dart ∈ data.side₂
          rw [← h]; exact hin
        · exact hene h
      exact data.alpha_mem_side₂_of_interior hface_e hbe hch
  · left; exact hout.2



open scoped Classical in
/-- The deleted dart-set of side 1, as a `Finset` (complement of `keptSet₁`). -/
noncomputable def keptDel₁ (data : hNT.ChordSplitData u v) : Finset D :=
  Finset.univ.filter (fun d => d ∉ data.keptSet₁)

open scoped Classical in
/-- The deleted dart-set of side 2, as a `Finset` (complement of `keptSet₂`). -/
noncomputable def keptDel₂ (data : hNT.ChordSplitData u v) : Finset D :=
  Finset.univ.filter (fun d => d ∉ data.keptSet₂)

lemma mem_keptDel₁_iff (data : hNT.ChordSplitData u v) (d : D) :
    d ∉ data.keptDel₁ ↔ d ∈ data.keptSet₁ := by
  classical
  simp only [keptDel₁, Finset.mem_filter, Finset.mem_univ, true_and, not_not]

lemma mem_keptDel₂_iff (data : hNT.ChordSplitData u v) (d : D) :
    d ∉ data.keptDel₂ ↔ d ∈ data.keptSet₂ := by
  classical
  simp only [keptDel₂, Finset.mem_filter, Finset.mem_univ, true_and, not_not]

/-- Membership in the side-1 kept set is `α`-invariant (under `Separates`). -/
lemma mem_keptSet₁_alpha_iff (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (d : D) : M.α d ∈ data.keptSet₁ ↔ d ∈ data.keptSet₁ := by
  constructor
  · intro hd
    have := data.alpha_keptSet₁ hsep hd
    rwa [M.alpha_alpha] at this
  · intro hd; exact data.alpha_keptSet₁ hsep hd

/-- Membership in the side-2 kept set is `α`-invariant (under `Separates`). -/
lemma mem_keptSet₂_alpha_iff (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (d : D) : M.α d ∈ data.keptSet₂ ↔ d ∈ data.keptSet₂ := by
  constructor
  · intro hd
    have := data.alpha_keptSet₂ hsep hd
    rwa [M.alpha_alpha] at this
  · intro hd; exact data.alpha_keptSet₂ hsep hd

/-- **The side-1 edge involution.**  `α` restricted to the kept subtype of side 1.
A genuine permutation because `keptSet₁` is `α`-closed (under `Separates`). -/
noncomputable def sideAlpha₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    Equiv.Perm {d : D // d ∉ data.keptDel₁} :=
  M.α.subtypePerm (fun d => by
    rw [data.mem_keptDel₁_iff, data.mem_keptDel₁_iff]
    constructor
    · intro hd; exact (data.mem_keptSet₁_alpha_iff hsep d).1 hd
    · intro hd; exact (data.mem_keptSet₁_alpha_iff hsep d).2 hd)

/-- **The side-2 edge involution.** -/
noncomputable def sideAlpha₂ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    Equiv.Perm {d : D // d ∉ data.keptDel₂} :=
  M.α.subtypePerm (fun d => by
    rw [data.mem_keptDel₂_iff, data.mem_keptDel₂_iff]
    constructor
    · intro hd; exact (data.mem_keptSet₂_alpha_iff hsep d).1 hd
    · intro hd; exact (data.mem_keptSet₂_alpha_iff hsep d).2 hd)

@[simp]
lemma sideAlpha₁_apply_coe (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (d : {d : D // d ∉ data.keptDel₁}) :
    (data.sideAlpha₁ hsep d : D) = M.α d.1 := by
  simp [sideAlpha₁]

@[simp]
lemma sideAlpha₂_apply_coe (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (d : {d : D // d ∉ data.keptDel₂}) :
    (data.sideAlpha₂ hsep d : D) = M.α d.1 := by
  simp [sideAlpha₂]

/-- **Side-1 edge involution is an involution.** -/
lemma sideAlpha₁_involutive (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    data.sideAlpha₁ hsep * data.sideAlpha₁ hsep = 1 := by
  ext d
  simp only [Equiv.Perm.coe_mul, Function.comp_apply, sideAlpha₁_apply_coe,
    Equiv.Perm.coe_one, id_eq]
  exact M.alpha_alpha d.1

/-- **Side-2 edge involution is an involution.** -/
lemma sideAlpha₂_involutive (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    data.sideAlpha₂ hsep * data.sideAlpha₂ hsep = 1 := by
  ext d
  simp only [Equiv.Perm.coe_mul, Function.comp_apply, sideAlpha₂_apply_coe,
    Equiv.Perm.coe_one, id_eq]
  exact M.alpha_alpha d.1

/-- **Side-1 edge involution is fixed-point free.** -/
lemma sideAlpha₁_no_fixed (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    ∀ d, data.sideAlpha₁ hsep d ≠ d := by
  intro d hd
  apply M.α_no_fixed d.1
  have := congrArg Subtype.val hd
  rwa [sideAlpha₁_apply_coe] at this

/-- **Side-2 edge involution is fixed-point free.** -/
lemma sideAlpha₂_no_fixed (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    ∀ d, data.sideAlpha₂ hsep d ≠ d := by
  intro d hd
  apply M.α_no_fixed d.1
  have := congrArg Subtype.val hd
  rwa [sideAlpha₂_apply_coe] at this

/-- **The side-1 filtered rotation** (the kept σ before the fresh chord splice),
from file 4's generic `filteredRotation`.  A genuine permutation by construction. -/
noncomputable def sideSigma₁ (data : hNT.ChordSplitData u v) :
    Equiv.Perm {d : D // d ∉ data.keptDel₁} :=
  FilteredRotation.filteredRotation M.σ data.keptDel₁

/-- **The side-2 filtered rotation.** -/
noncomputable def sideSigma₂ (data : hNT.ChordSplitData u v) :
    Equiv.Perm {d : D // d ∉ data.keptDel₂} :=
  FilteredRotation.filteredRotation M.σ data.keptDel₂



/-- **The side-1 map.**  The fresh-dart adjunction over the side-1 kept type, with
edge involution `sideAlpha₁`, rotation `sideSigma₁`, and a duplicated chord edge
spliced at the two anchor darts `a₀, a₁`.  Its `α` is a fixed-point-free
involution and its `σ` is a permutation, both from `freshMap`. -/
noncomputable def sideMap₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) :
    CombMap ({d : D // d ∉ data.keptDel₁} ⊕ Fin 2) :=
  FilteredRotation.freshMap (data.sideAlpha₁ hsep) data.sideSigma₁
    (data.sideAlpha₁_involutive hsep) (data.sideAlpha₁_no_fixed hsep) a₀ a₁ hne

/-- **The side-2 map.** -/
noncomputable def sideMap₂ (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₂}) (hne : a₀ ≠ a₁) :
    CombMap ({d : D // d ∉ data.keptDel₂} ⊕ Fin 2) :=
  FilteredRotation.freshMap (data.sideAlpha₂ hsep) data.sideSigma₂
    (data.sideAlpha₂_involutive hsep) (data.sideAlpha₂_no_fixed hsep) a₀ a₁ hne













end ChordSplitData

end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapChordSplit
-/
/- Source module: ProofsInTheBook.PlanarMapSeparation -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)









namespace ChordSplitData

variable {hNT} {u v : M.Vertex}







/-- `Separates` literally says the second chord face is not in side 1. -/
lemma not_separates_iff_face₂_mem (data : hNT.ChordSplitData u v) :
    ¬ data.Separates ↔ data.face₂ ∈ data.side₁ := by
  unfold Separates
  exact not_not







/-- **`Separates` is the bridge property of the chord in the interior dual.**
`¬ Separates` holds iff the second chord face is reachable from the first through
`ChordSplitAdj` (which avoids the chord), i.e. iff there is a chord-avoiding dual
path joining the two chord faces.  Since the chord itself directly joins them,
this is exactly "the chord lies on a dual cycle" / "the chord is not a bridge of
the interior dual". -/
lemma not_separates_iff_reachable_avoiding_chord (data : hNT.ChordSplitData u v) :
    ¬ data.Separates ↔
      Relation.ReflTransGen (hNT.ChordSplitAdj u v) data.face₁ data.face₂ := by
  rw [data.not_separates_iff_face₂_mem]
  rfl



end ChordSplitData

/-- **The genus-0 chord separation input** (the combinatorial Jordan curve
theorem for sphere near-triangulations).  For a boundary chord `uv`, the two
chord-incident inner faces are **not** joined by a `ChordSplitAdj`-path — a dual
path avoiding boundary edges and the chord.  Combinatorially this is the
non-bridge/separating-cycle fact equivalent to the per-side Euler count
`F₁ + F₂ = F + 1`; it is the one isolated planarity keystone of the chord split. -/
def SphereChordSeparation {u v : M.Vertex} (h : hNT.outerCycle.Chord u v) : Prop :=
  ¬ Relation.ReflTransGen (hNT.ChordSplitAdj u v)
      (M.dartFace (hNT.chordDart h)) (M.dartFace (M.α (hNT.chordDart h)))

namespace ChordSplitData

variable {hNT} {u v : M.Vertex}





/-- **The chord-split separation theorem** (conditional on the isolated Jordan/
Euler input `SphereChordSeparation`).  Given the genus-0 separation input, the
second chord-incident face is not reachable from the first through the non-outer
adjacency avoiding boundary edges and the chord: i.e. `data.Separates`.

This is an honest conditional theorem on the one sharply-isolated planarity
input; by `sphereChordSeparation_iff_separates` the input is the separation
content itself at the interior-dual level (no hidden strengthening). -/
theorem separates_of_nearTriangulation (data : hNT.ChordSplitData u v)
    (hsep : hNT.SphereChordSeparation data.chord) : data.Separates := by
  by_contra hns
  exact hsep ((data.not_separates_iff_reachable_avoiding_chord).1 hns)



end ChordSplitData

end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap


end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapNearTriangulation
-/
/- Source module: ProofsInTheBook.PlanarMapBoundaryFan -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace NearTriangulation

variable {M : CombMap D}

/-- The base case for the boundary-deletion branch: exactly three graph
vertices. -/
def IsBaseTriangle (_hNT : NearTriangulation M) : Prop :=
  M.V = 3

/-- Consecutive unordered fan-path vertex pairs, represented in path order. -/
def consecutivePairs {α : Type*} (xs : List α) : List (α × α) :=
  xs.zip xs.tail

/-- The exposed fan path `x, z_1, ..., z_t, w`. -/
def fanPath (x : M.Vertex) (interior : List M.Vertex) (w : M.Vertex) :
    List M.Vertex :=
  x :: interior ++ [w]

/-- A face is incident with a vertex if one of its boundary darts has that
vertex as tail. -/
def FaceIncidentAtVertex (M : CombMap D) (f : M.Face) (v : M.Vertex) : Prop :=
  ∃ d : D, M.dartFace d = f ∧ M.tail d = v

/-- A triangle in the fan, with vertices in cyclic face order
`v0, a, b`. -/
structure FanTriangle (hNT : NearTriangulation M)
    (v0 a b : M.Vertex) where
  d0 : D
  d1 : D
  d2 : D
  triangle : M.IsFaceTriangle d0 d1 d2
  inner : M.dartFace d0 ≠ hNT.outerFace
  tail0 : M.tail d0 = v0
  tail1 : M.tail d1 = a
  tail2 : M.tail d2 = b

namespace FanTriangle

variable {hNT : NearTriangulation M} {v0 a b : M.Vertex}

/-- The inner face represented by a certified fan triangle. -/
def face (T : FanTriangle hNT v0 a b) : M.Face :=
  M.dartFace T.d0

lemma face_ne_outer (T : FanTriangle hNT v0 a b) :
    T.face ≠ hNT.outerFace :=
  T.inner

lemma faceLen_eq_three (T : FanTriangle hNT v0 a b) :
    M.faceLen T.face = 3 :=
  hNT.inner_faceLen_eq_three T.face_ne_outer

lemma vertices_pairwiseDistinct (T : FanTriangle hNT v0 a b) :
    v0 ≠ a ∧ a ≠ b ∧ b ≠ v0 := by
  have hdistinct :=
    M.isFaceTriangle_vertices_pairwiseDistinct hNT.simpleGraph T.triangle
  constructor
  · intro h
    exact hdistinct.1 (T.tail0.trans (h.trans T.tail1.symm))
  constructor
  · intro h
    exact hdistinct.2.1 (T.tail1.trans (h.trans T.tail2.symm))
  · intro h
    exact hdistinct.2.2 (T.tail2.trans (h.trans T.tail0.symm))

end FanTriangle

/-- The neighbors of `v0` occur in the listed cyclic rotation order.  This is
kept as data because File 3 does not yet expose a normalized vertex-rotation
list analogous to `BoundaryCycle.darts`. -/
structure NeighborRotationOrder (M : CombMap D) (v0 : M.Vertex)
    (neighbors : List M.Vertex) where
  darts : List D
  darts_nodup : darts.Nodup
  darts_nonempty : 0 < darts.length
  tails_eq : darts.map M.tail = List.replicate darts.length v0
  heads_eq : darts.map M.head = neighbors
  consecutive_sigma :
    ∀ i : Fin darts.length,
      darts.get (cyclicNext darts_nonempty i) = M.σ (darts.get i)

/-- The exact statement that the non-outer faces incident with `v0` are the
consecutive fan triangles along `path`.

**σ-backward / predecessor orientation (machine-certified fix, commit 15bd7a6).**
The `φ`-triangle of an inner spoke `e` at `v0` orients its edge toward the
σ-*predecessor* `head (σ⁻¹ e)`, never the σ-successor
(`ZinanCh35ChordlessFull.spokeFace_head_eq`); a forward-oriented
`FanTriangle hNT v0 a b` for a σ-forward consecutive pair `(a, b)` would force the
star of `v0` to have degree `≤ 2`
(`ZinanCh35ChordlessFull.forward_fanTriangle_forces_degree_two`).  The genuine face
between two σ-consecutive spokes carries the **reverse** labelling, so for a
consecutive pair `(a, b)` of `path` the certified triangle is
`FanTriangle hNT v0 b a` (apex `v0`, directed edge `b → a`).  All downstream
consumers use only the *unordered* edge `{a, b}` of the triangle (its surviving
edge dart, its face, and the symmetric `VConn`), so the predecessor labelling
re-threads cleanly.

The `exact_faces` field is stated with the **correct quantifier nesting**
`f ≠ outerFace → (Incident ↔ Exists)` (the legacy `→ … ↔ …` parsed as
`(f ≠ outer → Incident) ↔ Exists`, which is literally `True ↔ False` at
`f = outerFace`, making the structure uninhabitable). -/
structure IncidentNonOuterFacesExactly (hNT : NearTriangulation M)
    (v0 : M.Vertex) (path : List M.Vertex) where
  triangle_of_pair :
    ∀ {a b : M.Vertex}, (a, b) ∈ consecutivePairs path →
      FanTriangle hNT v0 b a
  exact_faces :
    ∀ f : M.Face, f ≠ hNT.outerFace →
      (FaceIncidentAtVertex M f v0 ↔
        ∃ (a b : M.Vertex) (hp : (a, b) ∈ consecutivePairs path),
          (triangle_of_pair hp).face = f)

/-- A certified boundary fan at a boundary vertex `v0`.

The interior list is `z_1, ..., z_t`; the exposed path is
`x :: interior ++ [w]`.  The chordless fields are included because they are the
facts needed later for boundary deletion and are not derivable from the current
File 3 API alone. -/
structure BoundaryVertexFan (hNT : NearTriangulation M) (v0 : M.Vertex) where
  x : M.Vertex
  interior : List M.Vertex
  w : M.Vertex
  v0_boundary : hNT.outerCycle.IsBoundaryVertex v0
  x_boundary : hNT.outerCycle.IsBoundaryVertex x
  w_boundary : hNT.outerCycle.IsBoundaryVertex w
  rotation_order : NeighborRotationOrder M v0 (fanPath x interior w)
  incident_faces_exact :
    IncidentNonOuterFacesExactly hNT v0 (fanPath x interior w)
  path_nodup_of_chordless :
    BoundaryChordless hNT.outerCycle → (fanPath x interior w).Nodup
  interior_not_boundary_of_chordless :
    BoundaryChordless hNT.outerCycle →
      ∀ z : M.Vertex, z ∈ interior → ¬ hNT.outerCycle.IsBoundaryVertex z
  empty_iff_base_triangle_of_chordless :
    BoundaryChordless hNT.outerCycle → (interior = [] ↔ hNT.IsBaseTriangle)

namespace BoundaryVertexFan

variable {hNT : NearTriangulation M} {v0 : M.Vertex}

/-- The exposed path `x, z_1, ..., z_t, w`. -/
def path (fan : BoundaryVertexFan hNT v0) : List M.Vertex :=
  fanPath fan.x fan.interior fan.w

/-- Number of exposed interior fan vertices. -/
def t (fan : BoundaryVertexFan hNT v0) : ℕ :=
  fan.interior.length





end BoundaryVertexFan

variable (hNT : NearTriangulation M) {v0 : M.Vertex}





/-- Under chordlessness, the exposed fan path has no repeated vertices. -/
theorem fan_path_simple_of_chordless (fan : BoundaryVertexFan hNT v0)
    (hchordless : BoundaryChordless hNT.outerCycle) :
    fan.path.Nodup := by
  simpa [BoundaryVertexFan.path] using
    fan.path_nodup_of_chordless hchordless

/-- Under chordlessness, an exposed interior fan vertex is not an old boundary
vertex. -/
theorem fan_interior_vertices_not_boundary_of_chordless
    (fan : BoundaryVertexFan hNT v0)
    (hchordless : BoundaryChordless hNT.outerCycle) :
    ∀ z : M.Vertex, z ∈ fan.interior → ¬ hNT.outerCycle.IsBoundaryVertex z :=
  fan.interior_not_boundary_of_chordless hchordless





/-- Under chordlessness, the exposed fan path meets the old boundary only at
its two endpoint vertices. -/
theorem fan_path_meets_old_boundary_only_at_ends
    (fan : BoundaryVertexFan hNT v0)
    (hchordless : BoundaryChordless hNT.outerCycle) :
    ∀ y : M.Vertex, y ∈ fan.path → hNT.outerCycle.IsBoundaryVertex y →
      y = fan.x ∨ y = fan.w := by
  intro y hy hy_boundary
  have hy_path : y ∈ fan.x :: fan.interior ++ [fan.w] := by
    simpa [BoundaryVertexFan.path, fanPath] using hy
  rcases List.mem_cons.mp hy_path with hyx | hyrest
  · exact Or.inl hyx
  · rcases List.mem_append.mp hyrest with hyint | hyw
    · exact False.elim
        ((fan_interior_vertices_not_boundary_of_chordless hNT fan hchordless
          y hyint) hy_boundary)
    · have hyw' : y = fan.w := by
        simpa using hyw
      exact Or.inr hyw'

/-- In the chordless non-base case, the fan has at least one exposed interior
vertex.  This is the tetrahedron/minimal-`t=1` side of the deletion case. -/
theorem fan_nonempty_of_chordless_of_not_triangle
    (fan : BoundaryVertexFan hNT v0)
    (hchordless : BoundaryChordless hNT.outerCycle)
    (hnot_base : 3 < M.V) :
    1 ≤ fan.t := by
  have hne : fan.t ≠ 0 := by
    intro ht0
    have hlen : fan.interior.length = 0 := by
      simpa [BoundaryVertexFan.t] using ht0
    have hempty : fan.interior = [] :=
      List.length_eq_zero_iff.mp hlen
    have hbase : hNT.IsBaseTriangle :=
      (fan.empty_iff_base_triangle_of_chordless hchordless).1 hempty
    unfold IsBaseTriangle at hbase
    omega
  exact Nat.one_le_iff_ne_zero.mpr hne



end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapBoundaryFan
import ProofsInTheBook.PlanarMapDelete
-/
/- Source module: ProofsInTheBook.PlanarMapBoundaryDelete -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace NearTriangulation

variable {M : CombMap D}



/-- A simple graph has no loop at any vertex (dart-representative form), so the
deletion edge-count hypothesis `NoLoopAt` holds unconditionally. -/
lemma noLoopAt_of_simpleGraph (hNT : NearTriangulation M) (d0 : D) :
    M.NoLoopAt d0 := by
  intro d hd
  rw [mem_vertexDarts] at hd ⊢
  exact noLoopAt_dart_of_isSimpleGraph M hNT.simpleGraph d0 d hd


structure BoundaryDeletionData (hNT : NearTriangulation M) (d0 : D) where
  /-- Local simple-boundary condition: distinct darts at `v0` lie on distinct
  faces. -/
  vertexFacesDistinct : M.VertexFacesDistinct d0
  /-- The surviving vertex quotients are the old ones minus the orbit of `d0`. -/
  vertexQuotient :
    Quotient (cycleSetoid (M.deleteVertex d0).σ) ≃
      {Q : Quotient (cycleSetoid M.σ) //
        Q ≠ Quotient.mk (cycleSetoid M.σ) d0}
  /-- The faces incident with `v0` merge into one new outer face. -/
  facesMerge : M.DeleteVertexFacesMerge d0
  /-- The deleted map is connected (via the exposed fan path). -/
  connected : (M.deleteVertex d0).Connected



/-- An edge `α`-cycle relation in `M` between two surviving darts lifts to the
deleted map. -/
 lemma deleted_alpha_sameCycle_of_M {d0 : D}
    (d e : {d : D // d ∉ M.deleteVertexSet d0})
    (h : M.α.SameCycle d.1 e.1) :
    (M.deleteVertex d0).α.SameCycle d e := by
  rcases (M.alpha_sameCycle_iff d.1 e.1).1 h with hde | hde
  · exact (Subtype.ext hde.symm).sameCycle _
  · refine ⟨1, ?_⟩
    apply Subtype.ext
    rw [zpow_one, deleteVertex_alpha_apply_coe]
    exact hde.symm

/-- The vertex `σ`-quotient of `d` in the deleted map equals that of `e` iff the
underlying darts share a `σ`-cycle in `M`. -/
 lemma deleted_tail_eq_iff {d0 : D}
    (d e : {d : D // d ∉ M.deleteVertexSet d0}) :
    (M.deleteVertex d0).tail d = (M.deleteVertex d0).tail e ↔
      M.σ.SameCycle d.1 e.1 := by
  constructor
  · intro h
    exact (deleteVertex_sigma_sameCycle_iff M d0 d e).1 (Quotient.exact h)
  · intro h
    exact Quotient.sound ((deleteVertex_sigma_sameCycle_iff M d0 d e).2 h)

/-- The deleted map is a simple graph: deletion only removes darts and reverses,
so no loop or parallel edge can appear among the survivors.  This holds for any
dart `d0` and needs no deletion certificate. -/
theorem deleteVertex_isSimpleGraph (hNT : NearTriangulation M) (d0 : D) :
    (M.deleteVertex d0).IsSimpleGraph := by
  refine ⟨?_, ?_⟩
  · -- no loop: a loop in the deleted map is a loop in `M`
    intro d hloop
    apply hNT.simpleGraph.no_loop d.1
    have hsame : (M.deleteVertex d0).σ.SameCycle d ((M.deleteVertex d0).α d) :=
      Quotient.exact hloop
    have hsameM : M.σ.SameCycle d.1 ((M.deleteVertex d0).α d).1 :=
      (deleteVertex_sigma_sameCycle_iff M d0 d ((M.deleteVertex d0).α d)).1 hsame
    have hαcoe : ((M.deleteVertex d0).α d : D) = M.α d.1 :=
      deleteVertex_alpha_apply_coe M d0 d
    show M.tail d.1 = M.head d.1
    exact Quotient.sound (by rwa [hαcoe] at hsameM)
  · -- no parallel edges: same endpoints in the deleted map means same edge in `M`
    intro d e hedge
    have hαd : ((M.deleteVertex d0).α d : D) = M.α d.1 :=
      deleteVertex_alpha_apply_coe M d0 d
    have hαe : ((M.deleteVertex d0).α e : D) = M.α e.1 :=
      deleteVertex_alpha_apply_coe M d0 e
    have hedge' :
        (s((M.deleteVertex d0).tail d, (M.deleteVertex d0).head d) :
            Sym2 (M.deleteVertex d0).Vertex) =
          s((M.deleteVertex d0).tail e, (M.deleteVertex d0).head e) := hedge
    rw [Sym2.eq_iff] at hedge'
    rcases hedge' with ⟨ht, hh⟩ | ⟨ht, hh⟩
    · have htM : M.σ.SameCycle d.1 e.1 := (deleted_tail_eq_iff d e).1 ht
      have hhM : M.σ.SameCycle (M.α d.1) (M.α e.1) := by
        have hh' : (M.deleteVertex d0).tail ((M.deleteVertex d0).α d) =
            (M.deleteVertex d0).tail ((M.deleteVertex d0).α e) := hh
        have := (deleted_tail_eq_iff ((M.deleteVertex d0).α d)
          ((M.deleteVertex d0).α e)).1 hh'
        rwa [hαd, hαe] at this
      refine deleted_alpha_sameCycle_of_M d e (hNT.simpleGraph.no_parallel ?_)
      show s(M.tail d.1, M.head d.1) = s(M.tail e.1, M.head e.1)
      rw [Sym2.eq_iff]
      exact Or.inl ⟨Quotient.sound htM, Quotient.sound hhM⟩
    · have htM : M.σ.SameCycle d.1 (M.α e.1) := by
        have ht' : (M.deleteVertex d0).tail d =
            (M.deleteVertex d0).tail ((M.deleteVertex d0).α e) := ht
        have := (deleted_tail_eq_iff d ((M.deleteVertex d0).α e)).1 ht'
        rwa [hαe] at this
      have hhM : M.σ.SameCycle (M.α d.1) e.1 := by
        have hh' : (M.deleteVertex d0).tail ((M.deleteVertex d0).α d) =
            (M.deleteVertex d0).tail e := hh
        have := (deleted_tail_eq_iff ((M.deleteVertex d0).α d) e).1 hh'
        rwa [hαd] at this
      refine deleted_alpha_sameCycle_of_M d e (hNT.simpleGraph.no_parallel ?_)
      show s(M.tail d.1, M.head d.1) = s(M.tail e.1, M.head e.1)
      rw [Sym2.eq_iff]
      exact Or.inr ⟨Quotient.sound htM, Quotient.sound hhM⟩

namespace BoundaryDeletionData

variable {hNT : NearTriangulation M} {d0 : D}

/-- The deleted map is a sphere map: assemble `noLoopAt_of_simpleGraph` with the
certificate fields and the reusable `deleteVertex_isSphereMap`. -/
theorem isSphereMap (data : BoundaryDeletionData hNT d0) :
    (M.deleteVertex d0).IsSphereMap :=
  M.deleteVertex_isSphereMap d0 hNT.sphere
    (hNT.noLoopAt_of_simpleGraph d0)
    data.vertexQuotient
    data.vertexFacesDistinct
    data.facesMerge
    data.connected







/-- The deleted map is simple (this needs no certificate). -/
theorem deleteVertex_isSimpleGraph (_data : BoundaryDeletionData hNT d0) :
    (M.deleteVertex d0).IsSimpleGraph :=
  hNT.deleteVertex_isSimpleGraph d0





end BoundaryDeletionData


structure DeletedBoundaryData (hNT : NearTriangulation M) (d0 : D) where
  /-- The merged outer face of the deleted map. -/
  outerFace : (M.deleteVertex d0).Face
  /-- The new outer boundary cycle. -/
  outerCycle : BoundaryCycle (M.deleteVertex d0) outerFace
  /-- The new boundary vertex list is simple. -/
  outer_simple : outerCycle.VertexNodup
  /-- The new boundary has length at least three. -/
  outer_len_ge_three : 3 ≤ outerCycle.length
  /-- Every non-outer face of the deleted map is triangular (an unchanged old
  inner face). -/
  inner_tri : ∀ f : (M.deleteVertex d0).Face, f ≠ outerFace →
    (M.deleteVertex d0).faceLen f = 3

/-- **Boundary-vertex deletion preserves near-triangulation.**

Given the residual deletion surgery certificate `data` and the deleted-map
boundary surgery certificate `bdy`, the map obtained by deleting the boundary
vertex represented by `d0` is again a near-triangulation.

The sphere-map and simple-graph fields are *derived* (`isSphereMap`,
`deleteVertex_isSimpleGraph`); only the outer-boundary cycle and the inner-face
triangularity come from `bdy`, exactly the dart-level surgery the fan layer does
not expose. -/
def deleteBoundaryVertex_nearTriangulation {hNT : NearTriangulation M}
    {d0 : D} (data : BoundaryDeletionData hNT d0)
    (bdy : DeletedBoundaryData hNT d0) :
    NearTriangulation (M.deleteVertex d0) where
  sphere := data.isSphereMap
  simpleGraph := data.deleteVertex_isSimpleGraph
  outerFace := bdy.outerFace
  outerCycle := bdy.outerCycle
  outer_simple := bdy.outer_simple
  outer_len := bdy.outer_len_ge_three
  inner_tri := bdy.inner_tri





end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapBoundaryDelete
-/
/- Source module: ProofsInTheBook.PlanarMapFanSurgery -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace NearTriangulation

variable {M : CombMap D}



/-- In a near-triangulation, a dart whose face is an inner (triangular) face lies
in the `φ`-orbit `{d, φ d, φ² d}`, and these three darts have distinct tails. -/
lemma inner_face_dart_eq_of_same_tail (hNT : NearTriangulation M) {d e : D}
    (hd : M.dartFace d ≠ hNT.outerFace)
    (hface : M.dartFace e = M.dartFace d) (htail : M.tail e = M.tail d) :
    e = d := by
  classical
  -- The triangular face: support of the `φ`-cycle of `d` has size 3.
  have hφ : M.φ d ≠ d := phi_ne_self_of_isSimpleGraph M hNT.simpleGraph d
  have hlen : M.faceLen (M.dartFace d) = 3 := hNT.inner_tri (M.dartFace d) hd
  have hcard : (M.φ.cycleOf d).support.card = 3 := by
    rw [← faceLen_dartFace_eq_card_support_cycleOf M hφ, hlen]
  -- `e` shares the `φ`-cycle with `d`.
  have hcycle : M.φ.SameCycle d e := Quotient.exact hface.symm
  have hsupport : d ∈ M.φ.support := by simpa [Equiv.Perm.mem_support] using hφ
  obtain ⟨i, hi, hipow⟩ := hcycle.exists_pow_eq_of_mem_support hsupport
  rw [hcard] at hi
  -- The three tails are pairwise distinct.
  have hverts := faceLen_three_vertices_pairwiseDistinct M hNT.simpleGraph hlen
  interval_cases i
  · simpa using hipow.symm
  · exfalso
    have he1 : M.φ d = e := by simpa using hipow
    have : M.tail (M.φ d) = M.tail d := by rw [he1, htail]
    exact hverts.1 this.symm
  · exfalso
    have he2 : M.φ (M.φ d) = e := by
      simpa [pow_succ, Equiv.Perm.coe_mul, Function.comp_apply] using hipow
    have : M.tail (M.φ (M.φ d)) = M.tail d := by rw [he2, htail]
    exact hverts.2.2 this

/-- Two darts of a near-triangulation that share the same face and the same tail
are equal.  This is the dart-level statement underlying `VertexFacesDistinct`. -/
lemma dart_eq_of_same_face_same_tail (hNT : NearTriangulation M) {d e : D}
    (hface : M.dartFace d = M.dartFace e) (htail : M.tail d = M.tail e) :
    d = e := by
  classical
  by_cases houter : M.dartFace d = hNT.outerFace
  · -- Both darts lie on the simple outer cycle; its tails are injective.
    have hdmem : d ∈ hNT.outerCycle.darts :=
      (hNT.outerCycle.mem_darts_iff d).mpr houter
    have hemem : e ∈ hNT.outerCycle.darts :=
      (hNT.outerCycle.mem_darts_iff e).mpr (hface ▸ houter)
    exact hNT.outerCycle.tail_injective_on_darts hNT.outer_simple hdmem hemem htail
  · exact (inner_face_dart_eq_of_same_tail hNT houter hface.symm htail.symm).symm

/-- **`VertexFacesDistinct` discharged.**  In a near-triangulation, the darts at a
vertex represented by `d0` lie on pairwise distinct faces. -/
theorem vertexFacesDistinct_of_nearTriangulation (hNT : NearTriangulation M)
    (d0 : D) : M.VertexFacesDistinct d0 := by
  intro d hd e he hface
  -- `hd, he : same σ-cycle as d0`, so `tail d = tail e = tail d0`.
  have hdtail : M.tail d = M.tail d0 := by
    have : M.σ.SameCycle d0 d := by simpa [vertexDarts] using hd
    exact (Quotient.sound this.symm)
  have hetail : M.tail e = M.tail d0 := by
    have : M.σ.SameCycle d0 e := by simpa [vertexDarts] using he
    exact (Quotient.sound this.symm)
  exact dart_eq_of_same_face_same_tail hNT hface (hdtail.trans hetail.symm)



namespace NeighborRotationOrder

variable {v0 : M.Vertex} {neighbors : List M.Vertex}

/-- Each listed rotation dart has tail `v0`. -/
lemma tail_get (rot : NeighborRotationOrder M v0 neighbors)
    (i : Fin rot.darts.length) : M.tail (rot.darts.get i) = v0 := by
  have hmem : M.tail (rot.darts.get i) ∈ rot.darts.map M.tail :=
    List.mem_map_of_mem (List.get_mem _ _)
  rw [rot.tails_eq] at hmem
  exact List.eq_of_mem_replicate hmem



/-- The rotation dart set is closed under `σ`. -/
lemma sigma_mem (rot : NeighborRotationOrder M v0 neighbors)
    {d : D} (hd : d ∈ rot.darts) : M.σ d ∈ rot.darts := by
  rw [List.mem_iff_get] at hd
  obtain ⟨i, hi⟩ := hd
  rw [← hi, ← rot.consecutive_sigma i]
  exact List.get_mem _ _

/-- The rotation list enumerates exactly the `σ`-orbit of a dart `d0` with tail
`v0`: it is closed under `σ`, nonempty, nodup, and shares the orbit of `d0`. -/
lemma vertexDarts_eq (rot : NeighborRotationOrder M v0 neighbors)
    {d0 : D} (htail : M.tail d0 = v0) :
    M.vertexDarts d0 = rot.darts.toFinset := by
  classical
  -- A representative dart of the list.
  set d1 : D := rot.darts.get ⟨0, rot.darts_nonempty⟩ with hd1
  have hd1_mem : d1 ∈ rot.darts := List.get_mem _ _
  have hd1_tail : M.tail d1 = v0 := rot.tail_get ⟨0, rot.darts_nonempty⟩
  have hsame01 : M.σ.SameCycle d0 d1 := Quotient.exact (htail.trans hd1_tail.symm)
  ext e
  rw [mem_vertexDarts, List.mem_toFinset]
  constructor
  · -- `σ.SameCycle d0 e → e ∈ list`.  Move along the orbit from `d1` to `e`.
    intro he
    have hse : M.σ.SameCycle d1 e := hsame01.symm.trans he
    obtain ⟨n, hn⟩ : ∃ n : ℕ, (M.σ ^ n) d1 = e :=
      Equiv.Perm.SameCycle.exists_nat_pow_eq hse
    -- climb `n` steps of `σ` from `d1`, staying inside the σ-closed list.
    have hclosed : ∀ m : ℕ, (M.σ ^ m) d1 ∈ rot.darts := by
      intro m
      induction m with
      | zero => simpa using hd1_mem
      | succ m ih =>
          have hstep : (M.σ ^ (m + 1)) d1 = M.σ ((M.σ ^ m) d1) := by
            rw [pow_succ']; rfl
          rw [hstep]
          exact rot.sigma_mem ih
    rw [← hn]; exact hclosed n
  · -- `e ∈ list → σ.SameCycle d0 e`.
    intro he
    rw [List.mem_iff_get] at he
    obtain ⟨j, hj⟩ := he
    have hetail : M.tail (rot.darts.get j) = v0 := rot.tail_get j
    rw [← hj]
    exact Quotient.exact (htail.trans hetail.symm)





end NeighborRotationOrder





/-- The dart-level output of the boundary-vertex deletion surgery at the boundary
vertex represented by `d0`.  Its fields are exactly the equivalences /
connectivity / boundary cycle that the `deleteSet`-based `deleteVertex` operation
does not produce automatically (see the `TwoEdgePathObstruction` section of
`PlanarMapDelete`), specialized to a chordless boundary vertex via the fan. -/
structure FanSurgeryReconstruction (hNT : NearTriangulation M) (d0 : D) where
  /-- The surviving vertex `σ`-orbits are the old ones minus `⟦d0⟧`. -/
  vertexQuotient :
    Quotient (cycleSetoid (M.deleteVertex d0).σ) ≃
      {Q : Quotient (cycleSetoid M.σ) //
        Q ≠ Quotient.mk (cycleSetoid M.σ) d0}
  /-- The faces incident with `v0` merge into one new outer face. -/
  facesMerge : M.DeleteVertexFacesMerge d0
  /-- The deleted map is connected. -/
  connected : (M.deleteVertex d0).Connected
  /-- The merged outer face of the deleted map. -/
  outerFace : (M.deleteVertex d0).Face
  /-- The new outer boundary cycle (fan path plus surviving old boundary arc). -/
  outerCycle : BoundaryCycle (M.deleteVertex d0) outerFace
  /-- The new boundary vertex list is simple. -/
  outer_simple : outerCycle.VertexNodup
  /-- The new boundary has length at least three. -/
  outer_len_ge_three : 3 ≤ outerCycle.length
  /-- Every non-outer face of the deleted map is an unchanged old inner triangle. -/
  inner_tri : ∀ f : (M.deleteVertex d0).Face, f ≠ outerFace →
    (M.deleteVertex d0).faceLen f = 3

namespace FanSurgeryReconstruction

variable {hNT : NearTriangulation M} {d0 : D}

/-- Assemble the `BoundaryDeletionData` certificate of `PlanarMapBoundaryDelete`
from the reconstruction.  The two locally-provable fields (`VertexFacesDistinct`)
are supplied by `vertexFacesDistinct_of_nearTriangulation`; the genuinely
dart-level fields come from the reconstruction. -/
def toBoundaryDeletionData (R : FanSurgeryReconstruction hNT d0) :
    BoundaryDeletionData hNT d0 where
  vertexFacesDistinct := hNT.vertexFacesDistinct_of_nearTriangulation d0
  vertexQuotient := R.vertexQuotient
  facesMerge := R.facesMerge
  connected := R.connected

/-- Assemble the `DeletedBoundaryData` certificate from the reconstruction. -/
def toDeletedBoundaryData (R : FanSurgeryReconstruction hNT d0) :
    DeletedBoundaryData hNT d0 where
  outerFace := R.outerFace
  outerCycle := R.outerCycle
  outer_simple := R.outer_simple
  outer_len_ge_three := R.outer_len_ge_three
  inner_tri := R.inner_tri

/-- **The deleted map is a near-triangulation, derived from the reconstruction.**

This is the headline endpoint: given the dart-level reconstruction `R`, deleting
the boundary vertex represented by `d0` again yields a near-triangulation.  Every
hypothesis of `deleteBoundaryVertex_nearTriangulation` is supplied — the locally
provable ones (`NoLoopAt`, `VertexFacesDistinct`) discharged here, the genuinely
dart-level ones taken from `R`. -/
def nearTriangulation (R : FanSurgeryReconstruction hNT d0) :
    NearTriangulation (M.deleteVertex d0) :=
  deleteBoundaryVertex_nearTriangulation R.toBoundaryDeletionData R.toDeletedBoundaryData











end FanSurgeryReconstruction









end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
/-
List-coloring primitives (Chapter 35 layer 4).

Design-independent groundwork for the Thomassen five-list-coloring route
(HANDOFF/CH35_DESIGN_ANSWER.md): proper colorings from lists, monotonicity
in the graph and in the lists, and the piecewise gluing lemmas — including
the rooted cut-vertex glue, which is the form that is actually true for
list colorings (naive gluing fails because the two sides may disagree at
the cut vertex).
-/
import Mathlib
-/
/- Source module: ProofsInTheBook.ListColoring -/
section
set_option autoImplicit true


namespace ProofsInTheBook.ListColoring

variable {V α : Type*}

/-- `c` is proper on the region `s`: no monochromatic edge inside `s`. -/
def ProperOn (G : SimpleGraph V) (s : Set V) (c : V → α) : Prop :=
  ∀ ⦃u v⦄, u ∈ s → v ∈ s → G.Adj u v → c u ≠ c v

/-- `c` picks from the lists `L` on the region `s`. -/
def ListValidOn (L : V → Finset α) (s : Set V) (c : V → α) : Prop :=
  ∀ ⦃v⦄, v ∈ s → c v ∈ L v

/-- A proper coloring of all of `G` choosing from the lists `L`. -/
def IsListColoring (G : SimpleGraph V) (L : V → Finset α) (c : V → α) : Prop :=
  (∀ v, c v ∈ L v) ∧ ∀ ⦃u v⦄, G.Adj u v → c u ≠ c v

/-- `G` admits a proper coloring from the lists `L`. -/
def ListColorable (G : SimpleGraph V) (L : V → Finset α) : Prop :=
  ∃ c, IsListColoring G L c











section Glue

variable {G : SimpleGraph V} {L : V → Finset α} {s t : Set V} {c₁ c₂ : V → α}





end Glue



end ProofsInTheBook.ListColoring

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapSeparation
import ProofsInTheBook.PlanarMapFanSurgery
import ProofsInTheBook.ListColoring
-/
/- Source module: ProofsInTheBook.ThomassenLists -/
section
set_option autoImplicit true




namespace ProofsInTheBook.ThomassenLists

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.ListColoring

variable {D : Type*} [Fintype D] [DecidableEq D]
variable {α : Type*} [DecidableEq α]

namespace CombMap

open ProofsInTheBook.PlanarMap.CombMap



/--
The Thomassen list hypotheses for a near-triangulation `M` with a distinguished
*precolored boundary edge* `s(p, q)`.

The two endpoints `p, q` are adjacent on the outer cycle, precolored by singleton
lists `{cp}`, `{cq}` with distinct colors; every other boundary vertex has a list
of size at least `3`; every interior (non-boundary) vertex has a list of size at
least `5`.
-/
structure ThomassenLists {M : CombMap D} (hNT : NearTriangulation M)
    (p q : M.Vertex) (L : M.Vertex → Finset α) (cp cq : α) : Prop where
  /-- `p` is on the outer boundary. -/
  p_boundary : hNT.outerCycle.IsBoundaryVertex p
  /-- `q` is on the outer boundary. -/
  q_boundary : hNT.outerCycle.IsBoundaryVertex q
  /-- `p` and `q` are joined by an outer-boundary edge: a precolored edge. -/
  pq_boundary_edge : hNT.outerCycle.IsBoundaryEdge s(p, q)
  /-- The two precolored endpoints carry distinct colors. -/
  colors_ne : cp ≠ cq
  /-- `p` is precolored to the singleton `{cp}`. -/
  list_p : L p = {cp}
  /-- `q` is precolored to the singleton `{cq}`. -/
  list_q : L q = {cq}
  /-- Every other boundary vertex has list size at least three. -/
  boundary_ge_three : ∀ v : M.Vertex,
    hNT.outerCycle.IsBoundaryVertex v → v ≠ p → v ≠ q → 3 ≤ (L v).card
  /-- Every interior (non-boundary) vertex has list size at least five. -/
  interior_ge_five : ∀ v : M.Vertex,
    ¬ hNT.outerCycle.IsBoundaryVertex v → 5 ≤ (L v).card

namespace ThomassenLists

variable {M : CombMap D} {hNT : NearTriangulation M}
  {p q : M.Vertex} {L : M.Vertex → Finset α} {cp cq : α}

/-- `p ≠ q`: a precolored edge has distinct endpoints. -/
lemma p_ne_q (h : ThomassenLists hNT p q L cp cq) : p ≠ q := by
  intro hpq
  have : cp = cq := by
    have hp := h.list_p
    have hq := h.list_q
    rw [hpq] at hp
    have : ({cp} : Finset α) = {cq} := hp.symm.trans hq
    simpa using this
  exact h.colors_ne this







end ThomassenLists



/--
The `M`-vertex level encoding of a chord split with chord endpoints `u, v` and a
precolored boundary edge `s(p, q)` lying on side 1.

`s₁, s₂ : Set M.Vertex` are the two sides (with the chord endpoints in both).
The Thomassen list hypotheses are carried as region predicates; the `glue` step
combines a side-1 coloring with a compatible side-2 coloring into a coloring of
all of `M.toSimpleGraph`.
-/
structure ChordSplitRegions {M : CombMap D} (hNT : NearTriangulation M)
    (u v p q : M.Vertex) (L : M.Vertex → Finset α) (cp cq : α) where
  /-- Side 1 of the split (contains the precolored edge `pq`). -/
  s₁ : Set M.Vertex
  /-- Side 2 of the split (contains the chord `uv`). -/
  s₂ : Set M.Vertex
  /-- The two sides cover all vertices. -/
  cover : ∀ w : M.Vertex, w ∈ s₁ ∨ w ∈ s₂
  /-- Every graph edge stays inside one side. -/
  edge_confined : ∀ ⦃a b : M.Vertex⦄, M.toSimpleGraph.Adj a b →
    (a ∈ s₁ ∧ b ∈ s₁) ∨ (a ∈ s₂ ∧ b ∈ s₂)
  /-- The two sides overlap in exactly the chord endpoints. -/
  overlap : s₁ ∩ s₂ ⊆ {u, v}
  /-- The chord endpoints are on side 1. -/
  u_s₁ : u ∈ s₁
  /-- The chord endpoints are on side 1. -/
  v_s₁ : v ∈ s₁
  /-- The chord endpoints are on side 2. -/
  u_s₂ : u ∈ s₂
  /-- The chord endpoints are on side 2. -/
  v_s₂ : v ∈ s₂
  /-- The precolored endpoints are on side 1. -/
  p_s₁ : p ∈ s₁
  /-- The precolored endpoints are on side 1. -/
  q_s₁ : q ∈ s₁
  /-- The chord `uv` is an edge of `M`. -/
  chord_adj : M.toSimpleGraph.Adj u v

namespace ChordSplitRegions

variable {M : CombMap D} {hNT : NearTriangulation M}
  {u v p q : M.Vertex} {L : M.Vertex → Finset α} {cp cq : α}





/-- The side-2 forced lists: `u, v` become singletons of their side-1 colors,
every other vertex keeps its list. -/
noncomputable def forcedLists (R : ChordSplitRegions hNT u v p q L cp cq)
    (c₁ : M.Vertex → α) (L : M.Vertex → Finset α) : M.Vertex → Finset α :=
  fun w => if w = u then {c₁ u} else if w = v then {c₁ v} else L w

@[simp]
lemma forcedLists_u (R : ChordSplitRegions hNT u v p q L cp cq)
    (c₁ : M.Vertex → α) (L₀ : M.Vertex → Finset α) :
    R.forcedLists c₁ L₀ u = {c₁ u} := by
  unfold forcedLists; rw [if_pos rfl]

lemma forcedLists_v (R : ChordSplitRegions hNT u v p q L cp cq)
    (huv : u ≠ v) (c₁ : M.Vertex → α) (L₀ : M.Vertex → Finset α) :
    R.forcedLists c₁ L₀ v = {c₁ v} := by
  simp [forcedLists, huv.symm]

lemma forcedLists_other (R : ChordSplitRegions hNT u v p q L cp cq)
    {w : M.Vertex} (hwu : w ≠ u) (hwv : w ≠ v)
    (c₁ : M.Vertex → α) (L₀ : M.Vertex → Finset α) :
    R.forcedLists c₁ L₀ w = L₀ w := by
  simp [forcedLists, hwu, hwv]



end ChordSplitRegions



section Deletion

variable {M : CombMap D}

/-- The canonical map from a vertex of the deleted map to a vertex of `M`,
induced by the kept-dart inclusion `⟦e⟧ ↦ ⟦e.1⟧`.  Well defined because the
deleted-map `σ`-cycle relation is the restriction of `M`'s (see
`deleteVertex_sigma_sameCycle_iff`). -/
noncomputable def deletedVertexToM (M : CombMap D) (d0 : D) :
    (M.deleteVertex d0).Vertex → M.Vertex :=
  Quotient.lift (fun e : {d : D // d ∉ M.deleteVertexSet d0} => M.tail e.1)
    (by
      intro a b hab
      have hsc : (M.deleteVertex d0).σ.SameCycle a b := hab
      rw [deleteVertex_sigma_sameCycle_iff] at hsc
      exact Quotient.sound hsc)

@[simp]
lemma deletedVertexToM_mk (M : CombMap D) (d0 : D)
    (e : {d : D // d ∉ M.deleteVertexSet d0}) :
    deletedVertexToM M d0 (Quotient.mk (cycleSetoid (M.deleteVertex d0).σ) e) =
      M.tail e.1 :=
  rfl

@[simp]
lemma deletedVertexToM_tail (M : CombMap D) (d0 : D)
    (e : {d : D // d ∉ M.deleteVertexSet d0}) :
    deletedVertexToM M d0 ((M.deleteVertex d0).tail e) = M.tail e.1 :=
  rfl

@[simp]
lemma deletedVertexToM_head (M : CombMap D) (d0 : D)
    (e : {d : D // d ∉ M.deleteVertexSet d0}) :
    deletedVertexToM M d0 ((M.deleteVertex d0).head e) = M.head e.1 := by
  show deletedVertexToM M d0
      (Quotient.mk (cycleSetoid (M.deleteVertex d0).σ) ((M.deleteVertex d0).α e)) = _
  rw [deletedVertexToM_mk]
  rw [deleteVertex_alpha_apply_coe]
  rfl

/-- The kept-dart vertex map is injective: distinct deleted-map vertices have
distinct underlying `M`-vertices. -/
lemma deletedVertexToM_injective (M : CombMap D) (d0 : D) :
    Function.Injective (deletedVertexToM M d0) := by
  intro a b hab
  induction a using Quotient.inductionOn with
  | _ ea =>
    induction b using Quotient.inductionOn with
    | _ eb =>
      rw [deletedVertexToM_mk, deletedVertexToM_mk] at hab
      have hsc : M.σ.SameCycle ea.1 eb.1 := Quotient.exact hab
      rw [← deleteVertex_sigma_sameCycle_iff] at hsc
      exact Quotient.sound hsc



/-- The image of the kept-dart vertex map avoids the deleted vertex `v0 = ⟦d0⟧`:
a surviving dart `e ∉ deleteVertexSet d0` is in particular not in the star of
`v0`, so its `M`-tail is not `⟦d0⟧`. -/
lemma deletedVertexToM_ne_v0 (M : CombMap D) (d0 : D)
    (a : (M.deleteVertex d0).Vertex) :
    deletedVertexToM M d0 a ≠ M.tail d0 := by
  induction a using Quotient.inductionOn with
  | _ e =>
    rw [deletedVertexToM_mk]
    intro hcontra
    -- `M.tail e.1 = M.tail d0` ⇒ `σ.SameCycle d0 e.1` ⇒ `e.1 ∈ vertexDarts d0`
    have hsc : M.σ.SameCycle d0 e.1 := Quotient.exact hcontra.symm
    have hmem : e.1 ∈ M.vertexDarts d0 := (mem_vertexDarts M d0 e.1).mpr hsc
    have hdel : e.1 ∈ M.deleteVertexSet d0 :=
      (mem_deleteVertexSet_iff M d0 e.1).mpr (Or.inl hmem)
    exact e.2 hdel

/-- The kept-dart vertex map, corestricted to `{Q // Q ≠ ⟦d0⟧}`. -/
noncomputable def deletedVertexToM' (M : CombMap D) (d0 : D)
    (a : (M.deleteVertex d0).Vertex) :
    {Q : M.Vertex // Q ≠ Quotient.mk (cycleSetoid M.σ) d0} :=
  ⟨deletedVertexToM M d0 a, deletedVertexToM_ne_v0 M d0 a⟩

lemma deletedVertexToM'_injective (M : CombMap D) (d0 : D) :
    Function.Injective (deletedVertexToM' M d0) := by
  intro a b hab
  exact deletedVertexToM_injective M d0 (Subtype.ext_iff.mp hab)

/-- **The kept-dart vertex map is a bijection onto `{Q // Q ≠ ⟦d0⟧}`.**

An injective map between two finite types of equal cardinality is bijective.
The cardinality equality is exactly the reconstruction equivalence
`FanSurgeryReconstruction.vertexQuotient`, so the *canonical* kept-dart map (not
the abstract reconstruction equiv) is itself the desired bijection. -/
lemma deletedVertexToM'_bijective {hNT : NearTriangulation M} {d0 : D}
    (R : NearTriangulation.FanSurgeryReconstruction hNT d0) :
    Function.Bijective (deletedVertexToM' M d0) := by
  classical
  have hcard :
      Fintype.card ((M.deleteVertex d0).Vertex) =
        Fintype.card {Q : M.Vertex // Q ≠ Quotient.mk (cycleSetoid M.σ) d0} :=
    Fintype.card_congr R.vertexQuotient
  exact (Fintype.bijective_iff_injective_and_card _).mpr
    ⟨deletedVertexToM'_injective M d0, hcard⟩

/-- A dart whose two `M`-endpoints both avoid `v0 = ⟦d0⟧` survives the deletion:
it is not in the closed star `deleteVertexSet d0`. -/
lemma dart_notMem_deleteVertexSet_of_endpoints_ne (M : CombMap D) (d0 : D)
    {d : D} (htail : M.tail d ≠ M.tail d0) (hhead : M.head d ≠ M.tail d0) :
    d ∉ M.deleteVertexSet d0 := by
  rw [mem_deleteVertexSet_iff]
  push_neg
  constructor
  · rw [mem_vertexDarts]
    intro hsc
    exact htail (Quotient.sound hsc.symm)
  · rw [mem_vertexDarts]
    intro hsc
    -- `σ.SameCycle d0 (α d)` ⇒ `tail (α d) = tail d0`, and `tail (α d) = head d`
    have : M.tail (M.α d) = M.tail d0 := Quotient.sound hsc.symm
    rw [tail_alpha] at this
    exact hhead this





variable {hNT : NearTriangulation M} {d0 : D} {v0 : M.Vertex}

/-- The deleted-map lists.  A deleted vertex `q'` whose `M`-image lies in the fan
interior loses the two reserved colors `γ, δ`; every other vertex keeps `L`. -/
noncomputable def deleteFanLists (M : CombMap D) (d0 : D)
    (fanInterior : Finset M.Vertex) (L : M.Vertex → Finset α) (γ δ : α) :
    (M.deleteVertex d0).Vertex → Finset α :=
  fun q' =>
    if deletedVertexToM M d0 q' ∈ fanInterior then
      (L (deletedVertexToM M d0 q')) \ {γ, δ}
    else L (deletedVertexToM M d0 q')

/-- On a fan vertex the deleted list is `L` minus the two reserved colors. -/
lemma deleteFanLists_fan (M : CombMap D) (d0 : D)
    (fanInterior : Finset M.Vertex) (L : M.Vertex → Finset α) (γ δ : α)
    {q' : (M.deleteVertex d0).Vertex}
    (hq : deletedVertexToM M d0 q' ∈ fanInterior) :
    deleteFanLists M d0 fanInterior L γ δ q' =
      (L (deletedVertexToM M d0 q')) \ {γ, δ} := by
  simp [deleteFanLists, hq]

/-- Off the fan vertices the deleted list is just `L`. -/
lemma deleteFanLists_other (M : CombMap D) (d0 : D)
    (fanInterior : Finset M.Vertex) (L : M.Vertex → Finset α) (γ δ : α)
    {q' : (M.deleteVertex d0).Vertex}
    (hq : deletedVertexToM M d0 q' ∉ fanInterior) :
    deleteFanLists M d0 fanInterior L γ δ q' = L (deletedVertexToM M d0 q') := by
  simp [deleteFanLists, hq]

/-- **Fan vertices keep a list of size at least three.**  An interior fan vertex
was interior (non-boundary) in `M`, hence had list size `≥ 5`; removing the two
reserved colors leaves `≥ 3`.  This is the exact size accounting of the review. -/
lemma deleteFanLists_card_ge_three (M : CombMap D) (d0 : D)
    (fanInterior : Finset M.Vertex) (L : M.Vertex → Finset α) {γ δ : α}
    {q' : (M.deleteVertex d0).Vertex}
    (hq : deletedVertexToM M d0 q' ∈ fanInterior)
    (h5 : 5 ≤ (L (deletedVertexToM M d0 q')).card) :
    3 ≤ (deleteFanLists M d0 fanInterior L γ δ q').card := by
  classical
  rw [deleteFanLists_fan M d0 fanInterior L γ δ hq]
  have hle : ((L (deletedVertexToM M d0 q')) \ {γ, δ}).card ≥
      (L (deletedVertexToM M d0 q')).card - ({γ, δ} : Finset α).card := by
    have := Finset.le_card_sdiff ({γ, δ} : Finset α) (L (deletedVertexToM M d0 q'))
    omega
  have hcard2 : ({γ, δ} : Finset α).card ≤ 2 := Finset.card_insert_le _ _ |>.trans
    (by simp)
  omega



/-- The kept-dart bijection onto `{Q // Q ≠ ⟦d0⟧}`, packaged as an `Equiv`. -/
noncomputable def deletedVertexEquiv
    (R : NearTriangulation.FanSurgeryReconstruction hNT d0) :
    (M.deleteVertex d0).Vertex ≃
      {Q : M.Vertex // Q ≠ Quotient.mk (cycleSetoid M.σ) d0} :=
  Equiv.ofBijective _ (deletedVertexToM'_bijective R)

/-- The section `Vertex M → Vertex(deleted)` for vertices other than `v0`. -/
noncomputable def sectionToDeleted
    (R : NearTriangulation.FanSurgeryReconstruction hNT d0)
    (x : M.Vertex) (hx : x ≠ Quotient.mk (cycleSetoid M.σ) d0) :
    (M.deleteVertex d0).Vertex :=
  (deletedVertexEquiv R).symm ⟨x, hx⟩

@[simp]
lemma deletedVertexToM_sectionToDeleted
    (R : NearTriangulation.FanSurgeryReconstruction hNT d0)
    (x : M.Vertex) (hx : x ≠ Quotient.mk (cycleSetoid M.σ) d0) :
    deletedVertexToM M d0 (sectionToDeleted R x hx) = x := by
  have := (deletedVertexEquiv R).apply_symm_apply ⟨x, hx⟩
  have h2 : deletedVertexToM' M d0 ((deletedVertexEquiv R).symm ⟨x, hx⟩) = ⟨x, hx⟩ := this
  exact congrArg Subtype.val h2

/-- The full extended coloring of `M`: at `v0` use the chosen color `a`, elsewhere
use the deleted-map coloring through the kept-dart section. -/
noncomputable def extendColoring
    (R : NearTriangulation.FanSurgeryReconstruction hNT d0)
    (c : (M.deleteVertex d0).Vertex → α) (a : α) : M.Vertex → α :=
  fun x =>
    if hx : x = Quotient.mk (cycleSetoid M.σ) d0 then a
    else c (sectionToDeleted R x hx)





















end Deletion

end CombMap

end ProofsInTheBook.ThomassenLists

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFanSurgery
-/
/- Source module: ProofsInTheBook.PlanarMapFanConnectivity -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



/-- An `α`-step between survivors lifts to the deleted map: if `x` survives then
so does `M.α x.1`, and `(deleteVertex).α x = ⟨M.α x.1, _⟩`. -/
lemma deleteVertex_dartStep_of_alpha (M : CombMap D) (v : D)
    (x : {d : D // d ∉ M.deleteVertexSet v})
    (y : {d : D // d ∉ M.deleteVertexSet v}) (h : y.1 = M.α x.1) :
    (M.deleteVertex v).dartStep x y := by
  right
  apply Subtype.ext
  rw [deleteVertex_alpha_apply_coe]
  exact h

/-- A `σ`-step between survivors lifts to the deleted map. -/
lemma deleteVertex_dartStep_of_sigma (M : CombMap D) (v : D)
    (x y : {d : D // d ∉ M.deleteVertexSet v}) (h : M.σ.SameCycle x.1 y.1) :
    (M.deleteVertex v).dartStep x y := by
  left
  exact (deleteVertex_sigma_sameCycle_iff M v x y).2 h

/-- `α` preserves survival: if `d` survives the star deletion of `v`, so does
`M.α d`. -/
lemma alpha_notMem_deleteVertexSet (M : CombMap D) (v : D) {d : D}
    (hd : d ∉ M.deleteVertexSet v) : M.α d ∉ M.deleteVertexSet v := by
  intro h
  exact hd ((M.alpha_mem_deleteVertexSet_iff v d).1 h)


def DeleteVertexNeighborsConnected (M : CombMap D) (v : D) : Prop :=
  ∀ x y : {d : D // d ∉ M.deleteVertexSet v},
    (∃ e ∈ M.deleteVertexSet v, M.σ.SameCycle e x.1) →
    (∃ e ∈ M.deleteVertexSet v, M.σ.SameCycle e y.1) →
    Relation.ReflTransGen (M.deleteVertex v).dartStep x y



/-- The deleted-map step relation is symmetric. -/
lemma deleteVertex_dartStep_symm (M : CombMap D) (v : D)
    {x y : {d : D // d ∉ M.deleteVertexSet v}}
    (h : (M.deleteVertex v).dartStep x y) :
    (M.deleteVertex v).dartStep y x := by
  rcases h with hσ | hα
  · exact Or.inl hσ.symm
  · -- `y = (deleteVertex).α x`, hence `x = (deleteVertex).α y` by involution.
    right
    have := congrArg (M.deleteVertex v).α hα
    rw [(M.deleteVertex v).alpha_alpha] at this
    exact this.symm

/-- The deleted-map reachability relation is symmetric. -/
lemma deleteVertex_reachable_symm (M : CombMap D) (v : D)
    {x y : {d : D // d ∉ M.deleteVertexSet v}}
    (h : Relation.ReflTransGen (M.deleteVertex v).dartStep x y) :
    Relation.ReflTransGen (M.deleteVertex v).dartStep y x := by
  induction h with
  | refl => exact Relation.ReflTransGen.refl
  | tail _ hbc ih =>
      exact Relation.ReflTransGen.head (deleteVertex_dartStep_symm M v hbc) ih



section Reduction

variable (M : CombMap D) (v : D)

/-- Local abbreviation for surviving darts. -/
 abbrev Surv := {d : D // d ∉ M.deleteVertexSet v}

/-- A survivor is a *neighbour-survivor* of `v` if its vertex `σ`-orbit contains a
deleted dart (so its vertex is adjacent to `v`). -/
 def IsNbr (a : Surv M v) : Prop :=
  ∃ e ∈ M.deleteVertexSet v, M.σ.SameCycle e a.1

/-- The connectivity reduction: from `M`-connectivity and the fan-geometric
neighbour-reconnection predicate, the deleted map is connected. -/
theorem deleteVertex_connected_of_neighborsConnected
    (hconn : M.Connected)
    (hnbr : M.DeleteVertexNeighborsConnected v) :
    (M.deleteVertex v).Connected := by
  classical
  set S := M.deleteVertexSet v with hS
  -- It suffices to connect every survivor to a fixed base survivor `r`.
  intro x y
  set Rel : Surv M v → Surv M v → Prop :=
    fun a b => Relation.ReflTransGen (M.deleteVertex v).dartStep a b with hRel
  -- Abbreviation: every neighbour-survivor reaches the base.
  -- The backward-induction invariant on darts of `M`.
  set AllNbrReach : Surv M v → Prop :=
    fun r => ∀ a : Surv M v, IsNbr M v a → Rel a r with hAllNbr
  set Inv : Surv M v → D → Prop :=
    fun r c =>
      (∀ h : c ∉ S, Rel ⟨c, h⟩ r) ∧ (c ∈ S → AllNbrReach r) with hInv
  -- The key: every survivor reaches every base survivor `r`.
  have key : ∀ r : Surv M v, ∀ a : Surv M v, Rel a r := by
    intro r
    -- Base of the induction: `Inv r r.1`.
    have hbase : Inv r r.1 := by
      refine ⟨?_, ?_⟩
      · intro h
        have heq : (⟨r.1, h⟩ : Surv M v) = r := Subtype.ext rfl
        rw [heq]
      · intro hr
        exact absurd hr r.2
    -- Backward closure of `Inv` along `M.dartStep`.
    have hstep : ∀ c c' : D, M.dartStep c c' → Inv r c' → Inv r c := by
      intro c c' hcc' hc'
      refine ⟨?_, ?_⟩
      · -- alive case
        intro hc
        rcases hcc' with hσ | hα
        · -- σ-step `c → c'`
          by_cases hc'S : c' ∈ S
          · -- c' deleted: `⟨c,hc⟩` is a neighbour-survivor, use `Inv c'`'s nbr-clause.
            have hnbr_c : IsNbr M v ⟨c, hc⟩ := ⟨c', hc'S, hσ.symm⟩
            exact hc'.2 hc'S ⟨c, hc⟩ hnbr_c
          · -- c' alive: σ-step lifts, then `Inv c'`.
            have hreach : Rel ⟨c', hc'S⟩ r := hc'.1 hc'S
            have hd : (M.deleteVertex v).dartStep ⟨c, hc⟩ ⟨c', hc'S⟩ :=
              deleteVertex_dartStep_of_sigma M v ⟨c, hc⟩ ⟨c', hc'S⟩ hσ
            exact Relation.ReflTransGen.head hd hreach
        · -- α-step `c' = α c`; α preserves survival.
          have hc'S : c' ∉ S := by
            rw [hα]; exact alpha_notMem_deleteVertexSet M v hc
          have hreach : Rel ⟨c', hc'S⟩ r := hc'.1 hc'S
          have hd : (M.deleteVertex v).dartStep ⟨c, hc⟩ ⟨c', hc'S⟩ :=
            deleteVertex_dartStep_of_alpha M v ⟨c, hc⟩ ⟨c', hc'S⟩ hα
          exact Relation.ReflTransGen.head hd hreach
      · -- deleted case: maintain `AllNbrReach`.
        intro hcS
        rcases hcc' with hσ | hα
        · by_cases hc'S : c' ∈ S
          · exact hc'.2 hc'S
          · -- c' alive and is itself a neighbour-survivor; bridge all neighbours via `hnbr`.
            intro a ha
            have hreach_c' : Rel ⟨c', hc'S⟩ r := hc'.1 hc'S
            have hnbr_c' : IsNbr M v ⟨c', hc'S⟩ := ⟨c, hcS, hσ⟩
            have hbridge :
                Relation.ReflTransGen (M.deleteVertex v).dartStep a ⟨c', hc'S⟩ :=
              hnbr a ⟨c', hc'S⟩ ha hnbr_c'
            exact hbridge.trans hreach_c'
        · -- α-step `c' = α c`; `c' ∈ S` since `c ∈ S`.
          have hc'S : c' ∈ S := by
            rw [hα]
            exact (M.alpha_mem_deleteVertexSet_iff v c).2 hcS
          exact hc'.2 hc'S
    -- Run the backward induction over an `M`-walk from `a` to `r`.
    intro a
    have hwalk : Relation.ReflTransGen M.dartStep a.1 r.1 := hconn a.1 r.1
    have hInva : Inv r a.1 :=
      Relation.ReflTransGen.head_induction_on hwalk hbase
        (fun {b c} hbc _ ih => hstep b c hbc ih)
    have hfin : Rel (⟨a.1, a.2⟩ : Surv M v) r := hInva.1 a.2
    have heq : (⟨a.1, a.2⟩ : Surv M v) = a := Subtype.ext rfl
    rwa [heq] at hfin
  -- Conclude: every survivor reaches every base survivor, so `x` reaches `y`.
  exact key y x

end Reduction



namespace NearTriangulation

variable {M : CombMap D}

/-- A dart survives the star deletion of `v` iff neither it nor its reverse lies
in the `σ`-orbit of `v`. -/
 lemma notMem_deleteVertexSet_iff (v d : D) :
    d ∉ M.deleteVertexSet v ↔
      ¬ M.σ.SameCycle v d ∧ ¬ M.σ.SameCycle v (M.α d) := by
  rw [mem_deleteVertexSet_iff]
  simp only [mem_vertexDarts, not_or]

/-- A dart whose tail and head are both different from the vertex of `v` (as
`σ`-orbits) survives the star deletion. -/
 lemma notMem_deleteVertexSet_of_tail_head_ne {v d : D}
    (htail : M.tail d ≠ M.tail v) (hhead : M.head d ≠ M.tail v) :
    d ∉ M.deleteVertexSet v := by
  rw [notMem_deleteVertexSet_iff]
  refine ⟨?_, ?_⟩
  · intro h
    exact htail (Quotient.sound h).symm
  · intro h
    exact hhead (Quotient.sound h).symm

/-- One deleted-map reachability step from a `σ`-cycle relation between
survivors. -/
 lemma rel_of_sigma {v : D} (x y : {d : D // d ∉ M.deleteVertexSet v})
    (h : M.σ.SameCycle x.1 y.1) :
    Relation.ReflTransGen (M.deleteVertex v).dartStep x y :=
  Relation.ReflTransGen.single (deleteVertex_dartStep_of_sigma M v x y h)

/-- One deleted-map reachability step from `y = M.α x` between survivors. -/
 lemma rel_of_alpha {v : D} (x y : {d : D // d ∉ M.deleteVertexSet v})
    (h : y.1 = M.α x.1) :
    Relation.ReflTransGen (M.deleteVertex v).dartStep x y :=
  Relation.ReflTransGen.single (deleteVertex_dartStep_of_alpha M v x y h)

variable {hNT : NearTriangulation M} {v0 : M.Vertex}

/-- The "edge dart" of a fan triangle `(v0, a, b)`: its middle dart `d1` has tail
`a` and head `b`, and survives the deletion of any dart `d0` representing `v0`. -/
 lemma fanTriangle_edge_dart_survives_p2m_6755d2cf6bd3 {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0) :
    T.d1 ∉ M.deleteVertexSet d0 := by
  have hdist := T.vertices_pairwiseDistinct
  -- tail T.d1 = a ≠ v0 = tail d0
  have htail : M.tail T.d1 ≠ M.tail d0 := by
    rw [T.tail1, htail0]
    exact (hdist.1).symm
  -- head T.d1 = b ≠ v0 = tail d0
  have hhead_eq : M.head T.d1 = b := by
    have hphi : M.φ T.d1 = T.d2 := T.triangle.2.1
    have hh : M.head T.d1 = M.tail T.d2 := by
      rw [← tail_phi, hphi]
    rw [hh, T.tail2]
  have hhead : M.head T.d1 ≠ M.tail d0 := by
    rw [hhead_eq, htail0]
    exact hdist.2.2
  exact notMem_deleteVertexSet_of_tail_head_ne htail hhead

/-- For a fan triangle `(v0, a, b)`, any surviving dart whose vertex is `a` is
deleted-map connected to any surviving dart whose vertex is `b`, via the
surviving triangle edge `a—b`. -/
 lemma fanTriangle_connects {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0)
    (p q : {d : D // d ∉ M.deleteVertexSet d0})
    (hp : M.tail p.1 = a) (hq : M.tail q.1 = b) :
    Relation.ReflTransGen (M.deleteVertex d0).dartStep p q := by
  -- The surviving edge dart `T.d1` (tail a, head b) and its reverse.
  have hd1 : T.d1 ∉ M.deleteVertexSet d0 :=
    fanTriangle_edge_dart_survives_p2m_6755d2cf6bd3 T htail0
  have hd1' : M.α T.d1 ∉ M.deleteVertexSet d0 :=
    alpha_notMem_deleteVertexSet M d0 hd1
  set e1 : {d : D // d ∉ M.deleteVertexSet d0} := ⟨T.d1, hd1⟩ with he1
  set e1' : {d : D // d ∉ M.deleteVertexSet d0} := ⟨M.α T.d1, hd1'⟩ with he1'
  -- p ↝ e1 (same vertex a)
  have hpe1 : M.σ.SameCycle p.1 T.d1 :=
    Quotient.exact (show M.tail p.1 = M.tail T.d1 by rw [hp, T.tail1])
  have step1 : Relation.ReflTransGen (M.deleteVertex d0).dartStep p e1 :=
    rel_of_sigma p e1 hpe1
  -- e1 ↝ e1' (edge step)
  have step2 : Relation.ReflTransGen (M.deleteVertex d0).dartStep e1 e1' :=
    rel_of_alpha e1 e1' rfl
  -- e1' ↝ q (same vertex b: tail (α T.d1) = head T.d1 = b)
  have hhead_eq : M.head T.d1 = b := by
    have hphi : M.φ T.d1 = T.d2 := T.triangle.2.1
    have hh : M.head T.d1 = M.tail T.d2 := by rw [← tail_phi, hphi]
    rw [hh, T.tail2]
  have he1'q : M.σ.SameCycle (M.α T.d1) q.1 :=
    Quotient.exact (show M.tail (M.α T.d1) = M.tail q.1 by rw [tail_alpha, hhead_eq, hq])
  have step3 : Relation.ReflTransGen (M.deleteVertex d0).dartStep e1' q :=
    rel_of_sigma e1' q he1'q
  exact (step1.trans step2).trans step3

/-- `consecutivePairs` of a two-or-more element list. -/
 lemma consecutivePairs_cons_cons_p2m_6755d2cf6bd3 {α : Type*} (a b : α) (l : List α) :
    consecutivePairs (a :: b :: l) = (a, b) :: consecutivePairs (b :: l) := by
  simp [consecutivePairs]

/-- Symmetric "all survivors at `a` connect to all survivors at `b`" relation. -/
 def VConn {d0 : D} (a b : M.Vertex) : Prop :=
  ∀ p q : {d : D // d ∉ M.deleteVertexSet d0},
    M.tail p.1 = a → M.tail q.1 = b →
    Relation.ReflTransGen (M.deleteVertex d0).dartStep p q

 lemma VConn.symm {d0 : D} {a b : M.Vertex} (h : VConn (M := M) (d0 := d0) a b) :
    VConn (M := M) (d0 := d0) b a := by
  intro p q hp hq
  exact deleteVertex_reachable_symm M d0 (h q p hq hp)

/-- A `FanTriangle` provides `VConn` between its two non-`v0` vertices, and a
surviving witness dart at each. -/
 lemma fanTriangle_vconn {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0) :
    VConn (M := M) (d0 := d0) a b :=
  fun p q hp hq => fanTriangle_connects T htail0 p q hp hq

/-- A `FanTriangle` provides a surviving dart whose vertex is its second
non-`v0` vertex `b` (the reverse `α T.d1` of the surviving edge dart). -/
 lemma fanTriangle_witness_snd_p2m_6755d2cf6bd3 {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0) :
    ∃ p : {d : D // d ∉ M.deleteVertexSet d0}, M.tail p.1 = b := by
  have hd1 : T.d1 ∉ M.deleteVertexSet d0 := fanTriangle_edge_dart_survives_p2m_6755d2cf6bd3 T htail0
  have hd1' : M.α T.d1 ∉ M.deleteVertexSet d0 := alpha_notMem_deleteVertexSet M d0 hd1
  refine ⟨⟨M.α T.d1, hd1'⟩, ?_⟩
  have hphi : M.φ T.d1 = T.d2 := T.triangle.2.1
  have hh : M.head T.d1 = M.tail T.d2 := by rw [← tail_phi, hphi]
  show M.tail (M.α T.d1) = b
  rw [tail_alpha, hh, T.tail2]

/-- A `FanTriangle` provides a surviving dart whose vertex is its first non-`v0`
vertex `a` (the surviving edge dart `T.d1` itself, tail `a`). -/
 lemma fanTriangle_witness_fst_p2m_6755d2cf6bd3 {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0) :
    ∃ p : {d : D // d ∉ M.deleteVertexSet d0}, M.tail p.1 = a :=
  ⟨⟨T.d1, fanTriangle_edge_dart_survives_p2m_6755d2cf6bd3 T htail0⟩, T.tail1⟩

/-- Chaining: if consecutive pairs of a list `L` (with at least the head vertex
present) all carry fan triangles in the **σ-predecessor** orientation
(`(a, b) ↦ FanTriangle v0 b a`, the fixed `triangle_of_pair` convention), then every
vertex of `L` is `VConn` to the head of `L`.  Proved by induction maintaining a
surviving witness at the head; `VConn` is symmetric so the orientation is immaterial. -/
 lemma vconn_head_of_pairs {d0 : D} (htail0 : M.tail d0 = v0) :
    ∀ (L : List M.Vertex) (hd : M.Vertex),
      (∀ a b : M.Vertex, (a, b) ∈ consecutivePairs (hd :: L) →
        FanTriangle hNT v0 b a) →
      ∀ u : M.Vertex, u ∈ (hd :: L) → VConn (M := M) (d0 := d0) u hd := by
  intro L
  induction L with
  | nil =>
      intro hd _ u hu
      have hueq : u = hd := by simpa using hu
      subst hueq
      intro p q hp hq
      exact rel_of_sigma p q
        (Quotient.exact (show M.tail p.1 = M.tail q.1 by rw [hp, hq]))
  | cons b l ih =>
      intro hd htri u hu
      -- The first pair `(hd, b)` carries a (predecessor-oriented) fan triangle.
      have hpair0 : (hd, b) ∈ consecutivePairs (hd :: b :: l) := by
        rw [consecutivePairs_cons_cons_p2m_6755d2cf6bd3]; exact List.mem_cons.mpr (Or.inl rfl)
      have T0 : FanTriangle hNT v0 b hd := htri hd b hpair0
      have hVhd_b : VConn (M := M) (d0 := d0) hd b := (fanTriangle_vconn T0 htail0).symm
      -- triangles for the tail list `b :: l`.
      have htri' : ∀ a c : M.Vertex, (a, c) ∈ consecutivePairs (b :: l) →
          FanTriangle hNT v0 c a := by
        intro a c hac
        apply htri a c
        rw [consecutivePairs_cons_cons_p2m_6755d2cf6bd3]
        exact List.mem_cons.mpr (Or.inr hac)
      have ihrun := ih b htri'
      rcases List.mem_cons.mp hu with hueq | hurest
      · -- u = hd: reflexive `VConn`.
        subst hueq
        intro p q hp hq
        exact rel_of_sigma p q
          (Quotient.exact (show M.tail p.1 = M.tail q.1 by rw [hp, hq]))
      · -- u ∈ b :: l: connect u → b (by IH) then b → hd (by T0).
        have hVu_b : VConn (M := M) (d0 := d0) u b := ihrun u hurest
        intro p q hp hq
        -- need a witness at `b` (the first label of the swapped triangle `T0`).
        obtain ⟨m, hm⟩ : ∃ m : {d : D // d ∉ M.deleteVertexSet d0}, M.tail m.1 = b :=
          fanTriangle_witness_fst_p2m_6755d2cf6bd3 T0 htail0
        have h1 : Relation.ReflTransGen (M.deleteVertex d0).dartStep p m :=
          hVu_b p m hp hm
        have h2 : Relation.ReflTransGen (M.deleteVertex d0).dartStep m q :=
          (hVhd_b.symm) m q hm hq
        exact h1.trans h2

/-- The vertex of a neighbour-survivor of `v0` lies on the fan path. -/
 lemma neighbor_tail_mem_path (fan : BoundaryVertexFan hNT v0) {d0 : D}
    (htail0 : M.tail d0 = v0) {x : {d : D // d ∉ M.deleteVertexSet d0}}
    (hx : ∃ e ∈ M.deleteVertexSet d0, M.σ.SameCycle e x.1) :
    M.tail x.1 ∈ fan.path := by
  obtain ⟨e, heS, hex⟩ := hx
  -- `e ∈ vertexDarts d0` would force `x` into the deleted star.
  rw [mem_deleteVertexSet_iff] at heS
  rcases heS with he | hαe
  · exfalso
    rw [mem_vertexDarts] at he
    -- tail x = v0 ⟹ x deleted
    have : M.σ.SameCycle d0 x.1 := he.trans hex
    exact x.2 ((mem_deleteVertexSet_iff M d0 x.1).2 (Or.inl ((mem_vertexDarts M d0 x.1).2 this)))
  · -- `α e` is a rotation dart; its head is a neighbour, equal to `tail x`.
    rw [mem_vertexDarts] at hαe
    have hαe_mem : M.α e ∈ fan.rotation_order.darts := by
      have heq : M.vertexDarts d0 = fan.rotation_order.darts.toFinset :=
        fan.rotation_order.vertexDarts_eq htail0
      have : M.α e ∈ M.vertexDarts d0 := (mem_vertexDarts M d0 (M.α e)).2 hαe
      rw [heq, List.mem_toFinset] at this
      exact this
    -- tail x = tail e = head (α e)
    have htx : M.tail x.1 = M.head (M.α e) := by
      have h1 : M.tail x.1 = M.tail e := (Quotient.sound hex).symm
      rw [h1, head_alpha]
    -- head (α e) ∈ neighbors = fan.path
    have hmem : M.head (M.α e) ∈ fan.rotation_order.darts.map M.head :=
      List.mem_map_of_mem hαe_mem
    rw [fan.rotation_order.heads_eq] at hmem
    rw [htx, BoundaryVertexFan.path]
    exact hmem

/-- **The fan discharges `DeleteVertexNeighborsConnected`.**  Given a boundary
fan at `v0` and any dart `d0` representing `v0`, the neighbour-survivors of `v0`
are reconnected in the deleted map via the fan path. -/
theorem deleteVertex_neighborsConnected_of_fan (fan : BoundaryVertexFan hNT v0)
    {d0 : D} (htail0 : M.tail d0 = v0) :
    M.DeleteVertexNeighborsConnected d0 := by
  -- Every neighbour-survivor is `VConn` to the fan head `fan.x`.
  set L : List M.Vertex := fan.interior ++ [fan.w] with hL
  have hpath : fan.path = fan.x :: L := by
    rw [BoundaryVertexFan.path, fanPath, hL, List.cons_append]
  have htri : ∀ a b : M.Vertex,
      (a, b) ∈ consecutivePairs (fan.x :: L) → FanTriangle hNT v0 b a := by
    intro a b hab
    have hab' : (a, b) ∈ consecutivePairs fan.path := by rw [hpath]; exact hab
    exact fan.incident_faces_exact.triangle_of_pair (by
      simpa [BoundaryVertexFan.path] using hab')
  have hhead : ∀ u : M.Vertex, u ∈ fan.path →
      VConn (M := M) (d0 := d0) u fan.x := by
    intro u hu
    have hu' : u ∈ fan.x :: L := by rw [← hpath]; exact hu
    exact vconn_head_of_pairs htail0 L fan.x htri u hu'
  -- Assemble: two neighbour-survivors both connect to `fan.x`.
  intro x y hx hy
  have hxpath : M.tail x.1 ∈ fan.path := neighbor_tail_mem_path fan htail0 hx
  have hypath : M.tail y.1 ∈ fan.path := neighbor_tail_mem_path fan htail0 hy
  have hVx : VConn (M := M) (d0 := d0) (M.tail x.1) fan.x := hhead _ hxpath
  have hVy : VConn (M := M) (d0 := d0) (M.tail y.1) fan.x := hhead _ hypath
  -- a witness survivor at `fan.x`: the pair `(fan.x, _)` triangle, if it exists,
  -- else `x` itself routes through.  We use the head triangle witness.
  -- Connect x → fan.x → y.
  -- Need a witness at fan.x.  `fan.x` is the head of the path of length ≥ 2.
  obtain ⟨b, _l, hLb⟩ : ∃ b l', L = b :: l' := by
    rw [hL]
    cases fan.interior with
    | nil => exact ⟨fan.w, [], rfl⟩
    | cons c t => exact ⟨c, t ++ [fan.w], rfl⟩
  have hpair0 : (fan.x, b) ∈ consecutivePairs (fan.x :: L) := by
    rw [hLb, consecutivePairs_cons_cons_p2m_6755d2cf6bd3]; exact List.mem_cons.mpr (Or.inl rfl)
  have T0 : FanTriangle hNT v0 b fan.x := htri fan.x b hpair0
  obtain ⟨m, hm⟩ : ∃ m : {d : D // d ∉ M.deleteVertexSet d0}, M.tail m.1 = fan.x :=
    fanTriangle_witness_snd_p2m_6755d2cf6bd3 T0 htail0
  have h1 : Relation.ReflTransGen (M.deleteVertex d0).dartStep x m :=
    hVx x m rfl hm
  have h2 : Relation.ReflTransGen (M.deleteVertex d0).dartStep m y :=
    (hVy.symm) m y hm rfl
  exact h1.trans h2

/-- **The deleted map is connected (fan form).**  Deleting the closed star of a
boundary vertex `v0` of a near-triangulation, where `d0` is a dart representing
`v0` and `fan` is a boundary fan at `v0`, leaves a connected combinatorial map.
The two boundary neighbours of `v0` and all interior fan vertices stay joined
through the surviving fan path `x, z₁, …, z_t, w`.

This discharges the `connected` field of `FanSurgeryReconstruction`
unconditionally from the fan and the near-triangulation invariant. -/
theorem deleteVertex_connected_of_fan (fan : BoundaryVertexFan hNT v0) {d0 : D}
    (htail0 : M.tail d0 = v0) :
    (M.deleteVertex d0).Connected :=
  deleteVertex_connected_of_neighborsConnected M d0 hNT.sphere.1
    (deleteVertex_neighborsConnected_of_fan fan htail0)

end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFanConnectivity
import ProofsInTheBook.PlanarMapFilteredRotation
-/
/- Source module: ProofsInTheBook.PlanarMapFanFaces -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



@[simp]
lemma deleteVertex_phi_apply_coe (M : CombMap D) (v : D)
    (x : {d : D // d ∉ M.deleteVertexSet v}) :
    ((M.deleteVertex v).φ x : D) =
      (M.σ ^ Equiv.Perm.DeleteSet.firstOutside M.σ (M.deleteVertexSet v)
        (M.alphaDeleteVertex v x)) (M.α x.1) := by
  show ((M.deleteVertex v).σ ((M.deleteVertex v).α x) : D) = _
  rw [show (M.deleteVertex v).σ = M.σ.deleteSet (M.deleteVertexSet v) from rfl]
  rw [Equiv.Perm.deleteSet_apply_coe]
  rfl

/-- **`φ` agrees with `M.φ` when the next dart survives.**  If `x` survives and
`M.φ x.1 = M.σ (M.α x.1)` again survives, then the deleted map's `φ`-successor of
`x` is exactly `M.φ x.1`. -/
lemma deleteVertex_phi_apply_of_next_kept (M : CombMap D) (v : D)
    (x : {d : D // d ∉ M.deleteVertexSet v})
    (hkept : M.φ x.1 ∉ M.deleteVertexSet v) :
    ((M.deleteVertex v).φ x : D) = M.φ x.1 := by
  have hαx : M.α x.1 ∉ M.deleteVertexSet v := alpha_notMem_deleteVertexSet M v x.2
  -- The filtered rotation from `α x.1` takes exactly one σ-step, landing on `M.φ x.1`.
  set y : {d : D // d ∉ M.deleteVertexSet v} := M.alphaDeleteVertex v x with hy
  have hycoe : (y : D) = M.α x.1 := by rw [hy]; exact alphaDeleteVertex_apply_coe M v x
  have hnext : M.σ (y : D) ∉ M.deleteVertexSet v := by
    rw [hycoe]; exact hkept
  have hone : Equiv.Perm.DeleteSet.firstOutside M.σ (M.deleteVertexSet v) y = 1 :=
    FilteredRotation.firstOutside_eq_one_of_next_notMem
      M.σ (M.deleteVertexSet v) y hnext
  rw [deleteVertex_phi_apply_coe]
  rw [show (M.alphaDeleteVertex v x) = y from rfl, hone, pow_one]
  rfl

namespace NearTriangulation

variable {M : CombMap D} {hNT : NearTriangulation M} {v0 : M.Vertex}



/-- `consecutivePairs` of a two-or-more element list. -/
 lemma consecutivePairs_cons_cons_p2m_e7d236328e37 {α : Type*} (a b : α) (l : List α) :
    consecutivePairs (a :: b :: l) = (a, b) :: consecutivePairs (b :: l) := by
  simp [consecutivePairs]

/-- The middle edge dart `d1` of a fan triangle survives the deletion of any dart
`d0` representing `v0`. -/
 lemma fanTriangle_edge_dart_survives_p2m_e7d236328e37 {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0) :
    T.d1 ∉ M.deleteVertexSet d0 := by
  have hdist := T.vertices_pairwiseDistinct
  have htail : M.tail T.d1 ≠ M.tail d0 := by
    rw [T.tail1, htail0]; exact (hdist.1).symm
  have hhead_eq : M.head T.d1 = b := by
    have hphi : M.φ T.d1 = T.d2 := T.triangle.2.1
    have hh : M.head T.d1 = M.tail T.d2 := by rw [← tail_phi, hphi]
    rw [hh, T.tail2]
  have hhead : M.head T.d1 ≠ M.tail d0 := by
    rw [hhead_eq, htail0]; exact hdist.2.2
  rw [mem_deleteVertexSet_iff]
  push_neg
  rw [mem_vertexDarts, mem_vertexDarts]
  refine ⟨fun h => ?_, fun h => ?_⟩
  · -- `M.σ.SameCycle d0 T.d1` would give `tail d0 = tail T.d1`.
    exact htail (Quotient.sound h).symm
  · -- `M.σ.SameCycle d0 (α T.d1)` gives `tail d0 = tail (α T.d1) = head T.d1`.
    have : M.tail d0 = M.head T.d1 := Quotient.sound h
    exact hhead this.symm

/-- A fan triangle provides a surviving dart whose tail is its second non-`v0`
vertex `b` (the reverse `α T.d1` of the surviving edge dart). -/
 lemma fanTriangle_witness_snd_p2m_e7d236328e37 {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0) :
    ∃ p : {d : D // d ∉ M.deleteVertexSet d0}, M.tail p.1 = b := by
  have hd1 : T.d1 ∉ M.deleteVertexSet d0 := fanTriangle_edge_dart_survives_p2m_e7d236328e37 T htail0
  have hd1' : M.α T.d1 ∉ M.deleteVertexSet d0 := alpha_notMem_deleteVertexSet M d0 hd1
  refine ⟨⟨M.α T.d1, hd1'⟩, ?_⟩
  have hphi : M.φ T.d1 = T.d2 := T.triangle.2.1
  have hh : M.head T.d1 = M.tail T.d2 := by rw [← tail_phi, hphi]
  show M.tail (M.α T.d1) = b
  rw [tail_alpha, hh, T.tail2]

/-- A fan triangle provides a surviving dart whose tail is its first non-`v0`
vertex `a` (the surviving edge dart `T.d1` itself, tail `a`). -/
 lemma fanTriangle_witness_fst_p2m_e7d236328e37 {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0) :
    ∃ p : {d : D // d ∉ M.deleteVertexSet d0}, M.tail p.1 = a :=
  ⟨⟨T.d1, fanTriangle_edge_dart_survives_p2m_e7d236328e37 T htail0⟩, T.tail1⟩

/-- Every vertex on the fan path carries a surviving dart whose tail is that
vertex. -/
lemma fan_path_vertex_has_survivor (fan : BoundaryVertexFan hNT v0) {d0 : D}
    (htail0 : M.tail d0 = v0) {u : M.Vertex} (hu : u ∈ fan.path) :
    ∃ p : {d : D // d ∉ M.deleteVertexSet d0}, M.tail p.1 = u := by
  -- Set up the path as `fan.x :: L`.
  set L : List M.Vertex := fan.interior ++ [fan.w] with hL
  have hpath : fan.path = fan.x :: L := by
    rw [BoundaryVertexFan.path, fanPath, hL, List.cons_append]
  -- Predecessor convention: a forward pair `(a, b)` carries `FanTriangle v0 b a`.
  have htri : ∀ a b : M.Vertex,
      (a, b) ∈ consecutivePairs (fan.x :: L) → FanTriangle hNT v0 b a := by
    intro a b hab
    have hab' : (a, b) ∈ consecutivePairs fan.path := by rw [hpath]; exact hab
    exact fan.incident_faces_exact.triangle_of_pair (by
      simpa [BoundaryVertexFan.path] using hab')
  -- `L` is nonempty: `L = b :: l'`.
  obtain ⟨b, l', hLb⟩ : ∃ b l', L = b :: l' := by
    rw [hL]
    cases fan.interior with
    | nil => exact ⟨fan.w, [], rfl⟩
    | cons c t => exact ⟨c, t ++ [fan.w], rfl⟩
  -- The head triangle for pair `(fan.x, b)` is `FanTriangle v0 b fan.x`.
  have hpair0 : (fan.x, b) ∈ consecutivePairs (fan.x :: L) := by
    rw [hLb, consecutivePairs_cons_cons_p2m_e7d236328e37]; exact List.mem_cons.mpr (Or.inl rfl)
  have T0 : FanTriangle hNT v0 b fan.x := htri fan.x b hpair0
  rw [hpath] at hu
  rcases List.mem_cons.mp hu with hux | huL
  · -- `u = fan.x`: `fan.x` is the second label of `T0`, use `α T0.d1`.
    subst hux
    exact fanTriangle_witness_snd_p2m_e7d236328e37 T0 htail0
  · -- `u ∈ L`: `u` is the second component of some forward consecutive pair, i.e.
    -- the first label of its (swapped) triangle; use that triangle's edge dart.
    -- Induct over `L` with the running "previous vertex" being `fan.x`.
    clear hu hpair0 T0 hLb b l'
    -- General statement: for any list `M0` and head `h0` such that all pairs of
    -- `h0 :: M0` carry (swapped) triangles, every member of `M0` has a survivor.
    suffices hgen : ∀ (M0 : List M.Vertex) (h0 : M.Vertex),
        (∀ a b : M.Vertex, (a, b) ∈ consecutivePairs (h0 :: M0) →
          FanTriangle hNT v0 b a) →
        ∀ z : M.Vertex, z ∈ M0 →
          ∃ p : {d : D // d ∉ M.deleteVertexSet d0}, M.tail p.1 = z by
      exact hgen L fan.x htri u huL
    clear htri huL hpath hL
    intro M0
    induction M0 with
    | nil => intro h0 _ z hz; simp at hz
    | cons c t ih =>
        intro h0 htri' z hz
        -- The first pair `(h0, c)` carries the swapped triangle `FanTriangle v0 c h0`;
        -- `c` is its first label, with surviving edge dart at `c`.
        have hpc : (h0, c) ∈ consecutivePairs (h0 :: c :: t) := by
          rw [consecutivePairs_cons_cons_p2m_e7d236328e37]; exact List.mem_cons.mpr (Or.inl rfl)
        have Tc : FanTriangle hNT v0 c h0 := htri' h0 c hpc
        rcases List.mem_cons.mp hz with hzc | hzt
        · subst hzc
          exact fanTriangle_witness_fst_p2m_e7d236328e37 Tc htail0
        · -- recurse on `c :: t`.
          have htri'' : ∀ a b : M.Vertex, (a, b) ∈ consecutivePairs (c :: t) →
              FanTriangle hNT v0 b a := by
            intro a b hab
            apply htri' a b
            rw [consecutivePairs_cons_cons_p2m_e7d236328e37]
            exact List.mem_cons.mpr (Or.inr hab)
          exact ih c htri'' z hzt



/-- Membership of a dart's face in `vertexFaces d0` is exactly: some dart in its
`M.φ`-orbit has tail `v0`. -/
 lemma dartFace_mem_vertexFaces_iff {d0 : D} (htail0 : M.tail d0 = v0)
    (d : D) :
    M.dartFace d ∈ M.vertexFaces d0 ↔
      ∃ k : ℤ, M.tail ((M.φ ^ k) d) = v0 := by
  classical
  constructor
  · intro hmem
    rw [vertexFaces, Finset.mem_image] at hmem
    obtain ⟨e, he, hef⟩ := hmem
    rw [mem_vertexDarts] at he
    -- `e` has tail v0 and same φ-orbit as `d`.
    have hetail : M.tail e = v0 := by
      have : M.tail d0 = M.tail e := Quotient.sound he
      rw [← this, htail0]
    have hsame : M.φ.SameCycle d e := Quotient.exact hef.symm
    obtain ⟨k, hk⟩ := hsame
    exact ⟨k, by rw [hk]; exact hetail⟩
  · rintro ⟨k, hk⟩
    rw [vertexFaces, Finset.mem_image]
    refine ⟨(M.φ ^ k) d, ?_, ?_⟩
    · rw [mem_vertexDarts]
      exact Quotient.exact (show M.tail d0 = M.tail ((M.φ ^ k) d) by rw [htail0, hk])
    · exact Quotient.sound (⟨-k, by simp⟩ : M.φ.SameCycle ((M.φ ^ k) d) d)

/-- If `d`'s face is not incident with `v0`, then `d` survives the deletion. -/
 lemma survives_of_dartFace_notMem {d0 : D} (htail0 : M.tail d0 = v0)
    {d : D} (hf : M.dartFace d ∉ M.vertexFaces d0) :
    d ∉ M.deleteVertexSet d0 := by
  rw [mem_deleteVertexSet_iff]
  push_neg
  rw [mem_vertexDarts, mem_vertexDarts]
  refine ⟨fun h => hf ?_, fun h => hf ?_⟩
  · -- `tail d = v0`: take `k = 0`.
    rw [dartFace_mem_vertexFaces_iff htail0]
    refine ⟨0, ?_⟩
    simp only [zpow_zero, Equiv.Perm.coe_one, id_eq]
    have heq : M.tail d0 = M.tail d := Quotient.sound h
    rw [← heq, htail0]
  · -- `tail (α d) = v0` i.e. `head d = v0 = tail (φ d)`: take `k = 1`.
    rw [dartFace_mem_vertexFaces_iff htail0]
    refine ⟨1, ?_⟩
    rw [zpow_one, tail_phi]
    have heq : M.tail d0 = M.tail (M.α d) := Quotient.sound h
    rw [tail_alpha] at heq
    rw [← heq, htail0]

/-- The same, for the `φ`-successor: if `d`'s face avoids `v0`, so does `M.φ d`,
hence `M.φ d` survives. -/
 lemma phi_survives_of_dartFace_notMem {d0 : D} (htail0 : M.tail d0 = v0)
    {d : D} (hf : M.dartFace d ∉ M.vertexFaces d0) :
    M.φ d ∉ M.deleteVertexSet d0 := by
  apply survives_of_dartFace_notMem htail0
  -- `M.φ d` has the same face as `d`.
  have hface : M.dartFace (M.φ d) = M.dartFace d :=
    Quotient.sound (⟨-1, by simp⟩ : M.φ.SameCycle (M.φ d) d)
  rw [hface]; exact hf

/-- On a clean dart, the deleted `φ` agrees with `M.φ`, and the result is again
clean. -/
 lemma deleteVertex_phi_clean_step {d0 : D} (htail0 : M.tail d0 = v0)
    (x : {d : D // d ∉ M.deleteVertexSet d0})
    (hf : M.dartFace x.1 ∉ M.vertexFaces d0) :
    ((M.deleteVertex d0).φ x : D) = M.φ x.1 ∧
      M.dartFace ((M.deleteVertex d0).φ x).1 ∉ M.vertexFaces d0 := by
  have hkept : M.φ x.1 ∉ M.deleteVertexSet d0 := phi_survives_of_dartFace_notMem htail0 hf
  have hagree : ((M.deleteVertex d0).φ x : D) = M.φ x.1 :=
    deleteVertex_phi_apply_of_next_kept M d0 x hkept
  refine ⟨hagree, ?_⟩
  rw [hagree]
  -- same face as `x`
  have hface : M.dartFace (M.φ x.1) = M.dartFace x.1 :=
    Quotient.sound (⟨-1, by simp⟩ : M.φ.SameCycle (M.φ x.1) x.1)
  rw [hface]; exact hf

/-- Iterating the clean step: for a clean dart `x`, the `k`-th deleted-`φ`
iterate has underlying dart `(M.φ ^ k) x.1`, and stays clean. -/
 lemma deleteVertex_phi_clean_iterate {d0 : D} (htail0 : M.tail d0 = v0)
    (x : {d : D // d ∉ M.deleteVertexSet d0})
    (hf : M.dartFace x.1 ∉ M.vertexFaces d0) (k : ℕ) :
    (((M.deleteVertex d0).φ ^ k) x : D) = (M.φ ^ k) x.1 ∧
      M.dartFace (((M.deleteVertex d0).φ ^ k) x).1 ∉ M.vertexFaces d0 := by
  induction k with
  | zero => exact ⟨rfl, by simpa using hf⟩
  | succ k ih =>
      obtain ⟨hval, hcln⟩ := ih
      have hstep := deleteVertex_phi_clean_step htail0 (((M.deleteVertex d0).φ ^ k) x) hcln
      have hiter1 : ((M.deleteVertex d0).φ ^ (k + 1)) x
          = (M.deleteVertex d0).φ (((M.deleteVertex d0).φ ^ k) x) := by
        rw [pow_succ']; rfl
      constructor
      · rw [hiter1, hstep.1, hval]
        rw [pow_succ']; rfl
      · rw [hiter1]; exact hstep.2

/-- Two clean survivors on the same `M`-face are in the same deleted-`φ` cycle. -/
 lemma deleteVertex_phi_sameCycle_of_clean {d0 : D} (htail0 : M.tail d0 = v0)
    (x y : {d : D // d ∉ M.deleteVertexSet d0})
    (hfx : M.dartFace x.1 ∉ M.vertexFaces d0)
    (hsame : M.dartFace x.1 = M.dartFace y.1) :
    (M.deleteVertex d0).φ.SameCycle x y := by
  have hφsame : M.φ.SameCycle x.1 y.1 := Quotient.exact hsame
  obtain ⟨k, hk⟩ := Equiv.Perm.SameCycle.exists_nat_pow_eq hφsame
  refine ⟨(k : ℤ), ?_⟩
  rw [zpow_natCast]
  apply Subtype.ext
  rw [(deleteVertex_phi_clean_iterate htail0 x hfx k).1, hk]



/-- The finset of clean survivors. -/
 noncomputable def cleanSurvSet (d0 : D) :
    Finset {d : D // d ∉ M.deleteVertexSet d0} :=
  Finset.univ.filter (fun x => M.dartFace x.1 ∉ M.vertexFaces d0)

 lemma mem_cleanSurvSet {d0 : D} (x : {d : D // d ∉ M.deleteVertexSet d0}) :
    x ∈ cleanSurvSet (M := M) d0 ↔ M.dartFace x.1 ∉ M.vertexFaces d0 := by
  simp [cleanSurvSet]

/-- The clean set is invariant under `φ'`: `φ' x` is clean iff `x` is. -/
 lemma cleanSurvSet_phi_invariant {d0 : D} (htail0 : M.tail d0 = v0)
    (x : {d : D // d ∉ M.deleteVertexSet d0}) :
    (M.deleteVertex d0).φ x ∈ cleanSurvSet (M := M) d0 ↔
      x ∈ cleanSurvSet (M := M) d0 := by
  classical
  -- `φ'` maps the clean set into itself.
  have hmaps : ∀ y ∈ cleanSurvSet (M := M) d0,
      (M.deleteVertex d0).φ y ∈ cleanSurvSet (M := M) d0 := by
    intro y hy
    rw [mem_cleanSurvSet] at hy ⊢
    exact (deleteVertex_phi_clean_step htail0 y hy).2
  -- Hence its image equals itself (injective on a finite set).
  have himg : (cleanSurvSet (M := M) d0).image (M.deleteVertex d0).φ
      = cleanSurvSet (M := M) d0 := by
    apply Finset.eq_of_subset_of_card_le
    · intro z hz
      rw [Finset.mem_image] at hz
      obtain ⟨y, hy, hyz⟩ := hz
      rw [← hyz]; exact hmaps y hy
    · rw [Finset.card_image_of_injective _ (M.deleteVertex d0).φ.injective]
  constructor
  · intro hφ
    by_contra hx
    -- `x ∉ clean` but `φ' x ∈ clean = image`, so `x ∈ clean`, contradiction.
    have : (M.deleteVertex d0).φ x ∈ (cleanSurvSet (M := M) d0).image (M.deleteVertex d0).φ := by
      rw [himg]; exact hφ
    rw [Finset.mem_image] at this
    obtain ⟨y, hy, hyx⟩ := this
    have : y = x := (M.deleteVertex d0).φ.injective hyx
    rw [this] at hy; exact hx hy
  · exact hmaps x



/-- A survivor's underlying old `σ`-orbit is never the orbit of `d0`. -/
 lemma survivor_orbit_ne {d0 : D}
    (x : {d : D // d ∉ M.deleteVertexSet d0}) :
    Quotient.mk (cycleSetoid M.σ) x.1 ≠ Quotient.mk (cycleSetoid M.σ) d0 := by
  intro h
  have hsame : M.σ.SameCycle d0 x.1 := (Quotient.exact h).symm
  exact x.2 ((mem_deleteVertexSet_iff M d0 x.1).2
    (Or.inl ((mem_vertexDarts M d0 x.1).2 hsame)))

/-- The forward vertex-quotient map: send a survivor's deleted-`σ`-orbit to its
old `σ`-orbit (which is never `⟦d0⟧`). -/
 noncomputable def vertexQuotientFun (d0 : D) :
    Quotient (cycleSetoid (M.deleteVertex d0).σ) →
      {Q : Quotient (cycleSetoid M.σ) //
        Q ≠ Quotient.mk (cycleSetoid M.σ) d0} :=
  Quotient.lift
    (fun x => ⟨Quotient.mk (cycleSetoid M.σ) x.1, survivor_orbit_ne x⟩)
    (by
      intro x y hxy
      apply Subtype.ext
      have : M.σ.SameCycle x.1 y.1 :=
        (deleteVertex_sigma_sameCycle_iff M d0 x y).1 hxy
      exact Quotient.sound this)

/-- The forward vertex-quotient map is injective. -/
 lemma vertexQuotientFun_injective (d0 : D) :
    Function.Injective (vertexQuotientFun (M := M) d0) := by
  intro a b hab
  obtain ⟨x, rfl⟩ := a.exists_rep
  obtain ⟨y, rfl⟩ := b.exists_rep
  have hval : Quotient.mk (cycleSetoid M.σ) x.1 = Quotient.mk (cycleSetoid M.σ) y.1 := by
    have := congrArg Subtype.val hab
    simpa [vertexQuotientFun] using this
  have hsame : M.σ.SameCycle x.1 y.1 := Quotient.exact hval
  exact Quotient.sound ((deleteVertex_sigma_sameCycle_iff M d0 x y).2 hsame)

/-- The forward vertex-quotient map is surjective, using the fan to guarantee a
surviving dart in every old orbit `≠ ⟦d0⟧`. -/
 lemma vertexQuotientFun_surjective (fan : BoundaryVertexFan hNT v0)
    {d0 : D} (htail0 : M.tail d0 = v0) :
    Function.Surjective (vertexQuotientFun (M := M) d0) := by
  rintro ⟨Q, hQ⟩
  obtain ⟨e, rfl⟩ := Q.exists_rep
  -- Produce a survivor in the σ-orbit of `e`.
  obtain ⟨p, hp⟩ : ∃ p : {d : D // d ∉ M.deleteVertexSet d0},
      M.σ.SameCycle e p.1 := by
    by_cases hes : e ∈ M.deleteVertexSet d0
    · -- `e` is deleted.  It is not in `vertexDarts d0` (else `⟦e⟧ = ⟦d0⟧`),
      -- so its reverse `α e` is, i.e. `head e = v0`; `tail e` is a neighbour.
      rw [mem_deleteVertexSet_iff] at hes
      rcases hes with hev | hαv
      · exfalso
        rw [mem_vertexDarts] at hev
        exact hQ (Quotient.sound hev.symm)
      · -- `α e ∈ vertexDarts d0`: `M.σ.SameCycle d0 (α e)`, so `head e = v0`.
        rw [mem_vertexDarts] at hαv
        have hhead : M.head e = v0 := by
          have : M.tail d0 = M.tail (M.α e) := Quotient.sound hαv
          rw [tail_alpha] at this; rw [← this, htail0]
        -- `tail e` is a neighbour of `v0`; it is on the fan path.
        -- `tail e = head (α e)` and `α e` is in the rotation, so `tail e ∈ heads = path`.
        have hαe_rot : M.α e ∈ fan.rotation_order.darts := by
          have heq : M.vertexDarts d0 = fan.rotation_order.darts.toFinset :=
            fan.rotation_order.vertexDarts_eq htail0
          have hmem : M.α e ∈ M.vertexDarts d0 := (mem_vertexDarts M d0 (M.α e)).2 hαv
          rw [heq, List.mem_toFinset] at hmem; exact hmem
        have htaile_path : M.tail e ∈ fan.path := by
          have hmem : M.head (M.α e) ∈ fan.rotation_order.darts.map M.head :=
            List.mem_map_of_mem hαe_rot
          rw [fan.rotation_order.heads_eq] at hmem
          rw [BoundaryVertexFan.path]
          simpa [head_alpha] using hmem
        obtain ⟨p, hp⟩ := fan_path_vertex_has_survivor fan htail0 htaile_path
        exact ⟨p, Quotient.exact (show M.tail e = M.tail p.1 by rw [hp])⟩
    · exact ⟨⟨e, hes⟩, Equiv.Perm.SameCycle.refl M.σ e⟩
  refine ⟨Quotient.mk (cycleSetoid (M.deleteVertex d0).σ) p, ?_⟩
  apply Subtype.ext
  show Quotient.mk (cycleSetoid M.σ) p.1 = Quotient.mk (cycleSetoid M.σ) e
  exact Quotient.sound hp.symm

/-- **The vertex-quotient equivalence (fan form).**  The surviving `σ`-orbits of
`M.deleteVertex d0` biject with the old vertex orbits other than `⟦d0⟧`. -/
noncomputable def deleteVertex_vertexQuotientEquiv (fan : BoundaryVertexFan hNT v0)
    {d0 : D} (htail0 : M.tail d0 = v0) :
    Quotient (cycleSetoid (M.deleteVertex d0).σ) ≃
      {Q : Quotient (cycleSetoid M.σ) //
        Q ≠ Quotient.mk (cycleSetoid M.σ) d0} :=
  Equiv.ofBijective (vertexQuotientFun d0)
    ⟨vertexQuotientFun_injective d0, vertexQuotientFun_surjective fan htail0⟩



/-- The residual seam fact: all surviving darts whose `M`-face is incident with
`v0` lie in a single `φ'`-cycle (the new merged outer face). -/
def DeleteVertexMergedFaceSingleOrbit (M : CombMap D) (d0 : D) : Prop :=
  ∀ x y : {d : D // d ∉ M.deleteVertexSet d0},
    M.dartFace x.1 ∈ M.vertexFaces d0 → M.dartFace y.1 ∈ M.vertexFaces d0 →
    (M.deleteVertex d0).φ.SameCycle x y

/-- The face classification (incident with `v0`, or clean) is invariant along
deleted-`φ` cycles. -/
 lemma incident_invariant_of_sameCycle {d0 : D} (htail0 : M.tail d0 = v0)
    {x y : {d : D // d ∉ M.deleteVertexSet d0}}
    (hxy : (M.deleteVertex d0).φ.SameCycle x y) :
    (M.dartFace x.1 ∈ M.vertexFaces d0 ↔ M.dartFace y.1 ∈ M.vertexFaces d0) := by
  classical
  obtain ⟨k, hk⟩ := Equiv.Perm.SameCycle.exists_nat_pow_eq hxy
  -- iterate the φ'-invariance of the clean set
  have hiter : ∀ m : ℕ,
      (M.dartFace (((M.deleteVertex d0).φ ^ m) x).1 ∈ M.vertexFaces d0 ↔
        M.dartFace x.1 ∈ M.vertexFaces d0) := by
    intro m
    induction m with
    | zero => simp
    | succ m ih =>
        have hstep := cleanSurvSet_phi_invariant htail0 (((M.deleteVertex d0).φ ^ m) x)
        rw [mem_cleanSurvSet, mem_cleanSurvSet] at hstep
        have hiter1 : ((M.deleteVertex d0).φ ^ (m + 1)) x
            = (M.deleteVertex d0).φ (((M.deleteVertex d0).φ ^ m) x) := by
          rw [pow_succ']; rfl
        rw [hiter1]
        -- `hstep : φ'(·) clean ↔ · clean`; negate to incident.
        rw [← not_iff_not] at ih ⊢
        rw [hstep]; exact ih
  have := hiter k
  rw [hk] at this
  exact this.symm

/-- On a clean deleted-`φ` cycle, the `M`-face is constant. -/
 lemma clean_face_const_of_sameCycle {d0 : D} (htail0 : M.tail d0 = v0)
    {x y : {d : D // d ∉ M.deleteVertexSet d0}}
    (hfx : M.dartFace x.1 ∉ M.vertexFaces d0)
    (hxy : (M.deleteVertex d0).φ.SameCycle x y) :
    M.dartFace x.1 = M.dartFace y.1 := by
  classical
  obtain ⟨k, hk⟩ := Equiv.Perm.SameCycle.exists_nat_pow_eq hxy
  have hval := (deleteVertex_phi_clean_iterate htail0 x hfx k).1
  rw [hk] at hval
  -- `y.1 = (M.φ^k) x.1`, so same M-face.
  rw [hval]
  exact (Quotient.sound (⟨(k : ℤ), by rw [zpow_natCast]⟩ :
    M.φ.SameCycle x.1 ((M.φ ^ k) x.1)))

/-- The forward face-merge map: a deleted-`φ` orbit maps to its (unchanged)
clean `M`-face, or to the single merged outer face `inr ()`. -/
 noncomputable def faceMergeFun {d0 : D} (htail0 : M.tail d0 = v0) :
    Quotient (cycleSetoid (M.deleteVertex d0).φ) → M.deleteVertexFaceModel d0 :=
  Quotient.lift
    (fun x =>
      if h : M.dartFace x.1 ∈ M.vertexFaces d0 then Sum.inr ()
      else Sum.inl ⟨M.dartFace x.1, h⟩)
    (by
      intro x y hxy
      by_cases hx : M.dartFace x.1 ∈ M.vertexFaces d0
      · have hy : M.dartFace y.1 ∈ M.vertexFaces d0 :=
          (incident_invariant_of_sameCycle htail0 hxy).1 hx
        simp [hx, hy]
      · have hy : M.dartFace y.1 ∉ M.vertexFaces d0 := by
          intro hy'
          exact hx ((incident_invariant_of_sameCycle htail0 hxy).2 hy')
        have hface := clean_face_const_of_sameCycle htail0 hx hxy
        simp only []
        rw [dif_neg hx, dif_neg hy, Sum.inl.injEq, Subtype.mk.injEq]
        exact hface)

/-- A fan triangle's surviving edge dart is an incident survivor (its `M`-face is
the triangle, which is incident with `v0`). -/
 lemma fanTriangle_edge_dart_incident {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0) :
    M.dartFace (⟨T.d1, fanTriangle_edge_dart_survives_p2m_e7d236328e37 T htail0⟩ :
      {d : D // d ∉ M.deleteVertexSet d0}).1 ∈ M.vertexFaces d0 := by
  -- `d0`-face of `T.d0` (tail `v0`) equals the triangle face, which is `dartFace T.d1`.
  rw [dartFace_mem_vertexFaces_iff htail0]
  -- `T.d2` is in the φ-orbit of `T.d1` and has head `v0`, i.e. tail of its φ-succ is `v0`.
  -- Actually `T.d0` (tail v0) is `M.φ T.d2 = M.φ (M.φ T.d1)`, in the same φ-orbit.
  refine ⟨2, ?_⟩
  have h01 : M.φ T.d1 = T.d2 := T.triangle.2.1
  have h12 : M.φ T.d2 = T.d0 := T.triangle.2.2
  have h2 : (M.φ ^ (2 : ℤ)) T.d1 = T.d0 := by
    rw [show (2 : ℤ) = 1 + 1 from rfl, zpow_add, zpow_one]
    simp only [Equiv.Perm.coe_mul, Function.comp_apply]
    rw [h01, h12]
  rw [h2, T.tail0]

/-- Existence of an incident survivor (the head fan triangle's edge dart). -/
 lemma exists_incident_survivor (fan : BoundaryVertexFan hNT v0)
    {d0 : D} (htail0 : M.tail d0 = v0) :
    ∃ x : {d : D // d ∉ M.deleteVertexSet d0},
      M.dartFace x.1 ∈ M.vertexFaces d0 := by
  -- The head triangle of the fan path.
  set L : List M.Vertex := fan.interior ++ [fan.w] with hL
  have hpath : fan.path = fan.x :: L := by
    rw [BoundaryVertexFan.path, fanPath, hL, List.cons_append]
  obtain ⟨b, l', hLb⟩ : ∃ b l', L = b :: l' := by
    rw [hL]
    cases fan.interior with
    | nil => exact ⟨fan.w, [], rfl⟩
    | cons c t => exact ⟨c, t ++ [fan.w], rfl⟩
  have hpair0 : (fan.x, b) ∈ consecutivePairs (fan.x :: L) := by
    rw [hLb, consecutivePairs_cons_cons_p2m_e7d236328e37]; exact List.mem_cons.mpr (Or.inl rfl)
  have T0 : FanTriangle hNT v0 b fan.x := by
    apply fan.incident_faces_exact.triangle_of_pair
    have : (fan.x, b) ∈ consecutivePairs fan.path := by rw [hpath]; exact hpair0
    simpa [BoundaryVertexFan.path] using this
  exact ⟨_, fanTriangle_edge_dart_incident T0 htail0⟩

/-- Evaluation of `faceMergeFun` on the class of a clean survivor. -/
 lemma faceMergeFun_clean {d0 : D} (htail0 : M.tail d0 = v0)
    (x : {d : D // d ∉ M.deleteVertexSet d0}) (hx : M.dartFace x.1 ∉ M.vertexFaces d0) :
    faceMergeFun htail0 (Quotient.mk _ x) = Sum.inl ⟨M.dartFace x.1, hx⟩ := by
  rw [faceMergeFun, Quotient.lift_mk]
  rw [dif_neg hx]

/-- Evaluation of `faceMergeFun` on the class of an incident survivor. -/
 lemma faceMergeFun_incident {d0 : D} (htail0 : M.tail d0 = v0)
    (x : {d : D // d ∉ M.deleteVertexSet d0}) (hx : M.dartFace x.1 ∈ M.vertexFaces d0) :
    faceMergeFun htail0 (Quotient.mk _ x) = Sum.inr () := by
  rw [faceMergeFun, Quotient.lift_mk]
  rw [dif_pos hx]

/-- The face-merge map is bijective, given the merged-orbit fact. -/
 lemma faceMergeFun_bijective (fan : BoundaryVertexFan hNT v0)
    {d0 : D} (htail0 : M.tail d0 = v0)
    (hmerge : DeleteVertexMergedFaceSingleOrbit M d0) :
    Function.Bijective (faceMergeFun (M := M) htail0) := by
  classical
  constructor
  · -- injective
    intro a c hac
    obtain ⟨x, rfl⟩ := a.exists_rep
    obtain ⟨y, rfl⟩ := c.exists_rep
    by_cases hx : M.dartFace x.1 ∈ M.vertexFaces d0
    · by_cases hy : M.dartFace y.1 ∈ M.vertexFaces d0
      · exact Quotient.sound (hmerge x y hx hy)
      · rw [faceMergeFun_incident htail0 x hx, faceMergeFun_clean htail0 y hy] at hac
        exact absurd hac (by simp)
    · by_cases hy : M.dartFace y.1 ∈ M.vertexFaces d0
      · rw [faceMergeFun_clean htail0 x hx, faceMergeFun_incident htail0 y hy] at hac
        exact absurd hac (by simp)
      · -- both clean: equal `inl` faces ⟹ φ'-SameCycle
        rw [faceMergeFun_clean htail0 x hx, faceMergeFun_clean htail0 y hy] at hac
        have hval : M.dartFace x.1 = M.dartFace y.1 :=
          congrArg Subtype.val (Sum.inl.inj hac)
        exact Quotient.sound (deleteVertex_phi_sameCycle_of_clean htail0 x y hx hval)
  · -- surjective
    rintro (⟨f, hf⟩ | ⟨⟩)
    · -- clean face `f`: pick a surviving dart of `f`.
      obtain ⟨d, rfl⟩ := f.exists_rep
      have hd : d ∉ M.deleteVertexSet d0 := survives_of_dartFace_notMem htail0 hf
      exact ⟨Quotient.mk _ ⟨d, hd⟩, faceMergeFun_clean htail0 ⟨d, hd⟩ hf⟩
    · -- the merged outer face `inr ()`: any incident survivor.
      obtain ⟨x, hx⟩ := exists_incident_survivor fan htail0
      exact ⟨Quotient.mk _ x, faceMergeFun_incident htail0 x hx⟩

/-- **The face-merge field (fan form).**  Given the fan and the merged-orbit
fact, the `φ`-orbits of the deleted map are exactly the clean old faces plus one
merged outer face. -/
theorem deleteVertex_facesMerge_of_fan (fan : BoundaryVertexFan hNT v0)
    {d0 : D} (htail0 : M.tail d0 = v0)
    (hmerge : DeleteVertexMergedFaceSingleOrbit M d0) :
    M.DeleteVertexFacesMerge d0 :=
  ⟨Equiv.ofBijective _ (faceMergeFun_bijective fan htail0 hmerge)⟩



/-- Bundle of the new outer boundary data of the deleted map: the merged outer
face, its boundary cycle, simplicity, length bound, and the triangularity of all
other (surviving inner) faces.  This is exactly the part of
`FanSurgeryReconstruction` that is *not* the dart-rotation algebra discharged in
this file. -/
structure DeletedOuterBoundary (hNT : NearTriangulation M) (d0 : D) where
  /-- The merged outer face of the deleted map. -/
  outerFace : (M.deleteVertex d0).Face
  /-- The new outer boundary cycle. -/
  outerCycle : BoundaryCycle (M.deleteVertex d0) outerFace
  /-- The new boundary vertex list is simple. -/
  outer_simple : outerCycle.VertexNodup
  /-- The new boundary has length at least three. -/
  outer_len_ge_three : 3 ≤ outerCycle.length
  /-- Every non-outer face of the deleted map is an unchanged old inner triangle. -/
  inner_tri : ∀ f : (M.deleteVertex d0).Face, f ≠ outerFace →
    (M.deleteVertex d0).faceLen f = 3

/-- **Assemble `FanSurgeryReconstruction` from the fan.**  All three
dart-rotation surgery fields are discharged from the fan; the merged-orbit fact
and the new outer boundary data are supplied as inputs. -/
noncomputable def fanSurgeryReconstruction (fan : BoundaryVertexFan hNT v0)
    {d0 : D} (htail0 : M.tail d0 = v0)
    (hmerge : DeleteVertexMergedFaceSingleOrbit M d0)
    (bdry : DeletedOuterBoundary hNT d0) :
    FanSurgeryReconstruction hNT d0 where
  vertexQuotient := deleteVertex_vertexQuotientEquiv fan htail0
  facesMerge := deleteVertex_facesMerge_of_fan fan htail0 hmerge
  connected := deleteVertex_connected_of_fan fan htail0
  outerFace := bdry.outerFace
  outerCycle := bdry.outerCycle
  outer_simple := bdry.outer_simple
  outer_len_ge_three := bdry.outer_len_ge_three
  inner_tri := bdry.inner_tri

end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFanFaces
-/
/- Source module: ProofsInTheBook.PlanarMapFanMergedOrbit -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



/-- The vertex rotation factors as `σ = φ · α` (since `φ = σ · α` and `α² = 1`). -/
lemma sigma_eq_phi_mul_alpha (M : CombMap D) : M.σ = M.φ * M.α := by
  rw [φ, mul_assoc, M.α_invol, mul_one]

/-- One `σ`-step is `φ` after `α`. -/
lemma sigma_apply (M : CombMap D) (d : D) : M.σ d = M.φ (M.α d) := by
  rw [sigma_eq_phi_mul_alpha]; rfl

/-- `σ (α d) = M.φ d`. -/
lemma sigma_alpha (M : CombMap D) (d : D) : M.σ (M.α d) = M.φ d := by
  rw [sigma_apply, M.alpha_alpha]

/-- **Closed-form `φ'` successor, Case B: the next dart is deleted.**  If `x`
survives, the immediate `M.φ`-successor `M.φ x.1` is deleted, but the following
`σ`-step `M.σ (M.φ x.1)` survives, then the deleted-map `φ'`-successor of `x`
is exactly `M.σ (M.φ x.1)`. -/
lemma deleteVertex_phi_apply_of_next_deleted (M : CombMap D) (v : D)
    (x : {d : D // d ∉ M.deleteVertexSet v})
    (hdel : M.φ x.1 ∈ M.deleteVertexSet v)
    (hsurv : M.σ (M.φ x.1) ∉ M.deleteVertexSet v) :
    ((M.deleteVertex v).φ x : D) = M.σ (M.φ x.1) := by
  classical
  set y : {d : D // d ∉ M.deleteVertexSet v} := M.alphaDeleteVertex v x with hy
  have hycoe : (y : D) = M.α x.1 := by rw [hy]; exact alphaDeleteVertex_apply_coe M v x
  -- σ¹ (α x.1) = M.φ x.1
  have hσ1 : (M.σ ^ 1) (y : D) = M.φ x.1 := by
    rw [pow_one, hycoe, sigma_alpha]
  -- σ² (α x.1) = σ (M.φ x.1)
  have hσ2 : (M.σ ^ 2) (y : D) = M.σ (M.φ x.1) := by
    rw [show (2 : ℕ) = 1 + 1 from rfl, pow_succ']
    simp only [Equiv.Perm.coe_mul, Function.comp_apply]
    rw [hσ1]
  -- firstOutside = 2
  have hfo : Equiv.Perm.DeleteSet.firstOutside M.σ (M.deleteVertexSet v) y = 2 := by
    refine (Nat.find_eq_iff (Equiv.Perm.DeleteSet.exists_pos_pow_notMem M.σ (M.deleteVertexSet v) y)).2 ?_
    refine ⟨⟨by norm_num, by rw [hσ2]; exact hsurv⟩, ?_⟩
    intro m hm ⟨hmpos, hmnot⟩
    interval_cases m
    · rw [hσ1] at hmnot; exact hmnot hdel
  rw [deleteVertex_phi_apply_coe]
  rw [show (M.alphaDeleteVertex v x) = y from rfl, hfo, ← hycoe, hσ2]



/-- A forward `M.φ`-run of survivors is followed step-for-step by `φ'`. -/
lemma deleteVertex_phi_survRun_iterate (M : CombMap D) (v : D)
    (x : {d : D // d ∉ M.deleteVertexSet v}) (k : ℕ)
    (hrun : ∀ j ≤ k, (M.φ ^ j) x.1 ∉ M.deleteVertexSet v) :
    (((M.deleteVertex v).φ ^ k) x : D) = (M.φ ^ k) x.1 := by
  induction k with
  | zero => simp
  | succ k ih =>
      have ihrun : ∀ j ≤ k, (M.φ ^ j) x.1 ∉ M.deleteVertexSet v :=
        fun j hj => hrun j (Nat.le_succ_of_le hj)
      have hval : (((M.deleteVertex v).φ ^ k) x : D) = (M.φ ^ k) x.1 := ih ihrun
      -- the dart we are stepping from survives
      have hxk : (M.φ ^ k) x.1 ∉ M.deleteVertexSet v := hrun k (Nat.le_succ k)
      -- its M.φ-successor survives
      have hnext : M.φ ((M.φ ^ k) x.1) ∉ M.deleteVertexSet v := by
        have : (M.φ ^ (k + 1)) x.1 = M.φ ((M.φ ^ k) x.1) := by
          rw [pow_succ']; rfl
        rw [← this]; exact hrun (k + 1) (le_refl _)
      have hiter1 : ((M.deleteVertex v).φ ^ (k + 1)) x
          = (M.deleteVertex v).φ (((M.deleteVertex v).φ ^ k) x) := by
        rw [pow_succ']; rfl
      rw [hiter1]
      -- φ' agrees with M.φ on the surviving dart ⟨(M.φ^k) x.1, hxk⟩
      have hstep : ((M.deleteVertex v).φ (((M.deleteVertex v).φ ^ k) x) : D)
          = M.φ ((M.φ ^ k) x.1) := by
        have hpt : (((M.deleteVertex v).φ ^ k) x) = (⟨(M.φ ^ k) x.1, hxk⟩ :
            {d : D // d ∉ M.deleteVertexSet v}) := Subtype.ext hval
        rw [hpt]
        exact deleteVertex_phi_apply_of_next_kept M v ⟨(M.φ ^ k) x.1, hxk⟩ hnext
      rw [hstep, pow_succ']; rfl

/-- Two survivors on the same `M`-face whose connecting forward `M.φ`-run stays
inside the survivors are in the same `φ'`-cycle. -/
lemma deleteVertex_phi_sameCycle_of_survRun (M : CombMap D) (v : D)
    (x y : {d : D // d ∉ M.deleteVertexSet v}) (k : ℕ)
    (hrun : ∀ j ≤ k, (M.φ ^ j) x.1 ∉ M.deleteVertexSet v)
    (hk : (M.φ ^ k) x.1 = y.1) :
    (M.deleteVertex v).φ.SameCycle x y := by
  refine ⟨(k : ℤ), ?_⟩
  rw [zpow_natCast]
  apply Subtype.ext
  rw [deleteVertex_phi_survRun_iterate M v x k hrun, hk]

namespace NearTriangulation

variable {M : CombMap D} {hNT : NearTriangulation M} {v0 : M.Vertex}



/-- The head of `T.d1` is `b`. -/
 lemma fanTriangle_head1 {a b : M.Vertex} (T : FanTriangle hNT v0 a b) :
    M.head T.d1 = b := by
  have hphi : M.φ T.d1 = T.d2 := T.triangle.2.1
  have hh : M.head T.d1 = M.tail T.d2 := by rw [← tail_phi, hphi]
  rw [hh, T.tail2]

/-- The head of `T.d2` is `v0`. -/
 lemma fanTriangle_head2 {a b : M.Vertex} (T : FanTriangle hNT v0 a b) :
    M.head T.d2 = v0 := by
  have hphi : M.φ T.d2 = T.d0 := T.triangle.2.2
  have hh : M.head T.d2 = M.tail T.d0 := by rw [← tail_phi, hphi]
  rw [hh, T.tail0]

/-- The head of `T.d0` is `a`. -/
 lemma fanTriangle_head0 {a b : M.Vertex} (T : FanTriangle hNT v0 a b) :
    M.head T.d0 = a := by
  have hphi : M.φ T.d0 = T.d1 := T.triangle.1
  have hh : M.head T.d0 = M.tail T.d1 := by rw [← tail_phi, hphi]
  rw [hh, T.tail1]

/-- `T.d1` survives the deletion of any dart `d0` representing `v0`. -/
 lemma fanTriangle_d1_survives {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0) :
    T.d1 ∉ M.deleteVertexSet d0 := by
  have hdist := T.vertices_pairwiseDistinct
  have htail : M.tail T.d1 ≠ M.tail d0 := by rw [T.tail1, htail0]; exact (hdist.1).symm
  have hhead : M.head T.d1 ≠ M.tail d0 := by
    rw [fanTriangle_head1 T, htail0]; exact hdist.2.2
  rw [mem_deleteVertexSet_iff]; push_neg
  rw [mem_vertexDarts, mem_vertexDarts]
  refine ⟨fun h => htail (Quotient.sound h).symm, fun h => ?_⟩
  have heq : M.tail d0 = M.tail (M.α T.d1) := Quotient.sound h
  rw [tail_alpha] at heq
  exact hhead heq.symm

/-- `T.d2` is deleted (its head is `v0`). -/
 lemma fanTriangle_d2_deleted {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0) :
    T.d2 ∈ M.deleteVertexSet d0 := by
  rw [mem_deleteVertexSet_iff]; right
  rw [mem_vertexDarts]
  -- α T.d2 has tail = head T.d2 = v0 = tail d0
  exact Quotient.exact (show M.tail d0 = M.tail (M.α T.d2) by
    rw [tail_alpha, fanTriangle_head2 T, htail0])



/-- **Consecutive fan triangles share the `v0`-spoke.**  If `Ti = (v0, a, b)` and
`Tj = (v0, b, c)` are consecutive fan triangles, then the reverse of `Ti.d2`
(tail `b`, head `v0`) is `Tj.d0` (tail `v0`, head `b`): they are the two darts of
the single edge `v0—b`. -/
 lemma fanTriangle_shared_spoke {a b c : M.Vertex}
    (Ti : FanTriangle hNT v0 a b) (Tj : FanTriangle hNT v0 b c) :
    M.α Ti.d2 = Tj.d0 := by
  have hsame : M.α.SameCycle Ti.d2 Tj.d0 :=
    alpha_sameCycle_of_same_endpoints_symm M hNT.simpleGraph
      (by rw [Ti.tail2, fanTriangle_head0 Tj])
      (by rw [fanTriangle_head2 Ti, Tj.tail0])
  rcases (alpha_sameCycle_iff M Ti.d2 Tj.d0).1 hsame with h | h
  · -- Tj.d0 = Ti.d2 impossible: different tails (v0 vs b)
    exfalso
    have hbv0 : (b : M.Vertex) = v0 := by
      have : M.tail Tj.d0 = M.tail Ti.d2 := by rw [h]
      rw [Tj.tail0, Ti.tail2] at this; exact this.symm
    exact (Tj.vertices_pairwiseDistinct).1 hbv0.symm
  · rw [h]

/-- **Triangle chain step.**  The deleted-map `φ'`-successor of `Ti.d1` is
`Tj.d1`, where `Tj` is the next consecutive fan triangle. -/
 lemma fanTriangle_chain_step {a b c : M.Vertex}
    (Ti : FanTriangle hNT v0 a b) (Tj : FanTriangle hNT v0 b c)
    {d0 : D} (htail0 : M.tail d0 = v0) :
    ((M.deleteVertex d0).φ ⟨Ti.d1, fanTriangle_d1_survives Ti htail0⟩ : D) = Tj.d1 := by
  have hdel : M.φ Ti.d1 ∈ M.deleteVertexSet d0 := by
    have hphi : M.φ Ti.d1 = Ti.d2 := Ti.triangle.2.1
    rw [hphi]; exact fanTriangle_d2_deleted Ti htail0
  -- σ (M.φ Ti.d1) = σ Ti.d2 = M.φ (α Ti.d2) = M.φ Tj.d0 = Tj.d1
  have hphi1 : M.φ Ti.d1 = Ti.d2 := Ti.triangle.2.1
  have hsig : M.σ (M.φ Ti.d1) = Tj.d1 := by
    rw [hphi1, sigma_apply, fanTriangle_shared_spoke Ti Tj]
    exact Tj.triangle.1
  have hsurv : M.σ (M.φ Ti.d1) ∉ M.deleteVertexSet d0 := by
    rw [hsig]; exact fanTriangle_d1_survives Tj htail0
  rw [deleteVertex_phi_apply_of_next_deleted M d0 _ hdel hsurv, hsig]

/-- `φ'`-cycle form of the chain step: consecutive triangle edge darts are in one
`φ'`-cycle. -/
 lemma fanTriangle_chain_sameCycle {a b c : M.Vertex}
    (Ti : FanTriangle hNT v0 a b) (Tj : FanTriangle hNT v0 b c)
    {d0 : D} (htail0 : M.tail d0 = v0) :
    (M.deleteVertex d0).φ.SameCycle
      ⟨Ti.d1, fanTriangle_d1_survives Ti htail0⟩
      ⟨Tj.d1, fanTriangle_d1_survives Tj htail0⟩ := by
  refine ⟨1, ?_⟩
  apply Subtype.ext
  rw [zpow_one]
  exact fanTriangle_chain_step Ti Tj htail0



/-- `consecutivePairs` of a two-or-more element list. -/
 lemma consecutivePairs_cons_cons_p2m_b5533c713919 {α : Type*} (a b : α) (l : List α) :
    consecutivePairs (a :: b :: l) = (a, b) :: consecutivePairs (b :: l) := by
  simp [consecutivePairs]

/-- Every triangle edge dart along the path is in the `φ'`-cycle of a fixed
reference survivor `r`, provided `r` is linked to the **head** triangle's edge
dart (the triangle of the first pair `(hd, L.head)`) and all consecutive pairs
carry triangles.  The tail list `L` is destructured internally, so the caller
need not split it (keeping the path's `fan.x :: interior ++ [w]` shape).

Predecessor convention: a forward consecutive pair `(a, b)` carries the swapped
triangle `FanTriangle v0 b a`.  Consecutive forward pairs `(hd, c), (c, c')` give
triangles `Ti = (v0, c, hd)`, `Tj = (v0, c', c)` sharing `c` as `Ti.tail1 = Tj.tail2`;
the chain step `fanTriangle_chain_sameCycle` (which links `(v0, a, b)`-then-`(v0, b, c)`
in `φ'`) thus applies in the reverse order `(Tj, Ti)`, giving the same `φ'`-cycle. -/
 lemma fanTriangle_edge_dart_sameCycle_ref {d0 : D} (htail0 : M.tail d0 = v0)
    (r : {d : D // d ∉ M.deleteVertexSet d0}) :
    ∀ (L : List M.Vertex) (hd : M.Vertex)
      (htri : ∀ a b : M.Vertex, (a, b) ∈ consecutivePairs (hd :: L) →
        FanTriangle hNT v0 b a),
      (∀ (c : M.Vertex) (hpc : (hd, c) ∈ consecutivePairs (hd :: L)),
        (M.deleteVertex d0).φ.SameCycle r
          ⟨(htri hd c hpc).d1, fanTriangle_d1_survives _ htail0⟩) →
      ∀ {a b : M.Vertex} (hab : (a, b) ∈ consecutivePairs (hd :: L)),
        (M.deleteVertex d0).φ.SameCycle r
          ⟨(htri a b hab).d1, fanTriangle_d1_survives _ htail0⟩ := by
  intro L
  induction L with
  | nil => intro hd htri _ a b hab; simp [consecutivePairs] at hab
  | cons c t ih =>
      intro hd htri hhead a b hab
      have hpc : (hd, c) ∈ consecutivePairs (hd :: c :: t) := by
        rw [consecutivePairs_cons_cons_p2m_b5533c713919]; exact List.mem_cons.mpr (Or.inl rfl)
      have lift : ∀ a' b' : M.Vertex, (a', b') ∈ consecutivePairs (c :: t) →
          (a', b') ∈ consecutivePairs (hd :: c :: t) := fun a' b' hab' => by
        rw [consecutivePairs_cons_cons_p2m_b5533c713919]; exact List.mem_cons.mpr (Or.inr hab')
      set htri' : ∀ a' b' : M.Vertex, (a', b') ∈ consecutivePairs (c :: t) →
          FanTriangle hNT v0 b' a' :=
        fun a' b' hab' => htri a' b' (lift a' b' hab') with htri'def
      have hhead' : ∀ (c' : M.Vertex) (hpc' : (c, c') ∈ consecutivePairs (c :: t)),
          (M.deleteVertex d0).φ.SameCycle r
            ⟨(htri' c c' hpc').d1, fanTriangle_d1_survives _ htail0⟩ := by
        intro c' hpc'
        -- `htri hd c hpc : (v0, c, hd)`, `htri' c c' hpc' : (v0, c', c)`; they share `c`
        -- as `(htri' c c').tail2 = (htri hd c).tail1`, so the chain step links
        -- `(htri' c c').d1 → (htri hd c).d1`; take `.symm`.
        exact (hhead c hpc).trans
          (fanTriangle_chain_sameCycle (htri' c c' hpc') (htri hd c hpc) htail0).symm
      rw [consecutivePairs_cons_cons_p2m_b5533c713919] at hab
      rcases List.mem_cons.mp hab with hhd | htl
      · have hae : a = hd := (Prod.ext_iff.mp hhd).1
        have hbe : b = c := (Prod.ext_iff.mp hhd).2
        cases hae; cases hbe; exact hhead c hab
      · exact ih c htri' hhead' htl



/-- The `φ`-orbit (face) of a fan triangle is exactly `{d0, d1, d2}`; a survivor
of that face is `d1`. -/
 lemma survivor_on_fanTriangle_eq_d1 {a b : M.Vertex}
    (T : FanTriangle hNT v0 a b) {d0 : D} (htail0 : M.tail d0 = v0)
    (x : {d : D // d ∉ M.deleteVertexSet d0})
    (hface : M.dartFace x.1 = T.face) :
    x.1 = T.d1 := by
  -- dartFace T.d1 = T.face (= dartFace T.d0, and φ T.d0 = T.d1).
  have hdf1 : M.dartFace T.d1 = T.face := by
    rw [FanTriangle.face, ← T.triangle.1, dartFace_phi]
  -- face has length 3, so φ-orbit of T.d1 is {d1, d2, d0}; x.1 is one of them.
  have hlen : M.faceLen (M.dartFace T.d1) = 3 := by
    rw [hdf1]; exact T.faceLen_eq_three
  -- x.1 ~φ T.d1
  have hsame : M.φ.SameCycle T.d1 x.1 :=
    Quotient.exact (show M.dartFace T.d1 = M.dartFace x.1 by rw [hdf1, hface])
  have hφ : M.φ T.d1 ≠ T.d1 := phi_ne_self_of_isSimpleGraph M hNT.simpleGraph T.d1
  have hsupp : T.d1 ∈ M.φ.support := by simpa [Equiv.Perm.mem_support] using hφ
  have hcard : (M.φ.cycleOf T.d1).support.card = 3 := by
    rw [← faceLen_dartFace_eq_card_support_cycleOf M hφ, hlen]
  obtain ⟨i, hi, hpow⟩ := hsame.exists_pow_eq_of_mem_support hsupp
  rw [hcard] at hi
  have h01 : M.φ T.d1 = T.d2 := T.triangle.2.1
  have h12 : M.φ T.d2 = T.d0 := T.triangle.2.2
  interval_cases i
  · simpa using hpow.symm
  · -- x.1 = φ T.d1 = T.d2, deleted (head v0): contradiction
    exfalso
    have : x.1 = T.d2 := by simpa [h01] using hpow.symm
    exact x.2 (this ▸ fanTriangle_d2_deleted T htail0)
  · -- x.1 = φ² T.d1 = T.d0, deleted (tail v0): contradiction
    exfalso
    have hx0 : x.1 = T.d0 := by
      have h2 : (M.φ ^ 2) T.d1 = T.d0 := by
        rw [show (2:ℕ) = 1+1 from rfl, pow_succ', pow_one]
        simp only [Equiv.Perm.coe_mul, Function.comp_apply, h01, h12]
      rw [h2] at hpow; exact hpow.symm
    have hd0del : T.d0 ∈ M.deleteVertexSet d0 := by
      rw [mem_deleteVertexSet_iff]; left
      rw [mem_vertexDarts]
      exact Quotient.exact (show M.tail d0 = M.tail T.d0 by rw [htail0, T.tail0])
    exact x.2 (hx0 ▸ hd0del)

/-- An incident survivor's `M`-face is incident with `v0` in the
`FaceIncidentAtVertex` sense (some dart of the face has tail `v0`). -/
 lemma faceIncidentAtVertex_of_incident {d0 : D} (htail0 : M.tail d0 = v0)
    (x : {d : D // d ∉ M.deleteVertexSet d0})
    (hx : M.dartFace x.1 ∈ M.vertexFaces d0) :
    FaceIncidentAtVertex M (M.dartFace x.1) v0 := by
  rw [vertexFaces, Finset.mem_image] at hx
  obtain ⟨e, he, hef⟩ := hx
  rw [mem_vertexDarts] at he
  refine ⟨e, hef, ?_⟩
  have : M.tail d0 = M.tail e := Quotient.sound he
  rw [← this, htail0]



/-- The isolated outer-arc reconnection: every surviving dart on the old outer
face is in the `φ'`-cycle of the fixed reference fan-triangle edge dart `r`. -/
def MergedOuterArcReconnects (M : CombMap D) (d0 : D)
    (r : {d : D // d ∉ M.deleteVertexSet d0})
    (outerFace : M.Face) : Prop :=
  ∀ x : {d : D // d ∉ M.deleteVertexSet d0},
    M.dartFace x.1 = outerFace → (M.deleteVertex d0).φ.SameCycle r x



/-- A fan-triangle edge reference tied to the canonical `triangle_of_pair` field of
the fan.  This is the right target for the old-outer seam: the Case-B jump lands
on one concrete fan edge, and the fan-chain lemma transports that edge to the
head reference internally. -/
def FanTriangleEdge (fan : BoundaryVertexFan hNT v0)
    {d0 : D} (r : {d : D // d ∉ M.deleteVertexSet d0}) : Prop :=
  ∃ (a b : M.Vertex) (hp : (a, b) ∈ consecutivePairs fan.path),
    r.1 = (fan.incident_faces_exact.triangle_of_pair hp).d1

/-- **The merged-face single-orbit fact from an arbitrary actual seam fan edge.**
The old outer arc may Case-B-jump into any fan-triangle edge on the fan chain.  The
proved fan-chain `SameCycle` calculus transports that entry edge to the head
reference used by the existing merged-orbit proof, so the final
`DeleteVertexMergedFaceSingleOrbit` is independent of the entry point. -/
theorem deleteVertexMergedFaceSingleOrbit_of_fan_from_edge (fan : BoundaryVertexFan hNT v0)
    (hchord : BoundaryChordless hNT.outerCycle)
    {d0 : D} (htail0 : M.tail d0 = v0)
    (rₛ : {d : D // d ∉ M.deleteVertexSet d0})
    (hrₛ : FanTriangleEdge fan rₛ)
    (houterₛ : MergedOuterArcReconnects M d0 rₛ hNT.outerFace) :
    DeleteVertexMergedFaceSingleOrbit M d0 := by
  classical
  set L : List M.Vertex := fan.interior ++ [fan.w] with hL
  have hpath : fan.path = fan.x :: L := by
    rw [BoundaryVertexFan.path, fanPath, hL, List.cons_append]
  let toPath : ∀ a b : M.Vertex,
      (a, b) ∈ consecutivePairs (fan.x :: L) → (a, b) ∈ consecutivePairs fan.path :=
    fun _ _ hab => by rw [hpath]; exact hab
  let htri : ∀ a b : M.Vertex,
      (a, b) ∈ consecutivePairs (fan.x :: L) → FanTriangle hNT v0 b a :=
    fun a b hab => fan.incident_faces_exact.triangle_of_pair (toPath a b hab)
  have hnodup : (fan.x :: L).Nodup := by
    have := fan_path_simple_of_chordless hNT fan hchord
    rwa [hpath] at this
  obtain ⟨b0, l', hLb⟩ : ∃ b l', L = b :: l' := by
    rw [hL]
    cases fan.interior with
    | nil => exact ⟨fan.w, [], rfl⟩
    | cons c t => exact ⟨c, t ++ [fan.w], rfl⟩
  have hpair0 : (fan.x, b0) ∈ consecutivePairs (fan.x :: L) := by
    rw [hLb, consecutivePairs_cons_cons_p2m_b5533c713919]; exact List.mem_cons.mpr (Or.inl rfl)
  set r : {d : D // d ∉ M.deleteVertexSet d0} :=
    ⟨(htri fan.x b0 hpair0).d1, fanTriangle_d1_survives _ htail0⟩ with hr
  have hhead : ∀ (c : M.Vertex) (hpc : (fan.x, c) ∈ consecutivePairs (fan.x :: L)),
      (M.deleteVertex d0).φ.SameCycle r
        ⟨(htri fan.x c hpc).d1, fanTriangle_d1_survives _ htail0⟩ := by
    intro c hpc
    have hcb0 : c = b0 := by
      rw [hLb, consecutivePairs_cons_cons_p2m_b5533c713919] at hpc
      rcases List.mem_cons.mp hpc with hhd | htl
      · exact (Prod.ext_iff.mp hhd).2
      · exfalso
        have hxmem : fan.x ∈ b0 :: l' := (List.of_mem_zip htl).1
        have hnd : (fan.x :: b0 :: l').Nodup := by rw [← hLb]; exact hnodup
        exact (List.nodup_cons.mp hnd).1 hxmem
    subst hcb0
    exact Equiv.Perm.SameCycle.refl _ _
  have hentry : (M.deleteVertex d0).φ.SameCycle r rₛ := by
    rcases hrₛ with ⟨a, b, hp, hrval⟩
    have hp' : (a, b) ∈ consecutivePairs (fan.x :: L) := by
      rw [← hpath]; exact hp
    have hlink := fanTriangle_edge_dart_sameCycle_ref htail0 r L fan.x htri hhead hp'
    have hval : rₛ.1 = (htri a b hp').d1 := by
      rw [hrval]
    have hsub : rₛ =
        (⟨(htri a b hp').d1, fanTriangle_d1_survives (htri a b hp') htail0⟩ :
          {d : D // d ∉ M.deleteVertexSet d0}) := Subtype.ext hval
    rw [hsub]
    exact hlink
  have houter_r : MergedOuterArcReconnects M d0 r hNT.outerFace := by
    intro x hx
    exact hentry.trans (houterₛ x hx)
  suffices hkey : ∀ z : {d : D // d ∉ M.deleteVertexSet d0},
      M.dartFace z.1 ∈ M.vertexFaces d0 → (M.deleteVertex d0).φ.SameCycle r z by
    intro x y hx hy
    exact (hkey x hx).symm.trans (hkey y hy)
  intro z hz
  by_cases hzouter : M.dartFace z.1 = hNT.outerFace
  · exact houter_r z hzouter
  · have hinc : FaceIncidentAtVertex M (M.dartFace z.1) v0 :=
      faceIncidentAtVertex_of_incident htail0 z hz
    obtain ⟨a, b, hp, hface⟩ :=
      (fan.incident_faces_exact.exact_faces (M.dartFace z.1) hzouter).1 hinc
    have hp' : (a, b) ∈ consecutivePairs (fan.x :: L) := by rw [← hpath]; exact hp
    have hTface : (htri a b hp').face = M.dartFace z.1 := by
      show (fan.incident_faces_exact.triangle_of_pair _).face = M.dartFace z.1
      convert hface using 2
    have hzd1 : z.1 = (htri a b hp').d1 :=
      survivor_on_fanTriangle_eq_d1 (htri a b hp') htail0 z hTface.symm
    have hlink := fanTriangle_edge_dart_sameCycle_ref htail0 r L fan.x htri hhead hp'
    have hzeq : z = (⟨(htri a b hp').d1, fanTriangle_d1_survives (htri a b hp') htail0⟩ :
        {d : D // d ∉ M.deleteVertexSet d0}) := Subtype.ext hzd1
    rw [hzeq]; exact hlink



end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapBoundary
-/
/- Source module: ProofsInTheBook.PlanarMapBoundaryArcSplit -/
section
set_option autoImplicit true




set_option maxHeartbeats 1600000
set_option linter.unusedVariables false

namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



namespace BoundaryCycleData

variable {M : CombMap D} {f : M.Face}

/-- Boundary vertices are represented by the exposed cyclic vertex list. -/
def IsBoundaryVertex (K : BoundaryCycleData M f) (v : M.Vertex) : Prop :=
  v ∈ K.vertices

/-- Boundary edges are represented by the exposed cyclic edge list. -/
def IsBoundaryEdge (K : BoundaryCycleData M f) (e : Sym2 M.Vertex) : Prop :=
  e ∈ K.edges

/-- The boundary vertex list is simple. -/
def VertexNodup (K : BoundaryCycleData M f) : Prop :=
  K.vertices.Nodup





lemma darts_length_pos (K : BoundaryCycleData M f) : 0 < K.darts.length :=
  K.normalized.length_pos

end BoundaryCycleData



theorem modCoverD (L pf pt : ℕ) (hLpos : 0 < L) (hpf : pf < L) (hpt : pt < L) (hne : pf ≠ pt)
    (kf kb : ℕ) (hkf_eq : kf = (pt + L - pf) % L) (hkb_eq : kb = (pf + L - pt) % L) :
    1 ≤ kf ∧ 1 ≤ kb ∧ kf + kb = L ∧ (pf + kf) % L = pt ∧
    ∀ q, q < L → (∃ j, j < kf ∧ (pf + j) % L = q) ∨ (∃ j, j < kb ∧ (pt + j) % L = q) := by
  have hkf1 : 1 ≤ kf := by
    rw [hkf_eq]
    rcases Nat.eq_zero_or_pos ((pt + L - pf) % L) with h0 | h0
    · exfalso
      obtain ⟨m, hm⟩ := Nat.dvd_of_mod_eq_zero h0
      have hlt : pt + L - pf < 2 * L := by omega
      have hgt : 0 < pt + L - pf := by omega
      have : m = 1 := by nlinarith
      rw [this, Nat.mul_one] at hm; omega
    · exact h0
  have hkb1 : 1 ≤ kb := by
    rw [hkb_eq]
    rcases Nat.eq_zero_or_pos ((pf + L - pt) % L) with h0 | h0
    · exfalso
      obtain ⟨m, hm⟩ := Nat.dvd_of_mod_eq_zero h0
      have hlt : pf + L - pt < 2 * L := by omega
      have hgt : 0 < pf + L - pt := by omega
      have : m = 1 := by nlinarith
      rw [this, Nat.mul_one] at hm; omega
    · exact h0
  have hkfval : kf = if pf ≤ pt then pt - pf else pt + L - pf := by
    rw [hkf_eq]; split
    · next h => rw [show pt + L - pf = (pt - pf) + L from by omega, Nat.add_mod_right,
        Nat.mod_eq_of_lt (by omega)]
    · next h => rw [Nat.mod_eq_of_lt (by omega)]
  have hkbval : kb = if pt ≤ pf then pf - pt else pf + L - pt := by
    rw [hkb_eq]; split
    · next h => rw [show pf + L - pt = (pf - pt) + L from by omega, Nat.add_mod_right,
        Nat.mod_eq_of_lt (by omega)]
    · next h => rw [Nat.mod_eq_of_lt (by omega)]
  have hsum : kf + kb = L := by rw [hkfval, hkbval]; split <;> split <;> omega
  have hpfkf : (pf + kf) % L = pt := by
    rw [hkf_eq]
    conv_lhs => rw [Nat.add_mod, Nat.mod_mod_of_dvd _ (dvd_refl L)]
    rw [← Nat.add_mod]
    have : pf + (pt + L - pf) = pt + L := by omega
    rw [this, Nat.add_mod_right, Nat.mod_eq_of_lt hpt]
  refine ⟨hkf1, hkb1, hsum, hpfkf, ?_⟩
  intro q hq
  set df := (q + L - pf) % L with hdf
  have hdfL : df < L := Nat.mod_lt _ hLpos
  have hpfdf : (pf + df) % L = q := by
    rw [hdf]
    conv_lhs => rw [Nat.add_mod, Nat.mod_mod_of_dvd _ (dvd_refl L)]
    rw [← Nat.add_mod]
    have : pf + (q + L - pf) = q + L := by omega
    rw [this, Nat.add_mod_right, Nat.mod_eq_of_lt hq]
  by_cases hd : df < kf
  · exact Or.inl ⟨df, hd, hpfdf⟩
  · refine Or.inr ⟨df - kf, by omega, ?_⟩
    calc (pt + (df - kf)) % L = ((pf + kf) % L + (df - kf)) % L := by rw [hpfkf]
      _ = (pf + kf + (df - kf)) % L := by
            rw [Nat.add_mod, Nat.mod_mod_of_dvd _ (dvd_refl L), ← Nat.add_mod]
      _ = (pf + df) % L := by rw [show pf + kf + (df - kf) = pf + df from by omega]
      _ = q := hpfdf



/-- A dart-level boundary arc from `u` to `v` on the boundary-cycle core `K`. -/
structure DataDartArc (M : CombMap D) {f : M.Face} (K : BoundaryCycleData M f)
    (u v : M.Vertex) where
  /-- Number of darts on the arc. -/
  len : ℕ
  /-- The arc is nonempty (at least one dart). -/
  len_pos : 0 < len
  /-- The directed arc darts `e_0, …, e_{len-1}`. -/
  arcDart : Fin len → D
  /-- Every arc dart lies on the boundary cycle. -/
  boundary : ∀ i : Fin len, arcDart i ∈ K.darts
  /-- Consecutive arc darts chain head→tail (no wraparound — this is a *path*). -/
  chain : ∀ i : Fin len, (h : (i : ℕ) + 1 < len) →
    M.head (arcDart i) = M.tail (arcDart ⟨i + 1, h⟩)
  /-- The first dart's tail is `u`. -/
  tail_first : M.tail (arcDart ⟨0, len_pos⟩) = u
  /-- The last dart's head is `v`. -/
  head_last : M.head (arcDart ⟨len - 1, by omega⟩) = v
  /-- The tail vertices of the arc darts are pairwise distinct (simplicity). -/
  tail_nodup : Function.Injective (fun i : Fin len => M.tail (arcDart i))
  /-- The final head `v` is distinct from every tail (the arc does not revisit its
  endpoint). -/
  head_last_ne_tail : ∀ i : Fin len, v ≠ M.tail (arcDart i)

namespace DataDartArc

variable {M : CombMap D} {f : M.Face} {K : BoundaryCycleData M f} {u v : M.Vertex}



/-- The first index of the arc. -/
def firstIdx (A : DataDartArc M K u v) : Fin A.len := ⟨0, A.len_pos⟩





/-- The explicit `List D` of a `DataDartArc`'s darts, `[arcDart 0, …, arcDart (len-1)]`. -/
def dartList (A : DataDartArc M K u v) : List D :=
  (List.finRange A.len).map A.arcDart

@[simp] lemma dartList_length (A : DataDartArc M K u v) : A.dartList.length = A.len := by
  simp [DataDartArc.dartList]

lemma dartList_ne_nil (A : DataDartArc M K u v) : A.dartList ≠ [] := by
  rw [← List.length_pos_iff_ne_nil, DataDartArc.dartList_length]; exact A.len_pos

lemma dartList_getElem (A : DataDartArc M K u v) (j : ℕ) (hj : j < A.len) :
    A.dartList[j]'(by rw [DataDartArc.dartList_length]; exact hj) = A.arcDart ⟨j, hj⟩ := by
  simp only [DataDartArc.dartList, List.getElem_map, List.getElem_finRange]
  congr 1

lemma mem_dartList (A : DataDartArc M K u v) {d : D} (hd : d ∈ A.dartList) :
    ∃ i : Fin A.len, A.arcDart i = d := by
  rw [DataDartArc.dartList, List.mem_map] at hd
  obtain ⟨i, _, hi⟩ := hd
  exact ⟨i, hi⟩

end DataDartArc



namespace BoundaryCycleData

variable {M : CombMap D} {f : M.Face}

/-- The position of a boundary vertex on the cyclic dart list (as the tail of a
listed dart), as a single existential over `Fin`. -/
lemma exists_pos_of_isBoundaryVertex (K : BoundaryCycleData M f) {a : M.Vertex}
    (ha : K.IsBoundaryVertex a) :
    ∃ p : Fin K.darts.length, M.tail (K.darts[p.1]'p.2) = a := by
  have ha' : a ∈ K.darts.map M.tail := by
    simpa [BoundaryCycleData.IsBoundaryVertex, K.vertices_eq] using ha
  rw [List.mem_iff_getElem] at ha'
  obtain ⟨p, hp, hget⟩ := ha'
  rw [List.length_map] at hp
  refine ⟨⟨p, hp⟩, ?_⟩
  rwa [List.getElem_map] at hget

/-- Given a boundary-cycle core `K` (vertices simple), a start position `p`, and a
*cyclic* run length `k` with `1 ≤ k ≤ K.darts.length`, the darts `K.darts[(p + j) % L]`
(`j < k`) form a `DataDartArc` from `M.tail (K.darts[p])` to `M.tail (K.darts[(p+k)%L])`. -/
noncomputable def cyclicDataDartArc (K : BoundaryCycleData M f) (hK : K.VertexNodup)
    (p k : ℕ) (hk : 1 ≤ k) (hkL : k < K.darts.length)
    (hp : p < K.darts.length) :
    DataDartArc M K (M.tail (K.darts[p]'hp))
      (M.tail (K.darts[(p + k) % K.darts.length]'(Nat.mod_lt _ (by omega)))) where
  len := k
  len_pos := hk
  arcDart j := K.darts[(p + j.1) % K.darts.length]'(Nat.mod_lt _ (by omega))
  boundary j := List.getElem_mem _
  chain j hj := by
    set L := K.darts.length with hL
    have hLpos : 0 < L := K.darts_length_pos
    have hpos : (p + (j : ℕ)) % L < L := Nat.mod_lt _ hLpos
    have hcv := K.consecutive_vertex ⟨(p + (j : ℕ)) % L, hpos⟩
    have hcyc : (cyclicNext K.normalized.length_pos ⟨(p + (j : ℕ)) % L, hpos⟩ : Fin L)
        = ⟨(p + ((j : ℕ) + 1)) % L, Nat.mod_lt _ hLpos⟩ := by
      apply Fin.ext
      show ((p + (j : ℕ)) % L + 1) % L = (p + ((j : ℕ) + 1)) % L
      rw [Nat.mod_add_mod]
      congr 1
    rw [hcyc] at hcv
    show M.head (K.darts[(p + (j : ℕ)) % L]'_)
        = M.tail (K.darts[(p + ((j : ℕ) + 1)) % L]'_)
    rw [show (K.darts.get ⟨(p + (j : ℕ)) % L, hpos⟩) = K.darts[(p + (j : ℕ)) % L]'hpos from rfl,
      show (K.darts.get ⟨(p + ((j : ℕ) + 1)) % L, Nat.mod_lt _ hLpos⟩)
          = K.darts[(p + ((j : ℕ) + 1)) % L]'(Nat.mod_lt _ hLpos) from rfl] at hcv
    exact hcv.symm
  tail_first := by
    have hLpos : 0 < K.darts.length := K.darts_length_pos
    have heq : (p + (0 : ℕ)) % K.darts.length = p := by
      rw [Nat.add_zero, Nat.mod_eq_of_lt hp]
    show M.tail (K.darts[(p + (0 : ℕ)) % K.darts.length]'_) = M.tail (K.darts[p]'hp)
    simp only [heq]
  head_last := by
    set L := K.darts.length with hL
    have hLpos : 0 < L := K.darts_length_pos
    have hpos : (p + (k - 1)) % L < L := Nat.mod_lt _ hLpos
    have hcv := K.consecutive_vertex ⟨(p + (k - 1)) % L, hpos⟩
    have hcyc : (cyclicNext K.normalized.length_pos ⟨(p + (k - 1)) % L, hpos⟩ : Fin L)
        = ⟨(p + k) % L, Nat.mod_lt _ hLpos⟩ := by
      apply Fin.ext
      show ((p + (k - 1)) % L + 1) % L = (p + k) % L
      rw [Nat.mod_add_mod]
      congr 1
      omega
    rw [hcyc] at hcv
    show M.head (K.darts[(p + ((k : ℕ) - 1)) % L]'_) = M.tail (K.darts[(p + k) % L]'_)
    rw [show (K.darts.get ⟨(p + (k - 1)) % L, hpos⟩) = K.darts[(p + (k - 1)) % L]'hpos from rfl,
      show (K.darts.get ⟨(p + k) % L, Nat.mod_lt _ hLpos⟩)
          = K.darts[(p + k) % L]'(Nat.mod_lt _ hLpos) from rfl] at hcv
    exact hcv.symm
  tail_nodup := by
    set L := K.darts.length with hL
    have hmap : (K.darts.map M.tail).Nodup := by
      simpa [BoundaryCycleData.VertexNodup, K.vertices_eq] using hK
    intro i₁ i₂ htail
    have hi₁ : (i₁ : ℕ) < k := i₁.isLt
    have hi₂ : (i₂ : ℕ) < k := i₂.isLt
    have h1 : (p + (i₁ : ℕ)) % L < L := Nat.mod_lt _ K.darts_length_pos
    have h2 : (p + (i₂ : ℕ)) % L < L := Nat.mod_lt _ K.darts_length_pos
    have hdarts : K.darts[(p + (i₁ : ℕ)) % L]'h1 = K.darts[(p + (i₂ : ℕ)) % L]'h2 := by
      have hinj := List.inj_on_of_nodup_map hmap (List.getElem_mem h1) (List.getElem_mem h2)
      exact hinj htail
    have hpos_eq : (p + (i₁ : ℕ)) % L = (p + (i₂ : ℕ)) % L :=
      (K.normalized.nodup.getElem_inj_iff).mp hdarts
    have hi₁L0 : (i₁ : ℕ) < L := lt_of_lt_of_le hi₁ (le_of_lt hkL)
    have hi₂L0 : (i₂ : ℕ) < L := lt_of_lt_of_le hi₂ (le_of_lt hkL)
    have hmodeq : Nat.ModEq L (p + (i₁ : ℕ)) (p + (i₂ : ℕ)) := hpos_eq
    have hcancel : Nat.ModEq L (i₁ : ℕ) (i₂ : ℕ) :=
      Nat.ModEq.add_left_cancel' p hmodeq
    have hi₁L : (i₁ : ℕ) % L = (i₁ : ℕ) := Nat.mod_eq_of_lt hi₁L0
    have hi₂L : (i₂ : ℕ) % L = (i₂ : ℕ) := Nat.mod_eq_of_lt hi₂L0
    apply Fin.ext
    have := hcancel
    rw [Nat.ModEq, hi₁L, hi₂L] at this
    exact this
  head_last_ne_tail := by
    set L := K.darts.length with hL
    have hmap : (K.darts.map M.tail).Nodup := by
      simpa [BoundaryCycleData.VertexNodup, K.vertices_eq] using hK
    intro i htail
    have hi : (i : ℕ) < k := i.isLt
    have hposk : (p + k) % L < L := Nat.mod_lt _ K.darts_length_pos
    have hposi : (p + (i : ℕ)) % L < L := Nat.mod_lt _ K.darts_length_pos
    have hdarts : K.darts[(p + k) % L]'hposk = K.darts[(p + (i : ℕ)) % L]'hposi := by
      have hinj := List.inj_on_of_nodup_map hmap (List.getElem_mem hposk) (List.getElem_mem hposi)
      exact hinj htail
    have hpos_eq : (p + k) % L = (p + (i : ℕ)) % L :=
      (K.normalized.nodup.getElem_inj_iff).mp hdarts
    have hiltL : (i : ℕ) < L := lt_trans hi hkL
    have hmodeq : Nat.ModEq L (p + k) (p + (i : ℕ)) := hpos_eq
    have hcancel : Nat.ModEq L k (i : ℕ) := Nat.ModEq.add_left_cancel' p hmodeq
    have hkL' : k % L = k := Nat.mod_eq_of_lt hkL
    have hiL : (i : ℕ) % L = (i : ℕ) := Nat.mod_eq_of_lt hiltL
    rw [Nat.ModEq, hkL', hiL] at hcancel
    omega



@[simp] lemma cyclicDataDartArc_arcDart (K : BoundaryCycleData M f) (hK : K.VertexNodup)
    (p k : ℕ) (hk : 1 ≤ k) (hkL : k < K.darts.length) (hp : p < K.darts.length)
    (j : Fin k) :
    (cyclicDataDartArc K hK p k hk hkL hp).arcDart j
      = K.darts[(p + j.1) % K.darts.length]'(Nat.mod_lt _ (by omega)) := rfl

end BoundaryCycleData



section Casts

variable {M : CombMap D}

/-- Retype a `DataDartArc`'s endpoints along equalities. -/
noncomputable def daCastD {f : M.Face} {K : BoundaryCycleData M f} {a a' b b' : M.Vertex}
    (A : DataDartArc M K a b) (ha : a = a') (hb : b = b') : DataDartArc M K a' b' := ha ▸ hb ▸ A

@[simp] lemma daCastD_len {f : M.Face} {K : BoundaryCycleData M f} {a a' b b' : M.Vertex}
    (A : DataDartArc M K a b) (ha : a = a') (hb : b = b') : (daCastD A ha hb).len = A.len := by
  subst ha; subst hb; rfl

lemma daCastD_arcDart {f : M.Face} {K : BoundaryCycleData M f} {a a' b b' : M.Vertex}
    (A : DataDartArc M K a b) (ha : a = a') (hb : b = b') (i : Fin (daCastD A ha hb).len) :
    M.tail ((daCastD A ha hb).arcDart i)
      = M.tail (A.arcDart (Fin.cast (daCastD_len A ha hb) i)) := by
  subst ha; subst hb; rfl



/-- **The tail of a casted cyclic dart-arc at index `i` is the cyclic-slice tail `darts[(p+i)%L]`.** -/
lemma daCastD_cyclic_tail {f : M.Face} (K : BoundaryCycleData M f) (hK : K.VertexNodup)
    (p k : ℕ) (hk : 1 ≤ k) (hkL : k < K.darts.length) (hp : p < K.darts.length)
    {a' b' : M.Vertex}
    (ha : M.tail (K.darts[p]'hp) = a')
    (hb : M.tail (K.darts[(p + k) % K.darts.length]'(Nat.mod_lt _ (by omega))) = b')
    (i : Fin (daCastD (K.cyclicDataDartArc hK p k hk hkL hp) ha hb).len) :
    M.tail ((daCastD (K.cyclicDataDartArc hK p k hk hkL hp) ha hb).arcDart i)
      = M.tail (K.darts[(p + i.1) % K.darts.length]'(Nat.mod_lt _ (by omega))) := by
  rw [daCastD_arcDart, BoundaryCycleData.cyclicDataDartArc_arcDart]; rfl

end Casts



/-- Under `Nodup`, the last element of a list does not occur in its `dropLast`. -/
lemma getLastNotMemDropLastD {α : Type*} {l : List α} (hl : l ≠ [])
    (hnd : l.Nodup) : l.getLast hl ∉ l.dropLast := by
  have hsplit : l.dropLast ++ [l.getLast hl] = l := List.dropLast_append_getLast hl
  have hnd' : (l.dropLast ++ [l.getLast hl]).Nodup := by rw [hsplit]; exact hnd
  intro hmem
  exact (List.disjoint_of_nodup_append hnd') hmem (by simp)

/-- A generic list fact: if `l.head? = some a` and `l.Nodup`, then `a ∉ l.tail`. -/
lemma headNotMemTailD {α : Type*} {a : α} {l : List α}
    (hh : l.head? = some a) (hnd : l.Nodup) : a ∉ l.tail := by
  cases l with
  | nil => simp at hh
  | cons b t =>
      simp only [List.head?_cons, Option.some.injEq] at hh
      subst hh
      simpa using (List.nodup_cons.mp hnd).1















namespace BoundaryPath

variable {M : CombMap D} {u v : M.Vertex}



/-- An internal vertex is distinct from the initial endpoint. -/
lemma internalVertexNeStartD (P : BoundaryPath M u v) {w : M.Vertex}
    (hw : w ∈ P.internalVertices) : w ≠ u := by
  have hutail : u ∉ P.vertices.tail :=
    headNotMemTailD P.starts_at P.simple
  have hwtail : w ∈ P.vertices.tail := List.dropLast_subset _ hw
  intro hwu; subst hwu; exact hutail hwtail

/-- An internal vertex is distinct from the terminal endpoint. -/
lemma internalVertexNeEndD (P : BoundaryPath M u v) {w : M.Vertex}
    (hw : w ∈ P.internalVertices) : w ≠ v := by
  have hwtail_dropLast : w ∈ P.vertices.tail.dropLast := hw
  have htail_ne : P.vertices.tail ≠ [] := fun h => by rw [h] at hwtail_dropLast; simp at hwtail_dropLast
  have hnodup_tail : P.vertices.tail.Nodup := P.simple.sublist (List.tail_sublist _)
  have hlast_tail : P.vertices.tail.getLast htail_ne = v :=
    getLast_tail_of_getLast? P.ends_at htail_ne
  have hnotmem : P.vertices.tail.getLast htail_ne ∉ P.vertices.tail.dropLast :=
    getLastNotMemDropLastD htail_ne hnodup_tail
  intro hwv; subst hwv
  exact hnotmem (hlast_tail.symm ▸ hwtail_dropLast)

end BoundaryPath



section BPOfDartArc

variable {M : CombMap D}

/-- **The `BoundaryPath` of a dart arc.**  Its vertices are the arc-dart tails followed by the
terminal endpoint `b`; its edges are the arc-dart graph edges. -/
noncomputable def bpOfDDA {f : M.Face} {K : BoundaryCycleData M f} {a b : M.Vertex}
    (A : DataDartArc M K a b) : BoundaryPath M a b where
  vertices := A.dartList.map M.tail ++ [b]
  edges := A.dartList.map M.dartEdge
  starts_at := by
    have hne : (A.dartList.map M.tail) ≠ [] := by simp [A.dartList_ne_nil]
    have h0 : 0 < A.dartList.length := by rw [DataDartArc.dartList_length]; exact A.len_pos
    rw [List.head?_append_of_ne_nil _ hne, List.head?_map, List.head?_eq_getElem?,
      List.getElem?_eq_getElem h0, A.dartList_getElem 0 A.len_pos]
    simp only [Option.map_some]; rw [A.tail_first]
  ends_at := by simp
  simple := by
    rw [List.nodup_append]
    refine ⟨?_, by simp, ?_⟩
    · rw [DataDartArc.dartList, List.map_map, List.nodup_map_iff_inj_on (List.nodup_finRange A.len)]
      intro i _ j _ hij; exact A.tail_nodup hij
    · intro x hx y hy
      rw [List.mem_singleton] at hy; subst hy
      rw [List.mem_map] at hx
      obtain ⟨d, hd, hdt⟩ := hx
      obtain ⟨i, hi⟩ := A.mem_dartList hd
      rw [← hi] at hdt
      exact fun hxb => A.head_last_ne_tail i (hxb ▸ hdt.symm)

@[simp] lemma bpOfDDA_vertices {f : M.Face} {K : BoundaryCycleData M f} {a b : M.Vertex}
    (A : DataDartArc M K a b) : (bpOfDDA A).vertices = A.dartList.map M.tail ++ [b] := rfl



/-- The internal vertices of `bpOfDDA A` are the tails of the arc darts with index `≥ 1`. -/
lemma bpOfDDA_internal {f : M.Face} {K : BoundaryCycleData M f} {a b : M.Vertex}
    (A : DataDartArc M K a b) :
    (bpOfDDA A).internalVertices = (A.dartList.map M.tail).tail := by
  show (A.dartList.map M.tail ++ [b]).tail.dropLast = (A.dartList.map M.tail).tail
  have hne : (A.dartList.map M.tail) ≠ [] := by simp [A.dartList_ne_nil]
  rw [List.tail_append_of_ne_nil hne, List.dropLast_concat]

/-- Every vertex of `bpOfDDA A` is a tail of an arc dart, or the terminal endpoint `b`. -/
lemma bpOfDDA_mem_vertices {f : M.Face} {K : BoundaryCycleData M f} {a b : M.Vertex}
    (A : DataDartArc M K a b) {w : M.Vertex} (hw : w ∈ (bpOfDDA A).vertices) :
    (∃ i : Fin A.len, M.tail (A.arcDart i) = w) ∨ w = b := by
  rw [bpOfDDA_vertices, List.mem_append, List.mem_singleton] at hw
  rcases hw with hw | hw
  · left
    rw [List.mem_map] at hw
    obtain ⟨d, hd, hdt⟩ := hw
    obtain ⟨i, hi⟩ := A.mem_dartList hd
    exact ⟨i, hi ▸ hdt⟩
  · right; exact hw

/-- An internal vertex of `bpOfDDA A` is a tail of an arc dart. -/
lemma bpOfDDA_internal_tail {f : M.Face} {K : BoundaryCycleData M f} {a b : M.Vertex}
    (A : DataDartArc M K a b) {w : M.Vertex} (hw : w ∈ (bpOfDDA A).internalVertices) :
    ∃ i : Fin A.len, M.tail (A.arcDart i) = w := by
  rw [bpOfDDA_internal] at hw
  have hsub : w ∈ A.dartList.map M.tail := List.tail_subset _ hw
  rw [List.mem_map] at hsub
  obtain ⟨d, hd, hdt⟩ := hsub
  obtain ⟨i, hi⟩ := A.mem_dartList hd
  exact ⟨i, hi ▸ hdt⟩

/-- An arc-dart tail is a boundary vertex (`A`'s darts lie on the cycle). -/
lemma arcDartTailMemVD {f : M.Face} {K : BoundaryCycleData M f} {a b : M.Vertex}
    (A : DataDartArc M K a b) (i : Fin A.len) : M.tail (A.arcDart i) ∈ K.vertices := by
  rw [K.vertices_eq]; exact List.mem_map_of_mem (A.boundary i)

/-- Every vertex of `bpOfDDA A` is a boundary vertex, provided the terminal endpoint `b` is. -/
lemma bpOfDDA_boundary_vertices {f : M.Face} {K : BoundaryCycleData M f} {a b : M.Vertex}
    (A : DataDartArc M K a b) (hb : b ∈ K.vertices) {w : M.Vertex}
    (hw : w ∈ (bpOfDDA A).vertices) : w ∈ K.vertices := by
  rcases bpOfDDA_mem_vertices A hw with ⟨i, hi⟩ | hwb
  · rw [← hi]; exact arcDartTailMemVD A i
  · rw [hwb]; exact hb

/-- `bpOfDDA A` has an internal vertex when `2 ≤ A.len`. -/
lemma bpOfDDA_hasInternal {f : M.Face} {K : BoundaryCycleData M f} {a b : M.Vertex}
    (A : DataDartArc M K a b) (hlen : 2 ≤ A.len) : (bpOfDDA A).HasInternalVertex := by
  rw [BoundaryPath.hasInternalVertex_iff, bpOfDDA_internal]
  intro hcontra
  have hlenlist : (A.dartList.map M.tail).length = A.len := by
    rw [List.length_map, DataDartArc.dartList_length]
  have htl : (A.dartList.map M.tail).tail.length = (A.dartList.map M.tail).length - 1 :=
    List.length_tail
  rw [hcontra] at htl
  simp only [List.length_nil] at htl
  omega

end BPOfDartArc



namespace BoundaryCycleData

variable {M : CombMap D} {f : M.Face}

/-- **No `1`-step between the two endpoint positions.**  If `s(u, v)` is not a boundary
edge then the positions `p` (tail `u`) and `q` (tail `v`) cannot be cyclic-consecutive. -/
lemma not_consecutive_of_nonBoundaryEdge (K : BoundaryCycleData M f) {u v : M.Vertex}
    (hnbe : ¬ K.IsBoundaryEdge s(u, v)) {p q : ℕ}
    (hp : p < K.darts.length) (hq : q < K.darts.length)
    (htu : M.tail (K.darts[p]'hp) = u)
    (htv : M.tail (K.darts[q]'hq) = v)
    (hadj : (p + 1) % K.darts.length = q) : False := by
  set L := K.darts.length with hL
  have hLpos : 0 < L := K.darts_length_pos
  have hcv := K.consecutive_vertex ⟨p, hp⟩
  have hcyc : (cyclicNext K.normalized.length_pos ⟨p, hp⟩ : Fin L) = ⟨q, hq⟩ := by
    apply Fin.ext; show (p + 1) % L = q; exact hadj
  rw [hcyc] at hcv
  have hhead : M.head (K.darts[p]'hp) = v := by
    rw [show (K.darts.get ⟨q, hq⟩) = K.darts[q]'hq from rfl,
        show (K.darts.get ⟨p, hp⟩) = K.darts[p]'hp from rfl] at hcv
    rw [← hcv, htv]
  apply hnbe
  show s(u, v) ∈ K.edges
  rw [K.edges_eq, show (s(u, v) : Sym2 M.Vertex) = M.dartEdge (K.darts[p]'hp) from by
    show s(u, v) = s(M.tail _, M.head _); rw [htu, hhead]]
  exact List.mem_map_of_mem (List.getElem_mem hp)





end BoundaryCycleData



namespace BoundaryCycleData

variable {M : CombMap D} {f : M.Face}

/-- **The universal arc-split from `VertexNodup`, over the CORE.**  For any two distinct
listed boundary vertices `u, v` (no adjacency restriction), the two complementary cyclic
runs assemble a `BoundaryArcSplit M K.vertices K.edges u v`.  Pure list combinatorics from
simplicity. -/
noncomputable def arcSplit_of_nodup (K : BoundaryCycleData M f) (hK : K.vertices.Nodup)
    ⦃u v : M.Vertex⦄ (hne : u ≠ v)
    (hu : u ∈ K.vertices) (hv : v ∈ K.vertices) :
    BoundaryArcSplit M K.vertices K.edges u v := by
  classical
  set L := K.darts.length with hL
  have hLpos : 0 < L := K.darts_length_pos
  set puF := (K.exists_pos_of_isBoundaryVertex hu).choose with hpuF
  have eu0 := (K.exists_pos_of_isBoundaryVertex hu).choose_spec
  set pvF := (K.exists_pos_of_isBoundaryVertex hv).choose with hpvF
  have ev0 := (K.exists_pos_of_isBoundaryVertex hv).choose_spec
  set pu := puF.1 with hpuval
  set pv := pvF.1 with hpvval
  have hpu : pu < L := puF.2
  have hpv : pv < L := pvF.2
  have eu : M.tail (K.darts[pu]'hpu) = u := eu0
  have ev : M.tail (K.darts[pv]'hpv) = v := ev0
  have hpune : pu ≠ pv := by
    intro hpe; apply hne
    rw [← eu, ← ev]
    have : K.darts[pu]'hpu = K.darts[pv]'hpv := getElem_congr rfl hpe hpu
    rw [this]
  set kf := (pv + L - pu) % L with hkf
  set kb := (pu + L - pv) % L with hkb
  obtain ⟨hkf1, hkb1, hsum, hpfkf, hcov⟩ :=
    modCoverD L pu pv hLpos hpu hpv hpune kf kb hkf hkb
  obtain ⟨_, _, _, hpvkb, _⟩ :=
    modCoverD L pv pu hLpos hpv hpu (Ne.symm hpune) kb kf hkb hkf
  have hkfL : kf < L := by rw [hkf]; exact Nat.mod_lt _ hLpos
  have hkbL : kb < L := by rw [hkb]; exact Nat.mod_lt _ hLpos
  set AUV := K.cyclicDataDartArc hK pu kf hkf1 hkfL hpu with hAUV
  set AVU := K.cyclicDataDartArc hK pv kb hkb1 hkbL hpv with hAVU
  have euv2 : M.tail (K.darts[(pu + kf) % L]'(Nat.mod_lt _ (by omega))) = v := by
    have : K.darts[(pu + kf) % L]'(Nat.mod_lt _ (by omega)) = K.darts[pv]'hpv := by congr 1
    rw [this]; exact ev
  have evu2 : M.tail (K.darts[(pv + kb) % L]'(Nat.mod_lt _ (by omega))) = u := by
    have : K.darts[(pv + kb) % L]'(Nat.mod_lt _ (by omega)) = K.darts[pu]'hpu := by congr 1
    rw [this]; exact eu
  have htailUV : ∀ i : Fin (daCastD AUV eu euv2).len,
      M.tail ((daCastD AUV eu euv2).arcDart i)
        = M.tail (K.darts[(pu + i.1) % L]'(Nat.mod_lt _ (by omega))) := by
    intro i; exact daCastD_cyclic_tail K hK pu kf hkf1 hkfL hpu eu euv2 i
  have htailVU : ∀ i : Fin (daCastD AVU ev evu2).len,
      M.tail ((daCastD AVU ev evu2).arcDart i)
        = M.tail (K.darts[(pv + i.1) % L]'(Nat.mod_lt _ (by omega))) := by
    intro i; exact daCastD_cyclic_tail K hK pv kb hkb1 hkbL hpv ev evu2 i
  have htailUV_fwd : ∀ j : ℕ, (hj : j < kf) →
      ∃ i : Fin (daCastD AUV eu euv2).len,
        M.tail ((daCastD AUV eu euv2).arcDart i)
          = M.tail (K.darts[(pu + j) % L]'(Nat.mod_lt _ (by omega))) := by
    intro j hj
    have hjlen : j < (daCastD AUV eu euv2).len := by rw [daCastD_len]; exact hj
    exact ⟨⟨j, hjlen⟩, htailUV ⟨j, hjlen⟩⟩
  have htailVU_fwd : ∀ j : ℕ, (hj : j < kb) →
      ∃ i : Fin (daCastD AVU ev evu2).len,
        M.tail ((daCastD AVU ev evu2).arcDart i)
          = M.tail (K.darts[(pv + j) % L]'(Nat.mod_lt _ (by omega))) := by
    intro j hj
    have hjlen : j < (daCastD AVU ev evu2).len := by rw [daCastD_len]; exact hj
    exact ⟨⟨j, hjlen⟩, htailVU ⟨j, hjlen⟩⟩
  have htailUV_bwd : ∀ i : Fin (daCastD AUV eu euv2).len,
      ∃ j : ℕ, j < kf ∧
        M.tail ((daCastD AUV eu euv2).arcDart i)
          = M.tail (K.darts[(pu + j) % L]'(Nat.mod_lt _ (by omega))) := by
    intro i
    have hi : i.1 < kf := lt_of_lt_of_eq i.2 (daCastD_len AUV eu euv2)
    exact ⟨i.1, hi, htailUV i⟩
  have htailVU_bwd : ∀ i : Fin (daCastD AVU ev evu2).len,
      ∃ j : ℕ, j < kb ∧
        M.tail ((daCastD AVU ev evu2).arcDart i)
          = M.tail (K.darts[(pv + j) % L]'(Nat.mod_lt _ (by omega))) := by
    intro i
    have hi : i.1 < kb := lt_of_lt_of_eq i.2 (daCastD_len AVU ev evu2)
    exact ⟨i.1, hi, htailVU i⟩
  -- covering and disjointness of the two runs' tails (no length-≥2 needed)
  have hmap : (K.darts.map M.tail).Nodup := by
    have := hK; rwa [K.vertices_eq] at this
  have covering : ∀ {w : M.Vertex}, w ∈ K.vertices →
      (∃ i, M.tail ((daCastD AUV eu euv2).arcDart i) = w) ∨
      (∃ i, M.tail ((daCastD AVU ev evu2).arcDart i) = w) ∨ w = u ∨ w = v := by
    intro w hw
    obtain ⟨q, hqt⟩ := K.exists_pos_of_isBoundaryVertex hw
    rcases hcov q.1 q.2 with ⟨j, hj, hjq⟩ | ⟨j, hj, hjq⟩
    · left
      obtain ⟨i, hi⟩ := htailUV_fwd j hj
      refine ⟨i, ?_⟩
      rw [hi]
      have : K.darts[(pu + j) % L]'(Nat.mod_lt _ (by omega)) = K.darts[q.1]'q.2 :=
        getElem_congr rfl hjq _
      rw [this, hqt]
    · right; left
      obtain ⟨i, hi⟩ := htailVU_fwd j hj
      refine ⟨i, ?_⟩
      rw [hi]
      have : K.darts[(pv + j) % L]'(Nat.mod_lt _ (by omega)) = K.darts[q.1]'q.2 :=
        getElem_congr rfl hjq _
      rw [this, hqt]
  have disjoint : ∀ {w : M.Vertex},
      (∃ i, M.tail ((daCastD AUV eu euv2).arcDart i) = w) →
      (∃ i, M.tail ((daCastD AVU ev evu2).arcDart i) = w) → w = u ∨ w = v := by
    rintro w ⟨i, hiw⟩ ⟨i', hi'w⟩
    obtain ⟨j, hj, hjeq⟩ := htailUV_bwd i
    obtain ⟨j', hj', hj'eq⟩ := htailVU_bwd i'
    have heq : M.tail (K.darts[(pu + j) % L]'(Nat.mod_lt _ (by omega)))
        = M.tail (K.darts[(pv + j') % L]'(Nat.mod_lt _ (by omega))) := by
      rw [← hjeq, ← hj'eq, hiw, hi'w]
    have hposeq : (pu + j) % L = (pv + j') % L := by
      have hmem1 : K.darts[(pu + j) % L]'(Nat.mod_lt _ (by omega)) ∈ K.darts :=
        List.getElem_mem _
      have hmem2 : K.darts[(pv + j') % L]'(Nat.mod_lt _ (by omega)) ∈ K.darts :=
        List.getElem_mem _
      have hdarts : K.darts[(pu + j) % L]'(Nat.mod_lt _ (by omega))
          = K.darts[(pv + j') % L]'(Nat.mod_lt _ (by omega)) :=
        List.inj_on_of_nodup_map hmap hmem1 hmem2 heq
      exact (K.normalized.nodup.getElem_inj_iff).mp hdarts
    by_cases hj0 : j = 0
    · left
      rw [← hiw, hjeq, hj0]
      simp only [Nat.add_zero, Nat.mod_eq_of_lt hpu]
      exact eu
    · by_cases hj'0 : j' = 0
      · right
        rw [← hi'w, hj'eq, hj'0]
        simp only [Nat.add_zero, Nat.mod_eq_of_lt hpv]
        exact ev
      · exfalso
        have hpvmod : pv % L = (pu + kf) % L := by rw [hpfkf, Nat.mod_eq_of_lt hpv]
        have h2 : Nat.ModEq L pv (pu + kf) := by
          show pv % L = (pu + kf) % L; exact hpvmod
        have hcong : Nat.ModEq L (pu + j) (pu + (kf + j')) := by
          have h1 : Nat.ModEq L (pu + j) (pv + j') := hposeq
          have h3 : Nat.ModEq L (pv + j') (pu + kf + j') := h2.add_right j'
          have h4 : Nat.ModEq L (pu + j) (pu + kf + j') := h1.trans h3
          rwa [show pu + kf + j' = pu + (kf + j') from by ring] at h4
        have hcong' : Nat.ModEq L j (kf + j') := Nat.ModEq.add_left_cancel' pu hcong
        have hjlt : j < L := by omega
        have hkfj' : kf + j' < L := by omega
        have : j = kf + j' := by
          have hj1 : j % L = j := Nat.mod_eq_of_lt hjlt
          have hj2 : (kf + j') % L = kf + j' := Nat.mod_eq_of_lt hkfj'
          rw [Nat.ModEq, hj1, hj2] at hcong'; exact hcong'
        omega
  -- length-≥2 from non-adjacency (only needed inside `internal_of_proper`)
  have hkf2_of_proper : s(u, v) ∉ K.edges → 2 ≤ kf := by
    intro hnbe
    rcases Nat.lt_or_ge kf 2 with hlt | hge
    · exfalso
      have hkf1' : kf = 1 := by omega
      apply not_consecutive_of_nonBoundaryEdge K hnbe hpu hpv eu ev
      rw [show (pu + 1) % L = (pu + kf) % L from by rw [hkf1'], hpfkf]
    · exact hge
  have hkb2_of_proper : s(u, v) ∉ K.edges → 2 ≤ kb := by
    intro hnbe
    rcases Nat.lt_or_ge kb 2 with hlt | hge
    · exfalso
      have hkb1' : kb = 1 := by omega
      have hnbe' : ¬ K.IsBoundaryEdge s(v, u) := by rw [Sym2.eq_swap]; exact hnbe
      exact not_consecutive_of_nonBoundaryEdge K hnbe' hpv hpu ev eu
        (by rw [show (pv + 1) % L = (pv + kb) % L from by rw [hkb1'], hpvkb])
    · exact hge
  refine
    { path₁ := bpOfDDA (daCastD AUV eu euv2)
      path₂ := bpOfDDA (daCastD AVU ev evu2)
      path₁_boundary_vertices := fun {w} hw => bpOfDDA_boundary_vertices (daCastD AUV eu euv2) hv hw
      path₂_boundary_vertices := fun {w} hw => bpOfDDA_boundary_vertices (daCastD AVU ev evu2) hu hw
      boundary_vertices_covered := ?_
      internally_disjoint := ?_
      path₁_internal_of_proper := ?_
      path₂_internal_of_proper := ?_ }
  · intro w
    constructor
    · intro hw
      rcases covering hw with ⟨i, hi⟩ | ⟨i, hi⟩ | hwu | hwv
      · left
        rw [bpOfDDA_vertices, List.mem_append]
        refine Or.inl ?_
        rw [← hi]
        exact List.mem_map_of_mem (by
          rw [DataDartArc.dartList]; exact List.mem_map_of_mem (List.mem_finRange i))
      · right
        rw [bpOfDDA_vertices, List.mem_append]
        refine Or.inl ?_
        rw [← hi]
        exact List.mem_map_of_mem (by
          rw [DataDartArc.dartList]; exact List.mem_map_of_mem (List.mem_finRange i))
      · left
        rw [bpOfDDA_vertices, List.mem_append]
        refine Or.inl ?_
        have hu_tail : M.tail ((daCastD AUV eu euv2).arcDart (daCastD AUV eu euv2).firstIdx) = w :=
          (daCastD AUV eu euv2).tail_first.trans hwu.symm
        have hmem : M.tail ((daCastD AUV eu euv2).arcDart (daCastD AUV eu euv2).firstIdx)
            ∈ (daCastD AUV eu euv2).dartList.map M.tail :=
          List.mem_map_of_mem (by
            rw [DataDartArc.dartList]; exact List.mem_map_of_mem (List.mem_finRange _))
        exact hu_tail ▸ hmem
      · left
        rw [bpOfDDA_vertices, List.mem_append]
        exact Or.inr (by rw [hwv]; exact List.mem_singleton_self _)
    · intro hw
      rcases hw with hw | hw
      · exact bpOfDDA_boundary_vertices (daCastD AUV eu euv2) hv hw
      · exact bpOfDDA_boundary_vertices (daCastD AVU ev evu2) hu hw
  · intro w hw1 hw2
    obtain ⟨i, hi⟩ := bpOfDDA_internal_tail (daCastD AUV eu euv2) hw1
    obtain ⟨i', hi'⟩ := bpOfDDA_internal_tail (daCastD AVU ev evu2) hw2
    have hwuv : w = u ∨ w = v := disjoint ⟨i, hi⟩ ⟨i', hi'⟩
    have hwu : w ≠ u := (bpOfDDA (daCastD AUV eu euv2)).internalVertexNeStartD hw1
    have hwv : w ≠ v := (bpOfDDA (daCastD AUV eu euv2)).internalVertexNeEndD hw1
    rcases hwuv with h' | h'
    · exact hwu h'
    · exact hwv h'
  · intro hnbe
    exact bpOfDDA_hasInternal (daCastD AUV eu euv2)
      (by rw [daCastD_len]; exact hkf2_of_proper hnbe)
  · intro hnbe
    exact bpOfDDA_hasInternal (daCastD AVU ev evu2)
      (by rw [daCastD_len]; exact hkb2_of_proper hnbe)

/-- **Promote a core + `VertexNodup` to a full `BoundaryCycle`** (the `arcSplit`
certificate is derived from simplicity by `arcSplit_of_nodup`). -/
noncomputable def toBoundaryCycle (K : BoundaryCycleData M f) (hK : K.vertices.Nodup) :
    BoundaryCycle M f :=
  { toBoundaryCycleData := K
    arcSplit := fun u v hne hu hv => K.arcSplit_of_nodup hK hne hu hv }

end BoundaryCycleData

end CombMap

end ProofsInTheBook.PlanarMap





end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFanFaces
import ProofsInTheBook.PlanarMapBoundaryArcSplit
-/
/- Source module: ProofsInTheBook.PlanarMapDeletedBoundary -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



/-- The explicit cyclic dart list of a face's `φ`-orbit, rooted at `root`:
`[root, φ root, φ² root, …]`. -/
def faceDartList (M : CombMap D) (root : D) : List D :=
  M.φ.toList root

/-- The face dart list enumerates exactly the face orbit. -/
lemma faceDartList_toFinset (M : CombMap D) (f : M.Face) {root : D}
    (hφ : M.φ root ≠ root) (hroot : M.dartFace root = f) :
    (M.faceDartList root).toFinset = faceOrbitFinset M f := by
  classical
  have hsupp : root ∈ M.φ.support := by simpa [Equiv.Perm.mem_support] using hφ
  ext d
  rw [List.mem_toFinset, mem_faceOrbitFinset_iff, faceDartList,
    Equiv.Perm.mem_toList_iff]
  constructor
  · rintro ⟨hsc, _⟩
    rw [← hroot]
    exact (Quotient.sound hsc.symm : M.dartFace d = M.dartFace root)
  · intro hdf
    refine ⟨?_, hsupp⟩
    exact Quotient.exact (show M.dartFace root = M.dartFace d by rw [hroot, hdf])

/-- The face dart list is nonempty when the orbit is nontrivial. -/
lemma faceDartList_length_pos (M : CombMap D) {root : D} (hφ : M.φ root ≠ root) :
    0 < (M.faceDartList root).length := by
  have hsupp : root ∈ M.φ.support := by simpa [Equiv.Perm.mem_support] using hφ
  exact Equiv.Perm.length_toList_pos_of_mem_support _ _ hsupp

/-- `getElem` of the face dart list is `φ`-iterate of the root. -/
lemma faceDartList_getElem (M : CombMap D) (root : D) (n : ℕ)
    (hn : n < (M.faceDartList root).length) :
    (M.faceDartList root)[n] = (M.φ ^ n) root :=
  Equiv.Perm.getElem_toList _ _ _ _

/-- The head of the face dart list is the root. -/
lemma faceDartList_head (M : CombMap D) {root : D} (hφ : M.φ root ≠ root) :
    (M.faceDartList root).head? = some root := by
  have hsupp : root ∈ M.φ.support := by simpa [Equiv.Perm.mem_support] using hφ
  have h0 : (M.faceDartList root)[0]'(M.faceDartList_length_pos hφ) = root := by
    have := M.faceDartList_getElem root 0 (M.faceDartList_length_pos hφ)
    simpa using this
  rw [List.head?_eq_getElem?,
    List.getElem?_eq_getElem (M.faceDartList_length_pos hφ), h0]

/-- The normalized cyclic dart list certificate for the face orbit. -/
lemma faceDartList_normalized (M : CombMap D) (f : M.Face) {root : D}
    (hφ : M.φ root ≠ root) (hroot : M.dartFace root = f) :
    NormalizedCyclicDartList M f root (M.faceDartList root) where
  head_eq := M.faceDartList_head hφ
  root_face := hroot
  nodup := Equiv.Perm.nodup_toList _ _
  length_pos := M.faceDartList_length_pos hφ
  toFinset_eq := M.faceDartList_toFinset f hφ hroot

/-- The `φ`-orbit length is the support cardinal of the root's cycle; the dart at
the cyclic-next index is the `φ`-image of the dart at the current index. -/
lemma faceDartList_consecutive_phi (M : CombMap D) {root : D} (hφ : M.φ root ≠ root)
    (i : Fin (M.faceDartList root).length) :
    (M.faceDartList root).get
        (cyclicNext (M.faceDartList_length_pos hφ) i) =
      M.φ ((M.faceDartList root).get i) := by
  classical
  have hlen : (M.faceDartList root).length = (M.φ.cycleOf root).support.card := by
    simp only [faceDartList, Equiv.Perm.length_toList]
  -- `(φ^n) root = root` where `n` is the list length.
  have hcycle : (M.φ ^ (M.faceDartList root).length) root = root := by
    have hself := Equiv.Perm.pow_mod_card_support_cycleOf_self_apply M.φ
      (M.faceDartList root).length root
    rw [hlen, Nat.mod_self, pow_zero] at hself
    rw [hlen]; exact hself.symm
  -- `(φ^n)^k root = root`.
  have hpow : ∀ k : ℕ, ((M.φ ^ (M.faceDartList root).length) ^ k) root = root := by
    intro k
    induction k with
    | zero => simp
    | succ k ih => rw [pow_succ', Equiv.Perm.coe_mul, Function.comp_apply, ih, hcycle]
  -- The cyclicNext index value.
  have hnext_val : ((cyclicNext (M.faceDartList_length_pos hφ) i :
      Fin (M.faceDartList root).length) : ℕ)
      = ((i : ℕ) + 1) % (M.faceDartList root).length := rfl
  rw [List.get_eq_getElem, List.get_eq_getElem,
    M.faceDartList_getElem root i i.2]
  rw [M.faceDartList_getElem root
    ((cyclicNext (M.faceDartList_length_pos hφ) i : Fin (M.faceDartList root).length) : ℕ)
    (cyclicNext (M.faceDartList_length_pos hφ) i).2]
  rw [hnext_val]
  -- `(φ ^ ((i+1) % n)) root = φ ((φ ^ i) root)`.
  have hmod : (M.φ ^ (((i : ℕ) + 1) % (M.faceDartList root).length)) root
      = (M.φ ^ ((i : ℕ) + 1)) root := by
    have hsplit : (i : ℕ) + 1
        = ((i : ℕ) + 1) % (M.faceDartList root).length
          + (M.faceDartList root).length * (((i : ℕ) + 1) / (M.faceDartList root).length) := by
      rw [Nat.add_comm, Nat.mod_add_div]
    conv_rhs => rw [hsplit]
    rw [pow_add, pow_mul, Equiv.Perm.coe_mul, Function.comp_apply, hpow]
  rw [hmod, pow_succ', Equiv.Perm.coe_mul, Function.comp_apply]

/-- Consecutive face darts match at the common boundary vertex. -/
lemma faceDartList_consecutive_vertex (M : CombMap D) {root : D} (hφ : M.φ root ≠ root)
    (i : Fin (M.faceDartList root).length) :
    M.tail ((M.faceDartList root).get
        (cyclicNext (M.faceDartList_length_pos hφ) i)) =
      M.head ((M.faceDartList root).get i) := by
  rw [M.faceDartList_consecutive_phi hφ i, tail_phi]

/-- **Generic normalized boundary cycle from a single nontrivial face orbit.**
The explicit cyclic dart list is `[root, φ root, φ² root, …]`; all orbit-algebraic
fields are discharged, and the Jordan-arc split `arcSplit` is now DERIVED from boundary
simplicity (`hnodup`) via `BoundaryCycleData.toBoundaryCycle` — it is no longer a
parameter (`ZinanCh35ArcSplitUniversal` / `PlanarMapBoundaryArcSplit`). -/
noncomputable def boundaryCycleOfFace (M : CombMap D) (f : M.Face) {root : D}
    (hφ : M.φ root ≠ root) (hroot : M.dartFace root = f)
    (hnodup : ((M.faceDartList root).map M.tail).Nodup) :
    BoundaryCycle M f :=
  BoundaryCycleData.toBoundaryCycle
    { root := root
      darts := M.faceDartList root
      vertices := (M.faceDartList root).map M.tail
      edges := (M.faceDartList root).map M.dartEdge
      normalized := M.faceDartList_normalized f hφ hroot
      vertices_eq := rfl
      edges_eq := rfl
      consecutive_phi := M.faceDartList_consecutive_phi hφ
      consecutive_vertex := M.faceDartList_consecutive_vertex hφ }
    hnodup

namespace NearTriangulation

variable {M : CombMap D} {hNT : NearTriangulation M} {v0 : M.Vertex}



/-- The deleted map's `φ'` has no fixed dart (it is a simple graph). -/
lemma deleteVertex_phi_ne_self (hNT : NearTriangulation M) (d0 : D)
    (x : {d : D // d ∉ M.deleteVertexSet d0}) :
    (M.deleteVertex d0).φ x ≠ x :=
  phi_ne_self_of_isSimpleGraph (M.deleteVertex d0)
    (hNT.deleteVertex_isSimpleGraph d0) x






namespace DeletedMergedBoundaryCertificate

variable {d0 : D}











end DeletedMergedBoundaryCertificate









end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFanMergedOrbit
import ProofsInTheBook.PlanarMapDeletedBoundary
-/
/- Source module: ProofsInTheBook.PlanarMapOuterArc -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace NearTriangulation

variable {M : CombMap D} {hNT : NearTriangulation M} {v0 : M.Vertex}


structure MergedOuterArcData (M : CombMap D) (d0 : D)
    (r : {d : D // d ∉ M.deleteVertexSet d0}) (outerFace : M.Face) where
  /-- The exit survivor `o_pre`: the last surviving dart of the outer arc. -/
  exit : {d : D // d ∉ M.deleteVertexSet d0}
  /-- The exit dart lies on the old outer face. -/
  exit_face : M.dartFace exit.1 = outerFace
  /-- Its immediate `M.φ`-successor (the in-boundary dart `bin`) is deleted. -/
  exit_next_deleted : M.φ exit.1 ∈ M.deleteVertexSet d0
  /-- The Case-B closed-form successor of `exit` is the reference triangle dart
  `r`: the seam reconnection from the outer arc into the fan-triangle chain. -/
  exit_jump : M.σ (M.φ exit.1) = r.1
  /-- Every surviving outer dart reaches `exit` along a contiguous forward
  `M.φ`-run of survivors (the surviving outer arc is one `M.φ`-block). -/
  arc_run : ∀ x : {d : D // d ∉ M.deleteVertexSet d0}, M.dartFace x.1 = outerFace →
    ∃ k : ℕ, (∀ j ≤ k, (M.φ ^ j) x.1 ∉ M.deleteVertexSet d0) ∧
      (M.φ ^ k) x.1 = exit.1

namespace MergedOuterArcData

variable {d0 : D} {r : {d : D // d ∉ M.deleteVertexSet d0}} {outerFace : M.Face}

/-- The `φ'`-successor of the exit survivor is the reference dart `r`: the single
Case-B seam jump from the surviving outer arc into the fan-triangle chain. -/
lemma phi'_exit (data : MergedOuterArcData M d0 r outerFace) :
    ((M.deleteVertex d0).φ data.exit : D) = r.1 := by
  have hsurv : M.σ (M.φ data.exit.1) ∉ M.deleteVertexSet d0 := by
    rw [data.exit_jump]; exact r.2
  rw [deleteVertex_phi_apply_of_next_deleted M d0 data.exit
      data.exit_next_deleted hsurv, data.exit_jump]

/-- The exit survivor is in the `φ'`-cycle of the reference dart `r`. -/
lemma sameCycle_exit (data : MergedOuterArcData M d0 r outerFace) :
    (M.deleteVertex d0).φ.SameCycle r data.exit := by
  have hexit_r : (M.deleteVertex d0).φ.SameCycle data.exit r := by
    refine ⟨1, ?_⟩
    apply Subtype.ext
    rw [zpow_one]
    exact data.phi'_exit
  exact hexit_r.symm

/-- **The outer-arc reconnection from the data.**  Every surviving dart on the old
outer face is `φ'`-`SameCycle` to the reference dart `r`: walk the contiguous
surviving arc forward with `deleteVertex_phi_survRun_iterate` to the exit
survivor, then take the single Case-B seam jump to `r`.  No further planar input
is consumed — all `φ'` machinery is the already-proved
`PlanarMapFanMergedOrbit` calculus. -/
theorem mergedOuterArcReconnects (data : MergedOuterArcData M d0 r outerFace) :
    MergedOuterArcReconnects M d0 r outerFace := by
  intro x hx
  obtain ⟨k, hrun, hk⟩ := data.arc_run x hx
  -- x reaches data.exit along the surviving arc.
  have hxexit : (M.deleteVertex d0).φ.SameCycle x data.exit :=
    deleteVertex_phi_sameCycle_of_survRun M d0 x data.exit k hrun hk
  -- r ~ exit (seam jump) and x ~ exit (arc run); compose to r ~ x.
  exact data.sameCycle_exit.trans hxexit.symm

end MergedOuterArcData





/-- **The merged-face single-orbit fact from the actual seam edge.**  The
`MergedOuterArcData.exit_jump` equality must be stated at the concrete fan edge
where the old outer arc enters the fan chain.  The fan-chain calculus then
transports that entry point to the head reference internally. -/
theorem deleteVertexMergedFaceSingleOrbit_of_fan_of_outerArc_edge
    (fan : BoundaryVertexFan hNT v0) (hchord : BoundaryChordless hNT.outerCycle)
    {d0 : D} (htail0 : M.tail d0 = v0)
    (r : {d : D // d ∉ M.deleteVertexSet d0}) (hr : FanTriangleEdge fan r)
    (data : MergedOuterArcData M d0 r hNT.outerFace) :
    DeleteVertexMergedFaceSingleOrbit M d0 :=
  deleteVertexMergedFaceSingleOrbit_of_fan_from_edge fan hchord htail0 r hr
    data.mergedOuterArcReconnects









end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapOuterArc
-/
/- Source module: ProofsInTheBook.PlanarMapFanExistence -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



/-- The explicit cyclic dart list of the `σ`-orbit (vertex star) of `v`. -/
def vertexDartList (M : CombMap D) (v : D) : List D :=
  M.σ.toList v

/-- The vertex dart list is nonempty when the `σ`-orbit is nontrivial. -/
lemma vertexDartList_length_pos (M : CombMap D) {v : D} (hσ : M.σ v ≠ v) :
    0 < (M.vertexDartList v).length := by
  have hsupp : v ∈ M.σ.support := by simpa [Equiv.Perm.mem_support] using hσ
  exact Equiv.Perm.length_toList_pos_of_mem_support _ _ hsupp

/-- `getElem` of the vertex dart list is the `σ`-iterate of `v`. -/
lemma vertexDartList_getElem (M : CombMap D) (v : D) (n : ℕ)
    (hn : n < (M.vertexDartList v).length) :
    (M.vertexDartList v)[n] = (M.σ ^ n) v :=
  Equiv.Perm.getElem_toList _ _ _ _

/-- The head of the vertex dart list is `v`. -/
lemma vertexDartList_head (M : CombMap D) {v : D} (hσ : M.σ v ≠ v) :
    (M.vertexDartList v).head? = some v := by
  have h0 : (M.vertexDartList v)[0]'(M.vertexDartList_length_pos hσ) = v := by
    have := M.vertexDartList_getElem v 0 (M.vertexDartList_length_pos hσ)
    simpa using this
  rw [List.head?_eq_getElem?,
    List.getElem?_eq_getElem (M.vertexDartList_length_pos hσ), h0]

/-- The vertex dart list has no repeats. -/
lemma vertexDartList_nodup (M : CombMap D) (v : D) :
    (M.vertexDartList v).Nodup :=
  Equiv.Perm.nodup_toList _ _

/-- Membership in the vertex dart list is `σ`-`SameCycle` with `v`. -/
lemma mem_vertexDartList_iff (M : CombMap D) {v : D} (hσ : M.σ v ≠ v) (d : D) :
    d ∈ M.vertexDartList v ↔ M.σ.SameCycle v d := by
  have hsupp : v ∈ M.σ.support := by simpa [Equiv.Perm.mem_support] using hσ
  rw [vertexDartList, Equiv.Perm.mem_toList_iff]
  exact ⟨fun h => h.1, fun h => ⟨h, hsupp⟩⟩



/-- Each dart of the vertex list has the same tail as `v`. -/
lemma vertexDartList_tail (M : CombMap D) {v : D} (hσ : M.σ v ≠ v)
    {d : D} (hd : d ∈ M.vertexDartList v) :
    M.tail d = M.tail v := by
  have hsame : M.σ.SameCycle v d := (mem_vertexDartList_iff M hσ d).mp hd
  exact (Quotient.sound hsame.symm : M.tail d = M.tail v)

/-- The `σ`-cube/closure power identity: `(σ ^ n) v = v` where `n` is the list
length.  Mirror of the `faceDartList` argument. -/
lemma vertexDartList_pow_length (M : CombMap D) {v : D} (_hσ : M.σ v ≠ v) :
    (M.σ ^ (M.vertexDartList v).length) v = v := by
  have hlen : (M.vertexDartList v).length = (M.σ.cycleOf v).support.card := by
    simp only [vertexDartList, Equiv.Perm.length_toList]
  have hself := Equiv.Perm.pow_mod_card_support_cycleOf_self_apply M.σ
    (M.vertexDartList v).length v
  rw [hlen, Nat.mod_self, pow_zero] at hself
  rw [hlen]; exact hself.symm

/-- **`consecutive_sigma` for the vertex dart list.**  The dart at the cyclic-next
index is the `σ`-image of the dart at the current index.  Exact mirror of
`faceDartList_consecutive_phi`. -/
lemma vertexDartList_consecutive_sigma (M : CombMap D) {v : D} (hσ : M.σ v ≠ v)
    (i : Fin (M.vertexDartList v).length) :
    (M.vertexDartList v).get
        (cyclicNext (M.vertexDartList_length_pos hσ) i) =
      M.σ ((M.vertexDartList v).get i) := by
  classical
  have hcycle : (M.σ ^ (M.vertexDartList v).length) v = v :=
    M.vertexDartList_pow_length hσ
  have hpow : ∀ k : ℕ, ((M.σ ^ (M.vertexDartList v).length) ^ k) v = v := by
    intro k
    induction k with
    | zero => simp
    | succ k ih => rw [pow_succ', Equiv.Perm.coe_mul, Function.comp_apply, ih, hcycle]
  have hnext_val : ((cyclicNext (M.vertexDartList_length_pos hσ) i :
      Fin (M.vertexDartList v).length) : ℕ)
      = ((i : ℕ) + 1) % (M.vertexDartList v).length := rfl
  rw [List.get_eq_getElem, List.get_eq_getElem,
    M.vertexDartList_getElem v i i.2]
  rw [M.vertexDartList_getElem v
    ((cyclicNext (M.vertexDartList_length_pos hσ) i : Fin (M.vertexDartList v).length) : ℕ)
    (cyclicNext (M.vertexDartList_length_pos hσ) i).2]
  rw [hnext_val]
  have hmod : (M.σ ^ (((i : ℕ) + 1) % (M.vertexDartList v).length)) v
      = (M.σ ^ ((i : ℕ) + 1)) v := by
    have hsplit : (i : ℕ) + 1
        = ((i : ℕ) + 1) % (M.vertexDartList v).length
          + (M.vertexDartList v).length * (((i : ℕ) + 1) / (M.vertexDartList v).length) := by
      rw [Nat.add_comm, Nat.mod_add_div]
    conv_rhs => rw [hsplit]
    rw [pow_add, pow_mul, Equiv.Perm.coe_mul, Function.comp_apply, hpow]
  rw [hmod, pow_succ', Equiv.Perm.coe_mul, Function.comp_apply]

namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)







/-- **The neighbour rotation order from the vertex dart list.**  Given a dart `d0`
at `v0` with nontrivial `σ`-orbit, and a proof that the head list of its
`σ`-rotation equals a given neighbour list, the `NeighborRotationOrder` certificate
is assembled. -/
def neighborRotationOrderOfVertexDartList {v0 : M.Vertex} {d0 : D}
    (hσ : M.σ d0 ≠ d0) (htail0 : M.tail d0 = v0)
    (neighbors : List M.Vertex)
    (hheads : (M.vertexDartList d0).map M.head = neighbors) :
    NeighborRotationOrder M v0 neighbors where
  darts := M.vertexDartList d0
  darts_nodup := M.vertexDartList_nodup d0
  darts_nonempty := M.vertexDartList_length_pos hσ
  tails_eq := by
    rw [List.eq_replicate_iff]
    refine ⟨by simp, ?_⟩
    intro v hv
    rcases List.mem_map.mp hv with ⟨d, hd, rfl⟩
    rw [M.vertexDartList_tail hσ hd, htail0]
  heads_eq := hheads
  consecutive_sigma := M.vertexDartList_consecutive_sigma hσ



/-- Two distinct darts at the same vertex have distinct heads, in a simple graph. -/
lemma head_injOn_sameCycle (hNT : NearTriangulation M) {v0 : M.Vertex} {d e : D}
    (hd : M.tail d = v0) (he : M.tail e = v0)
    (hhead : M.head d = M.head e) : d = e := by
  have hsame : M.α.SameCycle d e :=
    M.alpha_sameCycle_of_same_endpoints hNT.simpleGraph (hd.trans he.symm) hhead
  rcases (M.alpha_sameCycle_iff d e).mp hsame with rfl | rfl
  · rfl
  · exfalso
    apply hNT.simpleGraph.no_loop d
    -- `e = α d`, so `head e = head (α d) = tail d`; with `head d = head e`, `d` loops.
    have hhd : M.head (M.α d) = M.tail d := by simp
    rw [hhead, hhd]

/-- The fan path (heads of the `σ`-rotation rooted at `d0`) is simple, from graph
simplicity alone. -/
lemma vertexDartList_heads_nodup (hNT : NearTriangulation M) {v0 : M.Vertex} {d0 : D}
    (hσ : M.σ d0 ≠ d0) (htail0 : M.tail d0 = v0) :
    ((M.vertexDartList d0).map M.head).Nodup := by
  rw [List.nodup_map_iff_inj_on (M.vertexDartList_nodup d0)]
  intro d hd e he hhead
  exact head_injOn_sameCycle hNT
    ((M.vertexDartList_tail hσ hd).trans htail0)
    ((M.vertexDartList_tail hσ he).trans htail0) hhead



/-- The isolated fan-incidence datum at a boundary vertex `v0`: the planar
orientation residue from which the full `BoundaryVertexFan` is assembled. -/
structure FanIncidenceData {M : CombMap D} (hNT : NearTriangulation M)
    (v0 : M.Vertex) where
  /-- The outgoing boundary spoke at `v0`. -/
  d0 : D
  /-- Its `σ`-orbit (the star of `v0`) is nontrivial. -/
  sigma_ne : M.σ d0 ≠ d0
  /-- `d0` has tail `v0`. -/
  tail0 : M.tail d0 = v0
  /-- The exposed-path endpoints and interior fan vertices. -/
  x : M.Vertex
  interior : List M.Vertex
  w : M.Vertex
  /-- The head list of the `σ`-rotation rooted at `d0` is exactly the fan path. -/
  heads_eq : (M.vertexDartList d0).map M.head = fanPath x interior w
  /-- `v0` is a boundary vertex. -/
  v0_boundary : hNT.outerCycle.IsBoundaryVertex v0
  /-- `x` is a boundary vertex. -/
  x_boundary : hNT.outerCycle.IsBoundaryVertex x
  /-- `w` is a boundary vertex. -/
  w_boundary : hNT.outerCycle.IsBoundaryVertex w
  /-- The exact face-incidence certificate: the non-outer faces at `v0` are exactly
  the consecutive fan triangles along the path. -/
  incident_faces_exact :
    IncidentNonOuterFacesExactly hNT v0 (fanPath x interior w)
  /-- Chordless ⟹ interior fan vertices are not old boundary vertices. -/
  interior_not_boundary_of_chordless :
    BoundaryChordless hNT.outerCycle →
      ∀ z : M.Vertex, z ∈ interior → ¬ hNT.outerCycle.IsBoundaryVertex z
  /-- Chordless ⟹ empty interior characterizes the base triangle. -/
  empty_iff_base_triangle_of_chordless :
    BoundaryChordless hNT.outerCycle → (interior = [] ↔ hNT.IsBaseTriangle)

variable {hNT}

/-- **Assemble the boundary-vertex fan from the incidence datum.**  The
`NeighborRotationOrder` field is discharged constructively from the `σ`-rotation
list `vertexDartList d0`; the remaining (orientation / Jordan) fields come from the
datum. -/
def boundaryVertexFan_of_incidenceData {v0 : M.Vertex}
    (data : FanIncidenceData hNT v0) :
    BoundaryVertexFan hNT v0 where
  x := data.x
  interior := data.interior
  w := data.w
  v0_boundary := data.v0_boundary
  x_boundary := data.x_boundary
  w_boundary := data.w_boundary
  rotation_order :=
    neighborRotationOrderOfVertexDartList data.sigma_ne data.tail0
      (fanPath data.x data.interior data.w) data.heads_eq
  incident_faces_exact := data.incident_faces_exact
  path_nodup_of_chordless := fun _ => by
    rw [← data.heads_eq]
    exact vertexDartList_heads_nodup hNT data.sigma_ne data.tail0
  interior_not_boundary_of_chordless := data.interior_not_boundary_of_chordless
  empty_iff_base_triangle_of_chordless := data.empty_iff_base_triangle_of_chordless



/-- **The extreme-spoke / outer-neighbour tie (construction byproduct).**  The
first fan endpoint `x` is exactly the head of the rooting spoke `d0`, i.e. `d0` is
the spoke landing on the first fan neighbour.  This is the dart-level tie between
the extreme fan spoke and `v0`'s outer-cycle dart that the `MergedOuterArcData`
seam reconnection consumes (the `α`-pairing of the extreme spokes with the two
outer-cycle darts at `v0`). -/
theorem fan_first_spoke_head {v0 : M.Vertex} (data : FanIncidenceData hNT v0) :
    data.x = M.head data.d0 := by
  have hhd : (M.vertexDartList data.d0).head? = some data.d0 :=
    M.vertexDartList_head data.sigma_ne
  have hmap : ((M.vertexDartList data.d0).map M.head).head?
      = some (M.head data.d0) := by
    rw [List.head?_map, hhd, Option.map_some]
  rw [data.heads_eq] at hmap
  -- `fanPath x interior w` has head `x`.
  have : (fanPath data.x data.interior data.w).head? = some data.x := by
    simp [fanPath]
  rw [this] at hmap
  exact (Option.some.injEq _ _).mp hmap.symm ▸ rfl









end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.ThomassenLists
import ProofsInTheBook.PlanarMapFanExistence
-/
/- Source module: ProofsInTheBook.ThomassenInduction -/
section
set_option autoImplicit true




namespace ProofsInTheBook.ThomassenInduction

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ListColoring
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap

universe u





/-- The chordless-branch oracle datum: all the boundary-deletion Jordan data for a
chosen deletion site `v0`, the boundary neighbour of `p` distinct from `q`.

It carries the fan-incidence datum (which *constructs* the fan), chordlessness, the
merged-outer-arc supplier, and the merged-outer-boundary cycle — exactly the inputs
of `deleteBoundaryVertex_nearTriangulation_of_incidenceData`.  Plus the two reserved
colors `γ, δ ∈ L v0` and the bookkeeping facts the deletion list transport needs
(the precolored endpoint `p = fan.x` avoids `γ, δ` once colored, and `x, w ≠ v0`).

The `v0`-relation to `p, q` is recorded so the extension reconnects the precolored
edge. -/
structure ChordlessOracle {D : Type u} [Fintype D] [DecidableEq D] {α : Type u}
    [DecidableEq α] {M : CombMap D} (hNT : NearTriangulation M)
    (p q : M.Vertex) (L : M.Vertex → Finset α) (cp cq : α) : Type u where
  /-- The boundary is chordless. -/
  chordless : BoundaryChordless hNT.outerCycle
  /-- The deletion site `v0`: the boundary neighbour of `p` distinct from `q`. -/
  v0 : M.Vertex
  /-- The fan incidence datum at `v0` (constructs the fan). -/
  fanData : NearTriangulation.FanIncidenceData hNT v0
  /-- The dart-level fan-surgery reconstruction at `d0` (the boundary-deletion Jordan
  data: the vertex-quotient equivalence, the merged outer face, the new boundary
  cycle, and the inner-triangle preservation). -/
  recon : NearTriangulation.FanSurgeryReconstruction hNT fanData.d0
  /-- `d0` represents `v0`. -/
  hd0 : Quotient.mk (cycleSetoid M.σ) fanData.d0 = v0
  /-- The two reserved colors. -/
  γ : α
  /-- The two reserved colors. -/
  δ : α
  γ_mem : γ ∈ L v0
  δ_mem : δ ∈ L v0
  γδ_ne : γ ≠ δ
  /-- The fan endpoints differ from `v0`. -/
  x_ne : (NearTriangulation.boundaryVertexFan_of_incidenceData fanData).x ≠ v0
  w_ne : (NearTriangulation.boundaryVertexFan_of_incidenceData fanData).w ≠ v0
  /-- The first fan endpoint is one of the precolored endpoints, and that endpoint's
  precolored color avoids the two reserved colors. -/
  x_precolored :
    ((NearTriangulation.boundaryVertexFan_of_incidenceData fanData).x = p ∧
      cp ≠ γ ∧ cp ≠ δ) ∨
    ((NearTriangulation.boundaryVertexFan_of_incidenceData fanData).x = q ∧
      cq ≠ γ ∧ cq ≠ δ)
  /-- **The deletion's boundary bookkeeping (the one isolated Jordan residue).**  The
  deleted near-triangulation, with the fan-deleted lists, again satisfies the
  Thomassen list hypotheses for *some* precolored boundary edge.  This is the
  exact-list relabeling of the review's Case 2: `p, q` stay precolored singletons,
  the exposed fan vertices `z_i` (interior `≥ 5`) become boundary `≥ 3` after losing
  `γ, δ`, every surviving old boundary vertex keeps `≥ 3`, every surviving interior
  vertex keeps `≥ 5`.  It is supplied by the oracle because the new-boundary vertex
  labelling is the deletion's Jordan-curve bookkeeping that the combinatorial-map
  layer does not synthesize.  The existential over the precolored edge is all the
  recursion needs (the extension step `deleteBoundaryVertex_listColorable` consumes
  *any* `deleteFanLists`-coloring, independently of which edge was precolored). -/
  deleted_lists : ∃ (p' q' : (M.deleteVertex fanData.d0).Vertex) (cp' cq' : α),
    ThomassenLists recon.nearTriangulation p' q'
      (deleteFanLists M fanData.d0
        (NearTriangulation.boundaryVertexFan_of_incidenceData fanData).interior.toFinset
        L γ δ) cp' cq'





section Base

variable {D : Type u} [Fintype D] [DecidableEq D] {α : Type u} [DecidableEq α]
variable {M : CombMap D} {hNT : NearTriangulation M}
variable {p q : M.Vertex} {L : M.Vertex → Finset α} {cp cq : α}



end Base



section Chord

variable {D : Type u} [Fintype D] [DecidableEq D] {α : Type u} [DecidableEq α]
variable {M : CombMap D} {hNT : NearTriangulation M}
variable {p q : M.Vertex} {L : M.Vertex → Finset α} {cp cq : α}



end Chord



section Chordless

variable {D : Type u} [Fintype D] [DecidableEq D] {α : Type u} [DecidableEq α]
variable {M : CombMap D} {hNT : NearTriangulation M}
variable {p q : M.Vertex} {L : M.Vertex → Finset α} {cp cq : α}

/-- The fan built from the chordless oracle datum. -/
noncomputable def codFan (cod : ChordlessOracle hNT p q L cp cq) :
    NearTriangulation.BoundaryVertexFan hNT cod.v0 :=
  NearTriangulation.boundaryVertexFan_of_incidenceData cod.fanData

/-- The deleted near-triangulation produced by the chordless oracle datum (via the
dart-level fan-surgery reconstruction). -/
noncomputable def deletedNT (cod : ChordlessOracle hNT p q L cp cq) :
    NearTriangulation (M.deleteVertex cod.fanData.d0) :=
  cod.recon.nearTriangulation



/-- The fan-deleted lists for the chordless oracle datum. -/
noncomputable def codLists (cod : ChordlessOracle hNT p q L cp cq) :
    (M.deleteVertex cod.fanData.d0).Vertex → Finset α :=
  deleteFanLists M cod.fanData.d0 (codFan cod).interior.toFinset L cod.γ cod.δ







end Chordless



section Induction

variable {α : Type u} [DecidableEq α]

/-- A near-triangulation has at least three vertices: the outer cycle has length
`≥ 3` and a simple (nodup) vertex list, so it exhibits `≥ 3` distinct vertices. -/
theorem three_le_V {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
    (hNT : NearTriangulation M) : 3 ≤ M.V := by
  classical
  have hnodup : hNT.outerCycle.vertices.Nodup := hNT.outer_simple
  have hlen : 3 ≤ hNT.outerCycle.vertices.length := by
    rw [hNT.outerCycle.vertices_length]; exact hNT.outer_len
  have hcard : 3 ≤ hNT.outerCycle.vertices.toFinset.card := by
    rw [List.toFinset_card_of_nodup hnodup]; exact hlen
  calc 3 ≤ hNT.outerCycle.vertices.toFinset.card := hcard
    _ ≤ Fintype.card M.Vertex := Finset.card_le_univ _
    _ = M.V := rfl





end Induction



section Corollaries

variable {D : Type u} [Fintype D] [DecidableEq D] {α : Type u} [DecidableEq α]
variable {M : CombMap D}





end Corollaries



section FiveColor

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D}



end FiveColor

end ProofsInTheBook.ThomassenInduction

end

/- Original source header (imports hoisted):
import ProofsInTheBook.ThomassenInduction
import ProofsInTheBook.PlanarMapChordSplit
import ProofsInTheBook.PlanarMapSeparation
-/
/- Source module: ProofsInTheBook.ChordSplitNT -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ChordSplitNT

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ListColoring
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ThomassenInduction

universe u



variable {D : Type u} [Fintype D] [DecidableEq D] {α : Type u} [DecidableEq α]
variable {M : CombMap D} {hNT : NearTriangulation M}

/-- The reconstruction datum for ONE side of a chord split, relative to a side
region `s ⊆ M.Vertex` and side lists.  `Dₛ` is the side dart type (in the surgery,
`keptSideᵢ ⊕ Fin 2`).

The structure isolates the Jordan/Euler outputs that the combinatorial-map layer
cannot synthesize, exactly as `FanSurgeryReconstruction` does for the chordless
branch:

* `N` — the side as a near-triangulation (carries `IsSphereMap`/genus-0);
* `ι` — the side-vertex-to-`M` correspondence, injective and adjacency-reflecting
  *onto* the region `s` (`ι_surj`), so it is a graph isomorphism `N ≃ M⟦s⟧`;
* `ι_lists` — the side near-triangulation's lists are the pullback of `L` along
  `ι`, so a list coloring of `N` transports to a region coloring of `M`;
* `smaller` — strict vertex decrease, the recursion fuel.

`Lₛ` and the precolored data (`pₛ qₛ cpₛ cqₛ`) are the side's Thomassen inputs. -/
structure ChordSideReconstruction (hNT : NearTriangulation M)
    (s : Set M.Vertex) (L : M.Vertex → Finset α) where
  /-- The side dart type. -/
  Dₛ : Type u
  /-- Side dart type is a fintype. -/
  [fintypeDₛ : Fintype Dₛ]
  /-- Side dart type has decidable equality. -/
  [decEqDₛ : DecidableEq Dₛ]
  /-- The side combinatorial map. -/
  N : CombMap Dₛ
  /-- The side is a near-triangulation (carries `IsSphereMap`: genus-0/Euler-2). -/
  hN : NearTriangulation N
  /-- The side-vertex-to-`M`-vertex correspondence. -/
  ι : N.Vertex → M.Vertex
  /-- The correspondence is injective. -/
  ι_inj : Function.Injective ι
  /-- The correspondence lands in the region. -/
  ι_mem : ∀ x : N.Vertex, ι x ∈ s
  /-- The correspondence is *surjective onto the region* (the side-vertex
  classification: every region vertex is a side vertex). -/
  ι_surj : ∀ ⦃w : M.Vertex⦄, w ∈ s → ∃ x : N.Vertex, ι x = w
  /-- The correspondence carries side adjacency to `M`-adjacency (graph hom). -/
  ι_adj : ∀ ⦃x y : N.Vertex⦄, N.toSimpleGraph.Adj x y →
    M.toSimpleGraph.Adj (ι x) (ι y)
  /-- The correspondence *reflects* `M`-adjacency on the region (graph iso onto the
  induced subgraph): two side vertices adjacent in `M` are adjacent in `N`. -/
  ι_adj_reflect : ∀ ⦃x y : N.Vertex⦄, M.toSimpleGraph.Adj (ι x) (ι y) →
    N.toSimpleGraph.Adj x y
  /-- The side lists are the pullback of `L` along `ι`. -/
  Lₛ : N.Vertex → Finset α
  /-- The pullback identity for the side lists. -/
  Lₛ_eq : ∀ x : N.Vertex, Lₛ x = L (ι x)
  /-- The side's precolored boundary edge. -/
  pₛ : N.Vertex
  /-- The side's precolored boundary edge. -/
  qₛ : N.Vertex
  /-- The side's precolors. -/
  cpₛ : α
  /-- The side's precolors. -/
  cqₛ : α
  /-- The side near-triangulation carries the Thomassen list hypotheses, so the
  Thomassen induction can recurse on it.  (This is part of the list transport the
  classification produces alongside the correspondence.) -/
  hLₛ : ThomassenLists hN pₛ qₛ Lₛ cpₛ cqₛ
  /-- Strict vertex decrease (the recursion fuel). -/
  smaller : N.V < M.V

attribute [instance] ChordSideReconstruction.fintypeDₛ ChordSideReconstruction.decEqDₛ

namespace ChordSideReconstruction

variable {s : Set M.Vertex} {L : M.Vertex → Finset α}

/-- The section `M`-region `→` side vertex: the inverse of `ι` on the region.
Built classically from surjectivity + injectivity. -/
noncomputable def section_ (R : ChordSideReconstruction hNT s L)
    {w : M.Vertex} (hw : w ∈ s) : R.N.Vertex :=
  (R.ι_surj hw).choose





open scoped Classical in
/-- The region coloring of `M`: at a region vertex use `c` of the section; off the
region use an arbitrary fixed value (irrelevant — `ProperOn`/`ListValidOn` only
look at the region). -/
noncomputable def colorRegion (R : ChordSideReconstruction hNT s L)
    (c : R.N.Vertex → α) (default : α) : M.Vertex → α :=
  fun w => if hw : w ∈ s then c (R.section_ hw) else default









end ChordSideReconstruction



/-- The chord recursion datum: the `ChordSplitRegions` glue object, the side-1
reconstruction on its region (lists `L`), and — for *every* possible side-1
coloring `c₁` agreeing with the precolored edge — a side-2 reconstruction on its
region whose lists are the side-1-forced lists `forcedLists c₁ L`.  Making `R₂` a
function of `c₁` is faithful to Thomassen's order (color side 1, *then* force the
chord endpoints `u, v`, then color side 2): the side-2 datum genuinely depends on
the side-1 result, and the forcing makes the two recursive colorings agree at
`u, v` automatically. -/
structure ChordRecursionData (hNT : NearTriangulation M)
    (u v p q : M.Vertex) (L : M.Vertex → Finset α) (cp cq : α) where
  /-- The `M`-vertex-level chord split regions. -/
  regions : ChordSplitRegions hNT u v p q L cp cq
  /-- The chord endpoints are distinct (an edge of `M`). -/
  uv_ne : u ≠ v
  /-- The side-1 reconstruction (region `s₁`, lists `L`). -/
  R₁ : ChordSideReconstruction hNT regions.s₁ L
  /-- For each side-1 coloring `c₁` with distinct chord-endpoint colors, a side-2
  reconstruction whose region is `s₂`
  and whose lists are the chord-endpoint-forced lists `forcedLists c₁ L`.  This
  encodes "force `u, v` to the side-1 colors, then color side 2 by recursion". -/
  R₂ : (c₁ : M.Vertex → α) → c₁ u ≠ c₁ v → ChordSideReconstruction hNT regions.s₂
    (regions.forcedLists c₁ L)

namespace ChordRecursionData

variable {u v p q : M.Vertex} {L : M.Vertex → Finset α} {cp cq : α}



/-- The side-1 region coloring, produced by recursing on the side-1 near-
triangulation.  `ih` is the strong-induction hypothesis (every map with `< M.V`
vertices and the Thomassen lists is colorable). -/
noncomputable def color₁ (data : ChordRecursionData hNT u v p q L cp cq)
    (default : α)
    (ih : ∀ (m : ℕ), m < M.V → ∀ {Dₛ : Type u} [Fintype Dₛ] [DecidableEq Dₛ]
      {N : CombMap Dₛ} (hN : NearTriangulation N) (pₛ qₛ : N.Vertex)
      (Lₛ : N.Vertex → Finset α) (cpₛ cqₛ : α), N.V ≤ m →
      ThomassenLists hN pₛ qₛ Lₛ cpₛ cqₛ → ListColorable N.toSimpleGraph Lₛ) :
    M.Vertex → α := by
  classical
  -- recurse on side 1.
  have hcol₁ : ListColorable data.R₁.N.toSimpleGraph data.R₁.Lₛ :=
    ih data.R₁.N.V data.R₁.smaller data.R₁.hN data.R₁.pₛ data.R₁.qₛ data.R₁.Lₛ
      data.R₁.cpₛ data.R₁.cqₛ le_rfl data.R₁.hLₛ
  exact data.R₁.colorRegion hcol₁.choose default





end ChordRecursionData



/-- The chord-recursive dichotomy: for every near-triangulation with the Thomassen
lists, either a chord **recursion datum** (carrying the two smaller side near-
triangulations, NO colorings) or a chordless oracle datum.  This is strictly weaker
input than `ThomassenInduction.JordanOracle`: the chord branch no longer carries the
side colorings `c₁, c₂` — they are produced by recursion. -/
structure ChordRecursiveDichotomy (α : Type u) [DecidableEq α] : Type (u + 1) where
  /-- The dichotomy. -/
  decide :
    ∀ {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
      (hNT : NearTriangulation M) (p q : M.Vertex) (L : M.Vertex → Finset α)
      (cp cq : α),
      3 < M.V → ThomassenLists hNT p q L cp cq →
        (Σ' u v : M.Vertex, ChordRecursionData hNT u v p q L cp cq) ⊕
          ChordlessOracle hNT p q L cp cq







/-- `ChordRecursionData` is genuinely inhabited from its components: the regions,
the chord-endpoint distinctness, a side-1 reconstruction, and a side-2
reconstruction family.  This is the constructor, recorded to certify the datum is
not a hidden `False` (the §3.3 non-vacuity check). -/
def ChordRecursionData.ofComponents {u v p q : M.Vertex} {L : M.Vertex → Finset α}
    {cp cq : α}
    (regions : ChordSplitRegions hNT u v p q L cp cq) (uv_ne : u ≠ v)
    (R₁ : ChordSideReconstruction hNT regions.s₁ L)
    (R₂ : (c₁ : M.Vertex → α) → c₁ u ≠ c₁ v →
      ChordSideReconstruction hNT regions.s₂ (regions.forcedLists c₁ L)) :
    ChordRecursionData hNT u v p q L cp cq :=
  { regions := regions, uv_ne := uv_ne, R₁ := R₁, R₂ := R₂ }



end ProofsInTheBook.ChordSplitNT









end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSplitNT
-/
/- Source module: ProofsInTheBook.ChordSplitEuler -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ChordSplitEuler

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation

universe u

variable {K : Type u} [Fintype K] [DecidableEq K]





/-- **The edge count of a fresh map** is `(|K| + 2) / 2`, and in particular
`2 · E(freshMap) = |K| + 2`.  Proved purely from `freshAlpha` being a
fixed-point-free involution (`2E = |D|`). -/
theorem freshMap_two_mul_E (β ρ : Equiv.Perm K) (hβinv : β * β = 1)
    (hβfix : ∀ k, β k ≠ k) (a₀ a₁ : K) (hne : a₀ ≠ a₁) :
    2 * (freshMap β ρ hβinv hβfix a₀ a₁ hne).E = Fintype.card K + 2 := by
  rw [(freshMap β ρ hβinv hβfix a₀ a₁ hne).two_mul_E_eq_card]
  simp [Fintype.card_sum, Fintype.card_fin]



section VertexCount

variable (ρ : Equiv.Perm K) {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- The projection collapsing each fresh dart to its anchor:
`inl k ↦ k`, `inr 0 ↦ a₀`, `inr 1 ↦ a₁`. -/
def proj (a₀ a₁ : K) : K ⊕ Fin 2 → K
  | Sum.inl k => k
  | Sum.inr j => if j = 0 then a₀ else a₁

@[simp] lemma proj_inl (k : K) : proj a₀ a₁ (Sum.inl k) = k := rfl
@[simp] lemma proj_inr_zero : proj a₀ a₁ (Sum.inr 0) = a₀ := rfl
@[simp] lemma proj_inr_one : proj a₀ a₁ (Sum.inr 1) = a₁ := by
  simp [proj]

/-- Every fresh dart is in the same fresh `σ`-orbit as the `inl` of its anchor
projection.  (The fresh darts `inr 0`, `inr 1` sit immediately after `a₀`, `a₁`.) -/
lemma freshSigma_sameCycle_inl_proj (x : K ⊕ Fin 2) :
    (freshSigma ρ a₀ a₁ hne).SameCycle x (Sum.inl (proj a₀ a₁ x)) := by
  cases x with
  | inl k => simpa using Equiv.Perm.SameCycle.rfl
  | inr j =>
      -- the two fresh darts sit immediately after their anchors.
      have key : ∀ (c : K) (jj : Fin 2),
          freshSigma ρ a₀ a₁ hne (Sum.inl c) = Sum.inr jj →
          (freshSigma ρ a₀ a₁ hne).SameCycle (Sum.inr jj) (Sum.inl c) := by
        intro c jj h
        exact ⟨-1, by rw [zpow_neg, zpow_one, Equiv.Perm.inv_eq_iff_eq, h]⟩
      fin_cases j
      · have h : freshSigma ρ a₀ a₁ hne (Sum.inl a₀) = Sum.inr 0 :=
          freshSigma_anchor_zero ρ a₀ a₁ hne
        have hc := key a₀ 0 h
        simpa using hc
      · have h : freshSigma ρ a₀ a₁ hne (Sum.inl a₁) = Sum.inr 1 :=
          freshSigma_anchor_one ρ a₀ a₁ hne
        have hc := key a₁ 1 h
        simpa using hc

/-- **One fresh `σ`-step projects to one `ρ`-step (or stays put).**  Applying
`freshSigma` to `inl k` lands in the same `ρ`-orbit as `ρ k`; more precisely, the
projections of `x` and `freshSigma x` are `ρ`-SameCycle. -/
lemma ρ_sameCycle_proj_freshSigma_apply (x : K ⊕ Fin 2) :
    ρ.SameCycle (proj a₀ a₁ x) (proj a₀ a₁ (freshSigma ρ a₀ a₁ hne x)) := by
  cases x with
  | inl k =>
      by_cases h0 : k = a₀
      · rw [h0, freshSigma_anchor_zero ρ a₀ a₁ hne]
        simp only [proj_inl, proj_inr_zero]
        exact Equiv.Perm.SameCycle.rfl
      · by_cases h1 : k = a₁
        · rw [h1, freshSigma_anchor_one ρ a₀ a₁ hne]
          simp only [proj_inl, proj_inr_one]
          exact Equiv.Perm.SameCycle.rfl
        · rw [freshSigma_other ρ a₀ a₁ hne h0 h1]
          simp only [proj_inl]
          exact ⟨1, by rw [zpow_one]⟩
  | inr j =>
      fin_cases j
      · show ρ.SameCycle (proj a₀ a₁ (Sum.inr 0))
          (proj a₀ a₁ (freshSigma ρ a₀ a₁ hne (Sum.inr 0)))
        rw [freshSigma_fresh_zero ρ a₀ a₁ hne]
        simp only [proj_inr_zero, proj_inl]
        exact ⟨1, by rw [zpow_one]⟩
      · show ρ.SameCycle (proj a₀ a₁ (Sum.inr 1))
          (proj a₀ a₁ (freshSigma ρ a₀ a₁ hne (Sum.inr 1)))
        rw [freshSigma_fresh_one ρ a₀ a₁ hne, proj_inr_one]
        simp only [proj_inl]
        exact ⟨1, by rw [zpow_one]⟩

/-- The projections of `x` and `(freshSigma)^[n] x` are always `ρ`-SameCycle. -/
lemma ρ_sameCycle_proj_freshSigma_iterate (x : K ⊕ Fin 2) (n : ℕ) :
    ρ.SameCycle (proj a₀ a₁ x) (proj a₀ a₁ ((freshSigma ρ a₀ a₁ hne)^[n] x)) := by
  induction n with
  | zero => simpa using Equiv.Perm.SameCycle.rfl
  | succ n ih =>
      rw [Function.iterate_succ_apply']
      exact ih.trans (ρ_sameCycle_proj_freshSigma_apply ρ hne _)

/-- **Forward: a fresh `σ`-cycle projects into one `ρ`-cycle.** -/
lemma ρ_sameCycle_proj_of_freshSigma_sameCycle {x y : K ⊕ Fin 2}
    (h : (freshSigma ρ a₀ a₁ hne).SameCycle x y) :
    ρ.SameCycle (proj a₀ a₁ x) (proj a₀ a₁ y) := by
  obtain ⟨m, hm⟩ := h.exists_nat_pow_eq
  rw [← hm, Equiv.Perm.coe_pow]
  exact ρ_sameCycle_proj_freshSigma_iterate ρ hne x m

/-- **Backward: `inl` of `ρ`-equal anchors are fresh-`σ`-SameCycle.**  If `a` and
`b` are `ρ`-SameCycle then `inl a` and `inl b` are fresh-`σ`-SameCycle.  We trace
the `ρ`-power into a fresh-`σ`-power that visits the same `inl` darts. -/
lemma freshSigma_sameCycle_inl_of_ρ_sameCycle {a b : K} (h : ρ.SameCycle a b) :
    (freshSigma ρ a₀ a₁ hne).SameCycle (Sum.inl a) (Sum.inl b) := by
  -- It suffices to handle one `ρ`-step `b = ρ a` and chain.
  -- `freshSigma`-SameCycle to the `inl` of the `ρ`-successor:
  have step : ∀ c : K, (freshSigma ρ a₀ a₁ hne).SameCycle (Sum.inl c) (Sum.inl (ρ c)) := by
    intro c
    by_cases h0 : c = a₀
    · -- `inl a₀ → inr 0 → inl (ρ a₀)`: two `freshSigma` steps.
      refine ⟨2, ?_⟩
      rw [show (2 : ℤ) = ((2 : ℕ) : ℤ) from rfl, zpow_natCast, sq, Equiv.Perm.mul_apply, h0,
        freshSigma_anchor_zero ρ a₀ a₁ hne, freshSigma_fresh_zero ρ a₀ a₁ hne]
    · by_cases h1 : c = a₁
      · refine ⟨2, ?_⟩
        rw [show (2 : ℤ) = ((2 : ℕ) : ℤ) from rfl, zpow_natCast, sq, Equiv.Perm.mul_apply, h1,
          freshSigma_anchor_one ρ a₀ a₁ hne, freshSigma_fresh_one ρ a₀ a₁ hne]
      · refine ⟨1, ?_⟩
        rw [zpow_one]
        exact freshSigma_other ρ a₀ a₁ hne h0 h1
  -- now chain the single steps along the `ρ`-power.
  obtain ⟨m, hm⟩ := h.exists_nat_pow_eq
  rw [← hm, Equiv.Perm.coe_pow]
  clear hm
  induction m with
  | zero => simpa using Equiv.Perm.SameCycle.rfl
  | succ m ih =>
      rw [Function.iterate_succ_apply']
      exact ih.trans (step _)

/-- **The fresh `σ`-cycle / `ρ`-cycle correspondence.**  Two darts are in the same
fresh `σ`-orbit iff their anchor projections are in the same `ρ`-orbit. -/
theorem freshSigma_sameCycle_iff (x y : K ⊕ Fin 2) :
    (freshSigma ρ a₀ a₁ hne).SameCycle x y ↔ ρ.SameCycle (proj a₀ a₁ x) (proj a₀ a₁ y) := by
  constructor
  · exact ρ_sameCycle_proj_of_freshSigma_sameCycle ρ hne
  · intro h
    -- `x ~ inl (π x) ~ inl (π y) ~ y`.
    refine (freshSigma_sameCycle_inl_proj ρ hne x).trans ?_
    refine (freshSigma_sameCycle_inl_of_ρ_sameCycle ρ hne h).trans ?_
    exact (freshSigma_sameCycle_inl_proj ρ hne y).symm

/-- The `σ`-orbit quotient of the fresh map is in bijection with the `ρ`-orbit
quotient of the kept rotation, via the anchor projection `proj`. -/
noncomputable def freshSigma_vertexQuotientEquiv :
    Quotient (cycleSetoid (freshSigma ρ a₀ a₁ hne)) ≃ Quotient (cycleSetoid ρ) := by
  classical
  -- the descended map `[x] ↦ [proj x]` and its inverse `[k] ↦ [inl k]`.
  refine
    { toFun := Quotient.lift (fun x => Quotient.mk (cycleSetoid ρ) (proj a₀ a₁ x)) ?_,
      invFun := Quotient.lift (fun k => Quotient.mk (cycleSetoid (freshSigma ρ a₀ a₁ hne))
        (Sum.inl k)) ?_,
      left_inv := ?_, right_inv := ?_ }
  · -- well-defined forward: SameCycle x y ⇒ SameCycle (proj x) (proj y).
    intro x y hxy
    apply Quotient.sound
    exact (freshSigma_sameCycle_iff ρ hne x y).1 hxy
  · -- well-defined inverse: ρ.SameCycle a b ⇒ freshSigma.SameCycle (inl a) (inl b).
    intro a b hab
    apply Quotient.sound
    exact freshSigma_sameCycle_inl_of_ρ_sameCycle ρ hne hab
  · -- left inverse: `[inl (proj x)] = [x]`.
    intro q
    refine Quotient.inductionOn q (fun x => ?_)
    apply Quotient.sound
    exact (freshSigma_sameCycle_inl_proj ρ hne x).symm
  · -- right inverse: `[proj (inl k)] = [k]`.
    intro q
    refine Quotient.inductionOn q (fun k => ?_)
    simp only [Quotient.lift_mk, proj_inl]

/-- **The vertex count of a fresh-dart adjunction equals the kept rotation's
vertex count.**  Splicing the two fresh darts into existing `σ`-orbits neither
creates nor destroys an orbit, so `V(freshMap β ρ …) = numCycles ρ`. -/
theorem freshMap_V (β : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).V
      = Fintype.card (Quotient (cycleSetoid ρ)) := by
  show Fintype.card (Quotient (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ)) = _
  rw [show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ = freshSigma ρ a₀ a₁ hne from rfl]
  exact Fintype.card_congr (freshSigma_vertexQuotientEquiv ρ hne)

end VertexCount



section EulerReduction

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- **The honest isolated face count for a fresh-dart adjunction.**  The genus-0
content: the face (`σα`-orbit) count of the fresh map is `(|K|+2)/2 - numCycles ρ
+ 2`, i.e. exactly `E - V + 2`.  Equivalently `2·F = |K| + 2 - 2·V + 4`.  In the
chord split this is the per-side identity `F₁ + F₂ = F + 1` (the chord adds one
shared boundary face to each side).  Stated as a `Prop` because it is the single
remaining Jordan/Euler input (see the section docstring); it is *not* derivable for
generic `β, ρ, a₀, a₁`. -/
def FreshFaceCount : Prop :=
  2 * (freshMap β ρ hβinv hβfix a₀ a₁ hne).F
    = Fintype.card K + 6 - 2 * Fintype.card (Quotient (cycleSetoid ρ))

/-- **The genus-0 reduction.**  Given the proved `V` and `E` counts, the fresh
map's Euler characteristic is `2` **iff** the single face count `FreshFaceCount`
holds.  This pins the genus-0 preservation `eulerChar = 2` to one face-orbit
count, retiring the `V` and `E` counts entirely. -/
theorem freshMap_eulerChar_eq_two_iff_faceCount
    (hV : Fintype.card (Quotient (cycleSetoid ρ)) ≤ (Fintype.card K + 2) / 2 + 1) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).eulerChar = 2 ↔
      FreshFaceCount β ρ hβinv hβfix hne := by
  unfold CombMap.eulerChar FreshFaceCount
  have hE : 2 * (freshMap β ρ hβinv hβfix a₀ a₁ hne).E = Fintype.card K + 2 :=
    freshMap_two_mul_E β ρ hβinv hβfix a₀ a₁ hne
  have hVeq : (freshMap β ρ hβinv hβfix a₀ a₁ hne).V
      = Fintype.card (Quotient (cycleSetoid ρ)) :=
    freshMap_V ρ hne β hβinv hβfix
  rw [hVeq]
  constructor
  · intro heuler
    -- from `V - E + F = 2` (ℤ), multiply through by 2 and use `2E = |K|+2`.
    have hZ : 2 * (Fintype.card (Quotient (cycleSetoid ρ)) : ℤ)
        - 2 * ((freshMap β ρ hβinv hβfix a₀ a₁ hne).E : ℤ)
        + 2 * ((freshMap β ρ hβinv hβfix a₀ a₁ hne).F : ℤ) = 4 := by linarith [heuler]
    have hEZ : 2 * ((freshMap β ρ hβinv hβfix a₀ a₁ hne).E : ℤ)
        = (Fintype.card K : ℤ) + 2 := by exact_mod_cast hE
    have hgoalZ : 2 * ((freshMap β ρ hβinv hβfix a₀ a₁ hne).F : ℤ)
        = (Fintype.card K : ℤ) + 6
          - 2 * (Fintype.card (Quotient (cycleSetoid ρ)) : ℤ) := by linarith [hZ, hEZ]
    -- transfer to ℕ subtraction.
    omega
  · intro hface
    -- from `2F = |K| + 6 - 2V` (ℕ truncated), recover the ℤ Euler identity.
    have hEZ : 2 * ((freshMap β ρ hβinv hβfix a₀ a₁ hne).E : ℤ)
        = (Fintype.card K : ℤ) + 2 := by exact_mod_cast hE
    -- `2V ≤ |K| + 6` so the ℕ subtraction is exact.
    have hle : 2 * Fintype.card (Quotient (cycleSetoid ρ)) ≤ Fintype.card K + 6 := by
      have : (Fintype.card K + 2) / 2 * 2 ≤ Fintype.card K + 2 := Nat.div_mul_le_self _ _
      omega
    have hfaceZ : 2 * ((freshMap β ρ hβinv hβfix a₀ a₁ hne).F : ℤ)
        = (Fintype.card K : ℤ) + 6
          - 2 * (Fintype.card (Quotient (cycleSetoid ρ)) : ℤ) := by
      have := hface
      zify [hle] at this
      linarith [this]
    linarith [hfaceZ, hEZ]

end EulerReduction



section ChordApplication

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}













end ChordApplication



section NonVacuity













end NonVacuity

end ProofsInTheBook.ChordSplitEuler











end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSplitEuler
-/
/- Source module: ProofsInTheBook.ChordSideRecon -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ChordSideRecon

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler

universe u

variable {K : Type u} [Fintype K] [DecidableEq K]



section Connectivity

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- The **kept combinatorial map** on `K` with edge involution `β`, rotation `ρ`.
This is the side map *before* the fresh chord edge is spliced in; its connectivity
is the side's connectivity. -/
def keptCombMap (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k) :
    CombMap K where
  α := β
  σ := ρ
  α_invol := hβinv
  α_no_fixed := hβfix




/-- A `dartStep` of the kept map lifts to a `dartStep` of the fresh map on the
`inl` darts. -/
lemma freshMap_dartStep_inl_of_kept {x y : K}
    (h : (keptCombMap β ρ hβinv hβfix).dartStep x y) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartStep (Sum.inl x) (Sum.inl y) := by
  rcases h with hσ | hα
  · -- same σ-cycle in `ρ` ⇒ same `freshSigma`-cycle (by `freshSigma_sameCycle_iff`).
    left
    show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ.SameCycle (Sum.inl x) (Sum.inl y)
    rw [show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ = freshSigma ρ a₀ a₁ hne from rfl]
    rw [freshSigma_sameCycle_iff ρ hne]
    simpa using hσ
  · -- `y = β x` ⇒ `inl y = freshAlpha β (inl x)`.
    right
    show Sum.inl y = (freshMap β ρ hβinv hβfix a₀ a₁ hne).α (Sum.inl x)
    rw [show (freshMap β ρ hβinv hβfix a₀ a₁ hne).α = freshAlpha β from rfl, freshAlpha_inl]
    rw [hα]; rfl

/-- Each `inl k` reaches every `inl`-image of a kept-map `dartStep` chain. -/
lemma freshMap_reach_inl_of_kept {x y : K}
    (h : Relation.ReflTransGen (keptCombMap β ρ hβinv hβfix).dartStep x y) :
    Relation.ReflTransGen (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartStep
      (Sum.inl x) (Sum.inl y) := by
  induction h with
  | refl => exact Relation.ReflTransGen.refl
  | tail _ hstep ih =>
      exact ih.tail (freshMap_dartStep_inl_of_kept β ρ hβinv hβfix hne hstep)

/-- The fresh dart `inr 0` reaches `inl (ρ a₀)` in one σ-step. -/
lemma freshMap_reach_inr_zero :
    Relation.ReflTransGen (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartStep
      (Sum.inr 0) (Sum.inl (ρ a₀)) := by
  refine Relation.ReflTransGen.single (Or.inl ?_)
  show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ.SameCycle (Sum.inr 0) (Sum.inl (ρ a₀))
  rw [show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ = freshSigma ρ a₀ a₁ hne from rfl]
  exact ⟨1, by rw [zpow_one, freshSigma_fresh_zero ρ a₀ a₁ hne]⟩

/-- The fresh dart `inr 1` reaches `inl (ρ a₁)` in one σ-step. -/
lemma freshMap_reach_inr_one :
    Relation.ReflTransGen (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartStep
      (Sum.inr 1) (Sum.inl (ρ a₁)) := by
  refine Relation.ReflTransGen.single (Or.inl ?_)
  show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ.SameCycle (Sum.inr 1) (Sum.inl (ρ a₁))
  rw [show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ = freshSigma ρ a₀ a₁ hne from rfl]
  exact ⟨1, by rw [zpow_one, freshSigma_fresh_one ρ a₀ a₁ hne]⟩

/-- **Connectivity of the fresh map** (proved purely): if the kept map `(β, ρ)` is
connected, then so is the fresh map.  The two fresh darts attach to the existing
darts by one σ-step each (and to each other by an α-step), so reachability of the
kept darts lifts and the fresh darts join in. -/
theorem freshMap_connected_of_kept
    (hconn : (keptCombMap β ρ hβinv hβfix).Connected) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).Connected := by
  classical
  -- reach from any `inl x` to any `inl y` lifts from the kept connectivity.
  have reach_inl : ∀ x y : K, Relation.ReflTransGen
      (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartStep (Sum.inl x) (Sum.inl y) :=
    fun x y => freshMap_reach_inl_of_kept β ρ hβinv hβfix hne (hconn x y)
  -- reach from `inr j` to any `inl y`: go to `inl (ρ aⱼ)`, then lift.
  have reach_inr_inl : ∀ (j : Fin 2) (y : K), Relation.ReflTransGen
      (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartStep (Sum.inr j) (Sum.inl y) := by
    intro j y
    fin_cases j
    · exact (freshMap_reach_inr_zero β ρ hβinv hβfix hne).trans (reach_inl (ρ a₀) y)
    · exact (freshMap_reach_inr_one β ρ hβinv hβfix hne).trans (reach_inl (ρ a₁) y)
  -- reach from any `inl x` to any `inr j`: go to `inl (ρ aⱼ)`'s reverse via α back.
  -- easier: `inl x → inl (ρ a₀) → inr 0 → inr 1`.  Use α-step `inr 0 = α (inr 1)`? Build directly.
  have reach_inl_inr_zero : ∀ x : K, Relation.ReflTransGen
      (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartStep (Sum.inl x) (Sum.inr 0) := by
    intro x
    -- `inl x → inl a₀ → inr 0` (the anchor σ-step `freshSigma (inl a₀) = inr 0`).
    refine (reach_inl x a₀).tail (Or.inl ?_)
    show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ.SameCycle (Sum.inl a₀) (Sum.inr 0)
    rw [show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ = freshSigma ρ a₀ a₁ hne from rfl]
    exact ⟨1, by rw [zpow_one, freshSigma_anchor_zero ρ a₀ a₁ hne]⟩
  have reach_inl_inr_one : ∀ x : K, Relation.ReflTransGen
      (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartStep (Sum.inl x) (Sum.inr 1) := by
    intro x
    refine (reach_inl x a₁).tail (Or.inl ?_)
    show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ.SameCycle (Sum.inl a₁) (Sum.inr 1)
    rw [show (freshMap β ρ hβinv hβfix a₀ a₁ hne).σ = freshSigma ρ a₀ a₁ hne from rfl]
    exact ⟨1, by rw [zpow_one, freshSigma_anchor_one ρ a₀ a₁ hne]⟩
  intro a b
  cases a with
  | inl x =>
      cases b with
      | inl y => exact reach_inl x y
      | inr j => fin_cases j
                 · exact reach_inl_inr_zero x
                 · exact reach_inl_inr_one x
  | inr i =>
      cases b with
      | inl y => exact reach_inr_inl i y
      | inr j =>
          fin_cases i <;> fin_cases j
          · exact Relation.ReflTransGen.refl
          · exact (reach_inr_inl 0 a₁).trans (reach_inl_inr_one a₁)
          · exact (reach_inr_inl 1 a₀).trans (reach_inl_inr_zero a₀)
          · exact Relation.ReflTransGen.refl

end Connectivity



section SphereAssembly

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)



end SphereAssembly



section ChordApplication

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

/-- The kept combinatorial map of side 1 (before the fresh chord splice): edge
involution `sideAlpha₁`, rotation `sideSigma₁`.  Its connectivity is side 1's
connectivity. -/
noncomputable def sideKeptMap₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    CombMap {d : D // d ∉ data.keptDel₁} :=
  keptCombMap (data.sideAlpha₁ hsep) data.sideSigma₁
    (data.sideAlpha₁_involutive hsep) (data.sideAlpha₁_no_fixed hsep)

/-- The kept combinatorial map of side 2. -/
noncomputable def sideKeptMap₂ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    CombMap {d : D // d ∉ data.keptDel₂} :=
  keptCombMap (data.sideAlpha₂ hsep) data.sideSigma₂
    (data.sideAlpha₂_involutive hsep) (data.sideAlpha₂_no_fixed hsep)





end ChordApplication



section JordanData

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  (a₀ a₁ : K) (hne : a₀ ≠ a₁)





end JordanData



section NonVacuity







end NonVacuity

end ProofsInTheBook.ChordSideRecon











end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFilteredRotation
import ProofsInTheBook.PlanarMapSeparation
-/
/- Source module: ProofsInTheBook.PlanarMapCutCap -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



/-- A simple directed primal cycle of length `len` in `M`: a `Fin len`-indexed
family of darts whose source vertices are pairwise distinct and whose heads chain
to the next source. -/
structure SimplePrimalCycle (M : CombMap D) where
  /-- Length of the cycle (number of darts/edges). -/
  len : ℕ
  /-- The cycle has length at least three (no loops, no digons; faithful to a
  *simple* primal cycle in a simple graph). -/
  len_ge : 3 ≤ len
  /-- The directed cycle darts `d_0, …, d_{len-1}`. -/
  dart : Fin len → D
  /-- Simplicity: the source vertices are pairwise distinct. -/
  tail_inj : Function.Injective (fun i => M.tail (dart i))
  /-- Consecutive incidence: the head of `d_i` is the tail of `d_{i+1}`
  (cyclically). -/
  consecutive : ∀ i : Fin len,
    M.head (dart i) = M.tail (dart ⟨(i.1 + 1) % len, Nat.mod_lt _ (by omega)⟩)

namespace SimplePrimalCycle

variable {M : CombMap D}

lemma len_pos (C : SimplePrimalCycle M) : 0 < C.len := by have := C.len_ge; omega

/-- Cyclic successor index. -/
def nextIdx (C : SimplePrimalCycle M) (i : Fin C.len) : Fin C.len :=
  ⟨(i.1 + 1) % C.len, Nat.mod_lt _ C.len_pos⟩

/-- Cyclic predecessor index. -/
def prevIdx (C : SimplePrimalCycle M) (i : Fin C.len) : Fin C.len :=
  ⟨(i.1 + (C.len - 1)) % C.len, Nat.mod_lt _ C.len_pos⟩

@[simp]
lemma nextIdx_val (C : SimplePrimalCycle M) (i : Fin C.len) :
    (C.nextIdx i).1 = (i.1 + 1) % C.len := rfl

@[simp]
lemma prevIdx_val (C : SimplePrimalCycle M) (i : Fin C.len) :
    (C.prevIdx i).1 = (i.1 + (C.len - 1)) % C.len := rfl

lemma nextIdx_prevIdx (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.nextIdx (C.prevIdx i) = i := by
  apply Fin.ext
  simp only [nextIdx_val, prevIdx_val]
  have hk : 0 < C.len := C.len_pos
  rw [Nat.mod_add_mod]
  have : i.1 + (C.len - 1) + 1 = i.1 + C.len := by omega
  rw [this, Nat.add_mod_right, Nat.mod_eq_of_lt i.isLt]

lemma prevIdx_nextIdx (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.prevIdx (C.nextIdx i) = i := by
  apply Fin.ext
  simp only [nextIdx_val, prevIdx_val]
  have hk : 0 < C.len := C.len_pos
  rw [Nat.mod_add_mod]
  have : i.1 + 1 + (C.len - 1) = i.1 + C.len := by omega
  rw [this, Nat.add_mod_right, Nat.mod_eq_of_lt i.isLt]

/-- The `i`-th cycle edge, as the `α`-orbit (Sym2 of endpoints) of `dart i`. -/
def edge (C : SimplePrimalCycle M) (i : Fin C.len) : Sym2 M.Vertex :=
  M.dartEdge (C.dart i)

/-- The set of darts that constitute the cycle edges (both the forward darts and
their `α`-reverses). -/
def dartSet (C : SimplePrimalCycle M) : Finset D :=
  Finset.univ.filter (fun d => ∃ i : Fin C.len, d = C.dart i ∨ d = M.α (C.dart i))

lemma mem_dartSet_iff (C : SimplePrimalCycle M) (d : D) :
    d ∈ C.dartSet ↔ ∃ i : Fin C.len, d = C.dart i ∨ d = M.α (C.dart i) := by
  simp [dartSet]

lemma dart_mem_dartSet (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.dart i ∈ C.dartSet :=
  (C.mem_dartSet_iff _).2 ⟨i, Or.inl rfl⟩

lemma alpha_dart_mem_dartSet (C : SimplePrimalCycle M) (i : Fin C.len) :
    M.α (C.dart i) ∈ C.dartSet :=
  (C.mem_dartSet_iff _).2 ⟨i, Or.inr rfl⟩

/-- The set of cycle *edges* (as `Sym2`). -/
def edgeSet (C : SimplePrimalCycle M) : Finset (Sym2 M.Vertex) :=
  Finset.univ.filter (fun e => ∃ i : Fin C.len, e = C.edge i)

lemma mem_edgeSet_iff (C : SimplePrimalCycle M) (e : Sym2 M.Vertex) :
    e ∈ C.edgeSet ↔ ∃ i : Fin C.len, e = C.edge i := by
  simp [edgeSet]



/-- The "left" face of the `i`-th cycle edge: the face of the forward dart. -/
def faceLeft (C : SimplePrimalCycle M) (i : Fin C.len) : M.Face :=
  M.dartFace (C.dart i)

/-- The "right" face of the `i`-th cycle edge: the face of the reverse dart. -/
def faceRight (C : SimplePrimalCycle M) (i : Fin C.len) : M.Face :=
  M.dartFace (M.α (C.dart i))



lemma consecutive' (C : SimplePrimalCycle M) (i : Fin C.len) :
    M.head (C.dart i) = M.tail (C.dart (C.nextIdx i)) := C.consecutive i

/-- The forward cycle darts are pairwise distinct. -/
lemma dart_inj (C : SimplePrimalCycle M) : Function.Injective C.dart := by
  intro i j h
  exact C.tail_inj (by simp only []; rw [h])

/-- `tail (dart (nextIdx i)) = head (dart i)`, restated. -/
lemma tail_dart_nextIdx (C : SimplePrimalCycle M) (i : Fin C.len) :
    M.tail (C.dart (C.nextIdx i)) = M.head (C.dart i) := (C.consecutive i).symm

/-- The `nextIdx` map is a bijection on indices (it is `prevIdx`-inverse). -/
lemma nextIdx_inj (C : SimplePrimalCycle M) : Function.Injective C.nextIdx := by
  intro i j h
  have := congrArg C.prevIdx h
  rwa [C.prevIdx_nextIdx, C.prevIdx_nextIdx] at this

/-- A forward cycle dart is never the `α`-reverse of a forward cycle dart.
This rules out the digon/loop degeneracy and uses `3 ≤ len`. -/
lemma dart_ne_alpha_dart (C : SimplePrimalCycle M) (i j : Fin C.len) :
    C.dart i ≠ M.α (C.dart j) := by
  intro h
  -- tails: tail(dart i) = tail(α dart j) = head(dart j) = tail(dart (next j))
  have ht : M.tail (C.dart i) = M.tail (C.dart (C.nextIdx j)) := by
    rw [h]; rw [tail_alpha]; exact (C.tail_dart_nextIdx j).symm
  have hij : i = C.nextIdx j := C.tail_inj ht
  -- heads: head(dart i) = head(α dart j) = tail(dart j)
  have hh : M.tail (C.dart (C.nextIdx i)) = M.tail (C.dart j) := by
    have : M.head (C.dart i) = M.tail (C.dart j) := by
      rw [h, head_alpha]
    rw [C.tail_dart_nextIdx i, this]
  have hnij : C.nextIdx i = j := C.tail_inj hh
  -- i = next j and next i = j ⇒ next (next j) = j ⇒ len ∣ 2, contradiction with len ≥ 3.
  rw [hij] at hnij
  have hval := congrArg Fin.val hnij
  simp only [nextIdx_val] at hval
  have hk : 3 ≤ C.len := C.len_ge
  have hjlt : j.1 < C.len := j.isLt
  -- ((j+1)%len + 1) % len = j  with len ≥ 3 is impossible
  rcases Nat.lt_or_ge (j.1 + 1) C.len with hcase | hcase
  · rw [Nat.mod_eq_of_lt hcase] at hval
    rcases Nat.lt_or_ge (j.1 + 1 + 1) C.len with hc2 | hc2
    · rw [Nat.mod_eq_of_lt hc2] at hval; omega
    · have : (j.1 + 1 + 1) % C.len = j.1 + 1 + 1 - C.len := by
        rw [Nat.mod_eq_sub_mod hc2, Nat.mod_eq_of_lt (by omega)]
      rw [this] at hval; omega
  · have hje : j.1 + 1 = C.len := by omega
    rw [hje, Nat.mod_self, Nat.zero_add, Nat.mod_eq_of_lt (by omega)] at hval
    omega

/-- The `α`-reverse cycle darts are pairwise distinct. -/
lemma alpha_dart_inj (C : SimplePrimalCycle M) :
    Function.Injective (fun i => M.α (C.dart i)) := by
  intro i j h
  simp only [] at h
  exact C.dart_inj (M.α.injective h)

/-- A forward cycle dart is not its own reverse. -/
lemma dart_ne_alpha_self (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.dart i ≠ M.α (C.dart i) := fun h => M.α_no_fixed (C.dart i) h.symm



open Classical in
/-- Classify a dart with respect to the cycle:
`inl (inl i)` if `d = dart i`; `inl (inr i)` if `d = α (dart i)`; `inr ()` if
neither. -/
noncomputable def cycleKind (C : SimplePrimalCycle M) (d : D) :
    (Fin C.len ⊕ Fin C.len) ⊕ Unit :=
  if hf : ∃ i, d = C.dart i then Sum.inl (Sum.inl hf.choose)
  else if hr : ∃ i, d = M.α (C.dart i) then Sum.inl (Sum.inr hr.choose)
  else Sum.inr ()

open Classical in
lemma cycleKind_dart (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cycleKind (C.dart i) = Sum.inl (Sum.inl i) := by
  have hf : ∃ j, C.dart i = C.dart j := ⟨i, rfl⟩
  rw [cycleKind, dif_pos hf]
  congr 1
  congr 1
  exact (C.dart_inj hf.choose_spec.symm)

open Classical in
lemma cycleKind_alpha_dart (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cycleKind (M.α (C.dart i)) = Sum.inl (Sum.inr i) := by
  have hnf : ¬ ∃ j, M.α (C.dart i) = C.dart j := by
    rintro ⟨j, hj⟩; exact C.dart_ne_alpha_dart j i hj.symm
  have hr : ∃ j, M.α (C.dart i) = M.α (C.dart j) := ⟨i, rfl⟩
  rw [cycleKind, dif_neg hnf, dif_pos hr]
  congr 1
  congr 1
  exact C.alpha_dart_inj hr.choose_spec.symm

open Classical in
lemma cycleKind_other (C : SimplePrimalCycle M) {d : D}
    (h : d ∉ C.dartSet) :
    C.cycleKind d = Sum.inr () := by
  have hnf : ¬ ∃ i, d = C.dart i := by
    rintro ⟨i, rfl⟩; exact h (C.dart_mem_dartSet i)
  have hnr : ¬ ∃ i, d = M.α (C.dart i) := by
    rintro ⟨i, rfl⟩; exact h (C.alpha_dart_mem_dartSet i)
  rw [cycleKind, dif_neg hnf, dif_neg hnr]

open Classical in
lemma cycleKind_eq_inl_inl (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.cycleKind d = Sum.inl (Sum.inl i)) : d = C.dart i := by
  rw [cycleKind] at h
  by_cases hf : ∃ j, d = C.dart j
  · rw [dif_pos hf] at h
    simp only [Sum.inl.injEq] at h
    rw [hf.choose_spec, h]
  · rw [dif_neg hf] at h
    split at h <;> simp at h

open Classical in
lemma cycleKind_eq_inl_inr (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.cycleKind d = Sum.inl (Sum.inr i)) : d = M.α (C.dart i) := by
  rw [cycleKind] at h
  by_cases hf : ∃ j, d = C.dart j
  · rw [dif_pos hf] at h; simp at h
  · rw [dif_neg hf] at h
    by_cases hr : ∃ j, d = M.α (C.dart j)
    · rw [dif_pos hr] at h
      simp only [Sum.inl.injEq, Sum.inr.injEq] at h
      rw [hr.choose_spec, h]
    · rw [dif_neg hr] at h; simp at h

open Classical in
lemma cycleKind_eq_inr (C : SimplePrimalCycle M) {d : D}
    (h : C.cycleKind d = Sum.inr ()) : d ∉ C.dartSet := by
  intro hmem
  rw [C.mem_dartSet_iff] at hmem
  obtain ⟨i, hi | hi⟩ := hmem
  · rw [hi, C.cycleKind_dart] at h; simp at h
  · rw [hi, C.cycleKind_alpha_dart] at h; simp at h

end SimplePrimalCycle



/-- Face adjacency across a primal edge not in `C`'s edge set. -/
def DualAvoidsCycleStep (M : CombMap D) (C : SimplePrimalCycle M)
    (f g : M.Face) : Prop :=
  ∃ d : D, M.dartEdge d ∉ C.edgeSet ∧ M.dartFace d = f ∧ M.dartFace (M.α d) = g

/-- Dual reachability avoiding all cycle edges. -/
def DualReachableAvoidingCycle (M : CombMap D) (C : SimplePrimalCycle M)
    (f g : M.Face) : Prop :=
  Relation.ReflTransGen (DualAvoidsCycleStep M C) f g



namespace SimplePrimalCycle

variable {M : CombMap D}

/-- The fresh-dart-augmented dart type of the cut map: original darts plus `2k`
fresh cap darts `c_i^+ = inr (inl i)`, `c_i^- = inr (inr i)`. -/
abbrev CutDart (C : SimplePrimalCycle M) : Type _ := D ⊕ (Fin C.len ⊕ Fin C.len)

open Classical in
/-- The new edge involution of the cut map. -/
noncomputable def cutAlpha (C : SimplePrimalCycle M) : C.CutDart → C.CutDart :=
  fun x => match x with
  | Sum.inl d =>
      match C.cycleKind d with
      | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)   -- d = dart i ↦ c_i^+
      | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)   -- d = α (dart i) ↦ c_i^-
      | Sum.inr () => Sum.inl (M.α d)                -- non-cycle: old pairing
  | Sum.inr (Sum.inl i) => Sum.inl (C.dart i)        -- c_i^+ ↦ dart i
  | Sum.inr (Sum.inr i) => Sum.inl (M.α (C.dart i))  -- c_i^- ↦ α (dart i)

@[simp] lemma cutAlpha_dart (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutAlpha (Sum.inl (C.dart i)) = Sum.inr (Sum.inl i) := by
  show (match C.cycleKind (C.dart i) with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.α (C.dart i))) = _
  rw [C.cycleKind_dart]

@[simp] lemma cutAlpha_alpha_dart (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutAlpha (Sum.inl (M.α (C.dart i))) = Sum.inr (Sum.inr i) := by
  show (match C.cycleKind (M.α (C.dart i)) with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.α (M.α (C.dart i)))) = _
  rw [C.cycleKind_alpha_dart]

lemma cutAlpha_other (C : SimplePrimalCycle M) {d : D} (h : d ∉ C.dartSet) :
    C.cutAlpha (Sum.inl d) = Sum.inl (M.α d) := by
  show (match C.cycleKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.α d)) = _
  rw [C.cycleKind_other h]

@[simp] lemma cutAlpha_capPlus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutAlpha (Sum.inr (Sum.inl i)) = Sum.inl (C.dart i) := rfl

@[simp] lemma cutAlpha_capMinus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutAlpha (Sum.inr (Sum.inr i)) = Sum.inl (M.α (C.dart i)) := rfl

/-- A non-cycle dart's reverse is also a non-cycle dart. -/
lemma alpha_notMem_dartSet (C : SimplePrimalCycle M) {d : D} (h : d ∉ C.dartSet) :
    M.α d ∉ C.dartSet := by
  intro hmem
  rw [C.mem_dartSet_iff] at hmem
  obtain ⟨i, hi | hi⟩ := hmem
  · -- α d = dart i ⇒ d = α (dart i) ∈ dartSet
    apply h; rw [C.mem_dartSet_iff]
    exact ⟨i, Or.inr (by rw [← hi, M.alpha_alpha])⟩
  · -- α d = α (dart i) ⇒ d = dart i ∈ dartSet
    apply h; rw [C.mem_dartSet_iff]
    have : d = C.dart i := M.α.injective hi
    exact ⟨i, Or.inl this⟩

/-- `cutAlpha` is an involution. -/
lemma cutAlpha_involutive (C : SimplePrimalCycle M) :
    Function.Involutive C.cutAlpha := by
  intro x
  rcases x with d | (i | i)
  · by_cases h : d ∈ C.dartSet
    · rw [C.mem_dartSet_iff] at h
      obtain ⟨i, hi | hi⟩ := h
      · subst hi; rw [C.cutAlpha_dart, C.cutAlpha_capPlus]
      · subst hi; rw [C.cutAlpha_alpha_dart, C.cutAlpha_capMinus]
    · rw [C.cutAlpha_other h, C.cutAlpha_other (C.alpha_notMem_dartSet h), M.alpha_alpha]
  · rw [C.cutAlpha_capPlus, C.cutAlpha_dart]
  · rw [C.cutAlpha_capMinus, C.cutAlpha_alpha_dart]

/-- `cutAlpha` has no fixed points. -/
lemma cutAlpha_no_fixed (C : SimplePrimalCycle M) (x : C.CutDart) :
    C.cutAlpha x ≠ x := by
  rcases x with d | (i | i)
  · by_cases h : d ∈ C.dartSet
    · rw [C.mem_dartSet_iff] at h
      obtain ⟨i, hi | hi⟩ := h
      · subst hi; rw [C.cutAlpha_dart]; simp
      · subst hi; rw [C.cutAlpha_alpha_dart]; simp
    · rw [C.cutAlpha_other h]; simp only [ne_eq, Sum.inl.injEq]
      exact M.α_no_fixed d
  · rw [C.cutAlpha_capPlus]; simp
  · rw [C.cutAlpha_capMinus]; simp

/-- `cutAlpha` as a permutation. -/
noncomputable def cutAlphaPerm (C : SimplePrimalCycle M) : Equiv.Perm C.CutDart :=
  Function.Involutive.toPerm C.cutAlpha C.cutAlpha_involutive

@[simp] lemma cutAlphaPerm_apply (C : SimplePrimalCycle M) (x : C.CutDart) :
    C.cutAlphaPerm x = C.cutAlpha x := rfl

end SimplePrimalCycle





namespace CutCapSurgery

variable {M : CombMap D} {C : SimplePrimalCycle M}









end CutCapSurgery



namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)

/-- **Step lift.**  If `C.edgeSet ⊆ {s(u,v)} ∪ boundaryEdges`, then any
`ChordSplitAdj u v` step is a `DualAvoidsCycleStep M C` step: the shared edge,
being neither the chord nor a boundary edge, is not a cycle edge. -/
lemma chordSplitAdj_dualAvoidsCycleStep {u v : M.Vertex} (C : SimplePrimalCycle M)
    (hsub : ∀ e ∈ C.edgeSet, e = s(u, v) ∨ hNT.outerCycle.IsBoundaryEdge e)
    {f g : M.Face} (hfg : hNT.ChordSplitAdj u v f g) :
    DualAvoidsCycleStep M C f g := by
  obtain ⟨d, hdf, hdg, hbe, hch⟩ := hfg
  refine ⟨d, ?_, hdf, hdg⟩
  intro hmem
  rcases hsub _ hmem with hchord | hbound
  · exact hch hchord
  · exact hbe hbound

/-- **Path lift.**  Under the same edge-containment, a `ChordSplitAdj`-path lifts
to a `DualReachableAvoidingCycle` path. -/
lemma reachable_dualAvoidsCycle_of_chordSplitAdj {u v : M.Vertex}
    (C : SimplePrimalCycle M)
    (hsub : ∀ e ∈ C.edgeSet, e = s(u, v) ∨ hNT.outerCycle.IsBoundaryEdge e)
    {f g : M.Face}
    (hfg : Relation.ReflTransGen (hNT.ChordSplitAdj u v) f g) :
    DualReachableAvoidingCycle M C f g := by
  induction hfg with
  | refl => exact Relation.ReflTransGen.refl
  | tail _ hstep ih =>
      exact Relation.ReflTransGen.tail ih
        (hNT.chordSplitAdj_dualAvoidsCycleStep C hsub hstep)







end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCap
-/
/- Source module: ProofsInTheBook.PlanarMapCutCapSigma -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}



/-- The forward cycle dart at `v_i` (the `+`-bank start). -/
def qDart (C : SimplePrimalCycle M) (i : Fin C.len) : D := C.dart i

/-- The reverse dart entering `v_i` (the `−`-bank start), `p_i = α (dart (prevIdx i))`. -/
def pDart (C : SimplePrimalCycle M) (i : Fin C.len) : D := M.α (C.dart (C.prevIdx i))

@[simp] lemma qDart_def (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.qDart i = C.dart i := rfl

@[simp] lemma pDart_def (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.pDart i = M.α (C.dart (C.prevIdx i)) := rfl

/-- `q`-darts are pairwise distinct. -/
lemma qDart_inj (C : SimplePrimalCycle M) : Function.Injective C.qDart :=
  C.dart_inj

/-- `p`-darts are pairwise distinct. -/
lemma pDart_inj (C : SimplePrimalCycle M) : Function.Injective C.pDart := by
  intro i j h
  simp only [pDart_def] at h
  have := C.dart_inj (M.α.injective h)
  exact C.nextIdx_inj (by rw [← C.nextIdx_prevIdx i, ← C.nextIdx_prevIdx j, this])

/-- A `p`-dart never equals a `q`-dart (rules out the digon, uses `3 ≤ len`). -/
lemma pDart_ne_qDart (C : SimplePrimalCycle M) (i j : Fin C.len) :
    C.pDart i ≠ C.qDart j := by
  simp only [pDart_def, qDart_def]
  exact fun h => C.dart_ne_alpha_dart j (C.prevIdx i) h.symm



open Classical in
/-- Classify a dart by where its `σ`-successor sits among the bank-start darts:
`inl (inl i)` if `σ d = p_i` (`d` is the `+`-bank end `ℓ_i^+`); `inl (inr i)` if
`σ d = q_i` (`d` is the `−`-bank end `ℓ_i^-`); `inr ()` otherwise. -/
noncomputable def divertKind (C : SimplePrimalCycle M) (d : D) :
    (Fin C.len ⊕ Fin C.len) ⊕ Unit :=
  if hp : ∃ i, M.σ d = C.pDart i then Sum.inl (Sum.inl hp.choose)
  else if hq : ∃ i, M.σ d = C.qDart i then Sum.inl (Sum.inr hq.choose)
  else Sum.inr ()

open Classical in
lemma divertKind_plus (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : M.σ d = C.pDart i) : C.divertKind d = Sum.inl (Sum.inl i) := by
  have hp : ∃ j, M.σ d = C.pDart j := ⟨i, h⟩
  rw [divertKind, dif_pos hp]
  congr 2
  exact C.pDart_inj (hp.choose_spec.symm.trans h)

open Classical in
lemma divertKind_minus (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : M.σ d = C.qDart i) : C.divertKind d = Sum.inl (Sum.inr i) := by
  have hnp : ¬ ∃ j, M.σ d = C.pDart j := by
    rintro ⟨j, hj⟩; exact C.pDart_ne_qDart j i (hj.symm.trans h)
  have hq : ∃ j, M.σ d = C.qDart j := ⟨i, h⟩
  rw [divertKind, dif_neg hnp, dif_pos hq]
  congr 2
  exact C.qDart_inj (hq.choose_spec.symm.trans h)

open Classical in
lemma divertKind_none (C : SimplePrimalCycle M) {d : D}
    (hp : ∀ i, M.σ d ≠ C.pDart i) (hq : ∀ i, M.σ d ≠ C.qDart i) :
    C.divertKind d = Sum.inr () := by
  rw [divertKind, dif_neg (by rintro ⟨i, hi⟩; exact hp i hi),
    dif_neg (by rintro ⟨i, hi⟩; exact hq i hi)]

open Classical in
lemma divertKind_eq_plus (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.divertKind d = Sum.inl (Sum.inl i)) : M.σ d = C.pDart i := by
  rw [divertKind] at h
  by_cases hp : ∃ j, M.σ d = C.pDart j
  · rw [dif_pos hp] at h
    simp only [Sum.inl.injEq] at h
    rw [hp.choose_spec, h]
  · rw [dif_neg hp] at h; split at h <;> simp at h

open Classical in
lemma divertKind_eq_minus (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.divertKind d = Sum.inl (Sum.inr i)) : M.σ d = C.qDart i := by
  rw [divertKind] at h
  by_cases hp : ∃ j, M.σ d = C.pDart j
  · rw [dif_pos hp] at h; simp at h
  · rw [dif_neg hp] at h
    by_cases hq : ∃ j, M.σ d = C.qDart j
    · rw [dif_pos hq] at h
      simp only [Sum.inl.injEq, Sum.inr.injEq] at h
      rw [hq.choose_spec, h]
    · rw [dif_neg hq] at h; simp at h

open Classical in
lemma divertKind_eq_none (C : SimplePrimalCycle M) {d : D}
    (h : C.divertKind d = Sum.inr ()) :
    (∀ i, M.σ d ≠ C.pDart i) ∧ (∀ i, M.σ d ≠ C.qDart i) := by
  constructor
  · intro i hi; rw [C.divertKind_plus hi] at h; simp at h
  · intro i hi; rw [C.divertKind_minus hi] at h; simp at h



open Classical in
/-- Classify a dart by whether it is a bank-start dart: `inl (inl i)` if `d = q_i`,
`inl (inr i)` if `d = p_i`, `inr ()` otherwise. -/
noncomputable def startKind (C : SimplePrimalCycle M) (d : D) :
    (Fin C.len ⊕ Fin C.len) ⊕ Unit :=
  if hq : ∃ i, d = C.qDart i then Sum.inl (Sum.inl hq.choose)
  else if hp : ∃ i, d = C.pDart i then Sum.inl (Sum.inr hp.choose)
  else Sum.inr ()

open Classical in
lemma startKind_q (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.startKind (C.qDart i) = Sum.inl (Sum.inl i) := by
  have hq : ∃ j, C.qDart i = C.qDart j := ⟨i, rfl⟩
  rw [startKind, dif_pos hq]; congr 2; exact C.qDart_inj hq.choose_spec.symm

open Classical in
lemma startKind_p (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.startKind (C.pDart i) = Sum.inl (Sum.inr i) := by
  have hnq : ¬ ∃ j, C.pDart i = C.qDart j := by
    rintro ⟨j, hj⟩; exact C.pDart_ne_qDart i j hj
  have hp : ∃ j, C.pDart i = C.pDart j := ⟨i, rfl⟩
  rw [startKind, dif_neg hnq, dif_pos hp]; congr 2; exact C.pDart_inj hp.choose_spec.symm

open Classical in
lemma startKind_none (C : SimplePrimalCycle M) {d : D}
    (hq : ∀ i, d ≠ C.qDart i) (hp : ∀ i, d ≠ C.pDart i) :
    C.startKind d = Sum.inr () := by
  rw [startKind, dif_neg (by rintro ⟨i, hi⟩; exact hq i hi),
    dif_neg (by rintro ⟨i, hi⟩; exact hp i hi)]

open Classical in
lemma startKind_eq_q (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.startKind d = Sum.inl (Sum.inl i)) : d = C.qDart i := by
  rw [startKind] at h
  by_cases hq : ∃ j, d = C.qDart j
  · rw [dif_pos hq] at h; simp only [Sum.inl.injEq] at h; rw [hq.choose_spec, h]
  · rw [dif_neg hq] at h; split at h <;> simp at h

open Classical in
lemma startKind_eq_p (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.startKind d = Sum.inl (Sum.inr i)) : d = C.pDart i := by
  rw [startKind] at h
  by_cases hq : ∃ j, d = C.qDart j
  · rw [dif_pos hq] at h; simp at h
  · rw [dif_neg hq] at h
    by_cases hp : ∃ j, d = C.pDart j
    · rw [dif_pos hp] at h
      simp only [Sum.inl.injEq, Sum.inr.injEq] at h; rw [hp.choose_spec, h]
    · rw [dif_neg hp] at h; simp at h

open Classical in
lemma startKind_eq_none (C : SimplePrimalCycle M) {d : D}
    (h : C.startKind d = Sum.inr ()) :
    (∀ i, d ≠ C.qDart i) ∧ (∀ i, d ≠ C.pDart i) := by
  refine ⟨fun i hi => ?_, fun i hi => ?_⟩
  · rw [hi, C.startKind_q] at h; simp at h
  · rw [hi, C.startKind_p] at h; simp at h



open Classical in
/-- Forward map of the cut-and-cap rotation `σ'`. -/
noncomputable def cutSigma (C : SimplePrimalCycle M) : C.CutDart → C.CutDart :=
  fun x => match x with
  | Sum.inl d =>
      match C.divertKind d with
      | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)   -- ℓ_i^+ ↦ c_i^+
      | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)   -- ℓ_i^- ↦ c_i^-
      | Sum.inr () => Sum.inl (M.σ d)                -- unchanged rotation
  | Sum.inr (Sum.inl i) => Sum.inl (C.qDart i)       -- c_i^+ ↦ q_i
  | Sum.inr (Sum.inr i) => Sum.inl (C.pDart i)       -- c_i^- ↦ p_i

open Classical in
/-- Inverse map of the cut-and-cap rotation `σ'`. -/
noncomputable def cutSigmaInv (C : SimplePrimalCycle M) : C.CutDart → C.CutDart :=
  fun x => match x with
  | Sum.inl d =>
      match C.startKind d with
      | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)   -- q_i ↦ c_i^+
      | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)   -- p_i ↦ c_i^-
      | Sum.inr () => Sum.inl (M.σ.symm d)           -- unchanged inverse rotation
  | Sum.inr (Sum.inl i) => Sum.inl (M.σ.symm (C.pDart i))  -- c_i^+ ↦ ℓ_i^+ = σ⁻¹ p_i
  | Sum.inr (Sum.inr i) => Sum.inl (M.σ.symm (C.qDart i))  -- c_i^- ↦ ℓ_i^- = σ⁻¹ q_i



lemma cutSigma_inl_plus (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.divertKind d = Sum.inl (Sum.inl i)) :
    C.cutSigma (Sum.inl d) = Sum.inr (Sum.inl i) := by
  show (match C.divertKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ d)) = _
  rw [h]

lemma cutSigma_inl_minus (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.divertKind d = Sum.inl (Sum.inr i)) :
    C.cutSigma (Sum.inl d) = Sum.inr (Sum.inr i) := by
  show (match C.divertKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ d)) = _
  rw [h]

lemma cutSigma_inl_none (C : SimplePrimalCycle M) {d : D}
    (h : C.divertKind d = Sum.inr ()) :
    C.cutSigma (Sum.inl d) = Sum.inl (M.σ d) := by
  show (match C.divertKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ d)) = _
  rw [h]

@[simp] lemma cutSigma_capPlus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutSigma (Sum.inr (Sum.inl i)) = Sum.inl (C.qDart i) := rfl

@[simp] lemma cutSigma_capMinus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutSigma (Sum.inr (Sum.inr i)) = Sum.inl (C.pDart i) := rfl



lemma cutSigmaInv_inl_q (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.startKind d = Sum.inl (Sum.inl i)) :
    C.cutSigmaInv (Sum.inl d) = Sum.inr (Sum.inl i) := by
  show (match C.startKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ.symm d)) = _
  rw [h]

lemma cutSigmaInv_inl_p (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.startKind d = Sum.inl (Sum.inr i)) :
    C.cutSigmaInv (Sum.inl d) = Sum.inr (Sum.inr i) := by
  show (match C.startKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ.symm d)) = _
  rw [h]

lemma cutSigmaInv_inl_none (C : SimplePrimalCycle M) {d : D}
    (h : C.startKind d = Sum.inr ()) :
    C.cutSigmaInv (Sum.inl d) = Sum.inl (M.σ.symm d) := by
  show (match C.startKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl i)
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ.symm d)) = _
  rw [h]

@[simp] lemma cutSigmaInv_capPlus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutSigmaInv (Sum.inr (Sum.inl i)) = Sum.inl (M.σ.symm (C.pDart i)) := rfl

@[simp] lemma cutSigmaInv_capMinus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutSigmaInv (Sum.inr (Sum.inr i)) = Sum.inl (M.σ.symm (C.qDart i)) := rfl



open Classical in
lemma cutSigma_leftInv (C : SimplePrimalCycle M) :
    Function.LeftInverse C.cutSigmaInv C.cutSigma := by
  intro x
  rcases x with d | (i | i)
  · -- x = inl d, split on divertKind d
    rcases hd : C.divertKind d with (i | i) | u
    · -- σ d = p_i : ℓ_i^+
      have hσ : M.σ d = C.pDart i := C.divertKind_eq_plus hd
      rw [C.cutSigma_inl_plus hd, cutSigmaInv_capPlus]
      rw [← hσ, M.σ.symm_apply_apply]
    · -- σ d = q_i : ℓ_i^-
      have hσ : M.σ d = C.qDart i := C.divertKind_eq_minus hd
      rw [C.cutSigma_inl_minus hd, cutSigmaInv_capMinus]
      rw [← hσ, M.σ.symm_apply_apply]
    · -- unchanged
      obtain ⟨hp, hq⟩ := C.divertKind_eq_none hd
      rw [C.cutSigma_inl_none hd, C.cutSigmaInv_inl_none (C.startKind_none hq hp),
        M.σ.symm_apply_apply]
  · -- x = c_i^+
    rw [cutSigma_capPlus, C.cutSigmaInv_inl_q (C.startKind_q i)]
  · -- x = c_i^-
    rw [cutSigma_capMinus, C.cutSigmaInv_inl_p (C.startKind_p i)]

open Classical in
lemma cutSigma_rightInv (C : SimplePrimalCycle M) :
    Function.RightInverse C.cutSigmaInv C.cutSigma := by
  intro x
  rcases x with d | (i | i)
  · -- x = inl d, split on startKind d
    rcases hd : C.startKind d with (i | i) | u
    · -- d = q_i
      have hq : d = C.qDart i := C.startKind_eq_q hd
      rw [C.cutSigmaInv_inl_q hd, cutSigma_capPlus, hq]
    · -- d = p_i
      have hp : d = C.pDart i := C.startKind_eq_p hd
      rw [C.cutSigmaInv_inl_p hd, cutSigma_capMinus, hp]
    · -- neither: d ≠ q_i, p_i for all i
      obtain ⟨hq, hp⟩ := C.startKind_eq_none hd
      rw [C.cutSigmaInv_inl_none hd]
      have hdiv : C.divertKind (M.σ.symm d) = Sum.inr () := by
        apply C.divertKind_none
        · intro i; rw [M.σ.apply_symm_apply]; exact hp i
        · intro i; rw [M.σ.apply_symm_apply]; exact hq i
      rw [C.cutSigma_inl_none hdiv, M.σ.apply_symm_apply]
  · -- x = c_i^+ : σ⁻¹ p_i ↦ back to c_i^+
    rw [cutSigmaInv_capPlus]
    have hdiv : C.divertKind (M.σ.symm (C.pDart i)) = Sum.inl (Sum.inl i) :=
      C.divertKind_plus (by rw [M.σ.apply_symm_apply])
    rw [C.cutSigma_inl_plus hdiv]
  · -- x = c_i^-
    rw [cutSigmaInv_capMinus]
    have hdiv : C.divertKind (M.σ.symm (C.qDart i)) = Sum.inl (Sum.inr i) :=
      C.divertKind_minus (by rw [M.σ.apply_symm_apply])
    rw [C.cutSigma_inl_minus hdiv]

/-- The new vertex rotation `σ'` as a permutation of the cut dart set. -/
noncomputable def cutSigmaPerm (C : SimplePrimalCycle M) : Equiv.Perm C.CutDart where
  toFun := C.cutSigma
  invFun := C.cutSigmaInv
  left_inv := C.cutSigma_leftInv
  right_inv := C.cutSigma_rightInv

@[simp] lemma cutSigmaPerm_apply (C : SimplePrimalCycle M) (x : C.CutDart) :
    C.cutSigmaPerm x = C.cutSigma x := rfl





















end SimplePrimalCycle









end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import Mathlib
-/
/- Source module: ProofsInTheBook.PermTranspositionCycleCount -/
section
set_option autoImplicit true


set_option linter.unusedSectionVars false
set_option linter.unusedSimpArgs false
set_option linter.unnecessarySimpa false
set_option linter.unusedVariables false

open Equiv Equiv.Perm Function

variable {D : Type*} [Fintype D] [DecidableEq D]

noncomputable def numCycles (p : Equiv.Perm D) : ℕ := by
  classical
  exact Fintype.card (Quotient (SameCycle.setoid p))

namespace PermTranspositionCycleCount

open scoped Finset

def mergeRel (p : Equiv.Perm D) (a b x y : D) : Prop :=
  p.SameCycle x y ∨
    (p.SameCycle x a ∧ p.SameCycle y b) ∨
      (p.SameCycle x b ∧ p.SameCycle y a)

lemma mergeRel_refl (p : Equiv.Perm D) (a b x : D) :
    mergeRel p a b x x := by
  exact Or.inl SameCycle.rfl

lemma mergeRel_symm {p : Equiv.Perm D} {a b x y : D} :
    mergeRel p a b x y → mergeRel p a b y x := by
  rintro (h | ⟨hxa, hyb⟩ | ⟨hxb, hya⟩)
  · exact Or.inl h.symm
  · exact Or.inr (Or.inr ⟨hyb, hxa⟩)
  · exact Or.inr (Or.inl ⟨hya, hxb⟩)

lemma mergeRel_trans {p : Equiv.Perm D} {a b x y z : D} :
    mergeRel p a b x y → mergeRel p a b y z → mergeRel p a b x z := by
  intro hxy hyz
  rcases hxy with hxy | ⟨hxa, hyb⟩ | ⟨hxb, hya⟩
  · rcases hyz with hyz | ⟨hya, hzb⟩ | ⟨hyb, hza⟩
    · exact Or.inl (hxy.trans hyz)
    · exact Or.inr (Or.inl ⟨hxy.trans hya, hzb⟩)
    · exact Or.inr (Or.inr ⟨hxy.trans hyb, hza⟩)
  · rcases hyz with hyz | ⟨hya, hzb⟩ | ⟨hyb', hza⟩
    · exact Or.inr (Or.inl ⟨hxa, hyz.symm.trans hyb⟩)
    · exact Or.inr (Or.inl ⟨hxa, hzb⟩)
    · exact Or.inl (hxa.trans hza.symm)
  · rcases hyz with hyz | ⟨hya', hzb⟩ | ⟨hyb, hza⟩
    · exact Or.inr (Or.inr ⟨hxb, hyz.symm.trans hya⟩)
    · exact Or.inl (hxb.trans hzb.symm)
    · exact Or.inr (Or.inr ⟨hxb, hza⟩)

lemma mergeRel_step (p : Equiv.Perm D) (a b z : D) :
    mergeRel p a b z ((p * Equiv.swap a b) z) := by
  by_cases hza : z = a
  · subst hza
    refine Or.inr (Or.inl ⟨SameCycle.rfl, ?_⟩)
    rw [mul_apply, Equiv.swap_apply_left]
    exact sameCycle_apply_left.mpr SameCycle.rfl
  · by_cases hzb : z = b
    · subst hzb
      refine Or.inr (Or.inr ⟨SameCycle.rfl, ?_⟩)
      rw [mul_apply, Equiv.swap_apply_right]
      exact sameCycle_apply_left.mpr SameCycle.rfl
    · refine Or.inl ?_
      rw [mul_apply, Equiv.swap_apply_of_ne_of_ne hza hzb]
      exact sameCycle_apply_right.mpr SameCycle.rfl

lemma mergeRel_pow_apply (p : Equiv.Perm D) (a b x : D) (n : ℕ) :
    mergeRel p a b x (((p * Equiv.swap a b) ^ n) x) := by
  induction n with
  | zero =>
      simpa using mergeRel_refl p a b x
  | succ n ih =>
      rw [pow_succ', mul_apply]
      exact mergeRel_trans ih (mergeRel_step p a b (((p * Equiv.swap a b) ^ n) x))

lemma mergeRel_of_sameCycle_mul_swap {p : Equiv.Perm D} {a b x y : D} :
    (p * Equiv.swap a b).SameCycle x y → mergeRel p a b x y := by
  rintro ⟨i, hi⟩
  cases i with
  | ofNat n =>
      rw [← hi]
      exact mergeRel_pow_apply p a b x n
  | negSucc n =>
      have hxy : ((p * Equiv.swap a b) ^ (n + 1)) y = x := by
        rw [← hi]
        simp [zpow_negSucc, pow_succ]
      have hyx : mergeRel p a b y x := by
        simpa [hxy] using mergeRel_pow_apply p a b y (n + 1)
      exact mergeRel_symm hyx

lemma mergeRel_of_base_sameCycle {p : Equiv.Perm D} {a b x y : D}
    (hab : p.SameCycle a b) :
    mergeRel p a b x y → p.SameCycle x y := by
  rintro (h | ⟨hxa, hyb⟩ | ⟨hxb, hya⟩)
  · exact h
  · exact hxa.trans (hab.trans hyb.symm)
  · exact hxb.trans (hab.symm.trans hya.symm)

lemma mul_swap_pow_succ_apply_left_of_not_sameCycle
    (p : Equiv.Perm D) {a b : D} (hnsc : ¬ p.SameCycle a b) :
    ∀ n : ℕ, n < orderOf (p.cycleOf b) →
      (((p * Equiv.swap a b) ^ (n + 1)) a = (p ^ (n + 1)) b)
  | 0, _ => by
      simp [mul_apply]
  | n + 1, hnlt => by
      have hnlt' : n < orderOf (p.cycleOf b) := lt_trans (Nat.lt_succ_self n) hnlt
      have ih := mul_swap_pow_succ_apply_left_of_not_sameCycle p hnsc n hnlt'
      rw [pow_succ', mul_apply, ih, mul_apply]
      rw [Equiv.swap_apply_of_ne_of_ne]
      · rw [pow_succ', mul_apply]
        simp [pow_succ', mul_apply]
      · intro ha
        apply hnsc
        have hba : p.SameCycle b a :=
          ⟨((n + 1 : ℕ) : ℤ), by simpa [zpow_natCast] using ha⟩
        exact hba.symm
      · intro hb
        have hpbn : p b ≠ b := by
          intro hpb
          have hcycle : p.cycleOf b = 1 := (cycleOf_eq_one_iff p).mpr hpb
          rw [hcycle, orderOf_one] at hnlt
          omega
        have hcb : p.cycleOf b b ≠ b := by
          simpa using hpbn
        have hcyclePow : (p.cycleOf b ^ (n + 1)) b = b := by
          simpa using hb
        have hpowOne : p.cycleOf b ^ (n + 1) = 1 :=
          ((isCycle_cycleOf p hpbn).pow_eq_one_iff' hcb).mpr hcyclePow
        exact pow_ne_one_of_lt_orderOf (by omega : n + 1 ≠ 0) hnlt hpowOne

lemma sameCycle_mul_swap_self_of_not_sameCycle
    (p : Equiv.Perm D) {a b : D} (hnsc : ¬ p.SameCycle a b) :
    (p * Equiv.swap a b).SameCycle a b := by
  let m := orderOf (p.cycleOf b)
  have hmpos : 0 < m := orderOf_pos (p.cycleOf b)
  cases hm : m with
  | zero =>
      omega
  | succ n =>
      refine ⟨((n + 1 : ℕ) : ℤ), ?_⟩
      have hnlt : n < orderOf (p.cycleOf b) := by
        simpa [m, hm] using Nat.lt_succ_self n
      have hq := mul_swap_pow_succ_apply_left_of_not_sameCycle p hnsc n hnlt
      have hp : (p ^ (n + 1)) b = b := by
        have hc : (p.cycleOf b ^ (n + 1)) b = b := by
          have : p.cycleOf b ^ orderOf (p.cycleOf b) = 1 := pow_orderOf_eq_one _
          simpa [m, hm] using congrFun (congrArg DFunLike.coe this) b
        simpa using hc
      change ((p * Equiv.swap a b) ^ (n + 1 : ℕ)) a = b
      exact hq.trans hp

lemma sameCycle_le_mul_swap_of_not_sameCycle
    (p : Equiv.Perm D) {a b x y : D} (hnsc : ¬ p.SameCycle a b)
    (hxy : p.SameCycle x y) :
    (p * Equiv.swap a b).SameCycle x y := by
  let q := p * Equiv.swap a b
  have hqab : q.SameCycle a b := sameCycle_mul_swap_self_of_not_sameCycle p hnsc
  have hstep : ∀ z : D, q.SameCycle z (p z) := by
    intro z
    by_cases hza : z = a
    · subst z
      exact hqab.trans (by simpa [q, mul_apply] using (SameCycle.rfl : q.SameCycle b b).apply_right)
    · by_cases hzb : z = b
      · subst z
        exact hqab.symm.trans
          (by simpa [q, mul_apply] using (SameCycle.rfl : q.SameCycle a a).apply_right)
      · have hz : q z = p z := by simp [q, mul_apply, Equiv.swap_apply_of_ne_of_ne hza hzb]
        exact hz ▸ SameCycle.rfl.apply_right
  have hpow : ∀ n : ℕ, q.SameCycle x ((p ^ n) x) := by
    intro n
    induction n with
    | zero =>
        exact SameCycle.rfl
    | succ n ih =>
        rw [pow_succ', mul_apply]
        exact ih.trans (hstep ((p ^ n) x))
  obtain ⟨n, hn⟩ := hxy.exists_nat_pow_eq
  simpa [hn] using hpow n

lemma sameCycle_mul_swap_iff_mergeRel_of_not_sameCycle
    (p : Equiv.Perm D) {a b x y : D} (hnsc : ¬ p.SameCycle a b) :
    (p * Equiv.swap a b).SameCycle x y ↔ mergeRel p a b x y := by
  constructor
  · exact mergeRel_of_sameCycle_mul_swap
  · intro h
    let q := p * Equiv.swap a b
    have hqab : q.SameCycle a b := sameCycle_mul_swap_self_of_not_sameCycle p hnsc
    rcases h with hxy | ⟨hxa, hyb⟩ | ⟨hxb, hya⟩
    · exact sameCycle_le_mul_swap_of_not_sameCycle p hnsc hxy
    · exact (sameCycle_le_mul_swap_of_not_sameCycle p hnsc hxa).trans
        (hqab.trans (sameCycle_le_mul_swap_of_not_sameCycle p hnsc hyb.symm))
    · exact (sameCycle_le_mul_swap_of_not_sameCycle p hnsc hxb).trans
        (hqab.symm.trans (sameCycle_le_mul_swap_of_not_sameCycle p hnsc hya.symm))

noncomputable def orbitEquivFixedOrCycles (p : Equiv.Perm D) :
    Quotient (SameCycle.setoid p) ≃ Function.fixedPoints p ⊕ p.cycleFactorsFinset := by
  classical
  refine
    { toFun := ?toFun
      invFun := ?invFun
      left_inv := ?left
      right_inv := ?right }
  · refine Quotient.lift ?_ ?_
    · intro x
      by_cases hx : p x = x
      · exact Sum.inl ⟨x, by simpa [Function.mem_fixedPoints_iff] using hx⟩
      · exact Sum.inr ⟨p.cycleOf x, cycleOf_mem_cycleFactorsFinset_iff.mpr (mem_support.mpr hx)⟩
    · intro x y hxy
      change p.SameCycle x y at hxy
      by_cases hx : p x = x
      · have hy : p y = y := (hxy.apply_eq_self_iff).mp hx
        have hxy' : x = y := hxy.eq_of_left hx
        subst hxy'
        simp [hx, hy]
      · have hy : p y ≠ y := fun hy => hx ((hxy.apply_eq_self_iff).mpr hy)
        simp [hx, hy]
        exact hxy.cycleOf_eq
  · intro s
    rcases s with fp | c
    · exact Quotient.mk (SameCycle.setoid p) fp.1
    · let y : D := Classical.choose
          (IsCycle.nonempty_support (mem_cycleFactorsFinset_iff.mp c.2).1)
      exact Quotient.mk (SameCycle.setoid p) y
  · intro q
    refine Quotient.inductionOn q ?_
    intro x
    by_cases hx : p x = x
    · simp [hx, Function.mem_fixedPoints_iff]
    · dsimp
      simp [hx]
      let c : p.cycleFactorsFinset :=
        ⟨p.cycleOf x, cycleOf_mem_cycleFactorsFinset_iff.mpr (mem_support.mpr hx)⟩
      let y : D := Classical.choose
          (IsCycle.nonempty_support (mem_cycleFactorsFinset_iff.mp c.2).1)
      have hy : y ∈ (p.cycleOf x).support :=
        Classical.choose_spec
          (IsCycle.nonempty_support (mem_cycleFactorsFinset_iff.mp c.2).1)
      have hy' : p.SameCycle x y := by
        have := (mem_support_cycleOf_iff (f := p) (x := x) (y := y)).mp hy
        exact this.1
      exact Quotient.sound hy'.symm
  · intro s
    rcases s with fp | c
    · have hfp : p fp.1 = fp.1 := Function.mem_fixedPoints_iff.mp fp.2
      simp [hfp]
    · let y : D := Classical.choose
          (IsCycle.nonempty_support (mem_cycleFactorsFinset_iff.mp c.2).1)
      have hyc : y ∈ (c : Equiv.Perm D).support :=
        Classical.choose_spec
          (IsCycle.nonempty_support (mem_cycleFactorsFinset_iff.mp c.2).1)
      have hyp : y ∈ p.support := mem_cycleFactorsFinset_support_le c.2 hyc
      have hy : p y ≠ y := mem_support.mp hyp
      have hcy : c.1 = p.cycleOf y := cycle_is_cycleOf hyc c.2
      dsimp
      rw [dif_neg hy]
      exact congrArg (fun e : p.cycleFactorsFinset => Sum.inr e) (Subtype.ext hcy.symm)

lemma numCycles_eq_fixed_add_cycleType_card (p : Equiv.Perm D) :
    numCycles p =
      Fintype.card (Function.fixedPoints p) + Multiset.card p.cycleType := by
  classical
  unfold numCycles
  calc
    Fintype.card (Quotient (SameCycle.setoid p))
        = Fintype.card (Function.fixedPoints p ⊕ p.cycleFactorsFinset) :=
          Fintype.card_congr (orbitEquivFixedOrCycles p)
    _ = Fintype.card (Function.fixedPoints p) + Fintype.card p.cycleFactorsFinset := by
          simp
    _ = Fintype.card (Function.fixedPoints p) + Multiset.card p.cycleType := by
          rw [cycleType_def]
          simp



theorem numCycles_mul_swap_of_not_sameCycle
    (p : Equiv.Perm D) {a b : D} (hab : a ≠ b) (hnsc : ¬ p.SameCycle a b) :
    numCycles (p * Equiv.swap a b) + 1 = numCycles p := by
  classical
  let q : Equiv.Perm D := p * Equiv.swap a b
  let P := Quotient (SameCycle.setoid p)
  let Q := Quotient (SameCycle.setoid q)
  let A : P := Quotient.mk (SameCycle.setoid p) a
  let B : P := Quotient.mk (SameCycle.setoid p) b
  have hAB : A ≠ B := by
    intro h
    exact hnsc (Quotient.exact h)
  have hpq : ∀ {x y : D}, p.SameCycle x y → q.SameCycle x y := by
    intro x y hxy
    exact sameCycle_le_mul_swap_of_not_sameCycle p hnsc hxy
  let mergeMap : P → Q := Quotient.map' id (fun x y hxy => hpq hxy)
  let f : {u : P // u ≠ B} → Q := fun u => mergeMap u.1
  have hsurj : Function.Surjective f := by
    intro v
    refine Quotient.inductionOn v ?_
    intro x
    by_cases hxB : (Quotient.mk (SameCycle.setoid p) x : P) = B
    · refine ⟨⟨A, hAB⟩, ?_⟩
      have hxb : p.SameCycle x b := Quotient.exact hxB
      have hqxa : q.SameCycle x a :=
        (hpq hxb).trans (sameCycle_mul_swap_self_of_not_sameCycle p hnsc).symm
      apply Quotient.sound hqxa.symm
    · refine ⟨⟨Quotient.mk (SameCycle.setoid p) x, hxB⟩, ?_⟩
      rfl
  have hinj : Function.Injective f := by
    rintro ⟨u, hu⟩ ⟨v, hv⟩ huv
    apply Subtype.ext
    dsimp [f, mergeMap] at huv
    revert hu hv huv
    refine Quotient.inductionOn₂ u v ?_
    intro x y hxB hyB hxy
    simp only [Quotient.map'_mk'', id_eq] at hxy
    have hqxy : q.SameCycle x y := Quotient.exact hxy
    have hR : mergeRel p a b x y :=
      (sameCycle_mul_swap_iff_mergeRel_of_not_sameCycle p hnsc).mp hqxy
    rcases hR with hpxy | ⟨hxa, hyb⟩ | ⟨hxb, hya⟩
    · exact Quotient.sound hpxy
    · exfalso
      exact hyB (Quotient.sound hyb)
    · exfalso
      exact hxB (Quotient.sound hxb)
  have hcard_equiv : Fintype.card {u : P // u ≠ B} = Fintype.card Q :=
    Fintype.card_congr (Equiv.ofBijective f ⟨hinj, hsurj⟩)
  have hsub_card : Fintype.card {u : P // u ≠ B} + 1 = Fintype.card P := by
    have hcompl :
        Fintype.card {u : P // u ≠ B} = Fintype.card P - 1 := by
      simpa [Fintype.card_subtype_eq B] using
        (Fintype.card_subtype_compl (fun u : P => u = B))
    have hpos : 0 < Fintype.card P := Fintype.card_pos_iff.mpr ⟨B⟩
    omega
  unfold numCycles
  change Fintype.card Q + 1 = Fintype.card P
  rw [← hcard_equiv]
  exact hsub_card

lemma sign_eq_of_numCycles_eq (p q : Equiv.Perm D)
    (hnum : numCycles p = numCycles q) :
    Equiv.Perm.sign p = Equiv.Perm.sign q := by
  classical
  have hpnum :
      numCycles p = Fintype.card D - p.cycleType.sum + Multiset.card p.cycleType := by
    rw [numCycles_eq_fixed_add_cycleType_card, Equiv.Perm.card_fixedPoints]
  have hqnum :
      numCycles q = Fintype.card D - q.cycleType.sum + Multiset.card q.cycleType := by
    rw [numCycles_eq_fixed_add_cycleType_card, Equiv.Perm.card_fixedPoints]
  have hmod :
      (p.cycleType.sum + Multiset.card p.cycleType) % 2 =
        (q.cycleType.sum + Multiset.card q.cycleType) % 2 := by
    have hp_le := p.sum_cycleType_le
    have hq_le := q.sum_cycleType_le
    omega
  apply Units.ext
  rw [Equiv.Perm.sign_of_cycleType, Equiv.Perm.sign_of_cycleType]
  simp [neg_one_pow_eq_pow_mod_two, hmod]

lemma numCycles_mul_swap_ne (p : Equiv.Perm D) {a b : D} (hab : a ≠ b) :
    numCycles (p * Equiv.swap a b) ≠ numCycles p := by
  intro hnum
  have hsign_eq := sign_eq_of_numCycles_eq (p * Equiv.swap a b) p hnum
  have hsign_neg :
      Equiv.Perm.sign (p * Equiv.swap a b) = -Equiv.Perm.sign p := by
    rw [Equiv.Perm.sign_mul, Equiv.Perm.sign_swap hab]
    simp
  rw [hsign_neg] at hsign_eq
  have hself : Equiv.Perm.sign p = -Equiv.Perm.sign p := hsign_eq.symm
  have hone : (1 : ℤˣ) = -1 := by
    calc
      (1 : ℤˣ) = (Equiv.Perm.sign p)⁻¹ * Equiv.Perm.sign p := by simp
      _ = (Equiv.Perm.sign p)⁻¹ * (-Equiv.Perm.sign p) := by
        exact congrArg ((Equiv.Perm.sign p)⁻¹ * ·) hself
      _ = -1 := by
        rw [mul_neg, inv_mul_cancel]
  have hval := congrArg Units.val hone
  norm_num at hval

lemma numCycles_le_mul_swap_of_sameCycle
    (p : Equiv.Perm D) {a b : D} (hsc : p.SameCycle a b) :
    numCycles p ≤ numCycles (p * Equiv.swap a b) := by
  classical
  let q : Equiv.Perm D := p * Equiv.swap a b
  let P := Quotient (SameCycle.setoid p)
  let Q := Quotient (SameCycle.setoid q)
  have hrel : ∀ {x y : D}, q.SameCycle x y → p.SameCycle x y := by
    intro x y hxy
    exact mergeRel_of_base_sameCycle hsc (mergeRel_of_sameCycle_mul_swap hxy)
  let g : Q → P := Quotient.map' id (fun x y hxy => hrel hxy)
  have hsurj : Function.Surjective g := by
    intro u
    refine Quotient.inductionOn u ?_
    intro x
    exact ⟨Quotient.mk (SameCycle.setoid q) x, rfl⟩
  unfold numCycles
  change Fintype.card P ≤ Fintype.card Q
  exact Fintype.card_le_of_surjective g hsurj

theorem numCycles_mul_swap_dichotomy
    (p : Equiv.Perm D) {a b : D} (hab : a ≠ b) :
    numCycles (p * Equiv.swap a b) = numCycles p + 1 ∨
    numCycles (p * Equiv.swap a b) + 1 = numCycles p := by
  by_cases hnsc : ¬ p.SameCycle a b
  · exact Or.inr (numCycles_mul_swap_of_not_sameCycle p hab hnsc)
  · have hsc : p.SameCycle a b := by simpa using Classical.not_not.mp hnsc
    let q : Equiv.Perm D := p * Equiv.swap a b
    have hp_le_q : numCycles p ≤ numCycles q :=
      numCycles_le_mul_swap_of_sameCycle p hsc
    by_cases hqsc : q.SameCycle a b
    · have hq_le_p : numCycles q ≤ numCycles p := by
        have h := numCycles_le_mul_swap_of_sameCycle q hqsc
        simpa [q, mul_assoc] using h
      have heq : numCycles q = numCycles p := le_antisymm hq_le_p hp_le_q
      exact False.elim (numCycles_mul_swap_ne p hab heq)
    · have h := numCycles_mul_swap_of_not_sameCycle q hab hqsc
      exact Or.inl (by simpa [q, mul_assoc] using h.symm)

end PermTranspositionCycleCount

theorem numCycles_mul_swap_dichotomy
    (p : Equiv.Perm D) {a b : D} (hab : a ≠ b) :
    numCycles (p * Equiv.swap a b) = numCycles p + 1 ∨
    numCycles (p * Equiv.swap a b) + 1 = numCycles p :=
  PermTranspositionCycleCount.numCycles_mul_swap_dichotomy p hab

theorem numCycles_mul_swap_of_not_sameCycle
    (p : Equiv.Perm D) {a b : D} (hab : a ≠ b) (hnsc : ¬ p.SameCycle a b) :
    numCycles (p * Equiv.swap a b) + 1 = numCycles p :=
  PermTranspositionCycleCount.numCycles_mul_swap_of_not_sameCycle p hab hnsc

end

/- Original source header (imports hoisted):
import Mathlib
-/
/- Source module: ProofsInTheBook.RelationComponentCount -/
section
set_option autoImplicit true


open Classical

universe u

variable {V : Type u} [Fintype V]

def compSetoid (r : V → V → Prop) : Setoid V :=
  ⟨Relation.EqvGen r, Relation.EqvGen.is_equivalence r⟩

noncomputable def numComp (r : V → V → Prop) : ℕ :=
  Nat.card (Quotient (compSetoid r))

def addEdge (r : V → V → Prop) (a b : V) : V → V → Prop :=
  fun x y => r x y ∨ (x = a ∧ y = b) ∨ (x = b ∧ y = a)

 def pairRel {α : Type u} (a b : α) (x y : α) : Prop :=
  x = y ∨ (x = a ∧ y = b) ∨ (x = b ∧ y = a)

 theorem pairRel_refl {α : Type u} (a b : α) (x : α) :
    pairRel a b x x := by
  exact Or.inl rfl

 theorem pairRel_symm {α : Type u} (a b : α) {x y : α} :
    pairRel a b x y → pairRel a b y x := by
  intro h
  rcases h with rfl | ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩
  · exact Or.inl rfl
  · exact Or.inr (Or.inr ⟨rfl, rfl⟩)
  · exact Or.inr (Or.inl ⟨rfl, rfl⟩)

 theorem pairRel_trans {α : Type u} (a b : α) {x y z : α} :
    pairRel a b x y → pairRel a b y z → pairRel a b x z := by
  intro hxy hyz
  rcases hxy with hEq | hAB | hBA
  · subst y
    exact hyz
  · rcases hAB with ⟨rfl, rfl⟩
    rcases hyz with hEq | hAB' | hBA'
    · subst z
      exact Or.inr (Or.inl ⟨rfl, rfl⟩)
    · rcases hAB' with ⟨_, hz⟩
      subst z
      exact Or.inr (Or.inl ⟨rfl, rfl⟩)
    · rcases hBA' with ⟨_, hz⟩
      subst z
      exact Or.inl rfl
  · rcases hBA with ⟨rfl, rfl⟩
    rcases hyz with hEq | hAB' | hBA'
    · subst z
      exact Or.inr (Or.inr ⟨rfl, rfl⟩)
    · rcases hAB' with ⟨_, hz⟩
      subst z
      exact Or.inl rfl
    · rcases hBA' with ⟨_, hz⟩
      subst z
      exact Or.inr (Or.inr ⟨rfl, rfl⟩)

 def pairSetoid {α : Type u} (a b : α) : Setoid α where
  r := pairRel a b
  iseqv :=
    ⟨pairRel_refl a b, fun h => pairRel_symm a b h,
      fun h₁ h₂ => pairRel_trans a b h₁ h₂⟩

omit [Fintype V] in
 theorem eqvGen_mono {r s : V → V → Prop}
    (h : ∀ ⦃x y : V⦄, r x y → s x y) {x y : V} :
    Relation.EqvGen r x y → Relation.EqvGen s x y := by
  intro hxy
  induction hxy with
  | rel x y hxy =>
      exact Relation.EqvGen.rel x y (h hxy)
  | refl x =>
      exact Relation.EqvGen.refl x
  | symm x y _ ih =>
      exact Relation.EqvGen.symm x y ih
  | trans x y z _ _ ihxy ihyz =>
      exact Relation.EqvGen.trans x y z ihxy ihyz

omit [Fintype V] in
 theorem eqvGen_le_addEdge (r : V → V → Prop) (a b : V) {x y : V} :
    Relation.EqvGen r x y → Relation.EqvGen (addEdge r a b) x y := by
  intro hxy
  exact eqvGen_mono (s := addEdge r a b) (fun {x y} hr => Or.inl hr) hxy

omit [Fintype V] in
 theorem eqvGen_addEdge_iff_pairRel (r : V → V → Prop) (a b x y : V) :
    Relation.EqvGen (addEdge r a b) x y ↔
      pairRel (Quotient.mk (compSetoid r) a) (Quotient.mk (compSetoid r) b)
        (Quotient.mk (compSetoid r) x) (Quotient.mk (compSetoid r) y) := by
  constructor
  · intro hxy
    induction hxy with
    | rel x y hxy =>
        rcases hxy with hr | ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩
        · exact Or.inl (Quotient.sound (Relation.EqvGen.rel x y hr))
        · exact Or.inr (Or.inl ⟨rfl, rfl⟩)
        · exact Or.inr (Or.inr ⟨rfl, rfl⟩)
    | refl x =>
        exact pairRel_refl _ _ _
    | symm x y _ ih =>
        exact pairRel_symm _ _ ih
    | trans x y z _ _ ihxy ihyz =>
        exact pairRel_trans _ _ ihxy ihyz
  · intro hxy
    rcases hxy with hxy | hxab | hxba
    · exact eqvGen_le_addEdge r a b (Quotient.exact hxy)
    · rcases hxab with ⟨hxa, hyb⟩
      have hxa' : Relation.EqvGen (addEdge r a b) x a :=
        eqvGen_le_addEdge r a b (Quotient.exact hxa)
      have hby' : Relation.EqvGen (addEdge r a b) b y :=
        Relation.EqvGen.symm y b (eqvGen_le_addEdge r a b (Quotient.exact hyb))
      have hab' : Relation.EqvGen (addEdge r a b) a b :=
        Relation.EqvGen.rel a b (Or.inr (Or.inl ⟨rfl, rfl⟩))
      exact Relation.EqvGen.trans x a y hxa'
        (Relation.EqvGen.trans a b y hab' hby')
    · rcases hxba with ⟨hxb, hya⟩
      have hxb' : Relation.EqvGen (addEdge r a b) x b :=
        eqvGen_le_addEdge r a b (Quotient.exact hxb)
      have hay' : Relation.EqvGen (addEdge r a b) a y :=
        Relation.EqvGen.symm y a (eqvGen_le_addEdge r a b (Quotient.exact hya))
      have hba' : Relation.EqvGen (addEdge r a b) b a :=
        Relation.EqvGen.rel b a (Or.inr (Or.inr ⟨rfl, rfl⟩))
      exact Relation.EqvGen.trans x b y hxb'
        (Relation.EqvGen.trans b a y hba' hay')

omit [Fintype V] in
 theorem eqvGen_addEdge_iff (r : V → V → Prop) (a b x y : V) :
    Relation.EqvGen (addEdge r a b) x y ↔
      Relation.EqvGen r x y
        ∨ (Relation.EqvGen r x a ∧ Relation.EqvGen r y b)
        ∨ (Relation.EqvGen r x b ∧ Relation.EqvGen r y a) := by
  rw [eqvGen_addEdge_iff_pairRel]
  constructor
  · intro hxy
    rcases hxy with hxy | hxab | hxba
    · exact Or.inl (Quotient.exact hxy)
    · exact Or.inr (Or.inl ⟨Quotient.exact hxab.1, Quotient.exact hxab.2⟩)
    · exact Or.inr (Or.inr ⟨Quotient.exact hxba.1, Quotient.exact hxba.2⟩)
  · intro hxy
    rcases hxy with hxy | hxab | hxba
    · exact Or.inl (Quotient.sound hxy)
    · exact Or.inr (Or.inl ⟨Quotient.sound hxab.1, Quotient.sound hxab.2⟩)
    · exact Or.inr (Or.inr ⟨Quotient.sound hxba.1, Quotient.sound hxba.2⟩)

 def quotientEquivOfRelIff {α : Type u} (s t : Setoid α)
    (h : ∀ x y : α, s.r x y ↔ t.r x y) :
    Quotient s ≃ Quotient t where
  toFun := Quotient.map id (by
    intro x y hxy
    exact (h x y).1 hxy)
  invFun := Quotient.map id (by
    intro x y hxy
    exact (h x y).2 hxy)
  left_inv := by
    intro q
    refine Quotient.inductionOn q ?_
    intro x
    rfl
  right_inv := by
    intro q
    refine Quotient.inductionOn q ?_
    intro x
    rfl

 def pairRep {α : Type u} [DecidableEq α] {a b : α} (hab : a ≠ b)
    (x : α) : {x : α // x ≠ b} :=
  if hx : x = b then ⟨a, hab⟩ else ⟨x, hx⟩

 def pairQuotEquivSubtypeNe {α : Type u} [DecidableEq α] {a b : α}
    (hab : a ≠ b) :
    Quotient (pairSetoid a b) ≃ {x : α // x ≠ b} where
  toFun := Quotient.lift (pairRep hab) (by
    intro x y hxy
    change pairRel a b x y at hxy
    rcases hxy with rfl | ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩
    · rfl
    · simp [pairRep, hab]
    · simp [pairRep, hab])
  invFun := fun x => Quotient.mk (pairSetoid a b) x.1
  left_inv := by
    intro q
    refine Quotient.inductionOn q ?_
    intro x
    dsimp
    by_cases hx : x = b
    · subst x
      simp [pairRep]
      exact Quotient.sound (Or.inr (Or.inl ⟨rfl, rfl⟩))
    · simp [pairRep, hx]
  right_inv := by
    intro x
    ext
    simp [pairRep, x.2]

 theorem pairSetoid_card_add_one {α : Type u} [Fintype α] [DecidableEq α]
    {a b : α} (hab : a ≠ b) :
    Nat.card (Quotient (pairSetoid a b)) + 1 = Nat.card α := by
  classical
  haveI : Fintype (Quotient (pairSetoid a b)) := Quotient.fintype (pairSetoid a b)
  rw [Nat.card_eq_fintype_card, Nat.card_eq_fintype_card]
  have hcardEquiv :
      Fintype.card (Quotient (pairSetoid a b)) = Fintype.card {x : α // x ≠ b} :=
    Fintype.card_congr (pairQuotEquivSubtypeNe hab)
  rw [hcardEquiv]
  have hcompl := Fintype.card_subtype_compl (fun x : α => x = b)
  have hsingle : Fintype.card {x : α // x = b} = 1 := by
    rw [Fintype.card_eq_one_iff]
    refine ⟨⟨b, rfl⟩, ?_⟩
    intro y
    ext
    exact y.2
  rw [hcompl, hsingle]
  have hpos : 0 < Fintype.card α := Fintype.card_pos_iff.mpr ⟨b⟩
  omega

 def compAddQuotEquivPairQuot (r : V → V → Prop) (a b : V) :
    Quotient (compSetoid (addEdge r a b)) ≃
      Quotient
        (pairSetoid (Quotient.mk (compSetoid r) a) (Quotient.mk (compSetoid r) b)) where
  toFun := Quotient.lift
    (fun x =>
      Quotient.mk
        (pairSetoid (Quotient.mk (compSetoid r) a) (Quotient.mk (compSetoid r) b))
        (Quotient.mk (compSetoid r) x))
    (by
      intro x y hxy
      exact Quotient.sound ((eqvGen_addEdge_iff_pairRel r a b x y).1 hxy))
  invFun :=
    Quotient.lift
      (Quotient.map id (by
        intro x y hxy
        exact eqvGen_le_addEdge r a b hxy))
      (by
        intro x y hxy
        change pairRel (Quotient.mk (compSetoid r) a) (Quotient.mk (compSetoid r) b) x y
          at hxy
        rcases hxy with rfl | ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩
        · rfl
        · exact Quotient.sound (Relation.EqvGen.rel a b (Or.inr (Or.inl ⟨rfl, rfl⟩)))
        · exact Quotient.sound (Relation.EqvGen.rel b a (Or.inr (Or.inr ⟨rfl, rfl⟩))))
  left_inv := by
    intro q
    refine Quotient.inductionOn q ?_
    intro x
    rfl
  right_inv := by
    intro q
    refine Quotient.inductionOn q ?_
    intro x
    refine Quotient.inductionOn x ?_
    intro v
    rfl

omit [Fintype V] in
theorem numComp_addEdge_of_eqvGen (r : V → V → Prop) {a b : V}
    (h : Relation.EqvGen r a b) :
    numComp (addEdge r a b) = numComp r := by
  unfold numComp
  apply Nat.card_congr
  refine quotientEquivOfRelIff (compSetoid (addEdge r a b)) (compSetoid r) ?_
  intro x y
  constructor
  · intro hxy
    change Relation.EqvGen (addEdge r a b) x y at hxy
    rw [eqvGen_addEdge_iff] at hxy
    rcases hxy with hxy | hxab | hxba
    · exact hxy
    · exact Relation.EqvGen.trans x a y hxab.1
        (Relation.EqvGen.trans a b y h (Relation.EqvGen.symm y b hxab.2))
    · exact Relation.EqvGen.trans x b y hxba.1
        (Relation.EqvGen.trans b a y (Relation.EqvGen.symm a b h)
          (Relation.EqvGen.symm y a hxba.2))
  · intro hxy
    exact eqvGen_le_addEdge r a b hxy

theorem numComp_addEdge_of_not_eqvGen (r : V → V → Prop) {a b : V}
    (h : ¬ Relation.EqvGen r a b) :
    numComp (addEdge r a b) + 1 = numComp r := by
  classical
  let Q := Quotient (compSetoid r)
  let A : Q := Quotient.mk (compSetoid r) a
  let B : Q := Quotient.mk (compSetoid r) b
  haveI : Fintype Q := Quotient.fintype (compSetoid r)
  have hAB : A ≠ B := by
    intro hq
    exact h (Quotient.exact hq)
  unfold numComp
  change Nat.card (Quotient (compSetoid (addEdge r a b))) + 1 = Nat.card Q
  have hcard :
      Nat.card
          (Quotient
            (pairSetoid (Quotient.mk (compSetoid r) a) (Quotient.mk (compSetoid r) b)))
          + 1 =
        Nat.card Q := by
    simpa [Q, A, B] using pairSetoid_card_add_one hAB
  rw [Nat.card_congr (compAddQuotEquivPairQuot r a b)]
  exact hcard

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapEuler
import ProofsInTheBook.PermTranspositionCycleCount
import ProofsInTheBook.RelationComponentCount
-/
/- Source module: ProofsInTheBook.PlanarMapEulerInequality -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



open scoped Classical in
/-- The repo's orbit count (`Fintype.card (Quotient (cycleSetoid p))`) agrees with
`_root_.numCycles p` (built from `SameCycle.setoid`): the two setoids
carry the identical relation `p.SameCycle`. -/
lemma card_cycleSetoid_eq_numCycles (p : Equiv.Perm D) :
    Fintype.card (Quotient (cycleSetoid p)) = _root_.numCycles p := by
  classical
  unfold _root_.numCycles
  exact Fintype.card_congr
    (Quotient.congr (Equiv.refl D) (fun x y => by rfl))

lemma V_eq_numCycles (M : CombMap D) : M.V = _root_.numCycles M.σ :=
  card_cycleSetoid_eq_numCycles M.σ
lemma E_eq_numCycles (M : CombMap D) : M.E = _root_.numCycles M.α :=
  card_cycleSetoid_eq_numCycles M.α
lemma F_eq_numCycles (M : CombMap D) : M.F = _root_.numCycles M.φ :=
  card_cycleSetoid_eq_numCycles M.φ



/-- The dart-incidence relation of a raw pair `(σ, α)`: two darts are adjacent if
they share a `σ`-orbit (same vertex) or are joined by the `α`-edge. -/
def dartStepRel (σ α : Equiv.Perm D) (a b : D) : Prop :=
  σ.SameCycle a b ∨ b = α a

omit [Fintype D] [DecidableEq D] in
lemma dartStepRel_symm {σ α : Equiv.Perm D} (hα : α * α = 1) {a b : D}
    (h : dartStepRel σ α a b) : dartStepRel σ α b a := by
  rcases h with h | h
  · exact Or.inl h.symm
  · refine Or.inr ?_
    subst h
    have happ := congrArg (fun f : Equiv.Perm D => f a) hα
    simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ.symm



omit [Fintype D] [DecidableEq D] in
/-- `ReflTransGen` of a symmetric relation is symmetric. -/
lemma reflTransGen_symm {r : D → D → Prop} (hsymm : ∀ a b, r a b → r b a)
    {a b : D} (h : Relation.ReflTransGen r a b) : Relation.ReflTransGen r b a := by
  induction h with
  | refl => exact Relation.ReflTransGen.refl
  | tail _ hbc ih => exact Relation.ReflTransGen.head (hsymm _ _ hbc) ih

omit [Fintype D] [DecidableEq D] in
/-- For a symmetric relation, the equivalence closure is the reflexive-transitive
closure (the repo's `Connected` is phrased with `ReflTransGen`). -/
lemma eqvGen_iff_reflTransGen {r : D → D → Prop} (hsymm : ∀ a b, r a b → r b a)
    (a b : D) :
    Relation.EqvGen r a b ↔ Relation.ReflTransGen r a b := by
  constructor
  · intro h
    induction h with
    | rel x y hxy => exact Relation.ReflTransGen.single hxy
    | refl x => exact Relation.ReflTransGen.refl
    | symm x y _ ih => exact reflTransGen_symm hsymm ih
    | trans x y z _ _ ih1 ih2 => exact ih1.trans ih2
  · intro h
    induction h with
    | refl => exact Relation.EqvGen.refl a
    | tail _ hbc ih => exact Relation.EqvGen.trans _ _ _ ih (Relation.EqvGen.rel _ _ hbc)



/-- Number of `α`-transpositions. -/
noncomputable def Ehalf (α : Equiv.Perm D) : ℕ := (Equiv.Perm.support α).card / 2



/-- Removing the transposition `{a, b}` (with `α a = b`, `a ≠ b`) from an
involution `α`: the support loses exactly `a` and `b`. -/
lemma support_mul_swap_of_apply (α : Equiv.Perm D) (hα : α * α = 1)
    {a b : D} (hab : a ≠ b) (hαa : α a = b) :
    Equiv.Perm.support (α * Equiv.swap a b) = (Equiv.Perm.support α) \ {a, b} := by
  classical
  have hαb : α b = a := by
    have happ := congrArg (fun f : Equiv.Perm D => f a) hα
    have : α (α a) = a := by
      simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
    rw [hαa] at this; exact this
  ext x
  simp only [Equiv.Perm.mem_support, Finset.mem_sdiff, Finset.mem_insert,
    Finset.mem_singleton, ne_eq]
  constructor
  · intro hx
    rcases eq_or_ne x a with rfl | hxa
    · exact absurd (by rw [Equiv.Perm.mul_apply, Equiv.swap_apply_left, hαb]) hx
    · rcases eq_or_ne x b with rfl | hxb
      · exact absurd (by rw [Equiv.Perm.mul_apply, Equiv.swap_apply_right, hαa]) hx
      · refine ⟨?_, fun h => by rcases h with h | h <;> simp_all⟩
        rw [Equiv.Perm.mul_apply, Equiv.swap_apply_of_ne_of_ne hxa hxb] at hx
        exact hx
  · rintro ⟨hx, hx2⟩
    push_neg at hx2
    obtain ⟨hxa, hxb⟩ := hx2
    rw [Equiv.Perm.mul_apply, Equiv.swap_apply_of_ne_of_ne hxa hxb]
    exact hx

/-- `a` and `b` are distinct elements of `support α` when `α a = b`. -/
lemma mem_support_of_apply_ne {α : Equiv.Perm D} {a b : D} (hab : a ≠ b)
    (hαa : α a = b) : a ∈ Equiv.Perm.support α ∧ b ∈ Equiv.Perm.support α := by
  classical
  constructor
  · rw [Equiv.Perm.mem_support, hαa]; exact hab.symm
  · rw [Equiv.Perm.mem_support]
    intro hb
    -- if `α b = b` then `α a = b` and injectivity force `a = b`
    exact hab (α.injective (by rw [hαa, hb]))

/-- Deleting one transposition drops `Ehalf` by exactly one. -/
lemma Ehalf_mul_swap (α : Equiv.Perm D) (hα : α * α = 1)
    {a b : D} (hab : a ≠ b) (hαa : α a = b) :
    Ehalf (α * Equiv.swap a b) + 1 = Ehalf α := by
  classical
  have hαb : α b = a := by
    have happ := congrArg (fun f : Equiv.Perm D => f a) hα
    have : α (α a) = a := by
      simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
    rw [hαa] at this; exact this
  have hsupp := support_mul_swap_of_apply α hα hab hαa
  obtain ⟨ha, hb⟩ := mem_support_of_apply_ne hab hαa
  have hpair : ({a, b} : Finset D) ⊆ Equiv.Perm.support α := by
    intro x hx
    simp only [Finset.mem_insert, Finset.mem_singleton] at hx
    rcases hx with rfl | rfl <;> assumption
  have hcard2 : ({a, b} : Finset D).card = 2 := by
    rw [Finset.card_pair hab]
  have hinter : ({a, b} : Finset D) ∩ Equiv.Perm.support α = {a, b} :=
    Finset.inter_eq_left.mpr hpair
  have hcards : (Equiv.Perm.support (α * Equiv.swap a b)).card
      = (Equiv.Perm.support α).card - 2 := by
    rw [hsupp, Finset.card_sdiff, hinter, hcard2]
  -- `support α` has even cardinality (involution), and contains the 2-element pair.
  have heven : 2 ∣ (Equiv.Perm.support α).card :=
    Equiv.Perm.two_dvd_card_support (by
      have : α ^ 2 = 1 := by rw [pow_two]; exact hα
      exact this)
  have h2le : 2 ≤ (Equiv.Perm.support α).card := by
    have := Finset.card_le_card hpair
    rwa [hcard2] at this
  unfold Ehalf
  rw [hcards]
  omega



open Relation in
/-- One application of `σ * α` is a 2-step `dartStepRel` walk `x → α x → σ(α x)`. -/
lemma reflTransGen_dartStepRel_mul_apply (σ α : Equiv.Perm D) (x : D) :
    ReflTransGen (dartStepRel σ α) x ((σ * α) x) := by
  have h1 : dartStepRel σ α x (α x) := Or.inr rfl
  have h2 : dartStepRel σ α (α x) ((σ * α) x) := by
    refine Or.inl ?_
    have hmul : (σ * α) x = σ (α x) := rfl
    rw [hmul]
    exact ⟨1, by simp⟩
  exact (ReflTransGen.single h1).tail h2

open Relation in
/-- A `σα`-power walk lifts to a `dartStepRel` reflexive-transitive walk. -/
lemma reflTransGen_dartStepRel_of_pow (σ α : Equiv.Perm D) :
    ∀ (k : ℕ) (x : D), ReflTransGen (dartStepRel σ α) x (((σ * α) ^ k) x) := by
  intro k
  induction k with
  | zero => intro x; simpa using ReflTransGen.refl
  | succ k ih =>
      intro x
      have hstep := reflTransGen_dartStepRel_mul_apply σ α (((σ * α) ^ k) x)
      have hpow : ((σ * α) ^ (k + 1)) x = (σ * α) (((σ * α) ^ k) x) := by
        rw [pow_succ']; rfl
      rw [hpow]
      exact (ih x).trans hstep

open Relation in
/-- Same `σα`-cycle implies the two darts are `dartStepRel`-connected. -/
lemma eqvGen_dartStepRel_of_sameCycle_mul (σ α : Equiv.Perm D) (hα : α * α = 1)
    {a b : D} (h : (σ * α).SameCycle a b) :
    EqvGen (dartStepRel σ α) a b := by
  rw [eqvGen_iff_reflTransGen (fun x y => dartStepRel_symm hα)]
  obtain ⟨k, hk⟩ := h.exists_nat_pow_eq
  rw [← hk]
  exact reflTransGen_dartStepRel_of_pow σ α k a



/-- With `α a = b`, `α b = a`, `a ≠ b`, the dart relation of `α` is the dart
relation of `α' = α * swap a b` (which fixes `a, b`) with the single edge `{a, b}`
re-added. -/
lemma dartStepRel_eq_addEdge (σ α : Equiv.Perm D) (hα : α * α = 1)
    {a b : D} (hab : a ≠ b) (hαa : α a = b) :
    dartStepRel σ α
      = _root_.addEdge (dartStepRel σ (α * Equiv.swap a b)) a b := by
  have hαb : α b = a := by
    have happ := congrArg (fun f : Equiv.Perm D => f a) hα
    have hh : α (α a) = a := by simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
    rw [hαa] at hh; exact hh
  funext x y
  simp only [dartStepRel, _root_.addEdge, eq_iff_iff]
  have hrefl : σ.SameCycle x x := Equiv.Perm.SameCycle.refl σ x
  rcases eq_or_ne x a with rfl | hxa
  · -- `x = a`: `a` is eliminated, the surviving name is `x`
    have hα' : (α * Equiv.swap x b) x = x := by
      rw [Equiv.Perm.mul_apply, Equiv.swap_apply_left, hαb]
    rw [hαa, hα']
    constructor
    · rintro (h | h)
      · exact Or.inl (Or.inl h)
      · subst h; exact Or.inr (Or.inl ⟨rfl, rfl⟩)
    · rintro ((h | h) | ⟨_, h⟩ | ⟨hxb, _⟩)
      · exact Or.inl h
      · exact Or.inl (h ▸ hrefl)
      · exact Or.inr h
      · exact absurd hxb hab
  · rcases eq_or_ne x b with rfl | hxb
    · -- `x = b`: surviving name is `x`
      have hα' : (α * Equiv.swap a x) x = x := by
        rw [Equiv.Perm.mul_apply, Equiv.swap_apply_right, hαa]
      rw [hαb, hα']
      constructor
      · rintro (h | h)
        · exact Or.inl (Or.inl h)
        · subst h; exact Or.inr (Or.inr ⟨rfl, rfl⟩)
      · rintro ((h | h) | ⟨hxa', _⟩ | ⟨_, h⟩)
        · exact Or.inl h
        · exact Or.inl (h ▸ hrefl)
        · exact absurd hxa' hxa
        · exact Or.inr h
    · have hα' : (α * Equiv.swap a b) x = α x := by
        rw [Equiv.Perm.mul_apply, Equiv.swap_apply_of_ne_of_ne hxa hxb]
      rw [hα']
      constructor
      · rintro (h | h)
        · exact Or.inl (Or.inl h)
        · exact Or.inl (Or.inr h)
      · rintro ((h | h) | ⟨hxa', _⟩ | ⟨hxb', _⟩)
        · exact Or.inl h
        · exact Or.inr h
        · exact absurd hxa' hxa
        · exact absurd hxb' hxb



/-- Removing one transposition from an involution leaves an involution. -/
lemma mul_swap_involutive (α : Equiv.Perm D) (hα : α * α = 1)
    {a b : D} (hαa : α a = b) (hαb : α b = a) :
    (α * Equiv.swap a b) * (α * Equiv.swap a b) = 1 := by
  ext x
  simp only [Equiv.Perm.coe_one, id_eq]
  have hαα : ∀ z, α (α z) = z := by
    intro z
    have happ := congrArg (fun f : Equiv.Perm D => f z) hα
    simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
  rcases eq_or_ne x a with rfl | hxa
  · simp only [Equiv.Perm.mul_apply, Equiv.swap_apply_left, hαb, Equiv.swap_apply_right,
      hαa]
  · rcases eq_or_ne x b with rfl | hxb
    · simp only [Equiv.Perm.mul_apply, Equiv.swap_apply_right, hαa, Equiv.swap_apply_left,
        hαb]
    · have hαxa : α x ≠ a := by
        intro h
        apply hxb
        have : x = α a := by rw [← hαα x, h]
        rw [this, hαa]
      have hαxb : α x ≠ b := by
        intro h
        apply hxa
        have : x = α b := by rw [← hαα x, h]
        rw [this, hαb]
      simp only [Equiv.Perm.mul_apply, Equiv.swap_apply_of_ne_of_ne hxa hxb,
        Equiv.swap_apply_of_ne_of_ne hαxa hαxb, hαα]



/-- Component count of the raw pair `(σ, α)`. -/
noncomputable def numComponents (σ α : Equiv.Perm D) : ℕ :=
  _root_.numComp (dartStepRel σ α)

lemma numComponents_def (σ α : Equiv.Perm D) :
    numComponents σ α = _root_.numComp (dartStepRel σ α) := rfl

/-- Genus slack `2c - V + Ehalf - F` of a raw involution pair.  It is `≥ 0`; for a
connected fixed-point-free map this yields `χ ≤ 2`. -/
noncomputable def genusSlack (σ α : Equiv.Perm D) : ℤ :=
  2 * (numComponents σ α : ℤ) - (numCycles σ : ℤ) + (Ehalf α : ℤ)
    - (numCycles (σ * α) : ℤ)


open scoped Classical in
/-- For `α = 1` the dart relation is just `σ.SameCycle`. -/
lemma dartStepRel_one (σ : Equiv.Perm D) :
    dartStepRel σ 1 = fun x y => σ.SameCycle x y := by
  funext x y
  simp only [dartStepRel, Equiv.Perm.coe_one, id_eq, eq_iff_iff]
  constructor
  · rintro (h | h)
    · exact h
    · exact h ▸ Equiv.Perm.SameCycle.refl σ x
  · intro h; exact Or.inl h

open scoped Classical in
/-- For `α = 1` the components are exactly the `σ`-orbits. -/
lemma numComponents_one (σ : Equiv.Perm D) :
    numComponents σ 1 = numCycles σ := by
  classical
  rw [numComponents_def, dartStepRel_one]
  unfold _root_.numComp _root_.numCycles
  rw [← Nat.card_eq_fintype_card]
  apply Nat.card_congr
  refine Quotient.congr (Equiv.refl D) ?_
  intro x y
  simp only [Equiv.refl_apply]
  have hrel : Relation.EqvGen (fun x y => σ.SameCycle x y) x y ↔ σ.SameCycle x y :=
    Equivalence.eqvGen_iff (Equiv.Perm.SameCycle.equivalence σ)
  exact hrel



/-- **Genus nonnegativity.** For every involution `α`, `genusSlack σ α ≥ 0`. -/
lemma genusSlack_nonneg (σ : Equiv.Perm D) :
    ∀ α : Equiv.Perm D, α * α = 1 → 0 ≤ genusSlack σ α := by
  intro α
  induction hn : (Equiv.Perm.support α).card using Nat.strong_induction_on
    generalizing α with
  | _ n ih =>
    intro hα
    rcases eq_or_ne (Equiv.Perm.support α) ∅ with hemp | hemp
    · -- base case: α = 1
      have hα1 : α = 1 := Equiv.Perm.support_eq_empty_iff.mp hemp
      subst hα1
      have hEhalf : Ehalf (1 : Equiv.Perm D) = 0 := by simp [Ehalf]
      have hmul : (σ * 1) = σ := mul_one σ
      have hcomp : numComponents σ 1 = numCycles σ := numComponents_one σ
      unfold genusSlack
      rw [hEhalf, hmul, hcomp]
      push_cast
      ring_nf
      positivity
    · -- inductive step: delete one transposition {a, b}
      obtain ⟨a, ha⟩ := Finset.nonempty_iff_ne_empty.mpr hemp
      have hane : α a ≠ a := Equiv.Perm.mem_support.mp ha
      obtain ⟨b, hαa⟩ : ∃ b, α a = b := ⟨α a, rfl⟩
      have hab : a ≠ b := fun h => hane (by rw [hαa, ← h])
      have hαb : α b = a := by
        have happ := congrArg (fun f : Equiv.Perm D => f a) hα
        have hh : α (α a) = a := by
          simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
        rw [hαa] at hh; exact hh
      set α' := α * Equiv.swap a b with hα'def
      have hα'invol : α' * α' = 1 := mul_swap_involutive α hα hαa hαb
      have hsupp' : Equiv.Perm.support α' = (Equiv.Perm.support α) \ {a, b} :=
        support_mul_swap_of_apply α hα hab hαa
      have hcard' : (Equiv.Perm.support α').card < n := by
        rw [← hn, hsupp']
        apply Finset.card_lt_card
        refine (Finset.ssubset_iff_of_subset Finset.sdiff_subset).mpr ⟨a, ha, ?_⟩
        simp
      have IHα' := ih _ hcard' α' rfl hα'invol
      have hEhalf : Ehalf α' + 1 = Ehalf α := Ehalf_mul_swap α hα hab hαa
      have hface : σ * α = (σ * α') * Equiv.swap a b := by
        rw [hα'def, mul_assoc, mul_assoc, Equiv.swap_mul_self, mul_one]
      have hrel : dartStepRel σ α = _root_.addEdge (dartStepRel σ α') a b :=
        dartStepRel_eq_addEdge σ α hα hab hαa
      have hcompEq : numComponents σ α
          = _root_.numComp (_root_.addEdge (dartStepRel σ α') a b) := by
        rw [numComponents_def, hrel]
      have hdich := _root_.numCycles_mul_swap_dichotomy (σ * α') hab
      rw [← hface] at hdich
      have hEz : (Ehalf α : ℤ) = (Ehalf α' : ℤ) + 1 := by
        have h := hEhalf; push_cast [← h]; ring
      by_cases hsame : Relation.EqvGen (dartStepRel σ α') a b
      · -- same component: numComponents unchanged
        have hC : numComponents σ α = numComponents σ α' := by
          rw [hcompEq, numComponents_def]
          exact _root_.numComp_addEdge_of_eqvGen _ hsame
        unfold genusSlack at IHα' ⊢
        rw [hC, hEz]
        rcases hdich with hd | hd
        · rw [hd]; push_cast; linarith [IHα']
        · have hF : (numCycles (σ * α) : ℤ) = (numCycles (σ * α') : ℤ) - 1 := by
            have h := hd; push_cast [← h]; ring
          rw [hF]; linarith [IHα']
      · -- different components: merge, count drops by 1; faces also merge
        have hC : numComponents σ α + 1 = numComponents σ α' := by
          rw [hcompEq, numComponents_def]
          exact _root_.numComp_addEdge_of_not_eqvGen _ hsame
        have hnsc : ¬ (σ * α').SameCycle a b := fun h =>
          hsame (eqvGen_dartStepRel_of_sameCycle_mul σ α' hα'invol h)
        have hmerge : numCycles (σ * α) + 1 = numCycles (σ * α') := by
          have h := _root_.numCycles_mul_swap_of_not_sameCycle
            (σ * α') hab hnsc
          rw [← hface] at h; exact h
        unfold genusSlack at IHα' ⊢
        have hCz : (numComponents σ α : ℤ) = (numComponents σ α' : ℤ) - 1 := by
          have h := hC; push_cast [← h]; ring
        have hFz : (numCycles (σ * α) : ℤ) = (numCycles (σ * α') : ℤ) - 1 := by
          have h := hmerge; push_cast [← h]; ring
        rw [hCz, hEz, hFz]
        linarith [IHα']



/-- For a fixed-point-free involution, every dart is in the support. -/
lemma support_eq_univ_of_no_fixed (M : CombMap D) :
    Equiv.Perm.support M.α = Finset.univ := by
  classical
  rw [Finset.eq_univ_iff_forall]
  intro d
  rw [Equiv.Perm.mem_support]
  exact M.α_no_fixed d

/-- For the (fixed-point-free) edge involution of a `CombMap`, `Ehalf = E`. -/
lemma Ehalf_eq_E (M : CombMap D) : Ehalf M.α = M.E := by
  classical
  have h2E : 2 * M.E = Fintype.card D := two_mul_E_eq_card M
  unfold Ehalf
  rw [support_eq_univ_of_no_fixed M, Finset.card_univ]
  omega

/-- `M.dartStep` is exactly `dartStepRel M.σ M.α`. -/
lemma dartStep_eq_dartStepRel (M : CombMap D) :
    M.dartStep = dartStepRel M.σ M.α := rfl

open scoped Classical in
/-- A connected map on a nonempty dart set has exactly one component. -/
lemma numComponents_eq_one_of_connected (M : CombMap D) (hconn : M.Connected)
    (d₀ : D) : numComponents M.σ M.α = 1 := by
  classical
  rw [numComponents_def]
  unfold _root_.numComp
  rw [Nat.card_eq_one_iff_unique]
  refine ⟨?_, ⟨Quotient.mk (_root_.compSetoid (dartStepRel M.σ M.α)) d₀⟩⟩
  -- subsingleton: any two quotient points are equal
  constructor
  intro x y
  refine Quotient.inductionOn₂ x y ?_
  intro a c
  apply Quotient.sound
  show Relation.EqvGen (dartStepRel M.σ M.α) a c
  rw [eqvGen_iff_reflTransGen (fun u v => dartStepRel_symm M.α_invol)]
  have h := hconn a c
  rw [dartStep_eq_dartStepRel] at h
  exact h

/-- **Euler inequality for connected combinatorial maps.** Every connected map
has Euler characteristic at most `2` (the genus-zero bound `genus ≥ 0`). -/
theorem chi_le_two_of_connected (M : CombMap D) (hconn : M.Connected) :
    M.eulerChar ≤ 2 := by
  classical
  rcases isEmpty_or_nonempty D with hD | hD
  · -- no darts: V = E = F = 0
    have hV : M.V = 0 := by simp [V, Fintype.card_eq_zero_iff]
    have hE : M.E = 0 := by simp [E, Fintype.card_eq_zero_iff]
    have hF : M.F = 0 := by simp [F, Fintype.card_eq_zero_iff]
    simp [eulerChar, hV, hE, hF]
  · obtain ⟨d₀⟩ := hD
    have hgs : 0 ≤ genusSlack M.σ M.α := genusSlack_nonneg M.σ M.α M.α_invol
    have hc : numComponents M.σ M.α = 1 :=
      numComponents_eq_one_of_connected M hconn d₀
    -- φ = σ * α
    have hφ : M.φ = M.σ * M.α := rfl
    have hVc : (M.V : ℤ) = (numCycles M.σ : ℤ) := by
      rw [V_eq_numCycles]
    have hEc : (M.E : ℤ) = (Ehalf M.α : ℤ) := by
      rw [Ehalf_eq_E]
    have hFc : (M.F : ℤ) = (numCycles (M.σ * M.α) : ℤ) := by
      rw [F_eq_numCycles, hφ]
    unfold genusSlack at hgs
    rw [hc] at hgs
    unfold eulerChar
    rw [hVc, hEc, hFc]
    push_cast at hgs ⊢
    linarith [hgs]


end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCapSigma
import ProofsInTheBook.PlanarMapEulerInequality
-/
/- Source module: ProofsInTheBook.PlanarMapCutCapCounts -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



namespace CutCapCount

/-- Multiplying by a transposition of two darts in the **same** cycle raises the
cycle count by one (the split case of the dichotomy). -/
theorem numCycles_mul_swap_of_sameCycle (p : Equiv.Perm D) {a b : D}
    (hab : a ≠ b) (hsc : p.SameCycle a b) :
    _root_.numCycles (p * Equiv.swap a b) = _root_.numCycles p + 1 := by
  rcases _root_.numCycles_mul_swap_dichotomy p hab with h | h
  · exact h
  · -- the `-1` branch would force `a, b` in different cycles; contradiction.
    exfalso
    -- `q := p * swap a b`.  If it dropped the count, the merge characterization
    -- says `a, b` were in different `p`-cycles, contradicting `hsc`.
    -- Use: count drops ⟹ not sameCycle (else the dichotomy is the `+1` branch).
    have hne := PermTranspositionCycleCount.numCycles_mul_swap_ne p hab
    -- From `h : numCycles q + 1 = numCycles p` we get `numCycles q ≠ numCycles p`.
    -- But also the split branch (which holds for sameCycle) gives `+1`.  We close
    -- by ruling out the merge branch directly via `le_mul_swap_of_sameCycle`.
    have hle : _root_.numCycles p ≤ _root_.numCycles (p * Equiv.swap a b) :=
      PermTranspositionCycleCount.numCycles_le_mul_swap_of_sameCycle p hsc
    omega





/-- **Split lemma for a list of transpositions, each splitting the running
product.**  If `l = [(u₀,v₀), …]` and, writing `Pⱼ` for `p` times the product of
the first `j` swaps (built on the right), each pair `(uⱼ,vⱼ)` is distinct and in
the **same** `Pⱼ`-cycle, then the cycle count rises by `l.length`. -/
theorem numCycles_mul_listSwap_splits (p : Equiv.Perm D) :
    ∀ l : List (D × D),
      (∀ j : Fin l.length,
        (l.get j).1 ≠ (l.get j).2 ∧
          (p * ((l.take j).map (fun w => Equiv.swap w.1 w.2)).prod).SameCycle
            (l.get j).1 (l.get j).2) →
      _root_.numCycles (p * (l.map (fun w => Equiv.swap w.1 w.2)).prod)
        = _root_.numCycles p + l.length := by
  intro l
  induction l using List.reverseRecOn with
  | nil => intro _; simp
  | append_singleton t a ih =>
      intro hsplit
      -- The running products for the prefix `t` match those for `t ++ [a]`.
      have hpre : ∀ j : Fin t.length,
          (t.get j).1 ≠ (t.get j).2 ∧
            (p * ((t.take j).map (fun w => Equiv.swap w.1 w.2)).prod).SameCycle
              (t.get j).1 (t.get j).2 := by
        intro j
        have hj : (j : ℕ) < (t ++ [a]).length := by
          simp only [List.length_append, List.length_singleton]; omega
        have hget : (t ++ [a]).get ⟨j, hj⟩ = t.get j := by
          simp only [List.get_eq_getElem]
          rw [List.getElem_append_left j.isLt]
        have htake : (t ++ [a]).take j = t.take j := by
          rw [List.take_append_of_le_length (by omega)]
        have := hsplit ⟨j, hj⟩
        rw [hget, htake] at this
        exact this
      have ihres := ih hpre
      -- Last element `a`: splits the product of the prefix.
      have hlast : ((t ++ [a]).length - 1) = t.length := by
        simp only [List.length_append, List.length_singleton]; omega
      have hjlast : t.length < (t ++ [a]).length := by
        simp only [List.length_append, List.length_singleton]; omega
      have hgetlast : (t ++ [a]).get ⟨t.length, hjlast⟩ = a := by
        simp only [List.get_eq_getElem]
        rw [List.getElem_append_right (le_refl _)]
        simp
      have htakelast : (t ++ [a]).take t.length = t := by
        rw [List.take_append_of_le_length (le_refl _), List.take_length]
      have hsa := hsplit ⟨t.length, hjlast⟩
      rw [hgetlast, htakelast] at hsa
      obtain ⟨hane, hasc⟩ := hsa
      -- Now compute the count for the full product.
      have hprodappend :
          ((t ++ [a]).map (fun w => Equiv.swap w.1 w.2)).prod
            = (t.map (fun w => Equiv.swap w.1 w.2)).prod * Equiv.swap a.1 a.2 := by
        simp [List.map_append]
      rw [hprodappend, ← mul_assoc]
      rw [numCycles_mul_swap_of_sameCycle _ hane hasc, ihres]
      simp only [List.length_append, List.length_singleton]
      omega

/-- **Merge lemma for a list of transpositions, each merging the running
product.**  If each pair `(uⱼ,vⱼ)` is distinct and in **different** `Pⱼ`-cycles,
then the cycle count *drops* by `l.length`. -/
theorem numCycles_mul_listSwap_merges (p : Equiv.Perm D) :
    ∀ l : List (D × D),
      (∀ j : Fin l.length,
        (l.get j).1 ≠ (l.get j).2 ∧
          ¬ (p * ((l.take j).map (fun w => Equiv.swap w.1 w.2)).prod).SameCycle
            (l.get j).1 (l.get j).2) →
      _root_.numCycles (p * (l.map (fun w => Equiv.swap w.1 w.2)).prod) + l.length
        = _root_.numCycles p := by
  intro l
  induction l using List.reverseRecOn with
  | nil => intro _; simp
  | append_singleton t a ih =>
      intro hmerge
      have hpre : ∀ j : Fin t.length,
          (t.get j).1 ≠ (t.get j).2 ∧
            ¬ (p * ((t.take j).map (fun w => Equiv.swap w.1 w.2)).prod).SameCycle
              (t.get j).1 (t.get j).2 := by
        intro j
        have hj : (j : ℕ) < (t ++ [a]).length := by
          simp only [List.length_append, List.length_singleton]; omega
        have hget : (t ++ [a]).get ⟨j, hj⟩ = t.get j := by
          simp only [List.get_eq_getElem]
          rw [List.getElem_append_left j.isLt]
        have htake : (t ++ [a]).take j = t.take j := by
          rw [List.take_append_of_le_length (by omega)]
        have := hmerge ⟨j, hj⟩
        rw [hget, htake] at this
        exact this
      have ihres := ih hpre
      have hjlast : t.length < (t ++ [a]).length := by
        simp only [List.length_append, List.length_singleton]; omega
      have hgetlast : (t ++ [a]).get ⟨t.length, hjlast⟩ = a := by
        simp only [List.get_eq_getElem]
        rw [List.getElem_append_right (le_refl _)]; simp
      have htakelast : (t ++ [a]).take t.length = t := by
        rw [List.take_append_of_le_length (le_refl _), List.take_length]
      have hsa := hmerge ⟨t.length, hjlast⟩
      rw [hgetlast, htakelast] at hsa
      obtain ⟨hane, hansc⟩ := hsa
      have hprodappend :
          ((t ++ [a]).map (fun w => Equiv.swap w.1 w.2)).prod
            = (t.map (fun w => Equiv.swap w.1 w.2)).prod * Equiv.swap a.1 a.2 := by
        simp [List.map_append]
      rw [hprodappend, ← mul_assoc]
      have hstep := _root_.numCycles_mul_swap_of_not_sameCycle
        (p * (t.map (fun w => Equiv.swap w.1 w.2)).prod) hane hansc
      simp only [List.length_append, List.length_singleton]
      omega



/-- A product of transpositions fixes a point disjoint from every pair. -/
lemma listSwap_prod_apply_of_notMem (x : D) :
    ∀ l : List (D × D),
      (∀ w ∈ l, x ≠ w.1 ∧ x ≠ w.2) →
      (l.map (fun w => Equiv.swap w.1 w.2)).prod x = x := by
  intro l
  induction l with
  | nil => intro _; simp
  | cons a t ih =>
      intro h
      have ha := h a List.mem_cons_self
      have ht : ∀ w ∈ t, x ≠ w.1 ∧ x ≠ w.2 := fun w hw => h w (List.mem_cons_of_mem a hw)
      rw [List.map_cons, List.prod_cons, Equiv.Perm.mul_apply, ih ht,
        Equiv.swap_apply_of_ne_of_ne ha.1 ha.2]



section SumCongr

variable {α β : Type*} [Fintype α] [DecidableEq α] [Fintype β] [DecidableEq β]

@[simp] lemma sumCongr_one_apply_inl (σ : Equiv.Perm α) (a : α) :
    (Equiv.Perm.sumCongr σ (1 : Equiv.Perm β)) (Sum.inl a) = Sum.inl (σ a) := by
  simp

@[simp] lemma sumCongr_one_apply_inr (σ : Equiv.Perm α) (b : β) :
    (Equiv.Perm.sumCongr σ (1 : Equiv.Perm β)) (Sum.inr b) = Sum.inr b := by
  simp

/-- A power of `sumCongr σ 1` acts as `σ ^ n` on the left summand. -/
lemma sumCongr_one_pow_inl (σ : Equiv.Perm α) (n : ℕ) (a : α) :
    ((Equiv.Perm.sumCongr σ (1 : Equiv.Perm β)) ^ n) (Sum.inl a)
      = Sum.inl ((σ ^ n) a) := by
  induction n with
  | zero => simp
  | succ n ih => rw [pow_succ', pow_succ', Equiv.Perm.mul_apply, Equiv.Perm.mul_apply,
      ih, sumCongr_one_apply_inl]

/-- A power of `sumCongr σ 1` fixes the right summand. -/
lemma sumCongr_one_pow_inr (σ : Equiv.Perm α) (n : ℕ) (b : β) :
    ((Equiv.Perm.sumCongr σ (1 : Equiv.Perm β)) ^ n) (Sum.inr b) = Sum.inr b := by
  induction n with
  | zero => simp
  | succ n ih => rw [pow_succ', Equiv.Perm.mul_apply, ih, sumCongr_one_apply_inr]

lemma sameCycle_sumCongr_one_inl_inl (σ : Equiv.Perm α) (a a' : α) :
    (Equiv.Perm.sumCongr σ (1 : Equiv.Perm β)).SameCycle (Sum.inl a) (Sum.inl a')
      ↔ σ.SameCycle a a' := by
  constructor
  · intro h
    obtain ⟨m, hm⟩ := h.exists_nat_pow_eq
    refine ⟨(m : ℤ), ?_⟩
    rw [zpow_natCast]
    rw [sumCongr_one_pow_inl] at hm
    exact Sum.inl.inj hm
  · intro h
    obtain ⟨m, hm⟩ := SameCycle.exists_nat_pow_eq h
    exact ⟨(m : ℤ), by rw [zpow_natCast, sumCongr_one_pow_inl, hm]⟩

lemma sameCycle_sumCongr_one_inr_inr (σ : Equiv.Perm α) (b b' : β) :
    (Equiv.Perm.sumCongr σ (1 : Equiv.Perm β)).SameCycle (Sum.inr b) (Sum.inr b')
      ↔ b = b' := by
  constructor
  · intro h
    obtain ⟨m, hm⟩ := h.exists_nat_pow_eq
    rw [sumCongr_one_pow_inr] at hm; exact Sum.inr.inj hm
  · rintro rfl; exact SameCycle.rfl

lemma sameCycle_sumCongr_one_not_inl_inr (σ : Equiv.Perm α) (a : α) (b : β) :
    ¬ (Equiv.Perm.sumCongr σ (1 : Equiv.Perm β)).SameCycle (Sum.inl a) (Sum.inr b) := by
  intro h
  obtain ⟨m, hm⟩ := h.exists_nat_pow_eq
  rw [sumCongr_one_pow_inl] at hm
  exact Sum.inl_ne_inr hm

/-- The orbit-quotient bijection for the sum extension. -/
noncomputable def sumCongrOneOrbitEquiv (σ : Equiv.Perm α) :
    Quotient (SameCycle.setoid (Equiv.Perm.sumCongr σ (1 : Equiv.Perm β)))
      ≃ Quotient (SameCycle.setoid σ) ⊕ β := by
  classical
  refine
    { toFun := Quotient.lift
        (fun x => match x with
          | Sum.inl a => Sum.inl (Quotient.mk (SameCycle.setoid σ) a)
          | Sum.inr b => Sum.inr b) ?_
      invFun := fun s => match s with
        | Sum.inl q => Quotient.lift
            (fun a => Quotient.mk (SameCycle.setoid (Equiv.Perm.sumCongr σ
              (1 : Equiv.Perm β))) (Sum.inl a)) ?_ q
        | Sum.inr b => Quotient.mk _ (Sum.inr b)
      left_inv := ?_
      right_inv := ?_ }
  · -- well-defined forward
    intro x y hxy
    change (Equiv.Perm.sumCongr σ (1 : Equiv.Perm β)).SameCycle x y at hxy
    rcases x with a | b <;> rcases y with a' | b'
    · exact congrArg Sum.inl (Quotient.sound
        ((sameCycle_sumCongr_one_inl_inl σ a a').mp hxy))
    · exact absurd hxy (sameCycle_sumCongr_one_not_inl_inr σ a b')
    · exact absurd hxy.symm (sameCycle_sumCongr_one_not_inl_inr σ a' b)
    · exact congrArg Sum.inr ((sameCycle_sumCongr_one_inr_inr σ b b').mp hxy)
  · -- well-defined inverse on left
    intro a a' haa'
    change σ.SameCycle a a' at haa'
    exact Quotient.sound ((sameCycle_sumCongr_one_inl_inl σ a a').mpr haa')
  · -- left_inv
    intro q
    refine Quotient.inductionOn q ?_
    rintro (a | b) <;> rfl
  · -- right_inv
    rintro (q | b)
    · refine Quotient.inductionOn q ?_; intro a; rfl
    · rfl

/-- The cycle count of `sumCongr σ 1` is `numCycles σ + card β`. -/
theorem numCycles_sumCongr_one (σ : Equiv.Perm α) :
    _root_.numCycles (Equiv.Perm.sumCongr σ (1 : Equiv.Perm β))
      = _root_.numCycles σ + Fintype.card β := by
  classical
  unfold _root_.numCycles
  rw [Fintype.card_congr (sumCongrOneOrbitEquiv σ), Fintype.card_sum]

end SumCongr

end CutCapCount



namespace SimplePrimalCycle

variable {M : CombMap D}

open CutCapCount

/-- `σ` extended to the cut-dart set with the `2k` caps as fixed points. -/
noncomputable def sigmaLift (C : SimplePrimalCycle M) : Equiv.Perm C.CutDart :=
  Equiv.Perm.sumCongr M.σ (1 : Equiv.Perm (Fin C.len ⊕ Fin C.len))

@[simp] lemma sigmaLift_inl (C : SimplePrimalCycle M) (d : D) :
    C.sigmaLift (Sum.inl d) = Sum.inl (M.σ d) := by
  simp [sigmaLift]

@[simp] lemma sigmaLift_inr (C : SimplePrimalCycle M) (c : Fin C.len ⊕ Fin C.len) :
    C.sigmaLift (Sum.inr c) = Sum.inr c := by
  simp [sigmaLift]

/-- The cycle count of `sigmaLift` is `V + 2k`. -/
lemma numCycles_sigmaLift (C : SimplePrimalCycle M) :
    _root_.numCycles C.sigmaLift = M.V + 2 * C.len := by
  rw [sigmaLift, numCycles_sumCongr_one, M.V_eq_numCycles]
  simp [Fintype.card_sum, Fintype.card_fin]; ring

/-- The `+`-bank-end dart `ℓ_i^+ = σ⁻¹ p_i`. -/
noncomputable def lEndPlus (C : SimplePrimalCycle M) (i : Fin C.len) : C.CutDart :=
  Sum.inl (M.σ.symm (C.pDart i))

/-- The `−`-bank-end dart `ℓ_i^- = σ⁻¹ q_i`. -/
noncomputable def lEndMinus (C : SimplePrimalCycle M) (i : Fin C.len) : C.CutDart :=
  Sum.inl (M.σ.symm (C.qDart i))

/-- The `+`-cap dart. -/
def capP (C : SimplePrimalCycle M) (i : Fin C.len) : C.CutDart := Sum.inr (Sum.inl i)
/-- The `−`-cap dart. -/
def capM (C : SimplePrimalCycle M) (i : Fin C.len) : C.CutDart := Sum.inr (Sum.inr i)

end SimplePrimalCycle

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCapCounts
-/
/- Source module: ProofsInTheBook.PlanarMapCutCapV -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}

open CutCapCount



/-- `p_i` and `q_i` share the tail vertex `v_i`. -/
lemma tail_pDart_eq_tail_qDart (C : SimplePrimalCycle M) (i : Fin C.len) :
    M.tail (C.pDart i) = M.tail (C.qDart i) := by
  rw [pDart_def, qDart_def, M.tail_alpha]
  -- `head (dart (prevIdx i)) = tail (dart (nextIdx (prevIdx i))) = tail (dart i)`
  rw [← C.tail_dart_nextIdx (C.prevIdx i), C.nextIdx_prevIdx]

/-- `p_i` and `q_i` lie in the same `σ`-cycle. -/
lemma sameCycle_pDart_qDart (C : SimplePrimalCycle M) (i : Fin C.len) :
    M.σ.SameCycle (C.pDart i) (C.qDart i) := by
  have h : Quotient.mk (cycleSetoid M.σ) (C.pDart i)
      = Quotient.mk (cycleSetoid M.σ) (C.qDart i) := C.tail_pDart_eq_tail_qDart i
  exact Quotient.exact h

/-- The tail vertex of `q_i` is `M.tail (C.dart i)`, the `i`-th cycle vertex. -/
lemma tail_qDart (C : SimplePrimalCycle M) (i : Fin C.len) :
    M.tail (C.qDart i) = M.tail (C.dart i) := rfl

/-- Distinct cycle indices give `p`-darts (resp. `q`-darts) in distinct
`σ`-orbits.  The shared tail of `p_i, q_i` is the `i`-th cycle vertex
`M.tail (dart i)`, and these are pairwise distinct by `tail_inj`. -/
lemma not_sameCycle_pDart_of_ne (C : SimplePrimalCycle M) {i j : Fin C.len}
    (hij : i ≠ j) : ¬ M.σ.SameCycle (C.pDart i) (C.pDart j) := by
  intro h
  apply hij
  have hq : M.tail (C.pDart i) = M.tail (C.pDart j) := Quotient.sound h
  rw [C.tail_pDart_eq_tail_qDart i, C.tail_pDart_eq_tail_qDart j,
    C.tail_qDart i, C.tail_qDart j] at hq
  exact C.tail_inj hq



@[simp] lemma lEndPlus_ne_capP (C : SimplePrimalCycle M) (i j : Fin C.len) :
    C.lEndPlus i ≠ C.capP j := by simp [lEndPlus, capP]
@[simp] lemma lEndPlus_ne_capM (C : SimplePrimalCycle M) (i j : Fin C.len) :
    C.lEndPlus i ≠ C.capM j := by simp [lEndPlus, capM]
@[simp] lemma lEndMinus_ne_capP (C : SimplePrimalCycle M) (i j : Fin C.len) :
    C.lEndMinus i ≠ C.capP j := by simp [lEndMinus, capP]
@[simp] lemma lEndMinus_ne_capM (C : SimplePrimalCycle M) (i j : Fin C.len) :
    C.lEndMinus i ≠ C.capM j := by simp [lEndMinus, capM]

lemma capP_ne_capM (C : SimplePrimalCycle M) (i j : Fin C.len) :
    C.capP i ≠ C.capM j := by simp [capP, capM]

lemma capP_inj (C : SimplePrimalCycle M) {i j : Fin C.len} (h : C.capP i = C.capP j) :
    i = j := by simpa [capP] using h

lemma capM_inj (C : SimplePrimalCycle M) {i j : Fin C.len} (h : C.capM i = C.capM j) :
    i = j := by simpa [capM] using h

lemma lEndPlus_inj (C : SimplePrimalCycle M) {i j : Fin C.len}
    (h : C.lEndPlus i = C.lEndPlus j) : i = j := by
  simp only [lEndPlus, Sum.inl.injEq] at h
  exact C.pDart_inj (M.σ.symm.injective h)

lemma lEndMinus_inj (C : SimplePrimalCycle M) {i j : Fin C.len}
    (h : C.lEndMinus i = C.lEndMinus j) : i = j := by
  simp only [lEndMinus, Sum.inl.injEq] at h
  exact C.qDart_inj (M.σ.symm.injective h)

lemma lEndPlus_ne_lEndMinus (C : SimplePrimalCycle M) (i j : Fin C.len) :
    C.lEndPlus i ≠ C.lEndMinus j := by
  simp only [lEndPlus, lEndMinus, ne_eq, Sum.inl.injEq]
  intro h
  exact C.pDart_ne_qDart i j (M.σ.symm.injective h)



end SimplePrimalCycle

namespace CutCapCount

variable {E : Type*} [Fintype E] [DecidableEq E]



/-- A swap product fixes a point disjoint from every pair (restated for membership
hypotheses obtained from `flatMap`/`map`). -/
lemma listSwap_prod_fix (x : E) (l : List (E × E))
    (h : ∀ w ∈ l, x ≠ w.1 ∧ x ≠ w.2) :
    (l.map (fun w => Equiv.swap w.1 w.2)).prod x = x :=
  CutCapCount.listSwap_prod_apply_of_notMem x l h

/-- **Orbit-fixed transport (powers).**  If `g` fixes every point of the
`p`-cycle of `a`, then `p * g` iterates as `p` from `a`. -/
lemma pow_mul_apply_of_orbit_fixed (p g : Equiv.Perm E) {a : E}
    (hfix : ∀ y, p.SameCycle a y → g y = y) :
    ∀ n : ℕ, ((p * g) ^ n) a = (p ^ n) a := by
  intro n
  induction n with
  | zero => simp
  | succ n ih =>
      rw [pow_succ', Equiv.Perm.mul_apply, ih, Equiv.Perm.mul_apply,
        hfix ((p ^ n) a) ⟨(n : ℤ), by rw [zpow_natCast]⟩, ← Equiv.Perm.mul_apply, ← pow_succ']

/-- **Orbit-fixed transport (`SameCycle`).**  If `g` fixes every point of the
`p`-cycle of `a`, then `p.SameCycle a b` transfers to `p * g`. -/
lemma sameCycle_mul_of_orbit_fixed (p g : Equiv.Perm E) {a b : E}
    (hfix : ∀ y, p.SameCycle a y → g y = y) (hab : p.SameCycle a b) :
    (p * g).SameCycle a b := by
  obtain ⟨n, hn⟩ := hab.exists_nat_pow_eq
  exact ⟨(n : ℤ), by rw [zpow_natCast, pow_mul_apply_of_orbit_fixed p g hfix n, hn]⟩

/-- A fixed point stays fixed under all powers. -/
lemma pow_apply_of_fixed (p : Equiv.Perm E) {b : E} (hb : p b = b) :
    ∀ n : ℕ, (p ^ n) b = b := by
  intro n
  induction n with
  | zero => simp
  | succ n ih => rw [pow_succ', Equiv.Perm.mul_apply, ih, hb]

/-- A point distinct from a fixed point of `p` is not `p`-co-cyclic with it. -/
lemma not_sameCycle_of_fixed (p : Equiv.Perm E) {a b : E}
    (hb : p b = b) (hab : a ≠ b) : ¬ p.SameCycle a b := by
  intro h
  obtain ⟨n, hn⟩ := h.symm.exists_nat_pow_eq
  exact hab ((pow_apply_of_fixed p hb n).symm.trans hn).symm

end CutCapCount

namespace SimplePrimalCycle

variable {M : CombMap D}

open CutCapCount



/-- The `2k` merge swaps: for each `i`, splice the two caps into the `σ`-orbit at
`v_i` by swapping each bank-end with its cap. -/
noncomputable def mergeList (C : SimplePrimalCycle M) : List (C.CutDart × C.CutDart) :=
  (List.finRange C.len).flatMap (fun i => [(C.lEndPlus i, C.capP i), (C.lEndMinus i, C.capM i)])

/-- The `k` split swaps: for each `i`, separate the merged orbit into its two banks
by swapping the two caps. -/
noncomputable def splitList (C : SimplePrimalCycle M) : List (C.CutDart × C.CutDart) :=
  (List.finRange C.len).map (fun i => (C.capP i, C.capM i))

/-- The product of the merge swaps. -/
noncomputable def mergeProd (C : SimplePrimalCycle M) : Equiv.Perm C.CutDart :=
  (C.mergeList.map (fun w => Equiv.swap w.1 w.2)).prod

/-- The product of the split swaps. -/
noncomputable def splitProd (C : SimplePrimalCycle M) : Equiv.Perm C.CutDart :=
  (C.splitList.map (fun w => Equiv.swap w.1 w.2)).prod



/-- Over an arbitrary index list, the split product fixes `inl d`. -/
lemma splitMap_apply_inl (C : SimplePrimalCycle M) (d : D) (L : List (Fin C.len)) :
    ((L.map (fun i => (C.capP i, C.capM i))).map
        (fun w => Equiv.swap w.1 w.2)).prod (Sum.inl d) = Sum.inl d := by
  apply CutCapCount.listSwap_prod_fix
  intro w hw
  simp only [List.mem_map] at hw
  obtain ⟨i, _, rfl⟩ := hw
  exact ⟨by simp [capP], by simp [capM]⟩

/-- The split product over a `Nodup` index list sends `capP i` to `capM i` when
`i` is in the list, and fixes it otherwise. -/
lemma splitMap_apply_capP (C : SimplePrimalCycle M) (i : Fin C.len) :
    ∀ L : List (Fin C.len), L.Nodup →
      ((L.map (fun j => (C.capP j, C.capM j))).map
        (fun w => Equiv.swap w.1 w.2)).prod (C.capP i)
        = if i ∈ L then C.capM i else C.capP i := by
  intro L
  induction L with
  | nil => intro _; simp
  | cons j L' ih =>
      intro hnd
      rw [List.nodup_cons] at hnd
      obtain ⟨hj, hL'⟩ := hnd
      rw [List.map_cons, List.map_cons, List.prod_cons, Equiv.Perm.mul_apply, ih hL']
      by_cases hij : i = j
      · subst hij
        have hni : i ∉ L' := hj
        simp only [hni, if_false, List.mem_cons, true_or, if_true]
        exact Equiv.swap_apply_left _ _
      · by_cases hmem : i ∈ L'
        · simp only [hmem, if_true, List.mem_cons, or_true]
          -- apply `swap (capP j) (capM j)` to `capM i`: disjoint
          rw [Equiv.swap_apply_of_ne_of_ne
            (fun h => C.capP_ne_capM j i h.symm)
            (fun h => hij (C.capM_inj h))]
        · simp only [hmem, if_false, List.mem_cons, hij, false_or, if_false]
          -- apply `swap (capP j) (capM j)` to `capP i`: disjoint
          rw [Equiv.swap_apply_of_ne_of_ne
            (fun h => hij (C.capP_inj h)) (fun h => C.capP_ne_capM i j h)]

/-- The split product over a `Nodup` index list sends `capM i` to `capP i` when
`i` is in the list, and fixes it otherwise. -/
lemma splitMap_apply_capM (C : SimplePrimalCycle M) (i : Fin C.len) :
    ∀ L : List (Fin C.len), L.Nodup →
      ((L.map (fun j => (C.capP j, C.capM j))).map
        (fun w => Equiv.swap w.1 w.2)).prod (C.capM i)
        = if i ∈ L then C.capP i else C.capM i := by
  intro L
  induction L with
  | nil => intro _; simp
  | cons j L' ih =>
      intro hnd
      rw [List.nodup_cons] at hnd
      obtain ⟨hj, hL'⟩ := hnd
      rw [List.map_cons, List.map_cons, List.prod_cons, Equiv.Perm.mul_apply, ih hL']
      by_cases hij : i = j
      · subst hij
        have hni : i ∉ L' := hj
        simp only [hni, if_false, List.mem_cons, true_or, if_true]
        exact Equiv.swap_apply_right _ _
      · by_cases hmem : i ∈ L'
        · simp only [hmem, if_true, List.mem_cons, or_true]
          rw [Equiv.swap_apply_of_ne_of_ne
            (fun h => hij (C.capP_inj h)) (fun h => C.capP_ne_capM i j h)]
        · simp only [hmem, if_false, List.mem_cons, hij, false_or, if_false]
          rw [Equiv.swap_apply_of_ne_of_ne
            (fun h => C.capP_ne_capM j i h.symm) (fun h => hij (C.capM_inj h))]



@[simp] lemma splitProd_inl (C : SimplePrimalCycle M) (d : D) :
    C.splitProd (Sum.inl d) = Sum.inl d := by
  rw [splitProd, splitList]; exact C.splitMap_apply_inl d _

@[simp] lemma splitProd_capP (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.splitProd (C.capP i) = C.capM i := by
  rw [splitProd, splitList, C.splitMap_apply_capP i _ (List.nodup_finRange _)]
  simp [List.mem_finRange]

@[simp] lemma splitProd_capM (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.splitProd (C.capM i) = C.capP i := by
  rw [splitProd, splitList, C.splitMap_apply_capM i _ (List.nodup_finRange _)]
  simp [List.mem_finRange]







/-- Over an index list, the merge product fixes `inl d` whenever `d` is not a
bank-end (i.e. `inl d ≠ ℓ_j^±` for every `j` in the list). -/
lemma mergeMap_apply_inl_clean (C : SimplePrimalCycle M) (d : D)
    (hp : ∀ j, Sum.inl d ≠ C.lEndPlus j) (hq : ∀ j, Sum.inl d ≠ C.lEndMinus j)
    (L : List (Fin C.len)) :
    ((L.flatMap (fun i => [(C.lEndPlus i, C.capP i), (C.lEndMinus i, C.capM i)])).map
      (fun w => Equiv.swap w.1 w.2)).prod (Sum.inl d) = Sum.inl d := by
  apply CutCapCount.listSwap_prod_fix
  intro w hw
  simp only [List.mem_flatMap, List.mem_cons, List.not_mem_nil,
    or_false] at hw
  obtain ⟨j, _, hwj⟩ := hw
  rcases hwj with rfl | rfl
  · exact ⟨hp j, by simp [capP]⟩
  · exact ⟨hq j, by simp [capM]⟩

/-- Merge product over a `Nodup` list: `capP i ↦ ℓ_i^+` when `i` is present. -/
lemma mergeMap_apply_capP (C : SimplePrimalCycle M) (i : Fin C.len) :
    ∀ L : List (Fin C.len), L.Nodup →
      ((L.flatMap (fun j => [(C.lEndPlus j, C.capP j), (C.lEndMinus j, C.capM j)])).map
        (fun w => Equiv.swap w.1 w.2)).prod (C.capP i)
        = if i ∈ L then C.lEndPlus i else C.capP i := by
  intro L
  induction L with
  | nil => intro _; simp
  | cons j L' ih =>
      intro hnd
      rw [List.nodup_cons] at hnd
      obtain ⟨hj, hL'⟩ := hnd
      rw [List.flatMap_cons, List.map_append, List.prod_append, Equiv.Perm.mul_apply, ih hL']
      simp only [List.map_cons, List.map_nil, List.prod_cons, List.prod_nil, mul_one,
        Equiv.Perm.mul_apply]
      by_cases hij : i = j
      · subst hij
        have hni : i ∉ L' := hj
        simp only [hni, if_false, List.mem_cons, true_or, if_true]
        -- inner swap(ℓ⁻,c⁻) fixes capP i; outer swap(ℓ⁺,c⁺) sends capP i ↦ ℓ⁺
        rw [Equiv.swap_apply_of_ne_of_ne (by simp [capP, lEndMinus]) (C.capP_ne_capM i i),
          Equiv.swap_apply_right]
      · by_cases hmem : i ∈ L'
        · simp only [hmem, if_true, List.mem_cons, or_true]
          -- both swaps fix ℓ_i^+
          rw [Equiv.swap_apply_of_ne_of_ne (C.lEndPlus_ne_lEndMinus i j) (C.lEndPlus_ne_capM i j),
            Equiv.swap_apply_of_ne_of_ne (fun h => hij (C.lEndPlus_inj h)) (C.lEndPlus_ne_capP i j)]
        · simp only [hmem, if_false, List.mem_cons, hij, false_or, if_false]
          -- both swaps fix capP i
          rw [Equiv.swap_apply_of_ne_of_ne (by simp [capP, lEndMinus]) (C.capP_ne_capM i j),
            Equiv.swap_apply_of_ne_of_ne (fun h => (C.lEndPlus_ne_capP j i h.symm))
              (fun h => hij (C.capP_inj h))]

/-- Merge product over a `Nodup` list: `capM i ↦ ℓ_i^-` when `i` is present. -/
lemma mergeMap_apply_capM (C : SimplePrimalCycle M) (i : Fin C.len) :
    ∀ L : List (Fin C.len), L.Nodup →
      ((L.flatMap (fun j => [(C.lEndPlus j, C.capP j), (C.lEndMinus j, C.capM j)])).map
        (fun w => Equiv.swap w.1 w.2)).prod (C.capM i)
        = if i ∈ L then C.lEndMinus i else C.capM i := by
  intro L
  induction L with
  | nil => intro _; simp
  | cons j L' ih =>
      intro hnd
      rw [List.nodup_cons] at hnd
      obtain ⟨hj, hL'⟩ := hnd
      rw [List.flatMap_cons, List.map_append, List.prod_append, Equiv.Perm.mul_apply, ih hL']
      simp only [List.map_cons, List.map_nil, List.prod_cons, List.prod_nil, mul_one,
        Equiv.Perm.mul_apply]
      by_cases hij : i = j
      · subst hij
        have hni : i ∉ L' := hj
        simp only [hni, if_false, List.mem_cons, true_or, if_true]
        -- inner swap(ℓ⁻,c⁻) sends capM i ↦ ℓ⁻; outer fixes ℓ⁻
        rw [Equiv.swap_apply_right,
          Equiv.swap_apply_of_ne_of_ne (C.lEndPlus_ne_lEndMinus i i).symm
            (fun h => (C.lEndMinus_ne_capP i i) h)]
      · by_cases hmem : i ∈ L'
        · simp only [hmem, if_true, List.mem_cons, or_true]
          -- both swaps fix ℓ_i^-
          rw [Equiv.swap_apply_of_ne_of_ne (fun h => hij (C.lEndMinus_inj h)) (C.lEndMinus_ne_capM i j),
            Equiv.swap_apply_of_ne_of_ne (C.lEndPlus_ne_lEndMinus j i).symm (C.lEndMinus_ne_capP i j)]
        · simp only [hmem, if_false, List.mem_cons, hij, false_or, if_false]
          -- both swaps fix capM i
          rw [Equiv.swap_apply_of_ne_of_ne (fun h => (C.lEndMinus_ne_capM j i h.symm))
              (fun h => hij (C.capM_inj h)),
            Equiv.swap_apply_of_ne_of_ne (by simp [capM, lEndPlus]) (fun h => (C.capP_ne_capM j i h.symm))]

/-- Merge product over a `Nodup` list: `ℓ_i^+ ↦ capP i` when `i` is present. -/
lemma mergeMap_apply_lEndPlus (C : SimplePrimalCycle M) (i : Fin C.len) :
    ∀ L : List (Fin C.len), L.Nodup →
      ((L.flatMap (fun j => [(C.lEndPlus j, C.capP j), (C.lEndMinus j, C.capM j)])).map
        (fun w => Equiv.swap w.1 w.2)).prod (C.lEndPlus i)
        = if i ∈ L then C.capP i else C.lEndPlus i := by
  intro L
  induction L with
  | nil => intro _; simp
  | cons j L' ih =>
      intro hnd
      rw [List.nodup_cons] at hnd
      obtain ⟨hj, hL'⟩ := hnd
      rw [List.flatMap_cons, List.map_append, List.prod_append, Equiv.Perm.mul_apply, ih hL']
      simp only [List.map_cons, List.map_nil, List.prod_cons, List.prod_nil, mul_one,
        Equiv.Perm.mul_apply]
      by_cases hij : i = j
      · subst hij
        have hni : i ∉ L' := hj
        simp only [hni, if_false, List.mem_cons, true_or, if_true]
        -- inner fixes ℓ⁺; outer swap(ℓ⁺,c⁺) sends ℓ⁺ ↦ capP i
        rw [Equiv.swap_apply_of_ne_of_ne (C.lEndPlus_ne_lEndMinus i i) (C.lEndPlus_ne_capM i i),
          Equiv.swap_apply_left]
      · by_cases hmem : i ∈ L'
        · simp only [hmem, if_true, List.mem_cons, or_true]
          -- both swaps fix capP i
          rw [Equiv.swap_apply_of_ne_of_ne (by simp [capP, lEndMinus]) (C.capP_ne_capM i j),
            Equiv.swap_apply_of_ne_of_ne (fun h => (C.lEndPlus_ne_capP j i h.symm))
              (fun h => hij (C.capP_inj h))]
        · simp only [hmem, if_false, List.mem_cons, hij, false_or, if_false]
          -- both swaps fix ℓ_i^+
          rw [Equiv.swap_apply_of_ne_of_ne (C.lEndPlus_ne_lEndMinus i j) (C.lEndPlus_ne_capM i j),
            Equiv.swap_apply_of_ne_of_ne (fun h => hij (C.lEndPlus_inj h)) (C.lEndPlus_ne_capP i j)]

/-- Merge product over a `Nodup` list: `ℓ_i^- ↦ capM i` when `i` is present. -/
lemma mergeMap_apply_lEndMinus (C : SimplePrimalCycle M) (i : Fin C.len) :
    ∀ L : List (Fin C.len), L.Nodup →
      ((L.flatMap (fun j => [(C.lEndPlus j, C.capP j), (C.lEndMinus j, C.capM j)])).map
        (fun w => Equiv.swap w.1 w.2)).prod (C.lEndMinus i)
        = if i ∈ L then C.capM i else C.lEndMinus i := by
  intro L
  induction L with
  | nil => intro _; simp
  | cons j L' ih =>
      intro hnd
      rw [List.nodup_cons] at hnd
      obtain ⟨hj, hL'⟩ := hnd
      rw [List.flatMap_cons, List.map_append, List.prod_append, Equiv.Perm.mul_apply, ih hL']
      simp only [List.map_cons, List.map_nil, List.prod_cons, List.prod_nil, mul_one,
        Equiv.Perm.mul_apply]
      by_cases hij : i = j
      · subst hij
        have hni : i ∉ L' := hj
        simp only [hni, if_false, List.mem_cons, true_or, if_true]
        -- inner swap(ℓ⁻,c⁻) sends ℓ⁻ ↦ capM i; outer fixes capM i
        rw [Equiv.swap_apply_left,
          Equiv.swap_apply_of_ne_of_ne (fun h => (C.lEndPlus_ne_capM i i) h.symm)
            (C.capP_ne_capM i i).symm]
      · by_cases hmem : i ∈ L'
        · simp only [hmem, if_true, List.mem_cons, or_true]
          -- both swaps fix capM i
          rw [Equiv.swap_apply_of_ne_of_ne (fun h => (C.lEndMinus_ne_capM j i h.symm))
              (fun h => hij (C.capM_inj h)),
            Equiv.swap_apply_of_ne_of_ne (by simp [capM, lEndPlus]) (fun h => (C.capP_ne_capM j i h.symm))]
        · simp only [hmem, if_false, List.mem_cons, hij, false_or, if_false]
          -- both swaps fix ℓ_i^-
          rw [Equiv.swap_apply_of_ne_of_ne (fun h => hij (C.lEndMinus_inj h)) (C.lEndMinus_ne_capM i j),
            Equiv.swap_apply_of_ne_of_ne (C.lEndPlus_ne_lEndMinus j i).symm (C.lEndMinus_ne_capP i j)]



@[simp] lemma mergeProd_capP (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.mergeProd (C.capP i) = C.lEndPlus i := by
  rw [mergeProd, mergeList, C.mergeMap_apply_capP i _ (List.nodup_finRange _)]
  simp [List.mem_finRange]

@[simp] lemma mergeProd_capM (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.mergeProd (C.capM i) = C.lEndMinus i := by
  rw [mergeProd, mergeList, C.mergeMap_apply_capM i _ (List.nodup_finRange _)]
  simp [List.mem_finRange]

@[simp] lemma mergeProd_lEndPlus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.mergeProd (C.lEndPlus i) = C.capP i := by
  rw [mergeProd, mergeList, C.mergeMap_apply_lEndPlus i _ (List.nodup_finRange _)]
  simp [List.mem_finRange]

@[simp] lemma mergeProd_lEndMinus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.mergeProd (C.lEndMinus i) = C.capM i := by
  rw [mergeProd, mergeList, C.mergeMap_apply_lEndMinus i _ (List.nodup_finRange _)]
  simp [List.mem_finRange]

@[simp] lemma splitProd_lEndPlus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.splitProd (C.lEndPlus i) = C.lEndPlus i := by rw [lEndPlus, splitProd_inl]
@[simp] lemma splitProd_lEndMinus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.splitProd (C.lEndMinus i) = C.lEndMinus i := by rw [lEndMinus, splitProd_inl]

/-- `mergeProd` fixes `inl d` when `d` is not a bank-end. -/
lemma mergeProd_inl_clean (C : SimplePrimalCycle M) {d : D}
    (hp : ∀ i, Sum.inl d ≠ C.lEndPlus i) (hq : ∀ i, Sum.inl d ≠ C.lEndMinus i) :
    C.mergeProd (Sum.inl d) = Sum.inl d := by
  rw [mergeProd, mergeList]; exact C.mergeMap_apply_inl_clean d hp hq _



/-- `inl d = ℓ_i^+` iff `σ d = p_i`. -/
lemma inl_eq_lEndPlus_iff (C : SimplePrimalCycle M) (d : D) (i : Fin C.len) :
    Sum.inl d = C.lEndPlus i ↔ M.σ d = C.pDart i := by
  rw [lEndPlus, Sum.inl.injEq]
  constructor
  · intro h; rw [h, M.σ.apply_symm_apply]
  · intro h; rw [← h, M.σ.symm_apply_apply]

/-- `inl d = ℓ_i^-` iff `σ d = q_i`. -/
lemma inl_eq_lEndMinus_iff (C : SimplePrimalCycle M) (d : D) (i : Fin C.len) :
    Sum.inl d = C.lEndMinus i ↔ M.σ d = C.qDart i := by
  rw [lEndMinus, Sum.inl.injEq]
  constructor
  · intro h; rw [h, M.σ.apply_symm_apply]
  · intro h; rw [← h, M.σ.symm_apply_apply]

/-- **The transposition decomposition of the cut-and-cap rotation.** -/
theorem cutSigmaPerm_eq_sigmaLift_mul (C : SimplePrimalCycle M) :
    C.cutSigmaPerm = C.sigmaLift * C.mergeProd * C.splitProd := by
  ext x
  rw [cutSigmaPerm_apply, Equiv.Perm.coe_mul, Equiv.Perm.coe_mul,
    Function.comp_apply, Function.comp_apply]
  rcases x with d | (i | i)
  · -- inl d : classify by divertKind
    rcases hd : C.divertKind d with (i | i) | u
    · -- σ d = p_i, so inl d = ℓ_i^+
      have hσ : M.σ d = C.pDart i := C.divertKind_eq_plus hd
      have hℓ : Sum.inl d = C.lEndPlus i := (C.inl_eq_lEndPlus_iff d i).2 hσ
      rw [C.cutSigma_inl_plus hd, hℓ, splitProd_lEndPlus, mergeProd_lEndPlus, capP, sigmaLift_inr]
    · have hσ : M.σ d = C.qDart i := C.divertKind_eq_minus hd
      have hℓ : Sum.inl d = C.lEndMinus i := (C.inl_eq_lEndMinus_iff d i).2 hσ
      rw [C.cutSigma_inl_minus hd, hℓ, splitProd_lEndMinus, mergeProd_lEndMinus, capM, sigmaLift_inr]
    · obtain ⟨hp, hq⟩ := C.divertKind_eq_none hd
      have hcp : ∀ i, Sum.inl d ≠ C.lEndPlus i := fun i hi =>
        hp i ((C.inl_eq_lEndPlus_iff d i).1 hi)
      have hcq : ∀ i, Sum.inl d ≠ C.lEndMinus i := fun i hi =>
        hq i ((C.inl_eq_lEndMinus_iff d i).1 hi)
      rw [C.cutSigma_inl_none hd, splitProd_inl, C.mergeProd_inl_clean hcp hcq, sigmaLift_inl]
  · -- capP i ↦ q_i
    show _ = C.sigmaLift (C.mergeProd (C.splitProd (C.capP i)))
    rw [cutSigma_capPlus, splitProd_capP, mergeProd_capM, lEndMinus, sigmaLift_inl,
      M.σ.apply_symm_apply]
  · -- capM i ↦ p_i
    show _ = C.sigmaLift (C.mergeProd (C.splitProd (C.capM i)))
    rw [cutSigma_capMinus, splitProd_capM, mergeProd_capP, lEndPlus, sigmaLift_inl,
      M.σ.apply_symm_apply]



/-- The merged permutation `Q = σ⊕1` times the merge swaps. -/
noncomputable def merged (C : SimplePrimalCycle M) : Equiv.Perm C.CutDart :=
  C.sigmaLift * C.mergeProd

lemma merged_apply (C : SimplePrimalCycle M) (x : C.CutDart) :
    C.merged x = C.sigmaLift (C.mergeProd x) := rfl

@[simp] lemma merged_capP (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.merged (C.capP i) = Sum.inl (C.pDart i) := by
  rw [merged_apply, mergeProd_capP, lEndPlus, sigmaLift_inl, M.σ.apply_symm_apply]

@[simp] lemma merged_capM (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.merged (C.capM i) = Sum.inl (C.qDart i) := by
  rw [merged_apply, mergeProd_capM, lEndMinus, sigmaLift_inl, M.σ.apply_symm_apply]

/-- On a clean dart (not a bank-end) `Q` acts as `σ`. -/
lemma merged_inl_clean (C : SimplePrimalCycle M) {d : D}
    (hp : ∀ i, M.σ d ≠ C.pDart i) (hq : ∀ i, M.σ d ≠ C.qDart i) :
    C.merged (Sum.inl d) = Sum.inl (M.σ d) := by
  have hcp : ∀ i, Sum.inl d ≠ C.lEndPlus i := fun i hi =>
    hp i ((C.inl_eq_lEndPlus_iff d i).1 hi)
  have hcq : ∀ i, Sum.inl d ≠ C.lEndMinus i := fun i hi =>
    hq i ((C.inl_eq_lEndMinus_iff d i).1 hi)
  rw [merged_apply, C.mergeProd_inl_clean hcp hcq, sigmaLift_inl]

/-- On the `+`-bank-end `ℓ_i^+` the merged map diverts to the `+`-cap. -/
lemma merged_lEndPlus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.merged (C.lEndPlus i) = C.capP i := by
  rw [merged_apply, mergeProd_lEndPlus, capP, sigmaLift_inr]

/-- On the `−`-bank-end `ℓ_i^-` the merged map diverts to the `−`-cap. -/
lemma merged_lEndMinus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.merged (C.lEndMinus i) = C.capM i := by
  rw [merged_apply, mergeProd_lEndMinus, capM, sigmaLift_inr]

/-- The merged map applied to `inl d` always lands in the `inl` summand, equal to
`inl (σ d)` away from bank-ends and to a cap at a bank-end (which equals
`inl (σ d)` after one more `Q`-step).  This is the unified statement used by the
projection. -/
lemma merged_inl (C : SimplePrimalCycle M) (d : D) :
    C.merged (Sum.inl d) = Sum.inl (M.σ d) ∨
      (∃ i, M.σ d = C.pDart i ∧ C.merged (Sum.inl d) = C.capP i) ∨
      (∃ i, M.σ d = C.qDart i ∧ C.merged (Sum.inl d) = C.capM i) := by
  by_cases hp : ∃ i, M.σ d = C.pDart i
  · obtain ⟨i, hi⟩ := hp
    right; left
    refine ⟨i, hi, ?_⟩
    rw [show Sum.inl d = C.lEndPlus i from (C.inl_eq_lEndPlus_iff d i).2 hi, merged_lEndPlus]
  · by_cases hq : ∃ i, M.σ d = C.qDart i
    · obtain ⟨i, hi⟩ := hq
      right; right
      refine ⟨i, hi, ?_⟩
      rw [show Sum.inl d = C.lEndMinus i from (C.inl_eq_lEndMinus_iff d i).2 hi, merged_lEndMinus]
    · left
      exact C.merged_inl_clean (fun i hi => hp ⟨i, hi⟩) (fun i hi => hq ⟨i, hi⟩)



/-- The projection of a cut-dart back to `D`. -/
noncomputable def proj (C : SimplePrimalCycle M) : C.CutDart → D :=
  fun x => match x with
  | Sum.inl d => d
  | Sum.inr (Sum.inl i) => C.pDart i
  | Sum.inr (Sum.inr i) => C.qDart i

@[simp] lemma proj_inl (C : SimplePrimalCycle M) (d : D) : C.proj (Sum.inl d) = d := rfl
@[simp] lemma proj_capP (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.proj (C.capP i) = C.pDart i := rfl
@[simp] lemma proj_capM (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.proj (C.capM i) = C.qDart i := rfl

/-- **The per-step projection fact.**  `proj (Q x)` is either `σ (proj x)` (the
`inl`-dart case, including the divert-to-cap step) or `proj x` (the cap case). -/
lemma proj_merged (C : SimplePrimalCycle M) (x : C.CutDart) :
    C.proj (C.merged x) = M.σ (C.proj x) ∨ C.proj (C.merged x) = C.proj x := by
  rcases x with d | (i | i)
  · -- inl d : always the σ branch
    left
    rcases C.merged_inl d with h | ⟨i, hi, h⟩ | ⟨i, hi, h⟩
    · rw [h]; rfl
    · rw [h, proj_capP, proj_inl, hi]
    · rw [h, proj_capM, proj_inl, hi]
  · -- capP i : stall branch (Q (capP i) = inl (p_i), proj = p_i = proj (capP i))
    right
    rw [show (Sum.inr (Sum.inl i) : C.CutDart) = C.capP i from rfl, merged_capP, proj_inl, proj_capP]
  · -- capM i : stall branch
    right
    rw [show (Sum.inr (Sum.inr i) : C.CutDart) = C.capM i from rfl, merged_capM, proj_inl, proj_capM]

/-- Iterating the per-step fact: `proj (Q^n x) = σ^m (proj x)` for some `m`. -/
lemma proj_merged_pow (C : SimplePrimalCycle M) (x : C.CutDart) :
    ∀ n : ℕ, ∃ m : ℕ, C.proj ((C.merged ^ n) x) = (M.σ ^ m) (C.proj x) := by
  intro n
  induction n with
  | zero => exact ⟨0, by simp⟩
  | succ n ih =>
      obtain ⟨m, hm⟩ := ih
      rcases C.proj_merged ((C.merged ^ n) x) with h | h
      · refine ⟨m + 1, ?_⟩
        rw [pow_succ', Equiv.Perm.mul_apply, h, hm, pow_succ', Equiv.Perm.mul_apply]
      · refine ⟨m, ?_⟩
        rw [pow_succ', Equiv.Perm.mul_apply, h, hm]



/-- **Backward reduction.**  Co-cyclic `inl`-darts under `Q` are co-cyclic under
`σ`. -/
lemma sameCycle_merged_inl_imp (C : SimplePrimalCycle M) {a b : D}
    (h : C.merged.SameCycle (Sum.inl a) (Sum.inl b)) : M.σ.SameCycle a b := by
  obtain ⟨n, hn⟩ := h.exists_nat_pow_eq
  obtain ⟨m, hm⟩ := C.proj_merged_pow (Sum.inl a) n
  refine ⟨(m : ℤ), ?_⟩
  rw [zpow_natCast]
  have : C.proj ((C.merged ^ n) (Sum.inl a)) = b := by rw [hn]; rfl
  rw [hm, proj_inl] at this
  exact this

/-- One `σ`-step lifts to a `Q`-relation on `inl`-darts. -/
lemma sameCycle_merged_inl_sigma_step (C : SimplePrimalCycle M) (a : D) :
    C.merged.SameCycle (Sum.inl a) (Sum.inl (M.σ a)) := by
  by_cases hp : ∃ i, M.σ a = C.pDart i
  · obtain ⟨i, hi⟩ := hp
    -- inl a = ℓ_i^+, Q(ℓ_i^+) = c_i^+, Q(c_i^+) = inl(p_i) = inl(σ a)
    have hℓ : Sum.inl a = C.lEndPlus i := (C.inl_eq_lEndPlus_iff a i).2 hi
    refine ⟨(2 : ℤ), ?_⟩
    rw [show (2 : ℤ) = ((2 : ℕ) : ℤ) from rfl, zpow_natCast, pow_two, Equiv.Perm.mul_apply,
      hℓ, merged_lEndPlus, merged_capP, hi]
  · by_cases hq : ∃ i, M.σ a = C.qDart i
    · obtain ⟨i, hi⟩ := hq
      have hℓ : Sum.inl a = C.lEndMinus i := (C.inl_eq_lEndMinus_iff a i).2 hi
      refine ⟨(2 : ℤ), ?_⟩
      rw [show (2 : ℤ) = ((2 : ℕ) : ℤ) from rfl, zpow_natCast, pow_two, Equiv.Perm.mul_apply,
        hℓ, merged_lEndMinus, merged_capM, hi]
    · refine ⟨(1 : ℤ), ?_⟩
      rw [zpow_one, C.merged_inl_clean (fun i hi => hp ⟨i, hi⟩) (fun i hi => hq ⟨i, hi⟩)]

/-- **Forward reduction.**  Co-cyclic darts under `σ` lift to co-cyclic
`inl`-darts under `Q`. -/
lemma sameCycle_merged_inl_pow (C : SimplePrimalCycle M) (a : D) :
    ∀ n : ℕ, C.merged.SameCycle (Sum.inl a) (Sum.inl ((M.σ ^ n) a)) := by
  intro n
  induction n with
  | zero => simp only [pow_zero, Equiv.Perm.coe_one, id_eq]; exact Equiv.Perm.SameCycle.refl _ _
  | succ n ih =>
      have hstep := C.sameCycle_merged_inl_sigma_step ((M.σ ^ n) a)
      rw [pow_succ', Equiv.Perm.mul_apply]
      exact ih.trans hstep

lemma sameCycle_merged_inl_of_sigma (C : SimplePrimalCycle M) {a b : D}
    (h : M.σ.SameCycle a b) : C.merged.SameCycle (Sum.inl a) (Sum.inl b) := by
  obtain ⟨n, hn⟩ := h.exists_nat_pow_eq
  have := C.sameCycle_merged_inl_pow a n
  rwa [hn] at this



/-- Each cap is `Q`-co-cyclic with its bank-start `inl`-dart. -/
lemma sameCycle_merged_capP_inl (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.merged.SameCycle (C.capP i) (Sum.inl (C.pDart i)) :=
  ⟨(1 : ℤ), by rw [zpow_one, merged_capP]⟩

lemma sameCycle_merged_capM_inl (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.merged.SameCycle (C.capM i) (Sum.inl (C.qDart i)) :=
  ⟨(1 : ℤ), by rw [zpow_one, merged_capM]⟩

/-- The two caps at `v_i` are `Q`-co-cyclic (reduces to `σ.SameCycle p_i q_i`). -/
lemma sameCycle_merged_capP_capM (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.merged.SameCycle (C.capP i) (C.capM i) := by
  refine (C.sameCycle_merged_capP_inl i).trans ?_
  refine (C.sameCycle_merged_inl_of_sigma (C.sameCycle_pDart_qDart i)).trans ?_
  exact (C.sameCycle_merged_capM_inl i).symm

/-- Distinct-index caps are in different `Q`-cycles (reduces to distinct
`σ`-orbits at distinct cycle vertices). -/
lemma not_sameCycle_merged_capP_capP (C : SimplePrimalCycle M) {i j : Fin C.len}
    (hij : i ≠ j) : ¬ C.merged.SameCycle (C.capP i) (C.capP j) := by
  intro h
  apply C.not_sameCycle_pDart_of_ne hij
  apply C.sameCycle_merged_inl_imp
  exact ((C.sameCycle_merged_capP_inl i).symm.trans h).trans (C.sameCycle_merged_capP_inl j)

lemma not_sameCycle_merged_capP_capM (C : SimplePrimalCycle M) {i j : Fin C.len}
    (hij : i ≠ j) : ¬ C.merged.SameCycle (C.capP i) (C.capM j) := by
  intro h
  -- would give σ.SameCycle p_i q_j, but tail p_i = v_i ≠ v_j = tail q_j
  have hσ : M.σ.SameCycle (C.pDart i) (C.qDart j) := by
    apply C.sameCycle_merged_inl_imp
    exact ((C.sameCycle_merged_capP_inl i).symm.trans h).trans (C.sameCycle_merged_capM_inl j)
  apply hij
  have : M.tail (C.pDart i) = M.tail (C.qDart j) := Quotient.sound hσ
  rw [C.tail_pDart_eq_tail_qDart i, C.tail_qDart i, C.tail_qDart j] at this
  exact C.tail_inj this



/-- The list lengths. -/
lemma mergeList_length (C : SimplePrimalCycle M) : C.mergeList.length = 2 * C.len := by
  rw [mergeList, List.length_flatMap]
  simp only [List.length_cons, List.length_nil, List.map_const', List.sum_replicate,
    List.length_finRange, smul_eq_mul]
  ring

lemma splitList_length (C : SimplePrimalCycle M) : C.splitList.length = C.len := by
  rw [splitList, List.length_map, List.length_finRange]

/-- Every entry of `mergeList` is an `(ℓ, cap)` pair: first component `inl`, second
component a cap, and the two distinct. -/
lemma mergeList_mem (C : SimplePrimalCycle M) {w : C.CutDart × C.CutDart}
    (hw : w ∈ C.mergeList) :
    (∃ i, w = (C.lEndPlus i, C.capP i)) ∨ (∃ i, w = (C.lEndMinus i, C.capM i)) := by
  rw [mergeList, List.mem_flatMap] at hw
  obtain ⟨i, _, hwi⟩ := hw
  simp only [List.mem_cons, List.not_mem_nil, or_false] at hwi
  rcases hwi with rfl | rfl
  · exact Or.inl ⟨i, rfl⟩
  · exact Or.inr ⟨i, rfl⟩

/-- The caps as a flat list. -/
lemma mergeList_map_snd (C : SimplePrimalCycle M) :
    C.mergeList.map Prod.snd
      = (List.finRange C.len).flatMap (fun i => [C.capP i, C.capM i]) := by
  rw [mergeList, List.map_flatMap]
  rfl

/-- The second components of `mergeList` (the caps) are pairwise distinct. -/
lemma mergeList_snd_nodup (C : SimplePrimalCycle M) :
    (C.mergeList.map Prod.snd).Nodup := by
  rw [mergeList_map_snd]
  apply List.nodup_flatMap.2
  refine ⟨?_, ?_⟩
  · intro i _
    simp only [List.nodup_cons, List.mem_cons, List.not_mem_nil, or_false, List.nodup_nil,
      and_true]
    exact ⟨C.capP_ne_capM i i, not_false⟩
  · apply (List.nodup_finRange C.len).pairwise_of_forall_ne
    intro i _ j _ hij
    rw [Function.onFun, List.disjoint_left]
    intro x hx hx'
    simp only [List.mem_cons, List.not_mem_nil, or_false, capP, capM] at hx hx'
    rcases hx with rfl | rfl <;> rcases hx' with h | h <;> exact hij (by simp_all)

/-- The first component of any `mergeList` entry is an `inl` dart. -/
lemma mergeList_fst_inl (C : SimplePrimalCycle M) {w : C.CutDart × C.CutDart}
    (hw : w ∈ C.mergeList) : ∃ d : D, w.1 = Sum.inl d := by
  rcases C.mergeList_mem hw with ⟨i, rfl⟩ | ⟨i, rfl⟩
  · exact ⟨_, rfl⟩
  · exact ⟨_, rfl⟩

/-- The second component of any `mergeList` entry is a cap (an `inr` dart). -/
lemma mergeList_snd_inr (C : SimplePrimalCycle M) {w : C.CutDart × C.CutDart}
    (hw : w ∈ C.mergeList) : ∃ c, w.2 = Sum.inr c := by
  rcases C.mergeList_mem hw with ⟨i, rfl⟩ | ⟨i, rfl⟩
  · exact ⟨_, rfl⟩
  · exact ⟨_, rfl⟩

/-- Each `mergeList` pair has distinct first and second components. -/
lemma mergeList_fst_ne_snd (C : SimplePrimalCycle M) {w : C.CutDart × C.CutDart}
    (hw : w ∈ C.mergeList) : w.1 ≠ w.2 := by
  obtain ⟨d, hd⟩ := C.mergeList_fst_inl hw
  obtain ⟨c, hc⟩ := C.mergeList_snd_inr hw
  rw [hd, hc]; exact Sum.inl_ne_inr

/-- The cap at position `j` does not occur in the prefix `mergeList.take j`. -/
lemma mergeList_get_snd_not_mem_take (C : SimplePrimalCycle M) (j : Fin C.mergeList.length)
    {w : C.CutDart × C.CutDart} (hw : w ∈ C.mergeList.take j) :
    (C.mergeList.get j).2 ≠ w.1 ∧ (C.mergeList.get j).2 ≠ w.2 := by
  have hwmem : w ∈ C.mergeList := List.mem_of_mem_take hw
  -- the cap (get j).2 is an `inr`; w.1 is `inl`
  obtain ⟨c, hc⟩ := C.mergeList_snd_inr (List.get_mem C.mergeList j)
  obtain ⟨d, hd⟩ := C.mergeList_fst_inl hwmem
  refine ⟨by rw [hc, hd]; exact Sum.inr_ne_inl, ?_⟩
  -- distinctness of the second components via the Nodup of `mergeList.map .2`
  intro hcontra
  have hnd := C.mergeList_snd_nodup
  obtain ⟨k, hk, hwk⟩ := List.mem_iff_getElem.1 hw
  have hkj : k < (j : ℕ) := lt_of_lt_of_le hk (List.length_take_le _ _)
  have hklt : k < C.mergeList.length := hkj.trans j.isLt
  rw [List.getElem_take] at hwk
  -- (map .2)[j] = (map .2)[k] forces j = k, but k < j
  have hmapj : (C.mergeList.map Prod.snd)[(j : ℕ)]'(by simp [j.isLt]) = (C.mergeList.get j).2 := by
    simp [List.getElem_map]
  have hmapk : (C.mergeList.map Prod.snd)[k]'(by simp [hklt]) = w.2 := by
    simp [List.getElem_map, hwk]
  have hjk : (j : ℕ) = k := by
    apply (hnd.getElem_inj_iff).1
    rw [hmapj, hmapk, hcontra]
  omega

/-- Any `splitList` entry is a cap pair. -/
lemma splitList_mem (C : SimplePrimalCycle M) {w : C.CutDart × C.CutDart}
    (hw : w ∈ C.splitList) : ∃ idx, w = (C.capP idx, C.capM idx) := by
  rw [splitList, List.mem_map] at hw
  obtain ⟨i, _, rfl⟩ := hw; exact ⟨i, rfl⟩

/-- The index carried by `splitList.get j`. -/
lemma splitList_get (C : SimplePrimalCycle M) (j : Fin C.splitList.length) :
    ∃ idx : Fin C.len, C.splitList.get j = (C.capP idx, C.capM idx) :=
  C.splitList_mem (List.get_mem C.splitList j)

/-- `splitList` is `Nodup`. -/
lemma splitList_nodup (C : SimplePrimalCycle M) : C.splitList.Nodup := by
  rw [splitList]
  apply (List.nodup_finRange C.len).map
  intro i j h
  exact C.capP_inj (Prod.ext_iff.1 h).1

/-- The index at position `j` of `splitList` differs from every prefix index. -/
lemma splitList_take_index_ne (C : SimplePrimalCycle M) (j : Fin C.splitList.length)
    {idx idx' : Fin C.len} (hidx : C.splitList.get j = (C.capP idx, C.capM idx))
    (hw : (C.capP idx', C.capM idx') ∈ C.splitList.take j) : idx' ≠ idx := by
  obtain ⟨k, hk, hwk⟩ := List.mem_iff_getElem.1 hw
  have hkj : k < (j : ℕ) := lt_of_lt_of_le hk (List.length_take_le _ _)
  have hklt : k < C.splitList.length := hkj.trans j.isLt
  rw [List.getElem_take] at hwk
  intro hcontra; subst hcontra
  -- splitList[k] = (capP idx, capM idx) = splitList[j], so k = j by Nodup
  have hkj_eq : k = (j : ℕ) := by
    have := (C.splitList_nodup.getElem_inj_iff (i := k) (hi := hklt) (j := (j : ℕ))
      (hj := j.isLt)).1
    apply this
    rw [hwk]
    exact hidx.symm
  omega

/-- **Merge phase.**  `numCycles (sigmaLift * mergeProd) + 2k = numCycles sigmaLift`. -/
lemma numCycles_merged_add (C : SimplePrimalCycle M) :
    _root_.numCycles C.merged + C.mergeList.length = _root_.numCycles C.sigmaLift := by
  rw [merged, mergeProd]
  apply CutCapCount.numCycles_mul_listSwap_merges
  intro j
  have hget : C.mergeList.get j ∈ C.mergeList := List.get_mem C.mergeList j
  refine ⟨C.mergeList_fst_ne_snd hget, ?_⟩
  -- the cap (get j).2 is fixed by `sigmaLift * (prefix)` ⟹ not co-cyclic with (get j).1
  apply CutCapCount.not_sameCycle_of_fixed
  · -- fixed: prefix product fixes the cap, sigmaLift fixes the cap
    rw [Equiv.Perm.mul_apply]
    obtain ⟨c, hc⟩ := C.mergeList_snd_inr hget
    rw [CutCapCount.listSwap_prod_apply_of_notMem _ _
      (fun w hw => C.mergeList_get_snd_not_mem_take j hw), hc, sigmaLift_inr]
  · exact C.mergeList_fst_ne_snd hget

/-- **Split phase.**  `numCycles (merged * splitProd) = numCycles merged + k`. -/
lemma numCycles_split (C : SimplePrimalCycle M) :
    _root_.numCycles (C.merged * C.splitProd)
      = _root_.numCycles C.merged + C.splitList.length := by
  rw [splitProd]
  apply CutCapCount.numCycles_mul_listSwap_splits
  intro j
  obtain ⟨idx, hidx⟩ := C.splitList_get j
  rw [hidx]
  refine ⟨C.capP_ne_capM idx idx, ?_⟩
  -- transport `merged.SameCycle (capP idx) (capM idx)` across the prefix split swaps
  apply CutCapCount.sameCycle_mul_of_orbit_fixed
  · intro y hy
    -- the prefix product fixes y, since y's `merged`-class avoids all prefix caps
    apply CutCapCount.listSwap_prod_apply_of_notMem
    intro w hw
    obtain ⟨idx', hw'⟩ := C.splitList_mem (List.mem_of_mem_take hw)
    subst hw'
    have hne : idx' ≠ idx := C.splitList_take_index_ne j hidx hw
    -- y ≠ capP idx' and y ≠ capM idx', else y co-cyclic with capP idx contradicts distinct orbits
    dsimp only
    refine ⟨fun hyc => ?_, fun hyc => ?_⟩
    · exact C.not_sameCycle_merged_capP_capP (Ne.symm hne) (hyc ▸ hy)
    · exact C.not_sameCycle_merged_capP_capM (Ne.symm hne) (hyc ▸ hy)
  · exact C.sameCycle_merged_capP_capM idx



/-- `numCycles merged = V` (the merge swaps merge each of the `2k` caps into the
`σ`-orbit at its vertex). -/
lemma numCycles_merged (C : SimplePrimalCycle M) :
    _root_.numCycles C.merged = M.V := by
  have h := C.numCycles_merged_add
  rw [numCycles_sigmaLift, mergeList_length] at h
  omega

/-- **The cut-and-cap rotation has `V + k` cycles.** -/
theorem numCycles_cutSigmaPerm (C : SimplePrimalCycle M) :
    _root_.numCycles C.cutSigmaPerm = M.V + C.len := by
  rw [cutSigmaPerm_eq_sigmaLift_mul, ← merged, numCycles_split, numCycles_merged,
    splitList_length]



end SimplePrimalCycle

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCapV
-/
/- Source module: ProofsInTheBook.PlanarMapCutCapF -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace CutCapCount

variable {E : Type*} [Fintype E] [DecidableEq E]

/-- **Cycle count is conjugation-invariant.** -/
lemma numCycles_conj (g f : Equiv.Perm E) :
    _root_.numCycles (g * f * g⁻¹) = _root_.numCycles f := by
  classical
  unfold _root_.numCycles
  refine Fintype.card_congr (Quotient.congr g⁻¹ ?_)
  intro x y
  show (g * f * g⁻¹).SameCycle x y ↔ f.SameCycle (g⁻¹ x) (g⁻¹ y)
  exact Equiv.Perm.sameCycle_conj

/-- **`numCycles` is invariant under swapping factors** (`AB ~ BA`). -/
lemma numCycles_mul_comm (a b : Equiv.Perm E) :
    _root_.numCycles (a * b) = _root_.numCycles (b * a) := by
  have h : b * a = a⁻¹ * (a * b) * a⁻¹⁻¹ := by group
  rw [h, numCycles_conj]

end CutCapCount

namespace SimplePrimalCycle

variable {M : CombMap D}

open CutCapCount









/-- `φ = σ*α` extended to the cut-dart set, caps as fixed points. -/
noncomputable def phiLift (C : SimplePrimalCycle M) : Equiv.Perm C.CutDart :=
  Equiv.Perm.sumCongr M.φ (1 : Equiv.Perm (Fin C.len ⊕ Fin C.len))









/-- The cycle count of `phiLift` is `F + 2k`. -/
lemma numCycles_phiLift (C : SimplePrimalCycle M) :
    _root_.numCycles C.phiLift = M.F + 2 * C.len := by
  rw [phiLift, numCycles_sumCongr_one, M.F_eq_numCycles]
  simp [Fintype.card_sum, Fintype.card_fin]; ring



























end SimplePrimalCycle

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSideRecon
import ProofsInTheBook.PlanarMapCutCapCounts
import ProofsInTheBook.PlanarMapCutCapF
-/
/- Source module: ProofsInTheBook.ChordFaceCount -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordFaceCount

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.PlanarMap.CombMap.CutCapCount

universe u

variable {K : Type u} [Fintype K] [DecidableEq K]



section FacePerm

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- The face permutation of the fresh map: `freshSigma ∘ freshAlpha`. -/
lemma freshMap_phi_eq :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ
      = freshSigma ρ a₀ a₁ hne * freshAlpha β := rfl

/-- `φ` on `inl k` with `β k ≠ a₀`, `β k ≠ a₁`: the kept face permutation `ρ ∘ β`. -/
lemma freshMap_phi_inl_other {k : K} (h0 : β k ≠ a₀) (h1 : β k ≠ a₁) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ (Sum.inl k) = Sum.inl (ρ (β k)) := by
  rw [freshMap_phi_eq, Equiv.Perm.mul_apply, freshAlpha_inl,
    freshSigma_other ρ a₀ a₁ hne h0 h1]

/-- `φ (inl (β a₀)) = inr 0`. -/
lemma freshMap_phi_inl_b0 :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ (Sum.inl (β a₀)) = Sum.inr 0 := by
  have hbb : β (β a₀) = a₀ := by
    have := congrArg (fun f : Equiv.Perm K => f a₀) hβinv
    simpa [Equiv.Perm.mul_apply] using this
  rw [freshMap_phi_eq, Equiv.Perm.mul_apply, freshAlpha_inl, hbb,
    freshSigma_anchor_zero ρ a₀ a₁ hne]

/-- `φ (inl (β a₁)) = inr 1`. -/
lemma freshMap_phi_inl_b1 :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ (Sum.inl (β a₁)) = Sum.inr 1 := by
  have hbb : β (β a₁) = a₁ := by
    have := congrArg (fun f : Equiv.Perm K => f a₁) hβinv
    simpa [Equiv.Perm.mul_apply] using this
  rw [freshMap_phi_eq, Equiv.Perm.mul_apply, freshAlpha_inl, hbb,
    freshSigma_anchor_one ρ a₀ a₁ hne]

/-- `φ (inr 0) = inl (ρ a₁)`. -/
lemma freshMap_phi_inr_zero :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ (Sum.inr 0) = Sum.inl (ρ a₁) := by
  rw [freshMap_phi_eq, Equiv.Perm.mul_apply, freshAlpha_inr]
  simp only [Equiv.swap_apply_left]
  rw [freshSigma_fresh_one ρ a₀ a₁ hne]

/-- `φ (inr 1) = inl (ρ a₀)`. -/
lemma freshMap_phi_inr_one :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ (Sum.inr 1) = Sum.inl (ρ a₀) := by
  rw [freshMap_phi_eq, Equiv.Perm.mul_apply, freshAlpha_inr]
  simp only [Equiv.swap_apply_right]
  rw [freshSigma_fresh_zero ρ a₀ a₁ hne]

end FacePerm



section FaceBijection

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- The kept-side face permutation `ρ * β` (the face permutation of `keptCombMap β ρ`). -/
def keptPhi (β ρ : Equiv.Perm K) : Equiv.Perm K := ρ * β

/-- The **traced face permutation** on `K`: `ρ * β` with its values at the chord
predecessors `β a₀`, `β a₁` swapped (equivalently, multiplied on the left by the
transposition `swap (ρ a₀) (ρ a₁)`). -/
def tracePhi (β ρ : Equiv.Perm K) (a₀ a₁ : K) : Equiv.Perm K :=
  Equiv.swap (ρ a₀) (ρ a₁) * (ρ * β)

/-- The face projection collapsing each fresh dart to its face-cycle predecessor:
`inl k ↦ k`, `inr 0 ↦ β a₀`, `inr 1 ↦ β a₁`. -/
def faceProj (β : Equiv.Perm K) (a₀ a₁ : K) : K ⊕ Fin 2 → K
  | Sum.inl k => k
  | Sum.inr j => if j = 0 then β a₀ else β a₁

@[simp] lemma faceProj_inl (β : Equiv.Perm K) (a₀ a₁ k : K) :
    faceProj β a₀ a₁ (Sum.inl k) = k := rfl
@[simp] lemma faceProj_inr_zero (β : Equiv.Perm K) (a₀ a₁ : K) :
    faceProj β a₀ a₁ (Sum.inr 0) = β a₀ := rfl
@[simp] lemma faceProj_inr_one (β : Equiv.Perm K) (a₀ a₁ : K) :
    faceProj β a₀ a₁ (Sum.inr 1) = β a₁ := by simp [faceProj]

/-- `tracePhi` applied to `β a₀` is `ρ a₁` (the swapped value). -/
lemma tracePhi_b0 (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (a₀ a₁ : K) :
    tracePhi β ρ a₀ a₁ (β a₀) = ρ a₁ := by
  have hbb : β (β a₀) = a₀ := by
    have := congrArg (fun f : Equiv.Perm K => f a₀) hβinv
    simpa [Equiv.Perm.mul_apply] using this
  show Equiv.swap (ρ a₀) (ρ a₁) (ρ (β (β a₀))) = ρ a₁
  rw [hbb, Equiv.swap_apply_left]

/-- `tracePhi` applied to `β a₁` is `ρ a₀`. -/
lemma tracePhi_b1 (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (a₀ a₁ : K) :
    tracePhi β ρ a₀ a₁ (β a₁) = ρ a₀ := by
  have hbb : β (β a₁) = a₁ := by
    have := congrArg (fun f : Equiv.Perm K => f a₁) hβinv
    simpa [Equiv.Perm.mul_apply] using this
  show Equiv.swap (ρ a₀) (ρ a₁) (ρ (β (β a₁))) = ρ a₀
  rw [hbb, Equiv.swap_apply_right]

/-- Away from the two chord predecessors, `tracePhi` is the kept face permutation. -/
lemma tracePhi_other (β ρ : Equiv.Perm K) (a₀ a₁ : K) {k : K}
    (h0 : β k ≠ a₀) (h1 : β k ≠ a₁) :
    tracePhi β ρ a₀ a₁ k = ρ (β k) := by
  show Equiv.swap (ρ a₀) (ρ a₁) (ρ (β k)) = ρ (β k)
  have hk0 : ρ (β k) ≠ ρ a₀ := fun h => h0 (ρ.injective h)
  have hk1 : ρ (β k) ≠ ρ a₁ := fun h => h1 (ρ.injective h)
  rw [Equiv.swap_apply_of_ne_of_ne hk0 hk1]

/-- `β` is its own inverse on `a₀`: `β (β a₀) = a₀`. -/
 lemma beta_beta (β : Equiv.Perm K) (hβinv : β * β = 1) (a : K) : β (β a) = a := by
  have := congrArg (fun f : Equiv.Perm K => f a) hβinv
  simpa [Equiv.Perm.mul_apply] using this

/-- **Every fresh `φ`-dart is `φ`-SameCycle to the `inl` of its face projection.** -/
lemma freshPhi_sameCycle_inl_faceProj (x : K ⊕ Fin 2) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle x (Sum.inl (faceProj β a₀ a₁ x)) := by
  cases x with
  | inl k => simpa using Equiv.Perm.SameCycle.rfl
  | inr j =>
      fin_cases j
      · -- `inl (β a₀) → inr 0`, so `inr 0` is one φ-step after `inl (β a₀)`.
        show (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle (Sum.inr 0)
          (Sum.inl (faceProj β a₀ a₁ (Sum.inr 0)))
        rw [faceProj_inr_zero]
        refine ⟨-1, ?_⟩
        rw [zpow_neg, zpow_one, Equiv.Perm.inv_eq_iff_eq, freshMap_phi_inl_b0 β ρ hβinv hβfix hne]
      · show (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle (Sum.inr 1)
          (Sum.inl (faceProj β a₀ a₁ (Sum.inr 1)))
        rw [faceProj_inr_one]
        refine ⟨-1, ?_⟩
        rw [zpow_neg, zpow_one, Equiv.Perm.inv_eq_iff_eq, freshMap_phi_inl_b1 β ρ hβinv hβfix hne]

/-- **One fresh `φ`-step projects to a `tracePhi`-step (or stays put).** -/
lemma tracePhi_sameCycle_faceProj_phi_apply (x : K ⊕ Fin 2) :
    (tracePhi β ρ a₀ a₁).SameCycle (faceProj β a₀ a₁ x)
      (faceProj β a₀ a₁ ((freshMap β ρ hβinv hβfix a₀ a₁ hne).φ x)) := by
  cases x with
  | inl k =>
      by_cases h0 : β k = a₀
      · -- `k = β a₀` (since `β` involutive), `φ (inl (β a₀)) = inr 0`, proj = `β a₀`.
        have hk : k = β a₀ := by
          have h2 := congrArg β h0; rw [beta_beta β hβinv] at h2; exact h2
        subst hk
        rw [freshMap_phi_inl_b0 β ρ hβinv hβfix hne]
        simp only [faceProj_inl, faceProj_inr_zero]
        exact Equiv.Perm.SameCycle.rfl
      · by_cases h1 : β k = a₁
        · have hk : k = β a₁ := by
            have h2 := congrArg β h1; rw [beta_beta β hβinv] at h2; exact h2
          subst hk
          rw [freshMap_phi_inl_b1 β ρ hβinv hβfix hne]
          simp only [faceProj_inl, faceProj_inr_one]
          exact Equiv.Perm.SameCycle.rfl
        · rw [freshMap_phi_inl_other β ρ hβinv hβfix hne h0 h1]
          simp only [faceProj_inl]
          refine ⟨1, ?_⟩
          rw [zpow_one, tracePhi_other β ρ a₀ a₁ h0 h1]
  | inr j =>
      fin_cases j
      · -- `φ (inr 0) = inl (ρ a₁)`, proj(inr 0) = `β a₀`, tracePhi (β a₀) = ρ a₁.
        show (tracePhi β ρ a₀ a₁).SameCycle (faceProj β a₀ a₁ (Sum.inr 0))
          (faceProj β a₀ a₁ ((freshMap β ρ hβinv hβfix a₀ a₁ hne).φ (Sum.inr 0)))
        rw [freshMap_phi_inr_zero β ρ hβinv hβfix hne]
        simp only [faceProj_inr_zero, faceProj_inl]
        refine ⟨1, ?_⟩
        rw [zpow_one, tracePhi_b0 β ρ hβinv a₀ a₁]
      · show (tracePhi β ρ a₀ a₁).SameCycle (faceProj β a₀ a₁ (Sum.inr 1))
          (faceProj β a₀ a₁ ((freshMap β ρ hβinv hβfix a₀ a₁ hne).φ (Sum.inr 1)))
        rw [freshMap_phi_inr_one β ρ hβinv hβfix hne]
        simp only [faceProj_inr_one, faceProj_inl]
        refine ⟨1, ?_⟩
        rw [zpow_one, tracePhi_b1 β ρ hβinv a₀ a₁]

/-- The projections of `x` and `φ^[n] x` are always `tracePhi`-SameCycle. -/
lemma tracePhi_sameCycle_faceProj_phi_iterate (x : K ⊕ Fin 2) (n : ℕ) :
    (tracePhi β ρ a₀ a₁).SameCycle (faceProj β a₀ a₁ x)
      (faceProj β a₀ a₁ ((freshMap β ρ hβinv hβfix a₀ a₁ hne).φ^[n] x)) := by
  induction n with
  | zero => simpa using Equiv.Perm.SameCycle.rfl
  | succ n ih =>
      rw [Function.iterate_succ_apply']
      exact ih.trans (tracePhi_sameCycle_faceProj_phi_apply β ρ hβinv hβfix hne _)

/-- **Forward: a fresh `φ`-cycle projects into one `tracePhi`-cycle.** -/
lemma tracePhi_sameCycle_faceProj_of_freshPhi_sameCycle {x y : K ⊕ Fin 2}
    (h : (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle x y) :
    (tracePhi β ρ a₀ a₁).SameCycle (faceProj β a₀ a₁ x) (faceProj β a₀ a₁ y) := by
  obtain ⟨m, hm⟩ := h.exists_nat_pow_eq
  rw [← hm, Equiv.Perm.coe_pow]
  exact tracePhi_sameCycle_faceProj_phi_iterate β ρ hβinv hβfix hne x m

/-- **One `tracePhi`-step lifts to a fresh-`φ`-SameCycle of `inl`s.** -/
lemma freshPhi_sameCycle_inl_step (c : K) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle
      (Sum.inl c) (Sum.inl (tracePhi β ρ a₀ a₁ c)) := by
  by_cases h0 : β c = a₀
  · -- `c = β a₀`; `tracePhi (β a₀) = ρ a₁`; path `inl (β a₀) → inr 0 → inl (ρ a₁)`.
    have hk : c = β a₀ := by
      have h2 := congrArg β h0; rw [beta_beta β hβinv] at h2; exact h2
    subst hk
    rw [tracePhi_b0 β ρ hβinv a₀ a₁]
    refine ⟨2, ?_⟩
    rw [show (2 : ℤ) = ((2 : ℕ) : ℤ) from rfl, zpow_natCast, sq, Equiv.Perm.mul_apply,
      freshMap_phi_inl_b0 β ρ hβinv hβfix hne, freshMap_phi_inr_zero β ρ hβinv hβfix hne]
  · by_cases h1 : β c = a₁
    · have hk : c = β a₁ := by
        have h2 := congrArg β h1; rw [beta_beta β hβinv] at h2; exact h2
      subst hk
      rw [tracePhi_b1 β ρ hβinv a₀ a₁]
      refine ⟨2, ?_⟩
      rw [show (2 : ℤ) = ((2 : ℕ) : ℤ) from rfl, zpow_natCast, sq, Equiv.Perm.mul_apply,
        freshMap_phi_inl_b1 β ρ hβinv hβfix hne, freshMap_phi_inr_one β ρ hβinv hβfix hne]
    · rw [tracePhi_other β ρ a₀ a₁ h0 h1]
      refine ⟨1, ?_⟩
      rw [zpow_one, freshMap_phi_inl_other β ρ hβinv hβfix hne h0 h1]

/-- **Backward: `inl` of `tracePhi`-equal darts are fresh-`φ`-SameCycle.** -/
lemma freshPhi_sameCycle_inl_of_tracePhi_sameCycle {a b : K}
    (h : (tracePhi β ρ a₀ a₁).SameCycle a b) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle (Sum.inl a) (Sum.inl b) := by
  obtain ⟨m, hm⟩ := h.exists_nat_pow_eq
  rw [← hm, Equiv.Perm.coe_pow]
  clear hm
  induction m with
  | zero => simpa using Equiv.Perm.SameCycle.rfl
  | succ m ih =>
      rw [Function.iterate_succ_apply']
      exact ih.trans (freshPhi_sameCycle_inl_step β ρ hβinv hβfix hne _)

/-- **The fresh face / traced face correspondence.**  Two fresh darts are in the same
fresh face orbit iff their face projections are in the same `tracePhi` orbit. -/
theorem freshFace_sameCycle_iff (x y : K ⊕ Fin 2) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle x y ↔
      (tracePhi β ρ a₀ a₁).SameCycle (faceProj β a₀ a₁ x) (faceProj β a₀ a₁ y) := by
  constructor
  · exact tracePhi_sameCycle_faceProj_of_freshPhi_sameCycle β ρ hβinv hβfix hne
  · intro h
    refine (freshPhi_sameCycle_inl_faceProj β ρ hβinv hβfix hne x).trans ?_
    refine (freshPhi_sameCycle_inl_of_tracePhi_sameCycle β ρ hβinv hβfix hne h).trans ?_
    exact (freshPhi_sameCycle_inl_faceProj β ρ hβinv hβfix hne y).symm

/-- The face-orbit quotient of the fresh map is in bijection with the `tracePhi`-orbit
quotient on `K`, via the face projection `faceProj`. -/
noncomputable def freshFaceQuotientEquiv :
    Quotient (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ)
      ≃ Quotient (cycleSetoid (tracePhi β ρ a₀ a₁)) := by
  classical
  refine
    { toFun := Quotient.lift
        (fun x => Quotient.mk (cycleSetoid (tracePhi β ρ a₀ a₁)) (faceProj β a₀ a₁ x)) ?_,
      invFun := Quotient.lift
        (fun k => Quotient.mk (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ)
          (Sum.inl k)) ?_,
      left_inv := ?_, right_inv := ?_ }
  · intro x y hxy
    apply Quotient.sound
    exact (freshFace_sameCycle_iff β ρ hβinv hβfix hne x y).1 hxy
  · intro a b hab
    apply Quotient.sound
    exact freshPhi_sameCycle_inl_of_tracePhi_sameCycle β ρ hβinv hβfix hne hab
  · intro q
    refine Quotient.inductionOn q (fun x => ?_)
    apply Quotient.sound
    exact (freshPhi_sameCycle_inl_faceProj β ρ hβinv hβfix hne x).symm
  · intro q
    refine Quotient.inductionOn q (fun k => ?_)
    simp only [Quotient.lift_mk, faceProj_inl]

/-- **The face count of a fresh-dart adjunction equals the traced face count.**
`F(freshMap β ρ a₀ a₁) = numCycles (swap (ρ a₀) (ρ a₁) * (ρ * β))`.  The two fresh darts
are spliced *into* existing face orbits, so they neither create nor destroy a face
orbit; the chord re-routes only the two incident faces (the swap). -/
theorem freshMap_F_eq_tracePhi :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).F = numCycles (tracePhi β ρ a₀ a₁) := by
  show Fintype.card (Quotient (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ)) = _
  rw [Fintype.card_congr (freshFaceQuotientEquiv β ρ hβinv hβfix hne)]
  exact card_cycleSetoid_eq_numCycles (tracePhi β ρ a₀ a₁)

end FaceBijection



section Dichotomy

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

lemma ρa₀_ne_ρa₁ (ρ : Equiv.Perm K) {a₀ a₁ : K} (hne : a₀ ≠ a₁) :
    ρ a₀ ≠ ρ a₁ := fun h => hne (ρ.injective h)

/-- The swap of `ρ a₀`, `ρ a₁` equals the swap appearing in `tracePhi` written as a
left product `(swap …) * keptPhi`.  (Definitional, recorded for clarity.) -/
lemma tracePhi_eq_swap_mul :
    tracePhi β ρ a₀ a₁ = Equiv.swap (ρ a₀) (ρ a₁) * keptPhi β ρ := rfl

/-- The face count via commuting the swap to the right:
`numCycles (tracePhi) = numCycles (keptPhi * swap (ρ a₀) (ρ a₁))`. -/
lemma numCycles_tracePhi_eq_mul_swap :
    numCycles (tracePhi β ρ a₀ a₁)
      = numCycles (keptPhi β ρ * Equiv.swap (ρ a₀) (ρ a₁)) := by
  rw [tracePhi_eq_swap_mul β ρ, numCycles_mul_comm]

/-- **Same-face branch (`+1`).**  If `ρ a₀`, `ρ a₁` are in the same kept face
(`keptPhi`-cycle), the fresh face count is `numCycles keptPhi + 1`. -/
theorem freshMap_F_same_face
    (hsc : (keptPhi β ρ).SameCycle (ρ a₀) (ρ a₁)) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).F = numCycles (keptPhi β ρ) + 1 := by
  rw [freshMap_F_eq_tracePhi β ρ hβinv hβfix hne, numCycles_tracePhi_eq_mul_swap β ρ]
  exact numCycles_mul_swap_of_sameCycle (keptPhi β ρ) (ρa₀_ne_ρa₁ ρ hne) hsc



end Dichotomy



section Genus0

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- The kept combinatorial map's face count is `numCycles keptPhi`. -/
lemma keptCombMap_F : (keptCombMap β ρ hβinv hβfix).F = numCycles (keptPhi β ρ) := by
  rw [(keptCombMap β ρ hβinv hβfix).F_eq_numCycles]
  rfl

/-- The kept combinatorial map's vertex count is `numCycles ρ`. -/
lemma keptCombMap_V :
    (keptCombMap β ρ hβinv hβfix).V = Fintype.card (Quotient (cycleSetoid ρ)) := by
  rfl

/-- `2 · E_kept = |K|` (the kept edge involution is fixed-point-free). -/
lemma keptCombMap_two_mul_E :
    2 * (keptCombMap β ρ hβinv hβfix).E = Fintype.card K :=
  (keptCombMap β ρ hβinv hβfix).two_mul_E_eq_card

/-- **The genus-0 face count, from the kept Euler characteristic + same-face.**  If the
kept combinatorial map is genus-0 (`eulerChar = 2`) and the two chord successors
`ρ a₀`, `ρ a₁` lie on a common kept face, then `FreshFaceCount` holds.  This is the
explicit-bijection discharge of the chord-split face count using M's genus-0 structure:
the splice *splits* the shared boundary face (`+1`), and the kept disk's `V − E + F = 2`
turns the per-side identity `F₁ + F₂ = F + 1` into the required arithmetic. -/
theorem freshFaceCount_of_genus0
    (hkept_euler : (keptCombMap β ρ hβinv hβfix).eulerChar = 2)
    (hsame : (keptPhi β ρ).SameCycle (ρ a₀) (ρ a₁)) :
    FreshFaceCount β ρ hβinv hβfix hne := by
  unfold FreshFaceCount
  -- `F = numCycles keptPhi + 1 = F_kept + 1`.
  have hF : (freshMap β ρ hβinv hβfix a₀ a₁ hne).F
      = (keptCombMap β ρ hβinv hβfix).F + 1 := by
    rw [freshMap_F_same_face β ρ hβinv hβfix hne hsame, keptCombMap_F]
  -- the kept Euler identity, in ℤ.
  have heuler : ((keptCombMap β ρ hβinv hβfix).V : ℤ)
      - ((keptCombMap β ρ hβinv hβfix).E : ℤ)
      + ((keptCombMap β ρ hβinv hβfix).F : ℤ) = 2 := hkept_euler
  have hE2 : 2 * ((keptCombMap β ρ hβinv hβfix).E : ℤ) = (Fintype.card K : ℤ) := by
    exact_mod_cast keptCombMap_two_mul_E β ρ hβinv hβfix
  have hVeq : (keptCombMap β ρ hβinv hβfix).V
      = Fintype.card (Quotient (cycleSetoid ρ)) := keptCombMap_V β ρ hβinv hβfix
  -- target (ℤ): `2 * F = |K| + 6 - 2 * V_kept`.
  have hFZ : ((freshMap β ρ hβinv hβfix a₀ a₁ hne).F : ℤ)
      = ((keptCombMap β ρ hβinv hβfix).F : ℤ) + 1 := by exact_mod_cast hF
  have hgoalZ : 2 * ((freshMap β ρ hβinv hβfix a₀ a₁ hne).F : ℤ)
      = (Fintype.card K : ℤ) + 6
        - 2 * (Fintype.card (Quotient (cycleSetoid ρ)) : ℤ) := by
    rw [hVeq] at heuler
    linarith [heuler, hE2, hFZ]
  -- transfer to ℕ (the RHS `|K| + 6 - 2·V_kept` is nonnegative since `2·F ≥ 0`).
  omega

end Genus0



section SphereAssembly

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- The vertex bound consumed by the Euler reduction, derived from the genus-0 kept Euler
identity (so it is *not* an extra hypothesis at genus 0). -/
lemma vbound_of_kept_euler
    (hkept_euler : (keptCombMap β ρ hβinv hβfix).eulerChar = 2) :
    Fintype.card (Quotient (cycleSetoid ρ)) ≤ (Fintype.card K + 2) / 2 + 1 := by
  -- `V_kept = numCycles ρ`, `2·E_kept = |K|`, `F_kept ≥ 1` (nonempty face quotient? use χ=2).
  -- From `V - E + F = 2` and `F ≥ 0`, `V ≤ E + 2 = |K|/2 + 2 ≤ (|K|+2)/2 + 1`.
  have heuler : ((keptCombMap β ρ hβinv hβfix).V : ℤ)
      - ((keptCombMap β ρ hβinv hβfix).E : ℤ)
      + ((keptCombMap β ρ hβinv hβfix).F : ℤ) = 2 := hkept_euler
  have hE2 : 2 * (keptCombMap β ρ hβinv hβfix).E = Fintype.card K :=
    keptCombMap_two_mul_E β ρ hβinv hβfix
  have hVeq : (keptCombMap β ρ hβinv hβfix).V
      = Fintype.card (Quotient (cycleSetoid ρ)) := keptCombMap_V β ρ hβinv hβfix
  have hVZ : ((keptCombMap β ρ hβinv hβfix).V : ℤ)
      = (Fintype.card (Quotient (cycleSetoid ρ)) : ℤ) := by exact_mod_cast hVeq
  -- `V = E + 2 - F ≤ E + 2`.
  have hVle : (keptCombMap β ρ hβinv hβfix).V ≤ (keptCombMap β ρ hβinv hβfix).E + 2 := by
    have : ((keptCombMap β ρ hβinv hβfix).V : ℤ) ≤ ((keptCombMap β ρ hβinv hβfix).E : ℤ) + 2 := by
      have hFnn : (0 : ℤ) ≤ ((keptCombMap β ρ hβinv hβfix).F : ℤ) := by positivity
      linarith [heuler, hFnn]
    exact_mod_cast this
  omega

/-- **The fresh map is a genus-0 sphere map, from M's genus-0 structure.**  Inputs:
the kept side is a sphere map (`keptCombMap β ρ` connected with `eulerChar = 2`) and the
two chord successors `ρ a₀`, `ρ a₁` lie on a common kept face.  Output: the *full*
`IsSphereMap` of the side map (connectivity transferred across the splice, and the face
count discharged via the explicit orbit bijection + the genus-0 transposition sign). -/
theorem freshMap_isSphereMap_of_genus0
    (hkept_sphere : (keptCombMap β ρ hβinv hβfix).IsSphereMap)
    (hsame : (keptPhi β ρ).SameCycle (ρ a₀) (ρ a₁)) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).IsSphereMap := by
  refine ⟨ChordSideRecon.freshMap_connected_of_kept β ρ hβinv hβfix hne hkept_sphere.1, ?_⟩
  have hface := freshFaceCount_of_genus0 β ρ hβinv hβfix hne hkept_sphere.2 hsame
  have hV := vbound_of_kept_euler β ρ hβinv hβfix hkept_sphere.2
  exact (freshMap_eulerChar_eq_two_iff_faceCount β ρ hβinv hβfix hne hV).2 hface

end SphereAssembly



section NonVacuity







end NonVacuity



section ChordApplication

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}





end ChordApplication



section Headline

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



end Headline

end ProofsInTheBook.ChordFaceCount















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordFaceCount
import ProofsInTheBook.PlanarMapEulerInequality
-/
/- Source module: ProofsInTheBook.ChordDisk -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordDisk

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount

universe u

variable {K : Type u} [Fintype K] [DecidableEq K]



section Facts

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  (a₀ a₁ : K)

/-- **Fact 1 (the disk fact).**  The kept side of the chord split — the kept combinatorial
map `keptCombMap β ρ` (the side submap *before* the duplicated chord edge is spliced) — is a
combinatorial disk: a sphere map (`Connected ∧ eulerChar = 2`).  This is the discrete
Schoenflies content: a simple closed curve (chord ∪ boundary arc) on the genus-0 sphere M
bounds a disk on each side. -/
def KeptSideIsDisk : Prop := (keptCombMap β ρ hβinv hβfix).IsSphereMap

/-- **Fact 2 (the anchor incidence fact).**  The two chord anchors' rotation successors
`ρ a₀`, `ρ a₁` lie on a common kept face (the same `keptPhi = ρ * β`-cycle): the shared outer
boundary face that the chord splits.  This is a local incidence fact about the chord
endpoints' position on the side's boundary cycle. -/
def AnchorsShareBoundaryFace : Prop := (keptPhi β ρ).SameCycle (ρ a₀) (ρ a₁)

end Facts



section LowerHalf

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)





end LowerHalf



section Threading

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- **The two disk facts produce the side map's `IsSphereMap`.**  Fact 1 (kept side is a
disk) + fact 2 (anchors share the boundary face) give the *full* genus-0 structure of the
spliced side map: connectivity (transferred across the splice in `ChordSideRecon`) and
`eulerChar = 2` (the face count `FreshFaceCount`, proved from the bijection in
`ChordFaceCount`).  The face count is **not** a hypothesis. -/
theorem chordDisk_produces_isSphereMap
    (hdisk : KeptSideIsDisk β ρ hβinv hβfix)
    (hshare : AnchorsShareBoundaryFace β ρ a₀ a₁) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).IsSphereMap :=
  freshMap_isSphereMap_of_genus0 β ρ hβinv hβfix hne hdisk hshare





end Threading



section ChordApplication

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

/-- **Fact 1 at side 1.**  The kept side-1 map `sideKeptMap₁` is a disk. -/
def Side₁IsDisk (data : hNT.ChordSplitData u v) (hsep : data.Separates) : Prop :=
  (sideKeptMap₁ data hsep).IsSphereMap

/-- **Fact 2 at side 1.**  The side-1 splice anchors' `sideSigma₁`-successors share a kept
face. -/
def Side₁AnchorsShareFace (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) : Prop :=
  (keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁).SameCycle
    (data.sideSigma₁ a₀) (data.sideSigma₁ a₁)

/-- **Side-1 map is a genus-0 sphere map, from side 1's two disk facts** — face count
discharged (no longer a hypothesis), via `ChordFaceCount`. -/
theorem side₁_isSphereMap_of_disk
    (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (hdisk : Side₁IsDisk data hsep)
    (hshare : Side₁AnchorsShareFace data hsep a₀ a₁) :
    (data.sideMap₁ hsep a₀ a₁ hne).IsSphereMap :=
  chordDisk_produces_isSphereMap _ _ _ _ hne hdisk hshare



/-- **Fact 1 at side 2.** -/
def Side₂IsDisk (data : hNT.ChordSplitData u v) (hsep : data.Separates) : Prop :=
  (sideKeptMap₂ data hsep).IsSphereMap

/-- **Fact 2 at side 2.** -/
def Side₂AnchorsShareFace (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₂}) : Prop :=
  (keptPhi (data.sideAlpha₂ hsep) data.sideSigma₂).SameCycle
    (data.sideSigma₂ a₀) (data.sideSigma₂ a₁)

/-- **Side-2 map is a genus-0 sphere map, from side 2's two disk facts.** -/
theorem side₂_isSphereMap_of_disk
    (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₂}) (hne : a₀ ≠ a₁)
    (hdisk : Side₂IsDisk data hsep)
    (hshare : Side₂AnchorsShareFace data hsep a₀ a₁) :
    (data.sideMap₂ hsep a₀ a₁ hne).IsSphereMap :=
  chordDisk_produces_isSphereMap _ _ _ _ hne hdisk hshare



end ChordApplication



section NonVacuity











end NonVacuity



section Headline

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



end Headline



end ProofsInTheBook.ChordDisk
















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordDisk
-/
/- Source module: ProofsInTheBook.SubmapPlanar -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.SubmapPlanar

open Equiv
open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]



/-- **Single-edge removal does not increase the genus slack.**  If `α a = b` with `a ≠ b`
(so `{a, b}` is an edge of the involution `α`), then deleting it
(`α' = α * swap a b`, which fixes `a, b`) gives `genusSlack σ α' ≤ genusSlack σ α`. -/
theorem genusSlack_remove_le (σ α : Equiv.Perm D) (hα : α * α = 1)
    {a b : D} (hab : a ≠ b) (hαa : α a = b) :
    genusSlack σ (α * Equiv.swap a b) ≤ genusSlack σ α := by
  classical
  have hαb : α b = a := by
    have happ := congrArg (fun f : Equiv.Perm D => f a) hα
    have hh : α (α a) = a := by simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
    rw [hαa] at hh; exact hh
  set α' := α * Equiv.swap a b with hα'def
  have hα'invol : α' * α' = 1 := mul_swap_involutive α hα hαa hαb
  -- Edge count: `Ehalf α' + 1 = Ehalf α`.
  have hEhalf : Ehalf α' + 1 = Ehalf α := Ehalf_mul_swap α hα hab hαa
  have hEz : (Ehalf α : ℤ) = (Ehalf α' : ℤ) + 1 := by
    have h := hEhalf; push_cast [← h]; ring
  -- Face permutation: `σ * α = (σ * α') * swap a b`.
  have hface : σ * α = (σ * α') * Equiv.swap a b := by
    rw [hα'def, mul_assoc, mul_assoc, Equiv.swap_mul_self, mul_one]
  -- Component relation via `addEdge`.
  have hrel : dartStepRel σ α = _root_.addEdge (dartStepRel σ α') a b :=
    dartStepRel_eq_addEdge σ α hα hab hαa
  have hcompEq : numComponents σ α
      = _root_.numComp (_root_.addEdge (dartStepRel σ α') a b) := by
    rw [numComponents_def, hrel]
  -- Face cycle-count dichotomy.
  have hdich := _root_.numCycles_mul_swap_dichotomy (σ * α') hab
  rw [← hface] at hdich
  by_cases hsame : Relation.EqvGen (dartStepRel σ α') a b
  · -- Same component: `c` unchanged; `F` either unchanged (slack +1) or drops (slack +2).
    have hC : numComponents σ α = numComponents σ α' := by
      rw [hcompEq, numComponents_def]
      exact _root_.numComp_addEdge_of_eqvGen _ hsame
    unfold genusSlack at *
    rw [hC, hEz]
    rcases hdich with hd | hd
    · rw [hd]; push_cast; linarith
    · have hF : (numCycles (σ * α) : ℤ) = (numCycles (σ * α') : ℤ) - 1 := by
        have h := hd; push_cast [← h]; ring
      rw [hF]; linarith
  · -- Different components: `c` drops by one; faces merge (`F` drops by one); slack unchanged.
    have hC : numComponents σ α + 1 = numComponents σ α' := by
      rw [hcompEq, numComponents_def]
      exact _root_.numComp_addEdge_of_not_eqvGen _ hsame
    have hnsc : ¬ (σ * α').SameCycle a b := fun h =>
      hsame (eqvGen_dartStepRel_of_sameCycle_mul σ α' hα'invol h)
    have hmerge : numCycles (σ * α) + 1 = numCycles (σ * α') := by
      have h := _root_.numCycles_mul_swap_of_not_sameCycle (σ * α') hab hnsc
      rw [← hface] at h; exact h
    unfold genusSlack at *
    have hCz : (numComponents σ α : ℤ) = (numComponents σ α' : ℤ) - 1 := by
      have h := hC; push_cast [← h]; ring
    have hFz : (numCycles (σ * α) : ℤ) = (numCycles (σ * α') : ℤ) - 1 := by
      have h := hmerge; push_cast [← h]; ring
    rw [hCz, hEz, hFz]; linarith



/-- `α'` is an **edge-deletion sub-involution** of `α`: an involution that agrees with `α` on
its own support (so its edge set is a subset of `α`'s edge set). -/
def SubInvolution (α α' : Equiv.Perm D) : Prop :=
  α' * α' = 1 ∧ ∀ x, α' x ≠ x → α' x = α x

/-- A sub-involution's support is contained in `α`'s support. -/
lemma SubInvolution.support_subset {α α' : Equiv.Perm D} (h : SubInvolution α α') :
    Equiv.Perm.support α' ⊆ Equiv.Perm.support α := by
  classical
  intro x hx
  rw [Equiv.Perm.mem_support] at hx ⊢
  rw [h.2 x hx] at hx
  exact hx

/-- **Removing one edge from `α` keeps `α'` a sub-involution** when that edge is disjoint from
`α'`'s support.  This is the inductive step bridge. -/
lemma SubInvolution.remove_edge {α α' : Equiv.Perm D} (hα : α * α = 1)
    (h : SubInvolution α α') {a b : D} (hab : a ≠ b) (hαa : α a = b)
    (ha : a ∉ Equiv.Perm.support α') (hb : b ∉ Equiv.Perm.support α') :
    SubInvolution (α * Equiv.swap a b) α' := by
  classical
  have hαb : α b = a := by
    have happ := congrArg (fun f : Equiv.Perm D => f a) hα
    have hh : α (α a) = a := by simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
    rw [hαa] at hh; exact hh
  rw [Equiv.Perm.notMem_support] at ha hb
  refine ⟨h.1, ?_⟩
  intro x hx
  have hax : x ≠ a := by rintro rfl; exact hx ha
  have hbx : x ≠ b := by rintro rfl; exact hx hb
  rw [Equiv.Perm.mul_apply, Equiv.swap_apply_of_ne_of_ne hax hbx]
  exact h.2 x hx

/-- **Iterated monotonicity.**  Every edge-deletion sub-involution `α'` of an involution `α`
has genus slack at most that of `α`.  Proved by strong induction on the number of deleted
edges (`(support α).card`), peeling one `α`-edge disjoint from `support α'` at a time. -/
theorem genusSlack_le_of_subInvolution (σ : Equiv.Perm D) :
    ∀ α : Equiv.Perm D, α * α = 1 → ∀ α' : Equiv.Perm D, SubInvolution α α' →
      genusSlack σ α' ≤ genusSlack σ α := by
  intro α
  induction hn : (Equiv.Perm.support α).card using Nat.strong_induction_on
    generalizing α with
  | _ n ih =>
    intro hα α' hsub
    classical
    -- Either `α'` already equals `α` (no edge left to delete) or there is an `α`-edge
    -- disjoint from `support α'`.
    by_cases hdone : Equiv.Perm.support α ⊆ Equiv.Perm.support α'
    · -- supports equal ⇒ `α = α'` ⇒ slacks equal.
      have hsupp_eq : Equiv.Perm.support α = Equiv.Perm.support α' :=
        le_antisymm hdone hsub.support_subset
      have heq : α = α' := by
        ext x
        by_cases hx : x ∈ Equiv.Perm.support α
        · have hx' : x ∈ Equiv.Perm.support α' := hsupp_eq ▸ hx
          rw [Equiv.Perm.mem_support] at hx'
          exact (hsub.2 x hx').symm
        · have hx' : x ∉ Equiv.Perm.support α' := hsupp_eq ▸ hx
          rw [Equiv.Perm.notMem_support] at hx hx'
          rw [hx, hx']
      rw [heq]
    · -- there is `a ∈ support α \ support α'`; let `b = α a` (also outside `support α'`).
      obtain ⟨a, ha_in, ha_out⟩ := Finset.not_subset.mp hdone
      have hane : α a ≠ a := Equiv.Perm.mem_support.mp ha_in
      set b := α a with hbdef
      have hab : a ≠ b := fun h => hane h.symm
      have hαa : α a = b := hbdef.symm
      have hαb : α b = a := by
        have happ := congrArg (fun f : Equiv.Perm D => f a) hα
        have hh : α (α a) = a := by simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
        rw [hαa] at hh; exact hh
      have hb_in : b ∈ Equiv.Perm.support α := by
        rw [Equiv.Perm.mem_support, hαb]; exact hab
      -- `b` is also outside `support α'` (else `α' b = b'` would force the edge `{a,b}` into `α'`).
      have hb_out : b ∉ Equiv.Perm.support α' := by
        intro hb'
        rw [Equiv.Perm.mem_support] at hb'
        have := hsub.2 b hb'
        rw [hαb] at this
        -- `α' b = a`, so `α' a = b ≠ a` by the involution, putting `a` in `support α'`.
        have hα'a : α' a = b := by
          have happ := congrArg (fun f : Equiv.Perm D => f b) hsub.1
          have hh : α' (α' b) = b := by
            simpa [Equiv.Perm.coe_mul, Function.comp_apply] using happ
          rw [this] at hh; exact hh
        exact ha_out (Equiv.Perm.mem_support.mpr (by rw [hα'a]; exact hab.symm))
      -- Delete `{a, b}` from `α`.
      set α'' := α * Equiv.swap a b with hα''def
      have hα''invol : α'' * α'' = 1 := mul_swap_involutive α hα hαa hαb
      have hsub'' : SubInvolution α'' α' :=
        hsub.remove_edge hα hab hαa ha_out hb_out
      have hsupp'' : Equiv.Perm.support α'' = (Equiv.Perm.support α) \ {a, b} :=
        support_mul_swap_of_apply α hα hab hαa
      have hcard'' : (Equiv.Perm.support α'').card < n := by
        rw [← hn, hsupp'']
        apply Finset.card_lt_card
        refine (Finset.ssubset_iff_of_subset Finset.sdiff_subset).mpr ⟨a, ha_in, ?_⟩
        simp
      -- Recurse: slack α' ≤ slack α'' ≤ slack α.
      have hstep : genusSlack σ α'' ≤ genusSlack σ α :=
        genusSlack_remove_le σ α hα hab hαa
      have hrec : genusSlack σ α' ≤ genusSlack σ α'' :=
        ih _ hcard'' α'' rfl hα''invol α' hsub''
      exact le_trans hrec hstep



/-- **A sphere map has genus slack zero.**  For a connected map with `eulerChar = 2` and at
least one dart, `genusSlack M.σ M.α = 0` (`c = 1`, `χ = 2`). -/
theorem genusSlack_sphere_eq_zero (M : CombMap D) (hsphere : M.IsSphereMap) (d₀ : D) :
    genusSlack M.σ M.α = 0 := by
  classical
  have hc : numComponents M.σ M.α = 1 :=
    numComponents_eq_one_of_connected M hsphere.1 d₀
  have hVc : (M.V : ℤ) = (numCycles M.σ : ℤ) := by rw [V_eq_numCycles]
  have hEc : (M.E : ℤ) = (Ehalf M.α : ℤ) := by rw [Ehalf_eq_E]
  have hFc : (M.F : ℤ) = (numCycles (M.σ * M.α) : ℤ) := by
    rw [F_eq_numCycles]; rfl
  have heuler : (M.V : ℤ) - (M.E : ℤ) + (M.F : ℤ) = 2 := hsphere.2
  unfold genusSlack
  rw [hc]
  rw [hVc, hEc, hFc] at heuler
  push_cast
  linarith



section OrbitSplit

variable (p : Equiv.Perm D) (S : Finset D)

open scoped Classical

/-- A `p`-orbit is **deleted** if all its darts lie in `S`. -/
def DeletedOrbit (q : Quotient (cycleSetoid p)) : Prop :=
  ∀ x : D, Quotient.mk (cycleSetoid p) x = q → x ∈ S

/-- The kept subtype's filtered orbit quotient, as `p`-orbits via the `SameCycle` coincidence. -/
noncomputable def keptToFull :
    Quotient (cycleSetoid (Equiv.Perm.deleteSet p S)) → Quotient (cycleSetoid p) :=
  Quotient.lift (fun x => Quotient.mk (cycleSetoid p) (x.1 : D)) (by
    intro x y hxy
    apply Quotient.sound
    exact (Equiv.Perm.sameCycle_deleteSet_iff p S x y).1 hxy)

@[simp] lemma keptToFull_mk (x : {d : D // d ∉ S}) :
    keptToFull p S (Quotient.mk (cycleSetoid (Equiv.Perm.deleteSet p S)) x)
      = Quotient.mk (cycleSetoid p) (x.1 : D) := rfl

/-- `keptToFull` is injective: two filtered orbits mapping to the same `p`-orbit are equal. -/
lemma keptToFull_injective : Function.Injective (keptToFull p S) := by
  classical
  intro a b hab
  refine Quotient.inductionOn₂ a b (fun x y hxy => ?_) hab
  simp only [keptToFull_mk] at hxy
  apply Quotient.sound
  have hsc : p.SameCycle x.1 y.1 := Quotient.exact hxy
  exact (Equiv.Perm.sameCycle_deleteSet_iff p S x y).2 hsc

/-- The image of `keptToFull` is exactly the non-deleted `p`-orbits. -/
lemma keptToFull_range_iff (q : Quotient (cycleSetoid p)) :
    (∃ a, keptToFull p S a = q) ↔ ¬ DeletedOrbit p S q := by
  classical
  constructor
  · rintro ⟨a, rfl⟩
    refine Quotient.inductionOn a (fun x => ?_)
    simp only [keptToFull_mk, DeletedOrbit, not_forall]
    exact ⟨x.1, rfl, x.2⟩
  · intro hq
    -- some dart of the orbit is kept; lift it.
    simp only [DeletedOrbit, not_forall] at hq
    obtain ⟨x, hxq, hxS⟩ := hq
    refine ⟨Quotient.mk (cycleSetoid (Equiv.Perm.deleteSet p S)) ⟨x, hxS⟩, ?_⟩
    rw [keptToFull_mk]; exact hxq

/-- The number of **deleted** `p`-orbits (orbits entirely inside `S`). -/
noncomputable def numDeletedOrbits : ℕ :=
  Fintype.card {q : Quotient (cycleSetoid p) // DeletedOrbit p S q}

/-- **Orbit-count splitting.**  `numCycles p = numCycles (deleteSet p S) + numDeletedOrbits`.
Every `p`-orbit is either deleted or has a kept representative; the kept ones biject with the
filtered orbits via `keptToFull`. -/
theorem numCycles_eq_kept_add_deleted :
    _root_.numCycles p
      = _root_.numCycles (Equiv.Perm.deleteSet p S) + numDeletedOrbits p S := by
  classical
  -- `keptToFull` is a bijection onto the non-deleted orbits.
  have hbij : Function.Bijective
      (fun a => (⟨keptToFull p S a, by
        rw [← keptToFull_range_iff]; exact ⟨a, rfl⟩⟩ :
        {q : Quotient (cycleSetoid p) // ¬ DeletedOrbit p S q})) := by
    constructor
    · intro a b hab
      exact keptToFull_injective p S (Subtype.ext_iff.mp hab)
    · rintro ⟨q, hq⟩
      obtain ⟨a, ha⟩ := (keptToFull_range_iff p S q).2 hq
      exact ⟨a, Subtype.ext ha⟩
  have hcard_kept : _root_.numCycles (Equiv.Perm.deleteSet p S)
      = Fintype.card {q : Quotient (cycleSetoid p) // ¬ DeletedOrbit p S q} := by
    rw [← card_cycleSetoid_eq_numCycles]
    exact Fintype.card_of_bijective hbij
  have hcompl : Fintype.card {q : Quotient (cycleSetoid p) // ¬ DeletedOrbit p S q}
      = Fintype.card (Quotient (cycleSetoid p))
        - Fintype.card {q : Quotient (cycleSetoid p) // DeletedOrbit p S q} :=
    Fintype.card_subtype_compl _
  have hle : Fintype.card {q : Quotient (cycleSetoid p) // DeletedOrbit p S q}
      ≤ Fintype.card (Quotient (cycleSetoid p)) := Fintype.card_subtype_le _
  rw [← card_cycleSetoid_eq_numCycles p, hcard_kept, numDeletedOrbits, hcompl]
  omega

end OrbitSplit





section RawRestrict

variable (M : CombMap D) (Del : Finset D)

open scoped Classical

/-- The raw restricted function: identity on deleted darts, `M.α` elsewhere. -/
noncomputable def rawAlphaFun : D → D := fun d => if d ∈ Del then d else M.α d

/-- `rawAlphaFun` is an involution (uses `α`-closedness of `Del`). -/
lemma rawAlphaFun_involutive (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) :
    Function.Involutive (rawAlphaFun M Del) := by
  classical
  intro d
  unfold rawAlphaFun
  by_cases hd : d ∈ Del
  · simp [hd]
  · have hαd : M.α d ∉ Del := by
      intro h
      apply hd
      have := hclosed _ h
      rwa [M.alpha_alpha] at this
    simp [hd, hαd, M.alpha_alpha]

/-- The **raw restricted involution**: fixes every deleted dart, equals `M.α` on kept darts. -/
noncomputable def rawAlpha (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) : Equiv.Perm D :=
  Function.Involutive.toPerm (rawAlphaFun M Del) (rawAlphaFun_involutive M Del hclosed)

@[simp] lemma rawAlpha_apply (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) (d : D) :
    rawAlpha M Del hclosed d = if d ∈ Del then d else M.α d := rfl

/-- `rawAlpha` is an involution as a permutation. -/
lemma rawAlpha_invol (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) :
    rawAlpha M Del hclosed * rawAlpha M Del hclosed = 1 := by
  ext d
  simp only [Equiv.Perm.coe_mul, Function.comp_apply, Equiv.Perm.coe_one, id_eq]
  exact rawAlphaFun_involutive M Del hclosed d

/-- `rawAlpha` fixes deleted darts. -/
lemma rawAlpha_eq_self_of_mem (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) {d : D}
    (hd : d ∈ Del) : rawAlpha M Del hclosed d = d := by simp [rawAlpha_apply, hd]

/-- `rawAlpha` equals `M.α` on kept darts. -/
lemma rawAlpha_eq_alpha_of_notMem (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) {d : D}
    (hd : d ∉ Del) : rawAlpha M Del hclosed d = M.α d := by simp [rawAlpha_apply, hd]

/-- **Trajectory identity.**  Starting from a kept dart `x`, applying `M.α` and then iterating
`M.σ` through a run of deleted darts matches iterating `p := M.σ * rawAlpha`: for every `k`,
if the intermediate `σ`-iterates `(M.σ)^j (M.α x)` (`1 ≤ j ≤ k`) are all deleted, then
`p^(k+1) x = (M.σ)^(k+1) (M.α x)`.  (`rawAlpha` fixes the deleted darts visited.) -/
lemma rawFace_traj (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del)
    (x : {d : D // d ∉ Del}) :
    ∀ k : ℕ, (∀ j : ℕ, 1 ≤ j → j ≤ k → ((M.σ ^ j) (M.α x.1)) ∈ Del) →
      ((M.σ * rawAlpha M Del hclosed) ^ (k+1)) x.1 = (M.σ ^ (k+1)) (M.α x.1) := by
  classical
  set p := M.σ * rawAlpha M Del hclosed with hp
  intro k
  induction k with
  | zero =>
      intro _
      simp only [zero_add, pow_one, hp]
      rw [Equiv.Perm.mul_apply, rawAlpha_eq_alpha_of_notMem M Del hclosed x.2]
  | succ k ih =>
      intro hdel
      have ihk : (p ^ (k+1)) x.1 = (M.σ ^ (k+1)) (M.α x.1) :=
        ih (fun j hj1 hjk => hdel j hj1 (by omega))
      have hmemk : (M.σ ^ (k+1)) (M.α x.1) ∈ Del := hdel (k+1) (by omega) (by omega)
      have hstep : ((p ^ (k+1+1)) x.1) = p ((p ^ (k+1)) x.1) := by
        rw [pow_succ']; rfl
      rw [hstep, ihk, hp, Equiv.Perm.mul_apply,
        rawAlpha_eq_self_of_mem M Del hclosed hmemk, ← Equiv.Perm.mul_apply, ← pow_succ']



/-- Abbreviation: the kept combinatorial map's face permutation is
`(deleteSet M.σ Del) * (M.α.subtypePerm)`. -/
noncomputable def keptFacePerm (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del) : Equiv.Perm {d : D // d ∉ Del} :=
  (Equiv.Perm.deleteSet M.σ Del) * (M.α.subtypePerm (fun d => by
    rw [← hsub d]))



/-- **The kept face permutation equals the deleted raw face permutation.**  As permutations on
the kept subtype, `keptFacePerm = deleteSet (M.σ * rawAlpha) Del`.  Both send a kept dart `x`
to the first kept dart reached from `M.α x` by iterating `M.σ` through the deleted run; the raw
face permutation `M.σ * rawAlpha` walks the same trajectory because `rawAlpha` fixes the deleted
darts it passes through. -/
theorem keptFacePerm_eq_deleteSet_rawFace (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del) :
    keptFacePerm M Del hclosed hsub = Equiv.Perm.deleteSet (M.σ * rawAlpha M Del hclosed) Del := by
  classical
  ext x
  -- It suffices to prove the underlying dart values agree.
  set y : {d : D // d ∉ Del} := ⟨M.α x.1, fun hc => x.2 ((hsub x.1).2 hc)⟩ with hy
  -- LHS value: `(deleteSet M.σ Del) y = (M.σ)^m (M.α x)` with `m = firstOutside M.σ Del y`.
  set m := Equiv.Perm.DeleteSet.firstOutside M.σ Del y with hm
  have hmpos : 0 < m := Equiv.Perm.DeleteSet.firstOutside_pos M.σ Del y
  have hlhs : ((keptFacePerm M Del hclosed hsub) x : {d : D // d ∉ Del}).1
      = (M.σ ^ m) (M.α x.1) := by
    show ((Equiv.Perm.deleteSet M.σ Del) y : {d : D // d ∉ Del}).1 = _
    rw [Equiv.Perm.deleteSet_apply_coe]
  -- intermediate σ-iterates of `M.α x` (before step `m`) are deleted (firstOutside min).
  have hinter : ∀ j : ℕ, 1 ≤ j → j ≤ m - 1 → ((M.σ ^ j) (M.α x.1)) ∈ Del := by
    intro j hj1 hjm
    by_contra hnot
    exact Equiv.Perm.DeleteSet.firstOutside_min M.σ Del y (by omega : j < m)
      ⟨by omega, by show (M.σ ^ j) y.1 ∉ Del; rw [hy]; exact hnot⟩
  -- the `m`-th σ-iterate is kept.
  have hmkept : (M.σ ^ m) (M.α x.1) ∉ Del := by
    have := Equiv.Perm.DeleteSet.firstOutside_notMem M.σ Del y
    rwa [hy] at this
  -- trajectory: `(M.σ * rawAlpha)^m x = (M.σ)^m (M.α x)`.
  have htraj := rawFace_traj M Del hclosed x (m - 1) hinter
  have hmsucc : (m - 1) + 1 = m := by omega
  rw [hmsucc] at htraj
  -- RHS value: `deleteSet (M.σ*rawAlpha) Del x = (M.σ*rawAlpha)^M x`, `M = firstOutside …`.
  set P := M.σ * rawAlpha M Del hclosed with hP
  have hrhs : ((Equiv.Perm.deleteSet P Del) x : {d : D // d ∉ Del}).1
      = (P ^ (Equiv.Perm.DeleteSet.firstOutside P Del x)) x.1 :=
    Equiv.Perm.deleteSet_apply_coe P Del x
  -- The firstOutside of `P` at `x` is exactly `m`: the `P`-trajectory equals the σ-trajectory
  -- of `M.α x`, deleted before step `m`, kept at step `m`.
  have hPtraj : ∀ j : ℕ, 1 ≤ j → j ≤ m → (P ^ j) x.1 = (M.σ ^ j) (M.α x.1) := by
    intro j hj1 hjm
    have hjsub : ∀ i : ℕ, 1 ≤ i → i ≤ j - 1 → ((M.σ ^ i) (M.α x.1)) ∈ Del :=
      fun i hi1 hij => hinter i hi1 (by omega)
    have := rawFace_traj M Del hclosed x (j - 1) hjsub
    rwa [Nat.sub_add_cancel hj1] at this
  have hPm_kept : (P ^ m) x.1 ∉ Del := by rw [hPtraj m hmpos le_rfl]; exact hmkept
  have hPm_min : ∀ i : ℕ, i < m → ¬ (0 < i ∧ (P ^ i) x.1 ∉ Del) := by
    intro i him ⟨hipos, hinotmem⟩
    rw [hPtraj i hipos (by omega)] at hinotmem
    exact hinotmem (hinter i hipos (by omega))
  have hMeq : Equiv.Perm.DeleteSet.firstOutside P Del x = m := by
    apply le_antisymm
    · exact Nat.find_min' _ ⟨hmpos, hPm_kept⟩
    · by_contra hlt
      rw [not_le] at hlt
      exact hPm_min _ hlt
        ⟨Equiv.Perm.DeleteSet.firstOutside_pos P Del x,
         Equiv.Perm.DeleteSet.firstOutside_notMem P Del x⟩
  rw [hlhs, hrhs, hMeq, hPtraj m hmpos le_rfl]





/-- The face count of the kept map equals `numCycles (deleteSet (M.σ * rawAlpha) Del)`. -/
lemma numCycles_keptFacePerm_eq (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del) :
    _root_.numCycles (keptFacePerm M Del hclosed hsub)
      = _root_.numCycles (Equiv.Perm.deleteSet (M.σ * rawAlpha M Del hclosed) Del) := by
  rw [keptFacePerm_eq_deleteSet_rawFace M Del hclosed hsub]



/-- On the deleted set, `M.σ` and `M.σ * rawAlpha` agree, hence have the same `SameCycle`
relation among deleted darts; combined with the kept-orbit splitting this forces the deleted
orbit counts to be equal. -/
lemma sameCycle_sigma_rawFace_of_mem (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del)
    {x : D} (hx : x ∈ Del) :
    (M.σ * rawAlpha M Del hclosed) x = M.σ x := by
  rw [Equiv.Perm.mul_apply, rawAlpha_eq_self_of_mem M Del hclosed hx]



variable (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del)
  (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del)

open scoped Classical

/-- The kept edge involution: `M.α` restricted to the kept subtype. -/
noncomputable def keptAlpha : Equiv.Perm {d : D // d ∉ Del} :=
  M.α.subtypePerm (p := fun d => d ∉ Del) (fun d => by
    constructor
    · intro hd hc; exact hd ((hsub d).1 hc)
    · intro hd hc; exact hd ((hsub d).2 hc))

@[simp] lemma keptAlpha_apply_coe (d : {d : D // d ∉ Del}) :
    (keptAlpha M Del hsub d : D) = M.α d.1 := rfl

lemma keptAlpha_invol : keptAlpha M Del hsub * keptAlpha M Del hsub = 1 := by
  ext z
  simp only [Equiv.Perm.coe_mul, Equiv.Perm.coe_one, Function.comp_apply, id_eq,
    keptAlpha_apply_coe]
  exact M.alpha_alpha z.1

/-- The kept combinatorial map's dart-step relation, on the kept subtype. -/
noncomputable def keptStepRel : {d : D // d ∉ Del} → {d : D // d ∉ Del} → Prop :=
  dartStepRel (Equiv.Perm.deleteSet M.σ Del) (keptAlpha M Del hsub)

/-- **A kept dart-step lifts to a raw dart-step on the underlying darts.** -/
lemma keptStepRel_imp_raw {x y : {d : D // d ∉ Del}}
    (h : keptStepRel M Del hsub x y) :
    dartStepRel M.σ (rawAlpha M Del hclosed) x.1 y.1 := by
  classical
  rcases h with hσ | hα
  · -- same `deleteSet M.σ`-cycle ⇒ same `M.σ`-cycle on coercions.
    exact Or.inl ((Equiv.Perm.sameCycle_deleteSet_iff M.σ Del x y).1 hσ)
  · -- α-edge: `y = (M.α.subtypePerm) x`, so `y.1 = M.α x.1 = rawAlpha x.1` (x kept).
    refine Or.inr ?_
    have hxval : (rawAlpha M Del hclosed) x.1 = M.α x.1 :=
      rawAlpha_eq_alpha_of_notMem M Del hclosed x.2
    rw [hxval]
    have := congrArg Subtype.val hα
    simpa using this



/-- `EqvGen` of the kept dart-step relation lifts to `EqvGen` of the raw relation. -/
lemma eqvGen_keptStepRel_imp_raw {x y : {d : D // d ∉ Del}}
    (h : Relation.EqvGen (keptStepRel M Del hsub) x y) :
    Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) x.1 y.1 := by
  induction h with
  | rel x y hxy => exact Relation.EqvGen.rel _ _ (keptStepRel_imp_raw M Del hclosed hsub hxy)
  | refl x => exact Relation.EqvGen.refl _
  | symm x y _ ih => exact Relation.EqvGen.symm _ _ ih
  | trans x y z _ _ ih1 ih2 => exact Relation.EqvGen.trans _ _ _ ih1 ih2

/-- The raw dart-step relation is symmetric (`rawAlpha` is an involution). -/
lemma rawStepRel_symm {a b : D}
    (h : dartStepRel M.σ (rawAlpha M Del hclosed) a b) :
    dartStepRel M.σ (rawAlpha M Del hclosed) b a :=
  dartStepRel_symm (rawAlpha_invol M Del hclosed) h

/-- **Descent witness (forward walk).**  Every dart `z` raw-reachable from a kept dart `x`
(via `ReflTransGen`) is `M.σ`-`SameCycle` to a kept dart `w` in the same *kept* component as
`x`.  The only raw steps that can land in `Del` are `M.σ`-`SameCycle` steps; `M.σ`-`SameCycle`
is transitive, so deleted intermediates collapse, and the `rawAlpha`-edge from a kept dart lands
kept (`α`-closure), giving a genuine kept dart-step. -/
lemma raw_reach_kept_witness {x : {d : D // d ∉ Del}} {z : D}
    (h : Relation.ReflTransGen (dartStepRel M.σ (rawAlpha M Del hclosed)) x.1 z) :
    ∃ w : {d : D // d ∉ Del},
      Relation.ReflTransGen (keptStepRel M Del hsub) x w ∧ M.σ.SameCycle w.1 z := by
  classical
  induction h with
  | refl => exact ⟨x, Relation.ReflTransGen.refl, Equiv.Perm.SameCycle.rfl⟩
  | @tail b c hxb hbc ih =>
      obtain ⟨w, hwkept, hwb⟩ := ih
      -- one more raw step `b → c`; combine with `w ~σ b`.
      rcases hbc with hσ | hαe
      · -- `c` in same `M.σ`-cycle as `b`, hence as `w`.
        exact ⟨w, hwkept, hwb.trans hσ⟩
      · -- `c = rawAlpha b`.
        by_cases hbDel : b ∈ Del
        · -- `rawAlpha b = b`, so `c = b`; nothing changes.
          rw [rawAlpha_eq_self_of_mem M Del hclosed hbDel] at hαe
          exact ⟨w, hwkept, hαe ▸ hwb⟩
        · -- `b` kept, `c = M.α b` kept (α-closure); `w ~σ b` gives a kept σ-step `w → ⟨b⟩`,
          -- then the kept α-edge `⟨b⟩ → ⟨c⟩`.
          have hck : c ∉ Del := by
            rw [rawAlpha_eq_alpha_of_notMem M Del hclosed hbDel] at hαe
            rw [hαe]; intro hc; exact hbDel ((hsub b).2 hc)
          have hbw : M.σ.SameCycle w.1 b := hwb
          -- kept σ-step `w → ⟨b, hbDel⟩`:
          have hstep1 : keptStepRel M Del hsub w ⟨b, hbDel⟩ :=
            Or.inl ((Equiv.Perm.sameCycle_deleteSet_iff M.σ Del w ⟨b, hbDel⟩).2 hbw)
          -- kept α-edge `⟨b⟩ → ⟨c⟩`:
          have hstep2 : keptStepRel M Del hsub ⟨b, hbDel⟩ ⟨c, hck⟩ := by
            refine Or.inr (Subtype.ext ?_)
            show c = M.α b
            rw [rawAlpha_eq_alpha_of_notMem M Del hclosed hbDel] at hαe
            exact hαe
          exact ⟨⟨c, hck⟩, (hwkept.tail hstep1).tail hstep2, Equiv.Perm.SameCycle.rfl⟩

/-- **Descent.**  Two kept darts that are raw-`EqvGen` are kept-`EqvGen`.  (From the descent
witness: the witness `w` for `y` is `M.σ`-`SameCycle` to `y`, both kept, hence kept-connected
by a single kept `σ`-step.) -/
lemma raw_eqvGen_descends {x y : {d : D // d ∉ Del}}
    (h : Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) x.1 y.1) :
    Relation.EqvGen (keptStepRel M Del hsub) x y := by
  classical
  -- pass to `ReflTransGen` (symmetric relation), apply the witness, close with a kept σ-step.
  have hsymm : ∀ a b, dartStepRel M.σ (rawAlpha M Del hclosed) a b →
      dartStepRel M.σ (rawAlpha M Del hclosed) b a :=
    fun a b => rawStepRel_symm M Del hclosed
  rw [eqvGen_iff_reflTransGen hsymm] at h
  obtain ⟨w, hwkept, hwy⟩ := raw_reach_kept_witness M Del hclosed hsub h
  -- `w ~σ y` (both kept) ⇒ kept σ-step `w → y`.
  have hstep : keptStepRel M Del hsub w y :=
    Or.inl ((Equiv.Perm.sameCycle_deleteSet_iff M.σ Del w y).2 hwy)
  have hksymm : ∀ a b, keptStepRel M Del hsub a b → keptStepRel M Del hsub b a :=
    fun a b h => dartStepRel_symm (keptAlpha_invol M Del hsub) h
  rw [eqvGen_iff_reflTransGen hksymm]
  exact hwkept.tail hstep

/-- The lifted map `⟦x⟧_kept ↦ ⟦x.1⟧_raw` of component quotients. -/
noncomputable def keptCompToRaw :
    Quotient (_root_.compSetoid (keptStepRel M Del hsub))
      → Quotient (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed))) :=
  Quotient.lift (fun x => Quotient.mk _ (x.1 : D)) (by
    intro x y hxy
    apply Quotient.sound
    show Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) x.1 y.1
    exact eqvGen_keptStepRel_imp_raw M Del hclosed hsub hxy)

/-- `keptCompToRaw` is injective: by the descent lemma, kept darts raw-`EqvGen` are
kept-`EqvGen`. -/
lemma keptCompToRaw_injective : Function.Injective (keptCompToRaw M Del hclosed hsub) := by
  classical
  intro a b hab
  refine Quotient.inductionOn₂ a b (fun x y hxy => ?_) hab
  apply Quotient.sound
  show Relation.EqvGen (keptStepRel M Del hsub) x y
  exact raw_eqvGen_descends M Del hclosed hsub (Quotient.exact hxy)





/-- A raw component is **deleted** if all its darts lie in `Del`. -/
def DeletedComp (q : Quotient (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed)))) :
    Prop :=
  ∀ x : D, Quotient.mk _ x = q → x ∈ Del

/-- The image of `keptCompToRaw` is exactly the non-deleted raw components. -/
lemma keptCompToRaw_range_iff
    (q : Quotient (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed)))) :
    (∃ a, keptCompToRaw M Del hclosed hsub a = q) ↔ ¬ DeletedComp M Del hclosed q := by
  classical
  constructor
  · rintro ⟨a, rfl⟩
    refine Quotient.inductionOn a (fun x => ?_)
    simp only [DeletedComp, not_forall]
    exact ⟨x.1, rfl, x.2⟩
  · intro hq
    simp only [DeletedComp, not_forall] at hq
    obtain ⟨x, hxq, hxD⟩ := hq
    exact ⟨Quotient.mk _ ⟨x, hxD⟩, hxq⟩

/-- The number of deleted raw components. -/
noncomputable def numDeletedComp : ℕ :=
  Fintype.card {q : Quotient (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed)))
    // DeletedComp M Del hclosed q}

/-- **Component split.**  `numComponents M.σ rawAlpha = numComp (keptStepRel) + numDeletedComp`. -/
theorem numComponents_raw_split :
    numComponents M.σ (rawAlpha M Del hclosed)
      = _root_.numComp (keptStepRel M Del hsub) + numDeletedComp M Del hclosed := by
  classical
  rw [numComponents_def]
  have hbij : Function.Bijective
      (fun a => (⟨keptCompToRaw M Del hclosed hsub a, by
        rw [← keptCompToRaw_range_iff M Del hclosed hsub]; exact ⟨a, rfl⟩⟩ :
        {q // ¬ DeletedComp M Del hclosed q})) := by
    constructor
    · intro a b hab
      exact keptCompToRaw_injective M Del hclosed hsub (Subtype.ext_iff.mp hab)
    · rintro ⟨q, hq⟩
      obtain ⟨a, ha⟩ := (keptCompToRaw_range_iff M Del hclosed hsub q).2 hq
      exact ⟨a, Subtype.ext ha⟩
  have hcard_kept : _root_.numComp (keptStepRel M Del hsub)
      = Fintype.card {q // ¬ DeletedComp M Del hclosed q} := by
    unfold _root_.numComp
    rw [Nat.card_eq_fintype_card]
    exact Fintype.card_of_bijective hbij
  have hcompl : Fintype.card {q // ¬ DeletedComp M Del hclosed q}
      = Fintype.card (Quotient (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed))))
        - Fintype.card {q // DeletedComp M Del hclosed q} :=
    Fintype.card_subtype_compl _
  have hle : Fintype.card {q // DeletedComp M Del hclosed q}
      ≤ Fintype.card (Quotient (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed)))) :=
    Fintype.card_subtype_le _
  have hraw : _root_.numComp (dartStepRel M.σ (rawAlpha M Del hclosed))
      = Fintype.card (Quotient (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed)))) := by
    unfold _root_.numComp; rw [Nat.card_eq_fintype_card]
  rw [hraw, hcard_kept, numDeletedComp, hcompl]
  omega



/-- **A deleted-component dart has its whole `M.σ`-orbit deleted.**  If every dart in `x`'s
`dartStepRel`-component lies in `Del`, then in particular `M.σ x` lies in `Del` (it is a
`dartStepRel`-step away), and inductively the whole `M.σ`-orbit of `x` is deleted. -/
lemma sigma_sameCycle_imp_eqvGen_dartStepRel {a b : D} (h : M.σ.SameCycle a b) :
    Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) a b :=
  Relation.EqvGen.rel _ _ (Or.inl h)

/-- On `Del`, a `dartStepRel`-step keeps you in the same `M.σ`-orbit (the `rawAlpha`-edge fixes
deleted darts).  Hence within a deleted component the relation collapses to `M.σ.SameCycle`. -/
lemma dartStepRel_of_mem_del {a b : D} (ha : a ∈ Del)
    (h : dartStepRel M.σ (rawAlpha M Del hclosed) a b) : M.σ.SameCycle a b := by
  rcases h with hσ | hαe
  · exact hσ
  · rw [rawAlpha_eq_self_of_mem M Del hclosed ha] at hαe
    exact hαe ▸ Equiv.Perm.SameCycle.rfl

/-- **DeletedComp ⟺ DeletedOrbit (`M.σ`).**  The `dartStepRel`-class of a dart is entirely
deleted iff its `M.σ`-orbit is entirely deleted.  (`⟸`: a deleted `M.σ`-orbit admits no
`rawAlpha`-edge leaving `Del`, so the component stays in `Del`; `⟹`: `M.σ.SameCycle` is a
`dartStepRel`-step, so a deleted component contains the whole `M.σ`-orbit.) -/
lemma deletedComp_iff_deletedOrbit (x : D) :
    DeletedComp M Del hclosed (Quotient.mk _ x)
      ↔ DeletedOrbit M.σ Del (Quotient.mk (cycleSetoid M.σ) x) := by
  classical
  constructor
  · -- DeletedComp ⇒ DeletedOrbit: any `M.σ`-cycle dart is `dartStepRel`-related, hence deleted.
    intro hC y hy
    apply hC y
    apply Quotient.sound
    show Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) y x
    have hsc : M.σ.SameCycle y x := Quotient.exact hy
    exact sigma_sameCycle_imp_eqvGen_dartStepRel M Del hclosed hsc
  · -- DeletedOrbit ⇒ DeletedComp: every `dartStepRel`-related dart stays in the deleted σ-orbit.
    intro hO y hy
    have hxy : Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) x y :=
      (Quotient.exact hy).symm
    have hxDel : x ∈ Del := hO x rfl
    -- pass to ReflTransGen and carry the invariant `M.σ.SameCycle x z ∧ z ∈ Del` forward.
    have hsymm : ∀ a b, dartStepRel M.σ (rawAlpha M Del hclosed) a b →
        dartStepRel M.σ (rawAlpha M Del hclosed) b a :=
      fun a b => rawStepRel_symm M Del hclosed
    rw [eqvGen_iff_reflTransGen hsymm] at hxy
    have hinv : ∀ z, Relation.ReflTransGen (dartStepRel M.σ (rawAlpha M Del hclosed)) x z →
        M.σ.SameCycle x z ∧ z ∈ Del := by
      intro z hz
      induction hz with
      | refl => exact ⟨Equiv.Perm.SameCycle.rfl, hxDel⟩
      | @tail b c hxb hbc ih =>
          obtain ⟨hxb_sc, hbDel⟩ := ih
          have hbc_sc : M.σ.SameCycle b c := dartStepRel_of_mem_del M Del hclosed hbDel hbc
          have hxc_sc : M.σ.SameCycle x c := hxb_sc.trans hbc_sc
          refine ⟨hxc_sc, ?_⟩
          -- `c` is in `x`'s σ-orbit, which is deleted.
          exact hO c (Quotient.sound hxc_sc.symm)
    exact (hinv y hxy).2

/-- Within a deleted component, `dartStepRel`-`EqvGen` collapses to `M.σ.SameCycle`. -/
lemma comp_eqvGen_imp_sigma_of_deleted {x y : D} (hxDel : x ∈ Del)
    (hdel : ∀ z, Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) x z → z ∈ Del)
    (h : Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) x y) :
    M.σ.SameCycle x y := by
  classical
  have hsymm : ∀ a b, dartStepRel M.σ (rawAlpha M Del hclosed) a b →
      dartStepRel M.σ (rawAlpha M Del hclosed) b a :=
    fun a b => rawStepRel_symm M Del hclosed
  rw [eqvGen_iff_reflTransGen hsymm] at h
  have hinv : ∀ z, Relation.ReflTransGen (dartStepRel M.σ (rawAlpha M Del hclosed)) x z →
      M.σ.SameCycle x z := by
    intro z hz
    induction hz with
    | refl => exact Equiv.Perm.SameCycle.rfl
    | @tail b c hxb hbc ih =>
        have hbDel : b ∈ Del :=
          hdel b ((eqvGen_iff_reflTransGen hsymm x b).2 hxb)
        exact ih.trans (dartStepRel_of_mem_del M Del hclosed hbDel hbc)
  exact hinv y h

/-- A deleted `dartStepRel`-class's representative `out` is deleted, and its whole component is
deleted (every dart `EqvGen`-related to it). -/
lemma deletedComp_out_props
    {q : Quotient (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed)))}
    (hq : DeletedComp M Del hclosed q) :
    q.out ∈ Del ∧ ∀ z, Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) q.out z →
      z ∈ Del := by
  classical
  have hout : q.out ∈ Del := hq q.out (Quotient.out_eq q)
  refine ⟨hout, fun z hz => ?_⟩
  apply hq z
  rw [← Quotient.out_eq q]
  exact Quotient.sound (Relation.EqvGen.symm _ _ hz)

/-- **`numDeletedComp = numDeletedOrbits M.σ Del`.**  Both count the same family of deleted
`M.σ`-orbits; the equiv sends a deleted component to the `M.σ`-orbit of its representative and
back, well-defined by the within-deleted collapse `comp_eqvGen_imp_sigma_of_deleted`. -/
theorem numDeletedComp_eq_numDeletedOrbits :
    numDeletedComp M Del hclosed = numDeletedOrbits M.σ Del := by
  classical
  unfold numDeletedComp numDeletedOrbits
  refine Fintype.card_congr ?_
  refine
    { toFun := fun q => ⟨Quotient.mk (cycleSetoid M.σ) q.1.out,
        (deletedComp_iff_deletedOrbit M Del hclosed q.1.out).1 (by
          intro z hz
          obtain ⟨hout, hcomp⟩ := deletedComp_out_props M Del hclosed q.2
          exact q.2 z (by rw [hz]; exact Quotient.out_eq q.1))⟩,
      invFun := fun o => ⟨Quotient.mk _ o.1.out,
        (deletedComp_iff_deletedOrbit M Del hclosed o.1.out).2 (by
          intro z hz
          exact o.2 z (by rw [hz]; exact Quotient.out_eq o.1))⟩,
      left_inv := ?_, right_inv := ?_ }
  · -- `[ [qc].out ]_σ` then `[ · ]_comp` returns `qc`.
    rintro ⟨qc, hqc⟩
    apply Subtype.ext
    dsimp only
    obtain ⟨hout, hcomp⟩ := deletedComp_out_props M Del hclosed hqc
    -- the σ-orbit of `qc.out`'s out is σ-SameCycle to `qc.out`, hence same comp-class.
    nth_rewrite 2 [← Quotient.out_eq qc]
    apply Quotient.sound
    show Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) _ qc.out
    have hsc : M.σ.SameCycle (Quotient.mk (cycleSetoid M.σ) qc.out).out qc.out := by
      have := Quotient.out_eq (Quotient.mk (cycleSetoid M.σ) qc.out)
      exact Quotient.exact this
    exact sigma_sameCycle_imp_eqvGen_dartStepRel M Del hclosed hsc
  · -- `[ [o].out ]_comp` then `[ · ]_σ` returns `o`.
    rintro ⟨o, ho⟩
    apply Subtype.ext
    dsimp only
    nth_rewrite 2 [← Quotient.out_eq o]
    apply Quotient.sound
    show M.σ.SameCycle _ o.out
    -- the comp-class of `o.out` is deleted; its out is σ-SameCycle to `o.out` by the collapse.
    have hodel : o.out ∈ Del := ho o.out (Quotient.out_eq o)
    -- `o`'s σ-orbit is deleted ⇒ `o.out`'s comp-class is deleted (`deletedComp_iff_deletedOrbit`).
    have hDOrbit : DeletedOrbit M.σ Del (Quotient.mk (cycleSetoid M.σ) o.out) := by
      intro z hz
      exact ho z (by rw [hz]; exact Quotient.out_eq o)
    have hDComp : DeletedComp M Del hclosed
        (Quotient.mk (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed))) o.out) :=
      (deletedComp_iff_deletedOrbit M Del hclosed o.out).2 hDOrbit
    obtain ⟨_, hcompdel⟩ := deletedComp_out_props M Del hclosed hDComp
    have hsc : M.σ.SameCycle
        (Quotient.mk (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed))) o.out).out
        o.out := by
      apply comp_eqvGen_imp_sigma_of_deleted M Del hclosed
        (hcompdel _ (Relation.EqvGen.refl _)) hcompdel
      have := Quotient.out_eq
        (Quotient.mk (_root_.compSetoid (dartStepRel M.σ (rawAlpha M Del hclosed))) o.out)
      exact Quotient.exact this
    exact hsc







/-- **`DeletedOrbit`s coincide** for `M.σ` and `M.σ * rawAlpha`. -/
lemma deletedOrbit_sigmaRaw_iff (x : D) :
    DeletedOrbit (M.σ * rawAlpha M Del hclosed) Del
        (Quotient.mk (cycleSetoid (M.σ * rawAlpha M Del hclosed)) x)
      ↔ DeletedOrbit M.σ Del (Quotient.mk (cycleSetoid M.σ) x) := by
  classical
  -- Trajectory: if `x`'s `σRaw`-orbit is deleted then `σ^k x = σRaw^k x ∈ Del` for all `k`,
  -- and symmetrically; this collapses each orbit-deletion predicate to the other.
  have key : ∀ (p q : Equiv.Perm D),
      (∀ d : D, d ∈ Del → p d = q d) →
      ∀ (hpx : DeletedOrbit p Del (Quotient.mk (cycleSetoid p) x)),
      ∀ k : ℕ, (p ^ k) x = (q ^ k) x ∧ (q ^ k) x ∈ Del := by
    intro p q hpq hpx k
    have hxDel : x ∈ Del := hpx x rfl
    induction k with
    | zero => exact ⟨by simp, by simpa using hxDel⟩
    | succ k ih =>
        obtain ⟨ihEq, ihDel⟩ := ih
        have hqk_del : (q ^ k) x ∈ Del := ihDel
        have hpk_del : (p ^ k) x ∈ Del := ihEq ▸ ihDel
        have heq : (p ^ (k+1)) x = (q ^ (k+1)) x := by
          rw [pow_succ', pow_succ', Equiv.Perm.mul_apply, Equiv.Perm.mul_apply, ihEq,
            hpq _ hqk_del]
        refine ⟨heq, ?_⟩
        -- `q^(k+1) x = p^(k+1) x` is in `x`'s `p`-orbit, hence deleted by `hpx`.
        apply hpx
        apply Quotient.sound
        show p.SameCycle ((q ^ (k+1)) x) x
        exact ⟨-((k+1 : ℕ) : ℤ), by
          rw [← heq, zpow_neg, zpow_natCast, Equiv.Perm.inv_eq_iff_eq, Equiv.Perm.coe_pow]⟩
  constructor
  · intro hP y hy
    have hsc : M.σ.SameCycle y x := Quotient.exact hy
    have hagree : ∀ d : D, d ∈ Del → (M.σ * rawAlpha M Del hclosed) d = M.σ d :=
      fun d hd => sameCycle_sigma_rawFace_of_mem M Del hclosed hd
    -- `y` is in `x`'s σ-orbit; show deleted via the trajectory of `M.σ` matching `σRaw`.
    obtain ⟨n, hn⟩ := hsc.symm.exists_nat_pow_eq  -- `σ^n x = y`
    have := key (M.σ * rawAlpha M Del hclosed) M.σ hagree hP n
    rw [hn] at this
    exact this.2
  · intro hO y hy
    have hsc : (M.σ * rawAlpha M Del hclosed).SameCycle y x := Quotient.exact hy
    have hagree : ∀ d : D, d ∈ Del → M.σ d = (M.σ * rawAlpha M Del hclosed) d :=
      fun d hd => (sameCycle_sigma_rawFace_of_mem M Del hclosed hd).symm
    obtain ⟨n, hn⟩ := hsc.symm.exists_nat_pow_eq  -- `σRaw^n x = y`
    have := key M.σ (M.σ * rawAlpha M Del hclosed) hagree hO n
    rw [hn] at this
    exact this.2

/-- A `σ`-`SameCycle` within a deleted `σRaw`-orbit is a `σRaw`-`SameCycle` (and conversely),
since the two rotations agree on `Del` and the orbit stays in `Del`. -/
lemma sigmaRaw_sameCycle_iff_sigma_of_deletedOrbit {x : D}
    (hP : DeletedOrbit (M.σ * rawAlpha M Del hclosed) Del
      (Quotient.mk (cycleSetoid (M.σ * rawAlpha M Del hclosed)) x)) {y : D}
    (h : M.σ.SameCycle x y) : (M.σ * rawAlpha M Del hclosed).SameCycle x y := by
  classical
  have hxDel : x ∈ Del := hP x rfl
  -- trajectory: `σ^k x = σRaw^k x ∈ Del`.
  have key : ∀ k : ℕ, ((M.σ * rawAlpha M Del hclosed) ^ k) x = (M.σ ^ k) x
      ∧ (M.σ ^ k) x ∈ Del := by
    intro k
    induction k with
    | zero => exact ⟨by simp, by simpa using hxDel⟩
    | succ k ih =>
        obtain ⟨ihEq, ihDel⟩ := ih
        have hraw_del : ((M.σ * rawAlpha M Del hclosed) ^ k) x ∈ Del := ihEq ▸ ihDel
        have heq : ((M.σ * rawAlpha M Del hclosed) ^ (k+1)) x = (M.σ ^ (k+1)) x := by
          have e1 : ((M.σ * rawAlpha M Del hclosed) ^ (k+1)) x
              = M.σ (((M.σ * rawAlpha M Del hclosed) ^ k) x) := by
            rw [pow_succ', Equiv.Perm.mul_apply, Equiv.Perm.mul_apply,
              rawAlpha_eq_self_of_mem M Del hclosed hraw_del]
          have e2 : (M.σ ^ (k+1)) x = M.σ ((M.σ ^ k) x) := by rw [pow_succ']; rfl
          rw [e1, e2, ihEq]
        refine ⟨heq, ?_⟩
        apply hP
        apply Quotient.sound
        show (M.σ * rawAlpha M Del hclosed).SameCycle ((M.σ ^ (k+1)) x) x
        exact ⟨-((k+1 : ℕ) : ℤ), by
          rw [← heq, zpow_neg, zpow_natCast, Equiv.Perm.inv_eq_iff_eq, Equiv.Perm.coe_pow]⟩
  obtain ⟨n, hn⟩ := h.exists_nat_pow_eq
  exact ⟨(n : ℤ), by rw [zpow_natCast, (key n).1, hn]⟩

/-- The converse: a `σRaw`-`SameCycle` within a deleted `σ`-orbit is a `σ`-`SameCycle`. -/
lemma sigma_sameCycle_iff_sigmaRaw_of_deletedOrbit {x : D}
    (hO : DeletedOrbit M.σ Del (Quotient.mk (cycleSetoid M.σ) x)) {y : D}
    (h : (M.σ * rawAlpha M Del hclosed).SameCycle x y) : M.σ.SameCycle x y := by
  classical
  have hxDel : x ∈ Del := hO x rfl
  have key : ∀ k : ℕ, (M.σ ^ k) x = ((M.σ * rawAlpha M Del hclosed) ^ k) x
      ∧ ((M.σ * rawAlpha M Del hclosed) ^ k) x ∈ Del := by
    intro k
    induction k with
    | zero => exact ⟨by simp, by simpa using hxDel⟩
    | succ k ih =>
        obtain ⟨ihEq, ihDel⟩ := ih
        have hσ_del : (M.σ ^ k) x ∈ Del := ihEq ▸ ihDel
        have heq : (M.σ ^ (k+1)) x = ((M.σ * rawAlpha M Del hclosed) ^ (k+1)) x := by
          have e1 : ((M.σ * rawAlpha M Del hclosed) ^ (k+1)) x
              = M.σ (((M.σ * rawAlpha M Del hclosed) ^ k) x) := by
            rw [pow_succ', Equiv.Perm.mul_apply, Equiv.Perm.mul_apply,
              rawAlpha_eq_self_of_mem M Del hclosed ihDel]
          have e2 : (M.σ ^ (k+1)) x = M.σ ((M.σ ^ k) x) := by rw [pow_succ']; rfl
          rw [e1, e2, ihEq]
        refine ⟨heq, ?_⟩
        apply hO
        apply Quotient.sound
        show M.σ.SameCycle (((M.σ * rawAlpha M Del hclosed) ^ (k+1)) x) x
        exact ⟨-((k+1 : ℕ) : ℤ), by
          rw [← heq, zpow_neg, zpow_natCast, Equiv.Perm.inv_eq_iff_eq, Equiv.Perm.coe_pow]⟩
  obtain ⟨n, hn⟩ := h.exists_nat_pow_eq
  exact ⟨(n : ℤ), by rw [zpow_natCast, (key n).1, hn]⟩

/-- **`numDeletedOrbits (M.σ * rawAlpha) Del = numDeletedOrbits M.σ Del`.** -/
theorem numDeletedOrbits_sigmaRaw_eq :
    numDeletedOrbits (M.σ * rawAlpha M Del hclosed) Del = numDeletedOrbits M.σ Del := by
  classical
  unfold numDeletedOrbits
  refine Fintype.card_congr ?_
  refine
    { toFun := fun q => ⟨Quotient.mk (cycleSetoid M.σ) q.1.out,
        (deletedOrbit_sigmaRaw_iff M Del hclosed q.1.out).1 (by
          intro z hz; exact q.2 z (by rw [hz]; exact Quotient.out_eq q.1))⟩,
      invFun := fun o => ⟨Quotient.mk (cycleSetoid (M.σ * rawAlpha M Del hclosed)) o.1.out,
        (deletedOrbit_sigmaRaw_iff M Del hclosed o.1.out).2 (by
          intro z hz; exact o.2 z (by rw [hz]; exact Quotient.out_eq o.1))⟩,
      left_inv := ?_, right_inv := ?_ }
  · rintro ⟨q, hq⟩
    apply Subtype.ext
    dsimp only
    nth_rewrite 2 [← Quotient.out_eq q]
    apply Quotient.sound
    show (M.σ * rawAlpha M Del hclosed).SameCycle
      (Quotient.mk (cycleSetoid M.σ) q.out).out q.out
    -- `(mk_σ q.out).out` is `σ`-SameCycle to `q.out`; convert to `σRaw` via deletedness.
    have hsc : M.σ.SameCycle (Quotient.mk (cycleSetoid M.σ) q.out).out q.out :=
      Quotient.exact (Quotient.out_eq (Quotient.mk (cycleSetoid M.σ) q.out))
    -- `q.out`'s `σRaw`-orbit is deleted (q is a deleted `σRaw`-class).
    have hqDel : DeletedOrbit (M.σ * rawAlpha M Del hclosed) Del
        (Quotient.mk (cycleSetoid (M.σ * rawAlpha M Del hclosed)) q.out) := by
      intro z hz; exact hq z (by rw [hz]; exact Quotient.out_eq q)
    exact (sigmaRaw_sameCycle_iff_sigma_of_deletedOrbit M Del hclosed hqDel hsc.symm).symm
  · rintro ⟨o, ho⟩
    apply Subtype.ext
    dsimp only
    nth_rewrite 2 [← Quotient.out_eq o]
    apply Quotient.sound
    show M.σ.SameCycle (Quotient.mk (cycleSetoid (M.σ * rawAlpha M Del hclosed)) o.out).out o.out
    have hsc : (M.σ * rawAlpha M Del hclosed).SameCycle
        (Quotient.mk (cycleSetoid (M.σ * rawAlpha M Del hclosed)) o.out).out o.out :=
      Quotient.exact (Quotient.out_eq
        (Quotient.mk (cycleSetoid (M.σ * rawAlpha M Del hclosed)) o.out))
    -- `o.out`'s `σ`-orbit is deleted (o is a deleted `σ`-class); convert via the converse lemma.
    have hoDel : DeletedOrbit M.σ Del (Quotient.mk (cycleSetoid M.σ) o.out) := by
      intro z hz; exact ho z (by rw [hz]; exact Quotient.out_eq o)
    exact (sigma_sameCycle_iff_sigmaRaw_of_deletedOrbit M Del hclosed hoDel hsc.symm).symm



/-- `rawAlpha` is an edge-deletion sub-involution of `M.α`. -/
lemma rawAlpha_subInvolution : SubInvolution M.α (rawAlpha M Del hclosed) := by
  refine ⟨rawAlpha_invol M Del hclosed, fun x hx => ?_⟩
  -- where `rawAlpha` moves `x`, it equals `M.α x` (so `x ∉ Del`).
  by_cases hxD : x ∈ Del
  · exact absurd (rawAlpha_eq_self_of_mem M Del hclosed hxD) hx
  · exact rawAlpha_eq_alpha_of_notMem M Del hclosed hxD

/-- **The raw slack of a genus-0 `M` after deleting `Del` is zero** (`d₀` a witness dart). -/
theorem genusSlack_rawAlpha_eq_zero (hsphere : M.IsSphereMap) (d₀ : D) :
    genusSlack M.σ (rawAlpha M Del hclosed) = 0 := by
  have hle : genusSlack M.σ (rawAlpha M Del hclosed) ≤ genusSlack M.σ M.α :=
    genusSlack_le_of_subInvolution M.σ M.α M.α_invol _ (rawAlpha_subInvolution M Del hclosed)
  have hM0 : genusSlack M.σ M.α = 0 := genusSlack_sphere_eq_zero M hsphere d₀
  have hge : 0 ≤ genusSlack M.σ (rawAlpha M Del hclosed) :=
    genusSlack_nonneg M.σ _ (rawAlpha_invol M Del hclosed)
  rw [hM0] at hle
  exact le_antisymm hle hge

/-- The kept edge involution has the same number of edges (transpositions) as `rawAlpha`:
both have support exactly the kept darts. -/
lemma Ehalf_keptAlpha_eq_rawAlpha :
    Ehalf (keptAlpha M Del hsub) = Ehalf (rawAlpha M Del hclosed) := by
  classical
  -- `2 * Ehalf = card support`.  `keptAlpha` is fixed-point-free on the kept subtype, so its
  -- support is all kept darts; `rawAlpha`'s support is exactly the kept darts of `D`.
  have hk : (keptAlpha M Del hsub) ∈ Set.univ := ⟨⟩
  -- `keptAlpha` fixed-point-free:
  have hkff : ∀ d, keptAlpha M Del hsub d ≠ d := by
    intro d hd
    apply M.α_no_fixed d.1
    have := congrArg Subtype.val hd
    rwa [keptAlpha_apply_coe] at this
  have hksupp : Equiv.Perm.support (keptAlpha M Del hsub) = Finset.univ := by
    rw [Finset.eq_univ_iff_forall]; intro d; rw [Equiv.Perm.mem_support]; exact hkff d
  -- `rawAlpha` support = kept darts (its complement is `Del`).
  have hrsupp : Equiv.Perm.support (rawAlpha M Del hclosed) = Finset.univ.filter (· ∉ Del) := by
    ext d
    simp only [Equiv.Perm.mem_support, Finset.mem_filter, Finset.mem_univ, true_and]
    rw [rawAlpha_apply]
    by_cases hd : d ∈ Del
    · simp [hd]
    · simp only [hd, if_false, not_false_iff, iff_true]
      exact fun hc => M.α_no_fixed d hc
  unfold Ehalf
  rw [hksupp, hrsupp, Finset.card_univ]
  -- both cardinalities are `|kept darts|`.
  have : (Finset.univ.filter (· ∉ Del) : Finset D).card
      = Fintype.card {d : D // d ∉ Del} := by
    rw [Fintype.card_subtype]
  rw [this]

/-- **The kept combinatorial map's genus slack is zero** on a genus-0 `M`.  This is the
structural genus-0 certificate: the kept side (an edge-deletion sub-map of the sphere `M`) has
genus slack `0`, hence — when connected — Euler characteristic `2` (no handle). -/
theorem keptMap_genusSlack_eq_zero (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del)
    (hsphere : M.IsSphereMap) (d₀ : D) :
    genusSlack (Equiv.Perm.deleteSet M.σ Del) (keptAlpha M Del hsub) = 0 := by
  classical
  have hraw0 : genusSlack M.σ (rawAlpha M Del hclosed) = 0 :=
    genusSlack_rawAlpha_eq_zero M Del hclosed hsphere d₀
  -- expand both slacks via the count bridges.
  unfold genusSlack at hraw0 ⊢
  -- raw: `2c_raw - numCycles σ + Ehalf rawAlpha - numCycles (σ rawAlpha)`.
  -- kept: `2c_kept - numCycles(deleteSet σ) + Ehalf keptAlpha - numCycles(keptFacePerm)`.
  -- bridges:
  have hcsplit : numComponents M.σ (rawAlpha M Del hclosed)
      = _root_.numComp (keptStepRel M Del hsub) + numDeletedComp M Del hclosed :=
    numComponents_raw_split M Del hclosed hsub
  have hkeptStep_eq : _root_.numComp (keptStepRel M Del hsub)
      = numComponents (Equiv.Perm.deleteSet M.σ Del) (keptAlpha M Del hsub) := by
    rw [numComponents_def]; rfl
  have hDC : numDeletedComp M Del hclosed = numDeletedOrbits M.σ Del :=
    numDeletedComp_eq_numDeletedOrbits M Del hclosed
  have hVsplit : _root_.numCycles M.σ
      = _root_.numCycles (Equiv.Perm.deleteSet M.σ Del) + numDeletedOrbits M.σ Del :=
    numCycles_eq_kept_add_deleted M.σ Del
  have hFsplit : _root_.numCycles (M.σ * rawAlpha M Del hclosed)
      = _root_.numCycles (Equiv.Perm.deleteSet (M.σ * rawAlpha M Del hclosed) Del)
        + numDeletedOrbits (M.σ * rawAlpha M Del hclosed) Del :=
    numCycles_eq_kept_add_deleted (M.σ * rawAlpha M Del hclosed) Del
  have hFbridge : _root_.numCycles (keptFacePerm M Del hclosed hsub)
      = _root_.numCycles (Equiv.Perm.deleteSet (M.σ * rawAlpha M Del hclosed) Del) :=
    numCycles_keptFacePerm_eq M Del hclosed hsub
  have hDF : numDeletedOrbits (M.σ * rawAlpha M Del hclosed) Del = numDeletedOrbits M.σ Del :=
    numDeletedOrbits_sigmaRaw_eq M Del hclosed
  have hEh : Ehalf (keptAlpha M Del hsub) = Ehalf (rawAlpha M Del hclosed) :=
    Ehalf_keptAlpha_eq_rawAlpha M Del hclosed hsub
  -- the kept face permutation is the σα of the kept CombMap.
  have hkeptFace : (Equiv.Perm.deleteSet M.σ Del) * (keptAlpha M Del hsub)
      = keptFacePerm M Del hclosed hsub := rfl
  -- assemble: rewrite `hraw0` (raw slack = 0) into kept quantities.
  rw [hkeptStep_eq] at hcsplit
  rw [hcsplit, hVsplit, ← hEh, hFsplit, hDF, hDC] at hraw0
  -- hraw0 now: `2(c_kept + DV) - (V_kept + DV) + Ehalf keptAlpha
  --   - (numCycles(deleteSet(σ*rawAlpha)) + DV) = 0`.
  -- goal: `2 c_kept - V_kept + Ehalf keptAlpha - numCycles(keptFacePerm) = 0`.
  rw [hkeptFace, hFbridge]
  push_cast at hraw0 ⊢
  linarith

/-- **The kept combinatorial map of a chord-split side of a genus-0 `M` is a disk
(no handle).**  Given a `CombMap K` whose rotation is `deleteSet M.σ Del` and whose edge
involution is `keptAlpha`, if it is connected and has a dart, then its Euler characteristic is
exactly `2`.  This is the reverse inequality `2 ≤ eulerChar` (in fact equality), supplied by the
structural genus monotonicity — the genus-0 certificate that the chord side has no handle. -/
theorem keptMap_eulerChar_eq_two (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del)
    (hsphere : M.IsSphereMap)
    (K : CombMap {d : D // d ∉ Del})
    (hKσ : K.σ = Equiv.Perm.deleteSet M.σ Del) (hKα : K.α = keptAlpha M Del hsub)
    (d : {d : D // d ∉ Del}) (hconn : K.Connected) :
    K.eulerChar = 2 := by
  classical
  have hslack0 : genusSlack (Equiv.Perm.deleteSet M.σ Del) (keptAlpha M Del hsub) = 0 :=
    keptMap_genusSlack_eq_zero M Del hsub hclosed hsphere d.1
  have hc : numComponents K.σ K.α = 1 :=
    numComponents_eq_one_of_connected K hconn d
  have hVc : (K.V : ℤ) = (_root_.numCycles K.σ : ℤ) := by rw [V_eq_numCycles]
  have hEc : (K.E : ℤ) = (Ehalf K.α : ℤ) := by rw [Ehalf_eq_E]
  have hFc : (K.F : ℤ) = (_root_.numCycles (K.σ * K.α) : ℤ) := by rw [F_eq_numCycles]; rfl
  have hslack : genusSlack K.σ K.α = 0 := by rw [hKσ, hKα]; exact hslack0
  unfold genusSlack at hslack
  rw [hc] at hslack
  unfold CombMap.eulerChar
  rw [hVc, hEc, hFc]
  push_cast at hslack ⊢
  linarith

end RawRestrict



section ChordThreading

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordSideRecon

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

/-- `keptDel₁` is `M.α`-closed (membership is `α`-invariant), the input to the structural
certificate. -/
lemma keptDel₁_sub (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    ∀ d, d ∈ data.keptDel₁ ↔ M.α d ∈ data.keptDel₁ := by
  intro d
  have h1 : d ∉ data.keptDel₁ ↔ d ∈ data.keptSet₁ := data.mem_keptDel₁_iff d
  have h2 : M.α d ∉ data.keptDel₁ ↔ M.α d ∈ data.keptSet₁ := data.mem_keptDel₁_iff (M.α d)
  have hkept : M.α d ∈ data.keptSet₁ ↔ d ∈ data.keptSet₁ :=
    data.mem_keptSet₁_alpha_iff hsep d
  classical
  -- `d ∈ Del ↔ ¬ d ∈ keptSet`, similarly for `M.α d`; then use `hkept`.
  have h1' : d ∈ data.keptDel₁ ↔ ¬ d ∈ data.keptSet₁ := by
    rw [← h1]; exact (not_not).symm
  have h2' : M.α d ∈ data.keptDel₁ ↔ ¬ M.α d ∈ data.keptSet₁ := by
    rw [← h2]; exact (not_not).symm
  rw [h1', h2']
  exact (not_congr hkept).symm

lemma keptDel₁_closed (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    ∀ d, d ∈ data.keptDel₁ → M.α d ∈ data.keptDel₁ :=
  fun d hd => (keptDel₁_sub data hsep d).1 hd

/-- `sideAlpha₁` equals the abstract `keptAlpha` of `keptDel₁` (both are `M.α` restricted). -/
lemma sideAlpha₁_eq_keptAlpha (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    data.sideAlpha₁ hsep
      = SubmapPlanar.keptAlpha M data.keptDel₁ (keptDel₁_sub data hsep) := by
  ext d
  rw [data.sideAlpha₁_apply_coe]
  rfl

/-- **The `≥ 2` no-handle half of `KeptSideIsDisk` at side 1, discharged structurally.**  If the
kept side-1 map is connected and has a dart, its Euler characteristic is `2` — the genus-0
certificate from sub-map planarity (`M` is a sphere via `hNT.sphere`). -/
theorem side₁_keptMap_eulerChar_eq_two (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (d : {d : D // d ∉ data.keptDel₁})
    (hconn : (sideKeptMap₁ data hsep).Connected) :
    (sideKeptMap₁ data hsep).eulerChar = 2 := by
  refine SubmapPlanar.keptMap_eulerChar_eq_two M data.keptDel₁ (keptDel₁_sub data hsep)
    (keptDel₁_closed data hsep) hNT.sphere (sideKeptMap₁ data hsep) ?_ ?_ d hconn
  · -- `(sideKeptMap₁).σ = sideSigma₁ = filteredRotation M.σ keptDel₁ = deleteSet M.σ keptDel₁`.
    show data.sideSigma₁ = Equiv.Perm.deleteSet M.σ data.keptDel₁
    rfl
  · -- `(sideKeptMap₁).α = sideAlpha₁ = keptAlpha`.
    show data.sideAlpha₁ hsep = SubmapPlanar.keptAlpha M data.keptDel₁ (keptDel₁_sub data hsep)
    exact sideAlpha₁_eq_keptAlpha data hsep

/-- **`Side₁IsDisk` reduces to connectivity of the kept side.**  Given the structural genus-0
certificate, side 1 is a disk (`IsSphereMap`) *iff* its kept map is connected (the `eulerChar`
half is discharged).  This removes the no-handle inequality `2 ≤ eulerChar` from the residue —
its `≤ 2` half is `chi_le_two_of_connected`, its `≥ 2` half is now proved. -/
theorem side₁IsDisk_of_connected (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (d : {d : D // d ∉ data.keptDel₁})
    (hconn : (sideKeptMap₁ data hsep).Connected) :
    ChordDisk.Side₁IsDisk data hsep :=
  ⟨hconn, side₁_keptMap_eulerChar_eq_two data hsep d hconn⟩



end ChordThreading

end ProofsInTheBook.SubmapPlanar

















end

/- Original source header (imports hoisted):
import Mathlib
-/
/- Source module: ProofsInTheBook.TetPearls -/
section
set_option autoImplicit true




noncomputable section

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1000000

open scoped Classical
open Set

namespace ProofsInTheBook.TetPearls

/-- Ambient Euclidean 3-space. -/
abbrev Pt3 : Type := EuclideanSpace ℝ (Fin 3)





namespace Tet



















end Tet





namespace TetSolid







end TetSolid









namespace Segment3







































































end Segment3



namespace Tet













end Tet





















namespace Pearl








end Pearl





































end ProofsInTheBook.TetPearls

end
end

/- Original source header (imports hoisted):
import Mathlib
-/
/- Source module: ProofsInTheBook.Chapter09 -/
section
set_option autoImplicit true




namespace ProofsInTheBook.Chapter09

open scoped BigOperators TensorProduct
open Polynomial Chebyshev





















































-- (`angleClassQ_arccos_one_third_ne_zero` defined below, after
-- `arccos_one_third_irrational_over_pi`.)












































































































































































































































































end ProofsInTheBook.Chapter09

end

/- Original source header (imports hoisted):
import ProofsInTheBook.TetPearls
import ProofsInTheBook.Chapter09
-/
/- Source module: ProofsInTheBook.TetDihedral -/
section
set_option autoImplicit true




noncomputable section

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

open scoped RealInnerProductSpace
open ProofsInTheBook.TetPearls

namespace ProofsInTheBook.TetDihedral

























































































end ProofsInTheBook.TetDihedral

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.TetDihedral
-/
/- Source module: ProofsInTheBook.SphericalKernel -/
section
set_option autoImplicit true




noncomputable section

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

open scoped RealInnerProductSpace
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral

namespace ProofsInTheBook.SphericalKernel



/-- `E3` is the ambient Euclidean 3-space `EuclideanSpace ℝ (Fin 3)` (an alias for `Pt3`). -/
abbrev E3 : Type := Pt3

/-- The unit sphere `S²`, as the unit vectors of `E3`. -/
def S2 : Type := {x : E3 // ‖x‖ = 1}

instance : Coe S2 E3 := ⟨Subtype.val⟩




















































































































end ProofsInTheBook.SphericalKernel

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalKernel
-/
/- Source module: ProofsInTheBook.SphericalArm -/
section
set_option autoImplicit true




noncomputable section

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

open scoped RealInnerProductSpace
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel

namespace ProofsInTheBook.SphericalArm







































































end ProofsInTheBook.SphericalArm

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalArm
-/
/- Source module: ProofsInTheBook.SphericalRotation -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm

namespace ProofsInTheBook.SphericalRotation

/-- Cross product on `E3 = EuclideanSpace ℝ (Fin 3)`, in explicit coordinates. -/
def cross (a b : E3) : E3 :=
  !₂[a 1 * b 2 - a 2 * b 1, a 2 * b 0 - a 0 * b 2, a 0 * b 1 - a 1 * b 0]

@[simp] theorem cross_apply_zero (a b : E3) : cross a b 0 = a 1 * b 2 - a 2 * b 1 := rfl
@[simp] theorem cross_apply_one (a b : E3) : cross a b 1 = a 2 * b 0 - a 0 * b 2 := rfl
@[simp] theorem cross_apply_two (a b : E3) : cross a b 2 = a 0 * b 1 - a 1 * b 0 := rfl

/-- Inner product expanded into coordinates. -/
theorem inner_eq_coord (a b : E3) :
    (⟪a, b⟫ : ℝ) = a 0 * b 0 + a 1 * b 1 + a 2 * b 2 := by
  rw [PiLp.inner_apply, Fin.sum_univ_three]
  simp only [RCLike.inner_apply, conj_trivial]; ring
























/-- `⟪a × b, a⟫ = 0`: the cross product is orthogonal to the first factor. -/
theorem inner_cross_left (a b : E3) : (⟪cross a b, a⟫ : ℝ) = 0 := by
  rw [inner_eq_coord]; simp; ring











/-- **Binet–Cauchy identity:** `⟪a × b, c × d⟫ = ⟪a,c⟫⟪b,d⟫ − ⟪a,d⟫⟪b,c⟫`. -/
theorem inner_cross_cross (a b c d : E3) :
    (⟪cross a b, cross c d⟫ : ℝ) = ⟪a, c⟫ * ⟪b, d⟫ - ⟪a, d⟫ * ⟪b, c⟫ := by
  rw [inner_eq_coord, inner_eq_coord, inner_eq_coord, inner_eq_coord, inner_eq_coord]
  simp only [cross_apply_zero, cross_apply_one, cross_apply_two]; ring



/-- The Rodrigues rotation of `v` about unit axis `k` by angle `θ`. -/
def rot (k : E3) (θ : ℝ) (v : E3) : E3 :=
  Real.cos θ • v + Real.sin θ • cross k v + ((1 - Real.cos θ) * ⟪k, v⟫) • k















/-- **Inner-product preservation (the crux):** `⟪rot k θ v, rot k θ w⟫ = ⟪v, w⟫` for a unit axis.
Proved by bilinear expansion using `inner_cross_cross` (Binet–Cauchy), `inner_cross_left/right`
(`⟪k×v,k⟫ = 0`), and `cos²θ + sin²θ = 1`. -/
theorem inner_rot_rot {k : E3} (hk : ‖k‖ = 1) (θ : ℝ) (v w : E3) :
    (⟪rot k θ v, rot k θ w⟫ : ℝ) = ⟪v, w⟫ := by
  have hkk : (⟪k, k⟫ : ℝ) = 1 := by rw [real_inner_self_eq_norm_sq, hk]; norm_num
  have hcs : Real.cos θ ^ 2 + Real.sin θ ^ 2 = 1 := Real.cos_sq_add_sin_sq θ
  -- key cross identities (with k a unit vector)
  have h_kvk : (⟪cross k v, k⟫ : ℝ) = 0 := inner_cross_left k v
  have h_kkv : (⟪k, cross k v⟫ : ℝ) = 0 := by rw [real_inner_comm]; exact h_kvk
  have h_kwk : (⟪cross k w, k⟫ : ℝ) = 0 := inner_cross_left k w
  have h_kkw : (⟪k, cross k w⟫ : ℝ) = 0 := by rw [real_inner_comm]; exact h_kwk
  -- ⟪k×v, k×w⟫ = ⟪k,k⟫⟪v,w⟫ − ⟪k,w⟫⟪v,k⟫ = ⟪v,w⟫ − ⟪k,w⟫⟪v,k⟫
  have h_cc : (⟪cross k v, cross k w⟫ : ℝ) = ⟪v, w⟫ - ⟪k, w⟫ * ⟪v, k⟫ := by
    rw [inner_cross_cross, hkk, one_mul]
  -- mixed term antisymmetry: ⟪k×v, w⟫ = −⟪v, k×w⟫
  have h_mix : (⟪cross k v, w⟫ : ℝ) = -(⟪v, cross k w⟫) := by
    rw [inner_eq_coord, inner_eq_coord]
    simp only [cross_apply_zero, cross_apply_one, cross_apply_two]; ring
  have hvk : (⟪v, k⟫ : ℝ) = ⟪k, v⟫ := real_inner_comm k v
  -- expand the full inner product
  simp only [rot, inner_add_left, inner_add_right, real_inner_smul_left, real_inner_smul_right,
    h_kvk, h_kkw, hkk]
  rw [h_cc, h_mix, hvk]
  -- now everything is in terms of ⟪v,w⟫, ⟪k,v⟫, ⟪k,w⟫, ⟪v, cross k w⟫, cos, sin;
  -- LHS − ⟪v,w⟫ = (cos²+sin²−1)(⟪v,w⟫ − ⟪k,v⟫⟪k,w⟫), closed by hcs.
  linear_combination (⟪v, w⟫ - ⟪k, v⟫ * ⟪k, w⟫) * hcs

/-- **Norm preservation:** `‖rot k θ v‖ = ‖v‖`. -/
theorem norm_rot {k : E3} (hk : ‖k‖ = 1) (θ : ℝ) (v : E3) :
    ‖rot k θ v‖ = ‖v‖ := by
  have h1 : ‖rot k θ v‖ ^ 2 = ‖v‖ ^ 2 := by
    rw [← real_inner_self_eq_norm_sq, ← real_inner_self_eq_norm_sq, inner_rot_rot hk]
  have hnn1 : (0 : ℝ) ≤ ‖rot k θ v‖ := norm_nonneg _
  have hnn2 : (0 : ℝ) ≤ ‖v‖ := norm_nonneg _
  nlinarith [h1, hnn1, hnn2]



/-- The rotation maps `S²` into `S²` (norm preserved). -/
def rotS2 (k : S2) (θ : ℝ) (p : S2) : S2 :=
  ⟨rot (k : E3) θ (p : E3), by rw [norm_rot k.2]; exact p.2⟩























variable {ι : Type*}

























end ProofsInTheBook.SphericalRotation

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalRotation
-/
/- Source module: ProofsInTheBook.SphericalSZ -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm ProofsInTheBook.SphericalRotation

namespace ProofsInTheBook.SphericalSZ


























end ProofsInTheBook.SphericalSZ

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalSZ
-/
/- Source module: ProofsInTheBook.SphericalCore -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ

namespace ProofsInTheBook.SphericalCore

















































end ProofsInTheBook.SphericalCore

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalCore
-/
/- Source module: ProofsInTheBook.SphericalFinish -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore

namespace ProofsInTheBook.SphericalFinish









































end ProofsInTheBook.SphericalFinish

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalFinish
-/
/- Source module: ProofsInTheBook.SphericalOpening -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish

namespace ProofsInTheBook.SphericalOpening

























end ProofsInTheBook.SphericalOpening

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalOpening
-/
/- Source module: ProofsInTheBook.SphericalHinge -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening

namespace ProofsInTheBook.SphericalHinge



















































end ProofsInTheBook.SphericalHinge

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalHinge
-/
/- Source module: ProofsInTheBook.SphericalSZChain -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge

namespace ProofsInTheBook.SphericalSZChain































end ProofsInTheBook.SphericalSZChain

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalSZChain
-/
/- Source module: ProofsInTheBook.SphericalCyclicTriple -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain

namespace ProofsInTheBook.SphericalCyclicTriple









































end ProofsInTheBook.SphericalCyclicTriple

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalCyclicTriple
-/
/- Source module: ProofsInTheBook.SphericalGnomonic -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple

namespace ProofsInTheBook.SphericalGnomonic






















































end ProofsInTheBook.SphericalGnomonic

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalGnomonic
-/
/- Source module: ProofsInTheBook.PlanarConvexDiag -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalArm ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCyclicTriple ProofsInTheBook.SphericalSZChain
open ProofsInTheBook.SphericalGnomonic

namespace ProofsInTheBook.PlanarConvexDiag



























end ProofsInTheBook.PlanarConvexDiag

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarConvexDiag
-/
/- Source module: ProofsInTheBook.SphericalSZStep -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag

namespace ProofsInTheBook.SphericalSZStep































end ProofsInTheBook.SphericalSZStep

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalSZStep
-/
/- Source module: ProofsInTheBook.SphericalHingeCut -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep

namespace ProofsInTheBook.SphericalHingeCut







































end ProofsInTheBook.SphericalHingeCut

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalHingeCut
-/
/- Source module: ProofsInTheBook.SphericalDiagCut -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut

namespace ProofsInTheBook.SphericalDiagCut

















































end ProofsInTheBook.SphericalDiagCut

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalDiagCut
-/
/- Source module: ProofsInTheBook.SphericalOpeningProcess -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut

namespace ProofsInTheBook.SphericalOpeningProcess

























































end ProofsInTheBook.SphericalOpeningProcess

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalOpeningProcess
-/
/- Source module: ProofsInTheBook.SphericalReachStuck -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess

namespace ProofsInTheBook.SphericalReachStuck





































end ProofsInTheBook.SphericalReachStuck

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalReachStuck
-/
/- Source module: ProofsInTheBook.SphericalAdmissibleSup -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck

namespace ProofsInTheBook.SphericalAdmissibleSup

































































end ProofsInTheBook.SphericalAdmissibleSup

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalAdmissibleSup
-/
/- Source module: ProofsInTheBook.SphericalArmClose -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup

namespace ProofsInTheBook.SphericalArmClose































































end ProofsInTheBook.SphericalArmClose

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalArmClose
-/
/- Source module: ProofsInTheBook.SphericalArmFinal -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose

namespace ProofsInTheBook.SphericalArmFinal























end ProofsInTheBook.SphericalArmFinal

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalArmFinal
-/
/- Source module: ProofsInTheBook.SphericalSZComplete -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose

namespace ProofsInTheBook.SphericalSZComplete













































end ProofsInTheBook.SphericalSZComplete

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalSZComplete
-/
/- Source module: ProofsInTheBook.SphericalStuckWitness -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete

namespace ProofsInTheBook.SphericalStuckWitness





















































end ProofsInTheBook.SphericalStuckWitness

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalStuckWitness
-/
/- Source module: ProofsInTheBook.SphericalTerminalVis -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalStuckWitness

namespace ProofsInTheBook.SphericalTerminalVis































































end ProofsInTheBook.SphericalTerminalVis

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalTerminalVis
-/
/- Source module: ProofsInTheBook.SphericalArmUncond -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalTerminalVis

namespace ProofsInTheBook.SphericalArmUncond

















































end ProofsInTheBook.SphericalArmUncond

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalArmUncond
-/
/- Source module: ProofsInTheBook.SphericalMatchedCut -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalTerminalVis ProofsInTheBook.SphericalArmUncond

namespace ProofsInTheBook.SphericalMatchedCut









































































































end ProofsInTheBook.SphericalMatchedCut

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalMatchedCut
-/
/- Source module: ProofsInTheBook.SphericalCornerStep -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalTerminalVis ProofsInTheBook.SphericalArmUncond
open ProofsInTheBook.SphericalMatchedCut

namespace ProofsInTheBook.SphericalCornerStep















































end ProofsInTheBook.SphericalCornerStep

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalCornerStep
import ProofsInTheBook.PlanarConvexDiag
-/
/- Source module: ProofsInTheBook.SphericalConeMembership -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalTerminalVis ProofsInTheBook.SphericalArmUncond
open ProofsInTheBook.SphericalMatchedCut ProofsInTheBook.SphericalCornerStep

namespace ProofsInTheBook.SphericalConeMembership













































































end ProofsInTheBook.SphericalConeMembership

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalConeMembership
-/
/- Source module: ProofsInTheBook.SphericalArmDone -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalTerminalVis ProofsInTheBook.SphericalArmUncond
open ProofsInTheBook.SphericalMatchedCut ProofsInTheBook.SphericalCornerStep
open ProofsInTheBook.SphericalConeMembership

namespace ProofsInTheBook.SphericalArmDone



















































end ProofsInTheBook.SphericalArmDone

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalArmDone
-/
/- Source module: ProofsInTheBook.SphericalArmFinish -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalTerminalVis ProofsInTheBook.SphericalArmUncond
open ProofsInTheBook.SphericalMatchedCut ProofsInTheBook.SphericalCornerStep
open ProofsInTheBook.SphericalConeMembership ProofsInTheBook.SphericalArmDone

namespace ProofsInTheBook.SphericalArmFinish









































end ProofsInTheBook.SphericalArmFinish

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalArmFinish
-/
/- Source module: ProofsInTheBook.SphericalArmClose2 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalTerminalVis ProofsInTheBook.SphericalArmUncond
open ProofsInTheBook.SphericalMatchedCut ProofsInTheBook.SphericalCornerStep
open ProofsInTheBook.SphericalConeMembership ProofsInTheBook.SphericalArmDone
open ProofsInTheBook.SphericalArmFinish

namespace ProofsInTheBook.SphericalArmClose2















































end ProofsInTheBook.SphericalArmClose2

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalArmClose2
-/
/- Source module: ProofsInTheBook.SphericalStuckCollinear -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalTerminalVis ProofsInTheBook.SphericalArmUncond
open ProofsInTheBook.SphericalMatchedCut ProofsInTheBook.SphericalCornerStep
open ProofsInTheBook.SphericalConeMembership ProofsInTheBook.SphericalArmDone
open ProofsInTheBook.SphericalArmFinish ProofsInTheBook.SphericalArmClose2

namespace ProofsInTheBook.SphericalStuckCollinear















































end ProofsInTheBook.SphericalStuckCollinear

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalStuckCollinear
-/
/- Source module: ProofsInTheBook.SphericalOpenedArmCore -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalTerminalVis ProofsInTheBook.SphericalArmUncond
open ProofsInTheBook.SphericalMatchedCut ProofsInTheBook.SphericalCornerStep
open ProofsInTheBook.SphericalConeMembership ProofsInTheBook.SphericalArmDone
open ProofsInTheBook.SphericalArmFinish ProofsInTheBook.SphericalArmClose2
open ProofsInTheBook.SphericalStuckCollinear

namespace ProofsInTheBook.SphericalOpenedArmCore



























end ProofsInTheBook.SphericalOpenedArmCore

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalStuckCollinear
-/
/- Source module: ProofsInTheBook.SphericalSZInduction -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalDiagCut
open ProofsInTheBook.SphericalSZChain
open ProofsInTheBook.SphericalTerminalVis
open ProofsInTheBook.SphericalArmUncond
open ProofsInTheBook.SphericalStuckCollinear

namespace ProofsInTheBook.SphericalSZInduction

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000























/-- The interior tail-opening: fix vertices `≤ k`, rotate vertices `> k` about the axis `A k`. -/
def openTail {n : ℕ} (A : Fin (n + 1) → S2) (k : Fin (n + 1)) (δ : ℝ) : Fin (n + 1) → S2 :=
  fun r => if r.val ≤ k.val then A r else rotS2 (A k) δ (A r)







































































end ProofsInTheBook.SphericalSZInduction

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalSZInduction
-/
/- Source module: ProofsInTheBook.SphericalSZStepClose -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCyclicTriple ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZChain
open ProofsInTheBook.SphericalStuckCollinear
open ProofsInTheBook.SphericalSZInduction

namespace ProofsInTheBook.SphericalSZStepClose

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

















































end ProofsInTheBook.SphericalSZStepClose

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalSZStepClose
-/
/- Source module: ProofsInTheBook.SphericalSZFinal -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCyclicTriple ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalSZChain
open ProofsInTheBook.SphericalDiagCut
open ProofsInTheBook.SphericalSZStep
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose

namespace ProofsInTheBook.SphericalSZFinal

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

























































end ProofsInTheBook.SphericalSZFinal

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalSZFinal
-/
/- Source module: ProofsInTheBook.SphericalSZClose -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCyclicTriple ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalSZChain
open ProofsInTheBook.SphericalDiagCut
open ProofsInTheBook.SphericalSZStep
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal

namespace ProofsInTheBook.SphericalSZClose

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



































































end ProofsInTheBook.SphericalSZClose

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalSZClose
-/
/- Source module: ProofsInTheBook.SphericalCutTransport -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZClose

namespace ProofsInTheBook.SphericalCutTransport

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000































end ProofsInTheBook.SphericalCutTransport

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalCutTransport
-/
/- Source module: ProofsInTheBook.ZinanFFCT -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalCutTransport

namespace ProofsInTheBook.ZinanFFCT

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





























end ProofsInTheBook.ZinanFFCT

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT
-/
/- Source module: ProofsInTheBook.ZinanFFCT2 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalConeMembership
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.ZinanFFCT

namespace ProofsInTheBook.ZinanFFCT2

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000




































































end ProofsInTheBook.ZinanFFCT2

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT2
-/
/- Source module: ProofsInTheBook.ZinanFFCT3 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalConeMembership
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.ZinanFFCT
open ProofsInTheBook.ZinanFFCT2

namespace ProofsInTheBook.ZinanFFCT3

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000































end ProofsInTheBook.ZinanFFCT3

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT3
-/
/- Source module: ProofsInTheBook.ZinanFFCT4 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalConeMembership
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalGnomonic
open ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.ZinanFFCT
open ProofsInTheBook.ZinanFFCT2
open ProofsInTheBook.ZinanFFCT3

namespace ProofsInTheBook.ZinanFFCT4

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

































end ProofsInTheBook.ZinanFFCT4

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT4
-/
/- Source module: ProofsInTheBook.ZinanFFCT5 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalConeMembership
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalGnomonic
open ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.ZinanFFCT
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT4

namespace ProofsInTheBook.ZinanFFCT5

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



















end ProofsInTheBook.ZinanFFCT5

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT5
-/
/- Source module: ProofsInTheBook.ZinanFFCT6 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalConeMembership
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalGnomonic
open ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.ZinanFFCT
open ProofsInTheBook.ZinanFFCT2
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT5

namespace ProofsInTheBook.ZinanFFCT6

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000


























end ProofsInTheBook.ZinanFFCT6

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT6
-/
/- Source module: ProofsInTheBook.ZinanFFCT7 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalConeMembership
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalGnomonic
open ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.ZinanFFCT
open ProofsInTheBook.ZinanFFCT2
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT5
open ProofsInTheBook.ZinanFFCT6

namespace ProofsInTheBook.ZinanFFCT7

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



































end ProofsInTheBook.ZinanFFCT7

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT7
import ProofsInTheBook.PlanarConvexDiag
-/
/- Source module: ProofsInTheBook.ZinanFFCT8 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZ ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalCutTransport ProofsInTheBook.SphericalGnomonic
open ProofsInTheBook.SphericalConeMembership
open ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.ZinanFFCT ProofsInTheBook.ZinanFFCT2 ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT4 ProofsInTheBook.ZinanFFCT5 ProofsInTheBook.ZinanFFCT6
open ProofsInTheBook.ZinanFFCT7

namespace ProofsInTheBook.ZinanFFCT8

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000































end ProofsInTheBook.ZinanFFCT8

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT8
import ProofsInTheBook.SphericalRotation
-/
/- Source module: ProofsInTheBook.ZinanFFCT9 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalConeMembership
open ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.ZinanFFCT8

namespace ProofsInTheBook.ZinanFFCT9

set_option maxHeartbeats 1600000
















































































end ProofsInTheBook.ZinanFFCT9

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT9
-/
/- Source module: ProofsInTheBook.ZinanFFCT10 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace
open ProofsInTheBook.SphericalKernel
open ProofsInTheBook.ZinanFFCT8 ProofsInTheBook.ZinanFFCT9

namespace ProofsInTheBook.ZinanFFCT10

set_option maxHeartbeats 1600000






















































end ProofsInTheBook.ZinanFFCT10








end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT10
-/
/- Source module: ProofsInTheBook.ZinanFFCT17 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.ZinanFFCT10

namespace ProofsInTheBook.ZinanFFCT17

set_option maxHeartbeats 1600000















































































end ProofsInTheBook.ZinanFFCT17

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT17
-/
/- Source module: ProofsInTheBook.ZinanFFCT18 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.ZinanFFCT3 ProofsInTheBook.ZinanFFCT17

namespace ProofsInTheBook.ZinanFFCT18

set_option maxHeartbeats 1600000




















































end ProofsInTheBook.ZinanFFCT18

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalStuckWitness
import ProofsInTheBook.SphericalCutTransport
-/
/- Source module: ProofsInTheBook.SphericalStuckGeneral -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalStuckWitness ProofsInTheBook.SphericalTerminalVis
open ProofsInTheBook.SphericalSZInduction ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalCutTransport

namespace ProofsInTheBook.SphericalStuckGeneral





































end ProofsInTheBook.SphericalStuckGeneral

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalStuckGeneral
-/
/- Source module: ProofsInTheBook.SphericalLastCornerStuck -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpening ProofsInTheBook.SphericalHinge
open ProofsInTheBook.SphericalSZChain ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalGnomonic ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZStep ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalAdmissibleSup
open ProofsInTheBook.SphericalArmClose ProofsInTheBook.SphericalSZComplete
open ProofsInTheBook.SphericalCutTransport ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose ProofsInTheBook.SphericalStuckGeneral

namespace ProofsInTheBook.SphericalLastCornerStuck





























end ProofsInTheBook.SphericalLastCornerStuck

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT18
import ProofsInTheBook.SphericalLastCornerStuck
-/
/- Source module: ProofsInTheBook.ZinanFFCT19 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalCutTransport ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.TetDihedral
open ProofsInTheBook.ZinanFFCT18

namespace ProofsInTheBook.ZinanFFCT19

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000


















































end ProofsInTheBook.ZinanFFCT19

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalSZClose
-/
/- Source module: ProofsInTheBook.SphericalMonitoredSup -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalCyclicTriple ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalSZChain
open ProofsInTheBook.SphericalDiagCut
open ProofsInTheBook.SphericalSZStep
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose

namespace ProofsInTheBook.SphericalMonitoredSup

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

















/-- A non-incident edge–vertex pair: edge `(c.1, c.1+1)` and a vertex `c.2` off that edge. -/
def NonIncident (n : ℕ) : Type :=
  {c : Fin (n + 1) × Fin (n + 1) // c.2 ≠ c.1 ∧ c.2 ≠ c.1 + 1}

instance (n : ℕ) : Finite (NonIncident n) := by
  unfold NonIncident; infer_instance





















































end ProofsInTheBook.SphericalMonitoredSup

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalSZClose
-/
/- Source module: ProofsInTheBook.SphericalSpliceTransport -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose

namespace ProofsInTheBook.SphericalSpliceTransport

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000























end ProofsInTheBook.SphericalSpliceTransport

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalRotation
import ProofsInTheBook.SphericalCyclicTriple
-/
/- Source module: ProofsInTheBook.SphericalCongruence -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace
open ProofsInTheBook.TetPearls ProofsInTheBook.TetDihedral
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalCyclicTriple

namespace ProofsInTheBook.SphericalCongruence

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



























































end ProofsInTheBook.SphericalCongruence

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalMonitoredSup
import ProofsInTheBook.SphericalSpliceTransport
import ProofsInTheBook.SphericalCongruence
-/
/- Source module: ProofsInTheBook.SphericalArmAssembly -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalCyclicTriple ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSpliceTransport
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalCongruence

namespace ProofsInTheBook.SphericalArmAssembly

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000







































end ProofsInTheBook.SphericalArmAssembly

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalArmAssembly
-/
/- Source module: ProofsInTheBook.SphericalOpeningOutcome -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalArmAssembly

namespace ProofsInTheBook.SphericalOpeningOutcome

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



























end ProofsInTheBook.SphericalOpeningOutcome


end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT19
import ProofsInTheBook.SphericalSZClose
import ProofsInTheBook.SphericalOpeningOutcome
import ProofsInTheBook.ZinanFFCT18
-/
/- Source module: ProofsInTheBook.ZinanFFCT20 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT18

namespace ProofsInTheBook.ZinanFFCT20




















end ProofsInTheBook.ZinanFFCT20

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT10
-/
/- Source module: ProofsInTheBook.ZinanFFCT12 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace
open ProofsInTheBook.SphericalKernel
open ProofsInTheBook.ZinanFFCT8 ProofsInTheBook.ZinanFFCT9 ProofsInTheBook.ZinanFFCT10

namespace ProofsInTheBook.ZinanFFCT12

set_option maxHeartbeats 1600000



























end ProofsInTheBook.ZinanFFCT12

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT20
import ProofsInTheBook.ZinanFFCT12
-/
/- Source module: ProofsInTheBook.ZinanFFCT21 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT3 ProofsInTheBook.ZinanFFCT9 ProofsInTheBook.ZinanFFCT10
open ProofsInTheBook.ZinanFFCT12 ProofsInTheBook.ZinanFFCT18

namespace ProofsInTheBook.ZinanFFCT21

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





















































end ProofsInTheBook.ZinanFFCT21

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT21
-/
/- Source module: ProofsInTheBook.ZinanFFCT22 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT3 ProofsInTheBook.ZinanFFCT9 ProofsInTheBook.ZinanFFCT10
open ProofsInTheBook.ZinanFFCT12 ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT21

namespace ProofsInTheBook.ZinanFFCT22

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000















































end ProofsInTheBook.ZinanFFCT22

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT22
-/
/- Source module: ProofsInTheBook.ZinanFFCT23 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT3 ProofsInTheBook.ZinanFFCT9 ProofsInTheBook.ZinanFFCT10
open ProofsInTheBook.ZinanFFCT12 ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT21

namespace ProofsInTheBook.ZinanFFCT23

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





































end ProofsInTheBook.ZinanFFCT23

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT23
-/
/- Source module: ProofsInTheBook.ZinanFFCT24 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT3 ProofsInTheBook.ZinanFFCT9 ProofsInTheBook.ZinanFFCT10
open ProofsInTheBook.ZinanFFCT12 ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT21
open ProofsInTheBook.ZinanFFCT22 ProofsInTheBook.ZinanFFCT23

namespace ProofsInTheBook.ZinanFFCT24

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000






















































end ProofsInTheBook.ZinanFFCT24

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT24
-/
/- Source module: ProofsInTheBook.ZinanFFCT25 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction ProofsInTheBook.SphericalRotation
open ProofsInTheBook.ZinanFFCT3 ProofsInTheBook.ZinanFFCT9 ProofsInTheBook.ZinanFFCT10
open ProofsInTheBook.ZinanFFCT12 ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT21
open ProofsInTheBook.ZinanFFCT22 ProofsInTheBook.ZinanFFCT23 ProofsInTheBook.ZinanFFCT24

namespace ProofsInTheBook.ZinanFFCT25

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000













































end ProofsInTheBook.ZinanFFCT25

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT25
import ProofsInTheBook.SphericalCore
-/
/- Source module: ProofsInTheBook.ZinanFFCT26 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.ZinanFFCT10

namespace ProofsInTheBook.ZinanFFCT26

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000











































end ProofsInTheBook.ZinanFFCT26

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT26
import ProofsInTheBook.SphericalStuckGeneral
-/
/- Source module: ProofsInTheBook.ZinanFFCT27 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.ZinanFFCT9 ProofsInTheBook.ZinanFFCT10 ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT26 ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalSZ

namespace ProofsInTheBook.ZinanFFCT27

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000







































end ProofsInTheBook.ZinanFFCT27

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT27
import ProofsInTheBook.ZinanFFCT25
import ProofsInTheBook.SphericalMonitoredSup
import ProofsInTheBook.SphericalOpeningOutcome
-/
/- Source module: ProofsInTheBook.ZinanFFCT28 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT26 ProofsInTheBook.ZinanFFCT27
open ProofsInTheBook.SphericalStuckGeneral ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalMonitoredSup ProofsInTheBook.SphericalSZFinal

namespace ProofsInTheBook.ZinanFFCT28

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



































end ProofsInTheBook.ZinanFFCT28

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalOpeningOutcome
-/
/- Source module: ProofsInTheBook.SphericalOpeningGlue -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalDiagCut
open ProofsInTheBook.SphericalSZChain
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalOpeningOutcome

namespace ProofsInTheBook.SphericalOpeningGlue

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

































end ProofsInTheBook.SphericalOpeningGlue

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT28
import ProofsInTheBook.SphericalOpeningGlue
-/
/- Source module: ProofsInTheBook.ZinanFFCT30 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalMonitoredSup ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalOpeningGlue

namespace ProofsInTheBook.ZinanFFCT30

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

























end ProofsInTheBook.ZinanFFCT30

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT30
import ProofsInTheBook.ZinanFFCT22
-/
/- Source module: ProofsInTheBook.ZinanFFCT33 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT30

namespace ProofsInTheBook.ZinanFFCT33

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

















/-- The equator index set of the opened arm: vertices pushed onto the `h₀`-equator. -/
def equatorSet {n : ℕ} (A : Fin (n + 1) → S2) (K : Fin (n + 1)) (h₀ : E3) (δ : ℝ) :
    Fin (n + 1) → Prop :=
  fun r => (⟪h₀, ((openTail A K δ r : S2) : E3)⟫ : ℝ) = 0

instance equatorSet_decidable {n : ℕ} (A : Fin (n + 1) → S2) (K : Fin (n + 1)) (h₀ : E3) (δ : ℝ) :
    DecidablePred (equatorSet A K h₀ δ) := fun _ => Classical.dec _













end ProofsInTheBook.ZinanFFCT33
end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT33
-/
/- Source module: ProofsInTheBook.ZinanFFCT34 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT30 ProofsInTheBook.ZinanFFCT33

namespace ProofsInTheBook.ZinanFFCT34

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





















end ProofsInTheBook.ZinanFFCT34

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT34
import Mathlib.Analysis.LocallyConvex.Separation
import Mathlib.Analysis.InnerProductSpace.Dual
import Mathlib.Analysis.Convex.Topology
import Mathlib.Analysis.Convex.Combination
-/
/- Source module: ProofsInTheBook.ZinanFFCT36 -/
section
set_option autoImplicit true


noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT30
open ProofsInTheBook.ZinanFFCT33 ProofsInTheBook.ZinanFFCT34

namespace ProofsInTheBook.ZinanFFCT36

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000
























end ProofsInTheBook.ZinanFFCT36
end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT36
-/
/- Source module: ProofsInTheBook.ZinanFFCT44 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.ZinanFFCT21 ProofsInTheBook.ZinanFFCT22
open ProofsInTheBook.ZinanFFCT25 ProofsInTheBook.ZinanFFCT30
open ProofsInTheBook.ZinanFFCT36

namespace ProofsInTheBook.ZinanFFCT44

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





































end ProofsInTheBook.ZinanFFCT44

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT20
import ProofsInTheBook.ZinanFFCT3
import ProofsInTheBook.SphericalOpeningGlue
-/
/- Source module: ProofsInTheBook.ZinanFFCT37 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalOpeningGlue
open ProofsInTheBook.ZinanFFCT20
open ProofsInTheBook.ZinanFFCT3

namespace ProofsInTheBook.ZinanFFCT37

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





































































end ProofsInTheBook.ZinanFFCT37

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT37
import ProofsInTheBook.ZinanFFCT36
-/
/- Source module: ProofsInTheBook.ZinanFFCT38 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalSpliceTransport
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalOpeningGlue
open ProofsInTheBook.ZinanFFCT30
open ProofsInTheBook.ZinanFFCT36
open ProofsInTheBook.ZinanFFCT37

namespace ProofsInTheBook.ZinanFFCT38

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



















































end ProofsInTheBook.ZinanFFCT38






end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT38
-/
/- Source module: ProofsInTheBook.ZinanFFCT39 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningGlue
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.ZinanFFCT37
open ProofsInTheBook.ZinanFFCT38

namespace ProofsInTheBook.ZinanFFCT39

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000













































end ProofsInTheBook.ZinanFFCT39

-- Brick 1 (positive content + assembly + audit)





-- Brick 2 (audit + positive content)




end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT39
-/
/- Source module: ProofsInTheBook.ZinanFFCT40 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalSpliceTransport
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalOpeningGlue
open ProofsInTheBook.SphericalDiagCut
open ProofsInTheBook.ZinanFFCT30
open ProofsInTheBook.ZinanFFCT36
open ProofsInTheBook.ZinanFFCT37
open ProofsInTheBook.ZinanFFCT38
open ProofsInTheBook.ZinanFFCT39

namespace ProofsInTheBook.ZinanFFCT40

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000























































end ProofsInTheBook.ZinanFFCT40

-- §1 the any-h assembler

-- §3 the pure-hemi strict certificate + repaired stuck outcome + repaired clause (iii)



-- §3 the corrected outcome + repaired headline



-- refutation-resistance witnesses


end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT40
-/
/- Source module: ProofsInTheBook.ZinanFFCT41 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSZChain
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalSpliceTransport
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalOpeningGlue
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT20
open ProofsInTheBook.ZinanFFCT30
open ProofsInTheBook.ZinanFFCT36
open ProofsInTheBook.ZinanFFCT37
open ProofsInTheBook.ZinanFFCT38
open ProofsInTheBook.ZinanFFCT39
open ProofsInTheBook.ZinanFFCT40

namespace ProofsInTheBook.ZinanFFCT41

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000







































































































end ProofsInTheBook.ZinanFFCT41

-- §1 the WB family + W-admissibility bridge

-- §2 the base sinusoid

-- §3 the cap by admissibility (the central new content)


-- §5 the WB trichotomy

-- §6/§7 the clauses at the WB sup



-- §8/§9 the base-capped outcome + headline (GlueWBaseCap discharged)


-- refutation-resistance witness


end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT41
-/
/- Source module: ProofsInTheBook.ZinanFFCT42 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalSpliceTransport
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.ZinanFFCT41

namespace ProofsInTheBook.ZinanFFCT42

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000































end ProofsInTheBook.ZinanFFCT42

-- §1 the algebra/index micro-lemmas


-- §2 base-stuck = opened diagonal

-- §3 Brick 1 (the cyclic-identity bridge) + the vanishing-support payload


-- §4 the residual DISCHARGED + the base-stuck-free headline


-- non-vacuity guards


end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT42
-/
/- Source module: ProofsInTheBook.ZinanFFCT45 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalOpeningGlue
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT20
open ProofsInTheBook.ZinanFFCT37
open ProofsInTheBook.ZinanFFCT41
open ProofsInTheBook.ZinanFFCT42

namespace ProofsInTheBook.ZinanFFCT45

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



































































end ProofsInTheBook.ZinanFFCT45

-- §1 the WBS family + closure facts





-- §2 init admissibility

-- §3 deficit bound + base cap



-- §4 the trichotomy + clauses



-- §5 Brick 7: the FFCT42 base-stuck port DISCHARGED



end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT42
-/
/- Source module: ProofsInTheBook.ZinanFFCT43 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalSpliceTransport
open ProofsInTheBook.ZinanFFCT39
open ProofsInTheBook.ZinanFFCT41
open ProofsInTheBook.ZinanFFCT42

namespace ProofsInTheBook.ZinanFFCT43

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





















end ProofsInTheBook.ZinanFFCT43

-- §1 endpoint positivity

-- §2 closing edge distinct at the WB supremum

-- §3 the residual DISCHARGED + the closing-edge-free headline


-- non-vacuity guards


end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT44
import ProofsInTheBook.ZinanFFCT45
import ProofsInTheBook.ZinanFFCT43
-/
/- Source module: ProofsInTheBook.ZinanFFCT46 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalSpliceTransport
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalOpeningGlue
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT34
open ProofsInTheBook.ZinanFFCT36
open ProofsInTheBook.ZinanFFCT37
open ProofsInTheBook.ZinanFFCT40
open ProofsInTheBook.ZinanFFCT42
open ProofsInTheBook.ZinanFFCT43
open ProofsInTheBook.ZinanFFCT44
open ProofsInTheBook.ZinanFFCT45

namespace ProofsInTheBook.ZinanFFCT46

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

















































end ProofsInTheBook.ZinanFFCT46

-- §1 the margins-free open-hemisphere production (THE keystone mechanism)

-- §2 brick 4

-- §2′ the opened side / joint geometry



-- §3 bricks 5–6


-- §4 brick 8

-- §5 brick 9 + non-vacuity



end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT46
-/
/- Source module: ProofsInTheBook.ZinanFFCT47 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalSpliceTransport
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.ZinanFFCT21 ProofsInTheBook.ZinanFFCT22
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT36
open ProofsInTheBook.ZinanFFCT42
open ProofsInTheBook.ZinanFFCT43
open ProofsInTheBook.ZinanFFCT44
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46

namespace ProofsInTheBook.ZinanFFCT47

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



























































end ProofsInTheBook.ZinanFFCT47

-- §1 the open-chain collapse kernel (3 ≤ n)

-- §2 the wrap-edge-free open-hemisphere production

-- §3 wrap ShortArc from the hemisphere

-- §4 the residual discharged


-- §5 the wrap-free headline



end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT47
import ProofsInTheBook.ZinanFFCT28
import ProofsInTheBook.SphericalStuckGeneral
-/
/- Source module: ProofsInTheBook.ZinanFFCT49 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT28
open ProofsInTheBook.ZinanFFCT37
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47

namespace ProofsInTheBook.ZinanFFCT49

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000









































end ProofsInTheBook.ZinanFFCT49

-- §0 the opened arm

-- §2 discharged pieces



-- §4 the bridge

-- §5 non-vacuity guards



end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT49
import ProofsInTheBook.ZinanFFCT23
-/
/- Source module: ProofsInTheBook.ZinanFFCT52 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT49

namespace ProofsInTheBook.ZinanFFCT52

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000









































































end ProofsInTheBook.ZinanFFCT52

-- §1 component 2


-- §2 reversal infra




-- §3 orientation normalization

-- §4 interval convexity


-- §5 assembly


end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT19
import ProofsInTheBook.ZinanFFCT46
import ProofsInTheBook.ZinanFFCT47
-/
/- Source module: ProofsInTheBook.ZinanFFCT48 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47

namespace ProofsInTheBook.ZinanFFCT48

set_option maxHeartbeats 1600000



























end ProofsInTheBook.ZinanFFCT48




end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT25
import ProofsInTheBook.ZinanFFCT48
-/
/- Source module: ProofsInTheBook.ZinanFFCT53 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT23 ProofsInTheBook.ZinanFFCT25

namespace ProofsInTheBook.ZinanFFCT53

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000


















































end ProofsInTheBook.ZinanFFCT53

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT52
import ProofsInTheBook.ZinanFFCT53
-/
/- Source module: ProofsInTheBook.ZinanFFCT54 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT21 ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT52 ProofsInTheBook.ZinanFFCT53

namespace ProofsInTheBook.ZinanFFCT54

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

















































































end ProofsInTheBook.ZinanFFCT54

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT54
-/
/- Source module: ProofsInTheBook.ZinanFFCT63 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT53
open ProofsInTheBook.ZinanFFCT54

namespace ProofsInTheBook.ZinanFFCT63

set_option maxHeartbeats 1600000




















































end ProofsInTheBook.ZinanFFCT63

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT28
-/
/- Source module: ProofsInTheBook.ZinanFFCT29 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalSZ
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.ZinanFFCT10 ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT26 ProofsInTheBook.ZinanFFCT27
open ProofsInTheBook.ZinanFFCT28

namespace ProofsInTheBook.ZinanFFCT29

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





















































end ProofsInTheBook.ZinanFFCT29

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT29
-/
/- Source module: ProofsInTheBook.ZinanFFCT31 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT3 ProofsInTheBook.ZinanFFCT9 ProofsInTheBook.ZinanFFCT10
open ProofsInTheBook.ZinanFFCT12 ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT21
open ProofsInTheBook.ZinanFFCT22 ProofsInTheBook.ZinanFFCT23 ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT25 ProofsInTheBook.ZinanFFCT27 ProofsInTheBook.ZinanFFCT29

namespace ProofsInTheBook.ZinanFFCT31

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000
























































end ProofsInTheBook.ZinanFFCT31

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT31
-/
/- Source module: ProofsInTheBook.ZinanFFCT32 -/
section
set_option autoImplicit true




noncomputable section
open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT3 ProofsInTheBook.ZinanFFCT9 ProofsInTheBook.ZinanFFCT10
open ProofsInTheBook.ZinanFFCT12 ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT21
open ProofsInTheBook.ZinanFFCT22 ProofsInTheBook.ZinanFFCT23 ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT25 ProofsInTheBook.ZinanFFCT27 ProofsInTheBook.ZinanFFCT29
open ProofsInTheBook.ZinanFFCT31

namespace ProofsInTheBook.ZinanFFCT32

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000















































end ProofsInTheBook.ZinanFFCT32

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT49
import ProofsInTheBook.ZinanFFCT32
-/
/- Source module: ProofsInTheBook.ZinanFFCT51 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.ZinanFFCT3 ProofsInTheBook.ZinanFFCT18 ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT27 ProofsInTheBook.ZinanFFCT29 ProofsInTheBook.ZinanFFCT31
open ProofsInTheBook.ZinanFFCT32
open ProofsInTheBook.ZinanFFCT45 ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT49

namespace ProofsInTheBook.ZinanFFCT51

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





























end ProofsInTheBook.ZinanFFCT51

-- §1 the sharp residue

-- §2 the corner sign verification

-- §3 the main near-side line


-- §4 non-vacuity guards



end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT51
-/
/- Source module: ProofsInTheBook.ZinanFFCT55 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.ZinanFFCT26 ProofsInTheBook.ZinanFFCT27
open ProofsInTheBook.ZinanFFCT29
open ProofsInTheBook.ZinanFFCT45 ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT51

namespace ProofsInTheBook.ZinanFFCT55

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000









































end ProofsInTheBook.ZinanFFCT55

-- §R1/R2 the constant-binding contradiction at the WBS family


-- §δ*=0 edge

-- §R3 slot normalization

-- §R4 the derivative + the sign finding



-- §R4′ the forced collapse

-- §5 non-vacuity guards



end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT21
import ProofsInTheBook.ZinanFFCT55
-/
/- Source module: ProofsInTheBook.ZinanFFCT56 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT21
open ProofsInTheBook.ZinanFFCT45 ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT55

namespace ProofsInTheBook.ZinanFFCT56

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000







































end ProofsInTheBook.ZinanFFCT56

-- §A the coefficient bricks


-- §B the master mid-fold kill


-- §C the WBS axis-edge elimination

-- §D the honest dispatch + residue

-- §E the consequence wiring

-- §F non-vacuity guards




end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT48
import ProofsInTheBook.ZinanFFCT56
-/
/- Source module: ProofsInTheBook.ZinanFFCT57 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalSpliceTransport
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT48
open ProofsInTheBook.ZinanFFCT56

namespace ProofsInTheBook.ZinanFFCT57

set_option maxHeartbeats 1600000



































end ProofsInTheBook.ZinanFFCT57









end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT10
import ProofsInTheBook.SphericalSpliceTransport
import ProofsInTheBook.ZinanFFCT48
import ProofsInTheBook.ZinanFFCT57
-/
/- Source module: ProofsInTheBook.ZinanFFCT58 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalSpliceTransport
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT10
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT48
open ProofsInTheBook.ZinanFFCT57

namespace ProofsInTheBook.ZinanFFCT58

set_option maxHeartbeats 1600000
set_option linter.unnecessarySeqFocus false























































































end ProofsInTheBook.ZinanFFCT58







end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT58
-/
/- Source module: ProofsInTheBook.ZinanFFCT59 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT48
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT57
open ProofsInTheBook.ZinanFFCT58

namespace ProofsInTheBook.ZinanFFCT59

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



































end ProofsInTheBook.ZinanFFCT59









end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT54
import ProofsInTheBook.ZinanFFCT59
-/
/- Source module: ProofsInTheBook.ZinanFFCT60 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT21
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT53
open ProofsInTheBook.ZinanFFCT54
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT59

namespace ProofsInTheBook.ZinanFFCT60

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000


























end ProofsInTheBook.ZinanFFCT60

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT60
import ProofsInTheBook.SphericalRotation
-/
/- Source module: ProofsInTheBook.ZinanFFCT61 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT21
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT53
open ProofsInTheBook.ZinanFFCT54
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT59
open ProofsInTheBook.ZinanFFCT60

namespace ProofsInTheBook.ZinanFFCT61

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000


































































































end ProofsInTheBook.ZinanFFCT61

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT61
-/
/- Source module: ProofsInTheBook.ZinanFFCT62 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT48
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT53
open ProofsInTheBook.ZinanFFCT54
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT57
open ProofsInTheBook.ZinanFFCT58
open ProofsInTheBook.ZinanFFCT59
open ProofsInTheBook.ZinanFFCT61

namespace ProofsInTheBook.ZinanFFCT62

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





















































end ProofsInTheBook.ZinanFFCT62

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT62
-/
/- Source module: ProofsInTheBook.ZinanFFCT64 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT53
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT57
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT62

namespace ProofsInTheBook.ZinanFFCT64

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





































end ProofsInTheBook.ZinanFFCT64

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT63
import ProofsInTheBook.ZinanFFCT64
-/
/- Source module: ProofsInTheBook.ZinanFFCT65 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalCore ProofsInTheBook.SphericalFinish
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT53
open ProofsInTheBook.ZinanFFCT54
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT59
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT62
open ProofsInTheBook.ZinanFFCT63
open ProofsInTheBook.ZinanFFCT64

namespace ProofsInTheBook.ZinanFFCT65

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000



































































end ProofsInTheBook.ZinanFFCT65

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT65
import ProofsInTheBook.PlanarConvexDiag
-/
/- Source module: ProofsInTheBook.ZinanFFCT66 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT21
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT53
open ProofsInTheBook.ZinanFFCT54
open ProofsInTheBook.ZinanFFCT63
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65

namespace ProofsInTheBook.ZinanFFCT66

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000












































end ProofsInTheBook.ZinanFFCT66

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT66
-/
/- Source module: ProofsInTheBook.ZinanFFCT67 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT66

namespace ProofsInTheBook.ZinanFFCT67

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

















end ProofsInTheBook.ZinanFFCT67

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT67
import ProofsInTheBook.ZinanFFCT26
-/
/- Source module: ProofsInTheBook.ZinanFFCT68 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT26
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT53
open ProofsInTheBook.ZinanFFCT54
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT66
open ProofsInTheBook.ZinanFFCT67

namespace ProofsInTheBook.ZinanFFCT68

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000









































end ProofsInTheBook.ZinanFFCT68

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT68
-/
/- Source module: ProofsInTheBook.ZinanFFCT69 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT62
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT67
open ProofsInTheBook.ZinanFFCT68

namespace ProofsInTheBook.ZinanFFCT69

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000




































end ProofsInTheBook.ZinanFFCT69

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT69
import ProofsInTheBook.ZinanFFCT32
-/
/- Source module: ProofsInTheBook.ZinanFFCT70 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT31
open ProofsInTheBook.ZinanFFCT32
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT69

namespace ProofsInTheBook.ZinanFFCT70

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000




























end ProofsInTheBook.ZinanFFCT70

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT70
-/
/- Source module: ProofsInTheBook.ZinanFFCT71 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT66
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT69
open ProofsInTheBook.ZinanFFCT70

namespace ProofsInTheBook.ZinanFFCT71

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000






























end ProofsInTheBook.ZinanFFCT71

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT71
-/
/- Source module: ProofsInTheBook.ZinanFFCT72 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT48
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT57
open ProofsInTheBook.ZinanFFCT58
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT66
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT69
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT71

namespace ProofsInTheBook.ZinanFFCT72

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000








































end ProofsInTheBook.ZinanFFCT72

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT72
-/
/- Source module: ProofsInTheBook.ZinanFFCT73 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT48
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT53
open ProofsInTheBook.ZinanFFCT54
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT57
open ProofsInTheBook.ZinanFFCT58
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT66
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT69
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT71
open ProofsInTheBook.ZinanFFCT72

namespace ProofsInTheBook.ZinanFFCT73

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000










































end ProofsInTheBook.ZinanFFCT73

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT73
-/
/- Source module: ProofsInTheBook.ZinanFFCT74 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT48
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT53
open ProofsInTheBook.ZinanFFCT54
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT57
open ProofsInTheBook.ZinanFFCT58
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT66
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT69
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT71
open ProofsInTheBook.ZinanFFCT73

namespace ProofsInTheBook.ZinanFFCT74

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000







































































end ProofsInTheBook.ZinanFFCT74

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT74
-/
/- Source module: ProofsInTheBook.ZinanFFCT75 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT71
open ProofsInTheBook.ZinanFFCT74

namespace ProofsInTheBook.ZinanFFCT75

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000






















end ProofsInTheBook.ZinanFFCT75

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT75
import ProofsInTheBook.ZinanFFCT44
-/
/- Source module: ProofsInTheBook.ZinanFFCT76 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT21
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT44
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT71
open ProofsInTheBook.ZinanFFCT74
open ProofsInTheBook.ZinanFFCT75

namespace ProofsInTheBook.ZinanFFCT76

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





















end ProofsInTheBook.ZinanFFCT76

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT76
-/
/- Source module: ProofsInTheBook.ZinanFFCT77 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT48
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT57
open ProofsInTheBook.ZinanFFCT58
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT66
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT69
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT71
open ProofsInTheBook.ZinanFFCT74
open ProofsInTheBook.ZinanFFCT76

namespace ProofsInTheBook.ZinanFFCT77

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000


































































end ProofsInTheBook.ZinanFFCT77

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT77
-/
/- Source module: ProofsInTheBook.ZinanFFCT78 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT19
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT71
open ProofsInTheBook.ZinanFFCT74
open ProofsInTheBook.ZinanFFCT75
open ProofsInTheBook.ZinanFFCT76
open ProofsInTheBook.ZinanFFCT77

namespace ProofsInTheBook.ZinanFFCT78

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000















end ProofsInTheBook.ZinanFFCT78

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT78
-/
/- Source module: ProofsInTheBook.ZinanFFCT79 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT76
open ProofsInTheBook.ZinanFFCT77
open ProofsInTheBook.ZinanFFCT78

namespace ProofsInTheBook.ZinanFFCT79

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000





















end ProofsInTheBook.ZinanFFCT79

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT79
-/
/- Source module: ProofsInTheBook.ZinanFFCT80 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT48
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT75
open ProofsInTheBook.ZinanFFCT76
open ProofsInTheBook.ZinanFFCT77
open ProofsInTheBook.ZinanFFCT78
open ProofsInTheBook.ZinanFFCT79

namespace ProofsInTheBook.ZinanFFCT80

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000







































































end ProofsInTheBook.ZinanFFCT80

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT80
-/
/- Source module: ProofsInTheBook.ZinanFFCT81 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT74
open ProofsInTheBook.ZinanFFCT76
open ProofsInTheBook.ZinanFFCT77
open ProofsInTheBook.ZinanFFCT78
open ProofsInTheBook.ZinanFFCT79
open ProofsInTheBook.ZinanFFCT80

namespace ProofsInTheBook.ZinanFFCT81

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000










































end ProofsInTheBook.ZinanFFCT81

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT81
-/
/- Source module: ProofsInTheBook.ZinanFFCT82 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT74
open ProofsInTheBook.ZinanFFCT76
open ProofsInTheBook.ZinanFFCT77
open ProofsInTheBook.ZinanFFCT78
open ProofsInTheBook.ZinanFFCT79
open ProofsInTheBook.ZinanFFCT80
open ProofsInTheBook.ZinanFFCT81

namespace ProofsInTheBook.ZinanFFCT82

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000


































end ProofsInTheBook.ZinanFFCT82

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT82
-/
/- Source module: ProofsInTheBook.ZinanFFCT83 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT22
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT74
open ProofsInTheBook.ZinanFFCT76
open ProofsInTheBook.ZinanFFCT77
open ProofsInTheBook.ZinanFFCT78
open ProofsInTheBook.ZinanFFCT79
open ProofsInTheBook.ZinanFFCT80
open ProofsInTheBook.ZinanFFCT81
open ProofsInTheBook.ZinanFFCT82

namespace ProofsInTheBook.ZinanFFCT83

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000







































end ProofsInTheBook.ZinanFFCT83

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT83
-/
/- Source module: ProofsInTheBook.ZinanFFCT84 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT22
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT74
open ProofsInTheBook.ZinanFFCT76
open ProofsInTheBook.ZinanFFCT77
open ProofsInTheBook.ZinanFFCT78
open ProofsInTheBook.ZinanFFCT79
open ProofsInTheBook.ZinanFFCT80
open ProofsInTheBook.ZinanFFCT81
open ProofsInTheBook.ZinanFFCT82
open ProofsInTheBook.ZinanFFCT83

namespace ProofsInTheBook.ZinanFFCT84

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1600000

















end ProofsInTheBook.ZinanFFCT84

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT84
-/
/- Source module: ProofsInTheBook.ZinanFFCT85 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT22
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT69
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT71
open ProofsInTheBook.ZinanFFCT74
open ProofsInTheBook.ZinanFFCT75
open ProofsInTheBook.ZinanFFCT76
open ProofsInTheBook.ZinanFFCT77
open ProofsInTheBook.ZinanFFCT78
open ProofsInTheBook.ZinanFFCT79
open ProofsInTheBook.ZinanFFCT80
open ProofsInTheBook.ZinanFFCT81
open ProofsInTheBook.ZinanFFCT82
open ProofsInTheBook.ZinanFFCT83
open ProofsInTheBook.ZinanFFCT84

namespace ProofsInTheBook.ZinanFFCT85

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1800000









































end ProofsInTheBook.ZinanFFCT85

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT85
-/
/- Source module: ProofsInTheBook.ZinanFFCT86 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT22
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT69
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT71
open ProofsInTheBook.ZinanFFCT74
open ProofsInTheBook.ZinanFFCT75
open ProofsInTheBook.ZinanFFCT76
open ProofsInTheBook.ZinanFFCT77
open ProofsInTheBook.ZinanFFCT78
open ProofsInTheBook.ZinanFFCT79
open ProofsInTheBook.ZinanFFCT80
open ProofsInTheBook.ZinanFFCT81
open ProofsInTheBook.ZinanFFCT82
open ProofsInTheBook.ZinanFFCT83
open ProofsInTheBook.ZinanFFCT84
open ProofsInTheBook.ZinanFFCT85

namespace ProofsInTheBook.ZinanFFCT86

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1800000








































end ProofsInTheBook.ZinanFFCT86

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT86
-/
/- Source module: ProofsInTheBook.ZinanFFCT100 -/
section
set_option autoImplicit true




open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT78
open ProofsInTheBook.ZinanFFCT86

namespace ProofsInTheBook.ZinanFFCT100







end ProofsInTheBook.ZinanFFCT100




end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanFFCT100
-/
/- Source module: ProofsInTheBook.ZinanFFCT111 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation
open ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZStepClose
open ProofsInTheBook.SphericalSZFinal
open ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalArmAssembly
open ProofsInTheBook.SphericalMonitoredSup
open ProofsInTheBook.SphericalOpeningOutcome
open ProofsInTheBook.SphericalReachStuck
open ProofsInTheBook.SphericalStuckGeneral
open ProofsInTheBook.SphericalCutTransport
open ProofsInTheBook.PlanarConvexDiag
open ProofsInTheBook.SphericalCyclicTriple
open ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalDiagCut
open ProofsInTheBook.SphericalGnomonic
open ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.ZinanFFCT3
open ProofsInTheBook.ZinanFFCT20
open ProofsInTheBook.ZinanFFCT37
open ProofsInTheBook.ZinanFFCT12
open ProofsInTheBook.ZinanFFCT18
open ProofsInTheBook.ZinanFFCT22
open ProofsInTheBook.ZinanFFCT23
open ProofsInTheBook.ZinanFFCT24
open ProofsInTheBook.ZinanFFCT25
open ProofsInTheBook.ZinanFFCT45
open ProofsInTheBook.ZinanFFCT46
open ProofsInTheBook.ZinanFFCT47
open ProofsInTheBook.ZinanFFCT49
open ProofsInTheBook.ZinanFFCT52
open ProofsInTheBook.ZinanFFCT56
open ProofsInTheBook.ZinanFFCT61
open ProofsInTheBook.ZinanFFCT64
open ProofsInTheBook.ZinanFFCT65
open ProofsInTheBook.ZinanFFCT66
open ProofsInTheBook.ZinanFFCT68
open ProofsInTheBook.ZinanFFCT69
open ProofsInTheBook.ZinanFFCT70
open ProofsInTheBook.ZinanFFCT71
open ProofsInTheBook.ZinanFFCT74
open ProofsInTheBook.ZinanFFCT75
open ProofsInTheBook.ZinanFFCT76
open ProofsInTheBook.ZinanFFCT77
open ProofsInTheBook.ZinanFFCT78
open ProofsInTheBook.ZinanFFCT79
open ProofsInTheBook.ZinanFFCT80
open ProofsInTheBook.ZinanFFCT81
open ProofsInTheBook.ZinanFFCT82
open ProofsInTheBook.ZinanFFCT83
open ProofsInTheBook.ZinanFFCT84
open ProofsInTheBook.ZinanFFCT85
open ProofsInTheBook.ZinanFFCT86
open ProofsInTheBook.ZinanFFCT100

namespace ProofsInTheBook.ZinanFFCT111

set_option synthInstance.maxHeartbeats 400000
set_option maxHeartbeats 1800000













































































end ProofsInTheBook.ZinanFFCT111

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalReachStuck
import ProofsInTheBook.SphericalSZFinal
import ProofsInTheBook.SphericalSZClose
import ProofsInTheBook.ZinanFFCT111
-/
/- Source module: ProofsInTheBook.ZinanFFCT113 -/
section
set_option autoImplicit true




noncomputable section

open scoped RealInnerProductSpace NNReal
open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalRotation ProofsInTheBook.SphericalCore
open ProofsInTheBook.SphericalHinge ProofsInTheBook.SphericalHingeCut
open ProofsInTheBook.SphericalFinish ProofsInTheBook.SphericalSZStep
open ProofsInTheBook.SphericalReachStuck ProofsInTheBook.SphericalSZInduction
open ProofsInTheBook.SphericalSZFinal ProofsInTheBook.SphericalSZClose
open ProofsInTheBook.SphericalMonitoredSup ProofsInTheBook.SphericalOpeningProcess
open ProofsInTheBook.ZinanFFCT78 ProofsInTheBook.ZinanFFCT111

namespace ProofsInTheBook.ZinanFFCT113

set_option maxHeartbeats 1600000































end ProofsInTheBook.ZinanFFCT113

end
end

/- Original source header (imports hoisted):
import ProofsInTheBook.SphericalOpenedArmCore
import ProofsInTheBook.ZinanFFCT111
import ProofsInTheBook.ZinanFFCT113
-/
/- Source module: ProofsInTheBook.ZinanFFCT112 -/
section
set_option autoImplicit true




namespace ProofsInTheBook.ZinanFFCT112

open ProofsInTheBook.SphericalKernel
open ProofsInTheBook.SphericalArm
open ProofsInTheBook.SphericalOpenedArmCore












end ProofsInTheBook.ZinanFFCT112




end

/- Original source header (imports hoisted):
import Mathlib
import ProofsInTheBook.ZinanFFCT112
-/
/- Source module: ProofsInTheBook.Chapter13 -/
section
set_option autoImplicit true




namespace ProofsInTheBook.Chapter13

open ProofsInTheBook.SphericalKernel ProofsInTheBook.SphericalArm

/-- Edge signs in Cauchy's rigidity proof. -/
inductive EdgeSign where
  | plus | minus | zero
  deriving DecidableEq, Repr

open EdgeSign

/-- The nonzero signs left after Cauchy's proof discards unchanged edges. -/
inductive StrictEdgeSign where
  | plus | minus
  deriving DecidableEq, Repr





















namespace StrictTriangleSigns





end StrictTriangleSigns

















namespace CauchyArmOpeningObstruction



end CauchyArmOpeningObstruction



namespace CauchyArmClosingObstruction



end CauchyArmClosingObstruction



namespace CauchyArmFixedChordObstruction



end CauchyArmFixedChordObstruction

















namespace CauchyArmVertex







end CauchyArmVertex



namespace CauchyRigidityCertificate







end CauchyRigidityCertificate











end ProofsInTheBook.Chapter13

end

/- Original source header (imports hoisted):
import Mathlib
import ProofsInTheBook.Chapter13
-/
/- Source module: ProofsInTheBook.Ch13CyclicSigns -/
section
set_option autoImplicit true




namespace ProofsInTheBook.Ch13CyclicSigns

open ProofsInTheBook.Chapter13
open EdgeSign



variable {α : Type*} [DecidableEq α]

























end ProofsInTheBook.Ch13CyclicSigns

end

/- Original source header (imports hoisted):
import Mathlib
import ProofsInTheBook.PlanarMap
import ProofsInTheBook.Chapter13
import ProofsInTheBook.Ch13CyclicSigns
-/
/- Source module: ProofsInTheBook.Ch13MarkedSphere -/
section
set_option autoImplicit true




namespace ProofsInTheBook.Ch13MarkedSphere

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.Chapter13
open ProofsInTheBook.Ch13CyclicSigns

variable {D : Type*} [Fintype D] [DecidableEq D]



























































/-- Edge involution of the tetrahedron map: the six transpositions pairing each dart
with its reverse. -/
def tetraAlpha : Equiv.Perm (Fin 12) :=
  (List.formPerm [0, 3]) * (List.formPerm [1, 6]) * (List.formPerm [2, 9]) *
    (List.formPerm [4, 7]) * (List.formPerm [5, 10]) * (List.formPerm [8, 11])

/-- Vertex rotation of the tetrahedron map: the four `3`-cycles rotating the darts
around each of the four vertices. -/
def tetraSigma : Equiv.Perm (Fin 12) :=
  (List.formPerm [0, 1, 2]) * (List.formPerm [3, 5, 4]) *
    (List.formPerm [6, 7, 8]) * (List.formPerm [9, 11, 10])

/-- The tetrahedron as a combinatorial map on `Fin 12`. -/
def tetraMap : CombMap (Fin 12) where
  α := tetraAlpha
  σ := tetraSigma
  α_invol := by decide
  α_no_fixed := by decide





noncomputable instance : DecidableEq (Quotient (cycleSetoid tetraMap.φ)) :=
  Quotient.decidableEq























end ProofsInTheBook.Ch13MarkedSphere

end

/- Original source header (imports hoisted):
import Mathlib
import ProofsInTheBook.PlanarMap
import ProofsInTheBook.Chapter13
import ProofsInTheBook.Ch13CyclicSigns
import ProofsInTheBook.Ch13MarkedSphere
-/
/- Source module: ProofsInTheBook.Ch13MarkedReduction -/
section
set_option autoImplicit true




namespace ProofsInTheBook.Ch13MarkedReduction

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.Chapter13
open ProofsInTheBook.Ch13CyclicSigns
open ProofsInTheBook.Ch13MarkedSphere
open EdgeSign
open Equiv Equiv.Perm



section ListBridge

variable {α : Type*} [DecidableEq α]







end ListBridge



section OrbitBridge

variable {α : Type*} [DecidableEq α] [Fintype α] {β : Type*} [DecidableEq β]









end OrbitBridge



section StrictBridge

variable {D : Type*} [Fintype D] [DecidableEq D]











end StrictBridge



section ActiveComponent

variable {D : Type*} [Fintype D] [DecidableEq D]

/-- The degree of a face (`φ`-orbit): the number of darts on its boundary walk. -/
def faceDeg (M : CombMap D) (Q : Quotient (cycleSetoid M.φ)) : ℕ :=
  (Finset.univ.filter (fun x => Quotient.mk (cycleSetoid M.φ) x = Q)).card











end ActiveComponent



section Obstruction
































end Obstruction

end ProofsInTheBook.Ch13MarkedReduction

end

/- Original source header (imports hoisted):
import Mathlib
import ProofsInTheBook.PlanarMap
import ProofsInTheBook.PlanarMapSimple
import ProofsInTheBook.PlanarMapDelete
import ProofsInTheBook.SubmapPlanar
import ProofsInTheBook.Chapter13
import ProofsInTheBook.Ch13CyclicSigns
import ProofsInTheBook.Ch13MarkedSphere
import ProofsInTheBook.Ch13MarkedReduction
-/
/- Source module: ProofsInTheBook.Ch13ActiveComponent -/
section
set_option autoImplicit true




namespace ProofsInTheBook.Ch13ActiveComponent

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.Chapter13
open ProofsInTheBook.Ch13CyclicSigns
open ProofsInTheBook.Ch13MarkedSphere
open ProofsInTheBook.Ch13MarkedReduction
open EdgeSign

variable {D : Type*} [Fintype D] [DecidableEq D]

















open ProofsInTheBook.SubmapPlanar

/-- The kept (active sub-)combinatorial map on the surviving darts `{d ∉ Del}`. -/
noncomputable def keptMap (M : CombMap D) (Del : Finset D)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del) : CombMap {d : D // d ∉ Del} where
  α := keptAlpha M Del hsub
  σ := Equiv.Perm.deleteSet M.σ Del
  α_invol := keptAlpha_invol M Del hsub
  α_no_fixed := by
    intro d hd
    apply M.α_no_fixed d.1
    have := congrArg Subtype.val hd
    rwa [keptAlpha_apply_coe] at this



@[simp] theorem keptMap_alpha (M : CombMap D) (Del : Finset D)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del) :
    (keptMap M Del hsub).α = keptAlpha M Del hsub := rfl

/-- **Euler char of the kept map is `2` when it is connected** (genus-0 certificate from
`SubmapPlanar.keptMap_eulerChar_eq_two`): the active sub-map of a sphere has no handle. -/
theorem keptMap_eulerChar_eq_two_of_connected (M : CombMap D) (Del : Finset D)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del)
    (hclosed : ∀ d, d ∈ Del → M.α d ∈ Del) (hsphere : M.IsSphereMap)
    (d : {d : D // d ∉ Del}) (hconn : (keptMap M Del hsub).Connected) :
    (keptMap M Del hsub).eulerChar = 2 :=
  ProofsInTheBook.SubmapPlanar.keptMap_eulerChar_eq_two M Del hsub hclosed hsphere
    (keptMap M Del hsub) rfl rfl d hconn

/-- Euler identity form `(V:ℤ) - E + F = 2` for the connected kept map. -/
theorem keptMap_euler_VEF (M : CombMap D) (Del : Finset D)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del)
    (hclosed : ∀ d, d ∈ Del → M.α d ∈ Del) (hsphere : M.IsSphereMap)
    (d : {d : D // d ∉ Del}) (hconn : (keptMap M Del hsub).Connected) :
    ((keptMap M Del hsub).V : ℤ) - (keptMap M Del hsub).E + (keptMap M Del hsub).F = 2 := by
  have h := keptMap_eulerChar_eq_two_of_connected M Del hsub hclosed hsphere d hconn
  rwa [CombMap.eulerChar] at h



  -- unreachable on active darts























end ProofsInTheBook.Ch13ActiveComponent

end

/- Original source header (imports hoisted):
import Mathlib
import ProofsInTheBook.PlanarMap
import ProofsInTheBook.PlanarMapSimple
import ProofsInTheBook.PlanarMapDelete
import ProofsInTheBook.SubmapPlanar
import ProofsInTheBook.Chapter13
import ProofsInTheBook.Ch13CyclicSigns
import ProofsInTheBook.Ch13MarkedSphere
import ProofsInTheBook.Ch13MarkedReduction
import ProofsInTheBook.Ch13ActiveComponent
-/
/- Source module: ProofsInTheBook.Ch13FlipTransport -/
section
set_option autoImplicit true




namespace ProofsInTheBook.Ch13FlipTransport

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.Chapter13
open ProofsInTheBook.Ch13CyclicSigns
open ProofsInTheBook.Ch13MarkedSphere
open ProofsInTheBook.Ch13MarkedReduction
open ProofsInTheBook.Ch13ActiveComponent
open ProofsInTheBook.SubmapPlanar
open EdgeSign
open Equiv Equiv.Perm

variable {D : Type*} [Fintype D] [DecidableEq D]



open ProofsInTheBook -- for DeleteSet.firstOutside via Equiv.Perm namespace









































































end ProofsInTheBook.Ch13FlipTransport

end

/- Original source header (imports hoisted):
import Mathlib
import ProofsInTheBook.PlanarMap
import ProofsInTheBook.PlanarMapSimple
import ProofsInTheBook.PlanarMapEuler
import ProofsInTheBook.PlanarMapDelete
import ProofsInTheBook.SubmapPlanar
import ProofsInTheBook.Chapter13
import ProofsInTheBook.Ch13CyclicSigns
import ProofsInTheBook.Ch13MarkedSphere
import ProofsInTheBook.Ch13MarkedReduction
import ProofsInTheBook.Ch13ActiveComponent
import ProofsInTheBook.Ch13FlipTransport
import ProofsInTheBook.PlanarMapNearTriangulation
-/
/- Source module: ProofsInTheBook.Ch13ComponentClose -/
section
set_option autoImplicit true




namespace ProofsInTheBook.Ch13ComponentClose

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.Chapter13
open ProofsInTheBook.Ch13CyclicSigns
open ProofsInTheBook.Ch13MarkedSphere
open ProofsInTheBook.Ch13MarkedReduction
open ProofsInTheBook.Ch13ActiveComponent
open ProofsInTheBook.Ch13FlipTransport
open ProofsInTheBook.SubmapPlanar
open EdgeSign
open Equiv Equiv.Perm

variable {D : Type*} [Fintype D] [DecidableEq D]



/-- `faceDeg = faceLen` (same orbit-card definition). -/
theorem faceDeg_eq_faceLen (M : CombMap D) (Q : Quotient (cycleSetoid M.φ)) :
    faceDeg M Q = M.faceLen Q := rfl







/-- Two kept darts have the same kept tail-vertex iff their underlying darts have the same
`M`-tail-vertex. -/
theorem keptMap_tail_eq_iff (M : CombMap D) (Del : Finset D)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del) (x y : {d : D // d ∉ Del}) :
    (keptMap M Del hsub).tail x = (keptMap M Del hsub).tail y ↔ M.tail x.1 = M.tail y.1 := by
  unfold CombMap.tail
  rw [Quotient.eq, Quotient.eq]
  show (keptMap M Del hsub).σ.SameCycle x y ↔ M.σ.SameCycle x.1 y.1
  exact Equiv.Perm.sameCycle_deleteSet_iff M.σ Del x y

/-- The kept head-vertex of `x` is the `M`-head-vertex of `x.1`, transported. -/
theorem keptMap_head_eq_iff (M : CombMap D) (Del : Finset D)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del) (x y : {d : D // d ∉ Del}) :
    (keptMap M Del hsub).head x = (keptMap M Del hsub).head y ↔ M.head x.1 = M.head y.1 := by
  unfold CombMap.head
  rw [Quotient.eq, Quotient.eq]
  show (keptMap M Del hsub).σ.SameCycle ((keptMap M Del hsub).α x) ((keptMap M Del hsub).α y)
      ↔ M.σ.SameCycle (M.α x.1) (M.α y.1)
  have hx : ((keptMap M Del hsub).α x : D) = M.α x.1 := by
    rw [keptMap_alpha]; exact keptAlpha_apply_coe M Del hsub x
  have hy : ((keptMap M Del hsub).α y : D) = M.α y.1 := by
    rw [keptMap_alpha]; exact keptAlpha_apply_coe M Del hsub y
  rw [← hx, ← hy]
  exact Equiv.Perm.sameCycle_deleteSet_iff M.σ Del _ _

/-- Cross form: kept-tail of `x` equals kept-head of `y` iff `M`-tail of `x.1` equals `M`-head of
`y.1`. -/
theorem keptMap_tail_eq_head_iff (M : CombMap D) (Del : Finset D)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del) (x y : {d : D // d ∉ Del}) :
    (keptMap M Del hsub).tail x = (keptMap M Del hsub).head y ↔ M.tail x.1 = M.head y.1 := by
  unfold CombMap.tail CombMap.head
  rw [Quotient.eq, Quotient.eq]
  show (keptMap M Del hsub).σ.SameCycle x ((keptMap M Del hsub).α y)
      ↔ M.σ.SameCycle x.1 (M.α y.1)
  have hy : ((keptMap M Del hsub).α y : D) = M.α y.1 := by
    rw [keptMap_alpha]; exact keptAlpha_apply_coe M Del hsub y
  rw [← hy]
  exact Equiv.Perm.sameCycle_deleteSet_iff M.σ Del _ _

/-- The kept `dartEdge` of `x` is `s(keptTail x, keptHead x)`; we compare via the `M`-endpoints. -/
theorem keptMap_dartEdge_eq_iff (M : CombMap D) (Del : Finset D)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del) (x y : {d : D // d ∉ Del}) :
    (keptMap M Del hsub).dartEdge x = (keptMap M Del hsub).dartEdge y
      ↔ M.dartEdge x.1 = M.dartEdge y.1 := by
  unfold CombMap.dartEdge
  rw [Sym2.eq_iff, Sym2.eq_iff,
    keptMap_tail_eq_iff M Del hsub x y, keptMap_head_eq_iff M Del hsub x y,
    keptMap_tail_eq_head_iff M Del hsub x y,
    show ((keptMap M Del hsub).head x = (keptMap M Del hsub).tail y)
        ↔ (M.head x.1 = M.tail y.1) from by
      rw [eq_comm, keptMap_tail_eq_head_iff M Del hsub y x, eq_comm]]

/-- **The kept (active sub-)map inherits `IsSimpleGraph`.** -/
theorem keptMap_isSimpleGraph (M : CombMap D) (hM : M.IsSimpleGraph) (Del : Finset D)
    (hsub : ∀ d, d ∈ Del ↔ M.α d ∈ Del) :
    (keptMap M Del hsub).IsSimpleGraph where
  no_loop x := by
    rw [Ne, keptMap_tail_eq_head_iff M Del hsub x x]
    exact hM.no_loop x.1
  no_parallel {x y} h := by
    -- kept dartEdge equal ⟹ M dartEdge equal ⟹ M.α.SameCycle x.1 y.1 ⟹ keptAlpha.SameCycle x y
    rw [keptMap_dartEdge_eq_iff M Del hsub x y] at h
    have hMsc : M.α.SameCycle x.1 y.1 := hM.no_parallel h
    -- y.1 ∈ {x.1, M.α x.1}; both kept; gives keptAlpha.SameCycle x y
    rcases (M.alpha_sameCycle_iff x.1 y.1).mp hMsc with hxy | hxy
    · -- y = x
      have hyx : y = x := Subtype.ext hxy
      exact hyx ▸ Equiv.Perm.SameCycle.rfl
    · -- y = M.α x.1 = keptAlpha x (coercion)
      refine ⟨1, ?_⟩
      apply Subtype.ext
      have hcoe : ((keptMap M Del hsub).α x : D) = M.α x.1 := by
        rw [keptMap_alpha]; exact keptAlpha_apply_coe M Del hsub x
      rw [zpow_one, hcoe]
      exact hxy.symm





























variable (M : CombMap D) (es : D → EdgeSign)





















/-- A digon (`faceLen = 2`) representative `d` of a simple map has both `A.σ d = d` and
`A.σ (A.α d) = A.α d` (both darts of its single edge are `σ`-fixed leaves). -/
theorem digon_sigma_fixed {A : CombMap D} (hA : A.IsSimpleGraph) {d : D}
    (hφ : A.φ d ≠ d) (hcard2 : (A.φ.cycleOf d).support.card = 2) :
    A.σ d = d ∧ A.σ (A.α d) = A.α d := by
  -- φ² d = d (digon)
  have hpow := Equiv.Perm.pow_mod_card_support_cycleOf_self_apply A.φ 2 d
  rw [hcard2] at hpow
  have hsq : A.φ (A.φ d) = d := by
    have h2 : (A.φ ^ 2) d = d := by simpa using hpow.symm
    simpa [pow_succ, Equiv.Perm.coe_mul, Function.comp_apply] using h2
  -- the two boundary darts share an edge ⟹ φ d = α d
  have he1 : A.dartEdge d = s(A.tail d, A.tail (A.φ d)) := A.dartEdge_eq_mk_tail_tail_phi d
  have he2 : A.dartEdge (A.φ d) = s(A.tail (A.φ d), A.tail d) := by
    rw [A.dartEdge_eq_mk_tail_tail_phi (A.φ d), hsq]
  have hedge : A.dartEdge d = A.dartEdge (A.φ d) := by rw [he1, he2, Sym2.eq_swap]
  have hsc : A.α.SameCycle d (A.φ d) := hA.no_parallel hedge
  have hφα : A.φ d = A.α d := by
    rcases (A.alpha_sameCycle_iff d (A.φ d)).mp hsc with hcase | hcase
    · exact absurd hcase hφ
    · exact hcase
  -- φ = σ * α: φ d = σ (α d) = α d ⟹ σ fixes α d
  have hσαd : A.σ (A.α d) = A.α d := by
    have : A.σ (A.α d) = A.φ d := rfl
    rw [this, hφα]
  -- φ (φ d) = d with φ d = α d: φ (α d) = σ (α (α d)) = σ d = d ⟹ σ fixes d
  have hσd : A.σ d = d := by
    have hφαd : A.φ (A.α d) = d := by rw [← hφα]; exact hsq
    have hcalc : A.σ d = A.φ (A.α d) := by
      show A.σ d = A.σ (A.α (A.α d))
      rw [A.alpha_alpha]
    rw [hcalc, hφαd]
  exact ⟨hσd, hσαd⟩

/-- **A connected simple map with `≥ 2` edges has all faces of degree `≥ 3`** (no digon). -/
theorem three_le_faceDeg_of_connected_simple_twoEdge {A : CombMap D} (hA : A.IsSimpleGraph)
    (hconn : A.Connected) (hE : 2 ≤ A.E) (R : Quotient (cycleSetoid A.φ)) :
    3 ≤ faceDeg A R := by
  obtain ⟨d, rfl⟩ := R.exists_rep
  have hφ : A.φ d ≠ d := phi_ne_self_of_isSimpleGraph A hA d
  rw [faceDeg_eq_faceLen]
  show 3 ≤ A.faceLen (A.dartFace d)
  rw [faceLen_dartFace_eq_card_support_cycleOf A hφ]
  by_contra hlt
  push Not at hlt
  have h2 : 2 ≤ (A.φ.cycleOf d).support.card :=
    (Equiv.Perm.isCycle_cycleOf A.φ hφ).two_le_card_support
  have hcard2 : (A.φ.cycleOf d).support.card = 2 := by omega
  obtain ⟨hσd, hσαd⟩ := digon_sigma_fixed hA hφ hcard2
  -- the edge {d, α d} is the entire (connected) map: every dart is d or α d
  have hαd_ne : A.α d ≠ d := A.α_no_fixed d
  -- dartStep from d stays in {d, α d}
  have hstep_d : ∀ y, A.dartStep d y → y = d ∨ y = A.α d := by
    intro y hy
    rcases hy with hσ | hαe
    · -- same σ-cycle as d; σ fixes d ⟹ y = d
      left
      obtain ⟨k, hk⟩ := Equiv.Perm.SameCycle.exists_nat_pow_eq (f := A.σ) hσ
      have : (A.σ ^ k) d = d := Equiv.Perm.pow_apply_eq_self_of_apply_eq_self hσd k
      rw [← hk, this]
    · exact Or.inr hαe
  have hstep_αd : ∀ y, A.dartStep (A.α d) y → y = d ∨ y = A.α d := by
    intro y hy
    rcases hy with hσ | hαe
    · right
      obtain ⟨k, hk⟩ := Equiv.Perm.SameCycle.exists_nat_pow_eq (f := A.σ) hσ
      have : (A.σ ^ k) (A.α d) = A.α d := Equiv.Perm.pow_apply_eq_self_of_apply_eq_self hσαd k
      rw [← hk, this]
    · left; rw [hαe, A.alpha_alpha]
  -- every dart reachable from d lies in {d, α d}
  have hall : ∀ y, Relation.ReflTransGen A.dartStep d y → y = d ∨ y = A.α d := by
    intro y h
    induction h with
    | refl => exact Or.inl rfl
    | @tail b c _ hbc ih =>
        rcases ih with rfl | rfl
        · exact hstep_d c hbc
        · exact hstep_αd c hbc
  have hsub : ∀ y : D, y ∈ ({d, A.α d} : Finset D) := by
    intro y
    have := hall y (hconn d y)
    rcases this with rfl | rfl <;> simp
  -- so |D| ≤ 2, hence 2*E = |D| ≤ 2, E ≤ 1, contradicting hE
  have hcardD : Fintype.card D ≤ 2 := by
    have hle : Fintype.card D ≤ ({d, A.α d} : Finset D).card := by
      rw [← Finset.card_univ]
      apply Finset.card_le_card
      intro y _; exact hsub y
    calc Fintype.card D ≤ ({d, A.α d} : Finset D).card := hle
      _ ≤ 2 := by
          calc ({d, A.α d} : Finset D).card ≤ ({A.α d} : Finset D).card + 1 :=
                Finset.card_insert_le _ _
            _ ≤ 2 := by simp
  have h2E : 2 * A.E = Fintype.card D := A.two_mul_E_eq_card
  omega



















end ProofsInTheBook.Ch13ComponentClose

end

/- Original source header (imports hoisted):
import ProofsInTheBook.Ch13ComponentClose
import ProofsInTheBook.ChordFaceCount
import ProofsInTheBook.PlanarMapSimple
-/
/- Source module: ProofsInTheBook.FaceDiagonalSurgery -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.PlanarMap.CombMap

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordSideRecon

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]

/-- A choice of two non-adjacent boundary darts of a common face whose tail
vertices can be joined by a new diagonal edge.  The field
`nonadjacent_on_face` records the local boundary bookkeeping: the two cut
locations are not consecutive in either direction on the selected face. -/
structure FaceDiagonalChoice (M : CombMap D) where
  f : M.Face
  d0 : D
  d1 : D
  same_face : M.dartFace d0 = f
  same_face' : M.dartFace d1 = f
  endpoints_distinct : M.tail d0 ≠ M.tail d1
  no_existing_edge : ¬ M.toSimpleGraph.Adj (M.tail d0) (M.tail d1)
  nonadjacent_on_face : M.φ d0 ≠ d1 ∧ M.φ d1 ≠ d0

namespace FaceDiagonalChoice

variable {M : CombMap D} (c : FaceDiagonalChoice M)

/-- First splice anchor: the dart whose `σ`-successor is the first chosen
face dart. -/
def anchor0 : D :=
  M.σ.symm c.d0

/-- Second splice anchor: the dart whose `σ`-successor is the second chosen
face dart. -/
def anchor1 : D :=
  M.σ.symm c.d1

@[simp] lemma sigma_anchor0 : M.σ c.anchor0 = c.d0 := by
  simp [anchor0]

@[simp] lemma sigma_anchor1 : M.σ c.anchor1 = c.d1 := by
  simp [anchor1]

lemma tail_anchor0 : M.tail c.anchor0 = M.tail c.d0 := by
  have h := M.tail_sigma (M.σ.symm c.d0)
  simpa [anchor0] using h.symm

lemma tail_anchor1 : M.tail c.anchor1 = M.tail c.d1 := by
  have h := M.tail_sigma (M.σ.symm c.d1)
  simpa [anchor1] using h.symm

/-- The two splice anchors are distinct because their tail vertices are
distinct. -/
lemma anchors_ne : c.anchor0 ≠ c.anchor1 := by
  intro h
  apply c.endpoints_distinct
  calc
    M.tail c.d0 = M.tail c.anchor0 := (c.tail_anchor0).symm
    _ = M.tail c.anchor1 := by rw [h]
    _ = M.tail c.d1 := c.tail_anchor1

/-- The selected darts lie in the same old face orbit. -/
lemma same_face_sameCycle : M.φ.SameCycle c.d0 c.d1 := by
  change (cycleSetoid M.φ).r c.d0 c.d1
  apply Quotient.exact
  exact c.same_face.trans c.same_face'.symm

/-- The same-face condition in the exact form consumed by
`freshMap_F_same_face`. -/
lemma keptPhi_anchor_successors_sameCycle :
    (keptPhi M.α M.σ).SameCycle (M.σ c.anchor0) (M.σ c.anchor1) := by
  simpa [keptPhi, CombMap.φ] using c.same_face_sameCycle

end FaceDiagonalChoice

/-- Add one internal face diagonal by the generic fresh-dart adjunction. -/
noncomputable def addFaceDiagonal (M : CombMap D) (c : FaceDiagonalChoice M) :
    CombMap (D ⊕ Fin 2) :=
  freshMap M.α M.σ M.α_invol M.α_no_fixed c.anchor0 c.anchor1 c.anchors_ne

/-- Face excess: total surplus over triangular faces. -/
noncomputable def faceExcess (M : CombMap D) : ℕ :=
  ∑ f : M.Face, (M.faceLen f - 3)

theorem faceExcess_eq_two_mul_E_sub_three_mul_F
    (M : CombMap D) (h3 : M.FaceLengthGe 3) :
    faceExcess M = 2 * M.E - 3 * M.F := by
  unfold faceExcess
  have hsum := Finset.sum_tsub_distrib (s := (Finset.univ : Finset M.Face))
    (f := fun Q : M.Face => M.faceLen Q) (g := fun _ : M.Face => 3)
    (by intro Q _; exact h3 Q)
  calc
    (∑ Q : M.Face, (M.faceLen Q - 3))
        = (∑ Q : M.Face, M.faceLen Q) - Fintype.card M.Face * 3 := by
          simpa using hsum
    _ = 2 * M.E - 3 * M.F := by
          rw [sum_faceLen]
          simp [CombMap.F, Nat.mul_comm]

lemma sameCycle_mem_triple_of_phi_cube {p : Equiv.Perm D} {d e : D}
    (hcube : p (p (p d)) = d) (h : p.SameCycle d e) :
    e = d ∨ e = p d ∨ e = p (p d) := by
  obtain ⟨i, hi⟩ := h
  have hinv0 : p.symm d = p (p d) := by
    rw [Equiv.symm_apply_eq]
    exact hcube.symm
  have hinv1 : p.symm (p d) = d := by
    rw [Equiv.symm_apply_eq]
  have hinv2 : p.symm (p (p d)) = p d := by
    rw [Equiv.symm_apply_eq]
  have key : ∀ k : ℤ, (p ^ k) d = d ∨ (p ^ k) d = p d ∨
      (p ^ k) d = p (p d) := by
    intro k
    refine Int.induction_on k ?_ ?_ ?_
    · left
      simp
    · intro n ih
      rw [show ((n : ℤ) + 1) = 1 + (n : ℤ) by ring, zpow_add, zpow_one,
        Equiv.Perm.mul_apply]
      rcases ih with h0 | h1 | h2
      · right
        left
        rw [h0]
      · right
        right
        rw [h1]
      · left
        rw [h2]
        exact hcube
    · intro n ih
      have hstep : (p ^ (-(n : ℤ) - 1)) d = p.symm ((p ^ (-(n : ℤ))) d) := by
        rw [show (-(n : ℤ) - 1) = (-1) + (-(n : ℤ)) by ring, zpow_add,
          Equiv.Perm.mul_apply, show (p ^ (-1 : ℤ)) = p.symm from by
            rw [zpow_neg, zpow_one]
            rfl]
      rw [hstep]
      rcases ih with h0 | h1 | h2
      · rw [h0]
        right
        right
        exact hinv0
      · rw [h1]
        left
        exact hinv1
      · rw [h2]
        right
        left
        exact hinv2
  rcases key i with h0 | h1 | h2
  · left
    rw [← hi, h0]
  · right
    left
    rw [← hi, h1]
  · right
    right
    rw [← hi, h2]

namespace FaceDiagonal

variable (M : CombMap D) (c : FaceDiagonalChoice M)

/-- The old vertices embed into the fresh map by sending an old dart orbit to
the corresponding `inl` fresh-rotation orbit. -/
noncomputable def includeVertex :
    M.Vertex → (addFaceDiagonal M c).Vertex :=
  Quotient.lift
    (fun d : D =>
      Quotient.mk (cycleSetoid (addFaceDiagonal M c).σ) (Sum.inl d))
    (by
      intro d e hde
      apply Quotient.sound
      change (freshSigma M.σ c.anchor0 c.anchor1 c.anchors_ne).SameCycle
        (Sum.inl d) (Sum.inl e)
      rw [freshSigma_sameCycle_iff M.σ c.anchors_ne]
      simpa using hde)



/-- The old-vertex embedding is injective. -/
theorem includeVertex_injective :
    Function.Injective (includeVertex M c) := by
  intro x y hxy
  refine Quotient.inductionOn₂ x y ?_ hxy
  intro d e hde
  have hfresh :
      (freshSigma M.σ c.anchor0 c.anchor1 c.anchors_ne).SameCycle
        (Sum.inl d) (Sum.inl e) := by
    exact Quotient.exact hde
  have hold : M.σ.SameCycle d e := by
    have hproj := (freshSigma_sameCycle_iff M.σ c.anchors_ne
      (Sum.inl d) (Sum.inl e)).1 hfresh
    simpa using hproj
  exact Quotient.sound hold

lemma includeVertex_head (d : D) :
    includeVertex M c (M.head d)
      = (addFaceDiagonal M c).head (Sum.inl d) := by
  rfl

/-- Collapse a fresh-map vertex back to the old vertex containing its anchor
projection. -/
noncomputable def vertexToOld :
    (addFaceDiagonal M c).Vertex → M.Vertex :=
  Quotient.lift
    (fun x : D ⊕ Fin 2 => M.tail (proj c.anchor0 c.anchor1 x))
    (by
      intro x y hxy
      have hsc :
          (freshSigma M.σ c.anchor0 c.anchor1 c.anchors_ne).SameCycle x y := by
        simpa [addFaceDiagonal] using hxy
      have hproj : M.σ.SameCycle
          (proj c.anchor0 c.anchor1 x) (proj c.anchor0 c.anchor1 y) :=
        (freshSigma_sameCycle_iff M.σ c.anchors_ne x y).1 hsc
      exact Quotient.sound hproj)

@[simp] lemma vertexToOld_tail (x : D ⊕ Fin 2) :
    vertexToOld M c ((addFaceDiagonal M c).tail x)
      = M.tail (proj c.anchor0 c.anchor1 x) :=
  rfl

@[simp] lemma vertexToOld_head (x : D ⊕ Fin 2) :
    vertexToOld M c ((addFaceDiagonal M c).head x)
      = M.tail (proj c.anchor0 c.anchor1 ((addFaceDiagonal M c).α x)) :=
  rfl

@[simp] lemma vertexToOld_tail_inl (d : D) :
    vertexToOld M c ((addFaceDiagonal M c).tail (Sum.inl d)) = M.tail d := by
  simp [vertexToOld_tail, proj]

@[simp] lemma vertexToOld_head_inl (d : D) :
    vertexToOld M c ((addFaceDiagonal M c).head (Sum.inl d)) = M.head d := by
  rw [vertexToOld_head]
  simp [addFaceDiagonal, proj, CombMap.head]

@[simp] lemma vertexToOld_tail_inr_zero :
    vertexToOld M c ((addFaceDiagonal M c).tail (Sum.inr (0 : Fin 2))) = M.tail c.d0 := by
  simp [vertexToOld_tail, proj, c.tail_anchor0]

@[simp] lemma vertexToOld_head_inr_zero :
    vertexToOld M c ((addFaceDiagonal M c).head (Sum.inr (0 : Fin 2))) = M.tail c.d1 := by
  rw [vertexToOld_head]
  simp [addFaceDiagonal, proj, c.tail_anchor1]

@[simp] lemma vertexToOld_tail_inr_one :
    vertexToOld M c ((addFaceDiagonal M c).tail (Sum.inr (1 : Fin 2))) = M.tail c.d1 := by
  simp [vertexToOld_tail, proj, c.tail_anchor1]

@[simp] lemma vertexToOld_head_inr_one :
    vertexToOld M c ((addFaceDiagonal M c).head (Sum.inr (1 : Fin 2))) = M.tail c.d0 := by
  rw [vertexToOld_head]
  simp [addFaceDiagonal, proj, c.tail_anchor0]

lemma map_dartEdge_inl (d : D) :
    Sym2.map (vertexToOld M c) ((addFaceDiagonal M c).dartEdge (Sum.inl d))
      = M.dartEdge d := by
  rw [CombMap.dartEdge, Sym2.map_mk]
  simp only [vertexToOld_tail_inl, vertexToOld_head_inl]
  rfl

lemma map_dartEdge_inr_zero :
    Sym2.map (vertexToOld M c)
        ((addFaceDiagonal M c).dartEdge (Sum.inr (0 : Fin 2)))
      = s(M.tail c.d0, M.tail c.d1) := by
  rw [CombMap.dartEdge, Sym2.map_mk]
  simp only [vertexToOld_tail_inr_zero, vertexToOld_head_inr_zero]

lemma map_dartEdge_inr_one :
    Sym2.map (vertexToOld M c)
        ((addFaceDiagonal M c).dartEdge (Sum.inr (1 : Fin 2)))
      = s(M.tail c.d0, M.tail c.d1) := by
  rw [CombMap.dartEdge, Sym2.map_mk]
  simp only [vertexToOld_tail_inr_one, vertexToOld_head_inr_one]
  exact Sym2.eq_swap

/-- A fresh diagonal dart is not a loop under the endpoint-distinct hypothesis,
and old darts remain non-loops from the original simple-map hypothesis. -/
theorem no_loop (hSimple : M.IsSimpleGraph) :
    ∀ x : D ⊕ Fin 2, (addFaceDiagonal M c).tail x ≠ (addFaceDiagonal M c).head x := by
  intro x h
  have hsc :
      (freshSigma M.σ c.anchor0 c.anchor1 c.anchors_ne).SameCycle
        x (freshAlpha M.α x) := by
    simpa [addFaceDiagonal] using (Quotient.exact h)
  have hproj := (freshSigma_sameCycle_iff M.σ c.anchors_ne
    x (freshAlpha M.α x)).1 hsc
  cases x with
  | inl d =>
      have hold : M.σ.SameCycle d (M.α d) := by
        simpa [proj] using hproj
      exact hSimple.no_loop d (Quotient.sound hold)
  | inr j =>
      fin_cases j
      · have ht : M.tail c.anchor0 = M.tail c.anchor1 := by
          exact Quotient.sound (by simpa [proj] using hproj)
        apply c.endpoints_distinct
        calc
          M.tail c.d0 = M.tail c.anchor0 := (c.tail_anchor0).symm
          _ = M.tail c.anchor1 := ht
          _ = M.tail c.d1 := c.tail_anchor1
      · have ht : M.tail c.anchor1 = M.tail c.anchor0 := by
          exact Quotient.sound (by simpa [proj] using hproj)
        apply c.endpoints_distinct
        calc
          M.tail c.d0 = M.tail c.anchor0 := (c.tail_anchor0).symm
          _ = M.tail c.anchor1 := ht.symm
          _ = M.tail c.d1 := c.tail_anchor1

lemma freshAlpha_sameCycle_inl_of_alpha_sameCycle {d e : D}
    (h : M.α.SameCycle d e) :
    (addFaceDiagonal M c).α.SameCycle (Sum.inl d) (Sum.inl e) := by
  rcases (M.alpha_sameCycle_iff d e).1 h with rfl | rfl
  · exact Equiv.Perm.SameCycle.refl _ _
  · refine ⟨1, ?_⟩
    simp [addFaceDiagonal]

lemma freshAlpha_sameCycle_inr (j k : Fin 2) :
    (addFaceDiagonal M c).α.SameCycle (Sum.inr j) (Sum.inr k) := by
  fin_cases j <;> fin_cases k
  · exact Equiv.Perm.SameCycle.refl _ _
  · refine ⟨1, ?_⟩
    simp [addFaceDiagonal]
  · refine ⟨1, ?_⟩
    simp [addFaceDiagonal]
  · exact Equiv.Perm.SameCycle.refl _ _

lemma no_old_fresh_parallel (hSimple : M.IsSimpleGraph) {d : D} {j : Fin 2}
    (h : (addFaceDiagonal M c).dartEdge (Sum.inl d)
        = (addFaceDiagonal M c).dartEdge (Sum.inr j)) :
    False := by
  have hmap := congrArg (Sym2.map (vertexToOld M c)) h
  have hedge : M.dartEdge d = s(M.tail c.d0, M.tail c.d1) := by
    fin_cases j
    · simpa [map_dartEdge_inl, map_dartEdge_inr_zero] using hmap
    · simpa [map_dartEdge_inl, map_dartEdge_inr_one] using hmap
  have hadj : M.Adj (M.tail c.d0) (M.tail c.d1) := ⟨d, hedge⟩
  exact c.no_existing_edge ⟨c.endpoints_distinct, hadj⟩

/-- The face diagonal preserves map simplicity: old parallel edges are handled
by `hSimple`, the fresh edge is non-loop by `endpoints_distinct`, and it is not
parallel to an old edge by `no_existing_edge`. -/
theorem simple (hSimple : M.IsSimpleGraph) :
    (addFaceDiagonal M c).IsSimpleGraph := by
  refine ⟨no_loop M c hSimple, ?_⟩
  intro x y hxy
  cases x with
  | inl d =>
      cases y with
      | inl e =>
          have hmap := congrArg (Sym2.map (vertexToOld M c)) hxy
          have hold : M.dartEdge d = M.dartEdge e := by
            simpa [map_dartEdge_inl] using hmap
          exact freshAlpha_sameCycle_inl_of_alpha_sameCycle M c (hSimple.no_parallel hold)
      | inr j =>
          exact False.elim (no_old_fresh_parallel M c hSimple hxy)
  | inr j =>
      cases y with
      | inl e =>
          exact (False.elim (no_old_fresh_parallel M c hSimple hxy.symm))
      | inr k =>
          exact freshAlpha_sameCycle_inr M c j k

/-- The vertex count is unchanged by inserting the two fresh darts into
existing vertex rotations. -/
theorem V_eq :
    (addFaceDiagonal M c).V = M.V := by
  simpa [addFaceDiagonal, CombMap.V] using
    (freshMap_V M.σ c.anchors_ne M.α M.α_invol M.α_no_fixed)

/-- The edge count rises by one: the two new darts form one new `α`-orbit. -/
theorem E_eq :
    (addFaceDiagonal M c).E = M.E + 1 := by
  have hfresh :
      2 * (addFaceDiagonal M c).E = Fintype.card D + 2 := by
    simpa [addFaceDiagonal] using
      (freshMap_two_mul_E M.α M.σ M.α_invol M.α_no_fixed
        c.anchor0 c.anchor1 c.anchors_ne)
  have hold : 2 * M.E = Fintype.card D := M.two_mul_E_eq_card
  omega

/-- The selected old face orbit is split into two old-plus-fresh face orbits;
all other old face orbits are unchanged at the cycle-count level. -/
theorem F_eq :
    (addFaceDiagonal M c).F = M.F + 1 := by
  have hsame := c.keptPhi_anchor_successors_sameCycle
  have hF :
      (addFaceDiagonal M c).F = numCycles (keptPhi M.α M.σ) + 1 := by
    simpa [addFaceDiagonal] using
      (freshMap_F_same_face M.α M.σ M.α_invol M.α_no_fixed
        c.anchors_ne hsame)
  rw [hF]
  have hOld : M.F = numCycles (keptPhi M.α M.σ) := by
    rw [M.F_eq_numCycles]
    rfl
  omega

/-- The fresh map remains connected when the old map is connected. -/
theorem connected (hconn : M.Connected) :
    (addFaceDiagonal M c).Connected := by
  simpa [addFaceDiagonal, keptCombMap] using
    (freshMap_connected_of_kept M.α M.σ M.α_invol M.α_no_fixed
      c.anchors_ne (by simpa [keptCombMap] using hconn))

/-- Sphere-map preservation from the count identities. -/
theorem sphere (hS : M.IsSphereMap) :
    (addFaceDiagonal M c).IsSphereMap := by
  refine ⟨connected M c hS.1, ?_⟩
  unfold CombMap.eulerChar
  have hV := V_eq M c
  have hE := E_eq M c
  have hF := F_eq M c
  rw [hV, hE, hF]
  norm_num [Nat.cast_add]
  ring_nf
  simpa [CombMap.eulerChar] using hS.2

/-- Old adjacency embeds into the fresh map through `includeVertex`. -/
theorem old_adj_embed {u v : M.Vertex}
    (hadj : M.toSimpleGraph.Adj u v) :
    (addFaceDiagonal M c).toSimpleGraph.Adj
      (includeVertex M c u) (includeVertex M c v) := by
  rcases hadj with ⟨hne, d, hd⟩
  refine ⟨?_, Sum.inl d, ?_⟩
  · intro h
    exact hne (includeVertex_injective M c h)
  · have hmap := congrArg (Sym2.map (includeVertex M c)) hd
    simpa [CombMap.dartEdge, includeVertex_head] using hmap

lemma old_E_ge_two (c : FaceDiagonalChoice M) (hSimple : M.IsSimpleGraph) : 2 ≤ M.E := by
  have hd01 : c.d0 ≠ c.d1 := by
    intro h
    exact c.endpoints_distinct (by rw [h])
  have hφ0 : M.φ c.d0 ≠ c.d0 := by
    intro h
    apply hSimple.no_loop c.d0
    rw [← M.tail_phi c.d0, h]
  have hφ01 : M.φ c.d0 ≠ c.d1 := c.nonadjacent_on_face.1
  let f : Fin 3 → D := fun i =>
    if i = 0 then c.d0 else if i = 1 then c.d1 else M.φ c.d0
  have hf : Function.Injective f := by
    intro i j hij
    fin_cases i <;> fin_cases j <;>
      simp [f, hd01, hd01.symm, hφ0, hφ0.symm, hφ01, hφ01.symm] at hij ⊢
  have hcard : 3 ≤ Fintype.card D := by
    simpa using Fintype.card_le_of_injective f hf
  have htwo := M.two_mul_E_eq_card
  omega

theorem faceLengthGe_three (c : FaceDiagonalChoice M)
    (hS : M.IsSphereMap) (hSimple : M.IsSimpleGraph) :
    M.FaceLengthGe 3 := by
  intro Q
  have hdeg := ProofsInTheBook.Ch13ComponentClose.three_le_faceDeg_of_connected_simple_twoEdge
    (A := M) hSimple hS.1 (old_E_ge_two M c hSimple) Q
  simpa [ProofsInTheBook.Ch13ComponentClose.faceDeg_eq_faceLen] using hdeg

theorem faceLengthGe_three_add (hS : M.IsSphereMap) (hSimple : M.IsSimpleGraph) :
    (addFaceDiagonal M c).FaceLengthGe 3 := by
  intro Q
  have hS' := sphere M c hS
  have hSimple' := simple M c hSimple
  have hEold := old_E_ge_two M c hSimple
  have hE' : 2 ≤ (addFaceDiagonal M c).E := by
    have hEeq := E_eq M c
    omega
  have hdeg := ProofsInTheBook.Ch13ComponentClose.three_le_faceDeg_of_connected_simple_twoEdge
    (A := addFaceDiagonal M c) hSimple' hS'.1 hE' Q
  simpa [ProofsInTheBook.Ch13ComponentClose.faceDeg_eq_faceLen] using hdeg

lemma chosen_face_len_ne_three (hSimple : M.IsSimpleGraph) :
    M.faceLen c.f ≠ 3 := by
  intro hlen
  have hlen0 : M.faceLen (M.dartFace c.d0) = 3 := by
    rw [c.same_face, hlen]
  have hcube := faceLen_three_phi_cube_eq_self M hSimple hlen0
  have hsc : M.φ.SameCycle c.d0 c.d1 := c.same_face_sameCycle
  rcases sameCycle_mem_triple_of_phi_cube hcube hsc with h | h | h
  · apply c.endpoints_distinct
    rw [h]
  · exact c.nonadjacent_on_face.1 h.symm
  · have hφd1 : M.φ c.d1 = c.d0 := by
      rw [h]
      simpa [pow_succ, Equiv.Perm.coe_mul, Function.comp_apply] using hcube
    exact c.nonadjacent_on_face.2 hφd1

lemma faceExcess_pos (c : FaceDiagonalChoice M)
    (h3 : M.FaceLengthGe 3) (hSimple : M.IsSimpleGraph) :
    0 < faceExcess M := by
  have hne := chosen_face_len_ne_three M c hSimple
  have hlt : 3 < M.faceLen c.f := by
    exact lt_of_le_of_ne (h3 c.f) (by intro h; exact hne h.symm)
  have hterm : 0 < M.faceLen c.f - 3 := Nat.sub_pos_of_lt hlt
  unfold faceExcess
  have hle :
      M.faceLen c.f - 3 ≤ ∑ f : M.Face, (M.faceLen f - 3) := by
    simpa using Finset.single_le_sum
      (s := (Finset.univ : Finset M.Face))
      (f := fun f : M.Face => M.faceLen f - 3)
      (by intro f _; exact Nat.zero_le _)
      (Finset.mem_univ c.f)
  exact lt_of_lt_of_le hterm hle

theorem faceExcess_decrease (hS : M.IsSphereMap) (hSimple : M.IsSimpleGraph) :
    faceExcess (addFaceDiagonal M c) < faceExcess M := by
  have h3old := faceLengthGe_three M c hS hSimple
  have h3new := faceLengthGe_three_add M c hS hSimple
  have hold := faceExcess_eq_two_mul_E_sub_three_mul_F M h3old
  have hnew := faceExcess_eq_two_mul_E_sub_three_mul_F (addFaceDiagonal M c) h3new
  have hE := E_eq M c
  have hF := F_eq M c
  have hpos := faceExcess_pos M c h3old hSimple
  rw [hnew, hold, hE, hF] at *
  omega

end FaceDiagonal

/-- A one-step face-diagonal insertion certificate.  The generic fresh-map
count, connectivity, simplicity, old-edge embedding, and excess decrease fields
are produced below. -/
structure FaceDiagonalInsertion
    (M : CombMap D) (hS : M.IsSphereMap) (hSimple : M.IsSimpleGraph)
    (c : FaceDiagonalChoice M) where
  D' : Type u
  [fintypeD' : Fintype D']
  [decEqD' : DecidableEq D']
  M' : CombMap D'
  includeDart : D → D'
  includeVertex : M.Vertex → M'.Vertex
  sphere' : M'.IsSphereMap
  simple' : M'.IsSimpleGraph
  old_adj_embed :
    ∀ {u v : M.Vertex}, M.toSimpleGraph.Adj u v →
      M'.toSimpleGraph.Adj (includeVertex u) (includeVertex v)
  V_eq : M'.V = M.V
  E_eq : M'.E = M.E + 1
  F_eq : M'.F = M.F + 1
  faceExcess_decrease : faceExcess M' < faceExcess M

attribute [instance] FaceDiagonalInsertion.fintypeD' FaceDiagonalInsertion.decEqD'

namespace FaceDiagonalInsertion

/-- Assemble the diagonal insertion certificate from the two remaining local
geometric obligations. -/
noncomputable def of_addFaceDiagonal
    (M : CombMap D) (hS : M.IsSphereMap) (hSimple : M.IsSimpleGraph)
    (c : FaceDiagonalChoice M) :
    FaceDiagonalInsertion M hS hSimple c where
  D' := D ⊕ Fin 2
  M' := addFaceDiagonal M c
  includeDart := Sum.inl
  includeVertex := FaceDiagonal.includeVertex M c
  sphere' := FaceDiagonal.sphere M c hS
  simple' := FaceDiagonal.simple M c hSimple
  old_adj_embed := by
    intro u v h
    exact FaceDiagonal.old_adj_embed M c h
  V_eq := FaceDiagonal.V_eq M c
  E_eq := FaceDiagonal.E_eq M c
  F_eq := FaceDiagonal.F_eq M c
  faceExcess_decrease := FaceDiagonal.faceExcess_decrease M c hS hSimple

end FaceDiagonalInsertion

end ProofsInTheBook.PlanarMap.CombMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapChordSplitData
import ProofsInTheBook.PlanarMapCutCap
-/
/- Source module: ProofsInTheBook.ZinanCh35StarRotation -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



/-- A **star dart** at a vertex `x`: a dart whose tail is `x`.  Since `M.Vertex` is the
`σ`-orbit quotient and `M.tail d = ⟦d⟧_σ`, this is precisely the cyclic family of darts
incident at `x` in their rotation order. -/
abbrev StarDart (M : CombMap D) (x : M.Vertex) : Type _ :=
  {d : D // M.tail d = x}

instance (M : CombMap D) (x : M.Vertex) : DecidableEq (StarDart M x) :=
  Subtype.instDecidableEq

instance (M : CombMap D) (x : M.Vertex) : Fintype (StarDart M x) :=
  Subtype.fintype _









variable {M : CombMap D} (hNT : NearTriangulation M)













































end CombMap

end ProofsInTheBook.PlanarMap

-- Axiom audit for the main brick results (expect: propext, Classical.choice, Quot.sound).









end

/- Original source header (imports hoisted):
import ProofsInTheBook.SubmapPlanar
-/
/- Source module: ProofsInTheBook.ChordSideClose -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordSideClose

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.SubmapPlanar

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



section RawPrimitives

variable (M)

open scoped Classical

/-- For a kept dart `a` (`a ∉ Del`), one raw face step is one `M.φ` step:
`(M.σ * rawAlpha) a = M.φ a`. -/
lemma rawFace_step_eq_phi {Del : Finset D}
    (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) {a : D} (ha : a ∉ Del) :
    (M.σ * SubmapPlanar.rawAlpha M Del hclosed) a = M.φ a := by
  rw [Equiv.Perm.mul_apply, SubmapPlanar.rawAlpha_eq_alpha_of_notMem M Del hclosed ha]
  rfl

/-- **Raw face walk.**  If `a` and the first `k` forward `M.φ`-iterates `M.φ^j a` (`0 ≤ j < k`)
are all kept, then `(M.σ * rawAlpha)^k a = M.φ^k a`. -/
lemma rawFace_walk {Del : Finset D} (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) {a : D} :
    ∀ k : ℕ, (∀ j : ℕ, j < k → (M.φ ^ j) a ∉ Del) →
      ((M.σ * SubmapPlanar.rawAlpha M Del hclosed) ^ k) a = (M.φ ^ k) a := by
  classical
  set p := M.σ * SubmapPlanar.rawAlpha M Del hclosed with hp
  intro k
  induction k with
  | zero => intro _; simp
  | succ k ih =>
      intro hkept
      have ihk : (p ^ k) a = (M.φ ^ k) a :=
        ih (fun j hj => hkept j (by omega))
      have hak : (M.φ ^ k) a ∉ Del := hkept k (by omega)
      have hstep : (p ^ (k+1)) a = p ((p ^ k) a) := by rw [pow_succ']; rfl
      rw [hstep, ihk, hp, rawFace_step_eq_phi M hclosed hak, ← Equiv.Perm.mul_apply,
        ← pow_succ']

/-- **Whole-face kept ⟹ raw face SameCycle.**  If every dart in the `M.φ`-cycle of `a` is kept
(`∉ Del`), then `M.φ.SameCycle a b` implies `(M.σ * rawAlpha).SameCycle a b`: the `φ`-walk from
`a` to `b` never leaves the kept set, so the raw face perm tracks `M.φ` along it. -/
lemma rawFace_sameCycle_of_face_kept {Del : Finset D}
    (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) {a b : D}
    (hface : ∀ c : D, M.φ.SameCycle a c → c ∉ Del)
    (hab : M.φ.SameCycle a b) :
    (M.σ * SubmapPlanar.rawAlpha M Del hclosed).SameCycle a b := by
  classical
  obtain ⟨k, hk⟩ := hab.exists_nat_pow_eq
  refine ⟨(k : ℤ), ?_⟩
  rw [zpow_natCast, rawFace_walk M hclosed k (fun j _ => hface _ ⟨(j : ℤ), by rw [zpow_natCast]⟩),
    hk]

end RawPrimitives



/-- The **raw** dart-step relation at the side-1 chord split: `M.σ`-`SameCycle` or a
`rawAlpha`-edge (the restricted involution fixing deleted darts, equal to `M.α` on kept
darts).  This is `SubmapPlanar.dartStepRel M.σ (rawAlpha M keptDel₁ …)`. -/
noncomputable def rawStep₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    D → D → Prop :=
  dartStepRel M.σ (rawAlpha M data.keptDel₁ (SubmapPlanar.keptDel₁_closed data hsep))

/-- **Raw `EqvGen` from same-face whole-face-kept.**  Wrapper turning the raw face SameCycle
into raw `EqvGen` (the generator of the raw reachability). -/
lemma rawEqvGen_of_face_kept {Del : Finset D}
    (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) {a b : D}
    (hface : ∀ c : D, M.φ.SameCycle a c → c ∉ Del)
    (hab : M.φ.SameCycle a b) :
    Relation.EqvGen (dartStepRel M.σ (SubmapPlanar.rawAlpha M Del hclosed)) a b :=
  eqvGen_dartStepRel_of_sameCycle_mul M.σ (SubmapPlanar.rawAlpha M Del hclosed)
    (SubmapPlanar.rawAlpha_invol M Del hclosed)
    (rawFace_sameCycle_of_face_kept M hclosed hface hab)

/-- **One kept `φ`-step is raw-connected.**  For a kept dart `a` (`a ∉ Del`), `a` and `M.φ a`
are raw-`EqvGen`-connected: one raw face-perm step `(M.σ * rawAlpha) a = M.φ a`. -/
lemma rawEqvGen_phi_step {Del : Finset D}
    (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) {a : D} (ha : a ∉ Del) :
    Relation.EqvGen (dartStepRel M.σ (SubmapPlanar.rawAlpha M Del hclosed)) a (M.φ a) := by
  refine eqvGen_dartStepRel_of_sameCycle_mul M.σ (SubmapPlanar.rawAlpha M Del hclosed)
    (SubmapPlanar.rawAlpha_invol M Del hclosed) ?_
  exact ⟨(1 : ℤ), by rw [zpow_one, rawFace_step_eq_phi M hclosed ha]⟩

/-- **Raw `EqvGen` from a single `rawAlpha`-edge at a kept dart.**  For `a ∉ Del`,
`a` and `M.α a` are one raw step apart. -/
lemma rawEqvGen_of_alpha {Del : Finset D}
    (hclosed : ∀ d : D, d ∈ Del → M.α d ∈ Del) {a : D} (ha : a ∉ Del) :
    Relation.EqvGen (dartStepRel M.σ (SubmapPlanar.rawAlpha M Del hclosed)) a (M.α a) :=
  Relation.EqvGen.rel _ _ (Or.inr (SubmapPlanar.rawAlpha_eq_alpha_of_notMem M Del hclosed ha).symm)



section RawConnected

/-- The chord dart is deleted (removed from the side-1 kept set). -/
lemma dart_mem_keptDel₁ (data : hNT.ChordSplitData u v) :
    data.dart ∈ data.keptDel₁ := by
  classical
  by_contra hcontra
  rw [data.mem_keptDel₁_iff] at hcontra
  exact hcontra.2 rfl

/-- A dart whose face lies in side 1 and which is not the chord dart is kept. -/
lemma inner_notMem_keptDel₁ (data : hNT.ChordSplitData u v)
    {c : D} (hf : M.dartFace c ∈ data.side₁) (hne : c ≠ data.dart) :
    c ∉ data.keptDel₁ := by
  rw [data.mem_keptDel₁_iff]
  exact ⟨Or.inl hf, by simpa using hne⟩

/-- An outer-arc dart of side 1 (outer face, `α`-reverse inner) is kept; it is never the
chord dart (whose face is `face₁ ≠ outerFace`). -/
lemma outerArc_notMem_keptDel₁ (data : hNT.ChordSplitData u v)
    {c : D} (ho : M.dartFace c = hNT.outerFace)
    (hα : M.dartFace (M.α c) ∈ data.side₁) : c ∉ data.keptDel₁ := by
  rw [data.mem_keptDel₁_iff]
  refine ⟨Or.inr ⟨ho, hα⟩, ?_⟩
  simp only [Set.mem_singleton_iff]
  intro hc
  apply data.face₁_not_outer
  show M.dartFace data.dart = hNT.outerFace
  rw [← hc]; exact ho

/-- The reference kept dart of side 1: `M.φ data.dart`, a dart of the triangle `face₁` other
than the (deleted) chord dart. -/
lemma ref_kept (data : hNT.ChordSplitData u v) :
    M.φ data.dart ∉ data.keptDel₁ := by
  refine inner_notMem_keptDel₁ data ?_ ?_
  · show M.dartFace (M.φ data.dart) ∈ data.side₁
    rw [dartFace_phi]; exact data.face₁_mem_side₁
  · exact M.phi_ne_self_of_isSimpleGraph hNT.simpleGraph data.dart

/-- **Within-face raw connectivity, away from `face₁`.**  If `M.φ.SameCycle a b` and the common
face is in side 1 but is not `face₁`, then `a` and `b` are raw-connected.  (Every dart of such
a face is kept: it is in `sideDarts₁` and is not the chord dart, which lives in `face₁`.) -/
lemma rawE_within_face_ne_face₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    {a b : D} (hfa : M.dartFace a ∈ data.side₁)
    (hne : M.dartFace a ≠ data.face₁) (hab : M.φ.SameCycle a b) :
    Relation.EqvGen (rawStep₁ data hsep) a b := by
  refine rawEqvGen_of_face_kept (SubmapPlanar.keptDel₁_closed data hsep)
    (fun c hac => ?_) hab
  have hfeq : M.dartFace c = M.dartFace a := Quotient.sound hac.symm
  have hfc : M.dartFace c ∈ data.side₁ := by rw [hfeq]; exact hfa
  refine inner_notMem_keptDel₁ data hfc ?_
  intro hcd
  apply hne
  rw [← hfeq, hcd]; rfl

/-- The darts of the chord triangle `face₁`: any dart `c` with `M.φ.SameCycle data.dart c` is
`data.dart`, `M.φ data.dart`, or `M.φ² data.dart`. -/
lemma face₁_dart_cases (data : hNT.ChordSplitData u v)
    {c : D} (hsc : M.φ.SameCycle data.dart c) :
    c = data.dart ∨ c = M.φ data.dart ∨ c = M.φ (M.φ data.dart) := by
  classical
  obtain ⟨h1, h2, h3⟩ := data.face₁_isFaceTriangle
  obtain ⟨k, hk⟩ := hsc.exists_nat_pow_eq
  have hcube : (M.φ ^ 3) data.dart = data.dart := by
    have : (M.φ ^ 3) data.dart = M.φ (M.φ (M.φ data.dart)) := by
      simp [pow_succ, Equiv.Perm.mul_apply]
    rw [this, h3]
  have hperiodic : ∀ m : ℕ, (M.φ ^ m) data.dart = (M.φ ^ (m % 3)) data.dart := by
    intro m
    -- `φ^m dart = φ^(3*(m/3)) (φ^(m%3) dart)`; the outer factor fixes the inner point.
    conv_lhs => rw [← Nat.div_add_mod m 3, pow_add, pow_mul, Equiv.Perm.mul_apply]
    set y := (M.φ ^ (m % 3)) data.dart with hy
    -- `φ^3` fixes `y` (it fixes `dart`, and powers commute), so `(φ^3)^(m/3)` does too.
    have hfix : (M.φ ^ 3) y = y := by
      rw [hy, ← Equiv.Perm.mul_apply, ← pow_add, Nat.add_comm, pow_add, Equiv.Perm.mul_apply,
        hcube]
    exact Equiv.Perm.pow_apply_eq_self_of_apply_eq_self hfix (m / 3)
  have hmod : c = (M.φ ^ (k % 3)) data.dart := by rw [← hk, hperiodic k]
  have hlt : k % 3 < 3 := Nat.mod_lt _ (by norm_num)
  interval_cases h : (k % 3)
  · left; rw [hmod]; simp
  · right; left; rw [hmod, pow_one]
  · right; right; rw [hmod]; simp [pow_succ, Equiv.Perm.mul_apply]

/-- **Within-`face₁` raw connectivity.**  Any kept dart of `face₁` raw-connects to the
reference dart `M.φ data.dart`. -/
lemma rawE_face₁_to_ref (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    {a : D} (hfa : M.dartFace a = data.face₁) (hne : a ≠ data.dart) :
    Relation.EqvGen (rawStep₁ data hsep) a (M.φ data.dart) := by
  have hsc : M.φ.SameCycle data.dart a := by
    have hf : M.dartFace a = M.dartFace data.dart := by rw [hfa]; rfl
    exact (Quotient.exact hf).symm
  rcases face₁_dart_cases data hsc with h | h | h
  · exact absurd h hne
  · subst h; exact Relation.EqvGen.refl _
  · subst h
    -- `M.φ dart → M.φ² dart` is one raw step; take its symm.
    exact Relation.EqvGen.symm _ _
      (rawEqvGen_phi_step (SubmapPlanar.keptDel₁_closed data hsep) (ref_kept data))

/-- **Any inner kept dart raw-connects to the reference, given its face does**.  Let `a` be a
kept dart whose face is in side 1, and suppose some dart `r₀` of the *same* face raw-connects
to the reference `M.φ data.dart`.  Then so does `a`.  (Within `face₁` we connect directly via
`rawE_face₁_to_ref`, ignoring `r₀`; on any other face all darts are kept, so `a` and `r₀`
share a whole-kept face and connect by a raw `φ`-walk.) -/
lemma rawE_inner_to_ref (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    {a r₀ : D} (hkept : a ∉ data.keptDel₁) (hfa : M.dartFace a ∈ data.side₁)
    (hsamef : M.dartFace a = M.dartFace r₀)
    (hr₀ : Relation.EqvGen (rawStep₁ data hsep) r₀ (M.φ data.dart)) :
    Relation.EqvGen (rawStep₁ data hsep) a (M.φ data.dart) := by
  classical
  by_cases hne : M.dartFace a = data.face₁
  · -- `face₁`: `a` is kept, hence `a ≠ dart`; connect directly.
    have had : a ≠ data.dart := fun h => hkept (h ▸ dart_mem_keptDel₁ data)
    exact rawE_face₁_to_ref data hsep hne had
  · -- non-`face₁` face: `a` and `r₀` share a whole-kept face.
    have hsc : M.φ.SameCycle a r₀ := Quotient.exact hsamef
    exact Relation.EqvGen.trans _ _ _ (rawE_within_face_ne_face₁ data hsep hfa hne hsc) hr₀

/-- **The chord-split adjacency step is a raw `α`-edge between kept darts.**  If `f → g` via
`ChordSplitAdj` with `f, g ∈ side₁`, the witnessing dart `d` (`dartFace d = f`,
`dartFace (α d) = g`, non-chord edge) and its reverse `M.α d` are *both kept*, and `d`,
`M.α d` are one raw `α`-step apart. -/
lemma rawE_chordSplitAdj_step (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    {f g : M.Face} (hf : f ∈ data.side₁) (hg : g ∈ data.side₁)
    (hadj : hNT.ChordSplitAdj u v f g) :
    ∃ d : D, M.dartFace d = f ∧ M.dartFace (M.α d) = g ∧
      d ∉ data.keptDel₁ ∧ M.α d ∉ data.keptDel₁ ∧
      Relation.EqvGen (rawStep₁ data hsep) d (M.α d) := by
  obtain ⟨d, hdf, hdg, _hbe, hch⟩ := hadj
  -- `d ≠ dart` (its edge is not the chord), so `d` is a kept inner dart of `f ∈ side₁`.
  have hd_ne : d ≠ data.dart := by
    intro h; apply hch; rw [h]; exact (hNT.chordDart_edge data.chord)
  have hαd_ne : M.α d ≠ data.dart := by
    intro h
    apply hch
    have : M.dartEdge d = M.dartEdge (M.α d) := (M.dartEdge_alpha d).symm
    rw [this, h]; exact (hNT.chordDart_edge data.chord)
  have hd_kept : d ∉ data.keptDel₁ :=
    inner_notMem_keptDel₁ data (by rw [hdf]; exact hf) hd_ne
  have hαd_kept : M.α d ∉ data.keptDel₁ :=
    inner_notMem_keptDel₁ data (by rw [hdg]; exact hg) hαd_ne
  exact ⟨d, hdf, hdg, hd_kept, hαd_kept,
    rawEqvGen_of_alpha (SubmapPlanar.keptDel₁_closed data hsep) hd_kept⟩

/-- **Every inner kept side-1 dart raw-connects to the reference.**  By induction on the
`ChordSplitAdj`-reachability of its face from `face₁`.  Base: `face₁` via `rawE_face₁_to_ref`.
Step: the adjacency dart joins the previous face to the current one by a raw `α`-edge between
kept darts, threading the reachability. -/
lemma rawE_inner_kept_to_ref (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    {g : M.Face} (hg : Relation.ReflTransGen (hNT.ChordSplitAdj u v) data.face₁ g) :
    ∀ a : D, M.dartFace a = g → a ∉ data.keptDel₁ →
      Relation.EqvGen (rawStep₁ data hsep) a (M.φ data.dart) := by
  classical
  induction hg with
  | refl =>
      intro a hfa hkept
      have had : a ≠ data.dart := fun h => hkept (h ▸ dart_mem_keptDel₁ data)
      exact rawE_face₁_to_ref data hsep hfa had
  | @tail f g hfg hstep ih =>
      -- `f ∈ side₁` (reachable from `face₁`), `g ∈ side₁`.
      intro a hfa hkept
      have hf_side : f ∈ data.side₁ := hfg
      have hg_side : g ∈ data.side₁ := data.side₁_closed hf_side hstep
      -- the adjacency dart `d`: `dartFace d = f`, `dartFace (α d) = g`, both kept.
      obtain ⟨d, hdf, hdg, hd_kept, hαd_kept, hd_raw⟩ :=
        rawE_chordSplitAdj_step data hsep hf_side hg_side hstep
      -- `d` (in `f`) connects to the reference by the induction hypothesis.
      have hd_ref : Relation.EqvGen (rawStep₁ data hsep) d (M.φ data.dart) :=
        ih d hdf hd_kept
      -- `α d` (in `g`) connects to the reference: `α d → d → ref`.
      have hαd_ref : Relation.EqvGen (rawStep₁ data hsep) (M.α d) (M.φ data.dart) :=
        Relation.EqvGen.trans _ _ _ (Relation.EqvGen.symm _ _ hd_raw) hd_ref
      -- `a` (in `g`, same face as `α d`) connects to the reference via `rawE_inner_to_ref`.
      exact rawE_inner_to_ref data hsep hkept (by rw [hfa]; exact hg_side)
        (by rw [hfa, hdg]) hαd_ref

/-- **Every kept side-1 dart raw-connects to the reference `M.φ data.dart`.**  An inner kept
dart goes through `rawE_inner_kept_to_ref`; an outer-arc kept dart connects via its raw
`α`-edge to its (inner kept) reverse, then through the inner case. -/
lemma rawE_kept_to_ref (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    {a : D} (hkept : a ∉ data.keptDel₁) :
    Relation.EqvGen (rawStep₁ data hsep) a (M.φ data.dart) := by
  classical
  -- `a ∈ keptSet₁ = (sideDarts₁ ∪ outerArc₁) \ {dart}`.
  have ha_in : a ∈ data.keptSet₁ := (data.mem_keptDel₁_iff a).mp hkept
  obtain ⟨haU, _⟩ := ha_in
  rcases haU with hinner | houter
  · -- inner: `dartFace a ∈ side₁`.
    have hreach : Relation.ReflTransGen (hNT.ChordSplitAdj u v) data.face₁ (M.dartFace a) :=
      hinner
    exact rawE_inner_kept_to_ref data hsep hreach a rfl hkept
  · -- outer-arc: `dartFace a = outerFace`, `dartFace (α a) ∈ side₁`.
    obtain ⟨_haouter, hαinner⟩ := houter
    -- `α a` is kept (inner side-1, not the chord dart): membership is `α`-invariant.
    have hαa_kept : M.α a ∉ data.keptDel₁ := fun h =>
      hkept ((SubmapPlanar.keptDel₁_sub data hsep a).2 h)
    -- `α a` connects to the reference (inner case).
    have hreach : Relation.ReflTransGen (hNT.ChordSplitAdj u v) data.face₁ (M.dartFace (M.α a)) :=
      hαinner
    have hαa_ref : Relation.EqvGen (rawStep₁ data hsep) (M.α a) (M.φ data.dart) :=
      rawE_inner_kept_to_ref data hsep hreach (M.α a) rfl hαa_kept
    -- `a → α a` is a raw `α`-step.
    exact Relation.EqvGen.trans _ _ _
      (rawEqvGen_of_alpha (SubmapPlanar.keptDel₁_closed data hsep) hkept) hαa_ref

/-- **The kept-side raw-reachability predicate, PROVED.**  Every two kept side-1 darts are
connected through the raw relation `rawStep₁`: each connects to the reference `M.φ data.dart`,
so they connect to each other.  This is the genuine dart-graph reachability "the side is the
closure of one Jordan region", proved unconditionally from the chord-split structure. -/
theorem keptSideRawConnected (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    ∀ x y : {d : D // d ∉ data.keptDel₁},
      Relation.EqvGen (rawStep₁ data hsep) x.1 y.1 := by
  intro x y
  exact Relation.EqvGen.trans _ _ _ (rawE_kept_to_ref data hsep x.2)
    (Relation.EqvGen.symm _ _ (rawE_kept_to_ref data hsep y.2))

end RawConnected



/-- **Raw reachability descends to kept-side connectivity.**  If every two kept side-1 darts
are connected through the raw relation `rawStep₁`, then the kept side-1 map `sideKeptMap₁` is
connected.  `SubmapPlanar.raw_eqvGen_descends` descends the raw `EqvGen` to a kept `EqvGen` on
the kept subtype's `keptStepRel`, which (the relation being symmetric) is the `ReflTransGen`
of the kept map's `dartStep` after identifying `sideSigma₁ = deleteSet M.σ keptDel₁` and
`sideAlpha₁ = keptAlpha`. -/
theorem keptSide₁_connected_of_rawConnected (data : hNT.ChordSplitData u v)
    (hsep : data.Separates)
    (hraw : ∀ x y : {d : D // d ∉ data.keptDel₁},
      Relation.EqvGen (rawStep₁ data hsep) x.1 y.1) :
    (sideKeptMap₁ data hsep).Connected := by
  classical
  set Del := data.keptDel₁ with hDel
  set hsub := SubmapPlanar.keptDel₁_sub data hsep with hhsub
  set hclosed := SubmapPlanar.keptDel₁_closed data hsep with hhclosed
  have hsymm : ∀ a b, SubmapPlanar.keptStepRel M Del hsub a b →
      SubmapPlanar.keptStepRel M Del hsub b a :=
    fun a b h => dartStepRel_symm (SubmapPlanar.keptAlpha_invol M Del hsub) h
  intro a b
  have hrawab : Relation.EqvGen (dartStepRel M.σ (rawAlpha M Del hclosed)) a.1 b.1 := hraw a b
  have hkept : Relation.EqvGen (SubmapPlanar.keptStepRel M Del hsub) a b :=
    SubmapPlanar.raw_eqvGen_descends M Del hclosed hsub hrawab
  have hreach : Relation.ReflTransGen (SubmapPlanar.keptStepRel M Del hsub) a b :=
    (eqvGen_iff_reflTransGen hsymm a b).1 hkept
  refine hreach.mono ?_
  intro x y hxy
  rcases hxy with hσ | hα
  · left
    show (sideKeptMap₁ data hsep).σ.SameCycle x y
    show data.sideSigma₁.SameCycle x y
    exact hσ
  · right
    show y = (sideKeptMap₁ data hsep).α x
    show y = data.sideAlpha₁ hsep x
    rw [SubmapPlanar.sideAlpha₁_eq_keptAlpha data hsep]
    exact hα

/-- **The kept side-1 map is connected — UNCONDITIONALLY.**  Combining the proved raw
reachability `keptSideRawConnected` with the descent `keptSide₁_connected_of_rawConnected`.
This is the one remaining topological input of the Chapter-35 chord case, now discharged from
the chord-split data and the separation `Separates` alone. -/
theorem sideKeptMap₁_connected (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    (sideKeptMap₁ data hsep).Connected :=
  keptSide₁_connected_of_rawConnected data hsep (keptSideRawConnected data hsep)



/-- **`Side₁IsDisk`, UNCONDITIONAL.**  Side 1 of a chord split of a genus-0 near-triangulation
is a combinatorial disk (`IsSphereMap`) given the chord-split data and the separation
`Separates` alone: the genus-0 / Euler-2 half is the proved genus core
(`SubmapPlanar.side₁IsDisk_of_connected`), and the connectivity half is the proved raw
reachability (Sections A0/A).  The required kept dart witness is `M.φ data.dart` (kept by
`ref_kept`).  No connectivity or genus hypothesis is taken. -/
theorem side₁IsDisk_unconditional (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    ProofsInTheBook.ChordDisk.Side₁IsDisk data hsep :=
  SubmapPlanar.side₁IsDisk_of_connected data hsep ⟨M.φ data.dart, ref_kept data⟩
    (sideKeptMap₁_connected data hsep)

end ProofsInTheBook.ChordSideClose







end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSideClose
import ProofsInTheBook.ChordSplitNT
-/
/- Source module: ProofsInTheBook.ChordReconClose -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordReconClose

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordSideClose

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



/-- **The side-1 region.**  The set of `M`-vertices that are the tail of some kept side-1 dart
(`d ∉ keptDel₁`).  This is the image of the side-1 vertex correspondence `ι` (Section 3). -/
def sideRegion₁ (data : hNT.ChordSplitData u v) : Set M.Vertex :=
  {w : M.Vertex | ∃ d : D, d ∉ data.keptDel₁ ∧ M.tail d = w}

/-- A kept dart's tail is in the side-1 region. -/
lemma tail_mem_sideRegion₁ (data : hNT.ChordSplitData u v) {d : D}
    (hd : d ∉ data.keptDel₁) : M.tail d ∈ sideRegion₁ data :=
  ⟨d, hd, rfl⟩



/-- **The side-1 vertex correspondence `ι`.**  Maps a side-1 vertex (a `freshSigma`-orbit) to
the `M`-vertex it restricts from: a `freshSigma`-orbit `⟦y⟧` is sent to `M.tail (proj y).val`
(`proj` projects the two fresh chord darts onto the anchors).  Well-defined: a `freshSigma`-orbit
restricts (`freshSigma_sameCycle_iff`) to a `sideSigma₁`-orbit, which restricts
(`filteredRotation_sameCycle_iff`) to an `M.σ`-orbit.  This is the concrete realization of
`ChordSideReconstruction.ι`. -/
noncomputable def sideVertexToM₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) :
    (data.sideMap₁ hsep a₀ a₁ hne).Vertex → M.Vertex :=
  Quotient.lift
    (fun y : {d : D // d ∉ data.keptDel₁} ⊕ Fin 2 =>
      M.tail (proj a₀ a₁ y).1)
    (by
      intro x y hxy
      -- `hxy : freshSigma.SameCycle x y`.
      have hfs : (freshSigma data.sideSigma₁ a₀ a₁ hne).SameCycle x y := hxy
      -- project to a `sideSigma₁`-SameCycle, then to an `M.σ`-SameCycle.
      have hss : data.sideSigma₁.SameCycle (proj a₀ a₁ x) (proj a₀ a₁ y) :=
        (freshSigma_sameCycle_iff data.sideSigma₁ hne x y).1 hfs
      have hM : M.σ.SameCycle (proj a₀ a₁ x).1 (proj a₀ a₁ y).1 :=
        (filteredRotation_sameCycle_iff M.σ data.keptDel₁ _ _).1 hss
      show M.tail (proj a₀ a₁ x).1 = M.tail (proj a₀ a₁ y).1
      exact Quotient.sound hM)

/-- `ι` on the class of an `inl`-dart `⟨d, …⟩` is `M.tail d` (`proj (inl x) = x`). -/
lemma sideVertexToM₁_inl (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (x : {d : D // d ∉ data.keptDel₁}) :
    sideVertexToM₁ data hsep a₀ a₁ hne
        (Quotient.mk (cycleSetoid (freshSigma data.sideSigma₁ a₀ a₁ hne)) (Sum.inl x))
      = M.tail x.1 := by
  show M.tail (proj a₀ a₁ (Sum.inl x)).1 = M.tail x.1
  rw [proj_inl]

/-- **`ι` lands in the side-1 region.**  Every side-1 vertex is the orbit of a kept dart
(`proj` of any representative is kept), whose tail is in `sideRegion₁`. -/
theorem sideVertexToM₁_mem (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (V : (data.sideMap₁ hsep a₀ a₁ hne).Vertex) :
    sideVertexToM₁ data hsep a₀ a₁ hne V ∈ sideRegion₁ data := by
  refine Quotient.inductionOn V (fun y => ?_)
  show M.tail (proj a₀ a₁ y).1 ∈ sideRegion₁ data
  exact tail_mem_sideRegion₁ data (proj a₀ a₁ y).2



/-- **`ι` is surjective onto the side-1 region (`ι_surj`).**  Every vertex of the side-1 region
`sideRegion₁` is the image under `ι` of some side-1 vertex.  This is the concrete orbit
surjection the orchestration named as the attackable target: the side vertices are
`sideSigma₁`-orbits of kept darts, `ι` restricts each to its `M.σ`-orbit, and every region
vertex (the tail of a kept dart) is hit. -/
theorem sideVertexToM₁_surjective (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) :
    ∀ ⦃w : M.Vertex⦄, w ∈ sideRegion₁ data →
      ∃ V : (data.sideMap₁ hsep a₀ a₁ hne).Vertex,
        sideVertexToM₁ data hsep a₀ a₁ hne V = w := by
  rintro w ⟨d, hd, rfl⟩
  -- the side vertex `⟦inl ⟨d, hd⟩⟧` maps to `M.tail d`.
  refine ⟨Quotient.mk (cycleSetoid (freshSigma data.sideSigma₁ a₀ a₁ hne))
    (Sum.inl ⟨d, hd⟩), ?_⟩
  exact sideVertexToM₁_inl data hsep a₀ a₁ hne ⟨d, hd⟩

/-- **The image of `ι` is exactly the side-1 region.**  Combining `sideVertexToM₁_mem`
(image ⊆ region) and `sideVertexToM₁_surjective` (region ⊆ image): `ι` is a surjection onto
`sideRegion₁`. -/
theorem sideVertexToM₁_range (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) :
    Set.range (sideVertexToM₁ data hsep a₀ a₁ hne) = sideRegion₁ data := by
  apply Set.eq_of_subset_of_subset
  · rintro w ⟨V, rfl⟩
    exact sideVertexToM₁_mem data hsep a₀ a₁ hne V
  · intro w hw
    obtain ⟨V, hV⟩ := sideVertexToM₁_surjective data hsep a₀ a₁ hne hw
    exact ⟨V, hV⟩



/-- `ι` of the head of an `inl`-dart `x` is `M.head x.val` (`sideAlpha₁` restricts `M.α`). -/
lemma sideVertexToM₁_head_inl (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (x : {d : D // d ∉ data.keptDel₁}) :
    sideVertexToM₁ data hsep a₀ a₁ hne
        (Quotient.mk (cycleSetoid (freshSigma data.sideSigma₁ a₀ a₁ hne))
          ((freshAlpha (data.sideAlpha₁ hsep)) (Sum.inl x)))
      = M.head x.1 := by
  -- `freshAlpha (inl x) = inl (sideAlpha₁ x)`, whose `ι` is `M.tail (sideAlpha₁ x).val`.
  rw [freshAlpha_inl]
  rw [sideVertexToM₁_inl data hsep a₀ a₁ hne (data.sideAlpha₁ hsep x)]
  -- `(sideAlpha₁ x).val = M.α x.val`, and `M.tail (M.α x.val) = M.head x.val`.
  rw [data.sideAlpha₁_apply_coe hsep x]
  rfl

/-- **The inner-edge correspondence.**  The side edge of an `inl`-dart `x` maps under `ι` to the
`M`-edge `s(M.tail x.val, M.head x.val)` = `M.dartEdge x.val`.  Hence the two `ι`-endpoints are
`M`-adjacent via the dart `x.val`. -/
theorem ι_adj_of_inl (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (x : {d : D // d ∉ data.keptDel₁}) :
    M.Adj
      (sideVertexToM₁ data hsep a₀ a₁ hne
        (Quotient.mk (cycleSetoid (freshSigma data.sideSigma₁ a₀ a₁ hne)) (Sum.inl x)))
      (sideVertexToM₁ data hsep a₀ a₁ hne
        (Quotient.mk (cycleSetoid (freshSigma data.sideSigma₁ a₀ a₁ hne))
          ((freshAlpha (data.sideAlpha₁ hsep)) (Sum.inl x)))) := by
  rw [sideVertexToM₁_inl data hsep a₀ a₁ hne x,
    sideVertexToM₁_head_inl data hsep a₀ a₁ hne x]
  exact M.adj_of_dart x.1











end ProofsInTheBook.ChordReconClose










end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordReconClose
import ProofsInTheBook.ChordDisk
-/
/- Source module: ProofsInTheBook.ChordSideNT -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordSideNT

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordDisk
open ProofsInTheBook.ChordReconClose

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



/-- **The correct-anchor boundary classification of side 1.**  The boundary-cycle and
inner-triangulation data of `sideMap₁` that the contiguous chord split produces: the side is a
simple graph, its outer face is the chord face (arc `u..v` plus the duplicated chord edge), the
boundary cycle is simple of length `≥ 3`, and every *other* face is a triangle.  These are the
`NearTriangulation (sideMap₁)` fields beyond the already-proved `IsSphereMap`.

It is the chord analogue of `FanSurgeryReconstruction`'s boundary fields, and the genuine
discrete Jordan–Schoenflies residue (kernel-decided genus-dependent at the orbit layer,
`CutFaceLabel.lean`); it is **isolated, not fabricated**. -/
structure ContiguousInterval (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) where
  /-- The side map is a simple graph (the fresh chord edge is a non-loop, non-parallel edge —
  the correct-anchor condition that `u, v` are non-adjacent boundary vertices). -/
  simpleGraph : (data.sideMap₁ hsep a₀ a₁ hne).IsSimpleGraph
  /-- The side outer face (the chord face: boundary arc `u..v` plus the duplicated chord). -/
  outerFace : (data.sideMap₁ hsep a₀ a₁ hne).Face
  /-- The side outer boundary cycle (the arc-plus-duplicated-chord cycle). -/
  outerCycle : BoundaryCycle (data.sideMap₁ hsep a₀ a₁ hne) outerFace
  /-- The side boundary vertex list is simple. -/
  outer_simple : outerCycle.VertexNodup
  /-- The side boundary has length at least three. -/
  outer_len : 3 ≤ outerCycle.length
  /-- Every non-outer side face is a triangle (the intact `M`-inner triangles plus the chord
  triangle `face₁`). -/
  inner_tri : ∀ f : (data.sideMap₁ hsep a₀ a₁ hne).Face, f ≠ outerFace →
    (data.sideMap₁ hsep a₀ a₁ hne).faceLen f = 3



/-- **The side-1 near-triangulation, assembled.**  Given the correct-anchor boundary
classification `ci`, the side-1 sphere fact (here taken as the genus-0 disk core output), and
the anchor-incidence fact, `sideMap₁` is a `NearTriangulation`: `sphere` from the disk core,
everything else from `ci`.  This is the assembly the prior round named
`ChordSideClassification`, now built modulo the single residue `ContiguousInterval`. -/
def chordSideNearTriangulation (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (hsphere : (data.sideMap₁ hsep a₀ a₁ hne).IsSphereMap)
    (ci : ContiguousInterval data hsep a₀ a₁ hne) :
    NearTriangulation (data.sideMap₁ hsep a₀ a₁ hne) where
  sphere := hsphere
  simpleGraph := ci.simpleGraph
  outerFace := ci.outerFace
  outerCycle := ci.outerCycle
  outer_simple := ci.outer_simple
  outer_len := ci.outer_len
  inner_tri := ci.inner_tri

/-- **The sphere field, discharged unconditionally from the two local disk facts.**  This is
`ChordDisk.side₁_isSphereMap_of_disk` with `Side₁IsDisk` supplied by
`ChordSideClose.side₁IsDisk_unconditional` (proved from `Separates` alone).  It needs only the
anchor-incidence fact `Side₁AnchorsShareFace` (the proved fact-2). -/
theorem side₁_sphere_unconditional (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (hshare : Side₁AnchorsShareFace data hsep a₀ a₁) :
    (data.sideMap₁ hsep a₀ a₁ hne).IsSphereMap :=
  side₁_isSphereMap_of_disk data hsep a₀ a₁ hne
    (ProofsInTheBook.ChordSideClose.side₁IsDisk_unconditional data hsep) hshare

/-- **The side-1 near-triangulation from the predicate + the proved disk core.**  Combines
`side₁_sphere_unconditional` (sphere discharged from the disk facts) with `ci`
(`ContiguousInterval`) to assemble the full `NearTriangulation (sideMap₁)`.  The only input
beyond `ContiguousInterval` is the anchor-incidence fact, which is the proved fact-2. -/
def chordSideNearTriangulation_of_share (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (hshare : Side₁AnchorsShareFace data hsep a₀ a₁)
    (ci : ContiguousInterval data hsep a₀ a₁ hne) :
    NearTriangulation (data.sideMap₁ hsep a₀ a₁ hne) :=
  chordSideNearTriangulation data hsep a₀ a₁ hne
    (side₁_sphere_unconditional data hsep a₀ a₁ hne hshare) ci





/-- **`ContiguousInterval` is satisfiable from a side near-triangulation** (non-vacuity).  Any
`NearTriangulation (sideMap₁)` projects onto a `ContiguousInterval` (its boundary fields).  So
the predicate is not unsatisfiable: it holds exactly when the side is a near-triangulation, and
`chordSideNearTriangulation` round-trips it. -/
def contiguousInterval_of_nearTriangulation (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (N : NearTriangulation (data.sideMap₁ hsep a₀ a₁ hne)) :
    ContiguousInterval data hsep a₀ a₁ hne where
  simpleGraph := N.simpleGraph
  outerFace := N.outerFace
  outerCycle := N.outerCycle
  outer_simple := N.outer_simple
  outer_len := N.outer_len
  inner_tri := N.inner_tri







end ProofsInTheBook.ChordSideNT











end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSideNT
import ProofsInTheBook.ChordSplitNT
-/
/- Source module: ProofsInTheBook.ChordSplitFinal -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordSplitFinal

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ListColoring
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ThomassenInduction
open ProofsInTheBook.ChordSplitNT
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ChordSideNT
open ProofsInTheBook.ChordDisk

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {α : Type u} [DecidableEq α]
variable {M : CombMap D} {hNT : NearTriangulation M} {u v : M.Vertex}



/-- **The side-1 residue datum** (the genuinely-unbuilt `ChordSideReconstruction` fields).

Carries exactly the fields of `ChordSideReconstruction hNT (sideRegion₁ data) L` for the
pinned `N := sideMap₁`, `ι := sideVertexToM₁` that are **not** proved upstream: the vertex
correspondence's injectivity and adjacency-faithfulness, the list transport, the side Thomassen
list hypotheses, and the strict vertex decrease.  These are the discrete Jordan/Schoenflies
content of the chord split that the abstract `CombMap` layer does not synthesize (the same
character as the chordless branch's `FanSurgeryReconstruction` and the upstream
`Separates`/`SphereChordSeparation` Jordan input). -/
structure ChordSideResidue (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (L : M.Vertex → Finset α) where
  /-- The side near-triangulation (the boundary/inner-triangulation classification). -/
  ci : ContiguousInterval data hsep a₀ a₁ hne
  /-- The anchor-incidence fact (the proved fact-2 at the chord-cap anchors) — supplies the
  disk-core `sphere`. -/
  hshare : Side₁AnchorsShareFace data hsep a₀ a₁
  /-- The vertex correspondence is injective. -/
  ι_inj : Function.Injective (sideVertexToM₁ data hsep a₀ a₁ hne)
  /-- The vertex correspondence carries side adjacency to `M`-adjacency (the full graph hom,
  including the two fresh chord darts). -/
  ι_adj : ∀ ⦃x y : (data.sideMap₁ hsep a₀ a₁ hne).Vertex⦄,
    (data.sideMap₁ hsep a₀ a₁ hne).toSimpleGraph.Adj x y →
      M.toSimpleGraph.Adj (sideVertexToM₁ data hsep a₀ a₁ hne x)
        (sideVertexToM₁ data hsep a₀ a₁ hne y)
  /-- The vertex correspondence reflects `M`-adjacency on the region (graph iso onto the
  induced subgraph). -/
  ι_adj_reflect : ∀ ⦃x y : (data.sideMap₁ hsep a₀ a₁ hne).Vertex⦄,
    M.toSimpleGraph.Adj (sideVertexToM₁ data hsep a₀ a₁ hne x)
        (sideVertexToM₁ data hsep a₀ a₁ hne y) →
      (data.sideMap₁ hsep a₀ a₁ hne).toSimpleGraph.Adj x y
  /-- The side's precolored boundary edge. -/
  pₛ : (data.sideMap₁ hsep a₀ a₁ hne).Vertex
  /-- The side's precolored boundary edge. -/
  qₛ : (data.sideMap₁ hsep a₀ a₁ hne).Vertex
  /-- The side's precolors. -/
  cpₛ : α
  /-- The side's precolors. -/
  cqₛ : α
  /-- The side Thomassen list hypotheses (with the pullback lists). -/
  hLₛ : ThomassenLists
    (chordSideNearTriangulation_of_share data hsep a₀ a₁ hne hshare ci)
    pₛ qₛ (fun x => L (sideVertexToM₁ data hsep a₀ a₁ hne x)) cpₛ cqₛ
  /-- The strict vertex decrease (the recursion fuel). -/
  smaller : (data.sideMap₁ hsep a₀ a₁ hne).V < M.V



/-- **The side-1 reconstruction in the generic recursion framing.**

Assembles `ChordSplitNT.ChordSideReconstruction hNT (sideRegion₁ data) L` with:
`N := sideMap₁`, `hN :=` the proved side near-triangulation, `ι := sideVertexToM₁`, `ι_mem`
and `ι_surj` proved upstream, and the residue datum supplying the genuinely-unbuilt fields.

This is the unified framing: the side IS a `ChordSideReconstruction` (the recursion's input
type), built from `M` directly via the proven genus/connectivity/face/orbit machinery, with
the discrete-Jordan residue isolated in `ChordSideResidue`. -/
noncomputable def chordSideReconstruction_of_chord (data : hNT.ChordSplitData u v)
    (hsep : data.Separates) (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (L : M.Vertex → Finset α)
    (res : ChordSideResidue data hsep a₀ a₁ hne L) :
    ChordSplitNT.ChordSideReconstruction hNT (sideRegion₁ data) L where
  Dₛ := {d : D // d ∉ data.keptDel₁} ⊕ Fin 2
  N := data.sideMap₁ hsep a₀ a₁ hne
  hN := chordSideNearTriangulation_of_share data hsep a₀ a₁ hne res.hshare res.ci
  ι := sideVertexToM₁ data hsep a₀ a₁ hne
  ι_inj := res.ι_inj
  ι_mem := fun x => sideVertexToM₁_mem data hsep a₀ a₁ hne x
  ι_surj := fun _ hw => sideVertexToM₁_surjective data hsep a₀ a₁ hne hw
  ι_adj := res.ι_adj
  ι_adj_reflect := res.ι_adj_reflect
  Lₛ := fun x => L (sideVertexToM₁ data hsep a₀ a₁ hne x)
  Lₛ_eq := fun _ => rfl
  pₛ := res.pₛ
  qₛ := res.qₛ
  cpₛ := res.cpₛ
  cqₛ := res.cqₛ
  hLₛ := res.hLₛ
  smaller := res.smaller







/-- **The residue is inhabited from a genuine side reconstruction** (non-vacuity).  Given a
`ContiguousInterval`, the anchor-incidence fact, and the genuinely-unbuilt vertex/list/decrease
data, the residue is constructed.  This is just its constructor, recorded to certify the residue
is a real (satisfiable) datum, not a hidden `False`. -/
def chordSideResidue_mk (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) (L : M.Vertex → Finset α)
    (ci : ContiguousInterval data hsep a₀ a₁ hne)
    (hshare : Side₁AnchorsShareFace data hsep a₀ a₁)
    (ι_inj : Function.Injective (sideVertexToM₁ data hsep a₀ a₁ hne))
    (ι_adj : ∀ ⦃x y : (data.sideMap₁ hsep a₀ a₁ hne).Vertex⦄,
      (data.sideMap₁ hsep a₀ a₁ hne).toSimpleGraph.Adj x y →
        M.toSimpleGraph.Adj (sideVertexToM₁ data hsep a₀ a₁ hne x)
          (sideVertexToM₁ data hsep a₀ a₁ hne y))
    (ι_adj_reflect : ∀ ⦃x y : (data.sideMap₁ hsep a₀ a₁ hne).Vertex⦄,
      M.toSimpleGraph.Adj (sideVertexToM₁ data hsep a₀ a₁ hne x)
          (sideVertexToM₁ data hsep a₀ a₁ hne y) →
        (data.sideMap₁ hsep a₀ a₁ hne).toSimpleGraph.Adj x y)
    (pₛ qₛ : (data.sideMap₁ hsep a₀ a₁ hne).Vertex) (cpₛ cqₛ : α)
    (hLₛ : ThomassenLists
      (chordSideNearTriangulation_of_share data hsep a₀ a₁ hne hshare ci)
      pₛ qₛ (fun x => L (sideVertexToM₁ data hsep a₀ a₁ hne x)) cpₛ cqₛ)
    (smaller : (data.sideMap₁ hsep a₀ a₁ hne).V < M.V) :
    ChordSideResidue data hsep a₀ a₁ hne L :=
  { ci := ci, hshare := hshare, ι_inj := ι_inj, ι_adj := ι_adj,
    ι_adj_reflect := ι_adj_reflect, pₛ := pₛ, qₛ := qₛ, cpₛ := cpₛ, cqₛ := cqₛ,
    hLₛ := hLₛ, smaller := smaller }





/-- **The chord-branch residue for a chord `(u, v)`.**  The `M`-vertex-level chord split glue,
the chord endpoints' distinctness, and — for each side — the data needed to present it as a
`ChordSideReconstruction` via `chordSideReconstruction_of_chord` (the per-side separation,
anchors, and side residue), with the side-1 region identified with `regions.s₁` and side-2 with
`regions.s₂`.

This bundles exactly the discrete-Jordan content of one chord branch: the two side
separations + boundary classifications + the regions glue.  Building it is the chord half of a
`ChordRecursiveDichotomy`; its fields are the genuine residue (no fabricated structure). -/
structure ChordBranchResidue (hNT : NearTriangulation M) (u v p q : M.Vertex)
    (L : M.Vertex → Finset α) (cp cq : α) where
  /-- The `M`-vertex-level chord split regions. -/
  regions : ChordSplitRegions hNT u v p q L cp cq
  /-- The chord endpoints are distinct. -/
  uv_ne : u ≠ v
  /-- The side-1 reconstruction (on region `s₁`, lists `L`). -/
  R₁ : ChordSplitNT.ChordSideReconstruction hNT regions.s₁ L
  /-- For each side-1 coloring with distinct chord-endpoint colors, a side-2 reconstruction
  on `s₂` with the forced lists. -/
  R₂ : (c₁ : M.Vertex → α) → c₁ u ≠ c₁ v → ChordSplitNT.ChordSideReconstruction hNT regions.s₂
    (regions.forcedLists c₁ L)

/-- **The recursion datum, assembled from the chord-branch residue.**  This is exactly
`ChordRecursionData.ofComponents` on the bundled regions/reconstructions — presenting the chord
branch in the form `chord_case_recursive` consumes. -/
def chordRecursionData_of_branchResidue {u v p q : M.Vertex} {L : M.Vertex → Finset α}
    {cp cq : α} (br : ChordBranchResidue hNT u v p q L cp cq) :
    ChordRecursionData hNT u v p q L cp cq :=
  ChordRecursionData.ofComponents br.regions br.uv_ne br.R₁ br.R₂



end ProofsInTheBook.ChordSplitFinal



namespace ProofsInTheBook.ChordSplitFinal

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ListColoring
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ThomassenInduction
open ProofsInTheBook.ChordSplitNT

variable {α : Type u} [DecidableEq α]





end ProofsInTheBook.ChordSplitFinal












end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSideNT
-/
/- Source module: ProofsInTheBook.ChordContiguous -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordContiguous

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordSideNT

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}









/-- **The chord endpoints are adjacent in `M` (the fresh chord edge is a real edge).** -/
theorem chordChoice_adj (data : hNT.ChordSplitData u v) :
    M.toSimpleGraph.Adj u v :=
  data.chord.adj

























end ProofsInTheBook.ChordContiguous













end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordContiguous
import ProofsInTheBook.ChordFaceCount
-/
/- Source module: ProofsInTheBook.ChordInnerTri -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordInnerTri

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount

universe u

variable {K : Type u} [Fintype K] [DecidableEq K]



/-- The kept combinatorial map's face permutation is `keptPhi β ρ = ρ * β`. -/
lemma keptCombMap_phi (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k) :
    (keptCombMap β ρ hβinv hβfix).φ = keptPhi β ρ := rfl



section Splice

variable (β ρ : Equiv.Perm K) {a₀ a₁ : K}

/-- An orbit is **splice-untouched** if it avoids both chord predecessors `β a₀`, `β a₁`. -/
def SpliceUntouched (β ρ : Equiv.Perm K) (a₀ a₁ k : K) : Prop :=
  ¬ (keptPhi β ρ).SameCycle k (β a₀) ∧ ¬ (keptPhi β ρ).SameCycle k (β a₁)

/-- `β (β a) = a` (involutivity, the form used here). -/
 lemma beta_beta' (hβinv : β * β = 1) (a : K) : β (β a) = a := by
  have := congrArg (fun f : Equiv.Perm K => f a) hβinv
  simpa [Equiv.Perm.mul_apply] using this

/-- On a `keptPhi`-orbit avoiding the predecessors, one `tracePhi`-step equals one
`keptPhi`-step (the swap fires only at `β a₀`, `β a₁`, which are not on the orbit). -/
lemma tracePhi_apply_eq_keptPhi_of_avoid (hβinv : β * β = 1) {k : K}
    (h : SpliceUntouched β ρ a₀ a₁ k) {c : K} (hc : (keptPhi β ρ).SameCycle k c) :
    tracePhi β ρ a₀ a₁ c = keptPhi β ρ c := by
  have h0 : c ≠ β a₀ := fun hca => h.1 (hca ▸ hc)
  have h1 : c ≠ β a₁ := fun hca => h.2 (hca ▸ hc)
  have hβc0 : β c ≠ a₀ := by
    intro hb; apply h0; have := congrArg β hb; rwa [beta_beta' β hβinv] at this
  have hβc1 : β c ≠ a₁ := by
    intro hb; apply h1; have := congrArg β hb; rwa [beta_beta' β hβinv] at this
  rw [tracePhi_other β ρ a₀ a₁ hβc0 hβc1]; rfl

/-- On a splice-untouched orbit, the `tracePhi`-iterate equals the `keptPhi`-iterate. -/
lemma tracePhi_iterate_eq_keptPhi (hβinv : β * β = 1) {k : K}
    (h : SpliceUntouched β ρ a₀ a₁ k) (n : ℕ) :
    (tracePhi β ρ a₀ a₁)^[n] k = (keptPhi β ρ)^[n] k := by
  induction n with
  | zero => rfl
  | succ n ih =>
      rw [Function.iterate_succ_apply', Function.iterate_succ_apply', ih]
      -- `(keptPhi)^[n] k` is on the keptPhi-orbit of `k`.
      have hsc : (keptPhi β ρ).SameCycle k ((keptPhi β ρ)^[n] k) :=
        ⟨(n : ℤ), by rw [zpow_natCast, Equiv.Perm.coe_pow]⟩
      exact tracePhi_apply_eq_keptPhi_of_avoid β ρ hβinv h hsc

/-- **On a splice-untouched orbit, `tracePhi` and `keptPhi` define the same cycle.** -/
lemma tracePhi_sameCycle_iff_keptPhi (hβinv : β * β = 1) {k : K}
    (h : SpliceUntouched β ρ a₀ a₁ k) (c : K) :
    (tracePhi β ρ a₀ a₁).SameCycle k c ↔ (keptPhi β ρ).SameCycle k c := by
  constructor
  · intro hsc
    obtain ⟨n, hn⟩ := hsc.exists_nat_pow_eq
    refine ⟨(n : ℤ), ?_⟩
    rw [zpow_natCast, Equiv.Perm.coe_pow]
    rw [Equiv.Perm.coe_pow] at hn
    rw [← hn, tracePhi_iterate_eq_keptPhi β ρ hβinv h n]
  · intro hsc
    obtain ⟨n, hn⟩ := hsc.exists_nat_pow_eq
    refine ⟨(n : ℤ), ?_⟩
    rw [zpow_natCast, Equiv.Perm.coe_pow]
    rw [Equiv.Perm.coe_pow] at hn
    rw [← hn, ← tracePhi_iterate_eq_keptPhi β ρ hβinv h n]

end Splice



section Transfer

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- **No fresh dart lies in a splice-untouched side face.**  If `inr j` were
`freshMap.φ`-SameCycle to `inl k`, its `faceProj` (`β a₀` or `β a₁`) would be
`tracePhi`-SameCycle to `k`, contradicting splice-untouchedness. -/
lemma no_inr_in_spliceUntouched_face {k : K}
    (h : SpliceUntouched β ρ a₀ a₁ k) (j : Fin 2) :
    ¬ (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle (Sum.inl k) (Sum.inr j) := by
  intro hsc
  have htrace := (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inl k) (Sum.inr j)).1 hsc
  simp only [faceProj_inl] at htrace
  -- `faceProj (inr j) ∈ {β a₀, β a₁}`; both contradict splice-untouchedness.
  rw [tracePhi_sameCycle_iff_keptPhi β ρ hβinv h] at htrace
  fin_cases j
  · exact h.1 (by simpa using htrace)
  · exact h.2 (by simpa using htrace)

/-- **The side face of a splice-untouched `inl k` consists exactly of the `inl`-images of
the `keptPhi`-orbit of `k`.**  The filter of darts in that face equals the `keptPhi`-orbit
filter mapped by `Sum.inl`. -/
lemma spliceUntouched_face_filter_eq {k : K}
    (h : SpliceUntouched β ρ a₀ a₁ k) :
    (Finset.univ.filter (fun x : K ⊕ Fin 2 =>
        Quotient.mk (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ) x
          = Quotient.mk (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ) (Sum.inl k)))
      = (Finset.univ.filter (fun c : K =>
          Quotient.mk (cycleSetoid (keptPhi β ρ)) c
            = Quotient.mk (cycleSetoid (keptPhi β ρ)) k)).map ⟨Sum.inl, Sum.inl_injective⟩ := by
  classical
  ext x
  simp only [Finset.mem_filter, Finset.mem_univ, true_and, Finset.mem_map,
    Function.Embedding.coeFn_mk]
  constructor
  · intro hx
    -- `x` is freshPhi-SameCycle to `inl k`.
    have hsc : (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle (Sum.inl k) x :=
      Quotient.exact hx.symm
    cases x with
    | inl c =>
        refine ⟨c, ?_, rfl⟩
        apply Quotient.sound
        -- want keptPhi.SameCycle c k, i.e. SameCycle k c symm.
        have htrace := (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inl k) (Sum.inl c)).1 hsc
        simp only [faceProj_inl] at htrace
        rw [tracePhi_sameCycle_iff_keptPhi β ρ hβinv h] at htrace
        exact htrace.symm
    | inr j => exact absurd hsc (no_inr_in_spliceUntouched_face β ρ hβinv hβfix hne h j)
  · rintro ⟨c, hc, rfl⟩
    -- keptPhi.SameCycle c k ⇒ freshPhi.SameCycle (inl k) (inl c).
    have hkp : (keptPhi β ρ).SameCycle k c := (Quotient.exact hc.symm)
    have htrace : (tracePhi β ρ a₀ a₁).SameCycle (faceProj β a₀ a₁ (Sum.inl k))
        (faceProj β a₀ a₁ (Sum.inl c)) := by
      simp only [faceProj_inl]
      exact (tracePhi_sameCycle_iff_keptPhi β ρ hβinv h c).2 hkp
    have hsc := (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inl k) (Sum.inl c)).2 htrace
    exact (Quotient.sound hsc.symm)

/-- **Face-SIZE transfer (UNCONDITIONAL).**  For a kept dart `k` whose `keptPhi`-orbit is
splice-untouched, the side face length of `inl k` equals the kept-map face length of `k`:
`faceLen sideMap₁ (dartFace (inl k)) = faceLen (keptCombMap β ρ) (dartFace k)`.  This is the
precise content "the cut reroutes only the chord-incident faces; inner faces are untouched
`keptPhi`-orbits" — FACE SIZE, not the kernel-refuted COUNT label. -/
theorem freshPhi_faceLen_inl_eq_keptPhi {k : K}
    (h : SpliceUntouched β ρ a₀ a₁ k) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).faceLen
        ((freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl k))
      = (keptCombMap β ρ hβinv hβfix).faceLen
        ((keptCombMap β ρ hβinv hβfix).dartFace k) := by
  classical
  show (Finset.univ.filter (fun x => Quotient.mk _ x
      = Quotient.mk (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ) (Sum.inl k))).card
    = (Finset.univ.filter (fun c => Quotient.mk _ c
      = Quotient.mk (cycleSetoid (keptCombMap β ρ hβinv hβfix).φ) k)).card
  rw [keptCombMap_phi β ρ hβinv hβfix]
  rw [spliceUntouched_face_filter_eq β ρ hβinv hβfix hne h, Finset.card_map]

end Transfer



section MTransfer

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

/-- One `keptPhi`-step on side 1 agrees with one `M.φ`-step, provided the `M.φ`-successor
is kept. -/
lemma sideKeptPhi_apply_eq_phi (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (k : {d : D // d ∉ data.keptDel₁}) (hnext : M.φ k.1 ∉ data.keptDel₁) :
    (keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ k : D) = M.φ k.1 := by
  -- `keptPhi k = sideSigma₁ (sideAlpha₁ k)`.
  show (data.sideSigma₁ (data.sideAlpha₁ hsep k) : {d : D // d ∉ data.keptDel₁}).1 = M.φ k.1
  -- `sideAlpha₁ k` has coe `M.α k.1`; `sideSigma₁ = filteredRotation M.σ keptDel₁`.
  have hσnext : M.σ ((data.sideAlpha₁ hsep k : {d : D // d ∉ data.keptDel₁}) : D)
      ∉ data.keptDel₁ := by
    rw [sideAlpha₁_apply_coe]
    -- `M.σ (M.α k.1) = M.φ k.1`.
    show M.σ (M.α k.1) ∉ data.keptDel₁
    have : M.φ k.1 = M.σ (M.α k.1) := rfl
    rwa [← this]
  show (FilteredRotation.filteredRotation M.σ data.keptDel₁
      (data.sideAlpha₁ hsep k) : {d : D // d ∉ data.keptDel₁}).1 = M.φ k.1
  rw [FilteredRotation.filteredRotation_apply_of_next_kept M.σ data.keptDel₁
    (data.sideAlpha₁ hsep k) hσnext, sideAlpha₁_apply_coe]
  rfl

/-- **The `M.φ`-orbit of a kept dart stays kept.**  Every `M.φ`-iterate of `k.1` avoids the
deleted set.  (Provided here as a hypothesis; established below for inner side faces.) -/
def OrbitKept (data : hNT.ChordSplitData u v) (k : {d : D // d ∉ data.keptDel₁}) : Prop :=
  ∀ n : ℕ, M.φ^[n] k.1 ∉ data.keptDel₁

/-- On a kept orbit, the `keptPhi`-iterate coincides (under coercion) with the `M.φ`-iterate. -/
lemma sideKeptPhi_iterate_eq_phi (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (k : {d : D // d ∉ data.keptDel₁}) (hkept : OrbitKept data k) (n : ℕ) :
    ((keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁)^[n] k : D) = M.φ^[n] k.1 := by
  induction n with
  | zero => rfl
  | succ n ih =>
      rw [Function.iterate_succ_apply', Function.iterate_succ_apply']
      -- the iterate is `⟨M.φ^[n] k.1, _⟩` by `ih`; its φ-successor is `M.φ^[n+1] k.1`, kept.
      have hkn : ((keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁)^[n] k : D)
          = M.φ^[n] k.1 := ih
      have hnext : M.φ ((keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁)^[n] k : D)
          ∉ data.keptDel₁ := by
        rw [hkn]
        have := hkept (n + 1)
        rwa [Function.iterate_succ_apply'] at this
      rw [sideKeptPhi_apply_eq_phi data hsep _ hnext, hkn]

/-- **`keptPhi` and `M.φ` define the same cycle on a kept orbit.** -/
lemma sideKeptPhi_sameCycle_iff_phi (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (k : {d : D // d ∉ data.keptDel₁}) (hkept : OrbitKept data k)
    (x : {d : D // d ∉ data.keptDel₁}) :
    (keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁).SameCycle k x ↔ M.φ.SameCycle k.1 x.1 := by
  constructor
  · intro hsc
    obtain ⟨n, hn⟩ := hsc.exists_nat_pow_eq
    refine ⟨(n : ℤ), ?_⟩
    rw [zpow_natCast, Equiv.Perm.coe_pow]
    rw [Equiv.Perm.coe_pow] at hn
    have := congrArg (Subtype.val) hn
    rw [sideKeptPhi_iterate_eq_phi data hsep k hkept n] at this
    exact this
  · intro hsc
    obtain ⟨n, hn⟩ := hsc.exists_nat_pow_eq
    refine ⟨(n : ℤ), ?_⟩
    rw [zpow_natCast, Equiv.Perm.coe_pow]
    rw [Equiv.Perm.coe_pow] at hn
    apply Subtype.ext
    rw [sideKeptPhi_iterate_eq_phi data hsep k hkept n]
    exact hn

/-- Every dart on the `M.φ`-orbit of a kept dart `k` (with kept orbit) is itself kept. -/
lemma orbitKept_mem (data : hNT.ChordSplitData u v)
    (k : {d : D // d ∉ data.keptDel₁}) (hkept : OrbitKept data k)
    {d : D} (hd : M.φ.SameCycle k.1 d) : d ∉ data.keptDel₁ := by
  obtain ⟨n, hn⟩ := hd.exists_nat_pow_eq
  rw [Equiv.Perm.coe_pow] at hn
  rw [← hn]
  exact hkept n

/-- **The kept side face length equals `M`'s face length on a kept orbit.** -/
theorem sideKeptMap₁_faceLen_eq_M (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (k : {d : D // d ∉ data.keptDel₁}) (hkept : OrbitKept data k) :
    (sideKeptMap₁ data hsep).faceLen ((sideKeptMap₁ data hsep).dartFace k)
      = M.faceLen (M.dartFace k.1) := by
  classical
  show (Finset.univ.filter (fun x => Quotient.mk _ x
      = Quotient.mk (cycleSetoid (sideKeptMap₁ data hsep).φ) k)).card
    = (Finset.univ.filter (fun d => Quotient.mk _ d
      = Quotient.mk (cycleSetoid M.φ) k.1)).card
  have hφ : (sideKeptMap₁ data hsep).φ
      = keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ := rfl
  -- the kept filter maps bijectively via `Subtype.val` onto the M filter.
  rw [show (Finset.univ.filter (fun x => Quotient.mk _ x
      = Quotient.mk (cycleSetoid (sideKeptMap₁ data hsep).φ) k)).card
      = ((Finset.univ.filter (fun x : {d : D // d ∉ data.keptDel₁} =>
          Quotient.mk _ x = Quotient.mk (cycleSetoid (sideKeptMap₁ data hsep).φ) k)).map
          ⟨Subtype.val, Subtype.val_injective⟩).card from (Finset.card_map _).symm]
  congr 1
  ext d
  simp only [Finset.mem_map, Finset.mem_filter, Finset.mem_univ, true_and,
    Function.Embedding.coeFn_mk]
  constructor
  · rintro ⟨c, hcd, rfl⟩
    -- `keptPhi.SameCycle k c`  ⇒  `M.φ.SameCycle k.1 c.1`.
    have hsc : (sideKeptMap₁ data hsep).φ.SameCycle k c := Quotient.exact hcd.symm
    rw [hφ, sideKeptPhi_sameCycle_iff_phi data hsep k hkept] at hsc
    exact Quotient.sound hsc.symm
  · intro hd
    have hsc : M.φ.SameCycle k.1 d := Quotient.exact hd.symm
    have hdkept : d ∉ data.keptDel₁ := orbitKept_mem data k hkept hsc
    refine ⟨⟨d, hdkept⟩, ?_, rfl⟩
    apply Quotient.sound
    show (sideKeptMap₁ data hsep).φ.SameCycle (⟨d, hdkept⟩ : {d : D // d ∉ data.keptDel₁}) k
    refine Equiv.Perm.SameCycle.symm ?_
    rw [hφ, sideKeptPhi_sameCycle_iff_phi data hsep k hkept ⟨d, hdkept⟩]
    exact hsc

/-- **`OrbitKept` is discharged for a genuine inner side-1 face.**  If `k.1` is a side-1
inner dart (`M`-face in `side₁`) whose `M`-face is not the chord face `face₁`, then its whole
`M.φ`-orbit stays kept: each iterate keeps the same (side-1, non-`face₁`) `M`-face, hence lies
in `sideDarts₁ \ {dart} ⊆ keptSet₁`.  This removes `OrbitKept` from the residue: it follows
from the side-1 face classification alone. -/
theorem orbitKept_of_side₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (k : {d : D // d ∉ data.keptDel₁})
    (hside : M.dartFace k.1 ∈ data.side₁) (hface₁ : M.dartFace k.1 ≠ data.face₁) :
    OrbitKept data k := by
  intro n
  rw [data.mem_keptDel₁_iff]
  -- `M.φ^[n] k.1` has the same `M`-face as `k.1`.
  have hsameface : M.dartFace (M.φ^[n] k.1) = M.dartFace k.1 := by
    induction n with
    | zero => rfl
    | succ n ih => rw [Function.iterate_succ_apply', M.dartFace_phi, ih]
  -- in `sideDarts₁`:
  have hin : M.φ^[n] k.1 ∈ data.sideDarts₁ := by
    show M.dartFace (M.φ^[n] k.1) ∈ data.side₁
    rw [hsameface]; exact hside
  -- not the chord dart (its face is `face₁`):
  have hne_dart : M.φ^[n] k.1 ≠ data.dart := by
    intro he
    apply hface₁
    have : M.dartFace (M.φ^[n] k.1) = data.face₁ := by rw [he]; rfl
    rwa [hsameface] at this
  -- hence in `keptSet₁ = (sideDarts₁ ∪ outerArc₁) \ {dart}`.
  show M.φ^[n] k.1 ∈ data.keptSet₁
  exact ⟨Or.inl hin, by simpa using hne_dart⟩



/-- **The side face of an untouched inner `inl k` has the same length as its `M`-face.** -/
theorem sideMap₁_faceLen_inl_eq_M (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (k : {d : D // d ∉ data.keptDel₁})
    (huntouched : SpliceUntouched (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ k)
    (hkept : OrbitKept data k) :
    (data.sideMap₁ hsep a₀ a₁ hne).faceLen
        ((data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl k))
      = M.faceLen (M.dartFace k.1) := by
  have h1 := freshPhi_faceLen_inl_eq_keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁
    (data.sideAlpha₁_involutive hsep) (data.sideAlpha₁_no_fixed hsep) hne huntouched
  have h2 := sideKeptMap₁_faceLen_eq_M data hsep k hkept
  -- `sideMap₁ = freshMap (sideAlpha₁) (sideSigma₁) …`; `sideKeptMap₁ = keptCombMap …`.
  rw [show data.sideMap₁ hsep a₀ a₁ hne
      = freshMap (data.sideAlpha₁ hsep) data.sideSigma₁
          (data.sideAlpha₁_involutive hsep) (data.sideAlpha₁_no_fixed hsep) a₀ a₁ hne from rfl]
  rw [h1]
  rw [show keptCombMap (data.sideAlpha₁ hsep) data.sideSigma₁
      (data.sideAlpha₁_involutive hsep) (data.sideAlpha₁_no_fixed hsep)
      = sideKeptMap₁ data hsep from rfl]
  exact h2

/-- **An untouched inner side face, mapping to a non-outer `M`-face, is a triangle.** -/
theorem sideMap₁_faceLen_inl_eq_three (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (k : {d : D // d ∉ data.keptDel₁})
    (huntouched : SpliceUntouched (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ k)
    (hkept : OrbitKept data k)
    (hMinner : M.dartFace k.1 ≠ hNT.outerFace) :
    (data.sideMap₁ hsep a₀ a₁ hne).faceLen
        ((data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl k)) = 3 := by
  rw [sideMap₁_faceLen_inl_eq_M data hsep a₀ a₁ hne k huntouched hkept]
  exact hNT.inner_tri (M.dartFace k.1) hMinner



/-- **A side-1 inner face (not the chord face) that is splice-untouched is a triangle**, with
`OrbitKept` and `M`-non-outerness *both discharged* from the side-1 classification.  The only
remaining geometric input is `SpliceUntouched` (the correct-anchor condition: the orbit avoids
the chord predecessors) together with the face-membership data. -/
theorem sideMap₁_faceLen_inl_three_of_side₁ (data : hNT.ChordSplitData u v)
    (hsep : data.Separates) (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (k : {d : D // d ∉ data.keptDel₁})
    (hside : M.dartFace k.1 ∈ data.side₁) (hface₁ : M.dartFace k.1 ≠ data.face₁)
    (huntouched : SpliceUntouched (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ k) :
    (data.sideMap₁ hsep a₀ a₁ hne).faceLen
        ((data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl k)) = 3 :=
  sideMap₁_faceLen_inl_eq_three data hsep a₀ a₁ hne k huntouched
    (orbitKept_of_side₁ data hsep k hside hface₁)
    (data.side₁_subset_nonouter hside)

end MTransfer

open ProofsInTheBook.ChordContiguous

section Discharge

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

















end Discharge

end ProofsInTheBook.ChordInnerTri















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordInnerTri
-/
/- Source module: ProofsInTheBook.ChordFaceClass -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordFaceClass

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordInnerTri
open ProofsInTheBook.ChordContiguous

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



/-- **Every side face has a kept-`inl` representative** (the face-level `ι_surj`).  For any face
`f` of `sideMap₁`, there is a kept dart `k` with `dartFace (inl k) = f`.  Proof: a face is a
`freshMap.φ`-orbit; pick any representative `x`, then `f = dartFace (inl (faceProj x))` because
`x` is `φ`-SameCycle to `inl (faceProj x)` (`ChordFaceCount.freshPhi_sameCycle_inl_faceProj`),
and `faceProj x` is a kept dart of `K`. -/
theorem sideFace_has_inl_rep (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (f : (data.sideMap₁ hsep a₀ a₁ hne).Face) :
    ∃ k : {d : D // d ∉ data.keptDel₁},
      (data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl k) = f := by
  classical
  refine Quotient.inductionOn f (fun x => ?_)
  -- `f = ⟦x⟧`; take `k = faceProj x` and use `freshPhi_sameCycle_inl_faceProj`.
  refine ⟨faceProj (data.sideAlpha₁ hsep) a₀ a₁ x, ?_⟩
  show Quotient.mk (cycleSetoid (data.sideMap₁ hsep a₀ a₁ hne).φ)
      (Sum.inl (faceProj (data.sideAlpha₁ hsep) a₀ a₁ x))
    = Quotient.mk (cycleSetoid (data.sideMap₁ hsep a₀ a₁ hne).φ) x
  apply Quotient.sound
  -- need `(sideMap₁).φ.SameCycle (inl (faceProj x)) x`; we have the reverse from ChordFaceCount.
  have h := freshPhi_sameCycle_inl_faceProj (data.sideAlpha₁ hsep) data.sideSigma₁
    (data.sideAlpha₁_involutive hsep) (data.sideAlpha₁_no_fixed hsep) hne x
  -- `h : (freshMap …).φ.SameCycle x (inl (faceProj x))`; `sideMap₁ = freshMap …`.
  exact h.symm



/-- **Every kept dart has its `M`-face in `side₁` or equal to the outer face** (unconditional).
A kept dart `k.1 ∈ keptSet₁` is in `sideDarts₁` (face `∈ side₁`) or in `outerArc₁`
(face `= outerFace`). -/
theorem keptDart_face_side₁_or_outer (data : hNT.ChordSplitData u v)
    (k : {d : D // d ∉ data.keptDel₁}) :
    M.dartFace k.1 ∈ data.side₁ ∨ M.dartFace k.1 = hNT.outerFace := by
  -- `k.1 ∉ keptDel₁ ↔ k.1 ∈ keptSet₁ = (sideDarts₁ ∪ outerArc₁) \ {dart}`.
  have hk : k.1 ∈ data.keptSet₁ := (data.mem_keptDel₁_iff k.1).1 k.2
  obtain ⟨hU, _⟩ := hk
  rcases hU with hin | hout
  · -- `k.1 ∈ sideDarts₁`, i.e. `M.dartFace k.1 ∈ side₁`.
    exact Or.inl hin
  · -- `k.1 ∈ outerArc₁`, i.e. `M.dartFace k.1 = outerFace`.
    exact Or.inr hout.1

/-- **A kept dart whose `M`-face is neither outer nor the chord face lies in `side₁`.**  The
contrapositive packaging of the dichotomy: if `M.dartFace k.1 ≠ outerFace` then it is in `side₁`
(and we carry the `≠ face₁` hypothesis alongside).  Unconditional. -/
theorem keptDart_face_mem_side₁ (data : hNT.ChordSplitData u v)
    (k : {d : D // d ∉ data.keptDel₁}) (houter : M.dartFace k.1 ≠ hNT.outerFace) :
    M.dartFace k.1 ∈ data.side₁ :=
  (keptDart_face_side₁_or_outer data k).resolve_right houter

























end ProofsInTheBook.ChordFaceClass













end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordFaceClass
-/
/- Source module: ProofsInTheBook.ChordBoundaryOrbit -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordBoundaryOrbit

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordInnerTri
open ProofsInTheBook.ChordContiguous
open ProofsInTheBook.ChordFaceClass

universe u

variable {K : Type u} [Fintype K] [DecidableEq K]



section Trace

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- **The fresh chord dart `inr 0` is freshPhi-SameCycle to `inl (β a₀)`** (explicit trace).
`φ̃ (inl (β a₀)) = inr 0`, so a single `φ`-step joins them. -/
lemma chordDart_sameCycle_b0 :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle (Sum.inr 0) (Sum.inl (β a₀)) := by
  refine ⟨-1, ?_⟩
  rw [zpow_neg, zpow_one, Equiv.Perm.inv_eq_iff_eq, freshMap_phi_inl_b0 β ρ hβinv hβfix hne]

/-- **The fresh chord dart `inr 1` is freshPhi-SameCycle to `inl (β a₁)`** (explicit trace). -/
lemma chordDart_sameCycle_b1 :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle (Sum.inr 1) (Sum.inl (β a₁)) := by
  refine ⟨-1, ?_⟩
  rw [zpow_neg, zpow_one, Equiv.Perm.inv_eq_iff_eq, freshMap_phi_inl_b1 β ρ hβinv hβfix hne]

/-- **The chord-dart `inr 0`'s side face equals the side face of `inl (β a₀)`** (the boundary
orbit traced concretely from the chord dart's known position). -/
lemma chordDart_face_eq_b0 :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inr 0)
      = (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl (β a₀)) :=
  Quotient.sound (chordDart_sameCycle_b0 β ρ hβinv hβfix hne)

/-- **The chord-dart `inr 1`'s side face equals the side face of `inl (β a₁)`.** -/
lemma chordDart_face_eq_b1 :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inr 1)
      = (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl (β a₁)) :=
  Quotient.sound (chordDart_sameCycle_b1 β ρ hβinv hβfix hne)

end Trace



section Membership

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- **Side faces of two `inl` darts coincide iff their `tracePhi`-orbits do.** -/
lemma sideFace_inl_eq_iff_tracePhi (k c : K) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl k)
        = (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl c)
      ↔ (tracePhi β ρ a₀ a₁).SameCycle k c := by
  constructor
  · intro h
    have hsc : (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle (Sum.inl k) (Sum.inl c) :=
      Quotient.exact h
    have := (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inl k) (Sum.inl c)).1 hsc
    simpa only [faceProj_inl] using this
  · intro h
    apply Quotient.sound
    refine (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inl k) (Sum.inl c)).2 ?_
    simpa only [faceProj_inl] using h

/-- **The side face of `inl k` is the chord-dart-0 face iff `k` is `tracePhi`-SameCycle to
`β a₀`.** -/
lemma sideFace_eq_chordOrbit0_iff (k : K) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl k)
        = (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inr 0)
      ↔ (tracePhi β ρ a₀ a₁).SameCycle k (β a₀) := by
  rw [chordDart_face_eq_b0 β ρ hβinv hβfix hne, sideFace_inl_eq_iff_tracePhi β ρ hβinv hβfix hne]

/-- **The side face of `inl k` is the chord-dart-1 face iff `k` is `tracePhi`-SameCycle to
`β a₁`.** -/
lemma sideFace_eq_chordOrbit1_iff (k : K) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl k)
        = (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inr 1)
      ↔ (tracePhi β ρ a₀ a₁).SameCycle k (β a₁) := by
  rw [chordDart_face_eq_b1 β ρ hβinv hβfix hne, sideFace_inl_eq_iff_tracePhi β ρ hβinv hβfix hne]

end Membership



/-- `β (β a) = a` (involutivity, the local form). -/
 lemma betaBeta (β : Equiv.Perm K) (hβinv : β * β = 1) (a : K) : β (β a) = a := by
  have := congrArg (fun f : Equiv.Perm K => f a) hβinv
  simpa [Equiv.Perm.mul_apply] using this

/-- `keptPhi (β a₀) = ρ a₀` (since `β (β a₀) = a₀`). -/
lemma keptPhi_b0 (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (a₀ : K) :
    keptPhi β ρ (β a₀) = ρ a₀ := by
  show ρ (β (β a₀)) = ρ a₀
  rw [betaBeta β hβinv]

/-- `keptPhi (β a₁) = ρ a₁`. -/
lemma keptPhi_b1 (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (a₁ : K) :
    keptPhi β ρ (β a₁) = ρ a₁ := by
  show ρ (β (β a₁)) = ρ a₁
  rw [betaBeta β hβinv]

/-- **The walk lemma.**  Iterating `keptPhi` from `β a₀`, every iterate is `tracePhi`-SameCycle
to `β a₀` or to `β a₁`.  Proved by induction tracking which of the two split threads the iterate
sits on; the swap re-routes the thread exactly at the two predecessors. -/
lemma tracePhi_reaches_keptPhi_iterate_b0 (β ρ : Equiv.Perm K) (hβinv : β * β = 1)
    (a₀ a₁ : K) (n : ℕ) :
    (tracePhi β ρ a₀ a₁).SameCycle (β a₀) ((keptPhi β ρ)^[n] (β a₀))
      ∨ (tracePhi β ρ a₀ a₁).SameCycle (β a₁) ((keptPhi β ρ)^[n] (β a₀)) := by
  induction n with
  | zero => exact Or.inl (by simpa using Equiv.Perm.SameCycle.rfl)
  | succ n ih =>
      set c := (keptPhi β ρ)^[n] (β a₀) with hc
      rw [Function.iterate_succ_apply', ← hc]
      by_cases h0 : c = β a₀
      · -- keptPhi c = keptPhi (β a₀) = ρ a₀ = tracePhi (β a₁); hop to the β a₁ thread.
        right
        rw [h0, keptPhi_b0 β ρ hβinv, ← tracePhi_b1 β ρ hβinv a₀ a₁]
        exact ⟨1, by rw [zpow_one]⟩
      · by_cases h1 : c = β a₁
        · -- keptPhi c = ρ a₁ = tracePhi (β a₀); hop to the β a₀ thread.
          left
          rw [h1, keptPhi_b1 β ρ hβinv, ← tracePhi_b0 β ρ hβinv a₀ a₁]
          exact ⟨1, by rw [zpow_one]⟩
        · -- non-predecessor: keptPhi c = tracePhi c, stay on the same thread.
          have hβc0 : β c ≠ a₀ := by
            intro hb; apply h0; have := congrArg β hb
            rwa [betaBeta β hβinv] at this
          have hβc1 : β c ≠ a₁ := by
            intro hb; apply h1; have := congrArg β hb
            rwa [betaBeta β hβinv] at this
          have heq : keptPhi β ρ c = tracePhi β ρ a₀ a₁ c := by
            rw [tracePhi_other β ρ a₀ a₁ hβc0 hβc1]; rfl
          rw [heq]
          have hstep : (tracePhi β ρ a₀ a₁).SameCycle c (tracePhi β ρ a₀ a₁ c) :=
            ⟨1, by rw [zpow_one]⟩
          rcases ih with h | h
          · exact Or.inl (h.trans hstep)
          · exact Or.inr (h.trans hstep)

/-- **The unconditional orbit trichotomy (`β a₀` thread).**  Every kept dart `c` whose
`keptPhi`-orbit meets `β a₀` is `tracePhi`-SameCycle to `β a₀` or to `β a₁`. -/
lemma tracePhi_reaches_of_keptPhi_sameCycle_b0 (β ρ : Equiv.Perm K) (hβinv : β * β = 1)
    {a₀ a₁ c : K} (h : (keptPhi β ρ).SameCycle (β a₀) c) :
    (tracePhi β ρ a₀ a₁).SameCycle (β a₀) c ∨ (tracePhi β ρ a₀ a₁).SameCycle (β a₁) c := by
  obtain ⟨n, hn⟩ := h.exists_nat_pow_eq
  rw [Equiv.Perm.coe_pow] at hn
  rw [← hn]
  exact tracePhi_reaches_keptPhi_iterate_b0 β ρ hβinv a₀ a₁ n

/-- Symmetric walk from the `β a₁` thread. -/
lemma tracePhi_reaches_keptPhi_iterate_b1 (β ρ : Equiv.Perm K) (hβinv : β * β = 1)
    (a₀ a₁ : K) (n : ℕ) :
    (tracePhi β ρ a₀ a₁).SameCycle (β a₀) ((keptPhi β ρ)^[n] (β a₁))
      ∨ (tracePhi β ρ a₀ a₁).SameCycle (β a₁) ((keptPhi β ρ)^[n] (β a₁)) := by
  induction n with
  | zero => exact Or.inr (by simpa using Equiv.Perm.SameCycle.rfl)
  | succ n ih =>
      set c := (keptPhi β ρ)^[n] (β a₁) with hc
      rw [Function.iterate_succ_apply', ← hc]
      by_cases h0 : c = β a₀
      · right
        rw [h0, keptPhi_b0 β ρ hβinv, ← tracePhi_b1 β ρ hβinv a₀ a₁]
        exact ⟨1, by rw [zpow_one]⟩
      · by_cases h1 : c = β a₁
        · left
          rw [h1, keptPhi_b1 β ρ hβinv, ← tracePhi_b0 β ρ hβinv a₀ a₁]
          exact ⟨1, by rw [zpow_one]⟩
        · have hβc0 : β c ≠ a₀ := by
            intro hb; apply h0; have := congrArg β hb
            rwa [betaBeta β hβinv] at this
          have hβc1 : β c ≠ a₁ := by
            intro hb; apply h1; have := congrArg β hb
            rwa [betaBeta β hβinv] at this
          have heq : keptPhi β ρ c = tracePhi β ρ a₀ a₁ c := by
            rw [tracePhi_other β ρ a₀ a₁ hβc0 hβc1]; rfl
          rw [heq]
          have hstep : (tracePhi β ρ a₀ a₁).SameCycle c (tracePhi β ρ a₀ a₁ c) :=
            ⟨1, by rw [zpow_one]⟩
          rcases ih with h | h
          · exact Or.inl (h.trans hstep)
          · exact Or.inr (h.trans hstep)

/-- **The unconditional orbit trichotomy (`β a₁` thread).** -/
lemma tracePhi_reaches_of_keptPhi_sameCycle_b1 (β ρ : Equiv.Perm K) (hβinv : β * β = 1)
    {a₀ a₁ c : K} (h : (keptPhi β ρ).SameCycle (β a₁) c) :
    (tracePhi β ρ a₀ a₁).SameCycle (β a₀) c ∨ (tracePhi β ρ a₀ a₁).SameCycle (β a₁) c := by
  obtain ⟨n, hn⟩ := h.exists_nat_pow_eq
  rw [Equiv.Perm.coe_pow] at hn
  rw [← hn]
  exact tracePhi_reaches_keptPhi_iterate_b1 β ρ hβinv a₀ a₁ n



section Untouched

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- **The KEY fresh-angle theorem.**  A kept dart whose side face is neither chord-dart face is
splice-untouched. -/
theorem spliceUntouched_of_face_ne_chordOrbits {k : K}
    (h0 : (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl k)
        ≠ (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inr 0))
    (h1 : (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl k)
        ≠ (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inr 1)) :
    SpliceUntouched β ρ a₀ a₁ k := by
  -- ¬ tracePhi.SameCycle k (β a₀)  and  ¬ tracePhi.SameCycle k (β a₁).
  have ht0 : ¬ (tracePhi β ρ a₀ a₁).SameCycle k (β a₀) := by
    rw [← sideFace_eq_chordOrbit0_iff β ρ hβinv hβfix hne]; exact h0
  have ht1 : ¬ (tracePhi β ρ a₀ a₁).SameCycle k (β a₁) := by
    rw [← sideFace_eq_chordOrbit1_iff β ρ hβinv hβfix hne]; exact h1
  refine ⟨?_, ?_⟩
  · -- ¬ keptPhi.SameCycle k (β a₀)
    intro hkp
    rcases tracePhi_reaches_of_keptPhi_sameCycle_b0 β ρ hβinv (a₀ := a₀) (a₁ := a₁) hkp.symm
      with h | h
    · exact ht0 h.symm
    · exact ht1 h.symm
  · -- ¬ keptPhi.SameCycle k (β a₁)
    intro hkp
    rcases tracePhi_reaches_of_keptPhi_sameCycle_b1 β ρ hβinv (a₀ := a₀) (a₁ := a₁) hkp.symm
      with h | h
    · exact ht0 h.symm
    · exact ht1 h.symm

end Untouched



section Discharge

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

/-- **The chord-dart faces are the two touched orbits.**  Re-export of `chordDart_face_eq_*`
specialised to the chord-split side map. -/
lemma sideMap₁_chordDart_face_eq_b0 (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) :
    (data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inr 0)
      = (data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl (data.sideAlpha₁ hsep a₀)) :=
  chordDart_face_eq_b0 (data.sideAlpha₁ hsep) data.sideSigma₁
    (data.sideAlpha₁_involutive hsep) (data.sideAlpha₁_no_fixed hsep) hne











/-- **The two chord-dart faces coincide iff the chord predecessors share a `tracePhi`-orbit.**
The equivalence that makes the two-orbit structure explicit. -/
theorem chordOrbits_eq_iff_tracePhi (β ρ : Equiv.Perm K) (hβinv : β * β = 1)
    (hβfix : ∀ k, β k ≠ k) {a₀ a₁ : K} (hne : a₀ ≠ a₁) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inr 0)
        = (freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inr 1)
      ↔ (tracePhi β ρ a₀ a₁).SameCycle (β a₀) (β a₁) := by
  rw [chordDart_face_eq_b0 β ρ hβinv hβfix hne, chordDart_face_eq_b1 β ρ hβinv hβfix hne,
    sideFace_inl_eq_iff_tracePhi β ρ hβinv hβfix hne]







end Discharge

end ProofsInTheBook.ChordBoundaryOrbit



















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordBoundaryOrbit
-/
/- Source module: ProofsInTheBook.ChordFaceFinal -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordFaceFinal

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordInnerTri
open ProofsInTheBook.ChordContiguous
open ProofsInTheBook.ChordFaceClass
open ProofsInTheBook.ChordBoundaryOrbit

universe u

variable {K : Type u} [Fintype K] [DecidableEq K]



section Formula

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

/-- The `tracePhi`-orbit cardinality of `k` on `K` (the number of `inl`-darts in the side
face of `inl k`). -/
def tOrbitCard (β ρ : Equiv.Perm K) (a₀ a₁ k : K) : ℕ :=
  (Finset.univ.filter (fun c : K =>
    Quotient.mk (cycleSetoid (tracePhi β ρ a₀ a₁)) c
      = Quotient.mk (cycleSetoid (tracePhi β ρ a₀ a₁)) k)).card



/-- `inr 0` is in the side face of `inl k` iff `k ~ₜ β a₀`. -/
lemma inr_zero_mem_sideFace_iff (k : K) :
    (Quotient.mk (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ) (Sum.inr 0)
        = Quotient.mk (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ) (Sum.inl k))
      ↔ (tracePhi β ρ a₀ a₁).SameCycle k (β a₀) := by
  constructor
  · intro h
    have hsc : (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle (Sum.inr 0) (Sum.inl k) :=
      Quotient.exact h
    have htrace := (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inr 0) (Sum.inl k)).1 hsc
    simp only [faceProj_inr_zero, faceProj_inl] at htrace
    exact (htrace.symm)
  · intro h
    apply Quotient.sound
    have htrace : (tracePhi β ρ a₀ a₁).SameCycle (faceProj β a₀ a₁ (Sum.inr 0))
        (faceProj β a₀ a₁ (Sum.inl k)) := by
      simp only [faceProj_inr_zero, faceProj_inl]; exact h.symm
    exact (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inr 0) (Sum.inl k)).2 htrace

/-- `inr 1` is in the side face of `inl k` iff `k ~ₜ β a₁`. -/
lemma inr_one_mem_sideFace_iff (k : K) :
    (Quotient.mk (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ) (Sum.inr 1)
        = Quotient.mk (cycleSetoid (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ) (Sum.inl k))
      ↔ (tracePhi β ρ a₀ a₁).SameCycle k (β a₁) := by
  constructor
  · intro h
    have hsc : (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ.SameCycle (Sum.inr 1) (Sum.inl k) :=
      Quotient.exact h
    have htrace := (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inr 1) (Sum.inl k)).1 hsc
    simp only [faceProj_inr_one, faceProj_inl] at htrace
    exact (htrace.symm)
  · intro h
    apply Quotient.sound
    have htrace : (tracePhi β ρ a₀ a₁).SameCycle (faceProj β a₀ a₁ (Sum.inr 1))
        (faceProj β a₀ a₁ (Sum.inl k)) := by
      simp only [faceProj_inr_one, faceProj_inl]; exact h.symm
    exact (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inr 1) (Sum.inl k)).2 htrace

/-- The full dart-set splits as `inl`-images of `univ K` together with the two `inr` darts. -/
 lemma univ_sum_decomp :
    (Finset.univ : Finset (K ⊕ Fin 2))
      = (Finset.univ.map ⟨Sum.inl, Sum.inl_injective⟩)
        ∪ {Sum.inr 0, Sum.inr 1} := by
  classical
  ext x
  simp only [Finset.mem_univ, Finset.mem_union, Finset.mem_map, Finset.mem_univ, true_and,
    Function.Embedding.coeFn_mk, Finset.mem_insert, Finset.mem_singleton, true_iff]
  cases x with
  | inl c => exact Or.inl ⟨c, rfl⟩
  | inr j => fin_cases j <;> simp

/-- **The general side-face length formula (UNCONDITIONAL).**  The side face of `inl k` has
length `#(tracePhi-orbit of k)` plus `1` for each chord predecessor `β a₀`, `β a₁` lying in
that orbit. -/
theorem sideFaceLen_formula (k : K) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).faceLen
        ((freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl k))
      = tOrbitCard β ρ a₀ a₁ k
        + (if (tracePhi β ρ a₀ a₁).SameCycle k (β a₀) then 1 else 0)
        + (if (tracePhi β ρ a₀ a₁).SameCycle k (β a₁) then 1 else 0) := by
  classical
  set Φ := (freshMap β ρ hβinv hβfix a₀ a₁ hne).φ with hΦ
  set Q : K ⊕ Fin 2 → Prop := fun x =>
    Quotient.mk (cycleSetoid Φ) x = Quotient.mk (cycleSetoid Φ) (Sum.inl k) with hQ
  show (Finset.univ.filter Q).card = _
  -- Split the universe into the inl-image and the two inr darts.
  rw [univ_sum_decomp, Finset.filter_union]
  rw [Finset.card_union_of_disjoint ?disj]
  · -- inl part
    have hinl : (((Finset.univ.map ⟨Sum.inl, Sum.inl_injective⟩).filter Q)).card
        = tOrbitCard β ρ a₀ a₁ k := by
      rw [Finset.filter_map, Finset.card_map]
      -- the filtered preimage on `K` equals the tracePhi-orbit filter.
      congr 1
      ext c
      simp only [Finset.mem_filter, Finset.mem_univ, true_and, Function.comp_apply,
        Function.Embedding.coeFn_mk, hQ]
      constructor
      · intro h
        apply Quotient.sound
        have hsc : Φ.SameCycle (Sum.inl c) (Sum.inl k) := Quotient.exact h
        have := (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inl c) (Sum.inl k)).1 hsc
        simpa only [faceProj_inl] using this
      · intro h
        apply Quotient.sound
        have htr : (tracePhi β ρ a₀ a₁).SameCycle c k := Quotient.exact h
        have htrace : (tracePhi β ρ a₀ a₁).SameCycle (faceProj β a₀ a₁ (Sum.inl c))
            (faceProj β a₀ a₁ (Sum.inl k)) := by simpa only [faceProj_inl] using htr
        exact (freshFace_sameCycle_iff β ρ hβinv hβfix hne (Sum.inl c) (Sum.inl k)).2 htrace
    -- inr part
    have hinr : (({Sum.inr 0, Sum.inr 1} : Finset (K ⊕ Fin 2)).filter Q).card
        = (if (tracePhi β ρ a₀ a₁).SameCycle k (β a₀) then 1 else 0)
          + (if (tracePhi β ρ a₀ a₁).SameCycle k (β a₁) then 1 else 0) := by
      have key0 : Q (Sum.inr 0) ↔ (tracePhi β ρ a₀ a₁).SameCycle k (β a₀) :=
        inr_zero_mem_sideFace_iff β ρ hβinv hβfix hne k
      have key1 : Q (Sum.inr 1) ↔ (tracePhi β ρ a₀ a₁).SameCycle k (β a₁) :=
        inr_one_mem_sideFace_iff β ρ hβinv hβfix hne k
      rw [Finset.filter_insert, Finset.filter_singleton]
      by_cases h0 : Q (Sum.inr 0) <;> by_cases h1 : Q (Sum.inr 1)
      · rw [if_pos h0, if_pos h1, if_pos (key0.1 h0), if_pos (key1.1 h1)]
        rw [Finset.card_insert_of_notMem (by simp)]; simp
      · have ne1 : ¬ (tracePhi β ρ a₀ a₁).SameCycle k (β a₁) := fun e => h1 (key1.2 e)
        rw [if_pos h0, if_neg h1, if_pos (key0.1 h0), if_neg ne1]; simp
      · have ne0 : ¬ (tracePhi β ρ a₀ a₁).SameCycle k (β a₀) := fun e => h0 (key0.2 e)
        rw [if_neg h0, if_pos h1, if_neg ne0, if_pos (key1.1 h1)]; simp
      · have ne0 : ¬ (tracePhi β ρ a₀ a₁).SameCycle k (β a₀) := fun e => h0 (key0.2 e)
        have ne1 : ¬ (tracePhi β ρ a₀ a₁).SameCycle k (β a₁) := fun e => h1 (key1.2 e)
        rw [if_neg h0, if_neg h1, if_neg ne0, if_neg ne1]; simp
    rw [hinl, hinr, ← add_assoc]
  case disj =>
    apply Finset.disjoint_left.2
    intro x hx hx2
    simp only [Finset.mem_filter, Finset.mem_map, Finset.mem_univ, true_and,
      Function.Embedding.coeFn_mk] at hx hx2
    obtain ⟨⟨c, hc⟩, _⟩ := hx
    obtain ⟨hx2mem, _⟩ := hx2
    simp only [Finset.mem_insert, Finset.mem_singleton] at hx2mem
    subst hc
    rcases hx2mem with h | h <;> exact absurd h (by simp)

end Formula



section Consequences

variable (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

include hne



/-- **The chord-triangle face length, from the explicit count.**  If the side face's
representative `k` has a `tracePhi`-orbit of exactly `2` kept darts and exactly one of the two
chord predecessors joins it (the fresh chord dart re-closing the deleted-dart gap of the
`M`-triangle `face₁`), then the side face is a triangle.  This is the DIRECT discharge of the
touched chord-triangle face — no splice-untouchedness, computed from the formula. -/
theorem sideFaceLen_three_of_count {k : K} (htwo : tOrbitCard β ρ a₀ a₁ k = 2)
    (hone : ((if (tracePhi β ρ a₀ a₁).SameCycle k (β a₀) then 1 else 0)
        + (if (tracePhi β ρ a₀ a₁).SameCycle k (β a₁) then 1 else 0)) = 1) :
    (freshMap β ρ hβinv hβfix a₀ a₁ hne).faceLen
        ((freshMap β ρ hβinv hβfix a₀ a₁ hne).dartFace (Sum.inl k)) = 3 := by
  rw [sideFaceLen_formula β ρ hβinv hβfix hne k, add_assoc, htwo, hone]



end Consequences



section Discharge

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

/-- **The explicit chord-triangle count, at the side-map level.**  A kept dart `k` whose side
face has a `tracePhi`-orbit of `2` kept darts joined by exactly one fresh chord dart yields a
side triangle.  This is the DIRECT discharge of the touched `face₁` image — the chord re-closes
the deleted-dart gap of the `M`-triangle `face₁` with one fresh chord dart. -/
theorem sideMap₁_faceLen_three_of_count (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (k : {d : D // d ∉ data.keptDel₁})
    (htwo : tOrbitCard (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ k = 2)
    (hone : ((if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle k
            ((data.sideAlpha₁ hsep) a₀) then 1 else 0)
        + (if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle k
            ((data.sideAlpha₁ hsep) a₁) then 1 else 0)) = 1) :
    (data.sideMap₁ hsep a₀ a₁ hne).faceLen
        ((data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl k)) = 3 :=
  sideFaceLen_three_of_count (data.sideAlpha₁ hsep) data.sideSigma₁
    (data.sideAlpha₁_involutive hsep) (data.sideAlpha₁_no_fixed hsep) hne htwo hone

/-- **The per-face triangle witness (NO `≠ face₁` carve-out).**  For one side face `f`, a
representative giving `faceLen f = 3` via EITHER route. -/
inductive SideFaceTriangle (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (f : (data.sideMap₁ hsep a₀ a₁ hne).Face) : Prop where
  /-- A representative whose side face IS `f` and has `faceLen = 3`. -/
  | mk (k : {d : D // d ∉ data.keptDel₁})
      (hkf : (data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl k) = f)
      (hlen : (data.sideMap₁ hsep a₀ a₁ hne).faceLen
        ((data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl k)) = 3)



/-- The explicit chord-triangle count route produces a `SideFaceTriangle` witness (the touched
`face₁` image, discharged directly). -/
theorem sideFaceTriangle_of_count (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (f : (data.sideMap₁ hsep a₀ a₁ hne).Face)
    (k : {d : D // d ∉ data.keptDel₁})
    (hkf : (data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl k) = f)
    (htwo : tOrbitCard (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ k = 2)
    (hone : ((if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle k
            ((data.sideAlpha₁ hsep) a₀) then 1 else 0)
        + (if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle k
            ((data.sideAlpha₁ hsep) a₁) then 1 else 0)) = 1) :
    SideFaceTriangle data hsep a₀ a₁ hne f :=
  ⟨k, hkf, sideMap₁_faceLen_three_of_count data hsep a₀ a₁ hne k htwo hone⟩















/-- **The chord dart is deleted** (`dart ∈ keptDel₁`): it is removed from `keptSet₁`. -/
theorem dart_mem_keptDel₁ (data : hNT.ChordSplitData u v) :
    data.dart ∈ data.keptDel₁ := by
  classical
  by_contra h
  rw [data.mem_keptDel₁_iff] at h
  exact h.2 (by simp)

/-- **The two non-chord darts of `face₁` are kept.**  `M.φ dart`, `M.φ² dart` have `M`-face
`face₁ ∈ side₁`, hence lie in `sideDarts₁`; they are `≠ dart` (the triangle has distinct darts),
hence in `keptSet₁`. -/
theorem face₁_phi_dart_kept (data : hNT.ChordSplitData u v)
    (hd1 : M.φ data.dart ≠ data.dart) :
    M.φ data.dart ∉ data.keptDel₁ := by
  classical
  rw [data.mem_keptDel₁_iff]
  refine ⟨Or.inl ?_, by simpa using hd1⟩
  show M.dartFace (M.φ data.dart) ∈ data.side₁
  rw [M.dartFace_phi]; exact data.face₁_mem_side₁

/-- **The second non-chord dart of `face₁` is kept.** -/
theorem face₁_phi_phi_dart_kept (data : hNT.ChordSplitData u v)
    (hd2 : M.φ (M.φ data.dart) ≠ data.dart) :
    M.φ (M.φ data.dart) ∉ data.keptDel₁ := by
  classical
  rw [data.mem_keptDel₁_iff]
  refine ⟨Or.inl ?_, by simpa using hd2⟩
  show M.dartFace (M.φ (M.φ data.dart)) ∈ data.side₁
  rw [M.dartFace_phi, M.dartFace_phi]; exact data.face₁_mem_side₁

/-- **The two kept `face₁` darts are distinct** (the `M`-triangle `face₁` has three distinct
darts).  Uses graph simplicity from the near-triangulation. -/
theorem face₁_kept_darts_distinct (data : hNT.ChordSplitData u v) :
    M.φ data.dart ≠ M.φ (M.φ data.dart) := by
  intro h
  -- `φ d1 = φ d2 ⇒ d1 = d2`, but a triangle has distinct darts.
  have htri := data.face₁_isFaceTriangle
  -- htri : IsFaceTriangle dart (φ dart) (φ²dart): φ dart = φ dart, φ(φ dart)=φ²dart, φ(φ²dart)=dart
  obtain ⟨_, h12, h20⟩ := htri
  -- from `h : φ dart = φ² dart` we get `dart = φ dart` by injectivity, contradicting simplicity.
  have : M.φ data.dart = M.φ (M.φ data.dart) := h
  have heq : data.dart = M.φ data.dart := M.φ.injective this
  exact (M.phi_ne_self_of_isSimpleGraph hNT.simpleGraph data.dart) heq.symm

/-- **`face₁` contributes exactly two kept darts** (UNCONDITIONAL, the `M`-side of the count).
The two non-chord darts of the `M`-triangle `face₁` are kept and distinct; the chord dart is
deleted.  This is the genuine chord-triangle structure underlying `tOrbitCard = 2` for the
touched `face₁` side face — established with no correct-anchor input. -/
theorem face₁_two_kept_darts (data : hNT.ChordSplitData u v) :
    (M.φ data.dart ∉ data.keptDel₁) ∧ (M.φ (M.φ data.dart) ∉ data.keptDel₁) ∧
      M.φ data.dart ≠ M.φ (M.φ data.dart) ∧
      M.dartFace (M.φ data.dart) = data.face₁ ∧
      M.dartFace (M.φ (M.φ data.dart)) = data.face₁ := by
  -- triangle distinctness gives φ dart ≠ dart and φ² dart ≠ dart.
  obtain ⟨_, h12, h20⟩ := data.face₁_isFaceTriangle
  have hd1 : M.φ data.dart ≠ data.dart := by
    intro he
    have : data.dart = M.φ data.dart := he.symm
    exact (M.phi_ne_self_of_isSimpleGraph hNT.simpleGraph data.dart) he
  have hd2 : M.φ (M.φ data.dart) ≠ data.dart := by
    -- φ²dart = dart would force dart = φ dart (apply φ, use h20); contradiction.
    intro he
    have hstep : M.φ (M.φ (M.φ data.dart)) = M.φ data.dart := congrArg M.φ he
    -- h20 : φ (φ² dart) = dart, so dart = φ dart.
    have : data.dart = M.φ data.dart := h20.symm.trans hstep
    exact (M.phi_ne_self_of_isSimpleGraph hNT.simpleGraph data.dart) this.symm
  refine ⟨face₁_phi_dart_kept data hd1, face₁_phi_phi_dart_kept data hd2,
    face₁_kept_darts_distinct data, ?_, ?_⟩
  · show M.dartFace (M.φ data.dart) = M.dartFace data.dart; rw [M.dartFace_phi]
  · show M.dartFace (M.φ (M.φ data.dart)) = M.dartFace data.dart
    rw [M.dartFace_phi, M.dartFace_phi]

end Discharge

end ProofsInTheBook.ChordFaceFinal

















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordFaceFinal
-/
/- Source module: ProofsInTheBook.ChordAnchor -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordAnchor

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordInnerTri
open ProofsInTheBook.ChordContiguous
open ProofsInTheBook.ChordFaceClass
open ProofsInTheBook.ChordBoundaryOrbit
open ProofsInTheBook.ChordFaceFinal

universe u



section TwoCycle

variable {K : Type u} [DecidableEq K]

/-- The natural-number iterate of a swap stays on the two swapped points. -/
 lemma swap_iterate_mem {g : Equiv.Perm K} {k₀ k₁ : K}
    (h01 : g k₀ = k₁) (h10 : g k₁ = k₀) :
    ∀ n : ℕ, g^[n] k₀ = k₀ ∨ g^[n] k₀ = k₁ := by
  intro n
  induction n with
  | zero => exact Or.inl rfl
  | succ m ih =>
      rw [Function.iterate_succ_apply']
      rcases ih with h | h
      · rw [h]; exact Or.inr h01
      · rw [h]; exact Or.inl h10

variable [Fintype K]

/-- `g.SameCycle k₀ c` with `g` swapping `k₀ ↔ k₁` forces `c ∈ {k₀, k₁}`. -/
 lemma sameCycle_swap_mem {g : Equiv.Perm K} {k₀ k₁ : K}
    (h01 : g k₀ = k₁) (h10 : g k₁ = k₀) {c : K}
    (h : g.SameCycle k₀ c) : c = k₀ ∨ c = k₁ := by
  obtain ⟨n, hn⟩ := h.exists_nat_pow_eq
  rw [Equiv.Perm.coe_pow] at hn
  rcases swap_iterate_mem h01 h10 n with he | he
  · exact Or.inl (by rw [← hn, he])
  · exact Or.inr (by rw [← hn, he])

/-- **The two-cycle orbit has cardinality `2`.**  If `g k₀ = k₁`, `g k₁ = k₀` with
`k₀ ≠ k₁`, the cycle-orbit filter of `k₀` is exactly `{k₀, k₁}`, of cardinality `2`. -/
theorem twoCycle_orbit_card {g : Equiv.Perm K} {k₀ k₁ : K}
    (h01 : g k₀ = k₁) (h10 : g k₁ = k₀) (hne : k₀ ≠ k₁) :
    (Finset.univ.filter (fun c : K =>
        Quotient.mk (cycleSetoid g) c = Quotient.mk (cycleSetoid g) k₀)).card = 2 := by
  classical
  have hset : (Finset.univ.filter (fun c : K =>
      Quotient.mk (cycleSetoid g) c = Quotient.mk (cycleSetoid g) k₀))
      = ({k₀, k₁} : Finset K) := by
    ext c
    simp only [Finset.mem_filter, Finset.mem_univ, true_and, Finset.mem_insert,
      Finset.mem_singleton]
    constructor
    · intro hc
      have hsc : g.SameCycle c k₀ := Quotient.exact hc
      exact sameCycle_swap_mem h01 h10 hsc.symm
    · rintro (rfl | rfl)
      · rfl
      · apply Quotient.sound
        -- `g.SameCycle k₁ k₀`: one step `g k₁ = k₀`.
        exact ⟨1, by rw [zpow_one, h10]⟩
  rw [hset, Finset.card_insert_of_notMem (by simpa using hne), Finset.card_singleton]

end TwoCycle



section Card

variable {K : Type u} [Fintype K] [DecidableEq K]

/-- **`tOrbitCard = 2` from the explicit `tracePhi` 2-cycle.**  If the side `tracePhi` swaps
the two kept `face₁` darts `d₁ ↔ d₂` (the correct-anchor placement — the chord cap spliced at
the chord-dart position), then the `tracePhi`-orbit of `d₁` is exactly `{d₁, d₂}`, so the
`face₁` side-face has exactly `2` kept darts. -/
theorem tOrbitCard_eq_two_of_tracePhi_swap (β ρ : Equiv.Perm K) (a₀ a₁ : K) {d₁ d₂ : K}
    (h12 : tracePhi β ρ a₀ a₁ d₁ = d₂) (h21 : tracePhi β ρ a₀ a₁ d₂ = d₁)
    (hne : d₁ ≠ d₂) :
    tOrbitCard β ρ a₀ a₁ d₁ = 2 :=
  twoCycle_orbit_card h12 h21 hne

end Card



section Discharge

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

/-- **The correct-anchor orbit-isolation datum** for the touched `face₁` side face.  Records
the genuine discrete Jordan–Schoenflies placement of the chord cap:

* `kface : {d // d ∉ keptDel₁}` — the representative kept dart of the `face₁` side orbit;
* `kother` — its `tracePhi`-2-cycle partner (the other kept `face₁` dart);
* the side `tracePhi` cycles them (`tracePhi kface = kother`, `tracePhi kother = kface`),
  distinct;
* the rep's side face is the chosen `f`;
* exactly one of the two chord predecessors `(sideAlpha₁) a₀`, `(sideAlpha₁) a₁` is
  `tracePhi`-SameCycle to `kface` (the one fresh chord dart re-closing the deleted-dart gap).

This is the chord-cap placement, exposed as concrete `tracePhi` equations — the abstract
`CombMap` does not certify it (the anchors are free parameters of `sideMap₁`). -/
structure CorrectAnchorTwoCycle (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (f : (data.sideMap₁ hsep a₀ a₁ hne).Face) : Type u where
  /-- The representative kept dart of the `face₁` side orbit. -/
  kface : {d : D // d ∉ data.keptDel₁}
  /-- Its `tracePhi`-2-cycle partner. -/
  kother : {d : D // d ∉ data.keptDel₁}
  /-- The side `tracePhi` sends the rep to its partner. -/
  trace12 : tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ kface = kother
  /-- The side `tracePhi` sends the partner back to the rep. -/
  trace21 : tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ kother = kface
  /-- The two kept `face₁` darts are distinct. -/
  distinct : kface ≠ kother
  /-- The rep's side face is the chosen face `f`. -/
  hkf : (data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl kface) = f
  /-- Exactly one fresh chord dart re-closes the orbit (the one-indicator condition). -/
  one_fresh :
    ((if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle kface
          ((data.sideAlpha₁ hsep) a₀) then 1 else 0)
      + (if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle kface
          ((data.sideAlpha₁ hsep) a₁) then 1 else 0)) = 1

/-- **The correct-anchor datum gives `tOrbitCard = 2`** for the `face₁` orbit rep. -/
theorem correctAnchor_tOrbitCard_two (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (f : (data.sideMap₁ hsep a₀ a₁ hne).Face)
    (hca : CorrectAnchorTwoCycle data hsep a₀ a₁ hne f) :
    tOrbitCard (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ hca.kface = 2 :=
  tOrbitCard_eq_two_of_tracePhi_swap (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁
    hca.trace12 hca.trace21 hca.distinct

/-- **The touched `face₁` side face is a `SideFaceTriangle`** — discharged DIRECTLY from the
correct-anchor orbit-isolation (`tOrbitCard = 2` + one fresh chord dart), NOT via a `≠ face₁`
carve-out or boundary absorption.  This is the correct-anchor orbit-isolation closing the last
chord-side residue. -/
theorem face₁_sideFaceTriangle_of_correctAnchor (data : hNT.ChordSplitData u v)
    (hsep : data.Separates) (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (f : (data.sideMap₁ hsep a₀ a₁ hne).Face)
    (hca : CorrectAnchorTwoCycle data hsep a₀ a₁ hne f) :
    SideFaceTriangle data hsep a₀ a₁ hne f :=
  sideFaceTriangle_of_count data hsep a₀ a₁ hne f hca.kface hca.hkf
    (correctAnchor_tOrbitCard_two data hsep a₀ a₁ hne f hca) hca.one_fresh











/-- **The correct-anchor datum is satisfiable (non-vacuous), not a hidden `False`.**  Given the
component data — a `tracePhi`-2-cycle on two distinct kept darts, the rep's face, and the
one-fresh-dart indicator — the structure is inhabited.  This is the §3.3 satisfiability check:
`CorrectAnchorTwoCycle` is the genuine correct-anchor placement (a real 2-cycle equation), not
an unsatisfiable premise. -/
def CorrectAnchorTwoCycle.mk' (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (f : (data.sideMap₁ hsep a₀ a₁ hne).Face)
    (kface kother : {d : D // d ∉ data.keptDel₁})
    (trace12 : tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ kface = kother)
    (trace21 : tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ kother = kface)
    (distinct : kface ≠ kother)
    (hkf : (data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl kface) = f)
    (one_fresh :
      ((if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle kface
            ((data.sideAlpha₁ hsep) a₀) then 1 else 0)
        + (if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle kface
            ((data.sideAlpha₁ hsep) a₁) then 1 else 0)) = 1) :
    CorrectAnchorTwoCycle data hsep a₀ a₁ hne f :=
  { kface := kface, kother := kother, trace12 := trace12, trace21 := trace21,
    distinct := distinct, hkf := hkf, one_fresh := one_fresh }



/-- The first kept `face₁` dart `M.φ dart`, as a subtype element of `{d // d ∉ keptDel₁}`
(kept by the unconditional `face₁_two_kept_darts`). -/
noncomputable def face₁Dart₁ (data : hNT.ChordSplitData u v) :
    {d : D // d ∉ data.keptDel₁} :=
  ⟨M.φ data.dart, (face₁_two_kept_darts data).1⟩

/-- The second kept `face₁` dart `M.φ² dart`, as a subtype element. -/
noncomputable def face₁Dart₂ (data : hNT.ChordSplitData u v) :
    {d : D // d ∉ data.keptDel₁} :=
  ⟨M.φ (M.φ data.dart), (face₁_two_kept_darts data).2.1⟩

/-- The two kept `face₁` darts are distinct as subtype elements (from
`face₁_two_kept_darts`). -/
theorem face₁Dart_distinct (data : hNT.ChordSplitData u v) :
    face₁Dart₁ data ≠ face₁Dart₂ data := by
  intro h
  exact (face₁_two_kept_darts data).2.2.1 (congrArg Subtype.val h)

/-- **The correct-anchor datum, anchored to the ACTUAL `face₁` darts.**  Given the `tracePhi`
2-cycle on the two genuine kept `face₁` darts `M.φ dart ↔ M.φ² dart` (the chord-cap placement),
their `inl`-side face being the chosen `f`, and the one-fresh-chord-dart indicator, the
correct-anchor datum holds — with distinctness/keptness supplied UNCONDITIONALLY by
`face₁_two_kept_darts`.  This is the genuine chord-triangle orbit-isolation: the 2 kept `face₁`
darts form a length-2 `tracePhi`-orbit, re-closed by one fresh chord dart. -/
noncomputable def correctAnchorTwoCycle_ofFace₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (f : (data.sideMap₁ hsep a₀ a₁ hne).Face)
    (trace12 : tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ (face₁Dart₁ data)
        = face₁Dart₂ data)
    (trace21 : tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ (face₁Dart₂ data)
        = face₁Dart₁ data)
    (hkf : (data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl (face₁Dart₁ data)) = f)
    (one_fresh :
      ((if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle (face₁Dart₁ data)
            ((data.sideAlpha₁ hsep) a₀) then 1 else 0)
        + (if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle (face₁Dart₁ data)
            ((data.sideAlpha₁ hsep) a₁) then 1 else 0)) = 1) :
    CorrectAnchorTwoCycle data hsep a₀ a₁ hne f :=
  CorrectAnchorTwoCycle.mk' data hsep a₀ a₁ hne f (face₁Dart₁ data) (face₁Dart₂ data)
    trace12 trace21 (face₁Dart_distinct data) hkf one_fresh

/-- **The touched `face₁` side face is a triangle, from the ACTUAL `face₁`-dart 2-cycle.**  The
end-to-end statement the orchestration named: the chord-triangle `face₁`'s keptPhi-orbit has
`tOrbitCard = 2` (its 2 kept darts `M.φ dart`, `M.φ² dart`, the 3rd being the deleted chord
dart), re-closed by one fresh chord dart, so the `face₁` side face is a length-3 triangle —
DIRECTLY, with no `≠ face₁` carve-out. -/
theorem face₁_sideTriangle_ofFace₁Cycle (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (f : (data.sideMap₁ hsep a₀ a₁ hne).Face)
    (trace12 : tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ (face₁Dart₁ data)
        = face₁Dart₂ data)
    (trace21 : tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁ (face₁Dart₂ data)
        = face₁Dart₁ data)
    (hkf : (data.sideMap₁ hsep a₀ a₁ hne).dartFace (Sum.inl (face₁Dart₁ data)) = f)
    (one_fresh :
      ((if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle (face₁Dart₁ data)
            ((data.sideAlpha₁ hsep) a₀) then 1 else 0)
        + (if (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁ a₀ a₁).SameCycle (face₁Dart₁ data)
            ((data.sideAlpha₁ hsep) a₁) then 1 else 0)) = 1) :
    SideFaceTriangle data hsep a₀ a₁ hne f :=
  face₁_sideFaceTriangle_of_correctAnchor data hsep a₀ a₁ hne f
    (correctAnchorTwoCycle_ofFace₁ data hsep a₀ a₁ hne f trace12 trace21 hkf one_fresh)

end Discharge

end ProofsInTheBook.ChordAnchor














end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordAnchor
-/
/- Source module: ProofsInTheBook.ChordAnchorInst -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordAnchorInst

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordInnerTri
open ProofsInTheBook.ChordBoundaryOrbit
open ProofsInTheBook.ChordFaceFinal
open ProofsInTheBook.ChordAnchor

universe u



section Algebra

variable {K : Type u} [Fintype K] [DecidableEq K]

/-- **`tracePhi` is `keptPhi` with its values at `ρ a₀`, `ρ a₁` swapped.** -/
lemma tracePhi_eq_swap_keptPhi (β ρ : Equiv.Perm K) (a₀ a₁ k : K) :
    tracePhi β ρ a₀ a₁ k = Equiv.swap (ρ a₀) (ρ a₁) (keptPhi β ρ k) := by
  show (Equiv.swap (ρ a₀) (ρ a₁) * (ρ * β)) k = Equiv.swap (ρ a₀) (ρ a₁) ((ρ * β) k)
  rw [Equiv.Perm.mul_apply]



end Algebra



section KeptPhi

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

/-- **`keptPhi d₁ = d₂` on the chord-split side (the easy filtered step).**  The
side face permutation `keptPhi (sideAlpha₁) sideSigma₁` sends the first kept
`face₁` dart `face₁Dart₁ = ⟨M.φ dart, _⟩` to the second `face₁Dart₂ = ⟨M.φ² dart,
_⟩`.  The `α`-then-`σ` step is `M.σ (M.α (M.φ dart)) = M.φ² dart` (= `M.φ`
applied to `M.φ dart`), which is kept, so the filtered rotation does not skip. -/
theorem keptPhi_face₁Dart₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ (face₁Dart₁ data) = face₁Dart₂ data := by
  classical
  -- `keptPhi … d₁ = sideSigma₁ (sideAlpha₁ d₁)`.
  apply Subtype.ext
  show ((data.sideSigma₁ (data.sideAlpha₁ hsep (face₁Dart₁ data))) : D)
    = (face₁Dart₂ data : D)
  -- `sideSigma₁ = filteredRotation M.σ keptDel₁`.
  have hval : ((data.sideAlpha₁ hsep (face₁Dart₁ data)) : D) = M.α (M.φ data.dart) := by
    rw [sideAlpha₁_apply_coe]; rfl
  -- the `σ`-successor of `α (M.φ dart)` is `M.φ² dart`, which is kept.
  have hstep : M.σ ((data.sideAlpha₁ hsep (face₁Dart₁ data)) : D) = M.φ (M.φ data.dart) := by
    rw [hval]
    show M.σ (M.α (M.φ data.dart)) = (M.σ * M.α) (M.φ data.dart)
    rw [Equiv.Perm.mul_apply]
  have hkept : M.σ ((data.sideAlpha₁ hsep (face₁Dart₁ data)) : D) ∉ data.keptDel₁ := by
    rw [hstep]; exact (face₁_two_kept_darts data).2.1
  show ((FilteredRotation.filteredRotation M.σ data.keptDel₁
        (data.sideAlpha₁ hsep (face₁Dart₁ data))) : D) = (face₁Dart₂ data : D)
  rw [FilteredRotation.filteredRotation_apply_of_next_kept M.σ data.keptDel₁
    (data.sideAlpha₁ hsep (face₁Dart₁ data)) hkept, hstep]
  rfl

/-- **`keptPhi d₂ ≠ d₂`.**  From `keptPhi d₁ = d₂` and `d₁ ≠ d₂`: if `keptPhi d₂ =
d₂` then `keptPhi d₂ = keptPhi d₁`, so `d₂ = d₁` by injectivity — contradiction.
This is the only consequence needed beyond the bigon closure, and it is FREE. -/
theorem keptPhi_face₁Dart₂_ne_self (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ (face₁Dart₂ data) ≠ face₁Dart₂ data := by
  intro h
  have h1 := keptPhi_face₁Dart₁ data hsep
  -- keptPhi d₂ = d₂ = keptPhi d₁ ⇒ d₂ = d₁.
  have : keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ (face₁Dart₂ data)
      = keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ (face₁Dart₁ data) := by
    rw [h, ← h1]
  have heq : face₁Dart₂ data = face₁Dart₁ data :=
    (keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁).injective this
  exact (face₁Dart_distinct data) heq.symm

end KeptPhi



section Residue

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

















end Residue

end ProofsInTheBook.ChordAnchorInst













end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordAnchorInst
-/
/- Source module: ProofsInTheBook.ChordBigonWrap -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option linter.dupNamespace false

namespace ProofsInTheBook.ChordBigonWrap

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordInnerTri
open ProofsInTheBook.ChordBoundaryOrbit
open ProofsInTheBook.ChordFaceFinal
open ProofsInTheBook.ChordAnchor
open ProofsInTheBook.ChordAnchorInst

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



/-- **`M.φ³ dart = dart`** — the chord-incident face `face₁` is an `M`-triangle.  This is
the third leg of `data.face₁_isFaceTriangle` (which descends from `hNT.inner_tri` applied to
the non-outer face `face₁`): `M.φ (M.φ² dart) = dart`.  UNCONDITIONAL. -/
theorem phi_cube_dart (data : hNT.ChordSplitData u v) :
    M.φ (M.φ (M.φ data.dart)) = data.dart :=
  data.face₁_isFaceTriangle.2.2

/-- **`M.σ (M.α (M.φ² dart)) = dart`** — the immediate `σ`-successor of the `α`-image of `d₂`
is the chord dart.  `M.σ ∘ M.α = M.φ`, so this is `M.φ (M.φ² dart) = M.φ³ dart = dart`.
UNCONDITIONAL. -/
theorem sigma_alpha_phiSq_dart_eq_dart (data : hNT.ChordSplitData u v) :
    M.σ (M.α (M.φ (M.φ data.dart))) = data.dart := by
  show (M.σ * M.α) (M.φ (M.φ data.dart)) = data.dart
  rw [← CombMap.φ]
  exact phi_cube_dart data

/-- **The first `σ`-step of the filtered rotation at `d₂` is the DELETED chord dart.**  The
filtered rotation `sideSigma₁ = filteredRotation M.σ keptDel₁` starts from `sideAlpha₁ d₂`,
whose underlying dart is `M.α (M.φ² dart)`; its immediate `M.σ`-successor is
`M.σ (M.α (M.φ² dart)) = dart ∈ keptDel₁`.  So the rotation cannot take the trivial single
step — it MUST skip the chord dart.  This is the concrete skip certificate of the bigon
wrap, UNCONDITIONAL. -/
theorem bigonWrap_firstStep_deleted (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    M.σ ((data.sideAlpha₁ hsep (face₁Dart₂ data) : {d : D // d ∉ data.keptDel₁}) : D)
      ∈ data.keptDel₁ := by
  have hval : ((data.sideAlpha₁ hsep (face₁Dart₂ data)) : D) = M.α (M.φ (M.φ data.dart)) := by
    rw [sideAlpha₁_apply_coe]; rfl
  rw [hval, sigma_alpha_phiSq_dart_eq_dart data]
  exact dart_mem_keptDel₁ data

/-- **`firstOutside ≥ 2` at `d₂`.**  Because the first `σ`-successor is deleted
(`bigonWrap_firstStep_deleted`), the filtered rotation takes at least two `σ`-steps from
`sideAlpha₁ d₂`: the wrap is a genuine skip, never the trivial consecutive step.
UNCONDITIONAL. -/
theorem sideSigma₁_sideAlpha₁_firstOutside_ge_two
    (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    2 ≤ Equiv.Perm.DeleteSet.firstOutside M.σ data.keptDel₁
          (data.sideAlpha₁ hsep (face₁Dart₂ data)) := by
  by_contra hlt
  rw [Nat.not_le] at hlt
  -- `firstOutside` is positive, so it must be `1` — forcing the deleted first step to be kept.
  have hpos : 0 < Equiv.Perm.DeleteSet.firstOutside M.σ data.keptDel₁
      (data.sideAlpha₁ hsep (face₁Dart₂ data)) :=
    Equiv.Perm.DeleteSet.firstOutside_pos M.σ data.keptDel₁ _
  have heq1 : Equiv.Perm.DeleteSet.firstOutside M.σ data.keptDel₁
      (data.sideAlpha₁ hsep (face₁Dart₂ data)) = 1 := by omega
  -- the survivor (which is `∉ keptDel₁`) equals the first `σ`-step, which is deleted.
  have hnot := Equiv.Perm.DeleteSet.firstOutside_notMem M.σ data.keptDel₁
    (data.sideAlpha₁ hsep (face₁Dart₂ data))
  rw [heq1, pow_one] at hnot
  exact hnot (bigonWrap_firstStep_deleted data hsep)





















end ProofsInTheBook.ChordBigonWrap













end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordBigonWrap
-/
/- Source module: ProofsInTheBook.ChordSigmaContig -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option linter.dupNamespace false

namespace ProofsInTheBook.ChordSigmaContig

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordInnerTri
open ProofsInTheBook.ChordBoundaryOrbit
open ProofsInTheBook.ChordFaceFinal
open ProofsInTheBook.ChordAnchor
open ProofsInTheBook.ChordAnchorInst
open ProofsInTheBook.ChordBigonWrap

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



/-- A `σ`-power preserves the `tail` (vertex): `tail ((σ^n) d) = tail d`.  The two
darts are `σ`-`SameCycle` (witnessed by the exponent `n`), so they have the same
`σ`-orbit class, which is `tail`. -/
lemma tail_pow_sigma (n : ℕ) (d : D) :
    M.tail ((M.σ ^ n) d) = M.tail d := by
  apply Quotient.sound
  -- `SameCycle ((σ^n) d) d` via the exponent `-n`.
  refine ⟨-(n : ℤ), ?_⟩
  rw [zpow_neg, zpow_natCast, ← Equiv.Perm.mul_apply, inv_mul_cancel, Equiv.Perm.one_apply]

/-- **The filtered rotation keeps the vertex fixed.**  For any deleted set and kept
dart `x`, the filtered successor lives at the same vertex as `x`. -/
lemma tail_filteredRotation (Del : Finset D) (x : {d : D // d ∉ Del}) :
    M.tail (FilteredRotation.filteredRotation M.σ Del x : D) = M.tail x.1 := by
  rw [FilteredRotation.filteredRotation_apply_coe]
  exact tail_pow_sigma _ x.1



/-- `M.α (M.φ² dart)` lives at vertex `tail dart` (= `u`): its `σ`-successor is the
chord dart `dart`, so it is `σ`-`SameCycle` with `dart`. -/
lemma tail_alpha_phiSq_dart (data : hNT.ChordSplitData u v) :
    M.tail (M.α (M.φ (M.φ data.dart))) = M.tail data.dart := by
  have h : M.σ (M.α (M.φ (M.φ data.dart))) = data.dart :=
    sigma_alpha_phiSq_dart_eq_dart data
  calc
    M.tail (M.α (M.φ (M.φ data.dart)))
        = M.tail (M.σ (M.α (M.φ (M.φ data.dart)))) := (M.tail_sigma _).symm
    _ = M.tail data.dart := by rw [h]

/-- **`keptPhi d₂` lands at vertex `tail dart` (= `u`).**  `keptPhi d₂ =
sideSigma₁ (sideAlpha₁ d₂)`; the `α`-step's underlying dart is `M.α (M.φ² dart)`
(at vertex `tail dart`), and the filtered rotation keeps the vertex. -/
theorem keptPhi_face₁Dart₂_tail (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    M.tail ((keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ (face₁Dart₂ data) :
        {d : D // d ∉ data.keptDel₁}) : D)
      = M.tail data.dart := by
  -- `keptPhi β ρ k = ρ (β k)`; unfold `ρ = sideSigma₁ = filteredRotation M.σ keptDel₁`.
  show M.tail ((data.sideSigma₁ (data.sideAlpha₁ hsep (face₁Dart₂ data)) :
      {d : D // d ∉ data.keptDel₁}) : D) = M.tail data.dart
  -- the filtered rotation preserves the vertex of its argument,
  rw [show data.sideSigma₁ = FilteredRotation.filteredRotation M.σ data.keptDel₁ from rfl,
    tail_filteredRotation data.keptDel₁ (data.sideAlpha₁ hsep (face₁Dart₂ data))]
  -- whose underlying dart is `M.α (M.φ² dart)`, at vertex `tail dart`.
  rw [sideAlpha₁_apply_coe]
  show M.tail (M.α ((face₁Dart₂ data : {d : D // d ∉ data.keptDel₁}) : D)) = M.tail data.dart
  show M.tail (M.α (M.φ (M.φ data.dart))) = M.tail data.dart
  exact tail_alpha_phiSq_dart data

/-- **`d₁ = M.φ dart` lives at vertex `head dart` (= `v`).**  `tail (M.φ dart) =
head dart` by `tail_phi`. -/
theorem face₁Dart₁_tail (data : hNT.ChordSplitData u v) :
    M.tail ((face₁Dart₁ data : {d : D // d ∉ data.keptDel₁}) : D) = M.head data.dart := by
  show M.tail (M.φ data.dart) = M.head data.dart
  exact M.tail_phi data.dart

/-- **The two chord endpoints are distinct vertices** (`tail dart ≠ head dart`):
the chord is a genuine edge, so it is not a loop. -/
theorem u_ne_v (data : hNT.ChordSplitData u v) :
    M.tail data.dart ≠ M.head data.dart :=
  hNT.simpleGraph.no_loop data.dart



/-- **The chord-cap bigon WRAP `keptPhi d₂ = d₁` is FALSE.**  `keptPhi d₂` lives at
vertex `tail dart = u` (`keptPhi_face₁Dart₂_tail`) and `d₁ = M.φ dart` lives at the
other chord endpoint `head dart = v` (`face₁Dart₁_tail`), with `u ≠ v` (`u_ne_v`);
distinct vertices force distinct darts.

This is the precise refutation of the route proposed in `opus-bigonwrap-reply.md`:
the filtered rotation `sideSigma₁` only ever moves *within* a single `σ`-orbit
(vertex), so no `FilteredRotation.ContiguousInterval` for `u`'s kept darts can make
it reach `d₁`, which sits at `v`.  The `keptPhi`-wrap is the WRONG residue. -/
theorem keptPhi_face₁Dart₂_ne_face₁Dart₁ (data : hNT.ChordSplitData u v)
    (hsep : data.Separates) :
    keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ (face₁Dart₂ data) ≠ face₁Dart₁ data := by
  intro hwrap
  -- equal darts ⇒ equal `tail`s, contradicting the distinct-vertex facts.
  have htail : M.tail ((keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ (face₁Dart₂ data) :
      {d : D // d ∉ data.keptDel₁}) : D)
        = M.tail ((face₁Dart₁ data : {d : D // d ∉ data.keptDel₁}) : D) := by
    rw [hwrap]
  rw [keptPhi_face₁Dart₂_tail data hsep, face₁Dart₁_tail data] at htail
  exact u_ne_v data htail





















end ProofsInTheBook.ChordSigmaContig

















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSigmaContig
-/
/- Source module: ProofsInTheBook.ZinanCh35SideAnchors -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ZinanCh35SideAnchors

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordInnerTri
open ProofsInTheBook.ChordBoundaryOrbit
open ProofsInTheBook.ChordFaceFinal
open ProofsInTheBook.ChordAnchor
open ProofsInTheBook.ChordAnchorInst
open ProofsInTheBook.ChordSigmaContig

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



/-- **The canonical side-1 anchor `a₀`** — the kept dart whose `sideSigma₁`-successor is
`keptPhi d₂`. -/
noncomputable def side₁Anchor₀ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    {d : D // d ∉ data.keptDel₁} :=
  (data.sideSigma₁).symm
    (keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ (face₁Dart₂ data))

/-- **The canonical side-1 anchor `a₁`** — the kept dart whose `sideSigma₁`-successor is
`d₁ = M.φ dart`. -/
noncomputable def side₁Anchor₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    {d : D // d ∉ data.keptDel₁} :=
  (data.sideSigma₁).symm (face₁Dart₁ data)

/-- **`sideSigma₁ a₀ = keptPhi d₂`** (definitional, `Equiv.apply_symm_apply`). -/
@[simp] theorem sideSigma₁_side₁Anchor₀ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    data.sideSigma₁ (side₁Anchor₀ data hsep)
      = keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ (face₁Dart₂ data) := by
  rw [side₁Anchor₀, Equiv.apply_symm_apply]

/-- **`sideSigma₁ a₁ = d₁`** (definitional, `Equiv.apply_symm_apply`). -/
@[simp] theorem sideSigma₁_side₁Anchor₁ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    data.sideSigma₁ (side₁Anchor₁ data hsep) = face₁Dart₁ data := by
  rw [side₁Anchor₁, Equiv.apply_symm_apply]

/-- **The canonical anchors are distinct.**  If `a₀ = a₁` then their `sideSigma₁`-images
agree, i.e. `keptPhi d₂ = d₁` — refuted by the proven geometric fact
`ChordSigmaContig.keptPhi_face₁Dart₂_ne_face₁Dart₁` (the false-wrap correction). -/
theorem side₁Anchors_ne (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    side₁Anchor₀ data hsep ≠ side₁Anchor₁ data hsep := by
  intro h
  -- equal anchors ⇒ equal `sideSigma₁`-images ⇒ `keptPhi d₂ = d₁`, contradiction.
  have himg : data.sideSigma₁ (side₁Anchor₀ data hsep)
      = data.sideSigma₁ (side₁Anchor₁ data hsep) := by rw [h]
  rw [sideSigma₁_side₁Anchor₀, sideSigma₁_side₁Anchor₁] at himg
  exact keptPhi_face₁Dart₂_ne_face₁Dart₁ data hsep himg



/-- **`d₁` and `keptPhi d₂` lie on a common `keptPhi`-cycle.**  `keptPhi.SameCycle d₁
(keptPhi d₂)`: `keptPhi d₁ = d₂` (`keptPhi_face₁Dart₁`), and `keptPhi d₂` is one further
forward step from `d₂`, so `d₁ → d₂ → keptPhi d₂` is a `keptPhi`-walk. -/
theorem keptPhi_sameCycle_d₁_keptPhi_d₂ (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    (keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁).SameCycle
      (face₁Dart₁ data)
      (keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁ (face₁Dart₂ data)) := by
  -- peel the outer `keptPhi` on the right: reduce to `SameCycle d₁ d₂`.
  rw [Equiv.Perm.sameCycle_apply_right]
  -- `SameCycle d₁ d₂` from `keptPhi d₁ = d₂`.
  rw [← keptPhi_face₁Dart₁ data hsep]
  exact (Equiv.Perm.sameCycle_apply_right.mpr (Equiv.Perm.SameCycle.refl _ _))

/-- **The anchor-incidence fact for the canonical anchors** (`Side₁AnchorsShareFace`).  The
canonical anchors' `sideSigma₁`-successors `keptPhi d₂` and `d₁` lie on a common kept
(`keptPhi`) face — the shared pre-splice boundary face (the `face₁` orbit).  This is the
proven fact-2 instance the chord-side disk/sphere machinery
(`ChordDisk.side₁_isSphereMap_of_disk`, `ChordSideNT.side₁_sphere_unconditional`) consumes,
now SUPPLIED for the canonical anchors. -/
theorem side₁AnchorsShareFace_canonical (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    ProofsInTheBook.ChordDisk.Side₁AnchorsShareFace data hsep
      (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep) := by
  -- unfold to `keptPhi.SameCycle (sideSigma₁ a₀) (sideSigma₁ a₁)`,
  show (keptPhi (data.sideAlpha₁ hsep) data.sideSigma₁).SameCycle
    (data.sideSigma₁ (side₁Anchor₀ data hsep)) (data.sideSigma₁ (side₁Anchor₁ data hsep))
  rw [sideSigma₁_side₁Anchor₀, sideSigma₁_side₁Anchor₁]
  -- i.e. `SameCycle (keptPhi d₂) d₁`, the symmetric of `keptPhi_sameCycle_d₁_keptPhi_d₂`.
  exact (keptPhi_sameCycle_d₁_keptPhi_d₂ data hsep).symm



/-- **The easy splice-swap direction `tracePhi d₂ = d₁`** for the canonical anchors.  Since
`ρ a₀ = keptPhi d₂`, the swap `swap (keptPhi d₂) (ρ a₁)` sends `keptPhi d₂ ↦ ρ a₁ = d₁`. -/
theorem side₁Anchors_trace21 (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁
        (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep) (face₁Dart₂ data)
      = face₁Dart₁ data := by
  rw [tracePhi_eq_swap_keptPhi, sideSigma₁_side₁Anchor₀, sideSigma₁_side₁Anchor₁]
  -- `swap (keptPhi d₂) d₁ (keptPhi d₂) = d₁`.
  exact Equiv.swap_apply_left _ _

/-- **The other splice-swap direction `tracePhi d₁ = d₂`** for the canonical anchors.
`tracePhi d₁ = swap (keptPhi d₂) d₁ (keptPhi d₁)`; `keptPhi d₁ = d₂`
(`keptPhi_face₁Dart₁`), and `d₂ ∉ {keptPhi d₂, d₁}` (`keptPhi_face₁Dart₂_ne_self`,
`face₁Dart_distinct`), so the swap fixes `d₂`. -/
theorem side₁Anchors_trace12 (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁
        (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep) (face₁Dart₁ data)
      = face₁Dart₂ data := by
  rw [tracePhi_eq_swap_keptPhi, sideSigma₁_side₁Anchor₀, sideSigma₁_side₁Anchor₁,
    keptPhi_face₁Dart₁ data hsep]
  -- `swap (keptPhi d₂) d₁ d₂ = d₂` since `d₂ ≠ keptPhi d₂` and `d₂ ≠ d₁`.
  refine Equiv.swap_apply_of_ne_of_ne ?_ ?_
  · -- `d₂ ≠ keptPhi d₂` (symm of `keptPhi_face₁Dart₂_ne_self`).
    exact (keptPhi_face₁Dart₂_ne_self data hsep).symm
  · -- `d₂ ≠ d₁` (symm of `face₁Dart_distinct`).
    exact (face₁Dart_distinct data).symm







end ProofsInTheBook.ZinanCh35SideAnchors













end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35SideAnchors
-/
/- Source module: ProofsInTheBook.ZinanCh35Hclass -/
section
set_option autoImplicit true


/-!
# The Chapter 35 chord-side `hclass` gluing bricks (the `ContiguousInterval` master glue)

`ZinanCh35SideAnchors.lean` pinned the **canonical** chord-cap anchors `a₀, a₁` of side 1 and
proved, UNCONDITIONALLY, the post-splice `tracePhi` 2-cycle on the two kept `face₁` darts
(`side₁Anchors_trace12`/`trace21`).  This file assembles those anchor facts, together with the
explicit-trace orbit machinery of `ChordBoundaryOrbit` and the correct-anchor structure of
`ChordAnchor`, into the master **per-face classifier** consumed by
`ChordAnchor.contiguousInterval_of_correctAnchor`:

> for every non-outer side face `g`, EITHER `g` has a splice-untouched, side-`₁`,
> non-`face₁` kept-`inl` representative, OR `g` carries a `CorrectAnchorTwoCycle` datum.

and then feeds it into the final `ContiguousInterval` assembler.

## Bricks (design §8 order)

1.  Notation block (`β ρ a₀ a₁ hne S τ`).
2.  `side₁_trace_beta_a0_to_face₁Dart₁` — `τ (β a₀) = face₁Dart₁ data`
    (`tracePhi_b0` + `sideSigma₁_side₁Anchor₁`).
3.  `side₁_chord0_face_eq_face₁_canonical` — `S.dartFace (inr 0) = S.dartFace (inl face₁Dart₁)`
    (`chordDart_face_eq_b0` + `sideFace_inl_eq_iff_tracePhi` via brick 2).
4.  `Side₁OuterTraceData` — the INPUT bundle (outer face + its boundary cycle, the two chord/face
    incidence facts, and the inner-rep avoidance residue).
5.  `side₁Anchors_oneFresh_canonical` — the one-fresh indicator `= 1`.
6.  `side₁_correctAnchor_face₁_canonical` — the `CorrectAnchorTwoCycle` datum for the touched
    `face₁` side face (`correctAnchorTwoCycle_ofFace₁` + bricks 5 & landed trace12/trace21).
7.  `side1_hclass_canonical` — the MASTER per-face classifier (face₁ branch transports brick 6
    across the face equality; no-hit branch uses `spliceUntouched_of_face_ne_chordOrbits`).
8.  `contiguousInterval_canonical` — feed brick 7 into `contiguousInterval_of_correctAnchor`.

**Input-bundle addition (reported per the design's license).**  The design's
`Side₁OuterTraceData` lists `outerFace, outerCycle, outer_simple, outer_len, chord1_is_outer,
face₁_not_outer`.  The no-hit branch's `M.dartFace k.1 ∈ side₁` (`hside`) obligation is the
genuine geometric residue "the side outer face is exactly the `M`-outer-arc orbit, so every other
face's rep avoids the `M`-outer face" — NOT derivable from the abstract `CombMap`.  Rather than
weaken, we carry it as the repo-native field `inner_reps :
ChordBoundaryOrbit.InnerRepsAvoidBoundary …` (which packages exactly "each non-outer side face has
a kept-`inl` rep with `M`-face `≠ M`-outer and `≠ face₁`"), as the design explicitly permits.

No `sorry` / `axiom` / `admit` / `native_decide`.
-/

set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ZinanCh35Hclass

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordInnerTri
open ProofsInTheBook.ChordFaceClass
open ProofsInTheBook.ChordBoundaryOrbit
open ProofsInTheBook.ChordFaceFinal
open ProofsInTheBook.ChordAnchor
open ProofsInTheBook.ChordAnchorInst
open ProofsInTheBook.ChordSigmaContig
open ProofsInTheBook.ZinanCh35SideAnchors

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}





/-- **`τ (β a₀) = face₁Dart₁`** for the canonical anchors. -/
theorem side₁_trace_beta_a0_to_face₁Dart₁
    (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁
        (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep)
        ((data.sideAlpha₁ hsep) (side₁Anchor₀ data hsep))
      = face₁Dart₁ data := by
  rw [tracePhi_b0 (data.sideAlpha₁ hsep) data.sideSigma₁ (data.sideAlpha₁_involutive hsep),
    sideSigma₁_side₁Anchor₁]

/-- **`β a₀` is `τ`-SameCycle to `face₁Dart₁`** (one `τ`-step), the orbit form of brick 2. -/
theorem side₁_betaA0_sameCycle_face₁Dart₁
    (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁
        (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep)).SameCycle
      ((data.sideAlpha₁ hsep) (side₁Anchor₀ data hsep)) (face₁Dart₁ data) := by
  refine ⟨1, ?_⟩
  rw [zpow_one]
  exact side₁_trace_beta_a0_to_face₁Dart₁ data hsep



/-- **The fresh dart `inr 0` joins the `face₁` side face**: `S.dartFace (inr 0) = S.dartFace
(inl face₁Dart₁)`. -/
theorem side₁_chord0_face_eq_face₁_canonical
    (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    (data.sideMap₁ hsep (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep)
        (side₁Anchors_ne data hsep)).dartFace (Sum.inr 0)
      = (data.sideMap₁ hsep (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep)
          (side₁Anchors_ne data hsep)).dartFace (Sum.inl (face₁Dart₁ data)) := by
  -- `inr 0 ↦ inl (β a₀)` (wrapper, in `sideMap₁` form), then `inl (β a₀) ↦ inl face₁Dart₁`.
  rw [sideMap₁_chordDart_face_eq_b0 data hsep (side₁Anchor₀ data hsep)
        (side₁Anchor₁ data hsep) (side₁Anchors_ne data hsep)]
  -- `S.dartFace (inl (β a₀)) = S.dartFace (inl face₁Dart₁)` iff `β a₀ ~τ face₁Dart₁` (brick 2).
  exact (sideFace_inl_eq_iff_tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁
    (data.sideAlpha₁_involutive hsep) (data.sideAlpha₁_no_fixed hsep)
    (side₁Anchors_ne data hsep)
    ((data.sideAlpha₁ hsep) (side₁Anchor₀ data hsep)) (face₁Dart₁ data)).2
    (side₁_betaA0_sameCycle_face₁Dart₁ data hsep)





















end ProofsInTheBook.ZinanCh35Hclass










end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Hclass
import ProofsInTheBook.PlanarMapDeletedBoundary
-/
/- Source module: ProofsInTheBook.ZinanCh35OuterTrace -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35OuterTrace

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordInnerTri
open ProofsInTheBook.ChordFaceClass
open ProofsInTheBook.ChordBoundaryOrbit
open ProofsInTheBook.ChordFaceFinal
open ProofsInTheBook.ChordAnchor
open ProofsInTheBook.ChordAnchorInst
open ProofsInTheBook.ChordSigmaContig
open ProofsInTheBook.ZinanCh35SideAnchors
open ProofsInTheBook.ZinanCh35Hclass

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u



section PermSplit

variable {D : Type*} [Fintype D] [DecidableEq D]

/-- **Right-multiplication split.**  If `a ≠ b` and `a, b` are in the same `p`-cycle, then
`p * swap a b` does NOT have `a, b` in one cycle.  (The `same`-cycle branch of the dichotomy:
the swap splits the shared cycle.) -/
theorem notSameCycle_mul_swap_right_of_sameCycle (p : Equiv.Perm D) {a b : D}
    (hab : a ≠ b) (hsc : p.SameCycle a b) :
    ¬ (p * Equiv.swap a b).SameCycle a b := by
  intro hqsc
  -- If both `p` and `p * swap` had `a, b` same-cycle, the cycle counts coincide,
  -- contradicting `numCycles_mul_swap_ne`.
  have hq_le_p : numCycles (p * Equiv.swap a b) ≤ numCycles p := by
    have h := PermTranspositionCycleCount.numCycles_le_mul_swap_of_sameCycle
      (p * Equiv.swap a b) hqsc
    simpa [mul_assoc] using h
  have hp_le_q : numCycles p ≤ numCycles (p * Equiv.swap a b) :=
    PermTranspositionCycleCount.numCycles_le_mul_swap_of_sameCycle p hsc
  exact PermTranspositionCycleCount.numCycles_mul_swap_ne p hab
    (le_antisymm hq_le_p hp_le_q)

/-- **Left-multiplication split.**  If `a ≠ b` and `a, b` are in the same `p`-cycle, then
`swap a b * p` does NOT have `a, b` in one cycle.  Reduced to the right-multiplication split by
conjugation with `swap a b` (which fixes the cycle structure and swaps `a ↔ b`). -/
theorem notSameCycle_swap_mul_left_of_sameCycle (p : Equiv.Perm D) {a b : D}
    (hab : a ≠ b) (hsc : p.SameCycle a b) :
    ¬ (Equiv.swap a b * p).SameCycle a b := by
  intro hsc'
  -- Conjugating `(swap a b * p).SameCycle a b` by `g := swap a b`:
  -- `(swap·(swap·p)·swap⁻¹).SameCycle (swap a)(swap b)`, and
  -- `swap·(swap·p)·swap⁻¹ = p·swap⁻¹ = p·swap`, `swap a = b`, `swap b = a`.
  apply notSameCycle_mul_swap_right_of_sameCycle p hab hsc
  have h2 := hsc'.conj (g := Equiv.swap a b)
  -- normalise the conjugate permutation and the two swapped endpoints.
  have hperm : Equiv.swap a b * (Equiv.swap a b * p) * (Equiv.swap a b)⁻¹
      = p * Equiv.swap a b := by
    rw [← mul_assoc, Equiv.swap_mul_self, one_mul, Equiv.swap_inv]
  rw [hperm, Equiv.swap_apply_left, Equiv.swap_apply_right] at h2
  exact h2.symm

end PermSplit



section Canonical

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

/-- **The canonical chord predecessors are NOT `tracePhi`-SameCycle.**  `τ = swap (ρ a₀) (ρ a₁)
* keptPhi`, with `keptPhi.SameCycle (ρ a₀) (ρ a₁)` (the proved `side₁AnchorsShareFace_canonical`)
and `ρ a₀ ≠ ρ a₁` (anchors distinct).  Hence the swap splits the shared kept face, so the two
chord predecessors `ρ a₀`, `ρ a₁` no longer share a `τ`-cycle; transporting one `τ`-step on each
side gives `¬ τ.SameCycle (β a₀) (β a₁)`. -/
theorem side₁_chordPred_notSameCycle_canonical
    (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    ¬ (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁
        (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep)).SameCycle
      ((data.sideAlpha₁ hsep) (side₁Anchor₀ data hsep))
      ((data.sideAlpha₁ hsep) (side₁Anchor₁ data hsep)) := by
  classical
  set β := data.sideAlpha₁ hsep with hβ
  set ρ := data.sideSigma₁ with hρ
  set a₀ := side₁Anchor₀ data hsep with ha₀
  set a₁ := side₁Anchor₁ data hsep with ha₁
  -- the share-face fact: `keptPhi.SameCycle (ρ a₀) (ρ a₁)`.
  have hshare : (keptPhi β ρ).SameCycle (ρ a₀) (ρ a₁) := by
    have h := side₁AnchorsShareFace_canonical data hsep
    -- unfolds to `keptPhi.SameCycle (sideSigma₁ a₀) (sideSigma₁ a₁)`.
    simpa [hβ, hρ, ha₀, ha₁, ProofsInTheBook.ChordDisk.Side₁AnchorsShareFace, keptPhi]
      using h
  -- `ρ a₀ ≠ ρ a₁`.
  have hne : ρ a₀ ≠ ρ a₁ := ρa₀_ne_ρa₁ ρ (side₁Anchors_ne data hsep)
  -- the split: `¬ τ.SameCycle (ρ a₀) (ρ a₁)`.
  have hsplit : ¬ (tracePhi β ρ a₀ a₁).SameCycle (ρ a₀) (ρ a₁) := by
    rw [show tracePhi β ρ a₀ a₁ = Equiv.swap (ρ a₀) (ρ a₁) * keptPhi β ρ from rfl]
    exact notSameCycle_swap_mul_left_of_sameCycle (keptPhi β ρ) hne hshare
  -- transport: `τ (β a₀) = ρ a₁` and `τ (β a₁) = ρ a₀`, so
  -- `τ.SameCycle (β a₀) (β a₁) ↔ τ.SameCycle (ρ a₁) (ρ a₀)`.
  intro hsc
  apply hsplit
  have hb0 : tracePhi β ρ a₀ a₁ (β a₀) = ρ a₁ :=
    tracePhi_b0 β ρ (data.sideAlpha₁_involutive hsep) a₀ a₁
  have hb1 : tracePhi β ρ a₀ a₁ (β a₁) = ρ a₀ :=
    tracePhi_b1 β ρ (data.sideAlpha₁_involutive hsep) a₀ a₁
  -- `τ.SameCycle (β a₀) (β a₁) → τ.SameCycle (τ (β a₀)) (τ (β a₁)) = τ.SameCycle (ρ a₁) (ρ a₀)`.
  have hstep : (tracePhi β ρ a₀ a₁).SameCycle
      (tracePhi β ρ a₀ a₁ (β a₀)) (tracePhi β ρ a₀ a₁ (β a₁)) :=
    hsc.apply_left.apply_right
  rw [hb0, hb1] at hstep
  exact hstep.symm

/-- **`face₁_not_outer` for `outerFace := S.dartFace (inr 1)`.**  `S.dartFace (inl face₁Dart₁)
= S.dartFace (inr 0)` (brick 3), and `S.dartFace (inr 0) ≠ S.dartFace (inr 1)` by
`chordOrbits_eq_iff_tracePhi` + the splice-split fact. -/
theorem side₁_face₁_not_outer_canonical
    (data : hNT.ChordSplitData u v) (hsep : data.Separates) :
    (data.sideMap₁ hsep (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep)
        (side₁Anchors_ne data hsep)).dartFace (Sum.inl (face₁Dart₁ data))
      ≠ (data.sideMap₁ hsep (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep)
          (side₁Anchors_ne data hsep)).dartFace (Sum.inr 1) := by
  intro hcontra
  -- `S.dartFace (inr 0) = S.dartFace (inl face₁Dart₁) = S.dartFace (inr 1)`.
  have h01 : (data.sideMap₁ hsep (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep)
        (side₁Anchors_ne data hsep)).dartFace (Sum.inr 0)
      = (data.sideMap₁ hsep (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep)
          (side₁Anchors_ne data hsep)).dartFace (Sum.inr 1) := by
    rw [side₁_chord0_face_eq_face₁_canonical data hsep, hcontra]
  -- `chordOrbits_eq_iff_tracePhi` : the chord-dart faces coincide iff the chord predecessors
  -- share a `tracePhi`-orbit.
  have hsame : (tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁
      (side₁Anchor₀ data hsep) (side₁Anchor₁ data hsep)).SameCycle
        ((data.sideAlpha₁ hsep) (side₁Anchor₀ data hsep))
        ((data.sideAlpha₁ hsep) (side₁Anchor₁ data hsep)) :=
    (chordOrbits_eq_iff_tracePhi (data.sideAlpha₁ hsep) data.sideSigma₁
      (data.sideAlpha₁_involutive hsep) (data.sideAlpha₁_no_fixed hsep)
      (side₁Anchors_ne data hsep)).1 h01
  exact side₁_chordPred_notSameCycle_canonical data hsep hsame









end Canonical

end ProofsInTheBook.ZinanCh35OuterTrace









end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSplitFinal
import ProofsInTheBook.ZinanCh35OuterTrace
-/
/- Source module: ProofsInTheBook.ZinanCh35Iota -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Iota

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ChordSideNT
open ProofsInTheBook.ChordSplitFinal
open ProofsInTheBook.ChordDisk
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex} {α : Type u} [DecidableEq α]



/-- **`ι` computes on a class to the `M.tail` of its projected representative.**  By the
`Quotient.lift` definition of `sideVertexToM₁`, the class of a representative `y` maps to
`M.tail (proj a₀ a₁ y).1`.  (This is the generalisation of `sideVertexToM₁_inl` to arbitrary
representatives, fresh darts included.) -/
lemma sideVertexToM₁_mk (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (y : {d : D // d ∉ data.keptDel₁} ⊕ Fin 2) :
    sideVertexToM₁ data hsep a₀ a₁ hne
        (Quotient.mk (cycleSetoid (freshSigma data.sideSigma₁ a₀ a₁ hne)) y)
      = M.tail (proj a₀ a₁ y).1 :=
  rfl

/-- **Brick 1 — `ι` is injective.**  `ι ⟦y⟧ = ι ⟦z⟧` gives `M.σ.SameCycle (proj y).1 (proj z).1`
(`M.tail` equal ⇒ same `σ`-cycle, `Quotient.exact`).  Transport back: a `sideSigma₁`-SameCycle of
`proj y`, `proj z` (`filteredRotation_sameCycle_iff`), then a `freshSigma`-SameCycle of `y`, `z`
(`freshSigma_sameCycle_iff` backward), i.e. `⟦y⟧ = ⟦z⟧`.  Purely combinatorial. -/
theorem sideVertexToM₁_injective_canonical (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) :
    Function.Injective (sideVertexToM₁ data hsep a₀ a₁ hne) := by
  -- reduce to representatives.
  refine fun X Y => ?_
  refine Quotient.inductionOn₂ X Y (fun y z hYZ => ?_)
  -- `hYZ : ι ⟦y⟧ = ι ⟦z⟧`, defeq `M.tail (proj y).1 = M.tail (proj z).1`.
  -- `M.tail a = M.tail b` is `Quotient.mk (cycleSetoid M.σ) a = …`, so `Quotient.exact` gives
  -- `M.σ.SameCycle a b` (Lean unfolds `ι ⟦·⟧ = M.tail (proj ·).1` definitionally).
  have hM : M.σ.SameCycle (proj a₀ a₁ y).1 (proj a₀ a₁ z).1 := Quotient.exact hYZ
  -- back to a `sideSigma₁`-SameCycle of the (kept) projections.
  have hss : data.sideSigma₁.SameCycle (proj a₀ a₁ y) (proj a₀ a₁ z) :=
    (FilteredRotation.filteredRotation_sameCycle_iff M.σ data.keptDel₁
      (proj a₀ a₁ y) (proj a₀ a₁ z)).2 hM
  -- back to a `freshSigma`-SameCycle of the representatives.
  have hfs : (freshSigma data.sideSigma₁ a₀ a₁ hne).SameCycle y z :=
    (freshSigma_sameCycle_iff data.sideSigma₁ hne y z).2 hss
  exact Quotient.sound hfs



/-- `ι (sideMap₁.tail (inr j))` is `M.tail a₀.1` (`j = 0`) or `M.tail a₁.1` (`j = 1`). -/
lemma sideVertexToM₁_tail_inr (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) (j : Fin 2) :
    sideVertexToM₁ data hsep a₀ a₁ hne
        (Quotient.mk (cycleSetoid (freshSigma data.sideSigma₁ a₀ a₁ hne)) (Sum.inr j))
      = M.tail (if j = 0 then a₀.1 else a₁.1) := by
  rw [sideVertexToM₁_mk data hsep a₀ a₁ hne (Sum.inr j)]
  fin_cases j
  · simp [proj]
  · simp [proj]

/-- `freshAlpha (sideAlpha₁) (inr j)` is the *other* fresh dart `inr (swap j)`, whose `ι`-tail is
the *other* anchor.  Hence the fresh chord dart `inr j` has `ι`-endpoints `M.tail a₀.1` and
`M.tail a₁.1` (in some order). -/
lemma sideVertexToM₁_head_inr (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) (j : Fin 2) :
    sideVertexToM₁ data hsep a₀ a₁ hne
        (Quotient.mk (cycleSetoid (freshSigma data.sideSigma₁ a₀ a₁ hne))
          ((freshAlpha (data.sideAlpha₁ hsep)) (Sum.inr j)))
      = M.tail (if j = 0 then a₁.1 else a₀.1) := by
  rw [freshAlpha_inr]
  rw [sideVertexToM₁_tail_inr data hsep a₀ a₁ hne (Equiv.swap (0 : Fin 2) 1 j)]
  fin_cases j
  · simp [Equiv.swap_apply_left]
  · simp [Equiv.swap_apply_right]

/-- **The `ι`-edge of any side dart.**  For every side dart `d`, the `ι`-images of its side
endpoints `sideMap₁.tail d`, `sideMap₁.head d` are `M`-adjacent: an `inl x'` dart gives the proved
`M`-edge of `x'` (`ι_adj_of_inl`); a fresh chord dart gives the anchor-tail pair (`M`-adjacent by
`hchord`).  `sideMap₁.tail d = ⟦d⟧` and `sideMap₁.head d = ⟦freshAlpha _ d⟧` (definitional). -/
lemma ι_adj_of_dart (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (hchord : M.Adj (M.tail a₀.1) (M.tail a₁.1))
    (d : {d : D // d ∉ data.keptDel₁} ⊕ Fin 2) :
    M.Adj
      (sideVertexToM₁ data hsep a₀ a₁ hne
        (Quotient.mk (cycleSetoid (freshSigma data.sideSigma₁ a₀ a₁ hne)) d))
      (sideVertexToM₁ data hsep a₀ a₁ hne
        (Quotient.mk (cycleSetoid (freshSigma data.sideSigma₁ a₀ a₁ hne))
          ((freshAlpha (data.sideAlpha₁ hsep)) d))) := by
  cases d with
  | inl x' => exact ι_adj_of_inl data hsep a₀ a₁ hne x'
  | inr j =>
      rw [sideVertexToM₁_tail_inr data hsep a₀ a₁ hne j,
        sideVertexToM₁_head_inr data hsep a₀ a₁ hne j]
      fin_cases j
      · simpa using hchord
      · simpa using M.adj_symm hchord



/-- **Brick 2 — `ι_adj`.**  Side adjacency `sideMap₁.toSimpleGraph.Adj x y` carries to
`M.toSimpleGraph.Adj (ι x) (ι y)`.  The witnessing side dart `d` gives `s(x, y) = sideMap₁.dartEdge
d = s(sideMap₁.tail d, sideMap₁.head d)`, whose `ι`-images are `M`-adjacent (`ι_adj_of_dart`); the
unordered pair matches by `Sym2.eq_iff`.  The `≠` half is preserved by injectivity (Brick 1). -/
theorem sideVertexToM₁_adj_canonical (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (hchord : M.Adj (M.tail a₀.1) (M.tail a₁.1)) :
    ∀ ⦃x y : (data.sideMap₁ hsep a₀ a₁ hne).Vertex⦄,
      (data.sideMap₁ hsep a₀ a₁ hne).toSimpleGraph.Adj x y →
        M.toSimpleGraph.Adj (sideVertexToM₁ data hsep a₀ a₁ hne x)
          (sideVertexToM₁ data hsep a₀ a₁ hne y) := by
  intro x y hxy
  rw [toSimpleGraph_adj] at hxy ⊢
  obtain ⟨hne_xy, d, hd⟩ := hxy
  -- the `≠` part: `ι x ≠ ι y` from injectivity + `x ≠ y`.
  refine ⟨fun h => hne_xy (sideVertexToM₁_injective_canonical data hsep a₀ a₁ hne h), ?_⟩
  -- `s(x, y) = sideMap₁.dartEdge d = s(sideMap₁.tail d, sideMap₁.head d)` (the last `=` is `rfl`).
  have hM := ι_adj_of_dart data hsep a₀ a₁ hne hchord d
  -- `sideMap₁.tail d = ⟦d⟧` and `sideMap₁.head d = ⟦freshAlpha _ d⟧` (definitional), so:
  have hd' : s((data.sideMap₁ hsep a₀ a₁ hne).tail d, (data.sideMap₁ hsep a₀ a₁ hne).head d)
      = s(x, y) := hd
  rcases Sym2.eq_iff.1 hd' with ⟨hx, hy⟩ | ⟨hx, hy⟩
  · rw [← hx, ← hy]; exact hM
  · rw [← hx, ← hy]; exact M.adj_symm hM



/-- **Brick 3 — `ι_adj_reflect`, isolated as the named confinement residue.**  We do NOT silently
assume more than the field itself: the brick simply *is* the hypothesis, recorded as the minimal
region edge-confinement fact (an `M`-edge between two `ι`-images is a side edge), which the open
`ChordSplitRegions`/Schoenflies layer is responsible for.  Reported in the handoff as the genuine
planar block. -/
theorem sideVertexToM₁_adj_reflect_canonical (data : hNT.ChordSplitData u v)
    (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (hreflect : ∀ ⦃x y : (data.sideMap₁ hsep a₀ a₁ hne).Vertex⦄,
      M.toSimpleGraph.Adj (sideVertexToM₁ data hsep a₀ a₁ hne x)
          (sideVertexToM₁ data hsep a₀ a₁ hne y) →
        (data.sideMap₁ hsep a₀ a₁ hne).toSimpleGraph.Adj x y) :
    ∀ ⦃x y : (data.sideMap₁ hsep a₀ a₁ hne).Vertex⦄,
      M.toSimpleGraph.Adj (sideVertexToM₁ data hsep a₀ a₁ hne x)
          (sideVertexToM₁ data hsep a₀ a₁ hne y) →
        (data.sideMap₁ hsep a₀ a₁ hne).toSimpleGraph.Adj x y :=
  hreflect



/-- **Brick 5 — `smaller`.**  From the proved injectivity of `ι` and an explicit omitted
`M`-vertex `w ∉ Set.range ι` (the opposite-arc internal vertex side 1 drops — the named
region-confinement residue `homit`), the side has strictly fewer vertices than `M`. -/
theorem side₁_smaller_canonical (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁)
    (homit : ∃ w : M.Vertex, w ∉ Set.range (sideVertexToM₁ data hsep a₀ a₁ hne)) :
    (data.sideMap₁ hsep a₀ a₁ hne).V < M.V := by
  classical
  obtain ⟨w, hw⟩ := homit
  -- `(sideMap₁).V = Fintype.card (sideMap₁).Vertex`, `M.V = Fintype.card M.Vertex`.
  show Fintype.card (data.sideMap₁ hsep a₀ a₁ hne).Vertex < Fintype.card M.Vertex
  -- the image of `ι` is a proper subset of `M.Vertex` (it misses `w`); `ι` injective.
  have hinj := sideVertexToM₁_injective_canonical data hsep a₀ a₁ hne
  -- map the (full) domain finset injectively into `M.Vertex`, missing `w`.
  have hcard_le : Fintype.card (data.sideMap₁ hsep a₀ a₁ hne).Vertex
      = (Finset.univ.image (sideVertexToM₁ data hsep a₀ a₁ hne)).card := by
    rw [Finset.card_image_of_injective _ hinj, Finset.card_univ]
  rw [hcard_le]
  -- the image is a finset of `M.Vertex` not containing `w`, hence a strict subset of `univ`.
  have hsub : Finset.univ.image (sideVertexToM₁ data hsep a₀ a₁ hne) ⊂ Finset.univ := by
    refine Finset.ssubset_univ_iff.2 ?_
    intro hfull
    apply hw
    have hmem : w ∈ Finset.univ.image (sideVertexToM₁ data hsep a₀ a₁ hne) := by
      rw [hfull]; exact Finset.mem_univ w
    obtain ⟨V, _, hV⟩ := Finset.mem_image.1 hmem
    exact ⟨V, hV⟩
  calc (Finset.univ.image (sideVertexToM₁ data hsep a₀ a₁ hne)).card
      < (Finset.univ : Finset M.Vertex).card := Finset.card_lt_card hsub
    _ = Fintype.card M.Vertex := Finset.card_univ



/-- **Brick 6 — the side-1 residue, partially assembled.**  All six non-`ci`/`hshare`
`ChordSideResidue` fields are produced: `ι_inj` and the kept-dart half of `ι_adj` PROVED
unconditionally; the fresh-chord `ι_adj` half from `hchord`; `ι_adj_reflect` from the named
confinement residue `hreflect`; `hLₛ` the residue list field; `smaller` from injectivity + the
omitted-vertex residue `homit`.

Remaining (the open `ChordSplitRegions`/discrete-Schoenflies content): `hreflect` (region
edge-confinement) and `homit` (the opposite-arc omitted vertex's not-in-range).  These are the two
honest planar inputs; `hchord` is the chord adjacency `u–v` and `hLₛ` the list transport. -/
def chordSideResidue₁_partial (data : hNT.ChordSplitData u v) (hsep : data.Separates)
    (a₀ a₁ : {d : D // d ∉ data.keptDel₁}) (hne : a₀ ≠ a₁) (L : M.Vertex → Finset α)
    (ci : ContiguousInterval data hsep a₀ a₁ hne)
    (hshare : ProofsInTheBook.ChordDisk.Side₁AnchorsShareFace data hsep a₀ a₁)
    (hchord : M.Adj (M.tail a₀.1) (M.tail a₁.1))
    (hreflect : ∀ ⦃x y : (data.sideMap₁ hsep a₀ a₁ hne).Vertex⦄,
      M.toSimpleGraph.Adj (sideVertexToM₁ data hsep a₀ a₁ hne x)
          (sideVertexToM₁ data hsep a₀ a₁ hne y) →
        (data.sideMap₁ hsep a₀ a₁ hne).toSimpleGraph.Adj x y)
    (pₛ qₛ : (data.sideMap₁ hsep a₀ a₁ hne).Vertex) (cpₛ cqₛ : α)
    (hLₛ : ThomassenLists
      (chordSideNearTriangulation_of_share data hsep a₀ a₁ hne hshare ci)
      pₛ qₛ (fun x => L (sideVertexToM₁ data hsep a₀ a₁ hne x)) cpₛ cqₛ)
    (homit : ∃ w : M.Vertex, w ∉ Set.range (sideVertexToM₁ data hsep a₀ a₁ hne)) :
    ChordSideResidue data hsep a₀ a₁ hne L :=
  chordSideResidue_mk data hsep a₀ a₁ hne L ci hshare
    (sideVertexToM₁_injective_canonical data hsep a₀ a₁ hne)
    (sideVertexToM₁_adj_canonical data hsep a₀ a₁ hne hchord)
    (sideVertexToM₁_adj_reflect_canonical data hsep a₀ a₁ hne hreflect)
    pₛ qₛ cpₛ cqₛ hLₛ
    (side₁_smaller_canonical data hsep a₀ a₁ hne homit)

end ProofsInTheBook.ZinanCh35Iota









end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCapSigma
-/
/- Source module: ProofsInTheBook.PlanarMapCutCapSigma2 -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}



open Classical in
/-- Corrected forward map of the cut-and-cap rotation `σ'`. -/
noncomputable def cutSigma2 (C : SimplePrimalCycle M) : C.CutDart → C.CutDart :=
  fun x => match x with
  | Sum.inl d =>
      match C.divertKind d with
      | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl (C.prevIdx i))  -- ℓ_i^+ ↦ c_{prevIdx i}^+  (FIX)
      | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)             -- ℓ_i^- ↦ c_i^-
      | Sum.inr () => Sum.inl (M.σ d)                          -- unchanged rotation
  | Sum.inr (Sum.inl i) => Sum.inl (C.dart (C.nextIdx i))      -- c_i^+ ↦ dart (nextIdx i)  (FIX)
  | Sum.inr (Sum.inr i) => Sum.inl (C.pDart i)                 -- c_i^- ↦ p_i

open Classical in
/-- Corrected inverse map of the cut-and-cap rotation `σ'`. -/
noncomputable def cutSigmaInv2 (C : SimplePrimalCycle M) : C.CutDart → C.CutDart :=
  fun x => match x with
  | Sum.inl d =>
      match C.startKind d with
      | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl (C.prevIdx i))  -- d = q_i ↦ c_{prevIdx i}^+  (FIX)
      | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)             -- d = p_i ↦ c_i^-
      | Sum.inr () => Sum.inl (M.σ.symm d)                     -- unchanged inverse rotation
  | Sum.inr (Sum.inl i) => Sum.inl (M.σ.symm (C.pDart (C.nextIdx i)))  -- c_i^+ ↦ ℓ_{i+1}^+ = σ⁻¹ p_{i+1}
  | Sum.inr (Sum.inr i) => Sum.inl (M.σ.symm (C.qDart i))             -- c_i^- ↦ ℓ_i^- = σ⁻¹ q_i



lemma cutSigma2_inl_plus (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.divertKind d = Sum.inl (Sum.inl i)) :
    C.cutSigma2 (Sum.inl d) = Sum.inr (Sum.inl (C.prevIdx i)) := by
  show (match C.divertKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl (C.prevIdx i))
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ d)) = _
  rw [h]

lemma cutSigma2_inl_minus (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.divertKind d = Sum.inl (Sum.inr i)) :
    C.cutSigma2 (Sum.inl d) = Sum.inr (Sum.inr i) := by
  show (match C.divertKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl (C.prevIdx i))
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ d)) = _
  rw [h]

lemma cutSigma2_inl_none (C : SimplePrimalCycle M) {d : D}
    (h : C.divertKind d = Sum.inr ()) :
    C.cutSigma2 (Sum.inl d) = Sum.inl (M.σ d) := by
  show (match C.divertKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl (C.prevIdx i))
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ d)) = _
  rw [h]

@[simp] lemma cutSigma2_capPlus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutSigma2 (Sum.inr (Sum.inl i)) = Sum.inl (C.dart (C.nextIdx i)) := rfl

@[simp] lemma cutSigma2_capMinus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutSigma2 (Sum.inr (Sum.inr i)) = Sum.inl (C.pDart i) := rfl



lemma cutSigmaInv2_inl_q (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.startKind d = Sum.inl (Sum.inl i)) :
    C.cutSigmaInv2 (Sum.inl d) = Sum.inr (Sum.inl (C.prevIdx i)) := by
  show (match C.startKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl (C.prevIdx i))
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ.symm d)) = _
  rw [h]

lemma cutSigmaInv2_inl_p (C : SimplePrimalCycle M) {d : D} {i : Fin C.len}
    (h : C.startKind d = Sum.inl (Sum.inr i)) :
    C.cutSigmaInv2 (Sum.inl d) = Sum.inr (Sum.inr i) := by
  show (match C.startKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl (C.prevIdx i))
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ.symm d)) = _
  rw [h]

lemma cutSigmaInv2_inl_none (C : SimplePrimalCycle M) {d : D}
    (h : C.startKind d = Sum.inr ()) :
    C.cutSigmaInv2 (Sum.inl d) = Sum.inl (M.σ.symm d) := by
  show (match C.startKind d with
    | Sum.inl (Sum.inl i) => Sum.inr (Sum.inl (C.prevIdx i))
    | Sum.inl (Sum.inr i) => Sum.inr (Sum.inr i)
    | Sum.inr () => Sum.inl (M.σ.symm d)) = _
  rw [h]

@[simp] lemma cutSigmaInv2_capPlus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutSigmaInv2 (Sum.inr (Sum.inl i)) = Sum.inl (M.σ.symm (C.pDart (C.nextIdx i))) := rfl

@[simp] lemma cutSigmaInv2_capMinus (C : SimplePrimalCycle M) (i : Fin C.len) :
    C.cutSigmaInv2 (Sum.inr (Sum.inr i)) = Sum.inl (M.σ.symm (C.qDart i)) := rfl



open Classical in
lemma cutSigma2_leftInv (C : SimplePrimalCycle M) :
    Function.LeftInverse C.cutSigmaInv2 C.cutSigma2 := by
  intro x
  rcases x with d | (i | i)
  · -- x = inl d, split on divertKind d
    rcases hd : C.divertKind d with (i | i) | u
    · -- σ d = p_i : ℓ_i^+, goes to c_{prevIdx i}^+, must come back to inl d
      have hσ : M.σ d = C.pDart i := C.divertKind_eq_plus hd
      rw [C.cutSigma2_inl_plus hd, cutSigmaInv2_capPlus, C.nextIdx_prevIdx, ← hσ,
        M.σ.symm_apply_apply]
    · -- σ d = q_i : ℓ_i^-, goes to c_i^-, must come back
      have hσ : M.σ d = C.qDart i := C.divertKind_eq_minus hd
      rw [C.cutSigma2_inl_minus hd, cutSigmaInv2_capMinus, ← hσ, M.σ.symm_apply_apply]
    · -- unchanged
      obtain ⟨hp, hq⟩ := C.divertKind_eq_none hd
      rw [C.cutSigma2_inl_none hd, C.cutSigmaInv2_inl_none (C.startKind_none hq hp),
        M.σ.symm_apply_apply]
  · -- x = c_i^+ : σ' c_i^+ = inl (dart (nextIdx i)) = inl (q_{nextIdx i})
    rw [cutSigma2_capPlus]
    -- dart (nextIdx i) = qDart (nextIdx i); startKind sees it as q-dart at nextIdx i
    rw [show C.dart (C.nextIdx i) = C.qDart (C.nextIdx i) from rfl,
      C.cutSigmaInv2_inl_q (C.startKind_q (C.nextIdx i)), C.prevIdx_nextIdx]
  · -- x = c_i^- : σ' c_i^- = inl (p_i); startKind sees it as p-dart at i
    rw [cutSigma2_capMinus,
      show C.pDart i = C.pDart i from rfl, C.cutSigmaInv2_inl_p (C.startKind_p i)]

open Classical in
lemma cutSigma2_rightInv (C : SimplePrimalCycle M) :
    Function.RightInverse C.cutSigmaInv2 C.cutSigma2 := by
  intro x
  rcases x with d | (i | i)
  · -- x = inl d, split on startKind d
    rcases hd : C.startKind d with (i | i) | u
    · -- d = q_i : goes to c_{prevIdx i}^+, must come back to inl d = inl q_i
      have hq : d = C.qDart i := C.startKind_eq_q hd
      rw [C.cutSigmaInv2_inl_q hd, cutSigma2_capPlus, C.nextIdx_prevIdx, hq]; rfl
    · -- d = p_i : goes to c_i^-, must come back to inl p_i
      have hp : d = C.pDart i := C.startKind_eq_p hd
      rw [C.cutSigmaInv2_inl_p hd, cutSigma2_capMinus, hp]
    · -- neither
      obtain ⟨hq, hp⟩ := C.startKind_eq_none hd
      rw [C.cutSigmaInv2_inl_none hd]
      have hdiv : C.divertKind (M.σ.symm d) = Sum.inr () := by
        apply C.divertKind_none
        · intro i; rw [M.σ.apply_symm_apply]; exact hp i
        · intro i; rw [M.σ.apply_symm_apply]; exact hq i
      rw [C.cutSigma2_inl_none hdiv, M.σ.apply_symm_apply]
  · -- x = c_i^+ : inv sends it to inl (σ⁻¹ p_{nextIdx i}) = ℓ_{nextIdx i}^+,
    -- which σ' sends to c_{prevIdx (nextIdx i)}^+ = c_i^+
    rw [cutSigmaInv2_capPlus]
    have hdiv : C.divertKind (M.σ.symm (C.pDart (C.nextIdx i))) = Sum.inl (Sum.inl (C.nextIdx i)) :=
      C.divertKind_plus (by rw [M.σ.apply_symm_apply])
    rw [C.cutSigma2_inl_plus hdiv, C.prevIdx_nextIdx]
  · -- x = c_i^- : inv sends it to inl (σ⁻¹ q_i) = ℓ_i^-, which σ' sends to c_i^-
    rw [cutSigmaInv2_capMinus]
    have hdiv : C.divertKind (M.σ.symm (C.qDart i)) = Sum.inl (Sum.inr i) :=
      C.divertKind_minus (by rw [M.σ.apply_symm_apply])
    rw [C.cutSigma2_inl_minus hdiv]

/-- The corrected vertex rotation `σ'` as a permutation of the cut dart set. -/
noncomputable def cutSigmaPerm2 (C : SimplePrimalCycle M) : Equiv.Perm C.CutDart where
  toFun := C.cutSigma2
  invFun := C.cutSigmaInv2
  left_inv := C.cutSigma2_leftInv
  right_inv := C.cutSigma2_rightInv

@[simp] lemma cutSigmaPerm2_apply (C : SimplePrimalCycle M) (x : C.CutDart) :
    C.cutSigmaPerm2 x = C.cutSigma2 x := rfl





















end SimplePrimalCycle











end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCapF
-/
/- Source module: ProofsInTheBook.PlanarMapCutCapFCore -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}

open CutCapCount























end SimplePrimalCycle

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCapSigma2
import ProofsInTheBook.PlanarMapCutCapFCore
-/
/- Source module: ProofsInTheBook.PlanarMapCutCap2Counts -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}

open CutCapCount



































-- Triangle anchor (`PlanarMapCutCapEval.lean`):  V' = 6 = V + k = 3 + 3.























-- Triangle anchor (`PlanarMapCutCapEval.lean`):  F' = 4 = F + 2 = 2 + 2.







end SimplePrimalCycle

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCapSigma
-/
/- Source module: ProofsInTheBook.PlanarMapCutCapEval -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv



section Counters

variable {α : Type*} [DecidableEq α]

















end Counters



namespace TriangleMap

open CombMap



















-- α', σ', φ' cycle counts of the *base* triangle map:
                 -- V = 3 (expected)
                 -- E = 3 (expected)
  -- F = 2 (expected)
-- χ = V - E + F = 3 - 3 + 2 = 2.


-- base-map connectivity: one dartStep component.
        -- c = 1 (connected, expected)

end TriangleMap



namespace TriangleCut

open CombMap TriangleMap




























-- σ' table:  (enc x, enc (σ' x))

-- α' table:

-- φ' = σ' ∘ α' table:




-- E' = number of α'-cycles  (expected 6 = E + k = 3 + 3):

-- V' = number of σ'-cycles  (expected 6 = V + k = 3 + 3):

-- F' = number of φ'-cycles  (φ' = σ' ∘ α'):

-- χ' = V' - E' + F'




-- c = number of dartStep-components of the cut map  (the disputed number):


-- Sanity: cutAlphaC and cutSigmaC are bijections (images have 12 distinct darts).
   -- expect 12
   -- expect 12


  -- F + 2c - 2





              -- c_i^- ↦ p_i

-- corrected σ' table:

-- corrected φ' = σ'₂ ∘ α':


-- CORRECTED verdict numbers:
                              -- E' = 6
                             -- V' = 6
    -- F' = 4  (FIXED)
  -- χ' = 4
               -- c = 2  (FIXED)
-- corrected σ'₂ is a bijection (12 distinct images):
  -- 12

end TriangleCut

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCap2Counts
import ProofsInTheBook.PlanarMapCutCapEval
-/
/- Source module: ProofsInTheBook.PlanarMapCutCap2F -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}

open CutCapCount























end SimplePrimalCycle

end CombMap



namespace TriangleCut

open TriangleMap

-- Corrected `φ'₂ = σ'₂ ∘ α'` face-cycle count on the triangle cut:
-- expected `4 = F + 2` (`F = 2`).
   -- 4

-- The explicit `φ'₂`-orbit partition on the triangle (the structural reconnaissance):
-- forward cycle darts `{0,2,4}`, the reverse face `{1,5,3}`, the `+`-caps, the
-- `−`-caps — four orbits, `F' = 4 = F + 2`.


end TriangleCut

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCap2F
-/
/- Source module: ProofsInTheBook.PlanarMapCutCap2FWalk -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}

open CutCapCount

























end SimplePrimalCycle

end CombMap



namespace TriangleCut

open TriangleMap

-- Corrected `φ'₂ = σ'₂ ∘ α'` face-cycle count on the triangle cut: `4 = F + 2`.
   -- 4

-- `phiLift` reference count `F + 2k = 2 + 6 = 8` (caps as 2k singletons):
   -- 8 = F + 2k

-- The two `faceCorr₂` cap chains (here pure caps `{+0,+2,+1}` and `{−0,−1,−2}`):
-- print the `φ'₂`-orbit reps so the `−(k−1)` per chain is anchored.


end TriangleCut

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCap2FWalk
import ProofsInTheBook.PlanarMapEulerInequality
-/
/- Source module: ProofsInTheBook.ForcedSplits -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

open Equiv Equiv.Perm Function

namespace ForcedSplits



variable {X : Type*} [Fintype X] [DecidableEq X]




































end ForcedSplits



namespace ProofsInTheBook.PlanarMap

open ForcedSplits CombMap CombMap.SimplePrimalCycle

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}















end SimplePrimalCycle

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCap2FWalk
-/
/- Source module: ProofsInTheBook.PlanarMapSeamChain -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

open Equiv Equiv.Perm Function List

namespace ProofsInTheBook.PlanarMap

namespace SeamChain

variable {X : Type*} [Fintype X] [DecidableEq X]























































namespace SeamChainData

































































end SeamChainData



namespace SeamChainData













end SeamChainData

end SeamChain

end ProofsInTheBook.PlanarMap
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ForcedSplits
import ProofsInTheBook.PlanarMapSeamChain
-/
/- Source module: ProofsInTheBook.FaceCorrWord -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

open Equiv Equiv.Perm Function List

namespace ProofsInTheBook.PlanarMap

namespace FaceCorrWord

open ForcedSplits SeamChain

variable {X : Type*} [Fintype X] [DecidableEq X]

































end FaceCorrWord



namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

open ForcedSplits FaceCorrWord SeamChain

variable {M : CombMap D}











end SimplePrimalCycle

end CombMap

end ProofsInTheBook.PlanarMap



namespace ProofsInTheBook.PlanarMap

namespace FaceCorrWord



end FaceCorrWord



namespace ProofsInTheBook.PlanarMap

namespace FaceCorrWordEval








section
variable {n : ℕ} (alpha sigma : Fin n → Fin n) (dart : Fin 3 → Fin n)






end






















-- The cycle-list word realises `phiLift · faceCorr₂` across genus (all `true`):



-- The cycle-list shapes (genus-dependent; the word is uniform, the splits are not):




end FaceCorrWordEval










end ProofsInTheBook.PlanarMap

end ProofsInTheBook.PlanarMap
end

/- Original source header (imports hoisted):
import ProofsInTheBook.FaceCorrWord
import ProofsInTheBook.RelationComponentCount
-/
/- Source module: ProofsInTheBook.TouchRank -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

open Equiv Equiv.Perm Function

namespace ProofsInTheBook.TouchRank

open ForcedSplits

variable {X : Type*} [Fintype X] [DecidableEq X]



































































































namespace TouchCompressionCert











































end TouchCompressionCert









end ProofsInTheBook.TouchRank



namespace ProofsInTheBook.PlanarMap

open ForcedSplits CombMap CombMap.SimplePrimalCycle
open ProofsInTheBook.TouchRank
open ProofsInTheBook.PlanarMap.FaceCorrWord

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}











end SimplePrimalCycle

end CombMap

end ProofsInTheBook.PlanarMap








end

/- Original source header (imports hoisted):
import ProofsInTheBook.TouchRank
-/
/- Source module: ProofsInTheBook.TouchCert -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

open Equiv Equiv.Perm Function List

namespace ProofsInTheBook

namespace TouchCert

open ForcedSplits ProofsInTheBook.TouchRank
open ProofsInTheBook.PlanarMap.FaceCorrWord
open ProofsInTheBook.PlanarMap.SeamChain

variable {X : Type*} [Fintype X] [DecidableEq X]













end TouchCert



namespace PlanarMap

open ForcedSplits ProofsInTheBook.TouchRank
open ProofsInTheBook.PlanarMap.FaceCorrWord
open ProofsInTheBook.TouchCert

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}









end SimplePrimalCycle

end CombMap

end PlanarMap



namespace TouchCert

open ForcedSplits ProofsInTheBook.PlanarMap.FaceCorrWord
open ProofsInTheBook.PlanarMap.SeamChain







end TouchCert

end ProofsInTheBook








end

/- Original source header (imports hoisted):
import ProofsInTheBook.TouchCert
-/
/- Source module: ProofsInTheBook.SeamStructure -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

open Equiv Equiv.Perm Function

namespace ProofsInTheBook

namespace SeamStructure

open ProofsInTheBook.TouchRank
open ProofsInTheBook.PlanarMap.FaceCorrWord
open ProofsInTheBook.PlanarMap.SeamChain

variable {X : Type*} [Fintype X] [DecidableEq X]















end SeamStructure



namespace PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}

open CutCapCount





















open ProofsInTheBook.TouchRank
open ProofsInTheBook.PlanarMap.FaceCorrWord









end SimplePrimalCycle

end CombMap

end PlanarMap



namespace SeamStructure

open ProofsInTheBook.TouchRank
open ProofsInTheBook.PlanarMap.FaceCorrWord
open ProofsInTheBook.PlanarMap.SeamChain





end SeamStructure

end ProofsInTheBook











end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCapF
-/
/- Source module: ProofsInTheBook.PlanarMapCutCapConn -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}





















































end SimplePrimalCycle



namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)



end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCapConn
-/
/- Source module: ProofsInTheBook.PlanarMapDualPathSep -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}























































end SimplePrimalCycle



namespace SimplePrimalCycle

variable {M : CombMap D}





end SimplePrimalCycle

namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)



end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapCutCap2FWalk
import ProofsInTheBook.PlanarMapDualPathSep
-/
/- Source module: ProofsInTheBook.PlanarMapBridge -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}





































































































































end SimplePrimalCycle

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapBridge
import ProofsInTheBook.PlanarMapSeparation
-/
/- Source module: ProofsInTheBook.PlanarMapBridgeWitness -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}

























end SimplePrimalCycle

namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)





end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.SeamStructure
import ProofsInTheBook.PlanarMapBridgeWitness
-/
/- Source module: ProofsInTheBook.SeamApplication -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}













end SimplePrimalCycle



namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)





end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap



namespace ProofsInTheBook.PlanarMap.CombMap.SimplePrimalCycle

variable {D : Type*} [Fintype D] [DecidableEq D] {M : CombMap D}





end ProofsInTheBook.PlanarMap.CombMap.SimplePrimalCycle










end

/- Original source header (imports hoisted):
import ProofsInTheBook.SeamApplication
-/
/- Source module: ProofsInTheBook.SeamIncidence -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function
open ProofsInTheBook.TouchRank

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}



















end SimplePrimalCycle



namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)





end NearTriangulation



namespace SimplePrimalCycle

variable {M : CombMap D}

open ProofsInTheBook.PlanarMap.FaceCorrWord
open ProofsInTheBook.SeamStructure



namespace ArcChordSeam

variable {C : SimplePrimalCycle M}







end ArcChordSeam

end SimplePrimalCycle



namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)





end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap



namespace ProofsInTheBook.PlanarMap.CombMap.SimplePrimalCycle

open ProofsInTheBook.TouchRank

variable {D : Type*} [Fintype D] [DecidableEq D] {M : CombMap D}





end ProofsInTheBook.PlanarMap.CombMap.SimplePrimalCycle










end

/- Original source header (imports hoisted):
import ProofsInTheBook.SeamIncidence
-/
/- Source module: ProofsInTheBook.DartArc -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv
open ProofsInTheBook.TouchRank
open ProofsInTheBook.PlanarMap.FaceCorrWord

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]





namespace DartArc

variable {M : CombMap D} {f : M.Face} {C : BoundaryCycle M f} {u v : M.Vertex}









end DartArc







namespace SimplePrimalCycle

variable {M : CombMap D}





















open ProofsInTheBook.PlanarMap.FaceCorrWord
open ProofsInTheBook.SeamStructure



end SimplePrimalCycle



namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)

open SimplePrimalCycle



end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap



namespace ProofsInTheBook.PlanarMap.CombMap.SimplePrimalCycle

variable {D : Type*} [Fintype D] [DecidableEq D] {M : CombMap D}







end ProofsInTheBook.PlanarMap.CombMap.SimplePrimalCycle









end

/- Original source header (imports hoisted):
import ProofsInTheBook.DartArc
import ProofsInTheBook.PlanarMapBridge
import ProofsInTheBook.PlanarMapBridgeWitness
-/
/- Source module: ProofsInTheBook.WitnessFinal -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv Equiv.Perm Function
open ProofsInTheBook.TouchRank
open ProofsInTheBook.PlanarMap.FaceCorrWord
open ProofsInTheBook.SeamStructure

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

variable {M : CombMap D}







































end SimplePrimalCycle

namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)

open SimplePrimalCycle



end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap



namespace ProofsInTheBook.PlanarMap.CombMap.SimplePrimalCycle

variable {D : Type*} [Fintype D] [DecidableEq D] {M : CombMap D}





end ProofsInTheBook.PlanarMap.CombMap.SimplePrimalCycle











end

/- Original source header (imports hoisted):
import ProofsInTheBook.WitnessFinal
import ProofsInTheBook.PlanarMapEulerInequality
-/
/- Source module: ProofsInTheBook.ChordSeparation -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.PlanarMap

open ProofsInTheBook.PlanarMap.CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace CombMap.SimplePrimalCycle

variable {M : CombMap D}















end CombMap.SimplePrimalCycle



namespace CombMap.SimplePrimalCycle

variable {M : CombMap D}



end CombMap.SimplePrimalCycle

namespace CombMap.NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)

open SimplePrimalCycle





end CombMap.NearTriangulation



namespace CombMap.SimplePrimalCycle

variable {M : CombMap D}





end CombMap.SimplePrimalCycle

namespace CombMap.NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)

open SimplePrimalCycle





end CombMap.NearTriangulation



namespace CombMap.SimplePrimalCycle



variable {M : CombMap D}







end CombMap.SimplePrimalCycle

end ProofsInTheBook.PlanarMap












end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSeparation
-/
/- Source module: ProofsInTheBook.ChordGateCompat -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open ProofsInTheBook.PlanarMap.CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace CombMap.SimplePrimalCycle

variable {M : CombMap D}

























































end CombMap.SimplePrimalCycle

end ProofsInTheBook.PlanarMap














end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordGateCompat
-/
/- Source module: ProofsInTheBook.ChordSeparationClose -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open ProofsInTheBook.PlanarMap.CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace CombMap.SimplePrimalCycle

variable {M : CombMap D}

























end CombMap.SimplePrimalCycle



namespace CombMap.NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)

open SimplePrimalCycle





end CombMap.NearTriangulation



namespace CombMap.SimplePrimalCycle

variable {M : CombMap D}







end CombMap.SimplePrimalCycle

end ProofsInTheBook.PlanarMap











end

/- Original source header (imports hoisted):
import ProofsInTheBook.FaceCorrWord
import ProofsInTheBook.ChordSeparationClose
-/
/- Source module: ProofsInTheBook.ZinanCh35CountRoute -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

open Equiv Equiv.Perm Function List
open scoped Finset

namespace ForcedSplits

variable {X : Type*} [Fintype X] [DecidableEq X]







end ForcedSplits

namespace ProofsInTheBook.PlanarMap

namespace FaceCorrWord

open ForcedSplits SeamChain

variable {X : Type*} [Fintype X] [DecidableEq X]







end FaceCorrWord

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

open ForcedSplits FaceCorrWord SeamChain

variable {M : CombMap D}












-- If Mathlib renamed this, alternates: `Finset.orderIsoOfFin S`,
-- `Fintype.equivFin {x // x ∈ S}`.

















end SimplePrimalCycle

end CombMap

namespace CombMap.NearTriangulation

variable {D : Type*} [Fintype D] [DecidableEq D]
variable {M : CombMap D} (hNT : NearTriangulation M)

open SimplePrimalCycle





end CombMap.NearTriangulation

end ProofsInTheBook.PlanarMap















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35CountRoute
-/
/- Source module: ProofsInTheBook.ZinanCh35Split -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

open Equiv Equiv.Perm Function

namespace ProofsInTheBook.PlanarMap

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace CutCapCount



section SumCongrTwo

variable {α β : Type*} [Fintype α] [DecidableEq α] [Fintype β] [DecidableEq β]



















end SumCongrTwo



end CutCapCount

namespace SimplePrimalCycle

open ForcedSplits FaceCorrWord SeamChain CutCapCount

variable {M : CombMap D}















        -- c_i⁻ ↦ dart i

  -- c_i⁻ ↦ α (dart i)















































































end SimplePrimalCycle

end CombMap

namespace CombMap.NearTriangulation

variable {D : Type*} [Fintype D] [DecidableEq D]
variable {M : CombMap D} (hNT : NearTriangulation M)

open SimplePrimalCycle





end CombMap.NearTriangulation

end ProofsInTheBook.PlanarMap




















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Split
-/
/- Source module: ProofsInTheBook.ZinanCh35Gates -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

open Equiv Equiv.Perm Function

namespace ProofsInTheBook.PlanarMap

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace SimplePrimalCycle

open CutCapCount

variable {M : CombMap D}





































end SimplePrimalCycle

end CombMap

namespace CombMap.NearTriangulation

variable {D : Type*} [Fintype D] [DecidableEq D]
variable {M : CombMap D} (hNT : NearTriangulation M)

open SimplePrimalCycle





end CombMap.NearTriangulation



namespace ProofsInTheBook.PlanarMap.CombMap.SimplePrimalCycle

variable {D : Type*} [Fintype D] [DecidableEq D] {M : CombMap D}



end ProofsInTheBook.PlanarMap.CombMap.SimplePrimalCycle

















end ProofsInTheBook.PlanarMap
end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Iota
import ProofsInTheBook.ZinanCh35Gates
-/
/- Source module: ProofsInTheBook.ZinanCh35Confinement -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Confinement

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ChordSideNT
open ProofsInTheBook.ChordSplitFinal
open ProofsInTheBook.ZinanCh35Iota
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex} {α : Type u} [DecidableEq α]























end ProofsInTheBook.ZinanCh35Confinement









end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35StarRotation
import ProofsInTheBook.ZinanCh35Confinement
-/
/- Source module: ProofsInTheBook.ZinanCh35Schoenflies -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Schoenflies

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ChordSideNT
open ProofsInTheBook.ChordSplitFinal
open ProofsInTheBook.ZinanCh35Iota
open ProofsInTheBook.ZinanCh35Confinement
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex} {α : Type u} [DecidableEq α]





































end ProofsInTheBook.ZinanCh35Schoenflies











end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Schoenflies
-/
/- Source module: ProofsInTheBook.ZinanCh35EdgeCore -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35EdgeCore

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35Schoenflies

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}































end ProofsInTheBook.ZinanCh35EdgeCore








end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35EdgeCore
-/
/- Source module: ProofsInTheBook.ZinanCh35Coverage -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Coverage

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ZinanCh35EdgeCore

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



section Abstract

variable {V : Type*} (r : V → V → Prop)





end Abstract





























end ProofsInTheBook.ZinanCh35Coverage









end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35StarRotation
import ProofsInTheBook.ZinanCh35Coverage
-/
/- Source module: ProofsInTheBook.ZinanCh35InnerConn -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35InnerConn

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ZinanCh35Coverage
open ProofsInTheBook.ZinanCh35EdgeCore

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M}





































variable {u v : M.Vertex}









end ProofsInTheBook.ZinanCh35InnerConn












end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35InnerConn
-/
/- Source module: ProofsInTheBook.ZinanCh35OuterDual -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35OuterDual

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ZinanCh35InnerConn
open ProofsInTheBook.ZinanCh35Coverage
open ProofsInTheBook.ZinanCh35EdgeCore

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M}





































variable {u v : M.Vertex}





end ProofsInTheBook.ZinanCh35OuterDual















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35OuterDual
import ProofsInTheBook.RelationComponentCount
import ProofsInTheBook.PlanarMapEulerInequality
-/
/- Source module: ProofsInTheBook.ZinanCh35OuterCount -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35OuterCount

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ZinanCh35InnerConn
open ProofsInTheBook.ZinanCh35Coverage
open ProofsInTheBook.ZinanCh35EdgeCore
open ProofsInTheBook.ZinanCh35OuterDual

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M}



























variable {u v : M.Vertex}







end ProofsInTheBook.ZinanCh35OuterCount













end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35OuterCount
-/
/- Source module: ProofsInTheBook.ZinanCh35OuterSlack -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35OuterSlack

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ZinanCh35OuterDual
open ProofsInTheBook.ZinanCh35OuterCount
open ProofsInTheBook.SubmapPlanar

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}




























variable {hNT : NearTriangulation M}







































































end ProofsInTheBook.ZinanCh35OuterSlack













end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35OuterSlack
-/
/- Source module: ProofsInTheBook.ZinanCh35BankCount -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option linter.unnecessarySimpa false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35BankCount

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ZinanCh35OuterDual
open ProofsInTheBook.ZinanCh35OuterSlack
open Equiv Equiv.Perm

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}

variable {hNT : NearTriangulation M}



/-- The boundary length `B`. -/
local notation3 "B" => hNT.outerCycle.length







































































































end ProofsInTheBook.ZinanCh35BankCount






end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35EdgeCore
-/
/- Source module: ProofsInTheBook.ZinanCh35StarConn -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35StarConn

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35EdgeCore

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

































































end ProofsInTheBook.ZinanCh35StarConn








end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35BankCount
import ProofsInTheBook.ZinanCh35StarConn
-/
/- Source module: ProofsInTheBook.ZinanCh35CycleBank -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option linter.unnecessarySimpa false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35CycleBank

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ZinanCh35OuterSlack
open Equiv Equiv.Perm

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}



variable (C : SimplePrimalCycle M)































































































































































end ProofsInTheBook.ZinanCh35CycleBank











end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35CycleBank
import ProofsInTheBook.ZinanCh35Gates
-/
/- Source module: ProofsInTheBook.ZinanCh35BankLabels -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35BankLabels

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ZinanCh35CycleBank
open Equiv Equiv.Perm

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
variable (C : SimplePrimalCycle M)











































end ProofsInTheBook.ZinanCh35BankLabels








end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Gates
-/
/- Source module: ProofsInTheBook.ZinanCh35ChordCycle -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace BoundaryCycle

variable {M : CombMap D} {f : M.Face}








end BoundaryCycle



namespace BoundaryCycle

variable {M : CombMap D} {f : M.Face}





end BoundaryCycle



namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M)

open SimplePrimalCycle



variable {u v : M.Vertex}









end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap








end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35EdgeCore
-/
/- Source module: ProofsInTheBook.ZinanCh35Schoenflies2 -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Schoenflies2

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35Schoenflies
open ProofsInTheBook.ZinanCh35EdgeCore

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

































end ProofsInTheBook.ZinanCh35Schoenflies2












end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35BankCount
import ProofsInTheBook.ZinanCh35StarConn
import ProofsInTheBook.ZinanCh35Schoenflies2
-/
/- Source module: ProofsInTheBook.ZinanCh35EdgeCoreFinal -/
section
set_option autoImplicit true




namespace ProofsInTheBook.ZinanCh35EdgeCoreFinal

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35EdgeCore
open ProofsInTheBook.ZinanCh35OuterCount
open ProofsInTheBook.ZinanCh35BankCount
open ProofsInTheBook.ZinanCh35StarConn
open ProofsInTheBook.ZinanCh35Schoenflies
open ProofsInTheBook.ZinanCh35Schoenflies2

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}







end ProofsInTheBook.ZinanCh35EdgeCoreFinal

end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Schoenflies
import ProofsInTheBook.ZinanCh35StarConn
import ProofsInTheBook.ZinanCh35EdgeCoreFinal
-/
/- Source module: ProofsInTheBook.ZinanCh35Side1Confine -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Side1Confine

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35Schoenflies
open ProofsInTheBook.ZinanCh35StarConn
open ProofsInTheBook.ZinanCh35EdgeCore
open ProofsInTheBook.ZinanCh35EdgeCoreFinal
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}













end ProofsInTheBook.ZinanCh35Side1Confine






end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35ChordCycle
import ProofsInTheBook.ZinanCh35EdgeCore
import ProofsInTheBook.ZinanCh35Side1Confine
-/
/- Source module: ProofsInTheBook.ZinanCh35ArcDartRun -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35ArcDartRun

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ZinanCh35EdgeCore

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}





namespace BoundaryPathDartRun

variable {f : M.Face} {C : BoundaryCycle M f} {a b : M.Vertex}





end BoundaryPathDartRun



section DartArcHelpers

variable {f : M.Face} {C : BoundaryCycle M f} {a b : M.Vertex}











end DartArcHelpers





namespace NearTriangulation

variable {hNT : NearTriangulation M} {u v : M.Vertex}





end NearTriangulation



namespace NearTriangulation

variable (hNT : NearTriangulation M) {u v : M.Vertex}

open ProofsInTheBook.PlanarMap.CombMap.BoundaryCycle





end NearTriangulation



namespace NearTriangulation

variable {hNT : NearTriangulation M} {u v : M.Vertex}





end NearTriangulation



namespace NearTriangulation

variable {hNT : NearTriangulation M} {u v : M.Vertex}





end NearTriangulation

end ProofsInTheBook.ZinanCh35ArcDartRun











end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35ArcDartRun
import ProofsInTheBook.ZinanCh35ChordCycle
-/
/- Source module: ProofsInTheBook.ZinanCh35Contiguity -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Contiguity

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ZinanCh35ArcDartRun

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



























end ProofsInTheBook.ZinanCh35Contiguity












end

/- Original source header (imports hoisted):
import Mathlib
-/
/- Source module: ProofsInTheBook.Chapter35 -/
section
set_option autoImplicit true




namespace ProofsInTheBook.Chapter35

open scoped BigOperators







section KempeChains







end KempeChains

section FiveColorInduction

universe u























end FiveColorInduction









end ProofsInTheBook.Chapter35

end

/- Original source header (imports hoisted):
import ProofsInTheBook.ThomassenInduction
import ProofsInTheBook.WitnessFinal
-/
/- Source module: ProofsInTheBook.JordanOracleConstruct -/
section
set_option autoImplicit true




namespace ProofsInTheBook.JordanOracleConstruct

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ThomassenInduction
open ProofsInTheBook.ListColoring

universe u











variable {D : Type u} [Fintype D] [DecidableEq D] {α : Type u} [DecidableEq α]
variable {M : CombMap D}





end ProofsInTheBook.JordanOracleConstruct



namespace ProofsInTheBook.JordanOracleConstruct

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ThomassenInduction

universe u





end ProofsInTheBook.JordanOracleConstruct








end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Schoenflies
-/
/- Source module: ProofsInTheBook.ZinanCh35FinalClose -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35FinalClose

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ChordSideNT
open ProofsInTheBook.ChordSplitFinal
open ProofsInTheBook.ChordDisk
open ProofsInTheBook.ZinanCh35Iota
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex} {α : Type u} [DecidableEq α]





























end ProofsInTheBook.ZinanCh35FinalClose










end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFanFaces
import ProofsInTheBook.ThomassenInduction
-/
/- Source module: ProofsInTheBook.ChordlessClose -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordlessClose

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {v0 : M.Vertex}























end ProofsInTheBook.ChordlessClose












end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFanFaces
import ProofsInTheBook.ChordlessClose
-/
/- Source module: ProofsInTheBook.ChordlessFinal -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordlessFinal

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ChordlessClose

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {v0 : M.Vertex}









































end ProofsInTheBook.ChordlessFinal












end

/- Original source header (imports hoisted):
import ProofsInTheBook.Chapter35
import ProofsInTheBook.JordanOracleConstruct
import ProofsInTheBook.ChordSplitFinal
import ProofsInTheBook.ZinanCh35FinalClose
import ProofsInTheBook.ChordlessFinal
-/
/- Source module: ProofsInTheBook.ZinanCh35Cert -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35Cert

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ChordSideNT
open ProofsInTheBook.ChordSplitFinal
open ProofsInTheBook.ChordSplitNT
open ProofsInTheBook.ChordDisk
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ListColoring

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D} {hNT : NearTriangulation M}
variable {u v : M.Vertex} {α : Type u} [DecidableEq α]





























end ProofsInTheBook.ZinanCh35Cert









end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Cert
import ProofsInTheBook.ZinanCh35EdgeCore
-/
/- Source module: ProofsInTheBook.ZinanCh35Side2 -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Side2

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ChordSideNT
open ProofsInTheBook.ChordSplitNT
open ProofsInTheBook.ChordSplitFinal
open ProofsInTheBook.ChordDisk
open ProofsInTheBook.ZinanCh35EdgeCore
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex} {α : Type u} [DecidableEq α]



















































































end ProofsInTheBook.ZinanCh35Side2














end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Side2
import ProofsInTheBook.ZinanCh35Side1Confine
import ProofsInTheBook.ZinanCh35EdgeCoreFinal
import ProofsInTheBook.ZinanCh35Schoenflies2
-/
/- Source module: ProofsInTheBook.ZinanCh35Side2Confine -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Side2Confine

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35EdgeCore
open ProofsInTheBook.ZinanCh35EdgeCoreFinal
open ProofsInTheBook.ZinanCh35StarConn
open ProofsInTheBook.ZinanCh35Schoenflies2
open ProofsInTheBook.ZinanCh35Side2

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}

































end ProofsInTheBook.ZinanCh35Side2Confine











end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Side1Confine
import ProofsInTheBook.ZinanCh35Side2Confine
-/
/- Source module: ProofsInTheBook.ZinanCh35BankOrient -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35BankOrient

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35EdgeCore

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



































end ProofsInTheBook.ZinanCh35BankOrient















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35BankLabels
import ProofsInTheBook.ZinanCh35ChordCycle
import ProofsInTheBook.ZinanCh35Contiguity
import ProofsInTheBook.ZinanCh35BankOrient
import ProofsInTheBook.ZinanCh35InnerConn
-/
/- Source module: ProofsInTheBook.ZinanCh35ArcSide -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35ArcSide

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35EdgeCore
open ProofsInTheBook.ZinanCh35CycleBank
open ProofsInTheBook.ZinanCh35BankLabels

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}











































































































end ProofsInTheBook.ZinanCh35ArcSide



-- The UNCONDITIONAL bank-side facts (the real new content of R8's chain A–F):








-- The honest assembly over the single isolated orientation input:






end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35ArcSide
-/
/- Source module: ProofsInTheBook.ZinanCh35Aligned -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Aligned

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35EdgeCore
open ProofsInTheBook.ZinanCh35CycleBank
open ProofsInTheBook.ZinanCh35BankLabels
open ProofsInTheBook.ZinanCh35ArcDartRun

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}











































namespace NearTriangulation

variable {hNT : NearTriangulation M} {u v : M.Vertex}























































end NearTriangulation







namespace NearTriangulation

variable {hNT : NearTriangulation M} {u v : M.Vertex}





































-- Both arcs of the normalized arc-split carry genuine internal vertices (the construction fires).


-- `Separates` for the normalized datum is the genuine chord keystone `face₂ ∉ side₁` (not trivial).


-- The datum's chord is the GIVEN chord, so `side₁`/`side₂` are the real chord sides.


-- The two runs have length ≥ 2 (genuinely longer than the chord — the arcs carry interior vertices).


end NearTriangulation

end ProofsInTheBook.ZinanCh35Aligned












end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Aligned
import ProofsInTheBook.PlanarMapDeletedBoundary
-/
/- Source module: ProofsInTheBook.ZinanCh35BoundaryAssembler -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35BoundaryAssembler

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ZinanCh35Aligned

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}



namespace BoundaryCycle

variable {f : M.Face}









end BoundaryCycle




















end ProofsInTheBook.ZinanCh35BoundaryAssembler

end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSplitNT
import ProofsInTheBook.ChordSplitFinal
import ProofsInTheBook.ZinanCh35Cert
-/
/- Source module: ProofsInTheBook.ZinanCh35Dichotomy -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35Dichotomy

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ListColoring
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ThomassenInduction
open ProofsInTheBook.ChordSplitNT
open ProofsInTheBook.ChordSplitFinal

universe u

variable {α : Type u} [DecidableEq α]























end ProofsInTheBook.ZinanCh35Dichotomy









end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Dichotomy
import ProofsInTheBook.ZinanCh35Side2
import ProofsInTheBook.ZinanCh35Aligned
-/
/- Source module: ProofsInTheBook.ZinanCh35ChordBranch -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35ChordBranch

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ChordSideNT
open ProofsInTheBook.ZinanCh35EdgeCore
open ProofsInTheBook.ZinanCh35Side2
open ProofsInTheBook.ChordSplitFinal
open ProofsInTheBook.ChordSplitNT
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ZinanCh35Aligned.NearTriangulation

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D} {hNT : NearTriangulation M}
variable {u v : M.Vertex} {α : Type u} [DecidableEq α]







































-- The residual genuinely PRODUCES (does not posit) the side-2 confinement: the field type that
-- `Side₂CertificateInputs.confinement` requires is exactly the output of
-- `bothConfinements_normalized`'s second component.


-- The residual data's `side₁`/`side₂` carry NO confinement field (audit: the confinement burden
-- is off the residual — it is the genuine reduction `bothConfinements_normalized` buys).


end ProofsInTheBook.ZinanCh35ChordBranch











end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35ChordBranch
import ProofsInTheBook.ZinanCh35EdgeCoreFinal
import ProofsInTheBook.ZinanCh35SideAnchors
import ProofsInTheBook.ChordSigmaContig
import ProofsInTheBook.ChordContiguous
-/
/- Source module: ProofsInTheBook.ZinanCh35ChordResidue -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35ChordResidue

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ChordSideNT
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordAnchor
open ProofsInTheBook.ChordSigmaContig
open ProofsInTheBook.ZinanCh35SideAnchors
open ProofsInTheBook.ZinanCh35EdgeCore
open ProofsInTheBook.ZinanCh35EdgeCoreFinal
open ProofsInTheBook.ZinanCh35StarConn
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ZinanCh35ChordBranch
open ProofsInTheBook.ZinanCh35Aligned.NearTriangulation

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D} {hNT : NearTriangulation M}
variable {u v : M.Vertex} {α : Type u} [DecidableEq α]





































-- The canonical side-1 anchors genuinely realize the chord endpoints (non-vacuity of `anchors₁`).


-- The produced region glue pins `s₁ = sideRegion₁`, `s₂ = sideRegion₂` definitionally (the
-- `regions_s₁`/`regions_s₂` of the residual data are `rfl`).


end ProofsInTheBook.ZinanCh35ChordResidue












end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35ChordResidue
import ProofsInTheBook.ZinanCh35Side2Confine
import ProofsInTheBook.ZinanCh35Schoenflies2
import ProofsInTheBook.ZinanCh35ArcSide
-/
/- Source module: ProofsInTheBook.ZinanCh35Regions -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Regions

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35EdgeCore
open ProofsInTheBook.ZinanCh35EdgeCoreFinal
open ProofsInTheBook.ZinanCh35Side2Confine
open ProofsInTheBook.ZinanCh35Schoenflies2
open ProofsInTheBook.ZinanCh35ChordResidue
open ProofsInTheBook.ZinanCh35ArcSide

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



























-- The side-2 region genuinely contains both chord endpoints (non-vacuity of `u_s₂`/`v_s₂`).


end ProofsInTheBook.ZinanCh35Regions










end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35OuterTrace
import ProofsInTheBook.ZinanCh35BoundaryAssembler
import ProofsInTheBook.ZinanCh35Side2
-/
/- Source module: ProofsInTheBook.ZinanCh35Contiguous -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35Contiguous

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.ChordBoundaryOrbit
open ProofsInTheBook.ZinanCh35SideAnchors
open ProofsInTheBook.ZinanCh35OuterTrace

open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u



section Itinerary

variable {K : Type u} [Fintype K] [DecidableEq K]
  (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)

















end Itinerary



variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



















section Audit

variable {K : Type u} [Fintype K] [DecidableEq K]
  (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)





end Audit

end ProofsInTheBook.ZinanCh35Contiguous












end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Contiguous
-/
/- Source module: ProofsInTheBook.ZinanCh35SideOuterSimple -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35SideOuterSimple

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ZinanCh35SideAnchors

universe u



section Bridge

variable {D : Type*} [Fintype D] [DecidableEq D]



end Bridge



section FreshTail

variable {K : Type u} [Fintype K] [DecidableEq K]
  (β ρ : Equiv.Perm K) (hβinv : β * β = 1) (hβfix : ∀ k, β k ≠ k)
  {a₀ a₁ : K} (hne : a₀ ≠ a₁)



end FreshTail



section SideTail

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



end SideTail



section Main

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  (hNT : NearTriangulation M) {u v : M.Vertex}

















end Main

end ProofsInTheBook.ZinanCh35SideOuterSimple











end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordAnchorInst
import ProofsInTheBook.ChordDisk
-/
/- Source module: ProofsInTheBook.ZinanCh35Side2Anchors -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ZinanCh35Side2Anchors

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData

universe u
variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



































end ProofsInTheBook.ZinanCh35Side2Anchors



end

/- Original source header (imports hoisted):
import ProofsInTheBook.ChordSideClose
-/
/- Source module: ProofsInTheBook.ZinanCh35Side2Disk -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ChordSideClose

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.ChordSideRecon
open ProofsInTheBook.SubmapPlanar

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v : M.Vertex}



















section RawConnected



























end RawConnected











end ProofsInTheBook.ChordSideClose







end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35SideOuterSimple
import ProofsInTheBook.ZinanCh35ChordResidue
import ProofsInTheBook.ZinanCh35ArcDartRun
import ProofsInTheBook.ZinanCh35EdgeCoreFinal
import ProofsInTheBook.ZinanCh35ArcSide
import ProofsInTheBook.ZinanCh35BoundaryAssembler
import ProofsInTheBook.ZinanCh35Side2Anchors
import ProofsInTheBook.ChordDisk
import ProofsInTheBook.ZinanCh35Side2Disk
import ProofsInTheBook.ZinanCh35Regions
-/
/- Source module: ProofsInTheBook.ZinanCh35OuterTraceProof -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35OuterTraceProof

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.FilteredRotation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordSplitEuler
open ProofsInTheBook.ZinanCh35SideAnchors
open ProofsInTheBook.ZinanCh35ChordResidue
open ProofsInTheBook.ZinanCh35SideOuterSimple
open ProofsInTheBook.ChordAnchor
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ZinanCh35OuterTrace
open ProofsInTheBook.ZinanCh35Side2Anchors

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}





































variable (hNT : NearTriangulation M) {u v : M.Vertex}
variable {a b : M.Vertex}











































































































































































































































































































variable {α : Type u} [DecidableEq α]









end ProofsInTheBook.ZinanCh35OuterTraceProof
















































end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35Side2Confine
import ProofsInTheBook.ZinanCh35Aligned
import ProofsInTheBook.ZinanCh35Regions
import ProofsInTheBook.ZinanCh35Iota
import ProofsInTheBook.ZinanCh35OuterTraceProof
-/
/- Source module: ProofsInTheBook.ZinanCh35ChordSupplier -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35ChordSupplier

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35Aligned.NearTriangulation
open ProofsInTheBook.ZinanCh35Regions
open ProofsInTheBook.ZinanCh35Side2Confine
open ProofsInTheBook.ZinanCh35SideAnchors
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v p q : M.Vertex}















































































end ProofsInTheBook.ZinanCh35ChordSupplier

end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35ChordSupplier
-/
/- Source module: ProofsInTheBook.ZinanCh35ChordSupplier2 -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false
set_option maxHeartbeats 1600000

namespace ProofsInTheBook.ZinanCh35ChordSupplier2

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation.ChordSplitData
open ProofsInTheBook.ChordReconClose
open ProofsInTheBook.ZinanCh35Aligned.NearTriangulation
open ProofsInTheBook.ZinanCh35Regions
open ProofsInTheBook.ZinanCh35Side2Confine
open ProofsInTheBook.ZinanCh35SideAnchors
open ProofsInTheBook.ZinanCh35Side2Anchors
open ProofsInTheBook.ZinanCh35OuterTrace
open ProofsInTheBook.ZinanCh35OuterTraceProof
open ProofsInTheBook.ChordFaceCount
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ZinanCh35ChordSupplier

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {u v p q : M.Vertex}









































end ProofsInTheBook.ZinanCh35ChordSupplier2



end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapOuterArc
import ProofsInTheBook.PlanarMapBoundaryArcSplit
-/
/- Source module: ProofsInTheBook.ZinanCh35OuterV0Consecutive -/
section
set_option autoImplicit true




namespace ProofsInTheBook.PlanarMap

open Equiv

namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]

namespace BoundaryCycle

variable {M : CombMap D} {f : M.Face}





end BoundaryCycle

namespace NearTriangulation

variable {M : CombMap D} (hNT : NearTriangulation M) {v0 : M.Vertex}















end NearTriangulation

end CombMap

end ProofsInTheBook.PlanarMap

end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFanExistence
import ProofsInTheBook.ZinanCh35StarConn
import ProofsInTheBook.ZinanCh35StarRotation
import ProofsInTheBook.ZinanCh35InnerConn
-/
/- Source module: ProofsInTheBook.ZinanCh35Chordless -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35Chordless

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D} (hNT : NearTriangulation M)


































end ProofsInTheBook.ZinanCh35Chordless
end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapFanExistence
import ProofsInTheBook.ZinanCh35Chordless
-/
/- Source module: ProofsInTheBook.ZinanCh35ChordlessFull -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35ChordlessFull

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open Equiv

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D} (hNT : NearTriangulation M)











































end ProofsInTheBook.ZinanCh35ChordlessFull












end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35ChordlessFull
import ProofsInTheBook.PlanarMapFanConnectivity
-/
/- Source module: ProofsInTheBook.ZinanCh35FanBackward -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35FanBackward

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open Equiv

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D} {hNT : NearTriangulation M}



















variable (hNT)



variable {hNT}







































namespace Conn

variable {v0 : M.Vertex}





























end Conn



















end ProofsInTheBook.ZinanCh35FanBackward

















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35FanBackward
import ProofsInTheBook.ZinanCh35ChordlessFull
-/
/- Source module: ProofsInTheBook.ZinanCh35ChordlessClose -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35ChordlessClose

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open Equiv

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D} {hNT : NearTriangulation M}









end ProofsInTheBook.ZinanCh35ChordlessClose








end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35OuterV0Consecutive
import ProofsInTheBook.ZinanCh35ChordlessClose
-/
/- Source module: ProofsInTheBook.ZinanCh35MergedArc -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35MergedArc

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open Equiv

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D} {hNT : NearTriangulation M}



















end ProofsInTheBook.ZinanCh35MergedArc












end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlanarMapOuterArc
import ProofsInTheBook.ChordlessFinal
import ProofsInTheBook.ZinanCh35ChordlessClose
import ProofsInTheBook.ZinanCh35BoundaryAssembler
-/
/- Source module: ProofsInTheBook.ZinanCh35DeletedBoundary -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false
set_option linter.unusedVariables false

namespace ProofsInTheBook.ZinanCh35DeletedBoundary

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ChordlessClose
open ProofsInTheBook.ChordlessFinal

universe u

variable {D : Type u} [Fintype D] [DecidableEq D] {M : CombMap D}
  {hNT : NearTriangulation M} {v0 : M.Vertex}





namespace DeletedSeamData

variable {fan : BoundaryVertexFan hNT v0} {hchord : BoundaryChordless hNT.outerCycle}
  {d0 : D} {htail0 : M.tail d0 = v0}























end DeletedSeamData





















end ProofsInTheBook.ZinanCh35DeletedBoundary

















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35MergedArc
import ProofsInTheBook.ZinanCh35DeletedBoundary
import ProofsInTheBook.PlanarMapDeletedBoundary
-/
/- Source module: ProofsInTheBook.ZinanCh35DeletedAssembly -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35DeletedAssembly

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ChordlessFinal

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D} {hNT : NearTriangulation M} {v0 : M.Vertex}



































































end ProofsInTheBook.ZinanCh35DeletedAssembly















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35FanBackward
import ProofsInTheBook.ZinanCh35ChordlessClose
import ProofsInTheBook.ZinanCh35Dichotomy
import ProofsInTheBook.ChordlessClose
import ProofsInTheBook.ChordlessFinal
-/
/- Source module: ProofsInTheBook.ZinanCh35ChordlessOracle -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35ChordlessOracle

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ListColoring
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ThomassenInduction
open ProofsInTheBook.ChordSplitNT
open ProofsInTheBook.ZinanCh35Dichotomy

universe u



variable {D : Type u} [Fintype D] [DecidableEq D]
variable {M : CombMap D} {hNT : NearTriangulation M}

























variable {α : Type u} [DecidableEq α]











end ProofsInTheBook.ZinanCh35ChordlessOracle
















end

/- Original source header (imports hoisted):
import ProofsInTheBook.ThomassenLists
import ProofsInTheBook.PlanarMapFanExistence
import ProofsInTheBook.PlanarMapFanSurgery
import Mathlib.Data.Finset.Basic
-/
/- Source module: ProofsInTheBook.ZinanCh35ChordlessSite -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35ChordlessSite

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {α : Type u} [DecidableEq α]
variable {M : CombMap D} {hNT : NearTriangulation M}

namespace BoundaryCycle

variable {f : M.Face}









end BoundaryCycle

namespace NearTriangulation

variable {v : M.Vertex}







end NearTriangulation

















end ProofsInTheBook.ZinanCh35ChordlessSite

end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35ChordlessSite
import ProofsInTheBook.ZinanCh35DeletedAssembly
import ProofsInTheBook.ZinanCh35DeletedBoundary
import ProofsInTheBook.ZinanCh35ChordlessOracle
-/
/- Source module: ProofsInTheBook.ZinanCh35ChordlessSupplier -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35ChordlessSupplier

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.PlanarMap.CombMap.NearTriangulation
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ThomassenInduction

universe u

variable {D : Type u} [Fintype D] [DecidableEq D]
variable {α : Type u} [DecidableEq α]
variable {M : CombMap D} {hNT : NearTriangulation M} {v0 : M.Vertex}











































































end ProofsInTheBook.ZinanCh35ChordlessSupplier

end

/- Original source header (imports hoisted):
import ProofsInTheBook.ZinanCh35ChordResidue
import ProofsInTheBook.ZinanCh35Regions
import ProofsInTheBook.ZinanCh35ChordSupplier
import ProofsInTheBook.ZinanCh35ChordSupplier2
import ProofsInTheBook.ZinanCh35MergedArc
import ProofsInTheBook.ZinanCh35DeletedAssembly
import ProofsInTheBook.ZinanCh35ChordlessOracle
import ProofsInTheBook.ZinanCh35ChordlessSupplier
-/
/- Source module: ProofsInTheBook.ZinanCh35Final -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.ZinanCh35Final

open ProofsInTheBook.PlanarMap
open ProofsInTheBook.PlanarMap.CombMap
open ProofsInTheBook.ThomassenLists
open ProofsInTheBook.ThomassenLists.CombMap
open ProofsInTheBook.ChordSplitNT
open ProofsInTheBook.ZinanCh35Dichotomy
open ProofsInTheBook.ZinanCh35ChordResidue
open ProofsInTheBook.ZinanCh35ChordlessOracle

universe u

variable {α : Type u} [DecidableEq α]







































end ProofsInTheBook.ZinanCh35Final














end

/- Original source header (imports hoisted):
import ProofsInTheBook.PlaneSimpleGraph
import ProofsInTheBook.PlanarMapSimple
import ProofsInTheBook.FaceDiagonalSurgery
import ProofsInTheBook.Ch13ActiveComponent
import ProofsInTheBook.ZinanCh35BoundaryAssembler
import ProofsInTheBook.ZinanCh35Final
-/
/- Source module: ProofsInTheBook.PlaneSimpleGraphTriangulate -/
section
set_option autoImplicit true




set_option linter.unusedSectionVars false

namespace ProofsInTheBook.PlanarMap

open Equiv

namespace PlaneSimpleGraph

variable {V D : Type*} [Fintype V] [DecidableEq V] [Fintype D] [DecidableEq D]































end PlaneSimpleGraph






namespace TriangleWitness

open PlaneSimpleGraph









































end TriangleWitness



universe u v u'

section Extension

variable {V D : Type*} [Fintype V] [DecidableEq V] [Fintype D] [DecidableEq D]







end Extension





namespace CombMap

variable {D : Type*} [Fintype D] [DecidableEq D]



































































































end CombMap

namespace PlaneSimpleGraph

variable {V : Type v} {D : Type u} [Fintype V] [DecidableEq V] [Fintype D] [DecidableEq D]







end PlaneSimpleGraph

namespace TriangleWitness



















end TriangleWitness



















end ProofsInTheBook.PlanarMap

end

Source
Representative original declarations: https://github.com/xiangyazi24/proof_in_the_book/blob/88d88d141768cded75e782c525ef1bf04b8fe220/ProofsInTheBook/PlanarMap.lean#L24; https://github.com/xiangyazi24/proof_in_the_book/blob/88d88d141768cded75e782c525ef1bf04b8fe220/ProofsInTheBook/ThomassenLists.lean#L84; https://github.com/xiangyazi24/proof_in_the_book/blob/88d88d141768cded75e782c525ef1bf04b8fe220/ProofsInTheBook/PlanarMapFilteredRotation.lean#L407; https://github.com/xiangyazi24/proof_in_the_book/blob/88d88d141768cded75e782c525ef1bf04b8fe220/ProofsInTheBook/PlanarMapFilteredRotation.lean#L415; https://github.com/xiangyazi24/proof_in_the_book/blob/88d88d141768cded75e782c525ef1bf04b8fe220/ProofsInTheBook/ChordAnchor.lean#L183. Topic: Aigner and Ziegler, Proofs from THE BOOK, 6th edition, Chapter 39, “Five-coloring plane graphs”, pp. 277–280 (https://doi.org/10.1007/978-3-662-57265-8_39).

View graph

Get started

Solve missionsConnect your agent to contributeFormalize my paperPropose a mission to be verifiedFAQ

About Prove2Me

Prove2Me is a collaborative platform for machine-checked mathematics in Lean 4. Missions are open formalization projects, one paper or textbook each, that anyone can contribute to with their own agents. Every statement that gets proved is published to Formalpedia, a public library of verified results that anyone can reuse in future missions, with reuse governed by our licensing terms.

How Prove2Me worksResearch paper
SKILL.mdTourFAQContactTerms
© 2026 Prove2Me