Skip to content

Commit 6cab3d6

Browse files
feat(NumberTheory.SmoothNumbers): add {smooth|rough}NumbersUpTo and some API (#9240)
This adds definitions of the `k`-smooth numbers up to and including `N` as a `Finset` and of its complement in `{1, ..., N}` plus some API, in particular cardinality bounds. There are also a few additional API lemmas for `Nat.primesBelow` and `Nat.smoothNumbers` (including a decidability instance for membership in the latter). This is a PR in preparation of the divergence of the sum of the reciprocals of the primes. See [here](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Sum.20over.201.2Fp.20diverges/near/409835682) on Zulip. Co-authored-by: Junyan Xu <[email protected]>
1 parent 5dee9c0 commit 6cab3d6

File tree

2 files changed

+144
-6
lines changed

2 files changed

+144
-6
lines changed

Mathlib/Data/Nat/Factorization/Basic.lean

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -866,7 +866,8 @@ theorem prod_pow_prime_padicValNat (n : Nat) (hn : n ≠ 0) (m : Nat) (pr : n <
866866

867867

868868
-- TODO: Port lemmas from `Data/Nat/Multiplicity` to here, re-written in terms of `factorization`
869-
/-- Exactly `n / p` naturals in `[1, n]` are multiples of `p`. -/
869+
/-- Exactly `n / p` naturals in `[1, n]` are multiples of `p`.
870+
See `Nat.card_multiples'` for an alternative spelling of the statement. -/
870871
theorem card_multiples (n p : ℕ) : card ((Finset.range n).filter fun e => p ∣ e + 1) = n / p := by
871872
induction' n with n hn
872873
· simp
@@ -887,4 +888,16 @@ theorem Ioc_filter_dvd_card_eq_div (n p : ℕ) : ((Ioc 0 n).filter fun x => p
887888
Finset.mem_filter, mem_Ioc, not_le.2 (lt_add_one n), Nat.succ_eq_add_one]
888889
#align nat.Ioc_filter_dvd_card_eq_div Nat.Ioc_filter_dvd_card_eq_div
889890

891+
/-- There are exactly `⌊N/n⌋` positive multiples of `n` that are `≤ N`.
892+
See `Nat.card_multiples` for a "shifted-by-one" version. -/
893+
lemma card_multiples' (N n : ℕ) :
894+
((Finset.range N.succ).filter (fun k ↦ k ≠ 0 ∧ n ∣ k)).card = N / n := by
895+
induction N with
896+
| zero => simp
897+
| succ N ih =>
898+
rw [Finset.range_succ, Finset.filter_insert]
899+
by_cases h : n ∣ N.succ
900+
· simp [h, succ_div_of_dvd, ih]
901+
· simp [h, succ_div_of_not_dvd, ih]
902+
890903
end Nat

Mathlib/NumberTheory/SmoothNumbers.lean

Lines changed: 130 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Michael Stoll
55
-/
66
import Mathlib.Data.Nat.Factorization.Basic
7+
import Mathlib.Data.Nat.Squarefree
78

89
/-!
910
# Smooth numbers
@@ -16,6 +17,11 @@ We also define the finite set `Nat.primesBelow n` to be the set of prime numbers
1617
The main definition `Nat.equivProdNatSmoothNumbers` establishes the bijection between
1718
`ℕ × (smoothNumbers p)` and `smoothNumbers (p+1)` given by sending `(e, n)` to `p^e * n`.
1819
Here `p` is a prime number.
20+
21+
Additionally, we define `Nat.smoothNumbersUpTo N n` as the `Finset` of `n`-smooth numbers
22+
up to and including `N`, and similarly `Nat.roughNumbersUpTo` for its complement in `{1, ..., N}`,
23+
and we provide some API, in particular bounds for their cardinalities; see
24+
`Nat.smoothNumbersUpTo_card_le` and `Nat.roughNumbersUpTo_card_le`.
1925
-/
2026

2127
namespace Nat
@@ -27,6 +33,9 @@ def primesBelow (n : ℕ) : Finset ℕ := (Finset.range n).filter (fun p ↦ p.P
2733
lemma primesBelow_zero : primesBelow 0 = ∅ := by
2834
rw [primesBelow, Finset.range_zero, Finset.filter_empty]
2935

36+
lemma mem_primesBelow {k n : ℕ} :
37+
n ∈ primesBelow k ↔ n < k ∧ n.Prime := by simp [primesBelow]
38+
3039
lemma prime_of_mem_primesBelow {p n : ℕ} (h : p ∈ n.primesBelow) : p.Prime :=
3140
(Finset.mem_filter.mp h).2
3241

@@ -47,14 +56,37 @@ def smoothNumbers (n : ℕ) : Set ℕ := {m | m ≠ 0 ∧ ∀ p ∈ factors m, p
4756
lemma mem_smoothNumbers {n m : ℕ} : m ∈ smoothNumbers n ↔ m ≠ 0 ∧ ∀ p ∈ factors m, p < n :=
4857
Iff.rfl
4958

59+
/-- Membership in `Nat.smoothNumbers n` is decidable. -/
60+
instance (n : ℕ) : DecidablePred (· ∈ smoothNumbers n) :=
61+
inferInstanceAs <| DecidablePred fun x ↦ x ∈ {m | m ≠ 0 ∧ ∀ p ∈ factors m, p < n}
62+
63+
/-- A number that divides an `n`-smooth number is itself `n`-smooth. -/
64+
lemma mem_smoothNumbers_of_dvd {n m k : ℕ} (h : m ∈ smoothNumbers n) (h' : k ∣ m) (hk : k ≠ 0) :
65+
k ∈ smoothNumbers n := by
66+
rw [mem_smoothNumbers] at h ⊢
67+
obtain ⟨h₁, h₂⟩ := h
68+
refine ⟨hk, fun p hp ↦ h₂ p ?_⟩
69+
rw [mem_factors <| by assumption] at hp ⊢
70+
exact ⟨hp.1, hp.2.trans h'⟩
71+
72+
/-- `m` is `n`-smooth if and only if `m` is nonzero and all prime divisors `≤ m` of `m`
73+
are less than `n`. -/
74+
lemma mem_smoothNumbers_iff_forall_le {n m : ℕ} :
75+
m ∈ smoothNumbers n ↔ m ≠ 0 ∧ ∀ p ≤ m, p.Prime → p ∣ m → p < n := by
76+
simp_rw [mem_smoothNumbers, mem_factors']
77+
exact ⟨fun ⟨H₀, H₁⟩ ↦ ⟨H₀, fun p _ hp₂ hp₃ ↦ H₁ p ⟨hp₂, hp₃, H₀⟩⟩,
78+
fun ⟨H₀, H₁⟩ ↦
79+
⟨H₀, fun p ⟨hp₁, hp₂, hp₃⟩ ↦ H₁ p (Nat.le_of_dvd (Nat.pos_of_ne_zero hp₃) hp₂) hp₁ hp₂⟩⟩
80+
5081
/-- `m` is `n`-smooth if and only if all prime divisors of `m` are less than `n`. -/
5182
lemma mem_smoothNumbers' {n m : ℕ} : m ∈ smoothNumbers n ↔ ∀ p, p.Prime → p ∣ m → p < n := by
52-
rw [mem_smoothNumbers]
53-
refine ⟨fun H p hp h ↦ H.2 p <| (mem_factors_iff_dvd H.1 hp).mpr h,
54-
fun H ↦ ⟨?_, fun p hp ↦ H p (prime_of_mem_factors hp) (dvd_of_mem_factors hp)⟩⟩
55-
rintro rfl
5683
obtain ⟨p, hp₁, hp₂⟩ := exists_infinite_primes n
57-
exact ((H p hp₂ <| dvd_zero _).trans_le hp₁).false
84+
rw [mem_smoothNumbers_iff_forall_le]
85+
exact ⟨fun ⟨H₀, H₁⟩ ↦ fun p hp₁ hp₂ ↦ H₁ p (Nat.le_of_dvd (Nat.pos_of_ne_zero H₀) hp₂) hp₁ hp₂,
86+
fun H ↦ ⟨fun h ↦ ((H p hp₂ <| h.symm ▸ dvd_zero p).trans_le hp₁).false, fun p _ ↦ H p⟩⟩
87+
88+
lemma ne_zero_of_mem_smoothNumbers {n m : ℕ} (h : m ∈ smoothNumbers n) : m ≠ 0 :=
89+
(mem_smoothNumbers_iff_forall_le.mp h).1
5890

5991
@[simp]
6092
lemma smoothNumbers_zero : smoothNumbers 0 = {1} := by
@@ -166,4 +198,97 @@ lemma equivProdNatSmoothNumbers_apply {p e m : ℕ} (hp: p.Prime) (hm : m ∈ p.
166198
lemma equivProdNatSmoothNumbers_apply' {p : ℕ} (hp: p.Prime) (x : ℕ × p.smoothNumbers) :
167199
equivProdNatSmoothNumbers hp x = p ^ x.1 * x.2 := rfl
168200

201+
/-- The `k`-smooth numbers up to and including `N` as a `Finset` -/
202+
def smoothNumbersUpTo (N k : ℕ) : Finset ℕ :=
203+
(Finset.range N.succ).filter (· ∈ smoothNumbers k)
204+
205+
lemma mem_smoothNumbersUpTo {N k n : ℕ} :
206+
n ∈ smoothNumbersUpTo N k ↔ n ≤ N ∧ n ∈ smoothNumbers k := by
207+
simp [smoothNumbersUpTo, lt_succ]
208+
209+
/-- The positive non-`k`-smooth (so "`k`-rough") numbers up to and including `N` as a `Finset` -/
210+
def roughNumbersUpTo (N k : ℕ) : Finset ℕ :=
211+
(Finset.range N.succ).filter (fun n ↦ n ≠ 0 ∧ n ∉ smoothNumbers k)
212+
213+
lemma smoothNumbersUpTo_card_add_roughNumbersUpTo_card (N k : ℕ) :
214+
(smoothNumbersUpTo N k).card + (roughNumbersUpTo N k).card = N := by
215+
rw [smoothNumbersUpTo, roughNumbersUpTo,
216+
← Finset.card_union_eq <| Finset.disjoint_filter.mpr fun n _ hn₂ h ↦ h.2 hn₂,
217+
Finset.filter_union_right]
218+
suffices : Finset.card (Finset.filter (fun x ↦ x ≠ 0) (Finset.range (succ N))) = N
219+
· convert this with n
220+
have hn : n ∈ smoothNumbers k → n ≠ 0 := ne_zero_of_mem_smoothNumbers
221+
tauto
222+
· rw [Finset.filter_ne', Finset.card_erase_of_mem <| Finset.mem_range_succ_iff.mpr <| zero_le N]
223+
simp
224+
225+
/-- A `k`-smooth number can be written as a square times a product of distinct primes `< k`. -/
226+
lemma eq_prod_primes_mul_sq_of_mem_smoothNumbers {n k : ℕ} (h : n ∈ smoothNumbers k) :
227+
∃ s ∈ k.primesBelow.powerset, ∃ m, n = m ^ 2 * (s.prod id) := by
228+
obtain ⟨l, m, H₁, H₂⟩ := sq_mul_squarefree n
229+
have hl : l ∈ smoothNumbers k :=
230+
mem_smoothNumbers_of_dvd h (Dvd.intro_left (m ^ 2) H₁) <| Squarefree.ne_zero H₂
231+
refine ⟨l.factors.toFinset, ?_, m, ?_⟩
232+
· simp only [toFinset_factors, Finset.mem_powerset]
233+
refine fun p hp ↦ mem_primesBelow.mpr ⟨?_, (mem_primeFactors.mp hp).1
234+
rw [mem_primeFactors] at hp
235+
exact mem_smoothNumbers'.mp hl p hp.1 hp.2.1
236+
rw [← H₁]
237+
congr
238+
simp only [toFinset_factors]
239+
exact (prod_primeFactors_of_squarefree H₂).symm
240+
241+
/-- The set of `k`-smooth numbers `≤ N` is contained in the set of numbers of the form `m^2 * P`,
242+
where `m ≤ √N` and `P` is a product of distinct primes `< k`. -/
243+
lemma smoothNumbersUpTo_subset_image (N k : ℕ) :
244+
smoothNumbersUpTo N k ⊆ Finset.image (fun (s, m) ↦ m ^ 2 * (s.prod id))
245+
(k.primesBelow.powerset ×ˢ (Finset.range N.sqrt.succ).erase 0) := by
246+
intro n hn
247+
obtain ⟨hn₁, hn₂⟩ := mem_smoothNumbersUpTo.mp hn
248+
obtain ⟨s, hs, m, hm⟩ := eq_prod_primes_mul_sq_of_mem_smoothNumbers hn₂
249+
simp only [id_eq, Finset.mem_range, zero_lt_succ, not_true_eq_false, Finset.mem_image,
250+
Finset.mem_product, Finset.mem_powerset, Finset.mem_erase, Prod.exists]
251+
refine ⟨s, m, ⟨Finset.mem_powerset.mp hs, ?_, ?_⟩, hm.symm⟩
252+
· have := hm ▸ ne_zero_of_mem_smoothNumbers hn₂
253+
simp only [ne_eq, _root_.mul_eq_zero, zero_lt_two, pow_eq_zero_iff, not_or] at this
254+
exact this.1
255+
· rw [lt_succ, le_sqrt']
256+
refine LE.le.trans ?_ (hm ▸ hn₁)
257+
nth_rw 1 [← mul_one (m ^ 2)]
258+
exact mul_le_mul_left' (Finset.one_le_prod' fun p hp ↦
259+
(prime_of_mem_primesBelow <| Finset.mem_powerset.mp hs hp).one_lt.le) _
260+
261+
/-- The cardinality of the set of `k`-smooth numbers `≤ N` is bounded by `2^π(k-1) * √N`. -/
262+
lemma smoothNumbersUpTo_card_le (N k : ℕ) :
263+
(smoothNumbersUpTo N k).card ≤ 2 ^ k.primesBelow.card * N.sqrt := by
264+
convert (Finset.card_le_card <| smoothNumbersUpTo_subset_image N k).trans <|
265+
Finset.card_image_le
266+
simp
267+
268+
/-- The set of `k`-rough numbers `≤ N` can be written as the union of the sets of multiples `≤ N`
269+
of primes `k ≤ p ≤ N`. -/
270+
lemma roughNumbersUpTo_eq_biUnion (N k) :
271+
roughNumbersUpTo N k =
272+
(N.succ.primesBelow \ k.primesBelow).biUnion
273+
fun p ↦ (Finset.range N.succ).filter (fun m ↦ m ≠ 0 ∧ p ∣ m) := by
274+
ext m
275+
simp only [roughNumbersUpTo, mem_smoothNumbers_iff_forall_le, not_and, not_forall,
276+
not_lt, exists_prop, exists_and_left, Finset.mem_range, not_le, Finset.mem_filter,
277+
Finset.filter_congr_decidable, Finset.mem_biUnion, Finset.mem_sdiff, mem_primesBelow,
278+
show ∀ P Q : Prop, P ∧ (P → Q) ↔ P ∧ Q by tauto]
279+
simp_rw [← exists_and_left, ← not_lt]
280+
refine exists_congr fun p ↦ ?_
281+
have H₁ : m ≠ 0 → p ∣ m → m < N.succ → p < N.succ :=
282+
fun h₁ h₂ h₃ ↦ (le_of_dvd (Nat.pos_of_ne_zero h₁) h₂).trans_lt h₃
283+
have H₂ : m ≠ 0 → p ∣ m → ¬ m < p :=
284+
fun h₁ h₂ ↦ not_lt.mpr <| le_of_dvd (Nat.pos_of_ne_zero h₁) h₂
285+
tauto
286+
287+
/-- The cardinality of the set of `k`-rough numbers `≤ N` is bounded by the sum of `⌊N/p⌋`
288+
over the primes `k ≤ p ≤ N`. -/
289+
lemma roughNumbersUpTo_card_le (N k : ℕ) :
290+
(roughNumbersUpTo N k).card ≤ (N.succ.primesBelow \ k.primesBelow).sum (fun p ↦ N / p) := by
291+
rw [roughNumbersUpTo_eq_biUnion]
292+
exact Finset.card_biUnion_le.trans <| Finset.sum_le_sum fun p _ ↦ (card_multiples' N p).le
293+
169294
end Nat

0 commit comments

Comments
 (0)