@@ -3,13 +3,101 @@ Copyright (c) 2018 Guy Leroy. All rights reserved.
3
3
Released under Apache 2.0 license as described in the file LICENSE.
4
4
Authors: Sangwoo Jo (aka Jason), Guy Leroy
5
5
6
- Lemmas and extended definitions and properties of gcd and lcm for integers.
6
+ Greatest common divisor (gcd) and least common multiple ( lcm) for integers.
7
7
-/
8
+ import data.int.basic data.nat.prime
8
9
9
- import data.int.basic data.nat.basic data.nat.gcd
10
+ /- extended euclidean algorithm -/
11
+ namespace nat
12
+
13
+ def xgcd_aux : ℕ → ℤ → ℤ → ℕ → ℤ → ℤ → ℕ × ℤ × ℤ
14
+ | 0 s t r' s' t' := (r', s', t')
15
+ | r@(succ _) s t r' s' t' :=
16
+ have r' % r < r, from mod_lt _ $ succ_pos _,
17
+ let q := r' / r in xgcd_aux (r' % r) (s' - q * s) (t' - q * t) r s t
18
+
19
+ @[simp] theorem xgcd_zero_left {s t r' s' t'} : xgcd_aux 0 s t r' s' t' = (r', s', t') :=
20
+ by simp [xgcd_aux]
21
+
22
+ @[simp] theorem xgcd_aux_rec {r s t r' s' t'} (h : 0 < r) : xgcd_aux r s t r' s' t' = xgcd_aux (r' % r) (s' - (r' / r) * s) (t' - (r' / r) * t) r s t :=
23
+ by cases r; [exact absurd h (lt_irrefl _), {simp only [xgcd_aux], refl}]
24
+
25
+ /-- Use the extended GCD algorithm to generate the `a` and `b` values
26
+ satisfying `gcd x y = x * a + y * b`. -/
27
+ def xgcd (x y : ℕ) : ℤ × ℤ := (xgcd_aux x 1 0 y 0 1 ).2
28
+
29
+ /-- The extended GCD `a` value in the equation `gcd x y = x * a + y * b`. -/
30
+ def gcd_a (x y : ℕ) : ℤ := (xgcd x y).1
31
+
32
+ /-- The extended GCD `b` value in the equation `gcd x y = x * a + y * b`. -/
33
+ def gcd_b (x y : ℕ) : ℤ := (xgcd x y).2
34
+
35
+ @[simp] theorem xgcd_aux_fst (x y) : ∀ s t s' t',
36
+ (xgcd_aux x s t y s' t').1 = gcd x y :=
37
+ gcd.induction x y (by simp) (λ x y h IH s t s' t', by simp [h, IH]; rw ← gcd_rec)
38
+
39
+ theorem xgcd_aux_val (x y) : xgcd_aux x 1 0 y 0 1 = (gcd x y, xgcd x y) :=
40
+ by rw [xgcd, ← xgcd_aux_fst x y 1 0 0 1 ]; cases xgcd_aux x 1 0 y 0 1 ; refl
41
+
42
+ theorem xgcd_val (x y) : xgcd x y = (gcd_a x y, gcd_b x y) :=
43
+ by unfold gcd_a gcd_b; cases xgcd x y; refl
44
+
45
+ section
46
+ parameters (a b : ℕ)
47
+
48
+ private def P : ℕ × ℤ × ℤ → Prop | (r, s, t) := (r : ℤ) = a * s + b * t
49
+
50
+ theorem xgcd_aux_P {r r'} : ∀ {s t s' t'}, P (r, s, t) → P (r', s', t') → P (xgcd_aux r s t r' s' t') :=
51
+ gcd.induction r r' (by simp) $ λ x y h IH s t s' t' p p', begin
52
+ rw [xgcd_aux_rec h], refine IH _ p, dsimp [P] at *,
53
+ rw [int.mod_def], generalize : (y / x : ℤ) = k,
54
+ rw [p, p'], simp [mul_add, mul_comm, mul_left_comm]
55
+ end
56
+
57
+ theorem gcd_eq_gcd_ab : (gcd a b : ℤ) = a * gcd_a a b + b * gcd_b a b :=
58
+ by have := @xgcd_aux_P a b a b 1 0 0 1 (by simp [P]) (by simp [P]);
59
+ rwa [xgcd_aux_val, xgcd_val] at this
60
+ end
61
+
62
+ end nat
10
63
11
64
namespace int
12
65
66
+ theorem nat_abs_div (a b : ℤ) (H : b ∣ a) : nat_abs (a / b) = (nat_abs a) / (nat_abs b) :=
67
+ begin
68
+ cases (nat.eq_zero_or_pos (nat_abs b)),
69
+ rw eq_zero_of_nat_abs_eq_zero h,
70
+ simp,
71
+ calc
72
+ nat_abs (a / b) = nat_abs (a / b) * 1 : by rw mul_one
73
+ ... = nat_abs (a / b) * (nat_abs b / nat_abs b) : by rw nat.div_self h
74
+ ... = nat_abs (a / b) * nat_abs b / nat_abs b : by rw (nat.mul_div_assoc _ (dvd_refl _))
75
+ ... = nat_abs (a / b * b) / nat_abs b : by rw (nat_abs_mul (a / b) b)
76
+ ... = nat_abs a / nat_abs b : by rw int.div_mul_cancel H,
77
+ end
78
+
79
+ theorem nat_abs_dvd_abs_iff {i j : ℤ} : i.nat_abs ∣ j.nat_abs ↔ i ∣ j :=
80
+ ⟨assume (H : i.nat_abs ∣ j.nat_abs), dvd_nat_abs.mp (nat_abs_dvd.mp (coe_nat_dvd.mpr H)),
81
+ assume H : (i ∣ j), coe_nat_dvd.mp (dvd_nat_abs.mpr (nat_abs_dvd.mpr H))⟩
82
+
83
+ lemma succ_dvd_or_succ_dvd_of_succ_sum_dvd_mul {p : ℕ} (p_prime : nat.prime p) {m n : ℤ} {k l : ℕ}
84
+ (hpm : ↑(p ^ k) ∣ m)
85
+ (hpn : ↑(p ^ l) ∣ n) (hpmn : ↑(p ^ (k+l+1 )) ∣ m*n) : ↑(p ^ (k+1 )) ∣ m ∨ ↑(p ^ (l+1 )) ∣ n :=
86
+ have hpm' : p ^ k ∣ m.nat_abs, from int.coe_nat_dvd.1 $ int.dvd_nat_abs.2 hpm,
87
+ have hpn' : p ^ l ∣ n.nat_abs, from int.coe_nat_dvd.1 $ int.dvd_nat_abs.2 hpn,
88
+ have hpmn' : (p ^ (k+l+1 )) ∣ m.nat_abs*n.nat_abs,
89
+ by rw ←int.nat_abs_mul; apply (int.coe_nat_dvd.1 $ int.dvd_nat_abs.2 hpmn),
90
+ let hsd := nat.succ_dvd_or_succ_dvd_of_succ_sum_dvd_mul p_prime hpm' hpn' hpmn' in
91
+ hsd.elim
92
+ (λ hsd1, or.inl begin apply int.dvd_nat_abs.1 , apply int.coe_nat_dvd.2 hsd1 end )
93
+ (λ hsd2, or.inr begin apply int.dvd_nat_abs.1 , apply int.coe_nat_dvd.2 hsd2 end )
94
+
95
+ theorem dvd_of_mul_dvd_mul_left {i j k : ℤ} (k_non_zero : k ≠ 0 ) (H : k * i ∣ k * j) : i ∣ j :=
96
+ dvd.elim H (λl H1, by rw mul_assoc at H1; exact ⟨_, eq_of_mul_eq_mul_left k_non_zero H1⟩)
97
+
98
+ theorem dvd_of_mul_dvd_mul_right {i j k : ℤ} (k_non_zero : k ≠ 0 ) (H : i * k ∣ j * k) : i ∣ j :=
99
+ by rw [mul_comm i k, mul_comm j k] at H; exact dvd_of_mul_dvd_mul_left k_non_zero H
100
+
13
101
/- gcd -/
14
102
15
103
@[simp] theorem gcd_self (i : ℤ) : gcd i i = nat_abs i :=
@@ -20,21 +108,21 @@ by cases i; simp [gcd, mod_self]
20
108
@[simp] theorem gcd_zero_right (i : ℤ) : gcd i 0 = nat_abs i :=
21
109
by cases i; simp [gcd]
22
110
23
- theorem gcd_dvd_left (i j : ℤ) : (gcd i j : ℤ) ∣ i :=
111
+ theorem gcd_dvd_left (i j : ℤ) : (gcd i j : ℤ) ∣ i :=
24
112
dvd_nat_abs.mp (coe_nat_dvd.mpr (nat.gcd_dvd_left (nat_abs i) (nat_abs j)))
25
113
26
114
theorem gcd_dvd_right (i j : ℤ) : (gcd i j : ℤ) ∣ j :=
27
115
dvd_nat_abs.mp (coe_nat_dvd.mpr (nat.gcd_dvd_right (nat_abs i) (nat_abs j)))
28
116
29
- theorem gcd_dvd (i j : ℤ) : ((gcd i j : ℤ) ∣ i) ∧ ((gcd i j : ℤ) ∣ j) :=
117
+ theorem gcd_dvd (i j : ℤ) : ((gcd i j : ℤ) ∣ i) ∧ ((gcd i j : ℤ) ∣ j) :=
30
118
⟨gcd_dvd_left i j, gcd_dvd_right i j⟩
31
119
32
120
theorem dvd_gcd {i j k : ℤ} : k ∣ i → k ∣ j → k ∣ gcd i j :=
33
- by intros H1 H2;
34
- exact nat_abs_dvd.mp (coe_nat_dvd.mpr (nat.dvd_gcd (nat_abs_dvd_abs_iff.mpr H1)
121
+ by intros H1 H2;
122
+ exact nat_abs_dvd.mp (coe_nat_dvd.mpr (nat.dvd_gcd (nat_abs_dvd_abs_iff.mpr H1)
35
123
(nat_abs_dvd_abs_iff.mpr H2)))
36
124
37
- theorem gcd_comm (i j : ℤ) : gcd i j = gcd j i :=
125
+ theorem gcd_comm (i j : ℤ) : gcd i j = gcd j i :=
38
126
nat.gcd_comm (nat_abs i) (nat_abs j)
39
127
40
128
theorem gcd_assoc (i j k : ℤ) : gcd (gcd i j) k = gcd i (gcd j k) :=
@@ -46,11 +134,11 @@ nat.gcd_assoc (nat_abs i) (nat_abs j) (nat_abs k)
46
134
eq.trans (gcd_comm i 1 ) $ gcd_one_left i
47
135
48
136
theorem gcd_mul_left (i j k : ℤ) : gcd (i * j) (i * k) = nat_abs i * gcd j k :=
49
- by rw [gcd, nat_abs_mul, nat_abs_mul];
137
+ by rw [gcd, nat_abs_mul, nat_abs_mul];
50
138
exact nat.gcd_mul_left (nat_abs i) (nat_abs j) (nat_abs k)
51
139
52
- theorem gcd_mul_right (i j k : ℤ) : gcd (i * j) (k * j) = gcd i k * nat_abs j :=
53
- by rw [gcd, nat_abs_mul, nat_abs_mul];
140
+ theorem gcd_mul_right (i j k : ℤ) : gcd (i * j) (k * j) = gcd i k * nat_abs j :=
141
+ by rw [gcd, nat_abs_mul, nat_abs_mul];
54
142
exact nat.gcd_mul_right (nat_abs i) (nat_abs j) (nat_abs k)
55
143
56
144
theorem gcd_pos_of_non_zero_left {i : ℤ} (j : ℤ) (i_non_zero : i ≠ 0 ) : gcd i j > 0 :=
@@ -113,15 +201,15 @@ theorem lcm_zero_right (i : ℤ) : lcm i 0 = 0 := lcm_comm 0 i ▸ lcm_zero_left
113
201
theorem lcm_one_left (i : ℤ) : lcm 1 i = nat_abs i :=
114
202
by rw [lcm, one_mul, gcd_one_left, nat.div_one]
115
203
116
- theorem lcm_one_right (i : ℤ) : lcm i 1 = nat_abs i :=
204
+ theorem lcm_one_right (i : ℤ) : lcm i 1 = nat_abs i :=
117
205
by unfold lcm; simp
118
206
119
207
theorem lcm_self (i : ℤ) : lcm i i = nat_abs i :=
120
- by rw [lcm, gcd_self, nat_abs_mul, nat.mul_div_assoc, mul_comm, nat.div_mul_cancel];
208
+ by rw [lcm, gcd_self, nat_abs_mul, nat.mul_div_assoc, mul_comm, nat.div_mul_cancel];
121
209
simp; simp
122
210
123
211
theorem dvd_lcm_left (i j : ℤ) : i ∣ lcm i j :=
124
- nat_abs_dvd.mp (coe_nat_dvd.mpr (eq.subst (eq.symm (lcm_def i j))
212
+ nat_abs_dvd.mp (coe_nat_dvd.mpr (eq.subst (eq.symm (lcm_def i j))
125
213
(nat.dvd_lcm_left (nat_abs i) (nat_abs j))))
126
214
127
215
theorem dvd_lcm_right (i j : ℤ) : j ∣ lcm i j :=
@@ -130,26 +218,17 @@ lcm_comm j i ▸ dvd_lcm_left j i
130
218
theorem gcd_mul_lcm (i j : ℤ) : gcd i j * lcm i j = nat_abs (i * j) :=
131
219
begin
132
220
rw [lcm, mul_comm, nat.div_mul_cancel],
133
- exact eq.subst (eq.symm (nat_abs_mul i j))
221
+ exact eq.subst (eq.symm (nat_abs_mul i j))
134
222
(dvd_mul_of_dvd_left (coe_nat_dvd.mp (dvd_nat_abs.mpr (gcd_dvd_left i j))) _),
135
223
end
136
224
137
225
theorem lcm_dvd {i j k : ℤ} (H1 : i ∣ k) (H2 : j ∣ k) : (lcm i j : ℤ) ∣ k :=
138
- dvd_nat_abs.mp (coe_nat_dvd.mpr (eq.subst (eq.symm (lcm_def i j))
226
+ dvd_nat_abs.mp (coe_nat_dvd.mpr (eq.subst (eq.symm (lcm_def i j))
139
227
(nat.lcm_dvd (nat_abs_dvd_abs_iff.mpr H1)
140
228
(nat_abs_dvd_abs_iff.mpr H2))))
141
229
142
230
theorem lcm_assoc (i j k : ℤ) : lcm (lcm i j) k = lcm i (lcm j k) :=
143
231
by rw [lcm_def, lcm_def, lcm_def, lcm_def];
144
232
exact nat.lcm_assoc (nat_abs i) (nat_abs j) (nat_abs k)
145
233
146
- /- lemmas -/
147
-
148
- theorem dvd_of_mul_dvd_mul_left {i j k : ℤ} (k_non_zero : k ≠ 0 ) (H : k * i ∣ k * j) : i ∣ j :=
149
- dvd.elim H (λl H1, by rw mul_assoc at H1; exact ⟨_, eq_of_mul_eq_mul_left k_non_zero H1⟩)
150
-
151
- theorem dvd_of_mul_dvd_mul_right {i j k : ℤ} (k_non_zero : k ≠ 0 ) (H : i * k ∣ j * k) : i ∣ j :=
152
- by rw [mul_comm i k, mul_comm j k] at H; exact dvd_of_mul_dvd_mul_left k_non_zero H
153
-
154
-
155
234
end int
0 commit comments