lean2/library/data/int/gcd.lean

294 lines
12 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2014 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Leonardo de Moura
Definitions and properties of gcd, lcm, and coprime.
-/
import .div data.nat.gcd
open eq.ops
namespace int
/- gcd -/
definition gcd (a b : ) : := of_nat (nat.gcd (nat_abs a) (nat_abs b))
theorem gcd_nonneg (a b : ) : gcd a b ≥ 0 :=
of_nat_nonneg (nat.gcd (nat_abs a) (nat_abs b))
theorem gcd.comm (a b : ) : gcd a b = gcd b a :=
by rewrite [↑gcd, nat.gcd.comm]
theorem gcd_zero_right (a : ) : gcd a 0 = abs a :=
by krewrite [↑gcd, nat.gcd_zero_right, of_nat_nat_abs]
theorem gcd_zero_left (a : ) : gcd 0 a = abs a :=
by rewrite [gcd.comm, gcd_zero_right]
theorem gcd_one_right (a : ) : gcd a 1 = 1 :=
by krewrite [↑gcd, nat.gcd_one_right]
theorem gcd_one_left (a : ) : gcd 1 a = 1 :=
by rewrite [gcd.comm, gcd_one_right]
theorem gcd_abs_left (a b : ) : gcd (abs a) b = gcd a b :=
by rewrite [↑gcd, *nat_abs_abs]
theorem gcd_abs_right (a b : ) : gcd (abs a) b = gcd a b :=
by rewrite [↑gcd, *nat_abs_abs]
theorem gcd_abs_abs (a b : ) : gcd (abs a) (abs b) = gcd a b :=
by rewrite [↑gcd, *nat_abs_abs]
theorem gcd_of_ne_zero (a : ) {b : } (H : b ≠ 0) : gcd a b = gcd b (abs a mod abs b) :=
have H1 : nat_abs b ≠ nat.zero, from assume H', H (nat_abs_eq_zero H'),
have H2 : (#nat nat_abs b > nat.zero), from nat.pos_of_ne_zero H1,
assert H3 : nat.gcd (nat_abs a) (nat_abs b) = (#nat nat.gcd (nat_abs b) (nat_abs a mod nat_abs b)),
from @nat.gcd_of_pos (nat_abs a) (nat_abs b) H2,
calc
gcd a b = nat.gcd (nat_abs b) (#nat nat_abs a mod nat_abs b) : by rewrite [↑gcd, H3]
... = gcd (abs b) (abs a mod abs b) :
by rewrite [↑gcd, -*of_nat_nat_abs, of_nat_mod_of_nat]
... = gcd b (abs a mod abs b) : by rewrite [↑gcd, *nat_abs_abs]
theorem gcd_of_pos (a : ) {b : } (H : b > 0) : gcd a b = gcd b (abs a mod b) :=
by rewrite [!gcd_of_ne_zero (ne_of_gt H), abs_of_pos H]
theorem gcd_of_nonneg_of_pos {a b : } (H1 : a ≥ 0) (H2 : b > 0) : gcd a b = gcd b (a mod b) :=
by rewrite [!gcd_of_pos H2, abs_of_nonneg H1]
theorem gcd_self (a : ) : gcd a a = abs a :=
by rewrite [↑gcd, nat.gcd_self, of_nat_nat_abs]
theorem gcd_dvd_left (a b : ) : gcd a b a :=
have H : gcd a b abs a,
by rewrite [↑gcd, -of_nat_nat_abs, of_nat_dvd_of_nat]; apply nat.gcd_dvd_left,
iff.mp !dvd_abs_iff H
theorem gcd_dvd_right (a b : ) : gcd a b b :=
by rewrite gcd.comm; apply gcd_dvd_left
theorem dvd_gcd {a b c : } : a b → a c → a gcd b c :=
begin
rewrite [↑gcd, -*(abs_dvd_iff a), -(dvd_abs_iff _ b), -(dvd_abs_iff _ c), -*of_nat_nat_abs],
rewrite [*of_nat_dvd_of_nat] ,
apply nat.dvd_gcd
end
theorem gcd.assoc (a b c : ) : gcd (gcd a b) c = gcd a (gcd b c) :=
dvd.antisymm !gcd_nonneg !gcd_nonneg
(dvd_gcd
(dvd.trans !gcd_dvd_left !gcd_dvd_left)
(dvd_gcd (dvd.trans !gcd_dvd_left !gcd_dvd_right) !gcd_dvd_right))
(dvd_gcd
(dvd_gcd !gcd_dvd_left (dvd.trans !gcd_dvd_right !gcd_dvd_left))
(dvd.trans !gcd_dvd_right !gcd_dvd_right))
theorem gcd_mul_left (a b c : ) : gcd (a * b) (a * c) = abs a * gcd b c :=
by rewrite [↑gcd, *nat_abs_mul, nat.gcd_mul_left, of_nat_mul, of_nat_nat_abs]
theorem gcd_mul_right (a b c : ) : gcd (a * b) (c * b) = gcd a c * abs b :=
by rewrite [mul.comm a, mul.comm c, mul.comm (gcd a c), gcd_mul_left]
theorem gcd_pos_of_ne_zero_left {a : } (b : ) (H : a ≠ 0) : gcd a b > 0 :=
have H1 : gcd a b ≠ 0, from
assume H2 : gcd a b = 0,
have H3: 0 a, from H2 ▸ gcd_dvd_left a b,
show false, from H (eq_zero_of_zero_dvd H3),
lt_of_le_of_ne (gcd_nonneg a b) (ne.symm H1)
theorem gcd_pos_of_ne_zero_right (a : ) {b : } (H : b ≠ 0) : gcd a b > 0 :=
by rewrite gcd.comm; apply !gcd_pos_of_ne_zero_left H
theorem eq_zero_of_gcd_eq_zero_left {a b : } (H : gcd a b = 0) : a = 0 :=
decidable.by_contradiction
(assume H1 : a ≠ 0,
have H2 : gcd a b > 0, from !gcd_pos_of_ne_zero_left H1,
ne_of_lt H2 H⁻¹)
theorem eq_zero_of_gcd_eq_zero_right {a b : } (H : gcd a b = 0) : b = 0 :=
by rewrite gcd.comm at H; apply !eq_zero_of_gcd_eq_zero_left H
theorem gcd_div {a b c : } (H1 : c a) (H2 : c b) :
gcd (a div c) (b div c) = gcd a b div (abs c) :=
decidable.by_cases
(assume H3 : c = 0,
calc
gcd (a div c) (b div c) = gcd 0 0 : by subst c; rewrite *div_zero
... = 0 : gcd_zero_left
... = gcd a b div 0 : div_zero
... = gcd a b div (abs c) : by subst c)
(assume H3 : c ≠ 0,
have H4 : abs c ≠ 0, from assume H', H3 (eq_zero_of_abs_eq_zero H'),
eq.symm (div_eq_of_eq_mul_left H4
(eq.symm (calc
gcd (a div c) (b div c) * abs c = gcd (a div c * c) (b div c * c) : gcd_mul_right
... = gcd a (b div c * c) : div_mul_cancel H1
... = gcd a b : div_mul_cancel H2))))
theorem gcd_dvd_gcd_mul_left (a b c : ) : gcd a b gcd (c * a) b :=
dvd_gcd (dvd.trans !gcd_dvd_left !dvd_mul_left) !gcd_dvd_right
theorem gcd_dvd_gcd_mul_right (a b c : ) : gcd a b gcd (a * c) b :=
!mul.comm ▸ !gcd_dvd_gcd_mul_left
/- lcm -/
definition lcm (a b : ) : := of_nat (nat.lcm (nat_abs a) (nat_abs b))
theorem lcm_nonneg (a b : ) : lcm a b ≥ 0 :=
of_nat_nonneg (nat.lcm (nat_abs a) (nat_abs b))
theorem lcm.comm (a b : ) : lcm a b = lcm b a :=
by rewrite [↑lcm, nat.lcm.comm]
theorem lcm_zero_left (a : ) : lcm 0 a = 0 :=
by krewrite [↑lcm, nat.lcm_zero_left]
theorem lcm_zero_right (a : ) : lcm a 0 = 0 :=
!lcm.comm ▸ !lcm_zero_left
theorem lcm_one_left (a : ) : lcm 1 a = abs a :=
by krewrite [↑lcm, nat.lcm_one_left, of_nat_nat_abs]
theorem lcm_one_right (a : ) : lcm a 1 = abs a :=
!lcm.comm ▸ !lcm_one_left
theorem lcm_abs_left (a b : ) : lcm (abs a) b = lcm a b :=
by rewrite [↑lcm, *nat_abs_abs]
theorem lcm_abs_right (a b : ) : lcm (abs a) b = lcm a b :=
by rewrite [↑lcm, *nat_abs_abs]
theorem lcm_abs_abs (a b : ) : lcm (abs a) (abs b) = lcm a b :=
by rewrite [↑lcm, *nat_abs_abs]
theorem lcm_self (a : ) : lcm a a = abs a :=
by krewrite [↑lcm, nat.lcm_self, of_nat_nat_abs]
theorem dvd_lcm_left (a b : ) : a lcm a b :=
by rewrite [↑lcm, -abs_dvd_iff, -of_nat_nat_abs, of_nat_dvd_of_nat]; apply nat.dvd_lcm_left
theorem dvd_lcm_right (a b : ) : b lcm a b :=
!lcm.comm ▸ !dvd_lcm_left
theorem gcd_mul_lcm (a b : ) : gcd a b * lcm a b = abs (a * b) :=
begin
rewrite [↑gcd, ↑lcm, -of_nat_nat_abs, -of_nat_mul, of_nat_eq_of_nat, nat_abs_mul],
apply nat.gcd_mul_lcm
end
theorem lcm_dvd {a b c : } : a c → b c → lcm a b c :=
begin
rewrite [↑lcm, -(abs_dvd_iff a), -(abs_dvd_iff b), -*(dvd_abs_iff _ c), -*of_nat_nat_abs],
rewrite [*of_nat_dvd_of_nat] ,
apply nat.lcm_dvd
end
theorem lcm_assoc (a b c : ) : lcm (lcm a b) c = lcm a (lcm b c) :=
dvd.antisymm !lcm_nonneg !lcm_nonneg
(lcm_dvd
(lcm_dvd !dvd_lcm_left (dvd.trans !dvd_lcm_left !dvd_lcm_right))
(dvd.trans !dvd_lcm_right !dvd_lcm_right))
(lcm_dvd
(dvd.trans !dvd_lcm_left !dvd_lcm_left)
(lcm_dvd (dvd.trans !dvd_lcm_right !dvd_lcm_left) !dvd_lcm_right))
/- coprime -/
abbreviation coprime (a b : ) : Prop := gcd a b = 1
theorem coprime_swap {a b : } (H : coprime b a) : coprime a b :=
!gcd.comm ▸ H
theorem dvd_of_coprime_of_dvd_mul_right {a b c : } (H1 : coprime c b) (H2 : c a * b) : c a :=
assert H3 : gcd (a * c) (a * b) = abs a, from
calc
gcd (a * c) (a * b) = abs a * gcd c b : gcd_mul_left
... = abs a * 1 : H1
... = abs a : mul_one,
assert H4 : (c gcd (a * c) (a * b)), from dvd_gcd !dvd_mul_left H2,
by rewrite [-dvd_abs_iff, -H3]; apply H4
theorem dvd_of_coprime_of_dvd_mul_left {a b c : } (H1 : coprime c a) (H2 : c a * b) : c b :=
dvd_of_coprime_of_dvd_mul_right H1 (!mul.comm ▸ H2)
theorem gcd_mul_left_cancel_of_coprime {c : } (a : ) {b : } (H : coprime c b) :
gcd (c * a) b = gcd a b :=
begin
revert H, rewrite [↑coprime, ↑gcd, *of_nat_eq_of_nat, nat_abs_mul],
apply nat.gcd_mul_left_cancel_of_coprime
end
theorem gcd_mul_right_cancel_of_coprime (a : ) {c b : } (H : coprime c b) :
gcd (a * c) b = gcd a b :=
!mul.comm ▸ !gcd_mul_left_cancel_of_coprime H
theorem gcd_mul_left_cancel_of_coprime_right {c a : } (b : ) (H : coprime c a) :
gcd a (c * b) = gcd a b :=
!gcd.comm ▸ !gcd.comm ▸ !gcd_mul_left_cancel_of_coprime H
theorem gcd_mul_right_cancel_of_coprime_right {c a : } (b : ) (H : coprime c a) :
gcd a (b * c) = gcd a b :=
!gcd.comm ▸ !gcd.comm ▸ !gcd_mul_right_cancel_of_coprime H
theorem coprime_div_gcd_div_gcd {a b : } (H : gcd a b ≠ 0) :
coprime (a div gcd a b) (b div gcd a b) :=
calc
gcd (a div gcd a b) (b div gcd a b)
= gcd a b div abs (gcd a b) : gcd_div !gcd_dvd_left !gcd_dvd_right
... = 1 : by rewrite [abs_of_nonneg !gcd_nonneg, div_self H]
theorem exists_coprime {a b : } (H : gcd a b ≠ 0) :
exists a' b', coprime a' b' ∧ a = a' * gcd a b ∧ b = b' * gcd a b :=
have H1 : a = (a div gcd a b) * gcd a b, from (div_mul_cancel !gcd_dvd_left)⁻¹,
have H2 : b = (b div gcd a b) * gcd a b, from (div_mul_cancel !gcd_dvd_right)⁻¹,
exists.intro _ (exists.intro _ (and.intro (coprime_div_gcd_div_gcd H) (and.intro H1 H2)))
theorem coprime_mul {a b c : } (H1 : coprime a c) (H2 : coprime b c) : coprime (a * b) c :=
calc
gcd (a * b) c = gcd b c : !gcd_mul_left_cancel_of_coprime H1
... = 1 : H2
theorem coprime_mul_right {c a b : } (H1 : coprime c a) (H2 : coprime c b) : coprime c (a * b) :=
coprime_swap (coprime_mul (coprime_swap H1) (coprime_swap H2))
theorem coprime_of_coprime_mul_left {c a b : } (H : coprime (c * a) b) : coprime a b :=
have H1 : (gcd a b gcd (c * a) b), from !gcd_dvd_gcd_mul_left,
eq_one_of_dvd_one !gcd_nonneg (H ▸ H1)
theorem coprime_of_coprime_mul_right {c a b : } (H : coprime (a * c) b) : coprime a b :=
coprime_of_coprime_mul_left (!mul.comm ▸ H)
theorem coprime_of_coprime_mul_left_right {c a b : } (H : coprime a (c * b)) : coprime a b :=
coprime_swap (coprime_of_coprime_mul_left (coprime_swap H))
theorem coprime_of_coprime_mul_right_right {c a b : } (H : coprime a (b * c)) : coprime a b :=
coprime_of_coprime_mul_left_right (!mul.comm ▸ H)
theorem exists_eq_prod_and_dvd_and_dvd {a b c} (H : c a * b) :
∃ a' b', c = a' * b' ∧ a' a ∧ b' b :=
decidable.by_cases
(assume H1 : gcd c a = 0,
have H2 : c = 0, from eq_zero_of_gcd_eq_zero_left H1,
have H3 : a = 0, from eq_zero_of_gcd_eq_zero_right H1,
have H4 : c = 0 * b, from H2 ⬝ !zero_mul⁻¹,
have H5 : 0 a, from H3⁻¹ ▸ !dvd.refl,
have H6 : b b, from !dvd.refl,
exists.intro _ (exists.intro _ (and.intro H4 (and.intro H5 H6))))
(assume H1 : gcd c a ≠ 0,
have H2 : gcd c a c, from !gcd_dvd_left,
have H3 : c div gcd c a (a * b) div gcd c a, from div_dvd_div H2 H,
have H4 : (a * b) div gcd c a = (a div gcd c a) * b, from
calc
a * b div gcd c a = b * a div gcd c a : mul.comm
... = b * (a div gcd c a) : !mul_div_assoc !gcd_dvd_right
... = a div gcd c a * b : mul.comm,
have H5 : c div gcd c a (a div gcd c a) * b, from H4 ▸ H3,
have H6 : coprime (c div gcd c a) (a div gcd c a), from coprime_div_gcd_div_gcd H1,
have H7 : c div gcd c a b, from dvd_of_coprime_of_dvd_mul_left H6 H5,
have H8 : c = gcd c a * (c div gcd c a), from (mul_div_cancel' H2)⁻¹,
exists.intro _ (exists.intro _ (and.intro H8 (and.intro !gcd_dvd_right H7))))
end int