Skip to content

Commit a956de5

Browse files
committed
feat(NumberTheory/Primorial): expand API for primorial (#36962)
This PR adds some simple API lemmas for the primorial, moves `le_primorial_self` and simplifies the proof to not need Bertrand, along with an `lt_primorial_self` version. We also provide an `lt` version of the primorial upper bound.
1 parent 81059bb commit a956de5

File tree

3 files changed

+67
-28
lines changed

3 files changed

+67
-28
lines changed

Mathlib/NumberTheory/Bertrand.lean

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ theorem centralBinom_le_of_no_bertrand_prime (n : ℕ) (n_large : 2 < n)
180180
refine pow_right_mono₀ n2_pos ((Finset.card_le_card fun x hx => ?_).trans this.le)
181181
obtain ⟨h1, h2⟩ := Finset.mem_filter.1 hx
182182
exact Finset.mem_Icc.mpr ⟨(Finset.mem_filter.1 h1).2.one_lt.le, h2⟩
183-
· refine le_trans ?_ (primorial_le_4_pow (2 * n / 3))
183+
· refine le_trans ?_ (primorial_le_four_pow (2 * n / 3))
184184
refine (Finset.prod_le_prod' fun p hp => (?_ : f p ≤ p)).trans ?_
185185
· obtain ⟨h1, h2⟩ := Finset.mem_filter.1 hp
186186
refine (pow_right_mono₀ (Finset.mem_filter.1 h1).2.one_lt.le ?_).trans (pow_one p).le
@@ -238,20 +238,6 @@ theorem exists_prime_lt_and_le_two_mul (n : ℕ) (hn0 : n ≠ 0) :
238238

239239
alias bertrand := Nat.exists_prime_lt_and_le_two_mul
240240

241-
lemma le_primorial_self {n : ℕ} : n ≤ primorial n := by
242-
rcases lt_or_ge n 4 with hn | hn
243-
· interval_cases n <;> decide
244-
· suffices ∃ p ≥ 3, p.Prime ∧ p ≤ n ∧ n ≤ 2 * p by
245-
obtain ⟨p, _, pp, _, hp⟩ := this
246-
apply hp.trans
247-
have rearr : 2 * p = ∏ q ∈ {2, p}, if q.Prime then q else 1 := by
248-
simp (disch := grind) [pp, prime_two]
249-
rw [rearr, primorial, Finset.prod_filter]
250-
refine Finset.prod_le_prod_of_subset_of_one_le' (by grind) fun _ _ _ ↦ ?_
251-
exact iteInduction Prime.one_le fun _ ↦ le_rfl
252-
obtain ⟨p, pp, _, _⟩ := bertrand (n / 2) (by lia)
253-
exact ⟨p, by lia, pp, by lia, by lia⟩
254-
255241
end Nat
256242

257243
end Nat

Mathlib/NumberTheory/Chebyshev.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ theorem theta_le_log4_mul_x {x : ℝ} (hx : 0 ≤ x) : θ x ≤ log 4 * x := by
140140
rw [theta_eq_log_primorial]
141141
trans log (4 ^ ⌊x⌋₊)
142142
· apply log_le_log <;> norm_cast
143-
exacts [primorial_pos _, primorial_le_4_pow _]
143+
exacts [primorial_pos _, primorial_le_four_pow _]
144144
rw [Real.log_pow, mul_comm]
145145
gcongr
146146
exact floor_le hx

Mathlib/NumberTheory/Primorial.lean

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
/-
22
Copyright (c) 2020 Patrick Stevens. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
4-
Authors: Patrick Stevens, Yury Kudryashov
4+
Authors: Patrick Stevens, Yury Kudryashov, Bhavik Mehta
55
-/
66
module
77

88
public import Mathlib.Algebra.BigOperators.Associated
9-
public import Mathlib.Algebra.Order.BigOperators.GroupWithZero.Finset
10-
public import Mathlib.Algebra.Order.Ring.Abs
9+
public import Mathlib.Algebra.Squarefree.Basic
1110
public import Mathlib.Data.Nat.Choose.Sum
12-
public import Mathlib.Data.Nat.Choose.Dvd
1311
public import Mathlib.Data.Nat.Prime.Basic
1412

13+
import Mathlib.Algebra.Order.BigOperators.GroupWithZero.Finset
14+
import Mathlib.Algebra.Order.Ring.Abs
15+
import Mathlib.Data.Nat.Choose.Dvd
16+
import Mathlib.Data.Nat.Squarefree
17+
1518
/-!
1619
# Primorial
1720
@@ -37,9 +40,23 @@ def primorial (n : ℕ) : ℕ := ∏ p ∈ range (n + 1) with p.Prime, p
3740

3841
local notation x "#" => primorial x
3942

43+
@[simp] theorem primorial_zero : 0 # = 1 := by decide
44+
45+
@[simp] theorem primorial_one : 1 # = 1 := by decide
46+
47+
@[simp] theorem primorial_two : 2 # = 2 := by decide
48+
4049
theorem primorial_pos (n : ℕ) : 0 < n# :=
4150
prod_pos fun _p hp ↦ (mem_filter.1 hp).2.pos
4251

52+
theorem primorial_mono {m n : ℕ} (h : m ≤ n) : m# ≤ n# :=
53+
prod_le_prod_of_subset_of_one_le' (by gcongr) (by grind)
54+
55+
theorem primorial_monotone : Monotone primorial := fun _ _ ↦ primorial_mono
56+
57+
theorem primorial_dvd_primorial {m n : ℕ} (h : m ≤ n) : m# ∣ n# :=
58+
prod_dvd_prod_of_subset _ _ _ (by gcongr)
59+
4360
theorem primorial_succ {n : ℕ} (hn1 : n ≠ 1) (hn : Odd n) : (n + 1)# = n# := by
4461
refine prod_congr ?_ fun _ _ ↦ rfl
4562
rw [range_add_one, filter_insert, if_neg fun h ↦ not_even_iff_odd.2 hn _]
@@ -63,22 +80,58 @@ theorem primorial_add_dvd {m n : ℕ} (h : n ≤ m) : (m + n)# ∣ m# * choose (
6380
theorem primorial_add_le {m n : ℕ} (h : n ≤ m) : (m + n)# ≤ m# * choose (m + n) m :=
6481
le_of_dvd (mul_pos (primorial_pos _) (choose_pos <| Nat.le_add_right _ _)) (primorial_add_dvd h)
6582

66-
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
83+
lemma Nat.Prime.dvd_primorial_iff {p n : ℕ} (hp : Prime p) : p ∣ n# ↔ p ≤ n := by
84+
refine ⟨?_, fun h ↦ dvd_prod_of_mem _ (by grind)⟩
85+
intro h
86+
simp only [primorial, hp.prime.dvd_finset_prod_iff, mem_filter, mem_range_succ_iff] at h
87+
obtain ⟨q, ⟨hqn, hq⟩, hpq⟩ := h
88+
exact (Nat.le_of_dvd hq.pos hpq).trans hqn
89+
90+
lemma Nat.Prime.dvd_primorial {p : ℕ} (hp : Prime p) : p ∣ p# :=
91+
hp.dvd_primorial_iff.2 le_rfl
92+
93+
lemma Squarefree.dvd_primorial {n : ℕ} (hn : Squarefree n) : n ∣ n# := by
94+
have : (∏ p ∈ n.primeFactors, p) ∣ (∏ p ∈ range (n + 1) with p.Prime, p) :=
95+
Finset.prod_dvd_prod_of_subset _ _ _ (by grind [le_of_dvd])
96+
rwa [Nat.prod_primeFactors_of_squarefree hn] at this
97+
98+
lemma lt_primorial_self {n : ℕ} (hn : 2 < n) : n < n# := by
99+
have : 3 ≤ n# := single_le_prod' (f := id) (by grind [→ Prime.pos]) (by grind [prime_three])
100+
let q := (n# - 1).minFac
101+
have : n < q := by
102+
by_contra! h1
103+
replace h1 : q ∣ n# := (minFac_prime (by lia)).dvd_primorial_iff.2 h1
104+
grind [minFac_eq_one_iff, dvd_one, dvd_sub_iff_right, minFac_dvd]
105+
grind [Nat.minFac_le]
106+
107+
lemma le_primorial_self {n : ℕ} : n ≤ n# := by
108+
obtain hn | hn := le_or_gt n 2
109+
· decide +revert
110+
· exact (lt_primorial_self hn).le
111+
112+
theorem primorial_lt_four_pow (n : ℕ) (hn : n ≠ 0) : n# < 4 ^ n := by
67113
induction n using Nat.strong_induction_on with | h n ihn =>
68-
rcases n with - | n; · rfl
69-
rcases n.even_or_odd with (⟨m, rfl⟩ | ho)
70-
· rcases m.eq_zero_or_pos with (rfl | hm)
114+
rcases n with - | n; · grind
115+
rcases n.even_or_odd with ⟨m, rfl⟩ | ho
116+
· rcases m.eq_zero_or_pos with rfl | hm
71117
· decide
72118
calc
73119
(m + m + 1)# = (m + 1 + m)# := by rw [add_right_comm]
74120
_ ≤ (m + 1)# * choose (m + 1 + m) (m + 1) := primorial_add_le m.le_succ
75121
_ = (m + 1)# * choose (2 * m + 1) m := by rw [choose_symm_add, two_mul, add_right_comm]
76-
_ 4 ^ (m + 1) * 4 ^ m :=
77-
mul_le_mul' (ihn _ <| succ_lt_succ <| (lt_add_iff_pos_left _).2 hm) (choose_middle_le_pow _)
122+
_ < 4 ^ (m + 1) * 4 ^ m :=
123+
Nat.mul_lt_mul_of_lt_of_le (ihn _ (by lia) (by lia)) (choose_middle_le_pow _) (by simp)
78124
_ ≤ 4 ^ (m + m + 1) := by rw [← pow_add, add_right_comm]
79-
· rcases Decidable.eq_or_ne n 1 with (rfl | hn)
125+
· rcases Decidable.eq_or_ne n 1 with rfl | hn
80126
· decide
81127
· calc
82128
(n + 1)# = n# := primorial_succ hn ho
83-
_ 4 ^ n := ihn n n.lt_succ_self
129+
_ < 4 ^ n := ihn n n.lt_succ_self (by grind)
84130
_ ≤ 4 ^ (n + 1) := Nat.pow_le_pow_right four_pos n.le_succ
131+
132+
theorem primorial_le_four_pow (n : ℕ) : n# ≤ 4 ^ n := by
133+
obtain rfl | hn := eq_or_ne n 0
134+
· decide
135+
· exact (primorial_lt_four_pow n hn).le
136+
137+
@[deprecated (since := "2026-03-21")] alias primorial_le_4_pow := primorial_le_four_pow

0 commit comments

Comments
 (0)