Analysis I, Section 2.1: The Peano Axioms
This file is a translation of Section 2.1 of Analysis I to Lean 4. All numbering refers to the original text.
I have attempted to make the translation as faithful a paraphrasing as possible of the original text. When there is a choice between a more idiomatic Lean solution and a more faithful translation, I have generally chosen the latter. In particular, there will be places where the Lean code could be "golfed" to be more elegant and idiomatic, but I have consciously avoided doing so.
Main constructions and results of this section:
-
Definition of the "Chapter 2" natural numbers,
Chapter2.Nat, abbreviated asNatwithin the Chapter2 namespace. (In the book, the natural numbers are treated in a purely axiomatic fashion, as a type that obeys the Peano axioms; but here we take advantage of Lean's native inductive types to explicitly construct a version of the natural numbers that obey those axioms. One could also proceed more axiomatically, as is done in Section 3 for set theory: see the epilogue to this chapter.) -
Establishment of the Peano axioms for
Chapter2.Nat. -
Recursive definitions for
Chapter2.Nat.
Note: at the end of this chapter, the Chapter2.Nat class will be deprecated in favor of the
standard Mathlib class _root_.Nat, or ℕ. However, we will develop the properties of
Chapter2.Nat "by hand" in the next few sections for pedagogical purposes.
namespace Chapter2Assumption 2.6 (Existence of natural numbers). Here we use an explicit construction of the natural numbers (using an inductive type). For a more axiomatic approach, see the epilogue to this chapter.
inductive Nat where
| zero : Nat
| succ : Nat → Nat
deriving Repr, DecidableEq -- this allows `decide` to work on `Nat`/-- Axiom 2.2 (Successor of a natural number is a natural number) -/
postfix:100 "++" => Nat.succDefinition 2.1.3 (Definition of the numerals 0, 1, 2, etc.). Note: to avoid ambiguity, one may need to use explicit casts such as (0:Nat), (1:Nat), etc. to refer to this chapter's version of the natural numbers.
instance Nat.instOfNat {n:_root_.Nat} : OfNat Nat n where
ofNat := _root_.Nat.rec 0 (fun _ n ↦ n++) ninstance Nat.instOne : One Nat := ⟨ 1 ⟩lemma Nat.zero_succ : 0++ = 1 := ⊢ 0++ = 1 All goals completed! 🐙lemma Nat.one_succ : 1++ = 2 := ⊢ 1++ = 2 All goals completed! 🐙Proposition 2.1.4 (3 is a natural number)
lemma Nat.two_succ : 2++ = 3 := ⊢ 2++ = 3 All goals completed! 🐙
Axiom 2.3 (0 is not the successor of any natural number).
Compare with Lean's Nat.succ_ne_zero.
theorem Nat.succ_ne (n:Nat) : n++ ≠ 0 := n:Nat⊢ n++ ≠ 0
n:Nath:n++ = 0⊢ False
All goals completed! 🐙Proposition 2.1.6 (4 is not equal to zero)
theorem Nat.four_ne : (4:Nat) ≠ 0 := ⊢ 4 ≠ 0
-- By definition, 4 = 3++.
⊢ 3++ ≠ 0
-- By axiom 2.3, 3++ is not zero.
All goals completed! 🐙
Axiom 2.4 (Different natural numbers have different successors).
Compare with Mathlib's Nat.succ_inj.
theorem Nat.succ_cancel {n m:Nat} (hnm: n++ = m++) : n = m := n:Natm:Nathnm:n++ = m++⊢ n = m
All goals completed! 🐙
Axiom 2.4 (Different natural numbers have different successors).
Compare with Mathlib's Nat.succ_ne_succ.
theorem Nat.succ_ne_succ (n m:Nat) : n ≠ m → n++ ≠ m++ := n:Natm:Nat⊢ n ≠ m → n++ ≠ m++
n:Natm:Nath:n ≠ m⊢ n++ ≠ m++
n:Natm:Nath:n++ = m++⊢ n = m
All goals completed! 🐙Proposition 2.1.8 (6 is not equal to 2)
theorem Nat.six_ne_two : (6:Nat) ≠ 2 := ⊢ 6 ≠ 2
-- this proof is written to follow the structure of the original text.
h:6 = 2⊢ False
h:5++ = 1++⊢ False
h:5 = 1⊢ False
h:4++ = 0++⊢ False
h:4 = 0⊢ False
h:4 = 0this:?_mvar.8344 := Chapter2.Nat.four_ne⊢ False
All goals completed! 🐙
One can also prove this sort of result by the decide tactic
theorem Nat.six_ne_two' : (6:Nat) ≠ 2 := ⊢ 6 ≠ 2
All goals completed! 🐙
Axiom 2.5 (Principle of mathematical induction). The induction (or induction') tactic in
Mathlib serves as a substitute for this axiom.
theorem Nat.induction (P : Nat → Prop) (hbase : P 0) (hind : ∀ n, P n → P (n++)) :
∀ n, P n := P:Nat → Prophbase:P 0hind:∀ (n : Nat), P n → P (n++)⊢ ∀ (n : Nat), P n
P:Nat → Prophbase:P 0hind:∀ (n : Nat), P n → P (n++)n:Nat⊢ P n
induction n with
P:Nat → Prophbase:P 0hind:∀ (n : Nat), P n → P (n++)⊢ P zero All goals completed! 🐙
P:Nat → Prophbase:P 0hind:∀ (n : Nat), P n → P (n++)n:Natih:P n⊢ P (n++) All goals completed! 🐙
Recursion. Analogous to the inbuilt Mathlib method Nat.rec associated to
the Mathlib natural numbers
abbrev Nat.recurse (f: Nat → Nat → Nat) (c: Nat) : Nat → Nat := fun n ↦ match n with
| 0 => c
| n++ => f n (recurse f c n)
Proposition 2.1.16 (recursive definitions). Compare with Mathlib's Nat.rec_zero.
theorem Nat.recurse_zero (f: Nat → Nat → Nat) (c: Nat) : Nat.recurse f c 0 = c := f:Nat → Nat → Natc:Nat⊢ recurse f c 0 = c All goals completed! 🐙
Proposition 2.1.16 (recursive definitions). Compare with Mathlib's Nat.rec_add_one.
theorem Nat.recurse_succ (f: Nat → Nat → Nat) (c: Nat) (n: Nat) :
recurse f c (n++) = f n (recurse f c n) := f:Nat → Nat → Natc:Natn:Nat⊢ recurse f c (n++) = f n (recurse f c n) All goals completed! 🐙Proposition 2.1.16 (recursive definitions).
theorem Nat.eq_recurse (f: Nat → Nat → Nat) (c: Nat) (a: Nat → Nat) :
(a 0 = c ∧ ∀ n, a (n++) = f n (a n)) ↔ a = recurse f c := f:Nat → Nat → Natc:Nata:Nat → Nat⊢ (a 0 = c ∧ ∀ (n : Nat), a (n++) = f n (a n)) ↔ a = recurse f c
f:Nat → Nat → Natc:Nata:Nat → Nat⊢ (a 0 = c ∧ ∀ (n : Nat), a (n++) = f n (a n)) → a = recurse f cf:Nat → Nat → Natc:Nata:Nat → Nat⊢ a = recurse f c → a 0 = c ∧ ∀ (n : Nat), a (n++) = f n (a n)
f:Nat → Nat → Natc:Nata:Nat → Nat⊢ (a 0 = c ∧ ∀ (n : Nat), a (n++) = f n (a n)) → a = recurse f c f:Nat → Nat → Natc:Nata:Nat → Nath0:a 0 = chsucc:∀ (n : Nat), a (n++) = f n (a n)⊢ a = recurse f c
-- this proof is written to follow the structure of the original text.
f:Nat → Nat → Natc:Nata:Nat → Nath0:a 0 = chsucc:∀ (n : Nat), a (n++) = f n (a n)⊢ ∀ (x : Nat), a x = recurse f c x; f:Nat → Nat → Natc:Nata:Nat → Nath0:a 0 = chsucc:∀ (n : Nat), a (n++) = f n (a n)⊢ a 0 = recurse f c 0f:Nat → Nat → Natc:Nata:Nat → Nath0:a 0 = chsucc:∀ (n : Nat), a (n++) = f n (a n)⊢ ∀ (n : Nat), a n = recurse f c n → a (n++) = recurse f c (n++)
f:Nat → Nat → Natc:Nata:Nat → Nath0:a 0 = chsucc:∀ (n : Nat), a (n++) = f n (a n)⊢ a 0 = recurse f c 0 All goals completed! 🐙
f:Nat → Nat → Natc:Nata:Nat → Nath0:a 0 = chsucc:∀ (n : Nat), a (n++) = f n (a n)n:Nathn:a n = recurse f c n⊢ a (n++) = recurse f c (n++)
All goals completed! 🐙
f:Nat → Nat → Natc:Nata:Nat → Nath:a = recurse f c⊢ a 0 = c ∧ ∀ (n : Nat), a (n++) = f n (a n)
f:Nat → Nat → Natc:Nata:Nat → Nath:a = recurse f c⊢ recurse f c 0 = c ∧ ∀ (n : Nat), recurse f c (n++) = f n (recurse f c n)
f:Nat → Nat → Natc:Nata:Nat → Nath:a = recurse f c⊢ recurse f c 0 = cf:Nat → Nat → Natc:Nata:Nat → Nath:a = recurse f c⊢ ∀ (n : Nat), recurse f c (n++) = f n (recurse f c n) -- could also use `split_ands` or `and_intros` here
f:Nat → Nat → Natc:Nata:Nat → Nath:a = recurse f c⊢ recurse f c 0 = c All goals completed! 🐙
All goals completed! 🐙Proposition 2.1.16 (recursive definitions).
theorem Nat.recurse_uniq (f: Nat → Nat → Nat) (c: Nat) :
∃! (a: Nat → Nat), a 0 = c ∧ ∀ n, a (n++) = f n (a n) := f:Nat → Nat → Natc:Nat⊢ ∃! a, a 0 = c ∧ ∀ (n : Nat), a (n++) = f n (a n)
f:Nat → Nat → Natc:Nat⊢ recurse f c 0 = c ∧ ∀ (n : Nat), recurse f c (n++) = f n (recurse f c n)f:Nat → Nat → Natc:Nat⊢ ∀ (y : Nat → Nat), (y 0 = c ∧ ∀ (n : Nat), y (n++) = f n (y n)) → y = recurse f c
f:Nat → Nat → Natc:Nat⊢ recurse f c 0 = c ∧ ∀ (n : Nat), recurse f c (n++) = f n (recurse f c n) f:Nat → Nat → Natc:Nat⊢ recurse f c 0 = cf:Nat → Nat → Natc:Nat⊢ ∀ (n : Nat), recurse f c (n++) = f n (recurse f c n) -- could also use `split_ands` or `and_intros` here
f:Nat → Nat → Natc:Nat⊢ recurse f c 0 = c All goals completed! 🐙
f:Nat → Nat → Natc:Nat⊢ ∀ (n : Nat), recurse f c (n++) = f n (recurse f c n) All goals completed! 🐙
f:Nat → Nat → Natc:Nata:Nat → Nat⊢ (a 0 = c ∧ ∀ (n : Nat), a (n++) = f n (a n)) → a = recurse f c
All goals completed! 🐙end Chapter2