Multiplication

Analysis I, Section 2.3: Multiplication

This file is a translation of Section 2.3 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 multiplication and exponentiation for the "Chapter 2" natural numbers, Chapter2.Nat : TypeChapter2.Nat.

Note: at the end of this chapter, the Chapter2.Nat : TypeChapter2.Nat class will be deprecated in favor of the standard Mathlib class Nat : Type_root_.Nat, or : Type. However, we will develop the properties of Chapter2.Nat : TypeChapter2.Nat "by hand" for pedagogical purposes.

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)

namespace Chapter2

Definition 2.3.1 (Multiplication of natural numbers)

abbrev Nat.mul (n m : Nat) : Nat := Nat.recurse (fun _ prod prod + m) 0 n

This instance allows for the notation to be used for natural number multiplication.

instance Nat.instMul : Mul Nat where mul := mul

Definition 2.3.1 (Multiplication of natural numbers) Compare with Mathlib's Chapter2.Nat.zero_mul (m : Nat) : 0 * m = 0Nat.zero_mul

theorem Nat.zero_mul (m: Nat) : 0 * m = 0 := recurse_zero (fun _ prod prod+m) _

Definition 2.3.1 (Multiplication of natural numbers) Compare with Mathlib's Chapter2.Nat.succ_mul (n m : Nat) : n++ * m = n * m + mNat.succ_mul

theorem Nat.succ_mul (n m: Nat) : (n++) * m = n * m + m := recurse_succ (fun _ prod prod+m) _ _
theorem Nat.one_mul' (m: Nat) : 1 * m = 0 + m := m:Nat1 * m = 0 + m All goals completed! 🐙

Compare with Mathlib's Chapter2.Nat.one_mul (m : Nat) : 1 * m = mNat.one_mul

theorem Nat.one_mul (m: Nat) : 1 * m = m := m:Nat1 * m = m All goals completed! 🐙
theorem Nat.two_mul (m: Nat) : 2 * m = 0 + m + m := m:Nat2 * m = 0 + m + m All goals completed! 🐙

This lemma will be useful to prove Lemma 2.3.2. Compare with Mathlib's Chapter2.Nat.mul_zero (n : Nat) : n * 0 = 0Nat.mul_zero

lemma declaration uses 'sorry'Nat.mul_zero (n: Nat) : n * 0 = 0 := n:Natn * 0 = 0 All goals completed! 🐙

This lemma will be useful to prove Lemma 2.3.2. Compare with Mathlib's Chapter2.Nat.mul_succ (n m : Nat) : n * m++ = n * m + nNat.mul_succ

lemma declaration uses 'sorry'Nat.mul_succ (n m:Nat) : n * m++ = n * m + n := n:Natm:Natn * m++ = n * m + n All goals completed! 🐙

Lemma 2.3.2 (Multiplication is commutative) / Exercise 2.3.1 Compare with Mathlib's Chapter2.Nat.mul_comm (n m : Nat) : n * m = m * nNat.mul_comm

lemma declaration uses 'sorry'Nat.mul_comm (n m: Nat) : n * m = m * n := n:Natm:Natn * m = m * n All goals completed! 🐙

Compare with Mathlib's Chapter2.Nat.mul_one (m : Nat) : m * 1 = mNat.mul_one

theorem Nat.mul_one (m: Nat) : m * 1 = m := m:Natm * 1 = m All goals completed! 🐙

This lemma will be useful to prove Lemma 2.3.3. Compare with Mathlib's Nat.mul_pos {n m : } (ha : n > 0) (hb : m > 0) : n * m > 0Nat.mul_pos

lemma declaration uses 'sorry'Nat.pos_mul_pos {n m: Nat} (h₁: n.IsPos) (h₂: m.IsPos) : (n * m).IsPos := n:Natm:Nath₁:n.IsPosh₂:m.IsPos(n * m).IsPos All goals completed! 🐙

Lemma 2.3.3 (Positive natural numbers have no zero divisors) / Exercise 2.3.2. Compare with Mathlib's Chapter2.Nat.mul_eq_zero (n m : Nat) : n * m = 0 n = 0 m = 0Nat.mul_eq_zero.

lemma declaration uses 'sorry'Nat.mul_eq_zero (n m: Nat) : n * m = 0 n = 0 m = 0 := n:Natm:Natn * m = 0 n = 0 m = 0 All goals completed! 🐙

Proposition 2.3.4 (Distributive law) Compare with Mathlib's Chapter2.Nat.mul_add (a b c : Nat) : a * (b + c) = a * b + a * cNat.mul_add

theorem Nat.mul_add (a b c: Nat) : a * (b + c) = a * b + a * c := a:Natb:Natc:Nata * (b + c) = a * b + a * c -- This proof is written to follow the structure of the original text. a:Natb:Nat (c : Nat), a * (b + c) = a * b + a * c; a:Natb:Nata * (b + 0) = a * b + a * 0a:Natb:Nat (n : Nat), a * (b + n) = a * b + a * n a * (b + n++) = a * b + a * n++ a:Natb:Nata * (b + 0) = a * b + a * 0 a:Natb:Nata * b = a * b + a * 0 All goals completed! 🐙 a:Natb:Natc:Nathabc:a * (b + c) = a * b + a * ca * (b + c++) = a * b + a * c++ a:Natb:Natc:Nathabc:a * (b + c) = a * b + a * ca * (b + c) + a = a * b + a * c++ All goals completed! 🐙

Proposition 2.3.4 (Distributive law) Compare with Mathlib's Chapter2.Nat.add_mul (a b c : Nat) : (a + b) * c = a * c + b * cNat.add_mul

theorem Nat.add_mul (a b c: Nat) : (a + b)*c = a*c + b*c := a:Natb:Natc:Nat(a + b) * c = a * c + b * c All goals completed! 🐙

Proposition 2.3.5 (Multiplication is associative) / Exercise 2.3.3 Compare with Mathlib's Chapter2.Nat.mul_assoc (a b c : Nat) : a * b * c = a * (b * c)Nat.mul_assoc

theorem declaration uses 'sorry'Nat.mul_assoc (a b c: Nat) : (a * b) * c = a * (b * c) := a:Natb:Natc:Nata * b * c = a * (b * c) All goals completed! 🐙

(Not from textbook) Nat is a commutative semiring. This allows tactics such as Unknown identifier `ring`ring to apply to the Chapter 2 natural numbers.

instance Nat.instCommSemiring : CommSemiring Nat where left_distrib := mul_add right_distrib := add_mul zero_mul := zero_mul mul_zero := mul_zero mul_assoc := mul_assoc one_mul := one_mul mul_one := mul_one mul_comm := mul_comm

This illustration of the Unknown identifier `ring`ring tactic is not from the textbook.

example (a b c d:) : (a+b)*1*(c+d) = d*b+a*c+c*b+a*d+0 := a:b:c:d:(a + b) * 1 * (c + d) = d * b + a * c + c * b + a * d + 0 All goals completed! 🐙

Proposition 2.3.6 (Multiplication preserves order) Compare with Mathlib's Chapter2.Nat.mul_lt_mul_of_pos_right {a b c : Nat} (h : a < b) (hc : c.IsPos) : a * c < b * cNat.mul_lt_mul_of_pos_right

theorem Nat.mul_lt_mul_of_pos_right {a b c: Nat} (h: a < b) (hc: c.IsPos) : a * c < b * c := a:Natb:Natc:Nath:a < bhc:c.IsPosa * c < b * c -- This proof is written to follow the structure of the original text. a:Natb:Natc:Nath: d, d.IsPos b = a + dhc:c.IsPosa * c < b * c a:Natb:Natc:Nathc:c.IsPosd:Nathdpos:d.IsPoshd:b = a + da * c < b * c a:Natb:Natc:Nathc:c.IsPosd:Nathdpos:d.IsPoshd:?_mvar.4948 := id (congrArg (fun x => x * _fvar.4891) _fvar.4944)a * c < b * c a:Natb:Natc:Nathc:c.IsPosd:Nathdpos:d.IsPoshd:b * c = a * c + d * ca * c < b * c a:Natb:Natc:Nathc:c.IsPosd:Nathdpos:d.IsPoshd:b * c = a * c + d * chdcpos:Chapter2.Nat.IsPos (_fvar.4931 * _fvar.4891) := Chapter2.Nat.pos_mul_pos _fvar.4940 _fvar.4916a * c < b * c a:Natb:Natc:Nathc:c.IsPosd:Nathdpos:d.IsPoshd:b * c = a * c + d * chdcpos:Chapter2.Nat.IsPos (_fvar.4931 * _fvar.4891) := Chapter2.Nat.pos_mul_pos _fvar.4940 _fvar.4916 d, d.IsPos b * c = a * c + d All goals completed! 🐙

Proposition 2.3.6 (Multiplication preserves order)

theorem Nat.mul_gt_mul_of_pos_right {a b c: Nat} (h: a > b) (hc: c.IsPos) : a * c > b * c := mul_lt_mul_of_pos_right h hc

Proposition 2.3.6 (Multiplication preserves order) Compare with Mathlib's Chapter2.Nat.mul_lt_mul_of_pos_left {a b c : Nat} (h : a < b) (hc : c.IsPos) : c * a < c * bNat.mul_lt_mul_of_pos_left

theorem Nat.mul_lt_mul_of_pos_left {a b c: Nat} (h: a < b) (hc: c.IsPos) : c * a < c * b := a:Natb:Natc:Nath:a < bhc:c.IsPosc * a < c * b a:Natb:Natc:Nath:a < bhc:c.IsPosa * c < b * c All goals completed! 🐙

Proposition 2.3.6 (Multiplication preserves order)

theorem Nat.mul_gt_mul_of_pos_left {a b c: Nat} (h: a > b) (hc: c.IsPos) : c * a > c * b := mul_lt_mul_of_pos_left h hc

Corollary 2.3.7 (Cancellation law) Compare with Mathlib's Nat.mul_right_cancel {n m k : } (mp : 0 < m) (h : n * m = k * m) : n = kNat.mul_right_cancel

lemma Nat.mul_cancel_right {a b c: Nat} (h: a * c = b * c) (hc: c.IsPos) : a = b := a:Natb:Natc:Nath:a * c = b * chc:c.IsPosa = b -- This proof is written to follow the structure of the original text. a:Natb:Natc:Nath:a * c = b * chc:c.IsPosthis:?_mvar.11884 := Chapter2.Nat.trichotomous _fvar.11877 _fvar.11878a = b a:Natb:Natc:Nath:a * c = b * chc:c.IsPoshlt:a < ba = ba:Natc:Nathc:c.IsPosh:a * c = a * ca = aa:Natb:Natc:Nath:a * c = b * chc:c.IsPoshgt:a > ba = b a:Natb:Natc:Nath:a * c = b * chc:c.IsPoshlt:a < ba = b a:Natb:Natc:Nath:a * c = b * chc:c.IsPoshlt:?_mvar.11956 := Chapter2.Nat.mul_lt_mul_of_pos_right _fvar.11911 _fvar.11881a = b a:Natb:Natc:Nath:a * c = b * chc:c.IsPoshlt:a * c b * ca = b All goals completed! 🐙 a:Natc:Nathc:c.IsPosh:a * c = a * ca = a All goals completed! 🐙 a:Natb:Natc:Nath:a * c = b * chc:c.IsPoshgt:?_mvar.12001 := Chapter2.Nat.mul_gt_mul_of_pos_right _fvar.11939 _fvar.11881a = b a:Natb:Natc:Nath:a * c = b * chc:c.IsPoshgt:a * c b * ca = b All goals completed! 🐙

(Not from textbook) Nat is an ordered semiring. This allows tactics such as Unknown identifier `gcongr`gcongr to apply to the Chapter 2 natural numbers.

instance declaration uses 'sorry'Nat.isOrderedRing : IsOrderedRing Nat where zero_le_one := 0 1 All goals completed! 🐙 mul_le_mul_of_nonneg_left := (a b c : Nat), a b 0 c c * a c * b All goals completed! 🐙 mul_le_mul_of_nonneg_right := (a b c : Nat), a b 0 c a * c b * c All goals completed! 🐙

This illustration of the Unknown identifier `gcongr`gcongr tactic is not from the textbook.

example (a b c d:Nat) (hab: a b) : c*a*d c*b*d := a:Natb:Natc:Natd:Nathab:a bc * a * d c * b * d a:Natb:Natc:Natd:Nathab:a b0 da:Natb:Natc:Natd:Nathab:a b0 c a:Natb:Natc:Natd:Nathab:a b0 d All goals completed! 🐙 All goals completed! 🐙

Proposition 2.3.9 (Euclid's division lemma) / Exercise 2.3.5 Compare with Mathlib's Nat.mod_eq_iff {a b c : } : a % b = c b = 0 a = c c < b k, a = b * k + cNat.mod_eq_iff

theorem declaration uses 'sorry'Nat.exists_div_mod (n:Nat) {q: Nat} (hq: q.IsPos) : m r: Nat, 0 r r < q n = m * q + r := n:Natq:Nathq:q.IsPos m r, 0 r r < q n = m * q + r All goals completed! 🐙

Definition 2.3.11 (Exponentiation for natural numbers)

abbrev Nat.pow (m n: Nat) : Nat := Nat.recurse (fun _ prod prod * m) 1 n
instance Nat.instPow : HomogeneousPow Nat where pow := Nat.pow

Definition 2.3.11 (Exponentiation for natural numbers) Compare with Mathlib's Chapter2.Nat.pow_zero (m : Nat) : m ^ 0 = 1Nat.pow_zero

@[simp] theorem Nat.pow_zero (m: Nat) : m ^ (0:Nat) = 1 := recurse_zero (fun _ prod prod * m) _

Definition 2.3.11 (Exponentiation for natural numbers)

@[simp] theorem Nat.zero_pow_zero : (0:Nat) ^ 0 = 1 := recurse_zero (fun _ prod prod * 0) _

Definition 2.3.11 (Exponentiation for natural numbers) Compare with Mathlib's Chapter2.Nat.pow_succ (m n : Nat) : m ^ n++ = m ^ n * mNat.pow_succ

theorem Nat.pow_succ (m n: Nat) : (m:Nat) ^ n++ = m^n * m := recurse_succ (fun _ prod prod * m) _ _

Compare with Mathlib's Chapter2.Nat.pow_one (m : Nat) : m ^ 1 = mNat.pow_one

@[simp] theorem Nat.pow_one (m: Nat) : m ^ (1:Nat) = m := m:Natm ^ 1 = m m:Natm ^ 0 * m = m; All goals completed! 🐙

Exercise 2.3.4

theorem declaration uses 'sorry'Nat.sq_add_eq (a b: Nat) : (a + b) ^ (2 : Nat) = a ^ (2 : Nat) + 2 * a * b + b ^ (2 : Nat) := a:Natb:Nat(a + b) ^ 2 = a ^ 2 + 2 * a * b + b ^ 2 All goals completed! 🐙
end Chapter2