Skip to content

Commit 2580ac6

Browse files
committed
chore(NumberTheory/SelbergSieve): turn BoundingSieve into a struct (#27820)
Based on a discussion [on zulip](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/BoundingSieve.20is.20a.20class.3F.3F). I wound up removing the custom notation as well, since not everybody was fond of it and I had some trouble getting it to work properly with structure inheritance and the corresponding coersions.
1 parent a7ada22 commit 2580ac6

File tree

1 file changed

+51
-84
lines changed

1 file changed

+51
-84
lines changed

Mathlib/NumberTheory/SelbergSieve.lean

Lines changed: 51 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,6 @@ minor notational difference is that we write $\nu(n)$ in place of $\frac{\omega(
2121
* `siftedSum_le_mainSum_errSum_of_UpperBoundSieve` - Every upper bound sieve gives an upper bound
2222
on the size of the sifted set in terms of `mainSum` and `errSum`
2323
24-
## Notation
25-
The `SelbergSieve.Notation` namespace includes common shorthand for the variables included in the
26-
`SelbergSieve` structure.
27-
* `A` for `support`
28-
* `𝒜 d` for `multSum d` - the combined weight of the elements of `A` that are divisible by `d`
29-
* `P` for `prodPrimes`
30-
* `a` for `weights`
31-
* `X` for `totalMass`
32-
* `ν` for `nu`
33-
* `y` for `level`
34-
* `R d` for `rem d`
35-
* `g d` for `selbergTerms d`
36-
3724
## References
3825
3926
* [Heath-Brown, *Lectures on sieves*][heathbrown2002lecturessieves]
@@ -56,7 +43,7 @@ and `ν` is a multiplicative arithmetic function such that `0 < ν p < 1` for al
5643
Then a sieve-type theorem will give us an upper (or lower) bound on the size of the sifted sum
5744
`∑ n ∈ {k ∈ support | k.Coprime P}, a n`, obtained by removing any elements of `A` that are a
5845
multiple of a prime in `P`. -/
59-
class BoundingSieve where
46+
structure BoundingSieve where
6047
/-- The set of natural numbers that is to be sifted. The fundamental lemma yields an upper bound
6148
on the size of this set after the multiples of small primes have been removed. -/
6249
support : Finset ℕ
@@ -80,7 +67,7 @@ class BoundingSieve where
8067

8168
/-- The Selberg upper bound sieve in particular introduces a parameter called the `level` which
8269
gives the user control over the size of the error term. -/
83-
class SelbergSieve extends BoundingSieve where
70+
structure SelbergSieve extends BoundingSieve where
8471
/-- The `level` of the sieve controls how many terms we include in the inclusion-exclusion type
8572
sum. A higher level will yield a tighter bound for the main term, but will also increase the
8673
size of the error term. -/
@@ -94,120 +81,99 @@ namespace Mathlib.Meta.Positivity
9481
open Lean Meta Qq
9582

9683
/-- Extension for the `positivity` tactic: `BoundingSieve.weights`. -/
97-
@[positivity BoundingSieve.weights _]
84+
@[positivity BoundingSieve.weights _ _]
9885
def evalBoundingSieveWeights : PositivityExt where eval {u α} _zα _pα e := do
9986
match u, α, e with
100-
| 0, ~q(ℝ), ~q(@BoundingSieve.weights $i $n) =>
87+
| 0, ~q(ℝ), ~q(@BoundingSieve.weights $s $n) =>
10188
assertInstancesCommute
102-
pure (.nonnegative q(BoundingSieve.weights_nonneg $n))
89+
pure (.nonnegative q(BoundingSieve.weights_nonneg $s $n))
10390
| _, _, _ => throwError "not BoundingSieve.weights"
10491

10592
end Mathlib.Meta.Positivity
10693

107-
namespace SelbergSieve
108-
open BoundingSieve
109-
110-
namespace Notation
111-
112-
@[inherit_doc nu]
113-
scoped notation3 "ν" => nu
114-
@[inherit_doc prodPrimes]
115-
scoped notation3 "P" => prodPrimes
116-
@[inherit_doc weights]
117-
scoped notation3 "a" => weights
118-
@[inherit_doc totalMass]
119-
scoped notation3 "X" => totalMass
120-
@[inherit_doc support]
121-
scoped notation3 "A" => support
122-
@[inherit_doc level]
123-
scoped notation3 "y" => level
94+
namespace BoundingSieve
95+
open SelbergSieve
12496

125-
theorem one_le_y [s : SelbergSieve] : 1y := one_le_level
97+
theorem one_le_y {s : SelbergSieve} : 1s.level := s.one_le_level
12698

127-
end Notation
128-
129-
open Notation
130-
131-
variable [s : BoundingSieve]
99+
variable {s : BoundingSieve}
132100

133101
/-! Lemmas about $P$. -/
134102

135-
theorem prodPrimes_ne_zero : P0 :=
136-
Squarefree.ne_zero prodPrimes_squarefree
103+
theorem prodPrimes_ne_zero : s.prodPrimes0 :=
104+
Squarefree.ne_zero s.prodPrimes_squarefree
137105

138-
theorem squarefree_of_dvd_prodPrimes {d : ℕ} (hd : d ∣ P) : Squarefree d :=
139-
Squarefree.squarefree_of_dvd hd prodPrimes_squarefree
106+
theorem squarefree_of_dvd_prodPrimes {d : ℕ} (hd : d ∣ s.prodPrimes) : Squarefree d :=
107+
Squarefree.squarefree_of_dvd hd s.prodPrimes_squarefree
140108

141-
theorem squarefree_of_mem_divisors_prodPrimes {d : ℕ} (hd : d ∈ divisors P) : Squarefree d := by
109+
theorem squarefree_of_mem_divisors_prodPrimes {d : ℕ} (hd : d ∈ divisors s.prodPrimes) :
110+
Squarefree d := by
142111
simp only [Nat.mem_divisors] at hd
143-
exact Squarefree.squarefree_of_dvd hd.left prodPrimes_squarefree
112+
exact Squarefree.squarefree_of_dvd hd.left s.prodPrimes_squarefree
144113

145114
/-! Lemmas about $\nu$. -/
146115

147-
theorem prod_primeFactors_nu {d : ℕ} (hd : d ∣ P) : ∏ p ∈ d.primeFactors, ν p = ν d := by
148-
rw [← nu_mult.map_prod_of_subset_primeFactors _ _ subset_rfl,
149-
Nat.prod_primeFactors_of_squarefree <| Squarefree.squarefree_of_dvd hd prodPrimes_squarefree]
116+
theorem prod_primeFactors_nu {d : ℕ} (hd : d ∣ s.prodPrimes) :
117+
∏ p ∈ d.primeFactors, s.nu p = s.nu d := by
118+
rw [← s.nu_mult.map_prod_of_subset_primeFactors _ _ subset_rfl,
119+
Nat.prod_primeFactors_of_squarefree <| Squarefree.squarefree_of_dvd hd s.prodPrimes_squarefree]
150120

151-
theorem nu_pos_of_dvd_prodPrimes {d : ℕ} (hd : d ∣ P) : 0 < ν d := by
121+
theorem nu_pos_of_dvd_prodPrimes {d : ℕ} (hd : d ∣ s.prodPrimes) : 0 < s.nu d := by
152122
calc
153-
0 < ∏ p ∈ d.primeFactors, ν p := by
123+
0 < ∏ p ∈ d.primeFactors, s.nu p := by
154124
apply prod_pos
155125
intro p hpd
156126
have hp_prime : p.Prime := prime_of_mem_primeFactors hpd
157-
have hp_dvd : p ∣ P := (dvd_of_mem_primeFactors hpd).trans hd
158-
exact nu_pos_of_prime p hp_prime hp_dvd
159-
_ = ν d := prod_primeFactors_nu hd
127+
have hp_dvd : p ∣ s.prodPrimes := (dvd_of_mem_primeFactors hpd).trans hd
128+
exact s.nu_pos_of_prime p hp_prime hp_dvd
129+
_ = s.nu d := prod_primeFactors_nu hd
160130

161-
theorem nu_ne_zero {d : ℕ} (hd : d ∣ P) : ν d ≠ 0 := by
131+
theorem nu_ne_zero {d : ℕ} (hd : d ∣ s.prodPrimes) : s.nu d ≠ 0 := by
162132
apply _root_.ne_of_gt
163133
exact nu_pos_of_dvd_prodPrimes hd
164134

165-
theorem nu_lt_one_of_dvd_prodPrimes {d : ℕ} (hdP : d ∣ P) (hd_ne_one : d ≠ 1) : ν d < 1 := by
166-
have hd_sq : Squarefree d := Squarefree.squarefree_of_dvd hdP prodPrimes_squarefree
135+
theorem nu_lt_one_of_dvd_prodPrimes {d : ℕ} (hdP : d ∣ s.prodPrimes) (hd_ne_one : d ≠ 1) :
136+
s.nu d < 1 := by
137+
have hd_sq : Squarefree d := Squarefree.squarefree_of_dvd hdP s.prodPrimes_squarefree
167138
have := hd_sq.ne_zero
168139
calc
169-
ν d = ∏ p ∈ d.primeFactors, ν p := (prod_primeFactors_nu hdP).symm
140+
s.nu d = ∏ p ∈ d.primeFactors, s.nu p := (prod_primeFactors_nu hdP).symm
170141
_ < ∏ p ∈ d.primeFactors, 1 := by
171142
apply prod_lt_prod_of_nonempty
172143
· intro p hp
173144
simp only [mem_primeFactors] at hp
174-
apply nu_pos_of_prime p hp.1 (hp.2.1.trans hdP)
145+
apply s.nu_pos_of_prime p hp.1 (hp.2.1.trans hdP)
175146
· intro p hpd; rw [mem_primeFactors_of_ne_zero hd_sq.ne_zero] at hpd
176-
apply nu_lt_one_of_prime p hpd.left (hpd.2.trans hdP)
147+
apply s.nu_lt_one_of_prime p hpd.left (hpd.2.trans hdP)
177148
· simp only [nonempty_primeFactors, show 1 < d by omega]
178149
_ = 1 := by
179150
simp
180151

181152
/-- The weight of all the elements that are a multiple of `d`. -/
182153
@[simp]
183-
def multSum (d : ℕ) : ℝ := ∑ n ∈ A, if d ∣ n then a n else 0
154+
def multSum (d : ℕ) : ℝ := ∑ n ∈ s.support, if d ∣ n then s.weights n else 0
184155

185-
@[inherit_doc multSum]
186-
scoped[SelbergSieve.Notation] notation3 "𝒜" => multSum
187156

188157
/-- The remainder term in the approximation A_d = ν (d) X + R_d. This is the degree to which `nu`
189158
fails to approximate the proportion of the weight that is a multiple of `d`. -/
190159
@[simp]
191-
def rem (d : ℕ) : ℝ := 𝒜 d - ν d * X
192-
193-
@[inherit_doc rem]
194-
scoped[SelbergSieve.Notation] notation3 "R" => rem
160+
def rem (d : ℕ) : ℝ := s.multSum d - s.nu d * s.totalMass
195161

196162
/-- The weight of all the elements that are not a multiple of any of our finite set of primes. -/
197-
def siftedSum : ℝ := ∑ d ∈ A, if Coprime P d then a d else 0
163+
def siftedSum : ℝ := ∑ d ∈ s.support, if Coprime s.prodPrimes d then s.weights d else 0
198164

199165
/-- `X * mainSum μ⁺` is the main term in the upper bound on `sifted_sum`. -/
200-
def mainSum (muPlus : ℕ → ℝ) : ℝ := ∑ d ∈ divisors P, muPlus d * ν d
166+
def mainSum (muPlus : ℕ → ℝ) : ℝ := ∑ d ∈ divisors s.prodPrimes, muPlus d * s.nu d
201167

202168
/-- `errSum μ⁺` is the error term in the upper bound on `sifted_sum`. -/
203-
def errSum (muPlus : ℕ → ℝ) : ℝ := ∑ d ∈ divisors P, |muPlus d| * |R d|
169+
def errSum (muPlus : ℕ → ℝ) : ℝ := ∑ d ∈ divisors s.prodPrimes, |muPlus d| * |s.rem d|
204170

205-
theorem multSum_eq_main_err (d : ℕ) : multSum d = ν d * X + R d := by
171+
theorem multSum_eq_main_err (d : ℕ) : s.multSum d = s.nu d * s.totalMass + s.rem d := by
206172
dsimp [rem]
207173
ring
208174

209175
theorem siftedSum_eq_sum_support_mul_ite :
210-
siftedSum = ∑ d ∈ support, a d * if Nat.gcd P d = 1 then 1 else 0 := by
176+
s.siftedSum = ∑ d ∈ s.support, s.weights d * if Nat.gcd s.prodPrimes d = 1 then 1 else 0 := by
211177
dsimp only [siftedSum]
212178
simp_rw [mul_ite, mul_one, mul_zero]
213179

@@ -221,16 +187,17 @@ def IsUpperMoebius (muPlus : ℕ → ℝ) : Prop :=
221187
∀ n : ℕ, (if n = 1 then 1 else 0) ≤ ∑ d ∈ n.divisors, muPlus d
222188

223189
theorem siftedSum_le_sum_of_upperMoebius (muPlus : ℕ → ℝ) (h : IsUpperMoebius muPlus) :
224-
siftedSum ≤ ∑ d ∈ divisors P, muPlus d * multSum d := by
190+
s.siftedSum ≤ ∑ d ∈ divisors s.prodPrimes, muPlus d * s.multSum d := by
225191
have hμ : ∀ n, (if n = 1 then 1 else 0) ≤ ∑ d ∈ n.divisors, muPlus d := h
226192
calc siftedSum ≤
227-
∑ n ∈ support, a n * ∑ d ∈ (Nat.gcd P n).divisors, muPlus d := ?caseA
228-
_ = ∑ n ∈ support, ∑ d ∈ divisors P, if d ∣ n then a n * muPlus d else 0 := ?caseB
229-
_ = ∑ d ∈ divisors P, muPlus d * multSum d := ?caseC
193+
∑ n ∈ s.support, s.weights n * ∑ d ∈ (Nat.gcd s.prodPrimes n).divisors, muPlus d := ?caseA
194+
_ = ∑ n ∈ s.support, ∑ d ∈ divisors s.prodPrimes,
195+
if d ∣ n then s.weights n * muPlus d else 0 := ?caseB
196+
_ = ∑ d ∈ divisors s.prodPrimes, muPlus d * multSum d := ?caseC
230197
case caseA =>
231198
rw [siftedSum_eq_sum_support_mul_ite]
232199
gcongr with n
233-
exact hμ (Nat.gcd P n)
200+
exact hμ (Nat.gcd s.prodPrimes n)
234201
case caseB =>
235202
simp_rw [mul_sum, ← sum_filter]
236203
congr with n
@@ -242,17 +209,17 @@ theorem siftedSum_le_sum_of_upperMoebius (muPlus : ℕ → ℝ) (h : IsUpperMoeb
242209
simp_rw [multSum, ← sum_filter, mul_sum, mul_comm]
243210

244211
theorem siftedSum_le_mainSum_errSum_of_upperMoebius (muPlus : ℕ → ℝ) (h : IsUpperMoebius muPlus) :
245-
siftedSum ≤ X * mainSum muPlus + errSum muPlus := calc
246-
siftedSum ≤ ∑ d ∈ divisors P, muPlus d * multSum d :=
212+
s.siftedSum ≤ s.totalMass * s.mainSum muPlus + s.errSum muPlus := calc
213+
s.siftedSum ≤ ∑ d ∈ divisors s.prodPrimes, muPlus d * multSum d :=
247214
siftedSum_le_sum_of_upperMoebius _ h
248-
_ = X * mainSum muPlus + ∑ d ∈ divisors P, muPlus d * R d := by
215+
_ = s.totalMass * mainSum muPlus + ∑ d ∈ divisors s.prodPrimes, muPlus d * s.rem d := by
249216
rw [mainSum, mul_sum, ← sum_add_distrib]
250217
congr with d
251218
dsimp only [rem]; ring
252-
_ ≤ X * mainSum muPlus + errSum muPlus := by
219+
_ ≤ s.totalMass * mainSum muPlus + errSum muPlus := by
253220
rw [errSum]
254221
gcongr _ + ∑ d ∈ _, ?_ with d
255222
rw [← abs_mul]
256-
exact le_abs_self (muPlus d * R d)
223+
exact le_abs_self (muPlus d * s.rem d)
257224

258-
end SelbergSieve
225+
end BoundingSieve

0 commit comments

Comments
 (0)