This repository was archived by the owner on Jul 24, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 294
/
Copy pathtotient.lean
374 lines (331 loc) · 14.5 KB
/
totient.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
/-
Copyright (c) 2018 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Chris Hughes
-/
import algebra.char_p.two
import data.nat.factorization.basic
import data.nat.periodic
import data.zmod.basic
/-!
# Euler's totient function
This file defines [Euler's totient function](https://en.wikipedia.org/wiki/Euler's_totient_function)
`nat.totient n` which counts the number of naturals less than `n` that are coprime with `n`.
We prove the divisor sum formula, namely that `n` equals `φ` summed over the divisors of `n`. See
`sum_totient`. We also prove two lemmas to help compute totients, namely `totient_mul` and
`totient_prime_pow`.
-/
open finset
open_locale big_operators
namespace nat
/-- Euler's totient function. This counts the number of naturals strictly less than `n` which are
coprime with `n`. -/
def totient (n : ℕ) : ℕ := ((range n).filter n.coprime).card
localized "notation (name := nat.totient) `φ` := nat.totient" in nat
@[simp] theorem totient_zero : φ 0 = 0 := rfl
@[simp] theorem totient_one : φ 1 = 1 :=
by simp [totient]
lemma totient_eq_card_coprime (n : ℕ) : φ n = ((range n).filter n.coprime).card := rfl
lemma totient_le (n : ℕ) : φ n ≤ n :=
((range n).card_filter_le _).trans_eq (card_range n)
lemma totient_lt (n : ℕ) (hn : 1 < n) : φ n < n :=
(card_lt_card (filter_ssubset.2 ⟨0, by simp [hn.ne', pos_of_gt hn]⟩)).trans_eq (card_range n)
@[simp] lemma totient_eq_zero : ∀ {n : ℕ}, φ n = 0 ↔ n = 0
| 0 := dec_trivial
| 1 := by simp [totient]
| (n + 2) :=
iff_of_false (card_pos.2 ⟨1, mem_filter.2 ⟨mem_range.2 dec_trivial, coprime_one_right _⟩⟩).ne'
(n + 1).succ_ne_zero
lemma totient_ne_zero {n : ℕ} : φ n ≠ 0 ↔ n ≠ 0 := totient_eq_zero.not
@[simp] lemma totient_pos {n : ℕ} : 0 < φ n ↔ n ≠ 0 :=
pos_iff_ne_zero.trans totient_ne_zero
lemma filter_coprime_Ico_eq_totient (a n : ℕ) :
((Ico n (n+a)).filter (coprime a)).card = totient a :=
begin
rw [totient, filter_Ico_card_eq_of_periodic, count_eq_card_filter_range],
exact periodic_coprime a,
end
lemma Ico_filter_coprime_le {a : ℕ} (k n : ℕ) (h0 : a ≠ 0) :
((Ico k (k + n)).filter (coprime a)).card ≤ totient a * (n / a + 1) :=
begin
conv_lhs { rw ←nat.mod_add_div n a },
induction n / a with i ih,
{ rw ←filter_coprime_Ico_eq_totient a k,
simp only [add_zero, mul_one, mul_zero, le_of_lt (mod_lt n h0.bot_lt)],
mono,
refine monotone_filter_left a.coprime _,
simp only [finset.le_eq_subset],
exact Ico_subset_Ico rfl.le (add_le_add_left (le_of_lt (mod_lt n h0.bot_lt)) k), },
simp only [mul_succ],
simp_rw ←add_assoc at ih ⊢,
calc (filter a.coprime (Ico k (k + n % a + a * i + a))).card
= (filter a.coprime (Ico k (k + n % a + a * i)
∪ Ico (k + n % a + a * i) (k + n % a + a * i + a))).card :
begin
congr,
rw Ico_union_Ico_eq_Ico,
rw add_assoc,
exact le_self_add,
exact le_self_add,
end
... ≤ (filter a.coprime (Ico k (k + n % a + a * i))).card + a.totient :
begin
rw [filter_union, ←filter_coprime_Ico_eq_totient a (k + n % a + a * i)],
apply card_union_le,
end
... ≤ a.totient * i + a.totient + a.totient : add_le_add_right ih (totient a),
end
open zmod
/-- Note this takes an explicit `fintype ((zmod n)ˣ)` argument to avoid trouble with instance
diamonds. -/
@[simp] lemma _root_.zmod.card_units_eq_totient (n : ℕ) [ne_zero n] [fintype ((zmod n)ˣ)] :
fintype.card ((zmod n)ˣ) = φ n :=
calc fintype.card ((zmod n)ˣ) = fintype.card {x : zmod n // x.val.coprime n} :
fintype.card_congr zmod.units_equiv_coprime
... = φ n :
begin
unfreezingI { obtain ⟨m, rfl⟩ : ∃ m, n = m + 1 := exists_eq_succ_of_ne_zero ne_zero.out },
simp only [totient, finset.card_eq_sum_ones, fintype.card_subtype, finset.sum_filter,
← fin.sum_univ_eq_sum_range, @nat.coprime_comm (m + 1)],
refl
end
lemma totient_even {n : ℕ} (hn : 2 < n) : even n.totient :=
begin
haveI : fact (1 < n) := ⟨one_lt_two.trans hn⟩,
haveI : ne_zero n := ne_zero.of_gt hn,
suffices : 2 = order_of (-1 : (zmod n)ˣ),
{ rw [← zmod.card_units_eq_totient, even_iff_two_dvd, this], exact order_of_dvd_card_univ },
rw [←order_of_units, units.coe_neg_one, order_of_neg_one, ring_char.eq (zmod n) n, if_neg hn.ne'],
end
lemma totient_mul {m n : ℕ} (h : m.coprime n) : φ (m * n) = φ m * φ n :=
if hmn0 : m * n = 0
then by cases nat.mul_eq_zero.1 hmn0 with h h;
simp only [totient_zero, mul_zero, zero_mul, h]
else
begin
haveI : ne_zero (m * n) := ⟨hmn0⟩,
haveI : ne_zero m := ⟨left_ne_zero_of_mul hmn0⟩,
haveI : ne_zero n := ⟨right_ne_zero_of_mul hmn0⟩,
simp only [← zmod.card_units_eq_totient],
rw [fintype.card_congr (units.map_equiv (zmod.chinese_remainder h).to_mul_equiv).to_equiv,
fintype.card_congr (@mul_equiv.prod_units (zmod m) (zmod n) _ _).to_equiv,
fintype.card_prod]
end
/-- For `d ∣ n`, the totient of `n/d` equals the number of values `k < n` such that `gcd n k = d` -/
lemma totient_div_of_dvd {n d : ℕ} (hnd : d ∣ n) :
φ (n/d) = (filter (λ (k : ℕ), n.gcd k = d) (range n)).card :=
begin
rcases d.eq_zero_or_pos with rfl | hd0, { simp [eq_zero_of_zero_dvd hnd] },
rcases hnd with ⟨x, rfl⟩,
rw nat.mul_div_cancel_left x hd0,
apply finset.card_congr (λ k _, d * k),
{ simp only [mem_filter, mem_range, and_imp, coprime],
refine λ a ha1 ha2, ⟨(mul_lt_mul_left hd0).2 ha1, _⟩,
rw [gcd_mul_left, ha2, mul_one] },
{ simp [hd0.ne'] },
{ simp only [mem_filter, mem_range, exists_prop, and_imp],
refine λ b hb1 hb2, _,
have : d ∣ b, { rw ←hb2, apply gcd_dvd_right },
rcases this with ⟨q, rfl⟩,
refine ⟨q, ⟨⟨(mul_lt_mul_left hd0).1 hb1, _⟩, rfl⟩⟩,
rwa [gcd_mul_left, mul_right_eq_self_iff hd0.ne'] at hb2 },
end
lemma sum_totient (n : ℕ) : n.divisors.sum φ = n :=
begin
rcases n.eq_zero_or_pos with rfl | hn, { simp },
rw ←sum_div_divisors n φ,
have : n = ∑ (d : ℕ) in n.divisors, (filter (λ (k : ℕ), n.gcd k = d) (range n)).card,
{ nth_rewrite_lhs 0 ←card_range n,
refine card_eq_sum_card_fiberwise (λ x hx, mem_divisors.2 ⟨_, hn.ne'⟩),
apply gcd_dvd_left },
nth_rewrite_rhs 0 this,
exact sum_congr rfl (λ x hx, totient_div_of_dvd (dvd_of_mem_divisors hx)),
end
lemma sum_totient' (n : ℕ) : ∑ m in (range n.succ).filter (∣ n), φ m = n :=
begin
convert sum_totient _ using 1,
simp only [nat.divisors, sum_filter, range_eq_Ico],
rw sum_eq_sum_Ico_succ_bot; simp
end
/-- When `p` is prime, then the totient of `p ^ (n + 1)` is `p ^ n * (p - 1)` -/
lemma totient_prime_pow_succ {p : ℕ} (hp : p.prime) (n : ℕ) :
φ (p ^ (n + 1)) = p ^ n * (p - 1) :=
calc φ (p ^ (n + 1))
= ((range (p ^ (n + 1))).filter (coprime (p ^ (n + 1)))).card :
totient_eq_card_coprime _
... = (range (p ^ (n + 1)) \ ((range (p ^ n)).image (* p))).card :
congr_arg card begin
rw [sdiff_eq_filter],
apply filter_congr,
simp only [mem_range, mem_filter, coprime_pow_left_iff n.succ_pos,
mem_image, not_exists, hp.coprime_iff_not_dvd],
intros a ha,
split,
{ rintros hap b _ rfl,
exact hap (dvd_mul_left _ _) },
{ rintros h ⟨b, rfl⟩,
rw [pow_succ] at ha,
exact h b (lt_of_mul_lt_mul_left ha (zero_le _)) (mul_comm _ _) }
end
... = _ :
have h1 : function.injective (* p),
from mul_left_injective₀ hp.ne_zero,
have h2 : (range (p ^ n)).image (* p) ⊆ range (p ^ (n + 1)),
from λ a, begin
simp only [mem_image, mem_range, exists_imp_distrib],
rintros b h rfl,
rw [pow_succ'],
exact (mul_lt_mul_right hp.pos).2 h
end,
begin
rw [card_sdiff h2, card_image_of_inj_on (h1.inj_on _), card_range,
card_range, ← one_mul (p ^ n), pow_succ, ← tsub_mul,
one_mul, mul_comm]
end
/-- When `p` is prime, then the totient of `p ^ n` is `p ^ (n - 1) * (p - 1)` -/
lemma totient_prime_pow {p : ℕ} (hp : p.prime) {n : ℕ} (hn : 0 < n) :
φ (p ^ n) = p ^ (n - 1) * (p - 1) :=
by rcases exists_eq_succ_of_ne_zero (pos_iff_ne_zero.1 hn) with ⟨m, rfl⟩;
exact totient_prime_pow_succ hp _
lemma totient_prime {p : ℕ} (hp : p.prime) : φ p = p - 1 :=
by rw [← pow_one p, totient_prime_pow hp]; simp
lemma totient_eq_iff_prime {p : ℕ} (hp : 0 < p) : p.totient = p - 1 ↔ p.prime :=
begin
refine ⟨λ h, _, totient_prime⟩,
replace hp : 1 < p,
{ apply lt_of_le_of_ne,
{ rwa succ_le_iff },
{ rintro rfl,
rw [totient_one, tsub_self] at h,
exact one_ne_zero h } },
rw [totient_eq_card_coprime, range_eq_Ico, ←Ico_insert_succ_left hp.le, finset.filter_insert,
if_neg (not_coprime_of_dvd_of_dvd hp (dvd_refl p) (dvd_zero p)), ←nat.card_Ico 1 p] at h,
refine p.prime_of_coprime hp (λ n hn hnz, finset.filter_card_eq h n $ finset.mem_Ico.mpr ⟨_, hn⟩),
rwa [succ_le_iff, pos_iff_ne_zero],
end
lemma card_units_zmod_lt_sub_one {p : ℕ} (hp : 1 < p) [fintype ((zmod p)ˣ)] :
fintype.card ((zmod p)ˣ) ≤ p - 1 :=
begin
haveI : ne_zero p := ⟨(pos_of_gt hp).ne'⟩,
rw zmod.card_units_eq_totient p,
exact nat.le_pred_of_lt (nat.totient_lt p hp),
end
lemma prime_iff_card_units (p : ℕ) [fintype ((zmod p)ˣ)] :
p.prime ↔ fintype.card ((zmod p)ˣ) = p - 1 :=
begin
casesI eq_zero_or_ne_zero p with hp hp,
{ substI hp,
simp only [zmod, not_prime_zero, false_iff, zero_tsub],
-- the substI created an non-defeq but subsingleton instance diamond; resolve it
suffices : fintype.card ℤˣ ≠ 0, { convert this },
simp },
rw [zmod.card_units_eq_totient, nat.totient_eq_iff_prime $ ne_zero.pos p],
end
@[simp] lemma totient_two : φ 2 = 1 :=
(totient_prime prime_two).trans rfl
lemma totient_eq_one_iff : ∀ {n : ℕ}, n.totient = 1 ↔ n = 1 ∨ n = 2
| 0 := by simp
| 1 := by simp
| 2 := by simp
| (n+3) :=
begin
have : 3 ≤ n + 3 := le_add_self,
simp only [succ_succ_ne_one, false_or],
exact ⟨λ h, not_even_one.elim $ h ▸ totient_even this, by rintro ⟨⟩⟩,
end
/-! ### Euler's product formula for the totient function
We prove several different statements of this formula. -/
/-- Euler's product formula for the totient function. -/
theorem totient_eq_prod_factorization {n : ℕ} (hn : n ≠ 0) :
φ n = n.factorization.prod (λ p k, p ^ (k - 1) * (p - 1)) :=
begin
rw multiplicative_factorization φ @totient_mul totient_one hn,
apply finsupp.prod_congr (λ p hp, _),
have h := zero_lt_iff.mpr (finsupp.mem_support_iff.mp hp),
rw [totient_prime_pow (prime_of_mem_factorization hp) h],
end
/-- Euler's product formula for the totient function. -/
theorem totient_mul_prod_factors (n : ℕ) :
φ n * ∏ p in n.factors.to_finset, p = n * ∏ p in n.factors.to_finset, (p - 1) :=
begin
by_cases hn : n = 0, { simp [hn] },
rw totient_eq_prod_factorization hn,
nth_rewrite 2 ←factorization_prod_pow_eq_self hn,
simp only [←prod_factorization_eq_prod_factors, ←finsupp.prod_mul],
refine finsupp.prod_congr (λ p hp, _),
rw [finsupp.mem_support_iff, ← zero_lt_iff] at hp,
rw [mul_comm, ←mul_assoc, ←pow_succ, nat.sub_add_cancel hp],
end
/-- Euler's product formula for the totient function. -/
theorem totient_eq_div_factors_mul (n : ℕ) :
φ n = n / (∏ p in n.factors.to_finset, p) * (∏ p in n.factors.to_finset, (p - 1)) :=
begin
rw [← mul_div_left n.totient, totient_mul_prod_factors, mul_comm,
nat.mul_div_assoc _ (prod_prime_factors_dvd n), mul_comm],
simpa [prod_factorization_eq_prod_factors] using prod_pos (λ p, pos_of_mem_factorization),
end
/-- Euler's product formula for the totient function. -/
theorem totient_eq_mul_prod_factors (n : ℕ) :
(φ n : ℚ) = n * ∏ p in n.factors.to_finset, (1 - p⁻¹) :=
begin
by_cases hn : n = 0, { simp [hn] },
have hn' : (n : ℚ) ≠ 0, { simp [hn] },
have hpQ : ∏ p in n.factors.to_finset, (p : ℚ) ≠ 0,
{ rw [←cast_prod, cast_ne_zero, ←zero_lt_iff, ←prod_factorization_eq_prod_factors],
exact prod_pos (λ p hp, pos_of_mem_factorization hp) },
simp only [totient_eq_div_factors_mul n, prod_prime_factors_dvd n, cast_mul, cast_prod,
cast_div_char_zero, mul_comm_div, mul_right_inj' hn', div_eq_iff hpQ, ←prod_mul_distrib],
refine prod_congr rfl (λ p hp, _),
have hp := pos_of_mem_factors (list.mem_to_finset.mp hp),
have hp' : (p : ℚ) ≠ 0 := cast_ne_zero.mpr hp.ne.symm,
rw [sub_mul, one_mul, mul_comm, mul_inv_cancel hp', cast_pred hp],
end
lemma totient_gcd_mul_totient_mul (a b : ℕ) : φ (a.gcd b) * φ (a * b) = φ a * φ b * (a.gcd b) :=
begin
have shuffle : ∀ a1 a2 b1 b2 c1 c2 : ℕ, b1 ∣ a1 → b2 ∣ a2 →
(a1/b1 * c1) * (a2/b2 * c2) = (a1*a2)/(b1*b2) * (c1*c2),
{ intros a1 a2 b1 b2 c1 c2 h1 h2,
calc
(a1/b1 * c1) * (a2/b2 * c2) = ((a1/b1) * (a2/b2)) * (c1*c2) : by apply mul_mul_mul_comm
... = (a1*a2)/(b1*b2) * (c1*c2) : by { congr' 1, exact div_mul_div_comm h1 h2 } },
simp only [totient_eq_div_factors_mul],
rw [shuffle, shuffle],
rotate, repeat { apply prod_prime_factors_dvd },
{ simp only [prod_factors_gcd_mul_prod_factors_mul],
rw [eq_comm, mul_comm, ←mul_assoc, ←nat.mul_div_assoc],
exact mul_dvd_mul (prod_prime_factors_dvd a) (prod_prime_factors_dvd b) }
end
lemma totient_super_multiplicative (a b : ℕ) : φ a * φ b ≤ φ (a * b) :=
begin
let d := a.gcd b,
rcases (zero_le a).eq_or_lt with rfl | ha0, { simp },
have hd0 : 0 < d, from nat.gcd_pos_of_pos_left _ ha0,
rw [←mul_le_mul_right hd0, ←totient_gcd_mul_totient_mul a b, mul_comm],
apply mul_le_mul_left' (nat.totient_le d),
end
lemma totient_dvd_of_dvd {a b : ℕ} (h : a ∣ b) : φ a ∣ φ b :=
begin
rcases eq_or_ne a 0 with rfl | ha0, { simp [zero_dvd_iff.1 h] },
rcases eq_or_ne b 0 with rfl | hb0, { simp },
have hab' : a.factorization.support ⊆ b.factorization.support,
{ intro p,
simp only [support_factorization, list.mem_to_finset],
apply factors_subset_of_dvd h hb0 },
rw [totient_eq_prod_factorization ha0, totient_eq_prod_factorization hb0],
refine finsupp.prod_dvd_prod_of_subset_of_dvd hab' (λ p hp, mul_dvd_mul _ dvd_rfl),
exact pow_dvd_pow p (tsub_le_tsub_right ((factorization_le_iff_dvd ha0 hb0).2 h p) 1),
end
lemma totient_mul_of_prime_of_dvd {p n : ℕ} (hp : p.prime) (h : p ∣ n) :
(p * n).totient = p * n.totient :=
begin
have h1 := totient_gcd_mul_totient_mul p n,
rw [(gcd_eq_left h), mul_assoc] at h1,
simpa [totient_ne_zero.2 hp.ne_zero, mul_comm] using h1,
end
lemma totient_mul_of_prime_of_not_dvd {p n : ℕ} (hp : p.prime) (h : ¬ p ∣ n) :
(p * n).totient = (p - 1) * n.totient :=
begin
rw [totient_mul _, totient_prime hp],
simpa [h] using coprime_or_dvd_of_prime hp n,
end
end nat