--- Copyright (c) 2014 Floris van Doorn. All rights reserved. --- Released under Apache 2.0 license as described in the file LICENSE. --- Author: Floris van Doorn -- data.nat.basic -- ============== -- -- Basic operations on the natural numbers. import logic data.num tools.tactic algebra.binary tools.helper_tactics import logic.inhabited open tactic binary eq.ops open decidable open relation -- for subst_iff open helper_tactics -- Definition of the type -- ---------------------- inductive nat : Type := zero : nat, succ : nat → nat namespace nat notation `ℕ` := nat theorem rec_zero {P : ℕ → Type} (x : P zero) (f : ∀m, P m → P (succ m)) : nat.rec x f zero = x theorem rec_succ {P : ℕ → Type} (x : P zero) (f : ∀m, P m → P (succ m)) (n : ℕ) : nat.rec x f (succ n) = f n (nat.rec x f n) protected theorem induction_on {P : ℕ → Prop} (a : ℕ) (H1 : P zero) (H2 : ∀ (n : ℕ) (IH : P n), P (succ n)) : P a := nat.rec H1 H2 a protected definition rec_on {P : ℕ → Type} (n : ℕ) (H1 : P zero) (H2 : ∀m, P m → P (succ m)) : P n := nat.rec H1 H2 n protected definition is_inhabited [instance] : inhabited nat := inhabited.mk zero -- Coercion from num -- ----------------- definition add (x y : ℕ) : ℕ := nat.rec x (λ n r, succ r) y notation a + b := add a b definition of_num [coercion] [reducible] (n : num) : ℕ := num.rec zero (λ n, pos_num.rec (succ zero) (λ n r, r + r + (succ zero)) (λ n r, r + r) n) n -- Successor and predecessor -- ------------------------- theorem succ_ne_zero (n : ℕ) : succ n ≠ 0 := assume H : succ n = 0, have H2 : true = false, from let f := (nat.rec false (fun a b, true)) in calc true = f (succ n) : rfl ... = f 0 : {H} ... = false : rfl, absurd H2 true_ne_false -- add_rewrite succ_ne_zero definition pred (n : ℕ) := nat.rec 0 (fun m x, m) n theorem pred.zero : pred 0 = 0 theorem pred.succ (n : ℕ) : pred (succ n) = n irreducible pred theorem zero_or_succ_pred (n : ℕ) : n = 0 ∨ n = succ (pred n) := induction_on n (or.inl rfl) (take m IH, or.inr (show succ m = succ (pred (succ m)), from congr_arg succ !pred.succ⁻¹)) theorem zero_or_exists_succ (n : ℕ) : n = 0 ∨ ∃k, n = succ k := or.imp_or (zero_or_succ_pred n) (assume H, H) (assume H : n = succ (pred n), exists_intro (pred n) H) theorem case {P : ℕ → Prop} (n : ℕ) (H1: P 0) (H2 : ∀m, P (succ m)) : P n := induction_on n H1 (take m IH, H2 m) theorem discriminate {B : Prop} {n : ℕ} (H1: n = 0 → B) (H2 : ∀m, n = succ m → B) : B := or.elim (zero_or_succ_pred n) (take H3 : n = 0, H1 H3) (take H3 : n = succ (pred n), H2 (pred n) H3) theorem succ.inj {n m : ℕ} (H : succ n = succ m) : n = m := calc n = pred (succ n) : !pred.succ⁻¹ ... = pred (succ m) : {H} ... = m : !pred.succ theorem succ.ne_self {n : ℕ} : succ n ≠ n := induction_on n (take H : 1 = 0, have ne : 1 ≠ 0, from !succ_ne_zero, absurd H ne) (take k IH H, IH (succ.inj H)) protected definition has_decidable_eq [instance] : decidable_eq ℕ := take n m : ℕ, have general : ∀n, decidable (n = m), from rec_on m (take n, rec_on n (inl rfl) (λ m iH, inr !succ_ne_zero)) (λ (m' : ℕ) (iH1 : ∀n, decidable (n = m')), take n, rec_on n (inr (ne.symm !succ_ne_zero)) (λ (n' : ℕ) (iH2 : decidable (n' = succ m')), decidable.by_cases (assume Heq : n' = m', inl (congr_arg succ Heq)) (assume Hne : n' ≠ m', have H1 : succ n' ≠ succ m', from assume Heq, absurd (succ.inj Heq) Hne, inr H1))), general n theorem two_step_induction_on {P : ℕ → Prop} (a : ℕ) (H1 : P 0) (H2 : P 1) (H3 : ∀ (n : ℕ) (IH1 : P n) (IH2 : P (succ n)), P (succ (succ n))) : P a := have stronger : P a ∧ P (succ a), from induction_on a (and.intro H1 H2) (take k IH, have IH1 : P k, from and.elim_left IH, have IH2 : P (succ k), from and.elim_right IH, and.intro IH2 (H3 k IH1 IH2)), and.elim_left stronger theorem sub_induction {P : ℕ → ℕ → Prop} (n m : ℕ) (H1 : ∀m, P 0 m) (H2 : ∀n, P (succ n) 0) (H3 : ∀n m, P n m → P (succ n) (succ m)) : P n m := have general : ∀m, P n m, from induction_on n (take m : ℕ, H1 m) (take k : ℕ, assume IH : ∀m, P k m, take m : ℕ, discriminate (assume Hm : m = 0, Hm⁻¹ ▸ (H2 k)) (take l : ℕ, assume Hm : m = succ l, Hm⁻¹ ▸ (H3 k l (IH l)))), general m -- Addition -- -------- theorem add.zero_right (n : ℕ) : n + 0 = n theorem add.succ_right (n m : ℕ) : n + succ m = succ (n + m) irreducible add theorem add.zero_left (n : ℕ) : 0 + n = n := induction_on n !add.zero_right (take m IH, show 0 + succ m = succ m, from calc 0 + succ m = succ (0 + m) : !add.succ_right ... = succ m : {IH}) theorem add.succ_left (n m : ℕ) : (succ n) + m = succ (n + m) := induction_on m (!add.zero_right ▸ !add.zero_right) (take k IH, calc succ n + succ k = succ (succ n + k) : !add.succ_right ... = succ (succ (n + k)) : {IH} ... = succ (n + succ k) : {!add.succ_right⁻¹}) theorem add.comm (n m : ℕ) : n + m = m + n := induction_on m (!add.zero_right ⬝ !add.zero_left⁻¹) (take k IH, calc n + succ k = succ (n+k) : !add.succ_right ... = succ (k + n) : {IH} ... = succ k + n : !add.succ_left⁻¹) theorem add.move_succ (n m : ℕ) : succ n + m = n + succ m := !add.succ_left ⬝ !add.succ_right⁻¹ theorem add.comm_succ (n m : ℕ) : n + succ m = m + succ n := !add.move_succ⁻¹ ⬝ !add.comm theorem add.assoc (n m k : ℕ) : (n + m) + k = n + (m + k) := induction_on k (!add.zero_right ▸ !add.zero_right) (take l IH, calc (n + m) + succ l = succ ((n + m) + l) : !add.succ_right ... = succ (n + (m + l)) : {IH} ... = n + succ (m + l) : !add.succ_right⁻¹ ... = n + (m + succ l) : {!add.succ_right⁻¹}) theorem add.left_comm (n m k : ℕ) : n + (m + k) = m + (n + k) := left_comm @add.comm @add.assoc n m k theorem add.right_comm (n m k : ℕ) : n + m + k = n + k + m := right_comm @add.comm @add.assoc n m k -- ### cancelation theorem add.cancel_left {n m k : ℕ} : n + m = n + k → m = k := induction_on n (take H : 0 + m = 0 + k, !add.zero_left⁻¹ ⬝ H ⬝ !add.zero_left) (take (n : ℕ) (IH : n + m = n + k → m = k) (H : succ n + m = succ n + k), have H2 : succ (n + m) = succ (n + k), from calc succ (n + m) = succ n + m : !add.succ_left⁻¹ ... = succ n + k : H ... = succ (n + k) : !add.succ_left, have H3 : n + m = n + k, from succ.inj H2, IH H3) theorem add.cancel_right {n m k : ℕ} (H : n + m = k + m) : n = k := have H2 : m + n = m + k, from !add.comm ⬝ H ⬝ !add.comm, add.cancel_left H2 theorem add.eq_zero_left {n m : ℕ} : n + m = 0 → n = 0 := induction_on n (take (H : 0 + m = 0), rfl) (take k IH, assume H : succ k + m = 0, absurd (show succ (k + m) = 0, from calc succ (k + m) = succ k + m : !add.succ_left⁻¹ ... = 0 : H) !succ_ne_zero) theorem add.eq_zero_right {n m : ℕ} (H : n + m = 0) : m = 0 := add.eq_zero_left (!add.comm ⬝ H) theorem add.eq_zero {n m : ℕ} (H : n + m = 0) : n = 0 ∧ m = 0 := and.intro (add.eq_zero_left H) (add.eq_zero_right H) -- ### misc theorem add.one (n : ℕ) : n + 1 = succ n := !add.zero_right ▸ !add.succ_right theorem add.one_left (n : ℕ) : 1 + n = succ n := !add.zero_left ▸ !add.succ_left -- TODO: rename? remove? theorem induction_plus_one {P : nat → Prop} (a : ℕ) (H1 : P 0) (H2 : ∀ (n : ℕ) (IH : P n), P (n + 1)) : P a := nat.rec H1 (take n IH, !add.one ▸ (H2 n IH)) a -- Multiplication -- -------------- definition mul (n m : ℕ) := nat.rec 0 (fun m x, x + n) m notation a * b := mul a b theorem mul.zero_right (n : ℕ) : n * 0 = 0 theorem mul.succ_right (n m : ℕ) : n * succ m = n * m + n irreducible mul -- ### commutativity, distributivity, associativity, identity theorem mul.zero_left (n : ℕ) : 0 * n = 0 := induction_on n !mul.zero_right (take m IH, !mul.succ_right ⬝ !add.zero_right ⬝ IH) theorem mul.succ_left (n m : ℕ) : (succ n) * m = (n * m) + m := induction_on m (!mul.zero_right ⬝ !mul.zero_right⁻¹ ⬝ !add.zero_right⁻¹) (take k IH, calc succ n * succ k = (succ n * k) + succ n : !mul.succ_right ... = (n * k) + k + succ n : {IH} ... = (n * k) + (k + succ n) : !add.assoc ... = (n * k) + (n + succ k) : {!add.comm_succ} ... = (n * k) + n + succ k : !add.assoc⁻¹ ... = (n * succ k) + succ k : {!mul.succ_right⁻¹}) theorem mul.comm (n m : ℕ) : n * m = m * n := induction_on m (!mul.zero_right ⬝ !mul.zero_left⁻¹) (take k IH, calc n * succ k = n * k + n : !mul.succ_right ... = k * n + n : {IH} ... = (succ k) * n : !mul.succ_left⁻¹) theorem mul.distr_right (n m k : ℕ) : (n + m) * k = n * k + m * k := induction_on k (calc (n + m) * 0 = 0 : !mul.zero_right ... = 0 + 0 : !add.zero_right⁻¹ ... = n * 0 + 0 : {!mul.zero_right⁻¹} ... = n * 0 + m * 0 : {!mul.zero_right⁻¹}) (take l IH, calc (n + m) * succ l = (n + m) * l + (n + m) : !mul.succ_right ... = n * l + m * l + (n + m) : {IH} ... = n * l + m * l + n + m : !add.assoc⁻¹ ... = n * l + n + m * l + m : {!add.right_comm} ... = n * l + n + (m * l + m) : !add.assoc ... = n * succ l + (m * l + m) : {!mul.succ_right⁻¹} ... = n * succ l + m * succ l : {!mul.succ_right⁻¹}) theorem mul.distr_left (n m k : ℕ) : n * (m + k) = n * m + n * k := calc n * (m + k) = (m + k) * n : !mul.comm ... = m * n + k * n : !mul.distr_right ... = n * m + k * n : {!mul.comm} ... = n * m + n * k : {!mul.comm} theorem mul.assoc (n m k : ℕ) : (n * m) * k = n * (m * k) := induction_on k (calc (n * m) * 0 = 0 : !mul.zero_right ... = n * 0 : !mul.zero_right⁻¹ ... = n * (m * 0) : {!mul.zero_right⁻¹}) (take l IH, calc (n * m) * succ l = (n * m) * l + n * m : !mul.succ_right ... = n * (m * l) + n * m : {IH} ... = n * (m * l + m) : !mul.distr_left⁻¹ ... = n * (m * succ l) : {!mul.succ_right⁻¹}) theorem mul.left_comm (n m k : ℕ) : n * (m * k) = m * (n * k) := left_comm mul.comm mul.assoc n m k theorem mul.right_comm (n m k : ℕ) : n * m * k = n * k * m := right_comm mul.comm mul.assoc n m k theorem mul.one_right (n : ℕ) : n * 1 = n := calc n * 1 = n * 0 + n : !mul.succ_right ... = 0 + n : {!mul.zero_right} ... = n : !add.zero_left theorem mul.one_left (n : ℕ) : 1 * n = n := calc 1 * n = n * 1 : !mul.comm ... = n : !mul.one_right theorem mul.eq_zero {n m : ℕ} (H : n * m = 0) : n = 0 ∨ m = 0 := discriminate (take Hn : n = 0, or.inl Hn) (take (k : ℕ), assume (Hk : n = succ k), discriminate (take (Hm : m = 0), or.inr Hm) (take (l : ℕ), assume (Hl : m = succ l), have Heq : succ (k * succ l + l) = n * m, from (calc n * m = n * succ l : {Hl} ... = succ k * succ l : {Hk} ... = k * succ l + succ l : !mul.succ_left ... = succ (k * succ l + l) : !add.succ_right)⁻¹, absurd (Heq ⬝ H) !succ_ne_zero)) end nat