Pith. sign in

IndisputableMonolith.Foundation.SingularSubdivision

IndisputableMonolith/Foundation/SingularSubdivision.lean · 1588 lines · 114 declarations

show as:
view math explainer →

open module explainer GitHub source

Explainer status: pending

   1/-
   2Barycentric subdivision and (toward) the small-simplices theorem for
   3Mathlib's singular homology (Hatcher §2.1, proof of excision, pp. 119–124).
   4
   5## Design
   6
   7Everything possible is done on a purely combinatorial *affine chain* layer:
   8an affine `n`-simplex in a type `α` is a vertex tuple `Fin (n+1) → α`, and an
   9affine `n`-chain is a finitely supported `ℤ`-linear combination of tuples,
  10`AC α n := (Fin (n+1) → α) →₀ ℤ`.  Faces are tuple reindexings along
  11`Fin.succAbove`, the cone with apex `b` is `Fin.cons b`, and the barycentric
  12subdivision `asub` and the chain homotopy `atee` are defined by the classical
  13cone recursions
  14
  15  `S λ = b_λ · S (∂ λ)`,   `T λ = b_λ · (λ − T (∂ λ))`,
  16
  17parametrized by an *abstract* apex function `bary`.  All chain identities
  18(`∂∂ = 0`, the cone identity `∂(b·c) = c − b·∂c`, the chain-map property
  19`∂S = S∂`, the homotopy identity `∂T + T∂ = 1 − S`, and the telescoped
  20iterate identity for `S^k`) hold at this combinatorial level, for *any*
  21apex function (degree 0 needs only `bary 0 w = w 0`).
  22
  23The geometry (the honest barycenter on `stdSimplex`, the realization of a
  24vertex tuple as a continuous affine map, the diameter estimate) enters only
  25in the later stages, and the transport to Mathlib's singular chain complex
  26reuses the `Idx`/`gen`/`gen_d`/`gen_map` normal forms of
  27`IndisputableMonolith.Foundation.SingularPrism`.
  28
  29## Stages (each stage builds green before the next begins)
  30
  31* Stage 1: affine chains, boundary, cone, augmentation; generator normal
  32  forms.
  33* Stage 2: the chain identities: cone identity (positive degrees and
  34  degree 0), `∂∂ = 0`, `ε∂ = 0`.
  35* Stage 3: the barycentric subdivision operator `asub` and the chain-map
  36  property `∂S = S∂`.
  37* Stage 4: the chain homotopy `atee` with `∂T + T∂ = 1 − S`, and the
  38  telescoped homotopy for the iterate `S^k`.
  39* Stage 5a: pushforward `amap` of affine chains along a vertex map and
  40  equivariance of `abnd`/`acone`/`asub`/`atee` under barycenter-preserving
  41  maps.
  42* Stage 5b: geometry on `stdSimplex`: the affine realization `affineMap` of
  43  a vertex tuple, functoriality, vertices, faces, the identity tuple, the
  44  honest barycenter `sbary` and its equivariance `sbary_affineMap`.
  45* Stage 5c: transport to Mathlib's singular chain complex: the singular
  46  subdivision `sdOp X n : C_n(X) ⟶ C_n(X)` and homotopy
  47  `tOp X n : C_n(X) ⟶ C_{n+1}(X)`, the chain-map property `sdOp_comp_bnd`,
  48  the homotopy identities `tOp_chain_homotopy_succ`/`_zero`, naturality
  49  `sdOp_natural`/`tOp_natural`, and the iterates `sdOpIter`/`tOpIter` with
  50  `sdOpIter_comp_bnd` and `tOpIter_chain_homotopy_succ`/`_zero`.
  51* Stage 6: the diameter estimate: support tracking of `asub` through the
  52  cone recursion (`asub_support_bound`), the `n/(n+1)` contraction with the
  53  convex-hull maximum principle, iterates (`asubIter_support_bound`), and
  54  geometric decay (`exists_asubIter_small`).
  55* Stage 7: the small-simplices theorem `exists_sdOpIter_small`: for open
  56  `U ∪ V = X` and any singular simplex, some iterate of the singular
  57  subdivision has every piece landing in `U` or in `V` (Lebesgue number on
  58  the compact metric `Δⁿ`); combined with `gen_comp_sdOpIter` and the
  59  homotopy witness `tOpIter_chain_homotopy_succ`/`_zero`, this is the input
  60  the next layer needs for excision / Mayer-Vietoris.
  61
  62## Frontier (next layer)
  63
  64The two-set small-chains subcomplex `C^{U,V}_*(X)` (chains all of whose
  65generators are `U`-small or `V`-small) and the surjectivity of
  66`H_*(C^{U,V}) → H_*(C)` remain to be packaged: `exists_sdOpIter_small`
  67gives, for each cycle generator, an iterate `k` landing in the subcomplex,
  68and `tOpIter_chain_homotopy_*` gives the homology-class-preserving witness;
  69the remaining work is uniformizing `k` over the finitely many generators of
  70a chain (take the max) and assembling the subcomplex as a `ChainComplex`
  71with the inclusion map, feeding `SingularPair.lean`'s LES machinery toward
  72Mayer-Vietoris and excision.
  73-/
  74import Mathlib.AlgebraicTopology.SingularHomology.Basic
  75import Mathlib.Algebra.Category.ModuleCat.Colimits
  76import Mathlib.Algebra.Category.ModuleCat.Abelian
  77import Mathlib.Analysis.Normed.Module.Convex
  78import Mathlib.Topology.MetricSpace.Pseudo.Lemmas
  79import IndisputableMonolith.Foundation.SingularPrism
  80
  81namespace IndisputableMonolith
  82namespace Foundation
  83namespace SingularSubdivision
  84
  85open CategoryTheory Limits AlgebraicTopology Simplicial Opposite
  86
  87/-! ## Stage 1: affine chains, boundary, cone, augmentation -/
  88
  89variable {α β : Type} {n : ℕ}
  90
  91/-- The group of affine `n`-chains in `α`: finitely supported `ℤ`-linear
  92combinations of vertex tuples `Fin (n+1) → α`. -/
  93abbrev AC (α : Type) (n : ℕ) : Type := (Fin (n + 1) → α) →₀ ℤ
  94
  95/-- The affine simplex (generator) attached to a vertex tuple. -/
  96noncomputable def asimplex (w : Fin (n + 1) → α) : AC α n := Finsupp.single w 1
  97
  98/-- Extensionality for linear maps out of `AC α n`: it suffices to agree on
  99generators. -/
 100lemma AC.hom_ext {M : Type*} [AddCommGroup M] [Module ℤ M]
 101    {φ ψ : AC α n →ₗ[ℤ] M} (h : ∀ w, φ (asimplex w) = ψ (asimplex w)) :
 102    φ = ψ := by
 103  refine Finsupp.lhom_ext fun a b => ?_
 104  have hsingle : (Finsupp.single a b : AC α n) = b • asimplex a := by
 105    rw [asimplex, Finsupp.smul_single, smul_eq_mul, mul_one]
 106  rw [hsingle, LinearMap.map_smul, LinearMap.map_smul, h]
 107
 108/-- Evaluation of a `Finsupp.linearCombination`-defined map on a generator. -/
 109lemma lift_asimplex {M : Type*} [AddCommGroup M] [Module ℤ M]
 110    (f : (Fin (n + 1) → α) → M) (w : Fin (n + 1) → α) :
 111    Finsupp.linearCombination ℤ f (asimplex w) = f w := by
 112  rw [asimplex, Finsupp.linearCombination_single, one_smul]
 113
 114/-- The boundary of affine chains, `∂ : AC α (n+1) → AC α n`, the alternating
 115sum of the tuple faces `w ∘ Fin.succAbove i`. -/
 116noncomputable def abnd (n : ℕ) : AC α (n + 1) →ₗ[ℤ] AC α n :=
 117  Finsupp.linearCombination ℤ
 118    (fun w : Fin (n + 2) → α =>
 119      ∑ i : Fin (n + 2), (-1 : ℤ) ^ (i : ℕ) • asimplex (w ∘ i.succAbove))
 120
 121/-- The boundary of a generator is the alternating sum of its faces. -/
 122lemma abnd_asimplex (w : Fin (n + 2) → α) :
 123    abnd n (asimplex w) =
 124      ∑ i : Fin (n + 2), (-1 : ℤ) ^ (i : ℕ) • asimplex (w ∘ i.succAbove) :=
 125  lift_asimplex _ w
 126
 127/-- The cone with apex `b`, `AC α n → AC α (n+1)`: prepend `b` to every
 128vertex tuple. -/
 129noncomputable def acone (b : α) : AC α n →ₗ[ℤ] AC α (n + 1) :=
 130  Finsupp.lmapDomain ℤ ℤ (fun w => Fin.cons b w)
 131
 132/-- The cone of a generator. -/
 133lemma acone_asimplex (b : α) (w : Fin (n + 1) → α) :
 134    acone b (asimplex w) = asimplex (Fin.cons b w) := by
 135  rw [acone, asimplex, Finsupp.lmapDomain_apply, Finsupp.mapDomain_single, asimplex]
 136
 137/-- The augmentation `ε : AC α 0 → ℤ` (sum of coefficients). -/
 138noncomputable def eps (α : Type) : AC α 0 →ₗ[ℤ] ℤ :=
 139  Finsupp.linearCombination ℤ (fun _ : Fin 1 → α => (1 : ℤ))
 140
 141lemma eps_asimplex (w : Fin 1 → α) : eps α (asimplex w) = 1 :=
 142  lift_asimplex _ w
 143
 144/-! ### Tuple bookkeeping for cones and faces -/
 145
 146/-- The `0`-th face of a cone is the base tuple. -/
 147lemma cons_comp_succAbove_zero (b : α) (w : Fin (n + 1) → α) :
 148    (Fin.cons b w) ∘ (Fin.succAbove 0) = w := by
 149  funext k
 150  simp only [Function.comp_apply, Fin.zero_succAbove, Fin.cons_succ]
 151
 152/-- The `(j+1)`-th face of a cone is the cone on the `j`-th face. -/
 153lemma cons_comp_succAbove_succ (b : α) (w : Fin (n + 1) → α) (j : Fin (n + 1)) :
 154    (Fin.cons b w) ∘ (Fin.succAbove j.succ) = Fin.cons b (w ∘ j.succAbove) := by
 155  funext k
 156  induction k using Fin.cases with
 157  | zero => simp only [Function.comp_apply, Fin.succ_succAbove_zero, Fin.cons_zero]
 158  | succ k => simp only [Function.comp_apply, Fin.succ_succAbove_succ, Fin.cons_succ]
 159
 160/-! ## Stage 2: the chain identities -/
 161
 162/-- The cone identity in positive degrees: `∂ (b · c) = c − b · (∂ c)`
 163for `c : AC α (n+1)`. -/
 164theorem abnd_comp_acone (b : α) (n : ℕ) :
 165    (abnd (n + 1)).comp (acone b : AC α (n + 1) →ₗ[ℤ] AC α (n + 2)) =
 166      LinearMap.id - (acone b).comp (abnd n) := by
 167  refine AC.hom_ext fun w => ?_
 168  rw [LinearMap.comp_apply, acone_asimplex, abnd_asimplex, Fin.sum_univ_succ,
 169    LinearMap.sub_apply, LinearMap.id_apply, LinearMap.comp_apply, abnd_asimplex,
 170    map_sum, Fin.val_zero, pow_zero, one_smul, cons_comp_succAbove_zero,
 171    sub_eq_add_neg, ← Finset.sum_neg_distrib]
 172  congr 1
 173  refine Finset.sum_congr rfl fun j _ => ?_
 174  rw [map_smul, acone_asimplex, cons_comp_succAbove_succ, Fin.val_succ, pow_succ,
 175    mul_neg_one, neg_smul]
 176
 177/-- The cone identity in degree `0`:
 178`∂ (b · c) = c − ε(c) · [b]` for `c : AC α 0`. -/
 179theorem abnd_comp_acone_zero (b : α) :
 180    (abnd 0).comp (acone b : AC α 0 →ₗ[ℤ] AC α 1) =
 181      LinearMap.id -
 182        (LinearMap.toSpanSingleton ℤ (AC α 0) (asimplex fun _ => b)).comp (eps α) := by
 183  refine AC.hom_ext fun w => ?_
 184  rw [LinearMap.comp_apply, acone_asimplex, abnd_asimplex, Fin.sum_univ_two]
 185  rw [LinearMap.sub_apply, LinearMap.id_apply, LinearMap.comp_apply, eps_asimplex,
 186    LinearMap.toSpanSingleton_apply, one_smul]
 187  have h0 : (Fin.cons b w) ∘ (Fin.succAbove (0 : Fin 2)) = w :=
 188    cons_comp_succAbove_zero b w
 189  have h1 : (Fin.cons b w) ∘ (Fin.succAbove (1 : Fin 2)) = (fun _ => b) := by
 190    funext k
 191    have hk : k = 0 := Subsingleton.elim k 0
 192    subst hk
 193    simp only [Function.comp_apply]
 194    have h : (1 : Fin 2).succAbove (0 : Fin 1) = 0 := rfl
 195    rw [h, Fin.cons_zero]
 196  rw [h0, h1]
 197  simp only [Fin.val_zero, Fin.val_one, pow_zero, pow_one, one_smul, neg_smul]
 198  rw [sub_eq_add_neg]
 199
 200/-- `∂∂ = 0` on affine chains. -/
 201theorem abnd_comp_abnd (n : ℕ) :
 202    (abnd n).comp (abnd (n + 1)) = (0 : AC α (n + 2) →ₗ[ℤ] AC α n) := by
 203  classical
 204  refine AC.hom_ext fun w => ?_
 205  rw [LinearMap.comp_apply, abnd_asimplex, map_sum, LinearMap.zero_apply]
 206  have hexp : ∀ i : Fin (n + 3),
 207      abnd n ((-1 : ℤ) ^ (i : ℕ) • asimplex (w ∘ i.succAbove)) =
 208        ∑ j : Fin (n + 2), (-1 : ℤ) ^ ((i : ℕ) + (j : ℕ)) •
 209          asimplex (w ∘ i.succAbove ∘ j.succAbove) := by
 210    intro i
 211    rw [map_smul, abnd_asimplex, Finset.smul_sum]
 212    refine Finset.sum_congr rfl fun j _ => ?_
 213    rw [smul_smul, ← pow_add]
 214    rfl
 215  simp only [hexp]
 216  rw [← Finset.sum_product', Finset.univ_product_univ]
 217  have hsplit := Finset.sum_filter_add_sum_filter_not
 218    (Finset.univ : Finset (Fin (n + 3) × Fin (n + 2)))
 219    (fun p => (p.2 : ℕ) < (p.1 : ℕ))
 220    (fun p => (-1 : ℤ) ^ ((p.1 : ℕ) + (p.2 : ℕ)) •
 221      asimplex (w ∘ p.1.succAbove ∘ p.2.succAbove))
 222  rw [← hsplit]
 223  have hcancel : (∑ p ∈ Finset.univ.filter
 224        (fun p : Fin (n + 3) × Fin (n + 2) => (p.2 : ℕ) < (p.1 : ℕ)),
 225        (-1 : ℤ) ^ ((p.1 : ℕ) + (p.2 : ℕ)) •
 226          asimplex (w ∘ p.1.succAbove ∘ p.2.succAbove)) =
 227      -∑ p ∈ Finset.univ.filter
 228        (fun p : Fin (n + 3) × Fin (n + 2) => ¬ (p.2 : ℕ) < (p.1 : ℕ)),
 229        (-1 : ℤ) ^ ((p.1 : ℕ) + (p.2 : ℕ)) •
 230          asimplex (w ∘ p.1.succAbove ∘ p.2.succAbove) := by
 231    rw [← Finset.sum_neg_distrib]
 232    refine Finset.sum_bij'
 233      (i := fun p hp => ((⟨(p.2 : ℕ), by
 234          simp only [Finset.mem_filter_univ] at hp
 235          omega⟩ : Fin (n + 3)),
 236        (⟨(p.1 : ℕ) - 1, by
 237          have := p.1.isLt
 238          omega⟩ : Fin (n + 2))))
 239      (j := fun q hq => ((⟨(q.2 : ℕ) + 1, by
 240          have := q.2.isLt
 241          omega⟩ : Fin (n + 3)),
 242        (⟨(q.1 : ℕ), by
 243          simp only [Finset.mem_filter_univ] at hq
 244          have := q.2.isLt
 245          omega⟩ : Fin (n + 2))))
 246      ?_ ?_ ?_ ?_ ?_
 247    · intro p hp
 248      simp only [Finset.mem_filter_univ] at hp ⊢
 249      omega
 250    · intro q hq
 251      simp only [Finset.mem_filter_univ] at hq ⊢
 252      omega
 253    · intro p hp
 254      simp only [Finset.mem_filter_univ] at hp
 255      ext
 256      all_goals (try dsimp only)
 257      all_goals omega
 258    · intro q hq
 259      simp only [Finset.mem_filter_univ] at hq
 260      ext
 261      all_goals (try dsimp only)
 262      all_goals omega
 263    · intro p hp
 264      simp only [Finset.mem_filter_univ] at hp
 265      have htuple : w ∘ p.1.succAbove ∘ p.2.succAbove =
 266          w ∘ (⟨(p.2 : ℕ), by omega⟩ : Fin (n + 3)).succAbove ∘
 267            (⟨(p.1 : ℕ) - 1, by have := p.1.isLt; omega⟩ : Fin (n + 2)).succAbove := by
 268      -- faces commute: δ_i δ_j = δ_j δ_{i-1} for j < i
 269        funext k
 270        apply congrArg w
 271        apply Fin.ext
 272        have hk := k.isLt
 273        simp only [Function.comp_apply, SingularPrism.coe_succAbove]
 274        split_ifs <;> omega
 275      rw [htuple]
 276      have hsign : ((p.1 : ℕ) + (p.2 : ℕ)) =
 277          (((⟨(p.2 : ℕ), by omega⟩ : Fin (n + 3)) : ℕ) +
 278            ((⟨(p.1 : ℕ) - 1, by have := p.1.isLt; omega⟩ : Fin (n + 2)) : ℕ)) + 1 := by
 279        dsimp only
 280        omega
 281      rw [hsign, pow_succ, mul_neg_one, neg_smul]
 282  rw [hcancel, neg_add_cancel]
 283
 284/-- The augmentation kills boundaries: `ε ∘ ∂ = 0`. -/
 285theorem eps_comp_abnd : (eps α).comp (abnd 0) = 0 := by
 286  refine AC.hom_ext fun w => ?_
 287  rw [LinearMap.comp_apply, abnd_asimplex, map_sum, Fin.sum_univ_two,
 288    LinearMap.zero_apply]
 289  simp only [map_smul, eps_asimplex, Fin.val_zero, Fin.val_one, pow_zero, pow_one,
 290    smul_eq_mul, mul_one]
 291  omega
 292
 293/-! ## Stage 3: the barycentric subdivision operator and `∂S = S∂`
 294
 295The subdivision operator is parametrized by an abstract apex function
 296`bary` assigning to every vertex tuple a point (the barycenter, in the
 297geometric realization); all chain identities hold for any such function. -/
 298
 299/-- The barycentric subdivision operator on affine chains, defined by the
 300cone recursion `S(σ) = b_σ · S(∂σ)` on generators (`S = id` in degree 0). -/
 301noncomputable def asub (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) :
 302    ∀ n, AC α n →ₗ[ℤ] AC α n
 303  | 0 => LinearMap.id
 304  | n + 1 => Finsupp.linearCombination ℤ
 305      (fun w : Fin (n + 2) → α =>
 306        acone (bary w) (asub bary n (abnd n (asimplex w))))
 307
 308@[simp] lemma asub_zero (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) :
 309    asub bary 0 = LinearMap.id := rfl
 310
 311lemma asub_asimplex (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) (n : ℕ)
 312    (w : Fin (n + 2) → α) :
 313    asub bary (n + 1) (asimplex w) =
 314      acone (bary w) (asub bary n (abnd n (asimplex w))) :=
 315  lift_asimplex _ w
 316
 317/-- The chain-map property of barycentric subdivision: `∂ ∘ S = S ∘ ∂`. -/
 318theorem abnd_comp_asub (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) :
 319    ∀ n, (abnd n).comp (asub bary (n + 1)) = (asub bary n).comp (abnd n)
 320  | 0 => by
 321    refine AC.hom_ext fun w => ?_
 322    rw [LinearMap.comp_apply, LinearMap.comp_apply, asub_asimplex, asub_zero,
 323      LinearMap.id_apply]
 324    have hcone := LinearMap.congr_fun (abnd_comp_acone_zero (bary w) (α := α))
 325      (abnd 0 (asimplex w))
 326    rw [LinearMap.comp_apply, LinearMap.sub_apply, LinearMap.id_apply,
 327      LinearMap.comp_apply] at hcone
 328    rw [hcone]
 329    have heps := LinearMap.congr_fun (eps_comp_abnd (α := α)) (asimplex w)
 330    rw [LinearMap.comp_apply, LinearMap.zero_apply] at heps
 331    rw [heps, map_zero, sub_zero]
 332  | n + 1 => by
 333    have IH := abnd_comp_asub bary n
 334    refine AC.hom_ext fun w => ?_
 335    rw [LinearMap.comp_apply, LinearMap.comp_apply, asub_asimplex]
 336    have hcone := LinearMap.congr_fun (abnd_comp_acone (bary w) n (α := α))
 337      (asub bary (n + 1) (abnd (n + 1) (asimplex w)))
 338    rw [LinearMap.comp_apply, LinearMap.sub_apply, LinearMap.id_apply,
 339      LinearMap.comp_apply] at hcone
 340    rw [hcone]
 341    have hIH := LinearMap.congr_fun IH (abnd (n + 1) (asimplex w))
 342    rw [LinearMap.comp_apply, LinearMap.comp_apply] at hIH
 343    rw [hIH]
 344    have hdd := LinearMap.congr_fun (abnd_comp_abnd n (α := α)) (asimplex w)
 345    rw [LinearMap.comp_apply, LinearMap.zero_apply] at hdd
 346    rw [hdd, map_zero, map_zero, sub_zero]
 347
 348/-! ## Stage 4: the chain homotopy `T` with `∂T + T∂ = id − S`,
 349and the telescoped homotopy for the iterate `S^k` -/
 350
 351/-- The subdivision chain homotopy on affine chains, defined by the cone
 352recursion `T(σ) = b_σ · (σ − T(∂σ))` on generators (`T = 0` in degree 0). -/
 353noncomputable def atee (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) :
 354    ∀ n, AC α n →ₗ[ℤ] AC α (n + 1)
 355  | 0 => 0
 356  | n + 1 => Finsupp.linearCombination ℤ
 357      (fun w : Fin (n + 2) → α =>
 358        acone (bary w) (asimplex w - atee bary n (abnd n (asimplex w))))
 359
 360@[simp] lemma atee_zero (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) :
 361    atee bary 0 = 0 := rfl
 362
 363lemma atee_asimplex (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) (n : ℕ)
 364    (w : Fin (n + 2) → α) :
 365    atee bary (n + 1) (asimplex w) =
 366      acone (bary w) (asimplex w - atee bary n (abnd n (asimplex w))) :=
 367  lift_asimplex _ w
 368
 369/-- The chain homotopy identity in degree 0 (trivially, since `T = 0` and
 370`S = id` there): `∂ ∘ T = id − S`. -/
 371theorem abnd_comp_atee_zero (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) :
 372    (abnd 0).comp (atee bary 0) = LinearMap.id - asub bary (0 : ℕ) := by
 373  rw [atee_zero, asub_zero, LinearMap.comp_zero, sub_self]
 374
 375/-- The chain homotopy identity in positive degrees:
 376`∂ ∘ T + T ∘ ∂ = id − S` on `AC α (n+1)` (Hatcher, proof of Prop. 2.21). -/
 377theorem abnd_comp_atee (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) :
 378    ∀ n, (abnd (n + 1)).comp (atee bary (n + 1)) + (atee bary n).comp (abnd n)
 379      = LinearMap.id - asub bary (n + 1)
 380  | 0 => by
 381    refine AC.hom_ext fun w => ?_
 382    rw [LinearMap.add_apply, LinearMap.comp_apply, LinearMap.comp_apply,
 383      LinearMap.sub_apply, LinearMap.id_apply, atee_asimplex, atee_zero,
 384      LinearMap.zero_apply, sub_zero, add_zero, asub_asimplex, asub_zero,
 385      LinearMap.id_apply]
 386    have hcone := LinearMap.congr_fun (abnd_comp_acone (bary w) 0 (α := α))
 387      (asimplex w)
 388    rw [LinearMap.comp_apply, LinearMap.sub_apply, LinearMap.id_apply,
 389      LinearMap.comp_apply] at hcone
 390    rw [hcone]
 391  | n + 1 => by
 392    have IH := abnd_comp_atee bary n
 393    refine AC.hom_ext fun w => ?_
 394    rw [LinearMap.add_apply, LinearMap.comp_apply, LinearMap.comp_apply,
 395      LinearMap.sub_apply, LinearMap.id_apply, atee_asimplex, asub_asimplex]
 396    have hcone := LinearMap.congr_fun (abnd_comp_acone (bary w) (n + 1) (α := α))
 397      (asimplex w - atee bary (n + 1) (abnd (n + 1) (asimplex w)))
 398    rw [LinearMap.comp_apply, LinearMap.sub_apply, LinearMap.id_apply,
 399      LinearMap.comp_apply] at hcone
 400    rw [hcone, map_sub]
 401    -- compute `∂(σ − T∂σ) = S∂σ` from the inductive hypothesis and `∂∂ = 0`
 402    have hIH := LinearMap.congr_fun IH (abnd (n + 1) (asimplex w))
 403    simp only [LinearMap.add_apply, LinearMap.comp_apply, LinearMap.sub_apply,
 404      LinearMap.id_apply] at hIH
 405    have hdd := LinearMap.congr_fun (abnd_comp_abnd n (α := α)) (asimplex w)
 406    rw [LinearMap.comp_apply, LinearMap.zero_apply] at hdd
 407    rw [hdd, map_zero, add_zero] at hIH
 408    rw [hIH, sub_sub_cancel]
 409    abel
 410
 411/-! ### Iteration: `S^k` is chain homotopic to the identity -/
 412
 413/-- The `k`-th iterate of the subdivision operator (as a family of chain
 414endomorphisms). -/
 415noncomputable def asubIter (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α)
 416    (k n : ℕ) : AC α n →ₗ[ℤ] AC α n :=
 417  match k with
 418  | 0 => LinearMap.id
 419  | k + 1 => (asub bary n).comp (asubIter bary k n)
 420
 421@[simp] lemma asubIter_zero (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) (n : ℕ) :
 422    asubIter bary 0 n = LinearMap.id := rfl
 423
 424lemma asubIter_succ (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) (k n : ℕ) :
 425    asubIter bary (k + 1) n = (asub bary n).comp (asubIter bary k n) := rfl
 426
 427/-- The iterate is a chain map: `∂ ∘ S^k = S^k ∘ ∂`. -/
 428theorem abnd_comp_asubIter (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α)
 429    (k n : ℕ) :
 430    (abnd n).comp (asubIter bary k (n + 1)) = (asubIter bary k n).comp (abnd n) := by
 431  induction k with
 432  | zero => rw [asubIter_zero, asubIter_zero, LinearMap.comp_id, LinearMap.id_comp]
 433  | succ k IH =>
 434      rw [asubIter_succ, asubIter_succ, ← LinearMap.comp_assoc,
 435        abnd_comp_asub, LinearMap.comp_assoc, IH, LinearMap.comp_assoc]
 436
 437/-- The telescoped chain homotopy between `S^k` and the identity:
 438`Tk = T ∘ (1 + S + ⋯ + S^{k−1})`, packaged degreewise by recursion
 439`T_0 = 0`, `T_{k+1} = T + T_k ∘ S`. -/
 440noncomputable def ateeIter (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α)
 441    (k n : ℕ) : AC α n →ₗ[ℤ] AC α (n + 1) :=
 442  match k with
 443  | 0 => 0
 444  | k + 1 => atee bary n + (ateeIter bary k n).comp (asub bary n)
 445
 446@[simp] lemma ateeIter_zero (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) (n : ℕ) :
 447    ateeIter bary 0 n = 0 := rfl
 448
 449lemma ateeIter_succ (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) (k n : ℕ) :
 450    ateeIter bary (k + 1) n =
 451      atee bary n + (ateeIter bary k n).comp (asub bary n) := rfl
 452
 453/-- The subdivision operator commutes with its own iterates. -/
 454lemma asubIter_comp_asub (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α) (k n : ℕ) :
 455    (asubIter bary k n).comp (asub bary n) = (asub bary n).comp (asubIter bary k n) := by
 456  induction k with
 457  | zero => rw [asubIter_zero, LinearMap.comp_id, LinearMap.id_comp]
 458  | succ k IH =>
 459      rw [asubIter_succ, LinearMap.comp_assoc, IH, ← LinearMap.comp_assoc]
 460
 461/-- The telescoped chain homotopy identity in positive degrees:
 462`∂ ∘ Tk + Tk ∘ ∂ = id − S^k` on `AC α (n+1)`. -/
 463theorem abnd_comp_ateeIter (bary : ∀ {m : ℕ}, (Fin (m + 1) → α) → α)
 464    (k n : ℕ) :
 465    (abnd (n + 1)).comp (ateeIter bary k (n + 1)) +
 466        (ateeIter bary k n).comp (abnd n)
 467      = LinearMap.id - asubIter bary k (n + 1) := by
 468  induction k with
 469  | zero =>
 470      rw [ateeIter_zero, ateeIter_zero, asubIter_zero, LinearMap.comp_zero,
 471        LinearMap.zero_comp, add_zero, sub_self]
 472  | succ k IH =>
 473      rw [ateeIter_succ, ateeIter_succ, asubIter_succ,
 474        LinearMap.comp_add, LinearMap.add_comp]
 475      -- rewrite `Tk S ∂` as `Tk ∂ S` via the chain-map property of `S`
 476      have hswap : ((ateeIter bary k n).comp (asub bary n)).comp (abnd n)
 477          = ((ateeIter bary k n).comp (abnd n)).comp (asub bary (n + 1)) := by
 478        rw [LinearMap.comp_assoc, LinearMap.comp_assoc, ← abnd_comp_asub]
 479      rw [hswap]
 480      -- regroup as `(∂T + T∂) + (∂Tk + Tk∂) ∘ S`
 481      have hgroup :
 482          ((abnd (n + 1)).comp (atee bary (n + 1)) +
 483              (abnd (n + 1)).comp ((ateeIter bary k (n + 1)).comp (asub bary (n + 1)))) +
 484            ((atee bary n).comp (abnd n) +
 485              ((ateeIter bary k n).comp (abnd n)).comp (asub bary (n + 1)))
 486          = ((abnd (n + 1)).comp (atee bary (n + 1)) + (atee bary n).comp (abnd n)) +
 487            ((abnd (n + 1)).comp (ateeIter bary k (n + 1)) +
 488              (ateeIter bary k n).comp (abnd n)).comp (asub bary (n + 1)) := by
 489        rw [LinearMap.add_comp, ← LinearMap.comp_assoc]
 490        abel
 491      rw [hgroup, abnd_comp_atee, IH, LinearMap.sub_comp, LinearMap.id_comp,
 492        asubIter_comp_asub]
 493      abel
 494
 495/-! ## Stage 5a: pushforward of affine chains and equivariance
 496
 497Affine chains push forward along any map of point types `f : α → β`
 498(post-composition of vertex tuples).  The pushforward commutes with the
 499boundary and the cone, and, when `f` intertwines the two apex functions
 500(`baryβ (f ∘ w) = f (baryα w)`), with the subdivision operator `asub` and
 501the chain homotopy `atee` as well.  For the geometric stage the map `f`
 502will be an affine map of standard simplices, which sends barycenters to
 503barycenters. -/
 504
 505/-- The pushforward of affine chains along a map of point types. -/
 506noncomputable def amap (f : α → β) (n : ℕ) : AC α n →ₗ[ℤ] AC β n :=
 507  Finsupp.lmapDomain ℤ ℤ (fun w : Fin (n + 1) → α => f ∘ w)
 508
 509lemma amap_asimplex (f : α → β) (n : ℕ) (w : Fin (n + 1) → α) :
 510    amap f n (asimplex w) = asimplex (f ∘ w) := by
 511  rw [amap, asimplex, Finsupp.lmapDomain_apply, Finsupp.mapDomain_single, asimplex]
 512
 513/-- The pushforward commutes with the boundary. -/
 514lemma amap_comp_abnd (f : α → β) (n : ℕ) :
 515    (amap f n).comp (abnd n) = (abnd n).comp (amap f (n + 1)) := by
 516  refine AC.hom_ext fun w => ?_
 517  rw [LinearMap.comp_apply, LinearMap.comp_apply, abnd_asimplex, map_sum,
 518    amap_asimplex, abnd_asimplex]
 519  refine Finset.sum_congr rfl fun i _ => ?_
 520  rw [map_smul, amap_asimplex]
 521  rfl
 522
 523/-- The pushforward commutes with the cone (with pushed apex). -/
 524lemma amap_comp_acone (f : α → β) (b : α) (n : ℕ) :
 525    (amap f (n + 1)).comp (acone b : AC α n →ₗ[ℤ] AC α (n + 1)) =
 526      (acone (f b)).comp (amap f n) := by
 527  refine AC.hom_ext fun w => ?_
 528  rw [LinearMap.comp_apply, LinearMap.comp_apply, acone_asimplex, amap_asimplex,
 529    amap_asimplex, acone_asimplex]
 530  congr 1
 531  funext k
 532  induction k using Fin.cases with
 533  | zero => simp only [Function.comp_apply, Fin.cons_zero]
 534  | succ k => simp only [Function.comp_apply, Fin.cons_succ]
 535
 536/-- Equivariance of the subdivision operator: a map intertwining the apex
 537functions intertwines `asub`. -/
 538theorem amap_comp_asub (f : α → β)
 539    (baryα : ∀ {m : ℕ}, (Fin (m + 1) → α) → α)
 540    (baryβ : ∀ {m : ℕ}, (Fin (m + 1) → β) → β)
 541    (hf : ∀ (m : ℕ) (w : Fin (m + 1) → α), baryβ (f ∘ w) = f (baryα w)) :
 542    ∀ n, (amap f n).comp (asub baryα n) = (asub baryβ n).comp (amap f n)
 543  | 0 => by rw [asub_zero, asub_zero, LinearMap.comp_id, LinearMap.id_comp]
 544  | n + 1 => by
 545    have IH := amap_comp_asub f baryα baryβ hf n
 546    refine AC.hom_ext fun w => ?_
 547    rw [LinearMap.comp_apply, LinearMap.comp_apply, asub_asimplex, amap_asimplex,
 548      asub_asimplex]
 549    have hcone := LinearMap.congr_fun (amap_comp_acone f (baryα w) n)
 550      (asub baryα n (abnd n (asimplex w)))
 551    rw [LinearMap.comp_apply, LinearMap.comp_apply] at hcone
 552    rw [hcone, hf]
 553    congr 1
 554    have hIH := LinearMap.congr_fun IH (abnd n (asimplex w))
 555    rw [LinearMap.comp_apply, LinearMap.comp_apply] at hIH
 556    rw [hIH]
 557    congr 1
 558    have hbnd := LinearMap.congr_fun (amap_comp_abnd f n) (asimplex w)
 559    rw [LinearMap.comp_apply, LinearMap.comp_apply] at hbnd
 560    rw [hbnd, amap_asimplex]
 561
 562/-- Equivariance of the subdivision homotopy: a map intertwining the apex
 563functions intertwines `atee`. -/
 564theorem amap_comp_atee (f : α → β)
 565    (baryα : ∀ {m : ℕ}, (Fin (m + 1) → α) → α)
 566    (baryβ : ∀ {m : ℕ}, (Fin (m + 1) → β) → β)
 567    (hf : ∀ (m : ℕ) (w : Fin (m + 1) → α), baryβ (f ∘ w) = f (baryα w)) :
 568    ∀ n, (amap f (n + 1)).comp (atee baryα n) = (atee baryβ n).comp (amap f n)
 569  | 0 => by rw [atee_zero, atee_zero, LinearMap.comp_zero, LinearMap.zero_comp]
 570  | n + 1 => by
 571    have IH := amap_comp_atee f baryα baryβ hf n
 572    refine AC.hom_ext fun w => ?_
 573    rw [LinearMap.comp_apply, LinearMap.comp_apply, atee_asimplex, amap_asimplex,
 574      atee_asimplex]
 575    have hcone := LinearMap.congr_fun (amap_comp_acone f (baryα w) (n + 1))
 576      (asimplex w - atee baryα n (abnd n (asimplex w)))
 577    rw [LinearMap.comp_apply, LinearMap.comp_apply] at hcone
 578    rw [hcone, hf]
 579    congr 1
 580    rw [map_sub, amap_asimplex]
 581    congr 1
 582    have hIH := LinearMap.congr_fun IH (abnd n (asimplex w))
 583    rw [LinearMap.comp_apply, LinearMap.comp_apply] at hIH
 584    rw [hIH]
 585    congr 1
 586    have hbnd := LinearMap.congr_fun (amap_comp_abnd f n) (asimplex w)
 587    rw [LinearMap.comp_apply, LinearMap.comp_apply] at hbnd
 588    rw [hbnd, amap_asimplex]
 589
 590/-! ## Stage 5b: geometry on the standard simplex
 591
 592The affine realization of a vertex tuple `v : Fin (n+1) → Δᵐ` as a
 593continuous map `Δⁿ → Δᵐ` (barycentric-coordinate weighted sum of the
 594vertices), its functoriality, and the honest barycenter `sbary`. -/
 595
 596section Geometry
 597
 598variable {d m k : ℕ}
 599
 600/-- The underlying function of the affine map determined by a vertex tuple:
 601`x ↦ ∑ i, x i • v i` in barycentric coordinates. -/
 602def affineMapFun (v : Fin (n + 1) → stdSimplex ℝ (Fin (m + 1)))
 603    (x : stdSimplex ℝ (Fin (n + 1))) : Fin (m + 1) → ℝ :=
 604  fun j => ∑ i, x i * v i j
 605
 606lemma affineMapFun_mem (v : Fin (n + 1) → stdSimplex ℝ (Fin (m + 1)))
 607    (x : stdSimplex ℝ (Fin (n + 1))) :
 608    affineMapFun v x ∈ stdSimplex ℝ (Fin (m + 1)) := by
 609  constructor
 610  · intro j
 611    exact Finset.sum_nonneg fun i _ =>
 612      mul_nonneg (stdSimplex.zero_le x i) (stdSimplex.zero_le (v i) j)
 613  · show ∑ j, ∑ i, x i * v i j = 1
 614    rw [Finset.sum_comm]
 615    calc ∑ i, ∑ j, x i * v i j = ∑ i : Fin (n + 1), x i * 1 := by
 616          refine Finset.sum_congr rfl fun i _ => ?_
 617          rw [← Finset.mul_sum, stdSimplex.sum_eq_one]
 618      _ = 1 := by
 619          simp only [mul_one]
 620          exact stdSimplex.sum_eq_one x
 621
 622lemma continuous_affineMapFun (v : Fin (n + 1) → stdSimplex ℝ (Fin (m + 1))) :
 623    Continuous (affineMapFun v) := by
 624  refine continuous_pi fun j => continuous_finset_sum _ fun i _ =>
 625    Continuous.mul ?_ continuous_const
 626  exact (continuous_apply i).comp continuous_subtype_val
 627
 628/-- The affine map `Δⁿ → Δᵐ` determined by a vertex tuple
 629`v : Fin (n+1) → Δᵐ`, sending the `i`-th vertex of `Δⁿ` to `v i`. -/
 630noncomputable def affineMap (v : Fin (n + 1) → stdSimplex ℝ (Fin (m + 1))) :
 631    C(stdSimplex ℝ (Fin (n + 1)), stdSimplex ℝ (Fin (m + 1))) where
 632  toFun x := ⟨affineMapFun v x, affineMapFun_mem v x⟩
 633  continuous_toFun := (continuous_affineMapFun v).subtype_mk _
 634
 635@[simp] lemma affineMap_apply_coe (v : Fin (n + 1) → stdSimplex ℝ (Fin (m + 1)))
 636    (x : stdSimplex ℝ (Fin (n + 1))) (j : Fin (m + 1)) :
 637    affineMap v x j = ∑ i, x i * v i j := rfl
 638
 639/-- The affine map sends vertices to the prescribed points. -/
 640lemma affineMap_vertex (v : Fin (n + 1) → stdSimplex ℝ (Fin (m + 1)))
 641    (i : Fin (n + 1)) :
 642    affineMap v (stdSimplex.vertex i) = v i := by
 643  refine stdSimplex.ext ?_
 644  funext j
 645  rw [affineMap_apply_coe, Finset.sum_eq_single i]
 646  · show (Pi.single i 1 : Fin (n + 1) → ℝ) i * v i j = v i j
 647    rw [Pi.single_eq_same, one_mul]
 648  · intro b _ hb
 649    show (Pi.single i 1 : Fin (n + 1) → ℝ) b * v b j = 0
 650    rw [Pi.single_eq_of_ne hb, zero_mul]
 651  · intro h
 652    exact absurd (Finset.mem_univ i) h
 653
 654/-- Functoriality: the composite of affine maps is the affine map of the
 655pushed vertex tuple. -/
 656theorem affineMap_comp (v : Fin (n + 1) → stdSimplex ℝ (Fin (m + 1)))
 657    (w : Fin (k + 1) → stdSimplex ℝ (Fin (n + 1))) :
 658    (affineMap v).comp (affineMap w) = affineMap (fun i => affineMap v (w i)) := by
 659  refine ContinuousMap.ext fun x => stdSimplex.ext ?_
 660  funext j
 661  show affineMap v (affineMap w x) j = affineMap (fun i => affineMap v (w i)) x j
 662  simp only [affineMap_apply_coe, Finset.sum_mul, Finset.mul_sum]
 663  rw [Finset.sum_comm]
 664  exact Finset.sum_congr rfl fun l _ => Finset.sum_congr rfl fun i _ => by ring
 665
 666/-- The identity vertex tuple. -/
 667noncomputable def idTuple (n : ℕ) : Fin (n + 1) → stdSimplex ℝ (Fin (n + 1)) :=
 668  fun i => stdSimplex.vertex i
 669
 670/-- The affine map of the identity tuple is the identity. -/
 671lemma affineMap_idTuple (n : ℕ) :
 672    affineMap (idTuple n) = ContinuousMap.id (stdSimplex ℝ (Fin (n + 1))) := by
 673  refine ContinuousMap.ext fun x => stdSimplex.ext ?_
 674  funext j
 675  show affineMap (idTuple n) x j = x j
 676  rw [affineMap_apply_coe, Finset.sum_eq_single j]
 677  · show x j * (Pi.single j 1 : Fin (n + 1) → ℝ) j = x j
 678    rw [Pi.single_eq_same, mul_one]
 679  · intro b _ hb
 680    show x b * (Pi.single b 1 : Fin (n + 1) → ℝ) j = 0
 681    rw [Pi.single_eq_of_ne (Ne.symm hb), mul_zero]
 682  · intro h
 683    exact absurd (Finset.mem_univ j) h
 684
 685/-- Composing an affine map with the identity tuple recovers the tuple. -/
 686lemma affineMap_comp_idTuple (v : Fin (n + 1) → stdSimplex ℝ (Fin (m + 1))) :
 687    ⇑(affineMap v) ∘ idTuple n = v :=
 688  funext fun i => affineMap_vertex v i
 689
 690/-- `stdSimplex.map` along a vertex map is the affine map of the
 691corresponding vertex tuple. -/
 692lemma stdSimplex_map_eq_affineMap (g : Fin (n + 1) → Fin (m + 1))
 693    (x : stdSimplex ℝ (Fin (n + 1))) :
 694    stdSimplex.map g x = affineMap (fun i => stdSimplex.vertex (g i)) x := by
 695  refine stdSimplex.ext ?_
 696  funext j
 697  have hL : (stdSimplex.map g x) j = ∑ i with g i = j, x i :=
 698    FunOnFinite.linearMap_apply_apply ℝ ℝ g (⇑x) j
 699  rw [hL]
 700  show ∑ i with g i = j, x i = ∑ i, x i * (Pi.single (g i) 1 : Fin (m + 1) → ℝ) j
 701  rw [Finset.sum_filter]
 702  refine Finset.sum_congr rfl fun i _ => ?_
 703  by_cases h : g i = j
 704  · rw [if_pos h, ← h, Pi.single_eq_same, mul_one]
 705  · rw [if_neg h, Pi.single_eq_of_ne (Ne.symm h), mul_zero]
 706
 707/-- Composing an affine map with a topological face inclusion restricts the
 708vertex tuple along `Fin.succAbove`. -/
 709lemma affineMap_comp_face (v : Fin (n + 2) → stdSimplex ℝ (Fin (d + 1)))
 710    (j : Fin (n + 2)) :
 711    (affineMap v).comp (SingularPrism.face j) =
 712      affineMap (v ∘ j.succAbove) := by
 713  refine ContinuousMap.ext fun x => ?_
 714  rw [ContinuousMap.comp_apply]
 715  show affineMap v (stdSimplex.map j.succAbove x) = _
 716  rw [stdSimplex_map_eq_affineMap j.succAbove x, ← ContinuousMap.comp_apply,
 717    affineMap_comp]
 718  have h : (fun i => affineMap v (stdSimplex.vertex (j.succAbove i))) =
 719      v ∘ j.succAbove := funext fun i => affineMap_vertex v _
 720  rw [h]
 721
 722/-- The barycenter of a vertex tuple in a standard simplex. -/
 723noncomputable def sbary {m : ℕ} (w : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1))) :
 724    stdSimplex ℝ (Fin (d + 1)) :=
 725  ⟨fun j => ((m : ℝ) + 1)⁻¹ * ∑ i, w i j, by
 726    constructor
 727    · intro j
 728      refine mul_nonneg (inv_nonneg.mpr (by positivity)) ?_
 729      exact Finset.sum_nonneg fun i _ => stdSimplex.zero_le (w i) j
 730    · rw [← Finset.mul_sum, Finset.sum_comm]
 731      have hsum : ∑ i, ∑ j, w i j = ((m : ℝ) + 1) := by
 732        calc ∑ i : Fin (m + 1), ∑ j, w i j = ∑ i : Fin (m + 1), (1 : ℝ) :=
 733              Finset.sum_congr rfl fun i _ => stdSimplex.sum_eq_one (w i)
 734          _ = ((m : ℝ) + 1) := by
 735              rw [Finset.sum_const, Finset.card_univ, Fintype.card_fin,
 736                nsmul_eq_mul, mul_one]
 737              push_cast
 738              ring
 739      rw [hsum, inv_mul_cancel₀ (by positivity)]⟩
 740
 741@[simp] lemma sbary_apply {m : ℕ} (w : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1)))
 742    (j : Fin (d + 1)) :
 743    sbary w j = ((m : ℝ) + 1)⁻¹ * ∑ i, w i j := rfl
 744
 745/-- Affine maps send barycenters to barycenters (the intertwining property
 746required by the equivariance lemmas of stage 5a). -/
 747lemma sbary_affineMap (v : Fin (n + 1) → stdSimplex ℝ (Fin (d + 1))) {m : ℕ}
 748    (w : Fin (m + 1) → stdSimplex ℝ (Fin (n + 1))) :
 749    sbary (⇑(affineMap v) ∘ w) = affineMap v (sbary w) := by
 750  refine stdSimplex.ext ?_
 751  funext j
 752  show ((m : ℝ) + 1)⁻¹ * ∑ i, (affineMap v (w i)) j = affineMap v (sbary w) j
 753  simp only [affineMap_apply_coe, sbary_apply, mul_assoc, Finset.sum_mul,
 754    ← Finset.mul_sum]
 755  rw [Finset.sum_comm]
 756
 757end Geometry
 758
 759/-! ## Stage 5c: the singular subdivision operator `sdOp` and homotopy `tOp`
 760
 761Affine chains in `Δⁿ` are evaluated as singular chains of `X` along a
 762singular simplex `σ : Δⁿ → X` (`toChain`); pushing forward the subdivided
 763identity tuple defines the singular barycentric subdivision `sdOp` and its
 764chain homotopy `tOp` on Mathlib's singular chain complex.  All identities
 765transport from the affine layer through the equivariance lemmas of
 766stage 5a. -/
 767
 768section Singular
 769
 770open SingularPrism
 771
 772variable {X Y : TopCat.{0}}
 773
 774/-- Post-composition with a morphism of `ℤ`-modules, as a `ℤ`-linear map on
 775hom groups out of `ℤ`. -/
 776noncomputable def postComp {M N : ModuleCat.{0} ℤ} (g : M ⟶ N) :
 777    (ModuleCat.of ℤ ℤ ⟶ M) →ₗ[ℤ] (ModuleCat.of ℤ ℤ ⟶ N) where
 778  toFun f := f ≫ g
 779  map_add' f₁ f₂ := by rw [Preadditive.add_comp]
 780  map_smul' r f := by rw [RingHom.id_apply, Preadditive.zsmul_comp]
 781
 782/-- `TopCat.toSSetObjEquiv`, retyped so that the domain of the continuous
 783map is literally `stdSimplex ℝ (Fin (m + 1))` (rather than the definitionally
 784equal `Fin ((unop (op ⦋m⦌)).len + 1)` normal form, which blocks rewriting). -/
 785noncomputable def simplexEquiv (X : TopCat.{0}) (m : ℕ) :
 786    Idx X m ≃ C(stdSimplex ℝ (Fin (m + 1)), X) :=
 787  X.toSSetObjEquiv (op ⦋m⦌)
 788
 789/-- Retyped naturality of `simplexEquiv` with respect to face maps. -/
 790lemma simplexEquiv_δ {m : ℕ} (j : Fin (m + 2)) (a : Idx X (m + 1)) :
 791    simplexEquiv X m ((TopCat.toSSet.obj X).δ j a) =
 792      (simplexEquiv X (m + 1) a).comp (face j) :=
 793  toSSetObjEquiv_δ j a
 794
 795/-- Retyped naturality of `simplexEquiv` with respect to continuous maps. -/
 796lemma simplexEquiv_map (f : X ⟶ Y) {m : ℕ} (a : Idx X m) :
 797    simplexEquiv Y m ((TopCat.toSSet.map f).app (op ⦋m⦌) a) =
 798      f.hom.comp (simplexEquiv X m a) :=
 799  toSSetObjEquiv_map f a
 800
 801/-- The singular `m`-simplex obtained by precomposing `σ` with the affine
 802map of a vertex tuple `w` in `Δⁿ`. -/
 803noncomputable def pushSimplex {n : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X)) {m : ℕ}
 804    (w : Fin (m + 1) → stdSimplex ℝ (Fin (n + 1))) : Idx X m :=
 805  (simplexEquiv X m).symm (σ.comp (affineMap w))
 806
 807lemma simplexEquiv_pushSimplex {n : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X)) {m : ℕ}
 808    (w : Fin (m + 1) → stdSimplex ℝ (Fin (n + 1))) :
 809    simplexEquiv X m (pushSimplex σ w) = σ.comp (affineMap w) :=
 810  Equiv.apply_symm_apply _ _
 811
 812/-- Evaluation of affine chains in `Δⁿ` as singular chains of `X` along a
 813singular simplex `σ : Δⁿ → X`. -/
 814noncomputable def toChain {n : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X)) (m : ℕ) :
 815    AC (stdSimplex ℝ (Fin (n + 1))) m →ₗ[ℤ] (ModuleCat.of ℤ ℤ ⟶ Cgrp X m) :=
 816  Finsupp.linearCombination ℤ (fun w => gen X m (pushSimplex σ w))
 817
 818lemma toChain_asimplex {n : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X)) (m : ℕ)
 819    (w : Fin (m + 1) → stdSimplex ℝ (Fin (n + 1))) :
 820    toChain σ m (asimplex w) = gen X m (pushSimplex σ w) :=
 821  lift_asimplex _ w
 822
 823/-- Faces of pushed simplices restrict the vertex tuple. -/
 824lemma δ_pushSimplex {n : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X)) {m : ℕ}
 825    (w : Fin (m + 2) → stdSimplex ℝ (Fin (n + 1))) (k : Fin (m + 2)) :
 826    (TopCat.toSSet.obj X).δ k (pushSimplex σ w) =
 827      pushSimplex σ (w ∘ k.succAbove) := by
 828  apply (simplexEquiv X m).injective
 829  rw [simplexEquiv_δ, simplexEquiv_pushSimplex, simplexEquiv_pushSimplex,
 830    ContinuousMap.comp_assoc, affineMap_comp_face]
 831
 832/-- The pushed simplex of the identity tuple is the simplex itself. -/
 833lemma pushSimplex_idTuple {n : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X)) :
 834    pushSimplex σ (idTuple n) = (simplexEquiv X n).symm σ := by
 835  unfold pushSimplex
 836  rw [affineMap_idTuple, ContinuousMap.comp_id]
 837
 838lemma toChain_asimplex_idTuple {n : ℕ} (s : Idx X n) :
 839    toChain (simplexEquiv X n s) n (asimplex (idTuple n)) = gen X n s := by
 840  rw [toChain_asimplex, pushSimplex_idTuple, Equiv.symm_apply_apply]
 841
 842/-- Any face of a singular simplex is the pushed simplex of a face of the
 843identity tuple. -/
 844lemma δ_eq_pushSimplex {n : ℕ} (s : Idx X (n + 1)) (k : Fin (n + 2)) :
 845    (TopCat.toSSet.obj X).δ k s =
 846      pushSimplex (simplexEquiv X (n + 1) s) (idTuple (n + 1) ∘ k.succAbove) := by
 847  have h : pushSimplex (simplexEquiv X (n + 1) s) (idTuple (n + 1)) = s := by
 848    rw [pushSimplex_idTuple, Equiv.symm_apply_apply]
 849  conv_lhs => rw [← h]
 850  exact δ_pushSimplex _ _ k
 851
 852/-- `toChain` intertwines the affine and the singular boundary. -/
 853lemma toChain_comp_abnd {n : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X)) (m : ℕ) :
 854    (postComp (bnd X m)).comp (toChain σ (m + 1)) = (toChain σ m).comp (abnd m) := by
 855  refine AC.hom_ext fun w => ?_
 856  rw [LinearMap.comp_apply, LinearMap.comp_apply, toChain_asimplex]
 857  show gen X (m + 1) (pushSimplex σ w) ≫ bnd X m = toChain σ m (abnd m (asimplex w))
 858  rw [gen_d, abnd_asimplex, map_sum]
 859  refine Finset.sum_congr rfl fun k _ => ?_
 860  rw [map_smul, toChain_asimplex, δ_pushSimplex]
 861
 862/-- `toChain` intertwines post-composition with the induced chain map. -/
 863lemma toChain_comp_chainMap {n : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X))
 864    (f : X ⟶ Y) (m : ℕ) :
 865    (postComp (chainMap f m)).comp (toChain σ m) = toChain (f.hom.comp σ) m := by
 866  refine AC.hom_ext fun w => ?_
 867  rw [LinearMap.comp_apply, toChain_asimplex, toChain_asimplex]
 868  show gen X m (pushSimplex σ w) ≫ chainMap f m =
 869    gen Y m (pushSimplex (f.hom.comp σ) w)
 870  rw [gen_map]
 871  congr 1
 872
 873/-- `toChain` turns the affine pushforward along an affine map into
 874precomposition of the singular simplex. -/
 875lemma toChain_amap {n n' : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X))
 876    (v : Fin (n' + 1) → stdSimplex ℝ (Fin (n + 1))) (m : ℕ) :
 877    (toChain σ m).comp (amap (⇑(affineMap v)) m) = toChain (σ.comp (affineMap v)) m := by
 878  refine AC.hom_ext fun w => ?_
 879  rw [LinearMap.comp_apply, amap_asimplex, toChain_asimplex, toChain_asimplex]
 880  congr 1
 881  apply (simplexEquiv X m).injective
 882  rw [simplexEquiv_pushSimplex, simplexEquiv_pushSimplex, ContinuousMap.comp_assoc,
 883    affineMap_comp]
 884  rfl
 885
 886/-- The barycentric apex function on `Δⁿ`, in the shape expected by
 887`asub`/`atee`. -/
 888noncomputable def baryFn (n : ℕ) :
 889    ∀ {m : ℕ}, (Fin (m + 1) → stdSimplex ℝ (Fin (n + 1))) → stdSimplex ℝ (Fin (n + 1)) :=
 890  fun {_} w => sbary w
 891
 892/-- Generator value of the singular subdivision operator. -/
 893noncomputable def sdGen (X : TopCat.{0}) (n : ℕ) (s : Idx X n) :
 894    ModuleCat.of ℤ ℤ ⟶ Cgrp X n :=
 895  toChain (simplexEquiv X n s) n (asub (baryFn n) n (asimplex (idTuple n)))
 896
 897/-- The singular barycentric subdivision operator `sdOp X : C_n(X) ⟶ C_n(X)`. -/
 898noncomputable def sdOp (X : TopCat.{0}) (n : ℕ) : Cgrp X n ⟶ Cgrp X n :=
 899  Sigma.desc (sdGen X n)
 900
 901lemma gen_sdOp {n : ℕ} (s : Idx X n) : gen X n s ≫ sdOp X n = sdGen X n s :=
 902  Sigma.ι_desc _ _
 903
 904/-- Generator value of the singular subdivision homotopy. -/
 905noncomputable def tGen (X : TopCat.{0}) (n : ℕ) (s : Idx X n) :
 906    ModuleCat.of ℤ ℤ ⟶ Cgrp X (n + 1) :=
 907  toChain (simplexEquiv X n s) (n + 1) (atee (baryFn n) n (asimplex (idTuple n)))
 908
 909/-- The singular subdivision chain homotopy `tOp X : C_n(X) ⟶ C_{n+1}(X)`. -/
 910noncomputable def tOp (X : TopCat.{0}) (n : ℕ) : Cgrp X n ⟶ Cgrp X (n + 1) :=
 911  Sigma.desc (tGen X n)
 912
 913lemma gen_tOp {n : ℕ} (s : Idx X n) : gen X n s ≫ tOp X n = tGen X n s :=
 914  Sigma.ι_desc _ _
 915
 916/-- The heart of the transport: `sdOp` on a pushed generator computes the
 917subdivision of the pushed tuple. -/
 918lemma gen_pushSimplex_comp_sdOp {n n' : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X))
 919    (w : Fin (n' + 1) → stdSimplex ℝ (Fin (n + 1))) :
 920    gen X n' (pushSimplex σ w) ≫ sdOp X n' =
 921      toChain σ n' (asub (baryFn n) n' (asimplex w)) := by
 922  rw [gen_sdOp]
 923  show toChain (simplexEquiv X n' (pushSimplex σ w)) n'
 924      (asub (baryFn n') n' (asimplex (idTuple n'))) = _
 925  rw [simplexEquiv_pushSimplex]
 926  have hL := LinearMap.congr_fun (toChain_amap σ w n')
 927    (asub (baryFn n') n' (asimplex (idTuple n')))
 928  rw [LinearMap.comp_apply] at hL
 929  rw [← hL]
 930  have heq := LinearMap.congr_fun (amap_comp_asub (⇑(affineMap w)) (baryFn n')
 931    (baryFn n) (fun m u => sbary_affineMap w u) n') (asimplex (idTuple n'))
 932  rw [LinearMap.comp_apply, LinearMap.comp_apply] at heq
 933  rw [heq, amap_asimplex, affineMap_comp_idTuple]
 934
 935/-- `tOp` on a pushed generator computes the homotopy of the pushed tuple. -/
 936lemma gen_pushSimplex_comp_tOp {n n' : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X))
 937    (w : Fin (n' + 1) → stdSimplex ℝ (Fin (n + 1))) :
 938    gen X n' (pushSimplex σ w) ≫ tOp X n' =
 939      toChain σ (n' + 1) (atee (baryFn n) n' (asimplex w)) := by
 940  rw [gen_tOp]
 941  show toChain (simplexEquiv X n' (pushSimplex σ w)) (n' + 1)
 942      (atee (baryFn n') n' (asimplex (idTuple n'))) = _
 943  rw [simplexEquiv_pushSimplex]
 944  have hL := LinearMap.congr_fun (toChain_amap σ w (n' + 1))
 945    (atee (baryFn n') n' (asimplex (idTuple n')))
 946  rw [LinearMap.comp_apply] at hL
 947  rw [← hL]
 948  have heq := LinearMap.congr_fun (amap_comp_atee (⇑(affineMap w)) (baryFn n')
 949    (baryFn n) (fun m u => sbary_affineMap w u) n') (asimplex (idTuple n'))
 950  rw [LinearMap.comp_apply, LinearMap.comp_apply] at heq
 951  rw [heq, amap_asimplex, affineMap_comp_idTuple]
 952
 953/-- The singular subdivision operator is a chain map: `∂ ∘ S = S ∘ ∂`. -/
 954theorem sdOp_comp_bnd (X : TopCat.{0}) (n : ℕ) :
 955    sdOp X (n + 1) ≫ bnd X n = bnd X n ≫ sdOp X n := by
 956  apply Sigma.hom_ext
 957  intro s
 958  rw [← Category.assoc, ← Category.assoc, gen_sdOp, gen_d]
 959  have hL : sdGen X (n + 1) s ≫ bnd X n =
 960      toChain (simplexEquiv X (n + 1) s) n
 961        (asub (baryFn (n + 1)) n (abnd n (asimplex (idTuple (n + 1))))) := by
 962    have h := LinearMap.congr_fun
 963      (toChain_comp_abnd (simplexEquiv X (n + 1) s) n)
 964      (asub (baryFn (n + 1)) (n + 1) (asimplex (idTuple (n + 1))))
 965    rw [LinearMap.comp_apply, LinearMap.comp_apply] at h
 966    have hcomm := LinearMap.congr_fun (abnd_comp_asub (baryFn (n + 1)) n)
 967      (asimplex (idTuple (n + 1)))
 968    rw [LinearMap.comp_apply, LinearMap.comp_apply] at hcomm
 969    rw [← hcomm]
 970    exact h
 971  rw [hL, abnd_asimplex, map_sum, map_sum, Preadditive.sum_comp]
 972  refine Finset.sum_congr rfl fun k _ => ?_
 973  rw [map_smul, map_smul, Preadditive.zsmul_comp]
 974  congr 1
 975  rw [δ_eq_pushSimplex, gen_pushSimplex_comp_sdOp]
 976
 977/-- In degree `0` the singular subdivision operator is the identity. -/
 978theorem sdOp_zero (X : TopCat.{0}) : sdOp X 0 = 𝟙 (Cgrp X 0) := by
 979  apply Sigma.hom_ext
 980  intro s
 981  rw [Category.comp_id, gen_sdOp]
 982  show toChain (simplexEquiv X 0 s) 0
 983    (asub (baryFn 0) 0 (asimplex (idTuple 0))) = gen X 0 s
 984  rw [asub_zero, LinearMap.id_apply]
 985  exact toChain_asimplex_idTuple s
 986
 987/-- In degree `0` the singular subdivision homotopy vanishes. -/
 988theorem tOp_zero (X : TopCat.{0}) : tOp X 0 = 0 := by
 989  apply Sigma.hom_ext
 990  intro s
 991  rw [Limits.comp_zero, gen_tOp]
 992  show toChain (simplexEquiv X 0 s) 1
 993    (atee (baryFn 0) 0 (asimplex (idTuple 0))) = 0
 994  rw [atee_zero, LinearMap.zero_apply, map_zero]
 995
 996/-- The chain homotopy identity in positive degrees:
 997`∂ ∘ T + T ∘ ∂ = id − S` on the degree-`(n+1)` singular chain group. -/
 998theorem tOp_chain_homotopy_succ (X : TopCat.{0}) (n : ℕ) :
 999    bnd X n ≫ tOp X n + tOp X (n + 1) ≫ bnd X (n + 1) =
1000      𝟙 (Cgrp X (n + 1)) - sdOp X (n + 1) := by
1001  apply Sigma.hom_ext
1002  intro s
1003  rw [Preadditive.comp_add, Preadditive.comp_sub, Category.comp_id]
1004  -- second summand: `T ∘ ∂` transported to `toChain σ (T (∂ id))`
1005  have h2 : gen X (n + 1) s ≫ (bnd X n ≫ tOp X n) =
1006      toChain (simplexEquiv X (n + 1) s) (n + 1)
1007        (atee (baryFn (n + 1)) n (abnd n (asimplex (idTuple (n + 1))))) := by
1008    rw [← Category.assoc, gen_d, Preadditive.sum_comp, abnd_asimplex, map_sum,
1009      map_sum]
1010    refine Finset.sum_congr rfl fun k _ => ?_
1011    rw [Preadditive.zsmul_comp, map_smul, map_smul]
1012    congr 1
1013    rw [δ_eq_pushSimplex, gen_pushSimplex_comp_tOp]
1014  -- first summand: `∂ ∘ T` transported to `toChain σ (∂ (T id))`
1015  have h1 : gen X (n + 1) s ≫ (tOp X (n + 1) ≫ bnd X (n + 1)) =
1016      toChain (simplexEquiv X (n + 1) s) (n + 1)
1017        (abnd (n + 1) (atee (baryFn (n + 1)) (n + 1) (asimplex (idTuple (n + 1))))) := by
1018    rw [← Category.assoc, gen_tOp]
1019    have h := LinearMap.congr_fun
1020      (toChain_comp_abnd (simplexEquiv X (n + 1) s) (n + 1))
1021      (atee (baryFn (n + 1)) (n + 1) (asimplex (idTuple (n + 1))))
1022    rw [LinearMap.comp_apply, LinearMap.comp_apply] at h
1023    exact h
1024  rw [h2, h1, ← map_add, gen_sdOp]
1025  have hhom := LinearMap.congr_fun (abnd_comp_atee (baryFn (n + 1)) n)
1026    (asimplex (idTuple (n + 1)))
1027  simp only [LinearMap.add_apply, LinearMap.comp_apply, LinearMap.sub_apply,
1028    LinearMap.id_apply] at hhom
1029  have hsum : atee (baryFn (n + 1)) n (abnd n (asimplex (idTuple (n + 1)))) +
1030      abnd (n + 1) (atee (baryFn (n + 1)) (n + 1) (asimplex (idTuple (n + 1)))) =
1031      asimplex (idTuple (n + 1)) -
1032        asub (baryFn (n + 1)) (n + 1) (asimplex (idTuple (n + 1))) := by
1033    exact (add_comm _ _).trans hhom
1034  rw [hsum, map_sub, toChain_asimplex_idTuple]
1035  rfl
1036
1037/-- In degree `0`: `∂ ∘ T = id − S` (both sides vanish). -/
1038theorem tOp_chain_homotopy_zero (X : TopCat.{0}) :
1039    tOp X 0 ≫ bnd X 0 = 𝟙 (Cgrp X 0) - sdOp X 0 := by
1040  rw [tOp_zero, sdOp_zero, Limits.zero_comp, sub_self]
1041
1042/-- Naturality of the singular subdivision operator. -/
1043theorem sdOp_natural (f : X ⟶ Y) (n : ℕ) :
1044    chainMap f n ≫ sdOp Y n = sdOp X n ≫ chainMap f n := by
1045  apply Sigma.hom_ext
1046  intro s
1047  rw [← Category.assoc, ← Category.assoc, gen_map, gen_sdOp, gen_sdOp]
1048  have hR := LinearMap.congr_fun
1049    (toChain_comp_chainMap (simplexEquiv X n s) f n)
1050    (asub (baryFn n) n (asimplex (idTuple n)))
1051  rw [LinearMap.comp_apply] at hR
1052  have hL : sdGen Y n ((TopCat.toSSet.map f).app (op ⦋n⦌) s) =
1053      toChain (f.hom.comp (simplexEquiv X n s)) n
1054        (asub (baryFn n) n (asimplex (idTuple n))) := by
1055    show toChain (simplexEquiv Y n ((TopCat.toSSet.map f).app (op ⦋n⦌) s)) n
1056        (asub (baryFn n) n (asimplex (idTuple n))) = _
1057    rw [simplexEquiv_map]
1058  rw [hL, ← hR]
1059  rfl
1060
1061/-- Naturality of the singular subdivision homotopy. -/
1062theorem tOp_natural (f : X ⟶ Y) (n : ℕ) :
1063    chainMap f n ≫ tOp Y n = tOp X n ≫ chainMap f (n + 1) := by
1064  apply Sigma.hom_ext
1065  intro s
1066  rw [← Category.assoc, ← Category.assoc, gen_map, gen_tOp, gen_tOp]
1067  have hR := LinearMap.congr_fun
1068    (toChain_comp_chainMap (simplexEquiv X n s) f (n + 1))
1069    (atee (baryFn n) n (asimplex (idTuple n)))
1070  rw [LinearMap.comp_apply] at hR
1071  have hL : tGen Y n ((TopCat.toSSet.map f).app (op ⦋n⦌) s) =
1072      toChain (f.hom.comp (simplexEquiv X n s)) (n + 1)
1073        (atee (baryFn n) n (asimplex (idTuple n))) := by
1074    show toChain (simplexEquiv Y n ((TopCat.toSSet.map f).app (op ⦋n⦌) s)) (n + 1)
1075        (atee (baryFn n) n (asimplex (idTuple n))) = _
1076    rw [simplexEquiv_map]
1077  rw [hL, ← hR]
1078  rfl
1079
1080/-! ### Iterates of the singular subdivision operator -/
1081
1082/-- The `k`-th iterate of the singular subdivision operator. -/
1083noncomputable def sdOpIter (X : TopCat.{0}) (n : ℕ) : ℕ → (Cgrp X n ⟶ Cgrp X n)
1084  | 0 => 𝟙 _
1085  | k + 1 => sdOpIter X n k ≫ sdOp X n
1086
1087@[simp] lemma sdOpIter_zero (X : TopCat.{0}) (n : ℕ) :
1088    sdOpIter X n 0 = 𝟙 (Cgrp X n) := rfl
1089
1090lemma sdOpIter_succ (X : TopCat.{0}) (n k : ℕ) :
1091    sdOpIter X n (k + 1) = sdOpIter X n k ≫ sdOp X n := rfl
1092
1093/-- The telescoped homotopy for the iterate, `T_{k+1} = T + S ≫ T_k`. -/
1094noncomputable def tOpIter (X : TopCat.{0}) (n : ℕ) : ℕ → (Cgrp X n ⟶ Cgrp X (n + 1))
1095  | 0 => 0
1096  | k + 1 => tOp X n + sdOp X n ≫ tOpIter X n k
1097
1098@[simp] lemma tOpIter_zero (X : TopCat.{0}) (n : ℕ) : tOpIter X n 0 = 0 := rfl
1099
1100lemma tOpIter_succ (X : TopCat.{0}) (n k : ℕ) :
1101    tOpIter X n (k + 1) = tOp X n + sdOp X n ≫ tOpIter X n k := rfl
1102
1103/-- The iterate commutes with `sdOp`. -/
1104lemma sdOpIter_comp_sdOp (X : TopCat.{0}) (n k : ℕ) :
1105    sdOpIter X n k ≫ sdOp X n = sdOp X n ≫ sdOpIter X n k := by
1106  induction k with
1107  | zero => rw [sdOpIter_zero, Category.id_comp, Category.comp_id]
1108  | succ k IH =>
1109      calc sdOpIter X n (k + 1) ≫ sdOp X n
1110          = sdOpIter X n k ≫ sdOp X n ≫ sdOp X n := by
1111            rw [sdOpIter_succ, Category.assoc]
1112        _ = (sdOp X n ≫ sdOpIter X n k) ≫ sdOp X n := by
1113            rw [← IH, Category.assoc]
1114        _ = sdOp X n ≫ sdOpIter X n (k + 1) := by
1115            rw [Category.assoc, sdOpIter_succ]
1116
1117/-- The iterate is a chain map. -/
1118theorem sdOpIter_comp_bnd (X : TopCat.{0}) (n k : ℕ) :
1119    sdOpIter X (n + 1) k ≫ bnd X n = bnd X n ≫ sdOpIter X n k := by
1120  induction k with
1121  | zero => rw [sdOpIter_zero, sdOpIter_zero, Category.id_comp, Category.comp_id]
1122  | succ k IH =>
1123      rw [sdOpIter_succ, sdOpIter_succ, Category.assoc, sdOp_comp_bnd,
1124        ← Category.assoc, IH, Category.assoc]
1125
1126/-- The telescoped chain homotopy identity in positive degrees:
1127`∂ ∘ T_k + T_k ∘ ∂ = id − S^k` on the degree-`(n+1)` singular chain group. -/
1128theorem tOpIter_chain_homotopy_succ (X : TopCat.{0}) (n k : ℕ) :
1129    bnd X n ≫ tOpIter X n k + tOpIter X (n + 1) k ≫ bnd X (n + 1) =
1130      𝟙 (Cgrp X (n + 1)) - sdOpIter X (n + 1) k := by
1131  induction k with
1132  | zero =>
1133      rw [tOpIter_zero, tOpIter_zero, sdOpIter_zero, Limits.comp_zero,
1134        Limits.zero_comp, add_zero, sub_self]
1135  | succ k IH =>
1136      rw [tOpIter_succ, tOpIter_succ, sdOpIter_succ]
1137      have key : bnd X n ≫ (tOp X n + sdOp X n ≫ tOpIter X n k) +
1138          (tOp X (n + 1) + sdOp X (n + 1) ≫ tOpIter X (n + 1) k) ≫ bnd X (n + 1) =
1139          (bnd X n ≫ tOp X n + tOp X (n + 1) ≫ bnd X (n + 1)) +
1140            sdOp X (n + 1) ≫
1141              (bnd X n ≫ tOpIter X n k + tOpIter X (n + 1) k ≫ bnd X (n + 1)) := by
1142        rw [Preadditive.comp_add, Preadditive.add_comp, Preadditive.comp_add,
1143          Category.assoc]
1144        have hmid : bnd X n ≫ sdOp X n ≫ tOpIter X n k =
1145            sdOp X (n + 1) ≫ bnd X n ≫ tOpIter X n k := by
1146          rw [← Category.assoc, ← sdOp_comp_bnd, Category.assoc]
1147        rw [hmid]
1148        abel
1149      rw [key, tOp_chain_homotopy_succ, IH, Preadditive.comp_sub,
1150        Category.comp_id, sdOpIter_comp_sdOp]
1151      abel
1152
1153/-- The telescoped chain homotopy identity in degree `0`:
1154`∂ ∘ T_k = id − S^k` on the degree-`0` singular chain group. -/
1155theorem tOpIter_chain_homotopy_zero (X : TopCat.{0}) (k : ℕ) :
1156    tOpIter X 0 k ≫ bnd X 0 = 𝟙 (Cgrp X 0) - sdOpIter X 0 k := by
1157  induction k with
1158  | zero => rw [tOpIter_zero, sdOpIter_zero, Limits.zero_comp, sub_self]
1159  | succ k IH =>
1160      rw [tOpIter_succ, sdOpIter_succ, Preadditive.add_comp, Category.assoc,
1161        tOp_chain_homotopy_zero, IH, Preadditive.comp_sub, Category.comp_id,
1162        sdOpIter_comp_sdOp]
1163      abel
1164
1165/-- `toChain` intertwines `sdOp` and the affine subdivision. -/
1166lemma toChain_comp_sdOp {n n' : ℕ} (σ : C(stdSimplex ℝ (Fin (n + 1)), X)) :
1167    (postComp (sdOp X n')).comp (toChain σ n') =
1168      (toChain σ n').comp (asub (baryFn n) n') := by
1169  refine AC.hom_ext fun w => ?_
1170  rw [LinearMap.comp_apply, LinearMap.comp_apply, toChain_asimplex]
1171  exact gen_pushSimplex_comp_sdOp σ w
1172
1173/-- The iterated singular subdivision of a generator is the evaluation of the
1174iterated affine subdivision of the identity tuple.  This ties the singular
1175operator to the affine support geometry of stage 6. -/
1176theorem gen_comp_sdOpIter {n : ℕ} (s : Idx X n) (k : ℕ) :
1177    gen X n s ≫ sdOpIter X n k =
1178      toChain (simplexEquiv X n s) n
1179        (asubIter (baryFn n) k n (asimplex (idTuple n))) := by
1180  induction k with
1181  | zero =>
1182      rw [sdOpIter_zero, Category.comp_id, asubIter_zero, LinearMap.id_apply,
1183        toChain_asimplex_idTuple]
1184  | succ k IH =>
1185      rw [sdOpIter_succ, ← Category.assoc, IH, asubIter_succ, LinearMap.comp_apply]
1186      have h := LinearMap.congr_fun
1187        (toChain_comp_sdOp (X := X) (n' := n) (simplexEquiv X n s))
1188        (asubIter (baryFn n) k n (asimplex (idTuple n)))
1189      rw [LinearMap.comp_apply, LinearMap.comp_apply] at h
1190      exact h
1191
1192end Singular
1193
1194/-! ## Stage 6: the diameter estimate for barycentric subdivision
1195
1196We track the `Finsupp` support of the affine subdivision operator through its
1197cone recursion.  The two invariants: every vertex of every piece lies in the
1198convex hull (in the ambient coordinate space) of the original vertex tuple,
1199and the pairwise vertex distances contract by the factor `n / (n + 1)`.
1200Iterating gives geometric decay of piece diameters.  The ambient metric is
1201the sup metric on `Fin (d + 1) → ℝ`, whose subtype metric induces the
1202topology of `SimplexCategory.toTop` on `stdSimplex ℝ (Fin (d + 1))`. -/
1203
1204section SupportTracking
1205
1206variable {α : Type}
1207
1208/-- Transport of a support predicate through a linear operator on affine
1209chains: if `T` maps every generator satisfying `P` to a chain supported on
1210tuples satisfying `Q`, the same holds for arbitrary chains supported on `P`. -/
1211lemma support_transport {n m : ℕ} (T : AC α n →ₗ[ℤ] AC α m)
1212    {P : (Fin (n + 1) → α) → Prop} {Q : (Fin (m + 1) → α) → Prop}
1213    (hT : ∀ w, P w → ∀ u ∈ (T (asimplex w)).support, Q u)
1214    (c : AC α n) (hc : ∀ w ∈ c.support, P w) :
1215    ∀ u ∈ (T c).support, Q u := by
1216  intro u hu
1217  have hrep : T c = ∑ w ∈ c.support, T (Finsupp.single w (c w)) := by
1218    conv_lhs => rw [← Finsupp.sum_single c]
1219    rw [Finsupp.sum, map_sum]
1220  rw [hrep] at hu
1221  obtain ⟨w, hw, hu'⟩ := Finsupp.mem_support_finset_sum u hu
1222  have hsingle : (Finsupp.single w (c w) : AC α n) = (c w) • asimplex w := by
1223    rw [asimplex, Finsupp.smul_single, smul_eq_mul, mul_one]
1224  rw [hsingle, map_smul] at hu'
1225  exact hT w (hc w hw) u (Finsupp.support_smul hu')
1226
1227/-- The support of the boundary of a generator consists of faces. -/
1228lemma support_abnd_asimplex {n : ℕ} (w : Fin (n + 2) → α) :
1229    ∀ v ∈ (abnd n (asimplex w)).support, ∃ j : Fin (n + 2), v = w ∘ j.succAbove := by
1230  intro v hv
1231  rw [abnd_asimplex] at hv
1232  obtain ⟨j, _, hv'⟩ := Finsupp.mem_support_finset_sum v hv
1233  have hmem := Finsupp.support_smul hv'
1234  rw [asimplex] at hmem
1235  have hsingle := Finsupp.support_single_subset hmem
1236  rw [Finset.mem_singleton] at hsingle
1237  exact ⟨j, hsingle⟩
1238
1239/-- The support of a cone consists of cones over the original support. -/
1240lemma support_acone {n : ℕ} (b : α) (c : AC α n) :
1241    ∀ u ∈ (acone b c).support, ∃ v ∈ c.support, u = Fin.cons b v := by
1242  classical
1243  intro u hu
1244  rw [acone, Finsupp.lmapDomain_apply] at hu
1245  obtain ⟨v, hv, huv⟩ := Finset.mem_image.mp (Finsupp.mapDomain_support hu)
1246  exact ⟨v, hv, huv.symm⟩
1247
1248end SupportTracking
1249
1250section Diameter
1251
1252variable {d : ℕ}
1253
1254@[simp] lemma baryFn_apply {m : ℕ} (w : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1))) :
1255    baryFn d w = sbary w := rfl
1256
1257/-- The convex hull, in the ambient coordinate space, of a vertex tuple in
1258the standard simplex. -/
1259def hullOf {m : ℕ} (w : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1))) :
1260    Set (Fin (d + 1) → ℝ) :=
1261  convexHull ℝ (Set.range fun i => ((w i : Fin (d + 1) → ℝ)))
1262
1263lemma coe_mem_hullOf {m : ℕ} (w : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1)))
1264    (i : Fin (m + 1)) : ((w i : Fin (d + 1) → ℝ)) ∈ hullOf w :=
1265  subset_convexHull ℝ _ ⟨i, rfl⟩
1266
1267/-- Hull monotonicity from a coordinatewise membership hypothesis. -/
1268lemma hullOf_subset {m m' : ℕ} {w : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1))}
1269    {v : Fin (m' + 1) → stdSimplex ℝ (Fin (d + 1))}
1270    (h : ∀ i, ((v i : Fin (d + 1) → ℝ)) ∈ hullOf w) : hullOf v ⊆ hullOf w :=
1271  convexHull_min (by rintro x ⟨i, rfl⟩; exact h i) (convex_convexHull ℝ _)
1272
1273/-- The barycenter as an explicit convex combination in the ambient space. -/
1274lemma coe_sbary {m : ℕ} (w : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1))) :
1275    ((sbary w : Fin (d + 1) → ℝ)) =
1276      ∑ i, ((m : ℝ) + 1)⁻¹ • ((w i : Fin (d + 1) → ℝ)) := by
1277  funext j
1278  rw [Finset.sum_apply]
1279  simp only [Pi.smul_apply, smul_eq_mul]
1280  rw [← Finset.mul_sum]
1281  rfl
1282
1283lemma sbary_mem_hullOf {m : ℕ} (w : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1))) :
1284    ((sbary w : Fin (d + 1) → ℝ)) ∈ hullOf w := by
1285  rw [coe_sbary]
1286  refine (convex_convexHull ℝ _).sum_mem (fun i _ => by positivity) ?_
1287    (fun i _ => coe_mem_hullOf w i)
1288  rw [Finset.sum_const, Finset.card_univ, Fintype.card_fin, nsmul_eq_mul]
1289  push_cast
1290  rw [mul_inv_cancel₀ (by positivity)]
1291
1292/-- Two points of the hull of a tuple with pairwise distances `≤ D` are
1293themselves at distance `≤ D` (maximum principle for the convex `dist`). -/
1294lemma dist_le_of_mem_hullOf {m : ℕ} {w : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1))}
1295    {D : ℝ} (hw : ∀ i j, dist (w i) (w j) ≤ D)
1296    {x y : Fin (d + 1) → ℝ} (hx : x ∈ hullOf w) (hy : y ∈ hullOf w) :
1297    dist x y ≤ D := by
1298  obtain ⟨x', ⟨i, rfl⟩, hx'⟩ := convexHull_exists_dist_ge hx y
1299  obtain ⟨y', ⟨j, rfl⟩, hy'⟩ := convexHull_exists_dist_ge hy ((w i : Fin (d + 1) → ℝ))
1300  calc dist x y ≤ dist ((w i : Fin (d + 1) → ℝ)) y := hx'
1301    _ = dist y ((w i : Fin (d + 1) → ℝ)) := dist_comm _ _
1302    _ ≤ dist ((w j : Fin (d + 1) → ℝ)) ((w i : Fin (d + 1) → ℝ)) := hy'
1303    _ = dist (w j) (w i) := (Subtype.dist_eq _ _).symm
1304    _ ≤ D := hw j i
1305
1306/-- Key metric estimate: the barycenter of an `m`-tuple with pairwise
1307distances `≤ D` is within `m/(m+1) · D` of every point of the tuple's hull. -/
1308lemma dist_sbary_le {m : ℕ} {w : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1))}
1309    {D : ℝ} (hw : ∀ i j, dist (w i) (w j) ≤ D)
1310    {x : Fin (d + 1) → ℝ} (hx : x ∈ hullOf w) :
1311    dist ((sbary w : Fin (d + 1) → ℝ)) x ≤ ((m : ℝ) / (m + 1)) * D := by
1312  obtain ⟨x', ⟨j, rfl⟩, hx'⟩ :=
1313    convexHull_exists_dist_ge hx ((sbary w : Fin (d + 1) → ℝ))
1314  rw [dist_comm] at hx'
1315  refine hx'.trans ?_
1316  show dist ((w j : Fin (d + 1) → ℝ)) ((sbary w : Fin (d + 1) → ℝ)) ≤ _
1317  rw [dist_comm, dist_eq_norm]
1318  have hrep : ((sbary w : Fin (d + 1) → ℝ)) - (w j : Fin (d + 1) → ℝ) =
1319      ∑ i, ((m : ℝ) + 1)⁻¹ •
1320        (((w i : Fin (d + 1) → ℝ)) - ((w j : Fin (d + 1) → ℝ))) := by
1321    funext j'
1322    rw [Pi.sub_apply, Finset.sum_apply]
1323    simp only [Pi.smul_apply, Pi.sub_apply, smul_eq_mul, mul_sub]
1324    rw [Finset.sum_sub_distrib]
1325    have h1 : ∑ i : Fin (m + 1), ((m : ℝ) + 1)⁻¹ * (w i) j' = sbary w j' := by
1326      rw [sbary_apply, Finset.mul_sum]
1327    have h2 : ∑ _i : Fin (m + 1), ((m : ℝ) + 1)⁻¹ * (w j) j' = (w j) j' := by
1328      rw [Finset.sum_const, Finset.card_univ, Fintype.card_fin, nsmul_eq_mul]
1329      push_cast
1330      rw [← mul_assoc, mul_inv_cancel₀ (by positivity), one_mul]
1331    rw [h1, h2]
1332  rw [hrep]
1333  calc ‖∑ i, ((m : ℝ) + 1)⁻¹ •
1334        (((w i : Fin (d + 1) → ℝ)) - ((w j : Fin (d + 1) → ℝ)))‖
1335      ≤ ∑ i, ‖((m : ℝ) + 1)⁻¹ •
1336        (((w i : Fin (d + 1) → ℝ)) - ((w j : Fin (d + 1) → ℝ)))‖ :=
1337        norm_sum_le _ _
1338    _ = ∑ i, ((m : ℝ) + 1)⁻¹ *
1339        ‖((w i : Fin (d + 1) → ℝ)) - ((w j : Fin (d + 1) → ℝ))‖ := by
1340        refine Finset.sum_congr rfl fun i _ => ?_
1341        rw [norm_smul, Real.norm_eq_abs, abs_of_nonneg (by positivity)]
1342    _ ≤ ((m : ℝ) / (m + 1)) * D := ?_
1343  rw [← Finset.add_sum_erase _ _ (Finset.mem_univ j), sub_self, norm_zero,
1344    mul_zero, zero_add]
1345  have hterm : ∀ i ∈ Finset.univ.erase j,
1346      ((m : ℝ) + 1)⁻¹ * ‖((w i : Fin (d + 1) → ℝ)) - ((w j : Fin (d + 1) → ℝ))‖ ≤
1347        ((m : ℝ) + 1)⁻¹ * D := by
1348    intro i _
1349    refine mul_le_mul_of_nonneg_left ?_ (by positivity)
1350    rw [← dist_eq_norm]
1351    exact hw i j
1352  calc ∑ i ∈ Finset.univ.erase j, ((m : ℝ) + 1)⁻¹ *
1353        ‖((w i : Fin (d + 1) → ℝ)) - ((w j : Fin (d + 1) → ℝ))‖
1354      ≤ (Finset.univ.erase j).card • (((m : ℝ) + 1)⁻¹ * D) :=
1355        Finset.sum_le_card_nsmul _ _ _ hterm
1356    _ = ((m : ℝ) / (m + 1)) * D := by
1357        rw [Finset.card_erase_of_mem (Finset.mem_univ j), Finset.card_univ,
1358          Fintype.card_fin, nsmul_eq_mul, div_eq_mul_inv]
1359        push_cast
1360        ring
1361
1362/-- The contraction ratio is monotone in the degree. -/
1363lemma ratio_mono (n : ℕ) : ((n : ℝ) / (n + 1)) ≤ (((n : ℝ) + 1) / ((n : ℝ) + 2)) := by
1364  rw [div_le_div_iff₀ (by positivity) (by positivity)]
1365  nlinarith [sq_nonneg ((n : ℝ))]
1366
1367/-- **Stage 6 main estimate.** Every piece of the barycentric subdivision of
1368an affine simplex has vertices in the hull of the original tuple, with
1369pairwise distances contracted by the factor `n / (n + 1)`. -/
1370theorem asub_support_bound :
1371    ∀ (n : ℕ) (w : Fin (n + 1) → stdSimplex ℝ (Fin (d + 1))) (D : ℝ), 0 ≤ D →
1372      (∀ i j, dist (w i) (w j) ≤ D) →
1373      ∀ u ∈ ((asub (baryFn d) n) (asimplex w)).support,
1374        (∀ i j, dist (u i) (u j) ≤ ((n : ℝ) / (n + 1)) * D) ∧
1375          ∀ i, ((u i : Fin (d + 1) → ℝ)) ∈ hullOf w
1376  | 0, w, D, hD, hw => by
1377      intro u hu
1378      rw [asub_zero, LinearMap.id_apply, asimplex] at hu
1379      have hmem := Finsupp.support_single_subset hu
1380      rw [Finset.mem_singleton] at hmem
1381      subst hmem
1382      refine ⟨fun i j => ?_, fun i => coe_mem_hullOf u i⟩
1383      have hij : i = j := Fin.ext (by omega)
1384      subst hij
1385      rw [dist_self]
1386      positivity
1387  | n + 1, w, D, hD, hw => by
1388      intro u hu
1389      rw [asub_asimplex] at hu
1390      obtain ⟨v, hv, huv⟩ := support_acone _ _ u hu
1391      subst huv
1392      have hmid : ∀ v' ∈ ((asub (baryFn d) n) (abnd n (asimplex w))).support,
1393          (∀ i j, dist (v' i) (v' j) ≤ ((n : ℝ) / (n + 1)) * D) ∧
1394            ∀ i, ((v' i : Fin (d + 1) → ℝ)) ∈ hullOf w := by
1395        refine support_transport _
1396          (P := fun v' => ∃ j : Fin (n + 2), v' = w ∘ j.succAbove) ?_ _
1397          (support_abnd_asimplex w)
1398        rintro v' ⟨j, rfl⟩ u' hu'
1399        obtain ⟨h1, h2⟩ := asub_support_bound n (w ∘ j.succAbove) D hD
1400          (fun i i' => hw _ _) u' hu'
1401        exact ⟨h1, fun i => hullOf_subset
1402          (fun i' => coe_mem_hullOf w (j.succAbove i')) (h2 i)⟩
1403      obtain ⟨h1, h2⟩ := hmid v hv
1404      have hr : ((n : ℝ) / (n + 1)) * D ≤ (((n + 1 : ℕ) : ℝ) / ((n + 1 : ℕ) + 1)) * D := by
1405        refine mul_le_mul_of_nonneg_right ?_ hD
1406        push_cast
1407        have h := ratio_mono n
1408        rwa [show ((n : ℝ) + 2) = ((n : ℝ) + 1 + 1) by ring] at h
1409      have happx : ∀ i' : Fin (n + 1),
1410          dist (baryFn d w) (v i') ≤ (((n + 1 : ℕ) : ℝ) / ((n + 1 : ℕ) + 1)) * D := by
1411        intro i'
1412        rw [baryFn_apply, Subtype.dist_eq]
1413        have hdist := dist_sbary_le (w := w) hw (h2 i')
1414        refine hdist.trans (le_of_eq ?_)
1415        push_cast
1416        ring
1417      refine ⟨fun i j => ?_, fun i => ?_⟩
1418      · refine Fin.cases ?_ (fun i' => ?_) i
1419        · refine Fin.cases ?_ (fun j' => ?_) j
1420          · rw [Fin.cons_zero, dist_self]
1421            positivity
1422          · rw [Fin.cons_zero, Fin.cons_succ]
1423            exact happx j'
1424        · refine Fin.cases ?_ (fun j' => ?_) j
1425          · rw [Fin.cons_succ, Fin.cons_zero, dist_comm]
1426            exact happx i'
1427          · rw [Fin.cons_succ, Fin.cons_succ]
1428            exact (h1 i' j').trans hr
1429      · refine Fin.cases ?_ (fun i' => ?_) i
1430        · rw [Fin.cons_zero, baryFn_apply]
1431          exact sbary_mem_hullOf w
1432        · rw [Fin.cons_succ]
1433          exact h2 i'
1434
1435/-- Iterated version: `k`-fold subdivision contracts pairwise distances by
1436`(n/(n+1))^k`, keeping all vertices in the hull of the original tuple. -/
1437theorem asubIter_support_bound (k : ℕ) :
1438    ∀ (n : ℕ) (w : Fin (n + 1) → stdSimplex ℝ (Fin (d + 1))) (D : ℝ), 0 ≤ D →
1439      (∀ i j, dist (w i) (w j) ≤ D) →
1440      ∀ u ∈ ((asubIter (baryFn d) k n) (asimplex w)).support,
1441        (∀ i j, dist (u i) (u j) ≤ ((n : ℝ) / (n + 1)) ^ k * D) ∧
1442          ∀ i, ((u i : Fin (d + 1) → ℝ)) ∈ hullOf w := by
1443  induction k with
1444  | zero =>
1445      intro n w D hD hw u hu
1446      rw [asubIter_zero, LinearMap.id_apply, asimplex] at hu
1447      have hmem := Finsupp.support_single_subset hu
1448      rw [Finset.mem_singleton] at hmem
1449      subst hmem
1450      exact ⟨fun i j => by rw [pow_zero, one_mul]; exact hw i j,
1451        fun i => coe_mem_hullOf u i⟩
1452  | succ k IH =>
1453      intro n w D hD hw u hu
1454      rw [asubIter_succ, LinearMap.comp_apply] at hu
1455      refine support_transport (asub (baryFn d) n)
1456        (P := fun v => (∀ i j, dist (v i) (v j) ≤ ((n : ℝ) / (n + 1)) ^ k * D) ∧
1457          ∀ i, ((v i : Fin (d + 1) → ℝ)) ∈ hullOf w)
1458        (Q := fun u => (∀ i j, dist (u i) (u j) ≤ ((n : ℝ) / (n + 1)) ^ (k + 1) * D) ∧
1459          ∀ i, ((u i : Fin (d + 1) → ℝ)) ∈ hullOf w) ?_ _
1460        (IH n w D hD hw) u hu
1461      rintro v ⟨hv1, hv2⟩ u' hu'
1462      obtain ⟨h1, h2⟩ := asub_support_bound n v (((n : ℝ) / (n + 1)) ^ k * D)
1463        (by positivity) hv1 u' hu'
1464      refine ⟨fun i j => ?_, fun i => hullOf_subset hv2 (h2 i)⟩
1465      calc dist (u' i) (u' j)
1466          ≤ ((n : ℝ) / (n + 1)) * (((n : ℝ) / (n + 1)) ^ k * D) := h1 i j
1467        _ = ((n : ℝ) / (n + 1)) ^ (k + 1) * D := by ring
1468
1469/-- Any two points of the standard simplex are at sup-distance `≤ 1`. -/
1470lemma stdSimplex_dist_le_one (x y : stdSimplex ℝ (Fin (d + 1))) : dist x y ≤ 1 := by
1471  rw [Subtype.dist_eq, dist_pi_le_iff zero_le_one]
1472  intro j
1473  rw [Real.dist_eq, abs_sub_le_iff]
1474  have hx := mem_Icc_of_mem_stdSimplex x.2 j
1475  have hy := mem_Icc_of_mem_stdSimplex y.2 j
1476  constructor
1477  · linarith [hx.2, hy.1]
1478  · linarith [hy.2, hx.1]
1479
1480/-- **Stage 6 payoff.** The pieces of the iterated barycentric subdivision of
1481any affine simplex in the standard simplex become uniformly small. -/
1482theorem exists_asubIter_small (n : ℕ) (w : Fin (n + 1) → stdSimplex ℝ (Fin (d + 1)))
1483    {ε : ℝ} (hε : 0 < ε) :
1484    ∃ k, ∀ u ∈ ((asubIter (baryFn d) k n) (asimplex w)).support,
1485      ∀ i j, dist (u i) (u j) < ε := by
1486  have hlt : ((n : ℝ) / (n + 1)) < 1 := by
1487    rw [div_lt_one (by positivity)]
1488    linarith
1489  obtain ⟨k, hk⟩ := exists_pow_lt_of_lt_one hε hlt
1490  refine ⟨k, fun u hu i j => ?_⟩
1491  have hbound := (asubIter_support_bound k n w 1 zero_le_one
1492    (fun i j => stdSimplex_dist_le_one _ _) u hu).1 i j
1493  calc dist (u i) (u j) ≤ ((n : ℝ) / (n + 1)) ^ k * 1 := hbound
1494    _ = ((n : ℝ) / (n + 1)) ^ k := mul_one _
1495    _ < ε := hk
1496
1497end Diameter
1498
1499/-! ## Stage 7: the small-simplices theorem
1500
1501For an open cover `U ∪ V = X` and a singular simplex `σ`, the Lebesgue
1502number of the preimage cover `σ⁻¹U, σ⁻¹V` of the compact metric `Δⁿ`
1503together with the stage 6 decay yields an iterate `k` of the singular
1504subdivision all of whose pieces land in `U` or in `V`.  By
1505`gen_comp_sdOpIter`, the pieces of `sdOpIter X n k` on the generator of `σ`
1506are exactly the `pushSimplex σ u` for `u` in the support of the iterated
1507affine subdivision of the identity tuple, so smallness is stated over that
1508support.  The chain-homotopy witness relating `sdOpIter X n k` to the
1509identity is `tOpIter_chain_homotopy_succ` / `tOpIter_chain_homotopy_zero`. -/
1510
1511section SmallSimplices
1512
1513open SingularPrism
1514
1515variable {X : TopCat.{0}}
1516
1517/-- The affine map of a tuple lands in the tuple's hull. -/
1518lemma affineMap_mem_hullOf {d m : ℕ} (u : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1)))
1519    (x : stdSimplex ℝ (Fin (m + 1))) :
1520    ((affineMap u x : Fin (d + 1) → ℝ)) ∈ hullOf u := by
1521  have hrep : ((affineMap u x : Fin (d + 1) → ℝ)) =
1522      ∑ i, x i • ((u i : Fin (d + 1) → ℝ)) := by
1523    funext j
1524    rw [Finset.sum_apply]
1525    simp only [Pi.smul_apply, smul_eq_mul]
1526    exact affineMap_apply_coe u x j
1527  rw [hrep]
1528  exact (convex_convexHull ℝ _).sum_mem (fun i _ => stdSimplex.zero_le x i)
1529    (stdSimplex.sum_eq_one x) (fun i _ => coe_mem_hullOf u i)
1530
1531/-- Every point of an affine piece is within the piece's vertex spread of
1532its zeroth vertex. -/
1533lemma dist_affineMap_le {d m : ℕ} {u : Fin (m + 1) → stdSimplex ℝ (Fin (d + 1))}
1534    {D : ℝ} (hu : ∀ i j, dist (u i) (u j) ≤ D) (x : stdSimplex ℝ (Fin (m + 1))) :
1535    dist (affineMap u x) (u 0) ≤ D :=
1536  dist_le_of_mem_hullOf hu (affineMap_mem_hullOf u x) (coe_mem_hullOf u 0)
1537
1538/-- **Stage 7: the small-simplices theorem.** For open sets `U, V` covering
1539`X` and any singular `n`-simplex `s`, there is an iterate `k` such that
1540every piece of `sdOpIter X n k` applied to the generator of `s` (i.e. every
1541`pushSimplex σ u` with `u` in the support of the iterated affine
1542subdivision, per `gen_comp_sdOpIter`) has range contained in `U` or in `V`. -/
1543theorem exists_sdOpIter_small {n : ℕ} (U V : Set X) (hU : IsOpen U) (hV : IsOpen V)
1544    (hUV : U ∪ V = Set.univ) (s : Idx X n) :
1545    ∃ k, ∀ u ∈ ((asubIter (baryFn n) k n) (asimplex (idTuple n))).support,
1546      Set.range ⇑(simplexEquiv X n (pushSimplex (simplexEquiv X n s) u)) ⊆ U ∨
1547        Set.range ⇑(simplexEquiv X n (pushSimplex (simplexEquiv X n s) u)) ⊆ V := by
1548  set σ := simplexEquiv X n s with hσ
1549  haveI : CompactSpace (stdSimplex ℝ (Fin (n + 1))) :=
1550    isCompact_iff_compactSpace.mp (isCompact_stdSimplex _)
1551  have hcover : (Set.univ : Set (stdSimplex ℝ (Fin (n + 1)))) ⊆
1552      ⋃ b : Bool, (if b then ⇑σ ⁻¹' U else ⇑σ ⁻¹' V) := by
1553    intro x _
1554    have hmem : σ x ∈ U ∪ V := by rw [hUV]; trivial
1555    rcases hmem with h | h
1556    · exact Set.mem_iUnion.mpr ⟨true, h⟩
1557    · exact Set.mem_iUnion.mpr ⟨false, h⟩
1558  have hopen : ∀ b : Bool, IsOpen (if b then ⇑σ ⁻¹' U else ⇑σ ⁻¹' V) := by
1559    intro b
1560    cases b
1561    · exact hV.preimage σ.continuous
1562    · exact hU.preimage σ.continuous
1563  obtain ⟨δ, hδ, hball⟩ := lebesgue_number_lemma_of_metric isCompact_univ hopen hcover
1564  obtain ⟨k, hk⟩ := exists_asubIter_small n (idTuple n) (half_pos hδ)
1565  refine ⟨k, fun u hu => ?_⟩
1566  obtain ⟨b, hb⟩ := hball (u 0) (Set.mem_univ _)
1567  have himg : Set.range ⇑(σ.comp (affineMap u)) ⊆
1568      (if b then U else V) := by
1569    rintro y ⟨x, rfl⟩
1570    have hdist : dist (affineMap u x) (u 0) < δ := by
1571      have hle := dist_affineMap_le (fun i j => (hk u hu i j).le) x
1572      linarith
1573    have hxball : affineMap u x ∈ Metric.ball (u 0) δ := Metric.mem_ball.mpr hdist
1574    have hpre := hb hxball
1575    cases b
1576    · exact hpre
1577    · exact hpre
1578  rw [simplexEquiv_pushSimplex]
1579  cases b
1580  · exact Or.inr himg
1581  · exact Or.inl himg
1582
1583end SmallSimplices
1584
1585end SingularSubdivision
1586end Foundation
1587end IndisputableMonolith
1588

source mirrored from github.com/jonwashburn/shape-of-logic