pith. machine review for the scientific record. sign in

IndisputableMonolith.Foundation.UniversalForcing.NaturalNumberObject

IndisputableMonolith/Foundation/UniversalForcing/NaturalNumberObject.lean · 302 lines · 10 declarations

show as:
view math explainer →

open module explainer GitHub source

Explainer status: pending

   1import IndisputableMonolith.Foundation.UniversalForcing
   2import IndisputableMonolith.Foundation.UniversalForcing.Strict.DiscreteBoolean
   3
   4/-!
   5  NaturalNumberObject.lean
   6
   7  Lawvere natural-number object characterization of the forced arithmetic.
   8
   9  This module makes precise the categorical sense in which the Law of Logic
  10  forces the natural numbers. The Lawvere characterization is:
  11  a triple `(N, z, s)` is a *natural-number object* if for every triple
  12  `(X, x, f)` with `x : X` and `f : X → X` there exists a unique map
  13  `h : N → X` satisfying `h z = x` and `h ∘ s = f ∘ h`.
  14
  15  This is the statement "ℕ is the initial pointed endomap algebra" and it is
  16  what "ℕ" means in any categorical foundation that does not presuppose ℕ.
  17
  18  We prove:
  19
  20  * `LogicNat` with `identity`/`step` is a natural-number object.
  21  * Every realization's forced arithmetic is a natural-number object.
  22  * Any two natural-number objects are canonically isomorphic.
  23  * The strict Boolean realization carrier collapses to the parity image
  24    `Nat.bodd ∘ toNat`, but the iteration object is unchanged.
  25
  26  The last point is the formal answer to the critic's worry: "you did not
  27  derive ℕ; you smuggled in iteration-counting." The iteration object is
  28  the natural-number object in the Lawvere sense, and it is the same in
  29  every realization, including the discrete Boolean one whose carrier
  30  contains only two elements.
  31-/
  32
  33namespace IndisputableMonolith
  34namespace Foundation
  35namespace UniversalForcing
  36
  37open ArithmeticFromLogic
  38
  39universe u
  40
  41/-! ## Lawvere natural-number object property -/
  42
  43/-- A triple `(N, z, s)` is a Lawvere natural-number object: for every
  44target pointed endomap `(X, x, f)`, primitive recursion exists and is unique.
  45
  46This characterization makes no reference to `Nat`. It is the universal
  47property that any Peano structure must satisfy. The field name `recursor`
  48avoids the reserved `rec` symbol used for auto-generated structure recursors. -/
  49structure IsNaturalNumberObject {N : Type u} (z : N) (s : N → N) where
  50  recursor : ∀ {X : Type u}, X → (X → X) → N → X
  51  recursor_zero : ∀ {X : Type u} (x : X) (f : X → X), recursor x f z = x
  52  recursor_step : ∀ {X : Type u} (x : X) (f : X → X) (n : N),
  53    recursor x f (s n) = f (recursor x f n)
  54  recursor_unique : ∀ {X : Type u} (x : X) (f : X → X) (h : N → X),
  55    h z = x → (∀ n, h (s n) = f (h n)) → ∀ n, h n = recursor x f n
  56
  57namespace IsNaturalNumberObject
  58
  59variable {N : Type u} {z : N} {s : N → N}
  60
  61/-- The Peano object carried by a natural-number object. -/
  62def toPeano (_h : IsNaturalNumberObject z s) : PeanoObject where
  63  carrier := N
  64  zero := z
  65  step := s
  66
  67/-- Initiality of an NNO in the category of pointed endomap algebras. -/
  68def isInitial (h : IsNaturalNumberObject z s) :
  69    PeanoObject.IsInitial (toPeano h) where
  70  lift := fun B =>
  71    { toFun := h.recursor B.zero B.step
  72      map_zero := h.recursor_zero B.zero B.step
  73      map_step := fun n => h.recursor_step B.zero B.step n }
  74  uniq := by
  75    intro B f g
  76    funext n
  77    have hf := h.recursor_unique B.zero B.step f.toFun f.map_zero f.map_step n
  78    have hg := h.recursor_unique B.zero B.step g.toFun g.map_zero g.map_step n
  79    rw [hf, hg]
  80
  81end IsNaturalNumberObject
  82
  83/-! ## `LogicNat` is a natural-number object -/
  84
  85/-- `LogicNat` with `identity` and `step` is a Lawvere natural-number object. -/
  86def logicNat_isNNO :
  87    IsNaturalNumberObject (N := LogicNat) LogicNat.identity LogicNat.step where
  88  recursor := fun {X} x f => ArithmeticOf.logicNatFold ⟨X, x, f⟩
  89  recursor_zero := fun _ _ => rfl
  90  recursor_step := fun _ _ _ => rfl
  91  recursor_unique := by
  92    intro X x f h hz hs n
  93    induction n with
  94    | identity => exact hz
  95    | step n ih =>
  96        calc
  97          h (LogicNat.step n) = f (h n) := hs n
  98          _ = f (ArithmeticOf.logicNatFold ⟨X, x, f⟩ n) := by rw [ih]
  99          _ = ArithmeticOf.logicNatFold ⟨X, x, f⟩ (LogicNat.step n) := rfl
 100
 101/-! ## Forced arithmetic of every realization is a natural-number object -/
 102
 103/-- The natural-number object structure on a realization's iteration orbit.
 104Provided by transport from `LogicNat` through the realization's certified
 105orbit equivalence. The universe of the NNO is the carrier universe of the
 106realization. -/
 107noncomputable def realizationOrbit_isNNO.{u₁, v₁} (R : LogicRealization.{u₁, v₁}) :
 108    IsNaturalNumberObject (N := R.Orbit) R.orbitZero R.orbitStep where
 109  recursor := fun {X} x f n =>
 110    @ArithmeticOf.logicNatFold.{u₁} ⟨X, x, f⟩ (R.orbitEquivLogicNat n)
 111  recursor_zero := fun {X} x f => by
 112    show @ArithmeticOf.logicNatFold.{u₁} ⟨X, x, f⟩ (R.orbitEquivLogicNat R.orbitZero) = x
 113    rw [R.orbitEquiv_zero]
 114    rfl
 115  recursor_step := fun {X} x f n => by
 116    show @ArithmeticOf.logicNatFold.{u₁} ⟨X, x, f⟩ (R.orbitEquivLogicNat (R.orbitStep n)) =
 117      f (@ArithmeticOf.logicNatFold.{u₁} ⟨X, x, f⟩ (R.orbitEquivLogicNat n))
 118    rw [R.orbitEquiv_step]
 119    rfl
 120  recursor_unique := by
 121    intro X x f h hz hs n
 122    have hlogic_zero :
 123        (h ∘ R.orbitEquivLogicNat.symm) LogicNat.zero = x := by
 124      simp only [Function.comp_apply]
 125      have hsymm0 : R.orbitEquivLogicNat.symm LogicNat.zero = R.orbitZero := by
 126        apply R.orbitEquivLogicNat.injective
 127        simp [R.orbitEquiv_zero]
 128      rw [hsymm0]
 129      exact hz
 130    have hlogic_step : ∀ k,
 131        (h ∘ R.orbitEquivLogicNat.symm) (LogicNat.step k) =
 132          f ((h ∘ R.orbitEquivLogicNat.symm) k) := by
 133      intro k
 134      simp only [Function.comp_apply]
 135      have hsymm_step :
 136          R.orbitEquivLogicNat.symm (LogicNat.step k) =
 137            R.orbitStep (R.orbitEquivLogicNat.symm k) := by
 138        apply R.orbitEquivLogicNat.injective
 139        rw [R.orbitEquiv_step]
 140        simp
 141      rw [hsymm_step]
 142      exact hs (R.orbitEquivLogicNat.symm k)
 143    have huniq :
 144        ∀ k, (h ∘ R.orbitEquivLogicNat.symm) k =
 145          @ArithmeticOf.logicNatFold.{u₁} ⟨X, x, f⟩ k := by
 146      intro k
 147      induction k with
 148      | identity => exact hlogic_zero
 149      | step k ih =>
 150          calc
 151            (h ∘ R.orbitEquivLogicNat.symm) (LogicNat.step k)
 152                = f ((h ∘ R.orbitEquivLogicNat.symm) k) := hlogic_step k
 153            _ = f (@ArithmeticOf.logicNatFold.{u₁} ⟨X, x, f⟩ k) := by rw [ih]
 154            _ = @ArithmeticOf.logicNatFold.{u₁} ⟨X, x, f⟩ (LogicNat.step k) := rfl
 155    have hh : h n = (h ∘ R.orbitEquivLogicNat.symm) (R.orbitEquivLogicNat n) := by
 156      simp [Function.comp_apply]
 157    rw [hh, huniq]
 158
 159/-- Convenience alias: the forced arithmetic of every realization is a Lawvere
 160natural-number object. The forced arithmetic is by definition the realization
 161orbit, so this is the same statement as `realizationOrbit_isNNO`. -/
 162noncomputable def forcedArithmetic_isNNO.{u₁, v₁} (R : LogicRealization.{u₁, v₁}) :
 163    IsNaturalNumberObject
 164      (N := (arithmeticOf R).peano.carrier)
 165      (arithmeticOf R).peano.zero
 166      (arithmeticOf R).peano.step :=
 167  realizationOrbit_isNNO R
 168
 169/-! ## Uniqueness up to canonical isomorphism -/
 170
 171/-- Any two natural-number objects are canonically equivalent. This is the
 172Lawvere statement that the natural-number object is unique up to unique
 173isomorphism. -/
 174def IsNaturalNumberObject.equiv
 175    {N₁ N₂ : Type u} {z₁ : N₁} {s₁ : N₁ → N₁} {z₂ : N₂} {s₂ : N₂ → N₂}
 176    (h₁ : IsNaturalNumberObject z₁ s₁) (h₂ : IsNaturalNumberObject z₂ s₂) :
 177    N₁ ≃ N₂ where
 178  toFun := h₁.recursor z₂ s₂
 179  invFun := h₂.recursor z₁ s₁
 180  left_inv := by
 181    intro n
 182    have hcomp_zero : (h₂.recursor z₁ s₁) ((h₁.recursor z₂ s₂) z₁) = z₁ := by
 183      rw [h₁.recursor_zero, h₂.recursor_zero]
 184    have hcomp_step : ∀ k,
 185        (h₂.recursor z₁ s₁) ((h₁.recursor z₂ s₂) (s₁ k)) =
 186          s₁ ((h₂.recursor z₁ s₁) ((h₁.recursor z₂ s₂) k)) := by
 187      intro k
 188      rw [h₁.recursor_step, h₂.recursor_step]
 189    have hid_zero : (id : N₁ → N₁) z₁ = z₁ := rfl
 190    have hid_step : ∀ k, (id : N₁ → N₁) (s₁ k) = s₁ ((id : N₁ → N₁) k) := by
 191      intro k; rfl
 192    have huniq_id := h₁.recursor_unique z₁ s₁ id hid_zero hid_step n
 193    have huniq_comp := h₁.recursor_unique z₁ s₁
 194      (fun k => (h₂.recursor z₁ s₁) ((h₁.recursor z₂ s₂) k))
 195      hcomp_zero hcomp_step n
 196    rw [huniq_comp]
 197    exact huniq_id.symm
 198  right_inv := by
 199    intro n
 200    have hcomp_zero : (h₁.recursor z₂ s₂) ((h₂.recursor z₁ s₁) z₂) = z₂ := by
 201      rw [h₂.recursor_zero, h₁.recursor_zero]
 202    have hcomp_step : ∀ k,
 203        (h₁.recursor z₂ s₂) ((h₂.recursor z₁ s₁) (s₂ k)) =
 204          s₂ ((h₁.recursor z₂ s₂) ((h₂.recursor z₁ s₁) k)) := by
 205      intro k
 206      rw [h₂.recursor_step, h₁.recursor_step]
 207    have hid_zero : (id : N₂ → N₂) z₂ = z₂ := rfl
 208    have hid_step : ∀ k, (id : N₂ → N₂) (s₂ k) = s₂ ((id : N₂ → N₂) k) := by
 209      intro k; rfl
 210    have huniq_id := h₂.recursor_unique z₂ s₂ id hid_zero hid_step n
 211    have huniq_comp := h₂.recursor_unique z₂ s₂
 212      (fun k => (h₁.recursor z₂ s₂) ((h₂.recursor z₁ s₁) k))
 213      hcomp_zero hcomp_step n
 214    rw [huniq_comp]
 215    exact huniq_id.symm
 216
 217/-- The forced arithmetic of every realization is canonically equivalent to
 218`LogicNat`. This is the Universal Forcing statement at the natural-number
 219object level: every Law-of-Logic realization carries the same NNO. -/
 220noncomputable def realizationOrbit_equiv_logicNat (R : LogicRealization.{0, 0}) :
 221    R.Orbit ≃ LogicNat :=
 222  IsNaturalNumberObject.equiv (realizationOrbit_isNNO R) logicNat_isNNO
 223
 224/-- The Lawvere universality statement: any two realizations have iteration
 225orbits that satisfy the natural-number-object property, hence are
 226canonically equivalent. -/
 227noncomputable def universal_forcing_via_NNO
 228    (R S : LogicRealization.{0, 0}) : R.Orbit ≃ S.Orbit :=
 229  IsNaturalNumberObject.equiv (realizationOrbit_isNNO R) (realizationOrbit_isNNO S)
 230
 231/-! ## The Boolean parity-collapse theorem
 232
 233The discrete Boolean realization is the sharpest test of the iteration-object
 234versus orbit-as-set distinction. The carrier `Bool` has only two elements,
 235and the strict realization's `interpret : LogicNat → Bool` collapses
 236infinitely many iteration steps onto two values. The iteration object
 237itself never collapses; it is `LogicNat`, the natural-number object.
 238
 239The theorem below makes the collapse explicit: the Boolean interpretation
 240is exactly the parity map `Nat.bodd ∘ toNat`. -/
 241
 242namespace Strict.DiscreteBoolean
 243
 244open IndisputableMonolith.Foundation.UniversalForcing.Strict
 245
 246/-- One step of the Boolean strict realization is `xor true _`, which is
 247boolean negation. -/
 248private theorem xorBool_true (b : Bool) : xorBool true b = !b := by
 249  cases b <;> rfl
 250
 251/-- The Boolean strict-realization interpretation is the parity map.
 252
 253This is the formal statement that the iteration count survives even when
 254the orbit-as-set collapses to `{false, true}`. -/
 255theorem interpret_eq_parity (n : LogicNat) :
 256    StrictLogicRealization.interpret strictBooleanRealization n =
 257      Nat.bodd (LogicNat.toNat n) := by
 258  induction n with
 259  | identity => rfl
 260  | step n ih =>
 261      show xorBool true (StrictLogicRealization.interpret strictBooleanRealization n) =
 262        Nat.bodd (Nat.succ (LogicNat.toNat n))
 263      rw [xorBool_true, ih, Nat.bodd_succ]
 264
 265/-- Even though the carrier image collapses, the iteration object is the
 266full `LogicNat`. Concretely: the interpretation map is not injective. -/
 267theorem interpret_collapses :
 268    ¬ Function.Injective
 269      (StrictLogicRealization.interpret strictBooleanRealization) := by
 270  intro hinj
 271  have h0 :
 272      StrictLogicRealization.interpret strictBooleanRealization LogicNat.identity =
 273        Nat.bodd 0 := interpret_eq_parity _
 274  have h2 :
 275      StrictLogicRealization.interpret strictBooleanRealization
 276        (LogicNat.step (LogicNat.step LogicNat.identity)) =
 277          Nat.bodd 2 := interpret_eq_parity _
 278  have hbodd : (Nat.bodd 0 : Bool) = Nat.bodd 2 := by decide
 279  have hboth :
 280      StrictLogicRealization.interpret strictBooleanRealization LogicNat.identity =
 281        StrictLogicRealization.interpret strictBooleanRealization
 282          (LogicNat.step (LogicNat.step LogicNat.identity)) := by
 283    rw [h0, h2, hbodd]
 284  have hne : LogicNat.identity ≠ LogicNat.step (LogicNat.step LogicNat.identity) :=
 285    LogicNat.zero_ne_succ _
 286  exact hne (hinj hboth)
 287
 288/-- Despite the carrier collapse, the iteration object is itself a
 289natural-number object — the same one as in the continuous positive-ratio
 290realization. -/
 291def boolean_freeOrbit_isNNO :
 292    IsNaturalNumberObject
 293      (N := StrictLogicRealization.FreeOrbit strictBooleanRealization)
 294      LogicNat.identity LogicNat.step :=
 295  logicNat_isNNO
 296
 297end Strict.DiscreteBoolean
 298
 299end UniversalForcing
 300end Foundation
 301end IndisputableMonolith
 302

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