File: Mathlib/SetTheory/Ordinal/Notation.lean

full_name: ONote.oadd
code: /-- Recursive definition of an ordinal notation. `zero` denotes the
  ordinal 0, and `oadd e n a` is intended to refer to `ω^e * n + a`.
  For this to be valid Cantor normal form, we must have the exponents
  decrease to the right, but we can't state this condition until we've
  defined `repr`, so it is a separate definition `NF`. -/
inductive ONote : Type
  | zero : ONote
  | oadd : ONote → ℕ+ → ONote → ONote
  deriving DecidableEq
goal: ONote → ℕ+ → ONote → ONote

full_name: ONote.zero
code: /-- Recursive definition of an ordinal notation. `zero` denotes the
  ordinal 0, and `oadd e n a` is intended to refer to `ω^e * n + a`.
  For this to be valid Cantor normal form, we must have the exponents
  decrease to the right, but we can't state this condition until we've
  defined `repr`, so it is a separate definition `NF`. -/
inductive ONote : Type
  | zero : ONote
  | oadd : ONote → ℕ+ → ONote → ONote
  deriving DecidableEq
goal: ONote

full_name: ONote
code: /-- Recursive definition of an ordinal notation. `zero` denotes the
  ordinal 0, and `oadd e n a` is intended to refer to `ω^e * n + a`.
  For this to be valid Cantor normal form, we must have the exponents
  decrease to the right, but we can't state this condition until we've
  defined `repr`, so it is a separate definition `NF`. -/
inductive ONote : Type
  | zero : ONote
  | oadd : ONote → ℕ+ → ONote → ONote
  deriving DecidableEq
goal: Type

full_name: ONote.instZero
code: /-- Notation for 0 -/
instance : Zero ONote 
goal: Zero ONote

full_name: ONote.zero_def
code: @[simp]
theorem zero_def : zero = 0 
goal: ONote.zero = 0

full_name: ONote.instInhabited
code: instance : Inhabited ONote 
goal: Inhabited ONote

full_name: ONote.instOne
code: /-- Notation for 1 -/
instance : One ONote 
goal: One ONote

full_name: ONote.omega
code: /-- Notation for ω -/
def omega : ONote 
goal: ONote

full_name: ONote.repr
code: /-- The ordinal denoted by a notation -/
@[simp]
noncomputable def repr : ONote → Ordinal.{0}
  
goal: ONote → Ordinal.{0}

full_name: ONote.toStringAux1
code: /-- Auxiliary definition to print an ordinal notation -/
def toStringAux1 (e : ONote) (n : ℕ) (s : String) : String 
goal: String

full_name: ONote.toString
code: /-- Print an ordinal notation -/
def toString : ONote → String
  
goal: ONote → String

full_name: ONote.repr'
code: /-- Print an ordinal notation -/
def repr' (prec : ℕ) : ONote → Format
  
goal: ONote → Lean.Format

full_name: ONote.instToString
code: instance : ToString ONote 
goal: ToString ONote

full_name: ONote.instRepr
code: instance : Repr ONote 
goal: Repr ONote

full_name: ONote.instPreorder
code: instance : Preorder ONote 
goal: Preorder ONote

full_name: ONote.lt_def
code: theorem lt_def {x y : ONote} : x < y ↔ repr x < repr y 
goal: x < y ↔ x.repr < y.repr

full_name: ONote.le_def
code: theorem le_def {x y : ONote} : x ≤ y ↔ repr x ≤ repr y 
goal: x ≤ y ↔ x.repr ≤ y.repr

full_name: ONote.instWellFoundedRelation
code: instance : WellFoundedRelation ONote 
goal: WellFoundedRelation ONote

full_name: ONote.ofNat
code: /-- Convert a `Nat` into an ordinal -/
@[coe]
def ofNat : ℕ → ONote
  
goal: ℕ → ONote

full_name: ONote.ofNat_zero
code: @[simp] theorem ofNat_zero : ofNat 0 = 0 
goal: ↑0 = 0

full_name: ONote.ofNat_succ
code: @[simp] theorem ofNat_succ (n) : ofNat (Nat.succ n) = oadd 0 n.succPNat 0 
goal: ↑n.succ = ONote.oadd 0 n.succPNat 0

full_name: ONote.nat
code: instance nat (n : ℕ) : OfNat ONote n 
goal: OfNat ONote n

full_name: ONote.ofNat_one
code: @[simp 1200]
theorem ofNat_one : ofNat 1 = 1 
goal: ↑1 = 1

full_name: ONote.repr_ofNat
code: @[simp]
theorem repr_ofNat (n : ℕ) : repr (ofNat n) = n 
goal: (↑n).repr = ↑n

full_name: ONote.repr_one
code: theorem repr_one : repr (ofNat 1) = (1 : ℕ) 
goal: (↑1).repr = ↑1

full_name: ONote.omega_le_oadd
code: theorem omega_le_oadd (e n a) : ω ^ repr e ≤ repr (oadd e n a) 
goal: ω ^ e.repr ≤ (e.oadd n a).repr

full_name: ONote.oadd_pos
code: theorem oadd_pos (e n a) : 0 < oadd e n a 
goal: 0 < e.oadd n a

full_name: ONote.cmp
code: /-- Compare ordinal notations -/
def cmp : ONote → ONote → Ordering
  
goal: ONote → ONote → Ordering

full_name: ONote.eq_of_cmp_eq
code: theorem eq_of_cmp_eq : ∀ {o₁ o₂}, cmp o₁ o₂ = Ordering.eq → o₁ = o₂
  
goal: o₁.cmp o₂ = Ordering.eq → o₁ = o₂

full_name: ONote.zero_lt_one
code: protected theorem zero_lt_one : (0 : ONote) < 1 
goal: 0 < 1

full_name: ONote.NFBelow.oadd'
code: /-- `NFBelow o b` says that `o` is a normal form ordinal notation
  satisfying `repr o < ω ^ b`. -/
inductive NFBelow : ONote → Ordinal.{0} → Prop
  | zero {b} : NFBelow 0 b
  | oadd' {e n a eb b} : NFBelow e eb → NFBelow a (repr e) → repr e < b → NFBelow (oadd e n a) b
goal: e.NFBelow eb → a.NFBelow e.repr → e.repr < b → (e.oadd n a).NFBelow b

full_name: ONote.NFBelow.zero
code: /-- `NFBelow o b` says that `o` is a normal form ordinal notation
  satisfying `repr o < ω ^ b`. -/
inductive NFBelow : ONote → Ordinal.{0} → Prop
  | zero {b} : NFBelow 0 b
  | oadd' {e n a eb b} : NFBelow e eb → NFBelow a (repr e) → repr e < b → NFBelow (oadd e n a) b
goal: ONote.NFBelow 0 b

full_name: ONote.NFBelow
code: /-- `NFBelow o b` says that `o` is a normal form ordinal notation
  satisfying `repr o < ω ^ b`. -/
inductive NFBelow : ONote → Ordinal.{0} → Prop
  | zero {b} : NFBelow 0 b
  | oadd' {e n a eb b} : NFBelow e eb → NFBelow a (repr e) → repr e < b → NFBelow (oadd e n a) b
goal: ONote → Ordinal.{0} → Prop

full_name: ONote.NF.out
code: /-- A normal form ordinal notation has the form

     ω ^ a₁ * n₁ + ω ^ a₂ * n₂ + ... ω ^ aₖ * nₖ
  where `a₁ > a₂ > ... > aₖ` and all the `aᵢ` are
  also in normal form.

  We will essentially only be interested in normal form
  ordinal notations, but to avoid complicating the algorithms
  we define everything over general ordinal notations and
  only prove correctness with normal form as an invariant. -/
class NF (o : ONote) : Prop where
  out : Exists (NFBelow o)
goal: Exists o.NFBelow

full_name: ONote.NF
code: /-- A normal form ordinal notation has the form

     ω ^ a₁ * n₁ + ω ^ a₂ * n₂ + ... ω ^ aₖ * nₖ
  where `a₁ > a₂ > ... > aₖ` and all the `aᵢ` are
  also in normal form.

  We will essentially only be interested in normal form
  ordinal notations, but to avoid complicating the algorithms
  we define everything over general ordinal notations and
  only prove correctness with normal form as an invariant. -/
class NF (o : ONote) : Prop where
  out : Exists (NFBelow o)
goal: Prop

full_name: ONote.NF.zero
code: instance NF.zero : NF 0 
goal: ONote.NF 0

full_name: ONote.NFBelow.oadd
code: theorem NFBelow.oadd {e n a b} : NF e → NFBelow a (repr e) → repr e < b → NFBelow (oadd e n a) b
  
goal: e.NF → a.NFBelow e.repr → e.repr < b → (e.oadd n a).NFBelow b

full_name: ONote.NFBelow.fst
code: theorem NFBelow.fst {e n a b} (h : NFBelow (ONote.oadd e n a) b) : NF e 
goal: e.NF

full_name: ONote.NF.fst
code: theorem NF.fst {e n a} : NF (oadd e n a) → NF e
  
goal: (e.oadd n a).NF → e.NF

full_name: ONote.NFBelow.snd
code: theorem NFBelow.snd {e n a b} (h : NFBelow (ONote.oadd e n a) b) : NFBelow a (repr e) 
goal: a.NFBelow e.repr

full_name: ONote.NF.snd'
code: theorem NF.snd' {e n a} : NF (oadd e n a) → NFBelow a (repr e)
  
goal: (e.oadd n a).NF → a.NFBelow e.repr

full_name: ONote.NF.snd
code: theorem NF.snd {e n a} (h : NF (oadd e n a)) : NF a 
goal: a.NF

full_name: ONote.NF.oadd
code: theorem NF.oadd {e a} (h₁ : NF e) (n) (h₂ : NFBelow a (repr e)) : NF (oadd e n a) 
goal: (e.oadd n a).NF

full_name: ONote.NF.oadd_zero
code: instance NF.oadd_zero (e n) [h : NF e] : NF (ONote.oadd e n 0) 
goal: (e.oadd n 0).NF

full_name: ONote.NFBelow.lt
code: theorem NFBelow.lt {e n a b} (h : NFBelow (ONote.oadd e n a) b) : repr e < b 
goal: e.repr < b

full_name: ONote.NFBelow_zero
code: theorem NFBelow_zero : ∀ {o}, NFBelow o 0 ↔ o = 0
  
goal: o.NFBelow 0 ↔ o = 0

full_name: ONote.NF.zero_of_zero
code: theorem NF.zero_of_zero {e n a} (h : NF (ONote.oadd e n a)) (e0 : e = 0) : a = 0 
goal: a = 0

full_name: ONote.NFBelow.repr_lt
code: theorem NFBelow.repr_lt {o b} (h : NFBelow o b) : repr o < ω ^ b 
goal: o.repr < ω ^ b

full_name: ONote.NFBelow.mono
code: theorem NFBelow.mono {o b₁ b₂} (bb : b₁ ≤ b₂) (h : NFBelow o b₁) : NFBelow o b₂ 
goal: o.NFBelow b₂

full_name: ONote.NF.below_of_lt
code: theorem NF.below_of_lt {e n a b} (H : repr e < b) :
    NF (ONote.oadd e n a) → NFBelow (ONote.oadd e n a) b
  
goal: (e.oadd n a).NF → (e.oadd n a).NFBelow b

full_name: ONote.NF.below_of_lt'
code: theorem NF.below_of_lt' : ∀ {o b}, repr o < ω ^ b → NF o → NFBelow o b
  
goal: o.repr < ω ^ b → o.NF → o.NFBelow b

full_name: ONote.nfBelow_ofNat
code: theorem nfBelow_ofNat : ∀ n, NFBelow (ofNat n) 1
  
goal: (↑n).NFBelow 1

full_name: ONote.nf_ofNat
code: instance nf_ofNat (n) : NF (ofNat n) 
goal: (↑n).NF

full_name: ONote.nf_one
code: instance nf_one : NF 1 
goal: ONote.NF 1

full_name: ONote.oadd_lt_oadd_1
code: theorem oadd_lt_oadd_1 {e₁ n₁ o₁ e₂ n₂ o₂} (h₁ : NF (oadd e₁ n₁ o₁)) (h : e₁ < e₂) :
    oadd e₁ n₁ o₁ < oadd e₂ n₂ o₂ 
goal: e₁.oadd n₁ o₁ < e₂.oadd n₂ o₂

full_name: ONote.oadd_lt_oadd_2
code: theorem oadd_lt_oadd_2 {e o₁ o₂ : ONote} {n₁ n₂ : ℕ+} (h₁ : NF (oadd e n₁ o₁)) (h : (n₁ : ℕ) < n₂) :
    oadd e n₁ o₁ < oadd e n₂ o₂ 
goal: e.oadd n₁ o₁ < e.oadd n₂ o₂

full_name: ONote.oadd_lt_oadd_3
code: theorem oadd_lt_oadd_3 {e n a₁ a₂} (h : a₁ < a₂) : oadd e n a₁ < oadd e n a₂ 
goal: e.oadd n a₁ < e.oadd n a₂

full_name: ONote.cmp_compares
code: theorem cmp_compares : ∀ (a b : ONote) [NF a] [NF b], (cmp a b).Compares a b
  
goal: (a.cmp b).Compares a b

full_name: ONote.repr_inj
code: theorem repr_inj {a b} [NF a] [NF b] : repr a = repr b ↔ a = b 
goal: a.repr = b.repr ↔ a = b

full_name: ONote.NF.of_dvd_omega_opow
code: theorem NF.of_dvd_omega_opow {b e n a} (h : NF (ONote.oadd e n a))
    (d : ω ^ b ∣ repr (ONote.oadd e n a)) :
    b ≤ repr e ∧ ω ^ b ∣ repr a 
goal: b ≤ e.repr ∧ ω ^ b ∣ a.repr

full_name: ONote.NF.of_dvd_omega
code: theorem NF.of_dvd_omega {e n a} (h : NF (ONote.oadd e n a)) :
    ω ∣ repr (ONote.oadd e n a) → repr e ≠ 0 ∧ ω ∣ repr a 
goal: ω ∣ (e.oadd n a).repr → e.repr ≠ 0 ∧ ω ∣ a.repr

full_name: ONote.TopBelow
code: /-- `TopBelow b o` asserts that the largest exponent in `o`, if
  it exists, is less than `b`. This is an auxiliary definition
  for decidability of `NF`. -/
def TopBelow (b : ONote) : ONote → Prop
  
goal: ONote → Prop

full_name: ONote.decidableTopBelow
code: instance decidableTopBelow : DecidableRel TopBelow 
goal: DecidableRel ONote.TopBelow

full_name: ONote.nfBelow_iff_topBelow
code: theorem nfBelow_iff_topBelow {b} [NF b] : ∀ {o}, NFBelow o (repr b) ↔ NF o ∧ TopBelow b o
  
goal: o.NFBelow b.repr ↔ o.NF ∧ b.TopBelow o

full_name: ONote.decidableNF
code: instance decidableNF : DecidablePred NF
  
goal: DecidablePred ONote.NF

full_name: ONote.addAux
code: /-- Auxiliary definition for `add` -/
def addAux (e : ONote) (n : ℕ+) (o : ONote) : ONote 
goal: ONote

full_name: ONote.add
code: /-- Addition of ordinal notations (correct only for normal input) -/
def add : ONote → ONote → ONote
  
goal: ONote → ONote → ONote

full_name: ONote.instAdd
code: instance : Add ONote 
goal: Add ONote

full_name: ONote.zero_add
code: @[simp]
theorem zero_add (o : ONote) : 0 + o = o 
goal: 0 + o = o

full_name: ONote.oadd_add
code: theorem oadd_add (e n a o) : oadd e n a + o = addAux e n (a + o) 
goal: e.oadd n a + o = e.addAux n (a + o)

full_name: ONote.sub
code: /-- Subtraction of ordinal notations (correct only for normal input) -/
def sub : ONote → ONote → ONote
  
goal: ONote → ONote → ONote

full_name: ONote.instSub
code: instance : Sub ONote 
goal: Sub ONote

full_name: ONote.add_nfBelow
code: theorem add_nfBelow {b} : ∀ {o₁ o₂}, NFBelow o₁ b → NFBelow o₂ b → NFBelow (o₁ + o₂) b
  
goal: o₁.NFBelow b → o₂.NFBelow b → (o₁ + o₂).NFBelow b

full_name: ONote.add_nf
code: instance add_nf (o₁ o₂) : ∀ [NF o₁] [NF o₂], NF (o₁ + o₂)
  
goal: (o₁ + o₂).NF

full_name: ONote.repr_add
code: @[simp]
theorem repr_add : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ + o₂) = repr o₁ + repr o₂
  
goal: (o₁ + o₂).repr = o₁.repr + o₂.repr

full_name: ONote.sub_nfBelow
code: theorem sub_nfBelow : ∀ {o₁ o₂ b}, NFBelow o₁ b → NF o₂ → NFBelow (o₁ - o₂) b
  
goal: o₁.NFBelow b → o₂.NF → (o₁ - o₂).NFBelow b

full_name: ONote.sub_nf
code: instance sub_nf (o₁ o₂) : ∀ [NF o₁] [NF o₂], NF (o₁ - o₂)
  
goal: (o₁ - o₂).NF

full_name: ONote.repr_sub
code: @[simp]
theorem repr_sub : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ - o₂) = repr o₁ - repr o₂
  
goal: (o₁ - o₂).repr = o₁.repr - o₂.repr

full_name: ONote.mul
code: /-- Multiplication of ordinal notations (correct only for normal input) -/
def mul : ONote → ONote → ONote
  
goal: ONote → ONote → ONote

full_name: ONote.instMul
code: instance : Mul ONote 
goal: Mul ONote

full_name: ONote.instMulZeroClass
code: instance : MulZeroClass ONote 
goal: MulZeroClass ONote

full_name: ONote.oadd_mul
code: theorem oadd_mul (e₁ n₁ a₁ e₂ n₂ a₂) :
    oadd e₁ n₁ a₁ * oadd e₂ n₂ a₂ =
      if e₂ = 0 then oadd e₁ (n₁ * n₂) a₁ else oadd (e₁ + e₂) n₂ (oadd e₁ n₁ a₁ * a₂) 
goal: e₁.oadd n₁ a₁ * e₂.oadd n₂ a₂ = if e₂ = 0 then e₁.oadd (n₁ * n₂) a₁ else (e₁ + e₂).oadd n₂ (e₁.oadd n₁ a₁ * a₂)

full_name: ONote.oadd_mul_nfBelow
code: theorem oadd_mul_nfBelow {e₁ n₁ a₁ b₁} (h₁ : NFBelow (oadd e₁ n₁ a₁) b₁) :
    ∀ {o₂ b₂}, NFBelow o₂ b₂ → NFBelow (oadd e₁ n₁ a₁ * o₂) (repr e₁ + b₂)
  
goal: o₂.NFBelow b₂ → (e₁.oadd n₁ a₁ * o₂).NFBelow (e₁.repr + b₂)

full_name: ONote.mul_nf
code: instance mul_nf : ∀ (o₁ o₂) [NF o₁] [NF o₂], NF (o₁ * o₂)
  
goal: (o₁ * o₂).NF

full_name: ONote.repr_mul
code: @[simp]
theorem repr_mul : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ * o₂) = repr o₁ * repr o₂
  
goal: (o₁ * o₂).repr = o₁.repr * o₂.repr

full_name: ONote.split'
code: /-- Calculate division and remainder of `o` mod ω.
  `split' o = (a, n)` means `o = ω * a + n`. -/
def split' : ONote → ONote × ℕ
  
goal: ONote → ONote × ℕ

full_name: ONote.split
code: /-- Calculate division and remainder of `o` mod ω.
  `split o = (a, n)` means `o = a + n`, where `ω ∣ a`. -/
def split : ONote → ONote × ℕ
  
goal: ONote → ONote × ℕ

full_name: ONote.scale
code: /-- `scale x o` is the ordinal notation for `ω ^ x * o`. -/
def scale (x : ONote) : ONote → ONote
  
goal: ONote → ONote

full_name: ONote.mulNat
code: /-- `mulNat o n` is the ordinal notation for `o * n`. -/
def mulNat : ONote → ℕ → ONote
  
goal: ONote → ℕ → ONote

full_name: ONote.opowAux
code: /-- Auxiliary definition to compute the ordinal notation for the ordinal
exponentiation in `opow` -/
def opowAux (e a0 a : ONote) : ℕ → ℕ → ONote
  
goal: ℕ → ℕ → ONote

full_name: ONote.opowAux2
code: /-- Auxiliary definition to compute the ordinal notation for the ordinal
exponentiation in `opow` -/
def opowAux2 (o₂ : ONote) (o₁ : ONote × ℕ) : ONote 
goal: ONote

full_name: ONote.opow
code: /-- `opow o₁ o₂` calculates the ordinal notation for
  the ordinal exponential `o₁ ^ o₂`. -/
def opow (o₁ o₂ : ONote) : ONote 
goal: ONote

full_name: ONote.instPow
code: instance : Pow ONote ONote 
goal: Pow ONote ONote

full_name: ONote.opow_def
code: theorem opow_def (o₁ o₂ : ONote) : o₁ ^ o₂ = opowAux2 o₂ (split o₁) 
goal: o₁ ^ o₂ = o₂.opowAux2 o₁.split

full_name: ONote.split_eq_scale_split'
code: theorem split_eq_scale_split' : ∀ {o o' m} [NF o], split' o = (o', m) → split o = (scale 1 o', m)
  
goal: o.split' = (o', m) → o.split = (ONote.scale 1 o', m)

full_name: ONote.nf_repr_split'
code: theorem nf_repr_split' : ∀ {o o' m} [NF o], split' o = (o', m) → NF o' ∧ repr o = ω * repr o' + m
  
goal: o.split' = (o', m) → o'.NF ∧ o.repr = ω * o'.repr + ↑m

full_name: ONote.scale_eq_mul
code: theorem scale_eq_mul (x) [NF x] : ∀ (o) [NF o], scale x o = oadd x 1 0 * o
  
goal: x.scale o = x.oadd 1 0 * o

full_name: ONote.nf_scale
code: instance nf_scale (x) [NF x] (o) [NF o] : NF (scale x o) 
goal: (x.scale o).NF

full_name: ONote.repr_scale
code: @[simp]
theorem repr_scale (x) [NF x] (o) [NF o] : repr (scale x o) = ω ^ repr x * repr o 
goal: (x.scale o).repr = ω ^ x.repr * o.repr

full_name: ONote.nf_repr_split
code: theorem nf_repr_split {o o' m} [NF o] (h : split o = (o', m)) : NF o' ∧ repr o = repr o' + m 
goal: o'.NF ∧ o.repr = o'.repr + ↑m

full_name: ONote.split_dvd
code: theorem split_dvd {o o' m} [NF o] (h : split o = (o', m)) : ω ∣ repr o' 
goal: ω ∣ o'.repr

full_name: ONote.split_add_lt
code: theorem split_add_lt {o e n a m} [NF o] (h : split o = (oadd e n a, m)) :
    repr a + m < ω ^ repr e 
goal: a.repr + ↑m < ω ^ e.repr

full_name: ONote.mulNat_eq_mul
code: @[simp]
theorem mulNat_eq_mul (n o) : mulNat o n = o * ofNat n 
goal: o.mulNat n = o * ↑n

full_name: ONote.nf_mulNat
code: instance nf_mulNat (o) [NF o] (n) : NF (mulNat o n) 
goal: (o.mulNat n).NF

full_name: ONote.nf_opowAux
code: instance nf_opowAux (e a0 a) [NF e] [NF a0] [NF a] : ∀ k m, NF (opowAux e a0 a k m) 
goal: (e.opowAux a0 a k m).NF

full_name: ONote.nf_opow
code: instance nf_opow (o₁ o₂) [NF o₁] [NF o₂] : NF (o₁ ^ o₂) 
goal: (o₁ ^ o₂).NF

full_name: ONote.scale_opowAux
code: theorem scale_opowAux (e a0 a : ONote) [NF e] [NF a0] [NF a] :
    ∀ k m, repr (opowAux e a0 a k m) = ω ^ repr e * repr (opowAux 0 a0 a k m)
  
goal: (e.opowAux a0 a k m).repr = ω ^ e.repr * (ONote.opowAux 0 a0 a k m).repr

full_name: ONote.repr_opow_aux₁
code: theorem repr_opow_aux₁ {e a} [Ne : NF e] [Na : NF a] {a' : Ordinal} (e0 : repr e ≠ 0)
    (h : a' < (ω : Ordinal.{0}) ^ repr e) (aa : repr a = a') (n : ℕ+) :
    ((ω : Ordinal.{0}) ^ repr e * (n : ℕ) + a') ^ (ω : Ordinal.{0}) =
      (ω ^ repr e) ^ (ω : Ordinal.{0}) 
goal: (ω ^ e.repr * ↑↑n + a') ^ ω = (ω ^ e.repr) ^ ω

full_name: ONote.repr_opow_aux₂
code: theorem repr_opow_aux₂ {a0 a'} [N0 : NF a0] [Na' : NF a'] (m : ℕ) (d : ω ∣ repr a')
    (e0 : repr a0 ≠ 0) (h : repr a' + m < (ω ^ repr a0)) (n : ℕ+) (k : ℕ) :
    let R := repr (opowAux 0 a0 (oadd a0 n a' * ofNat m) k m)
    (k ≠ 0 → R < ((ω ^ repr a0) ^ succ (k : Ordinal))) ∧
      ((ω ^ repr a0) ^ (k : Ordinal)) * ((ω ^ repr a0) * (n : ℕ) + repr a') + R =
        ((ω ^ repr a0) * (n : ℕ) + repr a' + m) ^ succ (k : Ordinal) 
goal: let R := (ONote.opowAux 0 a0 (a0.oadd n a' * ↑m) k m).repr;
(k ≠ 0 → R < (ω ^ a0.repr) ^ Order.succ ↑k) ∧
  (ω ^ a0.repr) ^ ↑k * (ω ^ a0.repr * ↑↑n + a'.repr) + R = (ω ^ a0.repr * ↑↑n + a'.repr + ↑m) ^ Order.succ ↑k

full_name: ONote.repr_opow
code: theorem repr_opow (o₁ o₂) [NF o₁] [NF o₂] : repr (o₁ ^ o₂) = repr o₁ ^ repr o₂ 
goal: (o₁ ^ o₂).repr = o₁.repr ^ o₂.repr

full_name: ONote.fundamentalSequence
code: /-- Given an ordinal, returns `inl none` for `0`, `inl (some a)` for `a+1`, and
  `inr f` for a limit ordinal `a`, where `f i` is a sequence converging to `a`. -/
def fundamentalSequence : ONote → (Option ONote) ⊕ (ℕ → ONote)
  
goal: ONote → Option ONote ⊕ (ℕ → ONote)

full_name: _private.Mathlib.SetTheory.Ordinal.Notation.0.ONote.exists_lt_add
code: private theorem exists_lt_add {α} [hα : Nonempty α] {o : Ordinal} {f : α → Ordinal}
    (H : ∀ ⦃a⦄, a < o → ∃ i, a < f i) {b : Ordinal} ⦃a⦄ (h : a < b + o) : ∃ i, a < b + f i 
goal: ∃ i, a < b + f i

full_name: _private.Mathlib.SetTheory.Ordinal.Notation.0.ONote.exists_lt_mul_omega'
code: private theorem exists_lt_mul_omega' {o : Ordinal} ⦃a⦄ (h : a < o * ω) :
    ∃ i : ℕ, a < o * ↑i + o 
goal: ∃ i, a < o * ↑i + o

full_name: _private.Mathlib.SetTheory.Ordinal.Notation.0.ONote.exists_lt_omega_opow'
code: private theorem exists_lt_omega_opow' {α} {o b : Ordinal} (hb : 1 < b) (ho : o.IsLimit)
    {f : α → Ordinal} (H : ∀ ⦃a⦄, a < o → ∃ i, a < f i) ⦃a⦄ (h : a < b ^ o) :
        ∃ i, a < b ^ f i 
goal: ∃ i, a < b ^ f i

full_name: ONote.FundamentalSequenceProp
code: /-- The property satisfied by `fundamentalSequence o`:
  * `inl none` means `o = 0`
  * `inl (some a)` means `o = succ a`
  * `inr f` means `o` is a limit ordinal and `f` is a
    strictly increasing sequence which converges to `o` -/
def FundamentalSequenceProp (o : ONote) : (Option ONote) ⊕ (ℕ → ONote) → Prop
  
goal: Option ONote ⊕ (ℕ → ONote) → Prop

full_name: ONote.fundamentalSequenceProp_inl_none
code: theorem fundamentalSequenceProp_inl_none (o) :
    FundamentalSequenceProp o (Sum.inl none) ↔ o = 0 
goal: o.FundamentalSequenceProp (Sum.inl none) ↔ o = 0

full_name: ONote.fundamentalSequenceProp_inl_some
code: theorem fundamentalSequenceProp_inl_some (o a) :
    FundamentalSequenceProp o (Sum.inl (some a)) ↔ o.repr = succ a.repr ∧ (o.NF → a.NF) 
goal: o.FundamentalSequenceProp (Sum.inl (some a)) ↔ o.repr = Order.succ a.repr ∧ (o.NF → a.NF)

full_name: ONote.fundamentalSequenceProp_inr
code: theorem fundamentalSequenceProp_inr (o f) :
    FundamentalSequenceProp o (Sum.inr f) ↔
      o.repr.IsLimit ∧
        (∀ i, f i < f (i + 1) ∧ f i < o ∧ (o.NF → (f i).NF)) ∧
        ∀ a, a < o.repr → ∃ i, a < (f i).repr 
goal: o.FundamentalSequenceProp (Sum.inr f) ↔
  o.repr.IsLimit ∧ (∀ (i : ℕ), f i < f (i + 1) ∧ f i < o ∧ (o.NF → (f i).NF)) ∧ ∀ a < o.repr, ∃ i, a < (f i).repr

full_name: ONote.fundamentalSequence_has_prop
code: theorem fundamentalSequence_has_prop (o) : FundamentalSequenceProp o (fundamentalSequence o) 
goal: o.FundamentalSequenceProp o.fundamentalSequence

full_name: ONote.fastGrowing
code: /-- The fast growing hierarchy for ordinal notations `< ε₀`. This is a sequence of
functions `ℕ → ℕ` indexed by ordinals, with the definition:
* `f_0(n) = n + 1`
* `f_(α+1)(n) = f_α^[n](n)`
* `f_α(n) = f_(α[n])(n)` where `α` is a limit ordinal
   and `α[i]` is the fundamental sequence converging to `α` -/
def fastGrowing : ONote → ℕ → ℕ
  
goal: ONote → ℕ → ℕ

full_name: ONote.fastGrowing_def
code: @[nolint unusedHavesSuffices]
theorem fastGrowing_def {o : ONote} {x} (e : fundamentalSequence o = x) :
    fastGrowing o =
      match
        (motive := (x : Option ONote ⊕ (ℕ → ONote)) → FundamentalSequenceProp o x → ℕ → ℕ)
        x, e ▸ fundamentalSequence_has_prop o with
      | Sum.inl none, _ => Nat.succ
      | Sum.inl (some a), _ =>
        fun i => (fastGrowing a)^[i] i
      | Sum.inr f, _ => fun i =>
        fastGrowing (f i) i 
goal: o.fastGrowing =
  match (motive := (x : Option ONote ⊕ (ℕ → ONote)) → o.FundamentalSequenceProp x → ℕ → ℕ) x, ⋯ with
  | Sum.inl none, x => Nat.succ
  | Sum.inl (some a), x => fun i => a.fastGrowing^[i] i
  | Sum.inr f, x => fun i => (f i).fastGrowing i

full_name: ONote.fastGrowing_zero'
code: theorem fastGrowing_zero' (o : ONote) (h : fundamentalSequence o = Sum.inl none) :
    fastGrowing o = Nat.succ 
goal: o.fastGrowing = Nat.succ

full_name: ONote.fastGrowing_succ
code: theorem fastGrowing_succ (o) {a} (h : fundamentalSequence o = Sum.inl (some a)) :
    fastGrowing o = fun i => (fastGrowing a)^[i] i 
goal: o.fastGrowing = fun i => a.fastGrowing^[i] i

full_name: ONote.fastGrowing_limit
code: theorem fastGrowing_limit (o) {f} (h : fundamentalSequence o = Sum.inr f) :
    fastGrowing o = fun i => fastGrowing (f i) i 
goal: o.fastGrowing = fun i => (f i).fastGrowing i

full_name: ONote.fastGrowing_zero
code: @[simp]
theorem fastGrowing_zero : fastGrowing 0 = Nat.succ 
goal: ONote.fastGrowing 0 = Nat.succ

full_name: ONote.fastGrowing_one
code: @[simp]
theorem fastGrowing_one : fastGrowing 1 = fun n => 2 * n 
goal: ONote.fastGrowing 1 = fun n => 2 * n

full_name: ONote.fastGrowing_two
code: @[simp]
theorem fastGrowing_two : fastGrowing 2 = fun n => (2 ^ n) * n 
goal: ONote.fastGrowing 2 = fun n => 2 ^ n * n

full_name: ONote.fastGrowingε₀
code: /-- We can extend the fast growing hierarchy one more step to `ε₀` itself,
  using `ω^(ω^...^ω^0)` as the fundamental sequence converging to `ε₀` (which is not an `ONote`).
  Extending the fast growing hierarchy beyond this requires a definition of fundamental sequence
  for larger ordinals. -/
def fastGrowingε₀ (i : ℕ) : ℕ 
goal: ℕ

full_name: ONote.fastGrowingε₀_zero
code: theorem fastGrowingε₀_zero : fastGrowingε₀ 0 = 1 
goal: ONote.fastGrowingε₀ 0 = 1

full_name: ONote.fastGrowingε₀_one
code: theorem fastGrowingε₀_one : fastGrowingε₀ 1 = 2 
goal: ONote.fastGrowingε₀ 1 = 2

full_name: ONote.fastGrowingε₀_two
code: theorem fastGrowingε₀_two : fastGrowingε₀ 2 = 2048 
goal: ONote.fastGrowingε₀ 2 = 2048

full_name: NONote
code: /-- The type of normal ordinal notations. (It would have been
  nicer to define this right in the inductive type, but `NF o`
  requires `repr` which requires `ONote`, so all these things
  would have to be defined at once, which messes up the VM
  representation.) -/
def NONote 
goal: Type

full_name: instDecidableEqNONote
code: instance : DecidableEq NONote 
goal: DecidableEq NONote

full_name: NONote.NF
code: instance NF (o : NONote) : NF o.1 
goal: (↑o).NF

full_name: NONote.mk
code: /-- Construct a `NONote` from an ordinal notation
  (and infer normality) -/
def mk (o : ONote) [h : ONote.NF o] : NONote 
goal: NONote

full_name: NONote.repr
code: /-- The ordinal represented by an ordinal notation.
  (This function is noncomputable because ordinal
  arithmetic is noncomputable. In computational applications
  `NONote` can be used exclusively without reference
  to `Ordinal`, but this function allows for correctness
  results to be stated.) -/
noncomputable def repr (o : NONote) : Ordinal 
goal: Ordinal.{0}

full_name: NONote.instToString
code: instance : ToString NONote 
goal: ToString NONote

full_name: NONote.instRepr
code: instance : Repr NONote 
goal: Repr NONote

full_name: NONote.instPreorder
code: instance : Preorder NONote 
goal: Preorder NONote

full_name: NONote.instZero
code: instance : Zero NONote 
goal: Zero NONote

full_name: NONote.instInhabited
code: instance : Inhabited NONote 
goal: Inhabited NONote

full_name: NONote.lt_wf
code: theorem lt_wf : @WellFounded NONote (· < ·) 
goal: WellFounded fun x x_1 => x < x_1

full_name: NONote.instWellFoundedLT
code: instance : WellFoundedLT NONote 
goal: WellFoundedLT NONote

full_name: NONote.instWellFoundedRelation
code: instance : WellFoundedRelation NONote 
goal: WellFoundedRelation NONote

full_name: NONote.ofNat
code: /-- Convert a natural number to an ordinal notation -/
def ofNat (n : ℕ) : NONote 
goal: NONote

full_name: NONote.cmp
code: /-- Compare ordinal notations -/
def cmp (a b : NONote) : Ordering 
goal: Ordering

full_name: NONote.cmp_compares
code: theorem cmp_compares : ∀ a b : NONote, (cmp a b).Compares a b
  
goal: (a.cmp b).Compares a b

full_name: NONote.instLinearOrder
code: instance : LinearOrder NONote 
goal: LinearOrder NONote

full_name: NONote.instIsWellOrderLt
code: instance : IsWellOrder NONote (· < ·) 
goal: IsWellOrder NONote fun x x_1 => x < x_1

full_name: NONote.below
code: /-- Asserts that `repr a < ω ^ repr b`. Used in `NONote.recOn` -/
def below (a b : NONote) : Prop 
goal: Prop

full_name: NONote.oadd
code: /-- The `oadd` pseudo-constructor for `NONote` -/
def oadd (e : NONote) (n : ℕ+) (a : NONote) (h : below a e) : NONote 
goal: NONote

full_name: NONote.recOn
code: /-- This is a recursor-like theorem for `NONote` suggesting an
  inductive definition, which can't actually be defined this
  way due to conflicting dependencies. -/
@[elab_as_elim]
def recOn {C : NONote → Sort*} (o : NONote) (H0 : C 0)
    (H1 : ∀ e n a h, C e → C a → C (oadd e n a h)) : C o 
goal: C o

full_name: NONote.instAdd
code: /-- Addition of ordinal notations -/
instance : Add NONote 
goal: Add NONote

full_name: NONote.repr_add
code: theorem repr_add (a b) : repr (a + b) = repr a + repr b 
goal: (a + b).repr = a.repr + b.repr

full_name: NONote.instSub
code: /-- Subtraction of ordinal notations -/
instance : Sub NONote 
goal: Sub NONote

full_name: NONote.repr_sub
code: theorem repr_sub (a b) : repr (a - b) = repr a - repr b 
goal: (a - b).repr = a.repr - b.repr

full_name: NONote.instMul
code: /-- Multiplication of ordinal notations -/
instance : Mul NONote 
goal: Mul NONote

full_name: NONote.repr_mul
code: theorem repr_mul (a b) : repr (a * b) = repr a * repr b 
goal: (a * b).repr = a.repr * b.repr

full_name: NONote.opow
code: /-- Exponentiation of ordinal notations -/
def opow (x y : NONote) 
goal: NONote

full_name: NONote.repr_opow
code: theorem repr_opow (a b) : repr (opow a b) = repr a ^ repr b 
goal: (a.opow b).repr = a.repr ^ b.repr