Skip to content

Commit

Permalink
move(set_theory/ordinal/cantor_normal_form): move CNF to a new file (
Browse files Browse the repository at this point in the history
…#14563)

We move the API for the Cantor Normal Form to a new file, in preparation for an API expansion.
  • Loading branch information
vihdzp committed Jun 6, 2022
1 parent 0f5ea39 commit d490ad1
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 107 deletions.
107 changes: 0 additions & 107 deletions src/set_theory/ordinal/arithmetic.lean
Expand Up @@ -40,7 +40,6 @@ Some properties of the operations are also used to discuss general tools on ordi
and order-continuous, i.e., the image `f o` of a limit ordinal `o` is the sup of `f a` for
`a < o`.
* `enum_ord`: enumerates an unbounded set of ordinals by the ordinals themselves.
* `CNF b o` is the Cantor normal form of the ordinal `o` in base `b`.
* `sup`, `lsub`: the supremum / least strict upper bound of an indexed family of ordinals in
`Type u`, as an ordinal in `Type u`.
* `bsup`, `blsub`: the supremum / least strict upper bound of a set of ordinals indexed by ordinals
Expand Down Expand Up @@ -2103,112 +2102,6 @@ begin
simp only [log_of_not_one_lt_left hb, zero_add]
end

/-! ### The Cantor normal form -/

/-- Proving properties of ordinals by induction over their Cantor normal form. -/
@[elab_as_eliminator] noncomputable def CNF_rec {b : ordinal} (b0 : b ≠ 0)
{C : ordinal → Sort*} (H0 : C 0) (H : ∀ o, o ≠ 0 → C (o % b ^ log b o) → C o) : ∀ o, C o
| o :=
if o0 : o = 0 then by rwa o0 else
have _, from mod_opow_log_lt_self b0 o0,
H o o0 (CNF_rec (o % b ^ log b o))
using_well_founded {dec_tac := `[assumption]}

@[simp] theorem CNF_rec_zero {b} (b0) {C H0 H} : @CNF_rec b b0 C H0 H 0 = H0 :=
by rw [CNF_rec, dif_pos rfl]; refl

@[simp] theorem CNF_rec_ne_zero {b} (b0) {C H0 H o} (o0) :
@CNF_rec b b0 C H0 H o = H o o0 (@CNF_rec b b0 C H0 H _) :=
by rw [CNF_rec, dif_neg o0]

/-- The Cantor normal form of an ordinal `o` is the list of coefficients and exponents in the
base-`b` expansion of `o`.
`CNF b (b ^ u₁ * v₁ + b ^ u₂ * v₂) = [(u₁, v₁), (u₂, v₂)]` -/
def CNF (b o : ordinal) : list (ordinal × ordinal) :=
if b0 : b = 0 then [] else
CNF_rec b0 [] (λ o o0 IH, (log b o, o / b ^ log b o) :: IH) o

@[simp] theorem zero_CNF (o) : CNF 0 o = [] :=
dif_pos rfl

@[simp] theorem CNF_zero (b) : CNF b 0 = [] :=
if b0 : b = 0 then dif_pos b0 else (dif_neg b0).trans $ CNF_rec_zero _

theorem CNF_ne_zero {b o : ordinal} (b0 : b ≠ 0) (o0 : o ≠ 0) :
CNF b o = (log b o, o / b ^ log b o) :: CNF b (o % b ^ log b o) :=
by unfold CNF; rw [dif_neg b0, dif_neg b0, CNF_rec_ne_zero b0 o0]

@[simp] theorem one_CNF {o : ordinal} (o0 : o ≠ 0) : CNF 1 o = [(0, o)] :=
by rw [CNF_ne_zero ordinal.one_ne_zero o0, log_of_not_one_lt_left (irrefl _), opow_zero, mod_one,
CNF_zero, div_one]

theorem CNF_foldr {b : ordinal} (b0 : b ≠ 0) (o) :
(CNF b o).foldr (λ p r, b ^ p.1 * p.2 + r) 0 = o :=
CNF_rec b0 (by rw CNF_zero; refl)
(λ o o0 IH, by rw [CNF_ne_zero b0 o0, list.foldr_cons, IH, div_add_mod]) o

/-- This theorem exists to factor out commonalities between the proofs of `ordinal.CNF_pairwise` and
`ordinal.CNF_fst_le_log`. -/
private theorem CNF_pairwise_aux (b o : ordinal.{u}) :
(∀ p : ordinal × ordinal, p ∈ CNF b o → p.1 ≤ log b o) ∧ (CNF b o).pairwise (λ p q, q.1 < p.1) :=
begin
by_cases b0 : b = 0,
{ simp only [b0, zero_CNF, list.pairwise.nil, and_true], exact λ _, false.elim },
cases lt_or_eq_of_le (one_le_iff_ne_zero.2 b0) with b1 b1,
{ refine CNF_rec b0 _ _ o,
{ simp only [CNF_zero, list.pairwise.nil, and_true], exact λ _, false.elim },
intros o o0 IH, cases IH with IH₁ IH₂,
simp only [CNF_ne_zero b0 o0, list.forall_mem_cons, list.pairwise_cons, IH₂, and_true],
refine ⟨⟨le_rfl, λ p m, _⟩, λ p m, _⟩,
{ exact (IH₁ p m).trans (log_mono_right _ $ le_of_lt $ mod_opow_log_lt_self b0 o0) },
{ refine (IH₁ p m).trans_lt ((lt_opow_iff_log_lt b1 _).1 _),
{ rw ordinal.pos_iff_ne_zero, intro e,
rw e at m, simpa only [CNF_zero] using m },
{ exact mod_lt _ (opow_ne_zero _ b0) } } },
{ by_cases o0 : o = 0,
{ simp only [o0, CNF_zero, list.pairwise.nil, and_true], exact λ _, false.elim },
rw [← b1, one_CNF o0],
simp only [list.mem_singleton, log_one_left, forall_eq, le_refl, true_and,
list.pairwise_singleton] }
end

theorem CNF_pairwise (b o : ordinal.{u}) :
(CNF b o).pairwise (λ p q : ordinal × ordinal, q.1 < p.1) :=
(CNF_pairwise_aux _ _).2

theorem CNF_fst_le_log {b o : ordinal.{u}} :
∀ {p : ordinal × ordinal}, p ∈ CNF b o → p.1 ≤ log b o :=
(CNF_pairwise_aux _ _).1

theorem CNF_fst_le {b o : ordinal.{u}} {p : ordinal × ordinal} (hp : p ∈ CNF b o) : p.1 ≤ o :=
(CNF_fst_le_log hp).trans (log_le_self _ _)

/-- This theorem exists to factor out commonalities between the proofs of `ordinal.CNF_snd_lt` and
`ordinal.CNF_lt_snd`. -/
private theorem CNF_snd_lt_aux {b o : ordinal.{u}} (b1 : 1 < b) :
∀ {p : ordinal × ordinal}, p ∈ CNF b o → p.2 < b ∧ 0 < p.2 :=
begin
have b0 := (zero_lt_one.trans b1).ne',
refine CNF_rec b0 (λ _, by { rw CNF_zero, exact false.elim }) (λ o o0 IH, _) o,
simp only [CNF_ne_zero b0 o0, list.mem_cons_iff, forall_eq_or_imp, iff_true_intro @IH, and_true],
nth_rewrite 1 ←@succ_le_iff,
rw [div_lt (opow_ne_zero _ b0), ←opow_succ, le_div (opow_ne_zero _ b0), succ_zero, mul_one],
refine ⟨lt_opow_succ_log_self b1 _, opow_log_le_self _ _⟩,
rwa ordinal.pos_iff_ne_zero
end

theorem CNF_snd_lt {b o : ordinal.{u}} (b1 : 1 < b) {p : ordinal × ordinal} (hp : p ∈ CNF b o) :
p.2 < b :=
(CNF_snd_lt_aux b1 hp).1

theorem CNF_lt_snd {b o : ordinal.{u}} (b1 : 1 < b) {p : ordinal × ordinal} (hp : p ∈ CNF b o) :
0 < p.2 :=
(CNF_snd_lt_aux b1 hp).2

theorem CNF_sorted (b o : ordinal) : ((CNF b o).map prod.fst).sorted (>) :=
by { rw [list.sorted, list.pairwise_map], exact CNF_pairwise b o }

/-! ### Casting naturals into ordinals, compatibility with operations -/

@[simp] theorem nat_cast_mul {m n : ℕ} : ((m * n : ℕ) : ordinal) = m * n :=
Expand Down
134 changes: 134 additions & 0 deletions src/set_theory/ordinal/cantor_normal_form.lean
@@ -0,0 +1,134 @@
/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/

import set_theory.ordinal.arithmetic

/-!
# Cantor Normal Form
The Cantor normal form of an ordinal is generally defined as its base `ω` expansion, with its
non-zero exponents in decreasing order. Here, we more generally define a base `b` expansion
`ordinal.CNF` in this manner, for any `b ≥ 2`.
# Todo
- Add API for the coefficients of the Cantor normal form.
- Prove the basic results relating the CNF to the arithmetic operations on ordinals.
-/

noncomputable theory

universe u

open order

namespace ordinal

/-- Proving properties of ordinals by induction over their Cantor normal form. -/
@[elab_as_eliminator] noncomputable def CNF_rec {b : ordinal} (b0 : b ≠ 0)
{C : ordinal → Sort*} (H0 : C 0) (H : ∀ o, o ≠ 0 → C (o % b ^ log b o) → C o) : ∀ o, C o
| o :=
if o0 : o = 0 then by rwa o0 else
have _, from mod_opow_log_lt_self b0 o0,
H o o0 (CNF_rec (o % b ^ log b o))
using_well_founded {dec_tac := `[assumption]}

@[simp] theorem CNF_rec_zero {b} (b0) {C H0 H} : @CNF_rec b b0 C H0 H 0 = H0 :=
by rw [CNF_rec, dif_pos rfl]; refl

@[simp] theorem CNF_rec_ne_zero {b} (b0) {C H0 H o} (o0) :
@CNF_rec b b0 C H0 H o = H o o0 (@CNF_rec b b0 C H0 H _) :=
by rw [CNF_rec, dif_neg o0]

/-- The Cantor normal form of an ordinal `o` is the list of coefficients and exponents in the
base-`b` expansion of `o`.
`CNF b (b ^ u₁ * v₁ + b ^ u₂ * v₂) = [(u₁, v₁), (u₂, v₂)]` -/
def CNF (b o : ordinal) : list (ordinal × ordinal) :=
if b0 : b = 0 then [] else
CNF_rec b0 [] (λ o o0 IH, (log b o, o / b ^ log b o) :: IH) o

@[simp] theorem zero_CNF (o) : CNF 0 o = [] :=
dif_pos rfl

@[simp] theorem CNF_zero (b) : CNF b 0 = [] :=
if b0 : b = 0 then dif_pos b0 else (dif_neg b0).trans $ CNF_rec_zero _

theorem CNF_ne_zero {b o : ordinal} (b0 : b ≠ 0) (o0 : o ≠ 0) :
CNF b o = (log b o, o / b ^ log b o) :: CNF b (o % b ^ log b o) :=
by unfold CNF; rw [dif_neg b0, dif_neg b0, CNF_rec_ne_zero b0 o0]

@[simp] theorem one_CNF {o : ordinal} (o0 : o ≠ 0) : CNF 1 o = [(0, o)] :=
by rw [CNF_ne_zero ordinal.one_ne_zero o0, log_of_not_one_lt_left (irrefl _), opow_zero, mod_one,
CNF_zero, div_one]

theorem CNF_foldr {b : ordinal} (b0 : b ≠ 0) (o) :
(CNF b o).foldr (λ p r, b ^ p.1 * p.2 + r) 0 = o :=
CNF_rec b0 (by rw CNF_zero; refl)
(λ o o0 IH, by rw [CNF_ne_zero b0 o0, list.foldr_cons, IH, div_add_mod]) o

/-- This theorem exists to factor out commonalities between the proofs of `ordinal.CNF_pairwise` and
`ordinal.CNF_fst_le_log`. -/
private theorem CNF_pairwise_aux (b o : ordinal.{u}) :
(∀ p : ordinal × ordinal, p ∈ CNF b o → p.1 ≤ log b o) ∧ (CNF b o).pairwise (λ p q, q.1 < p.1) :=
begin
by_cases b0 : b = 0,
{ simp only [b0, zero_CNF, list.pairwise.nil, and_true], exact λ _, false.elim },
cases lt_or_eq_of_le (one_le_iff_ne_zero.2 b0) with b1 b1,
{ refine CNF_rec b0 _ _ o,
{ simp only [CNF_zero, list.pairwise.nil, and_true], exact λ _, false.elim },
intros o o0 IH, cases IH with IH₁ IH₂,
simp only [CNF_ne_zero b0 o0, list.forall_mem_cons, list.pairwise_cons, IH₂, and_true],
refine ⟨⟨le_rfl, λ p m, _⟩, λ p m, _⟩,
{ exact (IH₁ p m).trans (log_mono_right _ $ le_of_lt $ mod_opow_log_lt_self b0 o0) },
{ refine (IH₁ p m).trans_lt ((lt_opow_iff_log_lt b1 _).1 _),
{ rw ordinal.pos_iff_ne_zero, intro e,
rw e at m, simpa only [CNF_zero] using m },
{ exact mod_lt _ (opow_ne_zero _ b0) } } },
{ by_cases o0 : o = 0,
{ simp only [o0, CNF_zero, list.pairwise.nil, and_true], exact λ _, false.elim },
rw [← b1, one_CNF o0],
simp only [list.mem_singleton, log_one_left, forall_eq, le_refl, true_and,
list.pairwise_singleton] }
end

theorem CNF_pairwise (b o : ordinal.{u}) :
(CNF b o).pairwise (λ p q : ordinal × ordinal, q.1 < p.1) :=
(CNF_pairwise_aux _ _).2

theorem CNF_fst_le_log {b o : ordinal.{u}} :
∀ {p : ordinal × ordinal}, p ∈ CNF b o → p.1 ≤ log b o :=
(CNF_pairwise_aux _ _).1

theorem CNF_fst_le {b o : ordinal.{u}} {p : ordinal × ordinal} (hp : p ∈ CNF b o) : p.1 ≤ o :=
(CNF_fst_le_log hp).trans (log_le_self _ _)

/-- This theorem exists to factor out commonalities between the proofs of `ordinal.CNF_snd_lt` and
`ordinal.CNF_lt_snd`. -/
private theorem CNF_snd_lt_aux {b o : ordinal.{u}} (b1 : 1 < b) :
∀ {p : ordinal × ordinal}, p ∈ CNF b o → p.2 < b ∧ 0 < p.2 :=
begin
have b0 := (zero_lt_one.trans b1).ne',
refine CNF_rec b0 (λ _, by { rw CNF_zero, exact false.elim }) (λ o o0 IH, _) o,
simp only [CNF_ne_zero b0 o0, list.mem_cons_iff, forall_eq_or_imp, iff_true_intro @IH, and_true],
nth_rewrite 1 ←@succ_le_iff,
rw [div_lt (opow_ne_zero _ b0), ←opow_succ, le_div (opow_ne_zero _ b0), succ_zero, mul_one],
refine ⟨lt_opow_succ_log_self b1 _, opow_log_le_self _ _⟩,
rwa ordinal.pos_iff_ne_zero
end

theorem CNF_snd_lt {b o : ordinal.{u}} (b1 : 1 < b) {p : ordinal × ordinal} (hp : p ∈ CNF b o) :
p.2 < b :=
(CNF_snd_lt_aux b1 hp).1

theorem CNF_lt_snd {b o : ordinal.{u}} (b1 : 1 < b) {p : ordinal × ordinal} (hp : p ∈ CNF b o) :
0 < p.2 :=
(CNF_snd_lt_aux b1 hp).2

theorem CNF_sorted (b o : ordinal) : ((CNF b o).map prod.fst).sorted (>) :=
by { rw [list.sorted, list.pairwise_map], exact CNF_pairwise b o }

end ordinal

0 comments on commit d490ad1

Please sign in to comment.