Equivalence of naturals
Analysis I, Chapter 2 epilogue: Isomorphism with the Mathlib natural numbers
In this (technical) epilogue, we show that the "Chapter 2" natural numbers Chapter2.Nat are
isomorphic in various senses to the standard natural numbers ℕ.
After this epilogue, Chapter2.Nat will be deprecated, and we will instead use the standard
natural numbers ℕ throughout. In particular, one should use the full Mathlib API for ℕ for
all subsequent chapters, in lieu of the Chapter2.Nat API.
Filling the sorries here requires both the Chapter2.Nat API and the Mathlib API for the standard
natural numbers ℕ. As such, they are excellent exercises to prepare you for the aforementioned
transition.
In second half of this section we also give a fully axiomatic treatment of the natural numbers
via the Peano axioms. The treatment in the preceding three sections was only partially axiomatic,
because we used a specific construction Chapter2.Nat of the natural numbers that was an inductive
type, and used that inductive type to construct a recursor. Here, we give some exercises to show
how one can accomplish the same tasks directly from the Peano axioms, without knowing the specific
implementation of the natural numbers.
Tips from past users
Users of the companion who have completed the exercises in this section are welcome to send their tips for future users in this section as PRs.
-
(Add tip here)
Converting a Chapter 2 natural number to a Mathlib natural number.
abbrev Chapter2.Nat.toNat (n : Chapter2.Nat) : ℕ := match n with
| zero => 0
| succ n' => n'.toNat + 1lemma Chapter2.Nat.zero_toNat : (0 : Chapter2.Nat).toNat = 0 := rfllemma Chapter2.Nat.succ_toNat (n : Chapter2.Nat) : (n++).toNat = n.toNat + 1 := rflThe conversion is a bijection. Here we use the existing capability (from Section 2.1) to map the Mathlib natural numbers to the Chapter 2 natural numbers.
abbrev Chapter2.Nat.equivNat : Chapter2.Nat ≃ ℕ where
toFun := toNat
invFun n := (n:Chapter2.Nat)
left_inv n := n:Nat⊢ (fun n => ↑n) n.toNat = n
⊢ (fun n => ↑n) zero.toNat = zeron:Nathn:(fun n => ↑n) n.toNat = n⊢ (fun n => ↑n) n++.toNat = n++; n:Nathn:(fun n => ↑n) n.toNat = n⊢ (fun n => ↑n) n++.toNat = n++
n:Nathn:(fun n => ↑n) n.toNat = n⊢ n + 1 = n++
All goals completed! 🐙
right_inv n := n:ℕ⊢ ((fun n => ↑n) n).toNat = n
⊢ ((fun n => ↑n) 0).toNat = 0n:ℕhn:((fun n => ↑n) n).toNat = n⊢ ((fun n => ↑n) (n + 1)).toNat = n + 1; n:ℕhn:((fun n => ↑n) n).toNat = n⊢ ((fun n => ↑n) (n + 1)).toNat = n + 1
All goals completed! 🐙The conversion preserves addition.
abbrev Chapter2.Nat.map_add : ∀ (n m : Nat), (n + m).toNat = n.toNat + m.toNat := ⊢ ∀ (n m : Nat), (n + m).toNat = n.toNat + m.toNat
n:Natm:Nat⊢ (n + m).toNat = n.toNat + m.toNat
m:Nat⊢ (zero + m).toNat = zero.toNat + m.toNatm:Natn:Nathn:(n + m).toNat = n.toNat + m.toNat⊢ (n++ + m).toNat = n++.toNat + m.toNat
m:Nat⊢ (zero + m).toNat = zero.toNat + m.toNat All goals completed! 🐙
All goals completed! 🐙The conversion preserves multiplication.
abbrev Chapter2.Nat.map_mul : ∀ (n m : Nat), (n * m).toNat = n.toNat * m.toNat := ⊢ ∀ (n m : Nat), (n * m).toNat = n.toNat * m.toNat
n:Natm:Nat⊢ (n * m).toNat = n.toNat * m.toNat
All goals completed! 🐙The conversion preserves order.
abbrev Chapter2.Nat.map_le_map_iff : ∀ {n m : Nat}, n.toNat ≤ m.toNat ↔ n ≤ m := ⊢ ∀ {n m : Nat}, n.toNat ≤ m.toNat ↔ n ≤ m
n:Natm:Nat⊢ n.toNat ≤ m.toNat ↔ n ≤ m
All goals completed! 🐙abbrev Chapter2.Nat.equivNat_ordered_ring : Chapter2.Nat ≃+*o ℕ where
toEquiv := equivNat
map_add' := map_add
map_mul' := map_mul
map_le_map_iff' := map_le_map_iffThe conversion preserves exponentiation.
lemma Chapter2.Nat.pow_eq_pow (n m : Chapter2.Nat) :
n.toNat ^ m.toNat = (n^m).toNat := n:Natm:Nat⊢ n.toNat ^ m.toNat = (n ^ m).toNat
All goals completed! 🐙
The Peano axioms for an abstract type Nat
@[ext]
structure PeanoAxioms where
Nat : Type
zero : Nat -- Axiom 2.1
succ : Nat → Nat -- Axiom 2.2
succ_ne : ∀ n : Nat, succ n ≠ zero -- Axiom 2.3
succ_cancel : ∀ {n m : Nat}, succ n = succ m → n = m -- Axiom 2.4
induction : ∀ (P : Nat → Prop),
P zero → (∀ n : Nat, P n → P (succ n)) → ∀ n : Nat, P n -- Axiom 2.5namespace PeanoAxiomsThe Chapter 2 natural numbers obey the Peano axioms.
def Chapter2_Nat : PeanoAxioms where
Nat := Chapter2.Nat
zero := Chapter2.Nat.zero
succ := Chapter2.Nat.succ
succ_ne := Chapter2.Nat.succ_ne
succ_cancel := Chapter2.Nat.succ_cancel
induction := Chapter2.Nat.inductionThe Mathlib natural numbers obey the Peano axioms.
def Mathlib_Nat : PeanoAxioms where
Nat := ℕ
zero := 0
succ := Nat.succ
succ_ne := Nat.succ_ne_zero
succ_cancel := Nat.succ_inj.mp
induction _ := Nat.recOne can map the Mathlib natural numbers into any other structure obeying the Peano axioms.
abbrev natCast (P : PeanoAxioms) : ℕ → P.Nat := fun n ↦ match n with
| Nat.zero => P.zero
| Nat.succ n => P.succ (natCast P n)
One can start the proof here with unfold Function.Injective, although it is not strictly necessary.
theorem natCast_injective (P : PeanoAxioms) : Function.Injective P.natCast := P:PeanoAxioms⊢ Function.Injective P.natCast
All goals completed! 🐙
One can start the proof here with unfold Function.Surjective, although it is not strictly necessary.
theorem natCast_surjective (P : PeanoAxioms) : Function.Surjective P.natCast := P:PeanoAxioms⊢ Function.Surjective P.natCast
All goals completed! 🐙
The notion of an equivalence between two structures obeying the Peano axioms.
The symbol is an alias for Mathlib's Equiv class; for instance P.Nat ≃ Q.Nat is
an alias for _root_.Equiv P.Nat Q.Nat.
class Equiv (P Q : PeanoAxioms) where
equiv : P.Nat ≃ Q.Nat
equiv_zero : equiv P.zero = Q.zero
equiv_succ : ∀ n : P.Nat, equiv (P.succ n) = Q.succ (equiv n)
This exercise will require application of Mathlib's API for the Equiv class.
Some of this API can be invoked automatically via the simp tactic.
abbrev Equiv.symm {P Q: PeanoAxioms} (equiv : Equiv P Q) : Equiv Q P where
equiv := equiv.equiv.symm
equiv_zero := P:PeanoAxiomsQ:PeanoAxiomsequiv:P.Equiv Q⊢ Equiv.equiv.symm Q.zero = P.zero All goals completed! 🐙
equiv_succ n := P:PeanoAxiomsQ:PeanoAxiomsequiv:P.Equiv Qn:Q.Nat⊢ Equiv.equiv.symm (Q.succ n) = P.succ (Equiv.equiv.symm n) All goals completed! 🐙
This exercise will require application of Mathlib's API for the Equiv class.
Some of this API can be invoked automatically via the simp tactic.
abbrev Equiv.trans {P Q R: PeanoAxioms} (equiv1 : Equiv P Q) (equiv2 : Equiv Q R) : Equiv P R where
equiv := equiv1.equiv.trans equiv2.equiv
equiv_zero := P:PeanoAxiomsQ:PeanoAxiomsR:PeanoAxiomsequiv1:P.Equiv Qequiv2:Q.Equiv R⊢ (equiv.trans equiv) P.zero = R.zero All goals completed! 🐙
equiv_succ n := P:PeanoAxiomsQ:PeanoAxiomsR:PeanoAxiomsequiv1:P.Equiv Qequiv2:Q.Equiv Rn:P.Nat⊢ (equiv.trans equiv) (P.succ n) = R.succ ((equiv.trans equiv) n) All goals completed! 🐙
Useful Mathlib tools for inverting bijections include Function.surjInv and Function.invFun.
noncomputable abbrev Equiv.fromNat (P : PeanoAxioms) : Equiv Mathlib_Nat P where
equiv := {
toFun := P.natCast
invFun := P:PeanoAxioms⊢ P.Nat → Mathlib_Nat.Nat All goals completed! 🐙
left_inv := P:PeanoAxioms⊢ Function.LeftInverse sorry P.natCast All goals completed! 🐙
right_inv := P:PeanoAxioms⊢ Function.RightInverse sorry P.natCast All goals completed! 🐙
}
equiv_zero := P:PeanoAxioms⊢ { toFun := P.natCast, invFun := sorry, left_inv := ⋯, right_inv := ⋯ } Mathlib_Nat.zero = P.zero All goals completed! 🐙
equiv_succ n := P:PeanoAxiomsn:Mathlib_Nat.Nat⊢ { toFun := P.natCast, invFun := sorry, left_inv := ⋯, right_inv := ⋯ } (Mathlib_Nat.succ n) =
P.succ ({ toFun := P.natCast, invFun := sorry, left_inv := ⋯, right_inv := ⋯ } n) All goals completed! 🐙The task here is to establish that any two structures obeying the Peano axioms are equivalent.
noncomputable abbrev Equiv.mk' (P Q : PeanoAxioms) : Equiv P Q := P:PeanoAxiomsQ:PeanoAxioms⊢ P.Equiv Q All goals completed! 🐙There is only one equivalence between any two structures obeying the Peano axioms.
theorem Equiv.uniq {P Q : PeanoAxioms} (equiv1 equiv2 : PeanoAxioms.Equiv P Q) :
equiv1 = equiv2 := P:PeanoAxiomsQ:PeanoAxiomsequiv1:P.Equiv Qequiv2:P.Equiv Q⊢ equiv1 = equiv2
P:PeanoAxiomsQ:PeanoAxiomsequiv2:P.Equiv Qequiv1:P.Nat ≃ Q.Natequiv_zero1:equiv1 P.zero = Q.zeroequiv_succ1:∀ (n : P.Nat), equiv1 (P.succ n) = Q.succ (equiv1 n)⊢ { equiv := equiv1, equiv_zero := equiv_zero1, equiv_succ := equiv_succ1 } = equiv2
P:PeanoAxiomsQ:PeanoAxiomsequiv1:P.Nat ≃ Q.Natequiv_zero1:equiv1 P.zero = Q.zeroequiv_succ1:∀ (n : P.Nat), equiv1 (P.succ n) = Q.succ (equiv1 n)equiv2:P.Nat ≃ Q.Natequiv_zero2:equiv2 P.zero = Q.zeroequiv_succ2:∀ (n : P.Nat), equiv2 (P.succ n) = Q.succ (equiv2 n)⊢ { equiv := equiv1, equiv_zero := equiv_zero1, equiv_succ := equiv_succ1 } =
{ equiv := equiv2, equiv_zero := equiv_zero2, equiv_succ := equiv_succ2 }
P:PeanoAxiomsQ:PeanoAxiomsequiv1:P.Nat ≃ Q.Natequiv_zero1:equiv1 P.zero = Q.zeroequiv_succ1:∀ (n : P.Nat), equiv1 (P.succ n) = Q.succ (equiv1 n)equiv2:P.Nat ≃ Q.Natequiv_zero2:equiv2 P.zero = Q.zeroequiv_succ2:∀ (n : P.Nat), equiv2 (P.succ n) = Q.succ (equiv2 n)⊢ equiv1 = equiv2
P:PeanoAxiomsQ:PeanoAxiomsequiv1:P.Nat ≃ Q.Natequiv_zero1:equiv1 P.zero = Q.zeroequiv_succ1:∀ (n : P.Nat), equiv1 (P.succ n) = Q.succ (equiv1 n)equiv2:P.Nat ≃ Q.Natequiv_zero2:equiv2 P.zero = Q.zeroequiv_succ2:∀ (n : P.Nat), equiv2 (P.succ n) = Q.succ (equiv2 n)n:P.Nat⊢ equiv1 n = equiv2 n
All goals completed! 🐙A sample result: recursion is well-defined on any structure obeying the Peano axioms
theorem Nat.recurse_uniq {P : PeanoAxioms} (f: P.Nat → P.Nat → P.Nat) (c: P.Nat) :
∃! (a: P.Nat → P.Nat), a P.zero = c ∧ ∀ n, a (P.succ n) = f n (a n) := P:PeanoAxiomsf:P.Nat → P.Nat → P.Natc:P.Nat⊢ ∃! a, a P.zero = c ∧ ∀ (n : P.Nat), a (P.succ n) = f n (a n)
All goals completed! 🐙end PeanoAxioms