@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44Authors: Michael Stoll
55-/
66import 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
1617The main definition `Nat.equivProdNatSmoothNumbers` establishes the bijection between
1718`ℕ × (smoothNumbers p)` and `smoothNumbers (p+1)` given by sending `(e, n)` to `p^e * n`.
1819Here `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
2127namespace Nat
@@ -27,6 +33,9 @@ def primesBelow (n : ℕ) : Finset ℕ := (Finset.range n).filter (fun p ↦ p.P
2733lemma 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+
3039lemma 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
4756lemma 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`. -/
5182lemma 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]
6092lemma smoothNumbers_zero : smoothNumbers 0 = {1 } := by
@@ -166,4 +198,97 @@ lemma equivProdNatSmoothNumbers_apply {p e m : ℕ} (hp: p.Prime) (hm : m ∈ p.
166198lemma 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+
169294end Nat
0 commit comments