From ec32958b233f647d3cc063b8514a552526f64818 Mon Sep 17 00:00:00 2001 From: Adam Kiezun Date: Mon, 11 May 2026 13:57:17 -0400 Subject: [PATCH 1/2] feat(NumberTheory): add Sylvester-Schur theorem --- Mathlib.lean | 18 + Mathlib/NumberTheory/SylvesterSchur.lean | 15 + .../SylvesterSchur/BlockReductions.lean | 284 ++++++ .../NumberTheory/SylvesterSchur/Bridge.lean | 108 ++ .../SylvesterSchur/ChooseFactorization.lean | 347 +++++++ .../SylvesterSchur/Conditional.lean | 536 ++++++++++ .../NumberTheory/SylvesterSchur/ErdosKey.lean | 314 ++++++ .../SylvesterSchur/ErdosLayers.lean | 204 ++++ .../SylvesterSchur/ErdosPowerBounds.lean | 424 ++++++++ .../SylvesterSchur/LargePrimeCriteria.lean | 360 +++++++ Mathlib/NumberTheory/SylvesterSchur/Main.lean | 91 ++ .../SylvesterSchur/PrimeCounting.lean | 112 +++ .../SylvesterSchur/ResidualFinite.lean | 494 ++++++++++ .../SylvesterSchur/ResidualLarge.lean | 16 + .../ResidualLarge/CentralOffsetBound.lean | 82 ++ .../ResidualLarge/PowerBounds.lean | 100 ++ .../ResidualLarge/ScaledTernaryBound.lean | 923 ++++++++++++++++++ .../ResidualLarge/TinyPrimeCountingBound.lean | 62 ++ .../ResidualLargeCertificates.lean | 716 ++++++++++++++ 19 files changed, 5206 insertions(+) create mode 100644 Mathlib/NumberTheory/SylvesterSchur.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/BlockReductions.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/Bridge.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ChooseFactorization.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/Conditional.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ErdosKey.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ErdosLayers.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ErdosPowerBounds.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/LargePrimeCriteria.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/Main.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/PrimeCounting.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ResidualFinite.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ResidualLarge.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/CentralOffsetBound.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/PowerBounds.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/ScaledTernaryBound.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/TinyPrimeCountingBound.lean create mode 100644 Mathlib/NumberTheory/SylvesterSchur/ResidualLargeCertificates.lean diff --git a/Mathlib.lean b/Mathlib.lean index 4460548cdfeedf..7437d000bb83a8 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5796,6 +5796,24 @@ public import Mathlib.NumberTheory.SmoothNumbers public import Mathlib.NumberTheory.SumFourSquares public import Mathlib.NumberTheory.SumPrimeReciprocals public import Mathlib.NumberTheory.SumTwoSquares +public import Mathlib.NumberTheory.SylvesterSchur +public import Mathlib.NumberTheory.SylvesterSchur.BlockReductions +public import Mathlib.NumberTheory.SylvesterSchur.Bridge +public import Mathlib.NumberTheory.SylvesterSchur.ChooseFactorization +public import Mathlib.NumberTheory.SylvesterSchur.Conditional +public import Mathlib.NumberTheory.SylvesterSchur.ErdosKey +public import Mathlib.NumberTheory.SylvesterSchur.ErdosLayers +public import Mathlib.NumberTheory.SylvesterSchur.ErdosPowerBounds +public import Mathlib.NumberTheory.SylvesterSchur.LargePrimeCriteria +public import Mathlib.NumberTheory.SylvesterSchur.Main +public import Mathlib.NumberTheory.SylvesterSchur.PrimeCounting +public import Mathlib.NumberTheory.SylvesterSchur.ResidualFinite +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge.CentralOffsetBound +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge.PowerBounds +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge.ScaledTernaryBound +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge.TinyPrimeCountingBound +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLargeCertificates public import Mathlib.NumberTheory.Transcendental.Lindemann.AnalyticalPart public import Mathlib.NumberTheory.Transcendental.Liouville.Basic public import Mathlib.NumberTheory.Transcendental.Liouville.LiouvilleNumber diff --git a/Mathlib/NumberTheory/SylvesterSchur.lean b/Mathlib/NumberTheory/SylvesterSchur.lean new file mode 100644 index 00000000000000..5d5f7f078a3d3b --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur.lean @@ -0,0 +1,15 @@ +module -- shake: keep-all + +public import Mathlib.NumberTheory.SylvesterSchur.BlockReductions +public import Mathlib.NumberTheory.SylvesterSchur.Bridge +public import Mathlib.NumberTheory.SylvesterSchur.ChooseFactorization +public import Mathlib.NumberTheory.SylvesterSchur.Conditional +public import Mathlib.NumberTheory.SylvesterSchur.ErdosKey +public import Mathlib.NumberTheory.SylvesterSchur.ErdosLayers +public import Mathlib.NumberTheory.SylvesterSchur.ErdosPowerBounds +public import Mathlib.NumberTheory.SylvesterSchur.LargePrimeCriteria +public import Mathlib.NumberTheory.SylvesterSchur.Main +public import Mathlib.NumberTheory.SylvesterSchur.PrimeCounting +public import Mathlib.NumberTheory.SylvesterSchur.ResidualFinite +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLargeCertificates diff --git a/Mathlib/NumberTheory/SylvesterSchur/BlockReductions.lean b/Mathlib/NumberTheory/SylvesterSchur/BlockReductions.lean new file mode 100644 index 00000000000000..9f56e192261269 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/BlockReductions.lean @@ -0,0 +1,284 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Algebra.BigOperators.Associated +public import Mathlib.Algebra.BigOperators.Group.Finset.Piecewise +public import Mathlib.Algebra.Group.Defs +public import Mathlib.Data.Finset.Card +public import Mathlib.Data.Nat.Choose.Basic +public import Mathlib.Data.Nat.Choose.Dvd +public import Mathlib.Data.Nat.Factorial.Basic +public import Mathlib.Data.Nat.Factorial.BigOperators +public import Mathlib.Data.Nat.Log +public import Mathlib.Data.Nat.ModEq +public import Mathlib.Data.Nat.NthRoot.Defs +public import Mathlib.Data.Nat.Prime.Basic +public import Mathlib.Data.Nat.Prime.Defs +public import Mathlib.Data.Nat.Prime.Factorial +public import Mathlib.Data.Nat.Sqrt +public import Mathlib.NumberTheory.Bertrand +public import Mathlib.NumberTheory.PrimeCounting +public import Mathlib.NumberTheory.Primorial +public import Mathlib.NumberTheory.SmoothNumbers +public import Mathlib.NumberTheory.SylvesterSchur.Conditional + +/-! +# Block-level reductions for the Sylvester-Schur theorem + +This file contains reusable block-product and binomial-coefficient lemmas for the +Sylvester-Schur proof. + +## Bertrand base case +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur +namespace Internal + +open Finset Nat + +/-- In the block starting at `n + 1`, Bertrand's prime in `(n, 2 * n]` is itself +one of the displayed terms. -/ +lemma bertrand_base {n : ℕ} (hn : 1 ≤ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ n + 1 + i := by + obtain ⟨p, hp_prime, hp_gt, hp_le⟩ := + Nat.exists_prime_lt_and_le_two_mul n (Nat.pos_iff_ne_zero.mp (by omega)) + refine ⟨p - (n + 1), ?_, p, hp_prime, hp_gt, ?_⟩ + · omega + · rw [Nat.add_sub_cancel' (by omega : n + 1 ≤ p)] + +/-! +### From block divisibility to binomial divisibility +-/ + +/-- If a prime `n < r` divides `k + j` for some `j < n`, then it divides +`Nat.choose (k + n - 1) n`. -/ +lemma prime_dvd_seq_implies_choose {n k r : ℕ} (hr : r.Prime) (hr_gt : n < r) + (j : ℕ) (hj : j < n) (hdvd : r ∣ k + j) : + r ∣ Nat.choose (k + n - 1) n := + prime_dvd_choose_of_dvd_consecutive hr hr_gt hj hdvd + +/-- A prime in the interval `[k, k + n - 1]`, and larger than `n`, divides the +corresponding block binomial coefficient. -/ +lemma prime_dvd_choose_of_mem_interval {n k p : ℕ} (hp : p.Prime) (hp_gt : n < p) + (hp_ge : k ≤ p) (hp_le : p ≤ k + n - 1) : + p ∣ Nat.choose (k + n - 1) n := + hp.dvd_choose hp_gt (by omega) hp_le + +private lemma exists_prime_dvd_choose_of_large_prime_dvd_term {n k i p : ℕ} + (hi : i < n) (hp : p.Prime) (hp_gt : n < p) (hp_dvd : p ∣ k + i) : + ∃ q : ℕ, q.Prime ∧ n < q ∧ q ∣ Nat.choose (k + n - 1) n := by + exact ⟨p, hp, hp_gt, prime_dvd_seq_implies_choose hp hp_gt i hi hp_dvd⟩ + +/-- A large prime divisor of any term in the block gives a large prime divisor of the +corresponding binomial coefficient. -/ +lemma exists_prime_dvd_choose_of_large_prime_dvd_block {n k : ℕ} + (hblock : ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i) : + ∃ q : ℕ, q.Prime ∧ n < q ∧ q ∣ Nat.choose (k + n - 1) n := by + obtain ⟨i, hi, p, hp, hp_gt, hp_dvd⟩ := hblock + exact exists_prime_dvd_choose_of_large_prime_dvd_term hi hp hp_gt hp_dvd + +private lemma block_term_prime_factors_le_of_no_large_prime_dvd_block {n k : ℕ} + (hblock : ¬ ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i) + {i p : ℕ} (hi : i < n) (hp : p.Prime) (hp_dvd : p ∣ k + i) : + p ≤ n := by + by_contra hp_le + push Not at hp_le + exact hblock ⟨i, hi, p, hp, by omega, hp_dvd⟩ + +private lemma block_term_mem_smoothNumbers_succ_of_no_large_prime_dvd_block {n k i : ℕ} + (hblock : ¬ ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i) + (hi : i < n) : + k + i ∈ Nat.smoothNumbers (n + 1) := by + rw [Nat.mem_smoothNumbers'] + intro p hp hp_dvd + have hp_le : + p ≤ n := + block_term_prime_factors_le_of_no_large_prime_dvd_block hblock hi hp hp_dvd + omega + +private lemma block_length_le_smoothNumbersUpTo_card_of_no_large_prime_dvd_block + {n k : ℕ} + (hblock : ¬ ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i) : + n ≤ (Nat.smoothNumbersUpTo (k + n - 1) (n + 1)).card := by + apply Finset.le_card_of_inj_on_range (fun i => k + i) + · intro i hi + rw [Nat.mem_smoothNumbersUpTo] + have hle_top : k + i ≤ k + n - 1 := by + calc + k + i ≤ k + (n - 1) := Nat.add_le_add_left (Nat.le_sub_one_of_lt hi) k + _ = k + n - 1 := by omega + exact ⟨hle_top, block_term_mem_smoothNumbers_succ_of_no_large_prime_dvd_block hblock hi⟩ + · intro a _ha b _hb hab + exact Nat.add_left_cancel hab + +private lemma block_length_le_smoothNumbersUpTo_bound_of_no_large_prime_dvd_block + {n k : ℕ} + (hblock : ¬ ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i) : + n ≤ 2 ^ Nat.primeCounting n * Nat.sqrt (k + n - 1) := by + have h := + (block_length_le_smoothNumbersUpTo_card_of_no_large_prime_dvd_block hblock).trans + (Nat.smoothNumbersUpTo_card_le (k + n - 1) (n + 1)) + rw [Nat.primeCounting, ← Nat.primesBelow_card_eq_primeCounting' (n + 1)] + exact h + +private lemma exists_dvd_block_or_dvd_recent_pred {n k p : ℕ} (hn : 0 < n) (hp_gt : n < p) : + (∃ i < n, p ∣ k + i) ∨ + ∃ j : ℕ, 1 ≤ j ∧ j ≤ p - n ∧ p ∣ k - j := by + have hp_pos : 0 < p := by omega + by_cases hmod0 : k % p = 0 + · left + exact ⟨0, hn, by + rw [Nat.dvd_iff_mod_eq_zero] + simp [hmod0]⟩ + · let r := k % p + have hr_lt : r < p := Nat.mod_lt k hp_pos + have hr_pos : 0 < r := Nat.pos_of_ne_zero hmod0 + by_cases hhit : p - r < n + · left + refine ⟨p - r, hhit, ?_⟩ + have hsum_mod : k + (p - r) ≡ r + (p - r) [MOD p] := + (Nat.mod_modEq k p).symm.add_right (p - r) + have hsum_eq : r + (p - r) = p := by omega + exact Nat.modEq_zero_iff_dvd.mp <| hsum_mod.trans <| by + simp [hsum_eq] + · right + have hr_le_pred : r ≤ p - n := by omega + have hr_le_k : r ≤ k := Nat.mod_le k p + refine ⟨r, by omega, hr_le_pred, ?_⟩ + have hmodEq : r ≡ k [MOD p] := by + simpa [r] using Nat.mod_modEq k p + exact (Nat.modEq_iff_dvd' hr_le_k).mp hmodEq + +/-- If `s = n + 2` does not divide the two terms immediately before the block, then +it divides some term in the block. -/ +lemma exists_dvd_block_of_succ_succ_prime_not_dvd_pred {n k s : ℕ} (hn : 0 < n) + (hsn : s = n + 2) (hnot_one : ¬ s ∣ k - 1) (hnot_two : ¬ s ∣ k - 2) : + ∃ i < n, s ∣ k + i := by + rcases exists_dvd_block_or_dvd_recent_pred (n := n) (k := k) (p := s) hn (by omega) + with hblock | hpred + · exact hblock + obtain ⟨j, hj1, hjle, hjdvd⟩ := hpred + rcases (by omega : j = 1 ∨ j = 2) with rfl | rfl + · exact (hnot_one hjdvd).elim + · exact (hnot_two hjdvd).elim + +/-! ### Binomial criteria from block estimates -/ + +/-- A large-start consecutive-block estimate gives the corresponding binomial +large-prime criterion. -/ +lemma exists_prime_dvd_choose_of_large_start {n k : ℕ} (hn : 2 ≤ n) (hk : n < k) + (hlarge : n ! * 2 ^ (n - 1) < k) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + obtain ⟨i, hi, p, hp, hp_gt, hp_dvd⟩ := consecutive_of_large_start hn hk hlarge + exact ⟨p, hp, by omega, prime_dvd_seq_implies_choose hp (by omega) i hi hp_dvd⟩ + +/-- The half-exponent conditional estimate gives the corresponding binomial +large-prime criterion. -/ +lemma exists_prime_dvd_choose_of_half_bound {n k : ℕ} (hn : 1 ≤ n) (hk : n < k) + (hbound : n ! * (k + n - 1) ^ (n / 2 + 1) < k ^ n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + obtain ⟨i, hi, p, hp, hp_gt, hp_dvd⟩ := + consecutive_of_factorial_mul_top_pow_half_add_one_lt_start_pow hn hk hbound + exact ⟨p, hp, by omega, prime_dvd_seq_implies_choose hp (by omega) i hi hp_dvd⟩ + +/-- If no block term has a prime divisor larger than `n`, the quadratic-start +consecutive estimate forces `k ≤ n ^ 2`. -/ +lemma start_le_quadratic_of_no_large_prime_dvd_block {n k : ℕ} (hn : 38 ≤ n) + (hblock : ¬ ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i) : + k ≤ n ^ 2 := by + by_contra hkquad + push Not at hkquad + obtain ⟨i, hi, p, hp, hp_gt, hp_dvd⟩ := consecutive_of_quadratic_start hn hkquad + exact hblock ⟨i, hi, p, hp, by omega, hp_dvd⟩ + +/-- Prime-counting conditional estimate in binomial form. -/ +lemma exists_prime_dvd_choose_of_primeCounting_bound {n k : ℕ} (hn : 1 ≤ n) + (hk : n < k) (hbound : n ! * (k + n - 1) ^ Nat.primeCounting n < k ^ n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + obtain ⟨i, hi, p, hp, hp_gt, hp_dvd⟩ := + consecutive_of_factorial_mul_top_pow_primeCounting_lt_start_pow hn hk hbound + exact ⟨p, hp, by omega, prime_dvd_seq_implies_choose hp (by omega) i hi hp_dvd⟩ + +/-- Split `sqrt/primorial` conditional estimate in binomial form. -/ +lemma exists_prime_dvd_choose_of_sqrt_primorial_bound {n k : ℕ} (hn : 1 ≤ n) + (hk : n < k) + (hbound : + n ! * ((k + n - 1) ^ (Nat.sqrt (k + n - 1) + 1) * primorial n) < k ^ n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + obtain ⟨i, hi, p, hp, hp_gt, hp_dvd⟩ := + consecutive_of_factorial_mul_top_pow_sqrt_mul_primorial_lt_start_pow hn hk hbound + exact ⟨p, hp, by omega, prime_dvd_seq_implies_choose hp (by omega) i hi hp_dvd⟩ + +/-- Full Erdős layer conditional estimate in binomial form. -/ +lemma exists_prime_dvd_choose_of_erdos_layers_bound {n k : ℕ} (hn : 1 ≤ n) + (hk : n < k) + (hbound : + n ! * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial n else primorial (Nat.nthRoot (j + 1) (k + n - 1))) < + k ^ n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + obtain ⟨i, hi, p, hp, hp_gt, hp_dvd⟩ := + consecutive_of_factorial_mul_prod_erdos_layers_lt_start_pow hn hk hbound + exact ⟨p, hp, by omega, prime_dvd_seq_implies_choose hp (by omega) i hi hp_dvd⟩ + +/-- Erdős layer estimate with first layer `N / 3`, in binomial form. -/ +lemma exists_prime_dvd_choose_of_erdos_div_three_layers_bound {n k : ℕ} + (hn : 1 ≤ n) (hk : n < k) (hN6 : 6 ≤ k + n - 1) + (hbound : + n ! * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial ((k + n - 1) / 3) + else primorial (Nat.nthRoot (j + 1) (k + n - 1))) < + k ^ n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + obtain ⟨i, hi, p, hp, hp_gt, hp_dvd⟩ := + consecutive_of_factorial_mul_prod_erdos_div_three_layers_lt_start_pow hn hk hN6 hbound + exact ⟨p, hp, by omega, prime_dvd_seq_implies_choose hp (by omega) i hi hp_dvd⟩ + +/-- Coarse power-of-four Erdős layer estimate in binomial form. -/ +lemma exists_prime_dvd_choose_of_erdos_layers_four_pow_bound {n k : ℕ} + (hn : 1 ≤ n) (hk : n < k) + (hbound : + n ! * + 4 ^ (n + Nat.sqrt (k + n - 1) * Nat.log 2 (k + n - 1)) < + k ^ n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + apply exists_prime_dvd_choose_of_erdos_layers_bound hn hk + have hprod := erdos_layers_le_four_pow (k + n - 1) n + exact (Nat.mul_le_mul_left (n !) hprod).trans_lt hbound + +/-- Three-layer power-of-four Erdős estimate in binomial form. -/ +lemma exists_prime_dvd_choose_of_erdos_layers_three_layers_bound {n k : ℕ} + (hn : 1 ≤ n) (hk : n < k) + (hbound : + n ! * + 4 ^ (n + Nat.sqrt (k + n - 1) + + Nat.nthRoot 3 (k + n - 1) * Nat.log 2 (k + n - 1)) < + k ^ n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + apply exists_prime_dvd_choose_of_erdos_layers_bound hn hk + have hprod := erdos_layers_le_four_pow_three_layers (k + n - 1) n + exact (Nat.mul_le_mul_left (n !) hprod).trans_lt hbound + +/-- The smooth-number count contradiction gives a large prime divisor of the block +binomial coefficient. -/ +lemma exists_prime_dvd_choose_of_smooth_count_bound {n k : ℕ} + (hbound : 2 ^ Nat.primeCounting n * Nat.sqrt (k + n - 1) < n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + by_cases hblock : ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i + · exact exists_prime_dvd_choose_of_large_prime_dvd_block hblock + · have hle := + block_length_le_smoothNumbersUpTo_bound_of_no_large_prime_dvd_block (n := n) (k := k) + hblock + omega + + +end Internal +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/Bridge.lean b/Mathlib/NumberTheory/SylvesterSchur/Bridge.lean new file mode 100644 index 00000000000000..cb21416366d555 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/Bridge.lean @@ -0,0 +1,108 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Data.Nat.Choose.Basic +public import Mathlib.Data.Nat.Prime.Basic + +import Mathlib.Algebra.BigOperators.Associated +import Mathlib.Data.Nat.Factorial.BigOperators +import Mathlib.Data.Nat.Prime.Factorial + +/-! +# Sylvester-Schur: binomial and consecutive forms + +This file records the elementary bridge between the binomial-coefficient form + +`∃ p, p.Prime ∧ i < p ∧ p ∣ Nat.choose N i`, for `1 ≤ i` and `2 * i ≤ N`, + +and the consecutive-integer form + +among `n` consecutive integers starting at `k` with `n < k`, one has a prime divisor +greater than `n`. + +The bridge contains no use of the main Sylvester-Schur theorem itself. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur + +open scoped BigOperators + +open Finset Nat + +/- Binomial-coefficient form of Sylvester-Schur. -/ +private def binomial_sylvester_schur : Prop := + ∀ N i : ℕ, 1 ≤ i → 2 * i ≤ N → + ∃ p : ℕ, p.Prime ∧ i < p ∧ p ∣ Nat.choose N i + +/- Consecutive-integer form of Sylvester-Schur. -/ +private def consecutive_sylvester_schur : Prop := + ∀ n k : ℕ, 1 ≤ n → n < k → + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i + +/-- If a prime `n < p` divides one term in the `n`-term block starting at `k`, then it +divides the corresponding binomial coefficient. -/ +theorem prime_dvd_choose_of_dvd_consecutive {n k p j : ℕ} (hp : p.Prime) (hp_gt : n < p) + (hj : j < n) (hdvd : p ∣ k + j) : + p ∣ Nat.choose (k + n - 1) n := by + have hprod_eq : k.ascFactorial n = n ! * Nat.choose (k + n - 1) n := + Nat.ascFactorial_eq_factorial_mul_choose' k n + have hprod_eq_range : k.ascFactorial n = ∏ i ∈ Finset.range n, (k + i) := + Nat.ascFactorial_eq_prod_range k n + have hp_dvd_prod : p ∣ ∏ i ∈ Finset.range n, (k + i) := + hdvd.trans (Finset.dvd_prod_of_mem _ (Finset.mem_range.mpr hj)) + rw [← hprod_eq_range, hprod_eq] at hp_dvd_prod + exact (hp.coprime_factorial_of_lt hp_gt).dvd_of_dvd_mul_left hp_dvd_prod + +/-- If a prime `n < p` divides `Nat.choose (k+n-1) n`, then it divides some term +`k+i` in the corresponding `n`-term block. -/ +theorem exists_dvd_consecutive_of_prime_dvd_choose (n k p : ℕ) (hp : p.Prime) + (_hp_gt : n < p) (hp_dvd : p ∣ Nat.choose (k + n - 1) n) : + ∃ i < n, p ∣ k + i := by + have hprod_eq : k.ascFactorial n = n ! * Nat.choose (k + n - 1) n := + Nat.ascFactorial_eq_factorial_mul_choose' k n + have hprod_eq_range : k.ascFactorial n = ∏ i ∈ Finset.range n, (k + i) := + Nat.ascFactorial_eq_prod_range k n + have hp_dvd_prod : p ∣ ∏ i ∈ Finset.range n, (k + i) := by + rw [← hprod_eq_range, hprod_eq] + exact dvd_mul_of_dvd_right hp_dvd (n !) + rw [hp.prime.dvd_finsetProd_iff] at hp_dvd_prod + simpa [Finset.mem_range] using hp_dvd_prod + +/-- A large prime divisor of the relevant binomial coefficient gives a large prime divisor in +the consecutive block. -/ +theorem consecutive_of_exists_prime_dvd_choose {n k : ℕ} + (hbin : ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + obtain ⟨p, hp, hp_gt, hp_dvd⟩ := hbin + obtain ⟨i, hi, hi_dvd⟩ := + exists_dvd_consecutive_of_prime_dvd_choose n k p hp hp_gt hp_dvd + exact ⟨i, hi, p, hp, hp_gt, hi_dvd⟩ + +/- The binomial form implies the consecutive-integer form. -/ +private lemma consecutive_of_binomial (h : binomial_sylvester_schur) : + consecutive_sylvester_schur := by + intro n k hn hk + exact consecutive_of_exists_prime_dvd_choose (h (k + n - 1) n hn (by omega)) + +/- The consecutive-integer form implies the binomial form. -/ +private lemma binomial_of_consecutive (h : consecutive_sylvester_schur) : + binomial_sylvester_schur := by + intro N i hi hhalf + have hk_gt : i < N - i + 1 := by omega + obtain ⟨j, hj, p, hp, hp_gt, hp_dvd⟩ := h i (N - i + 1) hi hk_gt + refine ⟨p, hp, hp_gt, ?_⟩ + have hchoose := prime_dvd_choose_of_dvd_consecutive hp hp_gt hj hp_dvd + rwa [show N - i + 1 + i - 1 = N from by omega] at hchoose + +/- The two standard Sylvester-Schur formulations are equivalent. -/ +private lemma binomial_iff_consecutive : + binomial_sylvester_schur ↔ consecutive_sylvester_schur := + ⟨consecutive_of_binomial, binomial_of_consecutive⟩ + +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/ChooseFactorization.lean b/Mathlib/NumberTheory/SylvesterSchur/ChooseFactorization.lean new file mode 100644 index 00000000000000..d06f96ec062f65 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ChooseFactorization.lean @@ -0,0 +1,347 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Analysis.SpecialFunctions.Pow.NthRootLemmas +public import Mathlib.Data.Nat.Choose.Central +public import Mathlib.Data.Nat.Choose.Factorization +public import Mathlib.NumberTheory.Primorial +public import Mathlib.NumberTheory.SylvesterSchur.PrimeCounting + +/-! +# Binomial factorization bounds for Sylvester-Schur + +This file bounds binomial coefficients under the hypothesis that all prime +divisors are small, using factorization and primorial estimates. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur + +open scoped BigOperators + +open Finset Nat + +/-! ### Binomial factorization bounds -/ + +/-- If every prime divisor of `Nat.choose N r` is at most `r`, then the product formula for +`Nat.choose N r` can be truncated from primes up to `N` to candidates up to `r`. -/ +theorem choose_eq_prod_small_prime_powers_of_no_large {N r : ℕ} (hrN : r ≤ N) + (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + (∏ p ∈ Finset.range (r + 1), p ^ (Nat.choose N r).factorization p) = + Nat.choose N r := by + calc + (∏ p ∈ Finset.range (r + 1), p ^ (Nat.choose N r).factorization p) + = ∏ p ∈ Finset.range (N + 1), p ^ (Nat.choose N r).factorization p := by + apply Finset.prod_subset + · intro p hp + exact Finset.mem_range.mpr <| (Finset.mem_range.mp hp).trans_le + (Nat.succ_le_succ hrN) + · intro p hpN hp_not_small + rw [Finset.mem_range] at hpN hp_not_small + have hpr : r < p := by omega + by_cases hp : p.Prime + · by_cases hdvd : p ∣ Nat.choose N r + · exact (hpr.not_ge (hsmall p hp hdvd)).elim + · rw [Nat.factorization_eq_zero_of_not_dvd hdvd, pow_zero] + · rw [Nat.factorization_eq_zero_of_not_prime _ hp, pow_zero] + _ = Nat.choose N r := Nat.prod_pow_factorization_choose N r hrN + +/- A first crude consequence of the previous lemma: under the same no-large-prime hypothesis, +`Nat.choose N r` is at most `N ^ (r + 1)`. This bound is too weak for the final theorem, but it is +a useful checkpoint for the factorization part of the proof. -/ +private lemma choose_le_top_pow_succ_of_no_large {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) + (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r ≤ N ^ (r + 1) := by + rw [← choose_eq_prod_small_prime_powers_of_no_large hrN hsmall] + calc + (∏ p ∈ Finset.range (r + 1), p ^ (Nat.choose N r).factorization p) + ≤ ∏ _p ∈ Finset.range (r + 1), N := by + apply Finset.prod_le_prod' + intro p hp_mem + by_cases hp : p.Prime + · exact Nat.pow_factorization_choose_le hN + · rw [Nat.factorization_eq_zero_of_not_prime _ hp, pow_zero] + exact hN + _ = N ^ (r + 1) := by simp + +/-- The same no-large-prime hypothesis gives the sharper Erdős factorization bound with exponent +`Nat.primeCounting r`. The remaining hard part of the classical proof is to contradict this bound +using lower estimates for the relevant binomial coefficient. -/ +theorem choose_le_top_pow_primeCounting_of_no_large {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) + (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r ≤ N ^ Nat.primeCounting r := by + rw [← choose_eq_prod_small_prime_powers_of_no_large hrN hsmall] + calc + (∏ p ∈ Finset.range (r + 1), p ^ (Nat.choose N r).factorization p) + = ∏ p ∈ (Finset.range (r + 1)).filter Nat.Prime, + p ^ (Nat.choose N r).factorization p := by + rw [Finset.prod_filter_of_ne] + intro p _ hp_ne_one + by_contra hp_not_prime + simp [Nat.factorization_eq_zero_of_not_prime _ hp_not_prime] at hp_ne_one + _ ≤ ∏ _p ∈ (Finset.range (r + 1)).filter Nat.Prime, N := by + exact Finset.prod_le_prod' fun p hp_mem => Nat.pow_factorization_choose_le hN + _ = N ^ Nat.primeCounting r := by + rw [Finset.prod_const] + congr + rw [Nat.primeCounting, ← Nat.primesBelow_card_eq_primeCounting' (r + 1), + Nat.primesBelow] + +/-- Replacing `Nat.primeCounting r` by the elementary bound `r - 1` gives a slightly coarser +version of the preceding no-large-prime estimate. -/ +theorem choose_le_top_pow_sub_one_of_no_large {N r : ℕ} (hN : 0 < N) (hr : 2 ≤ r) + (hrN : r ≤ N) (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r ≤ N ^ (r - 1) := by + exact (choose_le_top_pow_primeCounting_of_no_large hN hrN hsmall).trans + (Nat.pow_le_pow_right hN (primeCounting_le_sub_one hr)) + +/-- Using the already-formalized prime-counting bound `π(r) ≤ r / 2 + 1` gives a sharper +no-large-prime estimate. -/ +theorem choose_le_top_pow_half_add_one_of_no_large {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) + (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r ≤ N ^ (r / 2 + 1) := by + exact (choose_le_top_pow_primeCounting_of_no_large hN hrN hsmall).trans + (Nat.pow_le_pow_right hN (primeCounting_le_half_add_one r)) + +/-- Using the project `π(r) ≤ 3r/8` estimate gives the corresponding no-large-prime bound. -/ +theorem choose_le_top_pow_three_mul_div_eight_of_no_large {N r : ℕ} (hN : 0 < N) + (hr : 38 ≤ r) (hrN : r ≤ N) + (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r ≤ N ^ (3 * r / 8) := by + exact (choose_le_top_pow_primeCounting_of_no_large hN hrN hsmall).trans + (Nat.pow_le_pow_right hN (primeCounting_le_three_mul_div_eight hr)) + +/- Fixed-layer form of the Erdős prime-power estimate. For a fixed exponent `j`, primes whose +exponent in `Nat.choose N r` is at least `j` all lie below the `j`th root of `N`; hence their +product is bounded by the corresponding primorial. -/ +private lemma layer_prime_product_le_primorial_nthRoot {N r j : ℕ} (hN : 0 < N) (hj : j ≠ 0) : + (∏ p ∈ (Finset.range (r + 1)).filter + (fun p => p.Prime ∧ j ≤ (Nat.choose N r).factorization p), p) ≤ + primorial (Nat.nthRoot j N) := by + dsimp [primorial] + apply Finset.prod_le_prod_of_subset_of_one_le' + · intro p hp + rw [Finset.mem_filter] at hp + rw [Finset.mem_filter] + have hp_prime : p.Prime := hp.2.1 + have hpow_le : + p ^ j ≤ p ^ (Nat.choose N r).factorization p := + Nat.pow_le_pow_right hp_prime.one_le hp.2.2 + have hpow_top : + p ^ (Nat.choose N r).factorization p ≤ N := + Nat.pow_factorization_choose_le hN + have hp_root : p ≤ Nat.nthRoot j N := + (Nat.le_nthRoot_iff hj).mpr (hpow_le.trans hpow_top) + exact ⟨Finset.mem_range.mpr (Nat.lt_succ_iff.mpr hp_root), hp_prime⟩ + · intro p hp _hp_not + exact (Finset.mem_filter.mp hp).2.one_le + +/- Zero-based layer form: primes whose exponent is greater than `j` are controlled by the +`(j+1)`st root of `N`. -/ +private lemma layer_prime_product_lt_factorization_le_primorial_nthRoot {N r j : ℕ} + (hN : 0 < N) : + (∏ p ∈ (Finset.range (r + 1)).filter + (fun p => p.Prime ∧ j < (Nat.choose N r).factorization p), p) ≤ + primorial (Nat.nthRoot (j + 1) N) := by + simpa [Nat.succ_le_iff] using + (layer_prime_product_le_primorial_nthRoot (N := N) (r := r) (j := j + 1) hN + (by omega)) + +/- The first Erdős layer: primes that occur at least once are bounded by the primorial of `r` +under the no-large-prime truncation. -/ +private lemma first_layer_prime_product_le_primorial {N r : ℕ} : + (∏ p ∈ (Finset.range (r + 1)).filter + (fun p => p.Prime ∧ 0 < (Nat.choose N r).factorization p), p) ≤ primorial r := by + dsimp [primorial] + apply Finset.prod_le_prod_of_subset_of_one_le' + · intro p hp + rw [Finset.mem_filter] at hp + rw [Finset.mem_filter] + exact ⟨hp.1, hp.2.1⟩ + · intro p hp _hp_not + exact (Finset.mem_filter.mp hp).2.one_le + +private lemma first_layer_prime_product_le_primorial_div_three_aux {N r : ℕ} + (h2rN : 2 * r ≤ N) (hN6 : 6 ≤ N) : + (∏ p ∈ (Finset.range (r + 1)).filter + (fun p => p.Prime ∧ 0 < (Nat.choose N r).factorization p), p) ≤ + primorial (N / 3) := by + dsimp [primorial] + apply Finset.prod_le_prod_of_subset_of_one_le' + · intro p hp + rw [Finset.mem_filter] at hp + rw [Finset.mem_filter] + have hp_prime : p.Prime := hp.2.1 + have hp_le_r : p ≤ r := by + rw [Finset.mem_range] at hp + omega + have hp_le_sub : p ≤ N - r := by omega + have hp_le_div : p ≤ N / 3 := by + by_cases hp2 : p = 2 + · subst hp2 + omega + · have hnot : ¬ N < 3 * p := by + intro hlt + have hzero : + (Nat.choose N r).factorization p = 0 := + Nat.factorization_choose_of_lt_three_mul hp2 hp_le_r hp_le_sub hlt + omega + have hle : 3 * p ≤ N := by omega + omega + exact ⟨Finset.mem_range.mpr (Nat.lt_succ_iff.mpr hp_le_div), hp_prime⟩ + · intro p hp _hp_not + exact (Finset.mem_filter.mp hp).2.one_le + +/- Central-range first layer. If `2 * r ≤ N < 3 * r`, then every prime `p ≤ r` +that divides `Nat.choose N r` is at most `N / 3`. This is the formal version of +Erdős's observation in the `2r < N < 3r` case, using Mathlib's +`Nat.factorization_choose_of_lt_three_mul`. -/ +private lemma first_layer_central_prime_product_le_primorial_div_three {N r : ℕ} + (h2rN : 2 * r ≤ N) (_hNlt3r : N < 3 * r) (hN6 : 6 ≤ N) : + (∏ p ∈ (Finset.range (r + 1)).filter + (fun p => p.Prime ∧ 0 < (Nat.choose N r).factorization p), p) ≤ + primorial (N / 3) := by + exact first_layer_prime_product_le_primorial_div_three_aux h2rN hN6 + +/- First-layer `N / 3` bound without a central-range assumption. If `2 * r ≤ N`, then +every prime `p ≤ r` in the first layer of `Nat.choose N r` is at most `N / 3` (apart from +`p = 2`, which is also at most `N / 3` once `6 ≤ N`). -/ +private lemma first_layer_prime_product_le_primorial_div_three {N r : ℕ} + (h2rN : 2 * r ≤ N) (hN6 : 6 ≤ N) : + (∏ p ∈ (Finset.range (r + 1)).filter + (fun p => p.Prime ∧ 0 < (Nat.choose N r).factorization p), p) ≤ + primorial (N / 3) := by + exact first_layer_prime_product_le_primorial_div_three_aux h2rN hN6 + +/- Product over the first `L` layers with membership `j < e` is exactly `p ^ e`, provided +`e ≤ L`. -/ +private lemma prod_range_ite_lt_eq_pow (p e L : ℕ) (heL : e ≤ L) : + (∏ j ∈ Finset.range L, if j < e then p else 1) = p ^ e := by + rw [← Finset.prod_filter (s := Finset.range L) (p := fun j => j < e) (f := fun _ => p)] + have hfilter : (Finset.range L).filter (fun j => j < e) = Finset.range e := by + ext j + simp only [Finset.mem_filter, Finset.mem_range] + omega + rw [hfilter, Finset.prod_const, Finset.card_range] + +private lemma choose_eq_prod_prime_factorization_layers {N r : ℕ} (hrN : r ≤ N) + (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r = + ∏ j ∈ Finset.range (Nat.log 2 N), + ∏ p ∈ ((Finset.range (r + 1)).filter Nat.Prime).filter + (fun p => j < (Nat.choose N r).factorization p), p := by + classical + conv_lhs => rw [← choose_eq_prod_small_prime_powers_of_no_large hrN hsmall] + let S : Finset ℕ := (Finset.range (r + 1)).filter Nat.Prime + calc + (∏ p ∈ Finset.range (r + 1), p ^ (Nat.choose N r).factorization p) + = ∏ p ∈ S, p ^ (Nat.choose N r).factorization p := by + dsimp [S] + exact (Finset.prod_filter_of_ne + (s := Finset.range (r + 1)) (p := Nat.Prime) + (f := fun p => p ^ (Nat.choose N r).factorization p) + (by + intro p _ hp_ne_one + change p ^ (Nat.choose N r).factorization p ≠ 1 at hp_ne_one + by_contra hp_not_prime + simp [Nat.factorization_eq_zero_of_not_prime _ hp_not_prime] at hp_ne_one)).symm + _ = ∏ p ∈ S, ∏ j ∈ Finset.range (Nat.log 2 N), + if j < (Nat.choose N r).factorization p then p else 1 := by + apply Finset.prod_congr rfl + intro p hp + dsimp [S] at hp + rw [Finset.mem_filter] at hp + exact (prod_range_ite_lt_eq_pow p ((Nat.choose N r).factorization p) + (Nat.log 2 N) + (Nat.factorization_choose_le_log.trans + (Nat.log_anti_left Nat.one_lt_two hp.2.two_le))).symm + _ = ∏ j ∈ Finset.range (Nat.log 2 N), ∏ p ∈ S, + if j < (Nat.choose N r).factorization p then p else 1 := by + exact Finset.prod_comm + _ = ∏ j ∈ Finset.range (Nat.log 2 N), + ∏ p ∈ S.filter (fun p => j < (Nat.choose N r).factorization p), p := by + apply Finset.prod_congr rfl + intro j hj + exact (Finset.prod_filter + (s := S) (p := fun p => j < (Nat.choose N r).factorization p) + (f := fun p => p)).symm + +/-- Full Erdős prime-power layer bound. Under the no-large-prime hypothesis, the binomial +coefficient is bounded by the product of primorials at successive roots of `N`. -/ +theorem choose_le_prod_primorial_nthRoot_of_no_large {N r : ℕ} (hN : 0 < N) + (hrN : r ≤ N) (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r ≤ + ∏ j ∈ Finset.range (Nat.log 2 N), primorial (Nat.nthRoot (j + 1) N) := by + classical + rw [choose_eq_prod_prime_factorization_layers hrN hsmall] + exact Finset.prod_le_prod' fun j hj => by + have hlayer := layer_prime_product_lt_factorization_le_primorial_nthRoot + (N := N) (r := r) (j := j) hN + simpa [Finset.filter_filter, and_assoc, and_left_comm, and_comm] using hlayer + +/-- Sharpened full Erdős layer bound. The first layer uses the no-large-prime cutoff `r`; +subsequent layers use the root bounds. This matches the product estimate in Erdős's proof. -/ +theorem choose_le_prod_erdos_layers_of_no_large {N r : ℕ} (hN : 0 < N) + (hrN : r ≤ N) (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r ≤ + ∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N) := by + classical + rw [choose_eq_prod_prime_factorization_layers hrN hsmall] + exact Finset.prod_le_prod' fun j hj => by + by_cases hj0 : j = 0 + · subst hj0 + have hlayer := first_layer_prime_product_le_primorial (N := N) (r := r) + simpa [Finset.filter_filter, and_assoc, and_left_comm, and_comm] using hlayer + · have hlayer := layer_prime_product_lt_factorization_le_primorial_nthRoot + (N := N) (r := r) (j := j) hN + simpa [hj0, Finset.filter_filter, and_assoc, and_left_comm, and_comm] using hlayer + +/-- Sharpened Erdős layer bound in the central range `2 * r ≤ N < 3 * r`. The first +layer is bounded by `primorial (N / 3)` rather than `primorial r`. -/ +theorem choose_le_prod_erdos_central_layers_of_no_large {N r : ℕ} (hN : 0 < N) + (hrN : r ≤ N) (h2rN : 2 * r ≤ N) (hNlt3r : N < 3 * r) (hN6 : 6 ≤ N) + (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r ≤ + ∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N) := by + classical + rw [choose_eq_prod_prime_factorization_layers hrN hsmall] + exact Finset.prod_le_prod' fun j hj => by + by_cases hj0 : j = 0 + · subst hj0 + have hlayer := + first_layer_central_prime_product_le_primorial_div_three + (N := N) (r := r) h2rN hNlt3r hN6 + simpa [Finset.filter_filter, and_assoc, and_left_comm, and_comm] using hlayer + · have hlayer := layer_prime_product_lt_factorization_le_primorial_nthRoot + (N := N) (r := r) (j := j) hN + simpa [hj0, Finset.filter_filter, and_assoc, and_left_comm, and_comm] using hlayer + +/-- Sharpened Erdős layer bound with the `N / 3` first layer. Unlike +`choose_le_prod_erdos_central_layers_of_no_large`, this form does not assume `N < 3 * r`; +the first-layer cutoff follows from `Nat.factorization_choose_of_lt_three_mul`. -/ +theorem choose_le_prod_erdos_div_three_layers_of_no_large {N r : ℕ} (hN : 0 < N) + (hrN : r ≤ N) (h2rN : 2 * r ≤ N) (hN6 : 6 ≤ N) + (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r ≤ + ∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N) := by + classical + rw [choose_eq_prod_prime_factorization_layers hrN hsmall] + exact Finset.prod_le_prod' fun j hj => by + by_cases hj0 : j = 0 + · subst hj0 + have hlayer := + first_layer_prime_product_le_primorial_div_three (N := N) (r := r) h2rN hN6 + simpa [Finset.filter_filter, and_assoc, and_left_comm, and_comm] using hlayer + · have hlayer := layer_prime_product_lt_factorization_le_primorial_nthRoot + (N := N) (r := r) (j := j) hN + simpa [hj0, Finset.filter_filter, and_assoc, and_left_comm, and_comm] using hlayer + +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/Conditional.lean b/Mathlib/NumberTheory/SylvesterSchur/Conditional.lean new file mode 100644 index 00000000000000..3d86d8e13ca9fd --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/Conditional.lean @@ -0,0 +1,536 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Algebra.BigOperators.Group.Finset.Defs +public import Mathlib.Algebra.Group.Defs +public import Mathlib.Data.Nat.Choose.Basic +public import Mathlib.Data.Nat.Choose.Dvd +public import Mathlib.Data.Nat.Factorial.Basic +public import Mathlib.Data.Nat.Prime.Basic +public import Mathlib.Data.Nat.Sqrt +public import Mathlib.NumberTheory.Bertrand +public import Mathlib.NumberTheory.PrimeCounting +public import Mathlib.NumberTheory.Primorial +public import Mathlib.NumberTheory.SylvesterSchur.Bridge +public import Mathlib.NumberTheory.SylvesterSchur.LargePrimeCriteria + +/-! +# Conditional Sylvester-Schur consequences + +This file connects the small binomial coefficient estimates to the consecutive-integer +form. The remaining hard work is to prove estimates such as +`n ! * (k + n - 1) ^ Nat.primeCounting n < k ^ n` in the required range. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur + +open scoped BigOperators + +open Finset Nat + +/- Bertrand gives a prime divisor greater than `n` of the central binomial coefficient +`Nat.choose (2 * n) n`. This is the base binomial case of Sylvester-Schur. -/ +private lemma exists_large_prime_dvd_central_choose {n : ℕ} (hn : 1 ≤ n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (2 * n) n := by + obtain ⟨p, hp, hp_gt, hp_le⟩ := + Nat.exists_prime_lt_and_le_two_mul n (Nat.pos_iff_ne_zero.mp (by omega)) + refine ⟨p, hp, hp_gt, ?_⟩ + simpa [two_mul] using Nat.Prime.dvd_choose_add hp hp_gt hp_gt (by simpa [two_mul] using hp_le) + +/- Bertrand also proves the consecutive theorem for the base start `k = n + 1`. -/ +private lemma consecutive_base_start {n : ℕ} (hn : 1 ≤ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ n + 1 + i := by + obtain ⟨p, hp, hp_gt, hp_le⟩ := + Nat.exists_prime_lt_and_le_two_mul n (Nat.pos_iff_ne_zero.mp (by omega)) + refine ⟨p - (n + 1), ?_, p, hp, hp_gt, ?_⟩ + · omega + · rw [Nat.add_sub_cancel' (by omega : n + 1 ≤ p)] + +/- The consecutive theorem for blocks of length one. -/ +private lemma consecutive_one {k : ℕ} (hk : 1 < k) : + ∃ i : ℕ, i < 1 ∧ ∃ p : ℕ, p.Prime ∧ 1 < p ∧ p ∣ k + i := by + obtain ⟨p, hp, hp_dvd⟩ := Nat.exists_prime_and_dvd (by omega : k ≠ 1) + exact ⟨0, by omega, p, hp, hp.one_lt, by simpa using hp_dvd⟩ + +/-- The consecutive theorem for blocks of length two. -/ +theorem consecutive_two {k : ℕ} (hk : 2 < k) : + ∃ i : ℕ, i < 2 ∧ ∃ p : ℕ, p.Prime ∧ 2 < p ∧ p ∣ k + i := by + by_cases hk_even : 2 ∣ k + · have hk1_mf_prime : (k + 1).minFac.Prime := + Nat.minFac_prime (by omega : k + 1 ≠ 1) + have hk1_mf_odd : 2 < (k + 1).minFac := by + by_contra h + push Not at h + have htwo_dvd_k1 : 2 ∣ k + 1 := + (le_antisymm h hk1_mf_prime.two_le) ▸ (k + 1).minFac_dvd + omega + exact ⟨1, by omega, (k + 1).minFac, hk1_mf_prime, hk1_mf_odd, + by simpa using (k + 1).minFac_dvd⟩ + · have hk_mf_prime : k.minFac.Prime := Nat.minFac_prime (by omega : k ≠ 1) + have hk_mf_odd : 2 < k.minFac := by + by_contra h + push Not at h + exact hk_even ((le_antisymm h hk_mf_prime.two_le) ▸ k.minFac_dvd) + exact ⟨0, by omega, k.minFac, hk_mf_prime, hk_mf_odd, by simpa using k.minFac_dvd⟩ + +/- A number greater than one and coprime to `6` has a prime divisor greater than `3`. -/ +private lemma exists_prime_gt_three_dvd_of_not_two_dvd_of_not_three_dvd {m : ℕ} + (hm : 1 < m) (h2 : ¬ 2 ∣ m) (h3 : ¬ 3 ∣ m) : + ∃ p : ℕ, p.Prime ∧ 3 < p ∧ p ∣ m := by + obtain ⟨p, hp, hdvd⟩ := Nat.exists_prime_and_dvd (by omega : m ≠ 1) + refine ⟨p, hp, ?_, hdvd⟩ + by_contra hle + push Not at hle + have hp_two : 2 ≤ p := hp.two_le + interval_cases p + · exact h2 hdvd + · exact h3 hdvd + +/- A number greater than one and coprime to `30` has a prime divisor greater than `5`. -/ +private lemma exists_prime_gt_five_dvd_of_not_two_dvd_of_not_three_dvd_of_not_five_dvd + {m : ℕ} (hm : 1 < m) (h2 : ¬ 2 ∣ m) (h3 : ¬ 3 ∣ m) (h5 : ¬ 5 ∣ m) : + ∃ p : ℕ, p.Prime ∧ 5 < p ∧ p ∣ m := by + obtain ⟨p, hp, hdvd⟩ := Nat.exists_prime_and_dvd (by omega : m ≠ 1) + refine ⟨p, hp, ?_, hdvd⟩ + by_contra hle + push Not at hle + have hp_two : 2 ≤ p := hp.two_le + interval_cases p + · exact h2 hdvd + · exact h3 hdvd + · norm_num at hp + · exact h5 hdvd + +private lemma four_lt_of_prime_of_three_lt {p : ℕ} (hp : p.Prime) (h3 : 3 < p) : 4 < p := by + have hp_ne_four : p ≠ 4 := by + rintro rfl + norm_num at hp + omega + +private lemma six_lt_of_prime_of_five_lt {p : ℕ} (hp : p.Prime) (h5 : 5 < p) : 6 < p := by + have hp_ne_six : p ≠ 6 := by + rintro rfl + norm_num at hp + omega + +private lemma half_witness_three {k i : ℕ} (hi : i < 3) (hm : 1 < (k + i) / 2) + (heven : 2 ∣ k + i) (hcop : ¬ 2 ∣ (k + i) / 2 ∧ ¬ 3 ∣ (k + i) / 2) : + ∃ i m, i < 3 ∧ 1 < m ∧ m ∣ k + i ∧ ¬ 2 ∣ m ∧ ¬ 3 ∣ m := by + exact ⟨i, (k + i) / 2, hi, hm, Nat.div_dvd_of_dvd heven, hcop.1, hcop.2⟩ + +private lemma half_witness_five {k i : ℕ} (hi : i < 5) (hm : 1 < (k + i) / 2) + (heven : 2 ∣ k + i) + (hcop : ¬ 2 ∣ (k + i) / 2 ∧ ¬ 3 ∣ (k + i) / 2 ∧ ¬ 5 ∣ (k + i) / 2) : + ∃ i m, i < 5 ∧ 1 < m ∧ m ∣ k + i ∧ ¬ 2 ∣ m ∧ ¬ 3 ∣ m ∧ ¬ 5 ∣ m := by + exact ⟨i, (k + i) / 2, hi, hm, Nat.div_dvd_of_dvd heven, hcop.1, hcop.2.1, + hcop.2.2⟩ + +/- A finite witness certificate for the length-three consecutive theorem. -/ +private lemma consecutive_three_witness {k : ℕ} (hk : 3 < k) : + ∃ i m, i < 3 ∧ 1 < m ∧ m ∣ k + i ∧ ¬ 2 ∣ m ∧ ¬ 3 ∣ m := by + have hlt : k % 12 < 12 := Nat.mod_lt k (by norm_num) + interval_cases hmod : k % 12 + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega⟩ + · exact half_witness_three (i := 0) (by norm_num) (by omega) (by omega) (by omega) + · exact ⟨2, k + 2, by norm_num, by omega, by simp, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega⟩ + · exact half_witness_three (i := 2) (by norm_num) (by omega) (by omega) (by omega) + · exact ⟨2, k + 2, by norm_num, by omega, by simp, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega⟩ + +/-- The consecutive theorem for blocks of length three. -/ +theorem consecutive_three {k : ℕ} (hk : 3 < k) : + ∃ i : ℕ, i < 3 ∧ ∃ p : ℕ, p.Prime ∧ 3 < p ∧ p ∣ k + i := by + obtain ⟨i, m, hi, hm, hmdvd, h2, h3⟩ := consecutive_three_witness hk + obtain ⟨p, hp, hp_gt, hp_dvd⟩ := + exists_prime_gt_three_dvd_of_not_two_dvd_of_not_three_dvd hm h2 h3 + exact ⟨i, hi, p, hp, hp_gt, hp_dvd.trans hmdvd⟩ + +/-- The consecutive theorem for blocks of length four. -/ +theorem consecutive_four {k : ℕ} (hk : 4 < k) : + ∃ i : ℕ, i < 4 ∧ ∃ p : ℕ, p.Prime ∧ 4 < p ∧ p ∣ k + i := by + obtain ⟨i, hi, p, hp, hp_gt_three, hp_dvd⟩ := consecutive_three (k := k) (by omega) + exact ⟨i, by omega, p, hp, four_lt_of_prime_of_three_lt hp hp_gt_three, hp_dvd⟩ + +/- The finite residue certificate for the length-five consecutive theorem. -/ +private lemma consecutive_five_witness_mod_lt_fifteen {k : ℕ} (hk : 5 < k) + (hmod_lt : k % 60 < 15) : + ∃ i m, i < 5 ∧ 1 < m ∧ m ∣ k + i ∧ ¬ 2 ∣ m ∧ ¬ 3 ∣ m ∧ ¬ 5 ∣ m := by + interval_cases hmod : k % 60 + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact half_witness_five (i := 0) (by norm_num) (by omega) (by omega) (by omega) + · exact ⟨4, k + 4, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨3, k + 3, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨2, k + 2, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨3, k + 3, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨2, k + 2, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact half_witness_five (i := 0) (by norm_num) (by omega) (by omega) (by omega) + +private lemma consecutive_five_witness_mod_fifteen_to_twenty_nine {k : ℕ} (hk : 5 < k) + (hmod_ge : 15 ≤ k % 60) (hmod_lt : k % 60 < 30) : + ∃ i m, i < 5 ∧ 1 < m ∧ m ∣ k + i ∧ ¬ 2 ∣ m ∧ ¬ 3 ∣ m ∧ ¬ 5 ∣ m := by + interval_cases hmod : k % 60 + · exact ⟨2, k + 2, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact half_witness_five (i := 2) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 1) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 0) (by norm_num) (by omega) (by omega) (by omega) + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact half_witness_five (i := 2) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 1) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 0) (by norm_num) (by omega) (by omega) (by omega) + · exact ⟨2, k + 2, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + +private lemma consecutive_five_witness_mod_thirty_to_forty_four {k : ℕ} (hk : 5 < k) + (hmod_ge : 30 ≤ k % 60) (hmod_lt : k % 60 < 45) : + ∃ i m, i < 5 ∧ 1 < m ∧ m ∣ k + i ∧ ¬ 2 ∣ m ∧ ¬ 3 ∣ m ∧ ¬ 5 ∣ m := by + interval_cases hmod : k % 60 + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact half_witness_five (i := 2) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 1) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 0) (by norm_num) (by omega) (by omega) (by omega) + · exact ⟨2, k + 2, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact half_witness_five (i := 0) (by norm_num) (by omega) (by omega) (by omega) + · exact ⟨2, k + 2, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact half_witness_five (i := 2) (by norm_num) (by omega) (by omega) (by omega) + +private lemma consecutive_five_witness_mod_forty_five_to_fifty_nine {k : ℕ} (hk : 5 < k) + (hmod_ge : 45 ≤ k % 60) (hmod_lt : k % 60 < 60) : + ∃ i m, i < 5 ∧ 1 < m ∧ m ∣ k + i ∧ ¬ 2 ∣ m ∧ ¬ 3 ∣ m ∧ ¬ 5 ∣ m := by + interval_cases hmod : k % 60 + · exact half_witness_five (i := 1) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 0) (by norm_num) (by omega) (by omega) (by omega) + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨3, k + 3, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨2, k + 2, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨1, k + 1, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + · exact half_witness_five (i := 4) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 3) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 2) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 1) (by norm_num) (by omega) (by omega) (by omega) + · exact half_witness_five (i := 0) (by norm_num) (by omega) (by omega) (by omega) + · exact ⟨0, k, by norm_num, by omega, by simp, by omega, by omega, by omega⟩ + +/- A finite witness certificate for the length-five consecutive theorem. It chooses +a term, or half of an even term, that is coprime to `2`, `3`, and `5`. -/ +private lemma consecutive_five_witness {k : ℕ} (hk : 5 < k) : + ∃ i m, i < 5 ∧ 1 < m ∧ m ∣ k + i ∧ ¬ 2 ∣ m ∧ ¬ 3 ∣ m ∧ ¬ 5 ∣ m := by + by_cases h15 : k % 60 < 15 + · exact consecutive_five_witness_mod_lt_fifteen hk h15 + by_cases h30 : k % 60 < 30 + · exact consecutive_five_witness_mod_fifteen_to_twenty_nine hk (by omega) h30 + by_cases h45 : k % 60 < 45 + · exact consecutive_five_witness_mod_thirty_to_forty_four hk (by omega) h45 + exact consecutive_five_witness_mod_forty_five_to_fifty_nine hk (by omega) + (Nat.mod_lt k (by norm_num)) + +/- The finite residue certificate for the length-five consecutive theorem. -/ +private lemma consecutive_five_finite_certificate {k : ℕ} (hk : 5 < k) : + ∃ i : ℕ, i < 5 ∧ ∃ p : ℕ, p.Prime ∧ 5 < p ∧ p ∣ k + i := by + obtain ⟨i, m, hi, hm, hmdvd, h2, h3, h5⟩ := consecutive_five_witness hk + obtain ⟨p, hp, hp_gt, hp_dvd⟩ := + exists_prime_gt_five_dvd_of_not_two_dvd_of_not_three_dvd_of_not_five_dvd + hm h2 h3 h5 + exact ⟨i, hi, p, hp, hp_gt, hp_dvd.trans hmdvd⟩ + +/-- The consecutive theorem for blocks of length five. -/ +theorem consecutive_five {k : ℕ} (hk : 5 < k) : + ∃ i : ℕ, i < 5 ∧ ∃ p : ℕ, p.Prime ∧ 5 < p ∧ p ∣ k + i := + consecutive_five_finite_certificate hk + +/-- The consecutive theorem for blocks of length six. -/ +theorem consecutive_six {k : ℕ} (hk : 6 < k) : + ∃ i : ℕ, i < 6 ∧ ∃ p : ℕ, p.Prime ∧ 6 < p ∧ p ∣ k + i := by + obtain ⟨i, hi, p, hp, hp_gt_five, hp_dvd⟩ := consecutive_five (k := k) (by omega) + exact ⟨i, by omega, p, hp, six_lt_of_prime_of_five_lt hp hp_gt_five, hp_dvd⟩ + +/-- Conditional consecutive form using the sharper `Nat.primeCounting n` exponent. -/ +theorem consecutive_of_factorial_mul_top_pow_primeCounting_lt_start_pow {n k : ℕ} + (hn : 1 ≤ n) (hk : n < k) + (hbound : n ! * (k + n - 1) ^ Nat.primeCounting n < k ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_factorial_mul_top_pow_primeCounting_lt_lower_pow + (by omega) (by omega) + simpa [show k + n - 1 + 1 - n = k by omega] using hbound + +/-- Conditional consecutive form using the project prime-counting estimate +`Nat.primeCounting n ≤ n / 2 + 1`. -/ +theorem consecutive_of_factorial_mul_top_pow_half_add_one_lt_start_pow {n k : ℕ} + (hn : 1 ≤ n) (hk : n < k) + (hbound : n ! * (k + n - 1) ^ (n / 2 + 1) < k ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_factorial_mul_top_pow_half_add_one_lt_lower_pow + (by omega) (by omega) + simpa [show k + n - 1 + 1 - n = k by omega] using hbound + +/- Conditional consecutive form using the explicit `π(n) ≤ 3n/8` estimate. -/ +private lemma consecutive_of_factorial_mul_top_pow_three_mul_div_eight_lt_start_pow + {n k : ℕ} (hn : 38 ≤ n) (hk : n < k) + (hbound : n ! * (k + n - 1) ^ (3 * n / 8) < k ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_factorial_mul_top_pow_three_mul_div_eight_lt_lower_pow + (by omega) hn (by omega) + simpa [show k + n - 1 + 1 - n = k by omega] using hbound + +/- Large-start form of the `3n/8` estimate. Since `k + n - 1 ≤ 2k`, it is enough to +dominate the leftover power of `k`. -/ +private lemma consecutive_of_three_eighth_large_start {n k : ℕ} (hn : 38 ≤ n) (hk : n < k) + (hlarge : n ! * 2 ^ (3 * n / 8) < k ^ (n - 3 * n / 8)) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_factorial_mul_top_pow_three_mul_div_eight_lt_start_pow hn hk + calc + n ! * (k + n - 1) ^ (3 * n / 8) ≤ n ! * (2 * k) ^ (3 * n / 8) := by + exact Nat.mul_le_mul_left (n !) + (Nat.pow_le_pow_left (by omega : k + n - 1 ≤ 2 * k) (3 * n / 8)) + _ = n ! * (2 ^ (3 * n / 8) * k ^ (3 * n / 8)) := by + rw [Nat.mul_pow] + _ = (n ! * 2 ^ (3 * n / 8)) * k ^ (3 * n / 8) := by ring + _ < k ^ (n - 3 * n / 8) * k ^ (3 * n / 8) := by + exact Nat.mul_lt_mul_of_pos_right hlarge (pow_pos (by omega : 0 < k) (3 * n / 8)) + _ = k ^ n := by + rw [← pow_add] + congr 1 + omega + +/- Power-only consecutive form of the `3n/8` criterion, using `n! ≤ n ^ n`. -/ +private lemma consecutive_of_self_pow_mul_top_pow_three_mul_div_eight_lt_start_pow + {n k : ℕ} (hn : 38 ≤ n) (hk : n < k) + (hbound : n ^ n * (k + n - 1) ^ (3 * n / 8) < k ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_self_pow_mul_top_pow_three_mul_div_eight_lt_lower_pow + (by omega) hn (by omega) + simpa [show k + n - 1 + 1 - n = k by omega] using hbound + +/- Pure-power large-start form of the `3n/8` criterion. -/ +private lemma consecutive_of_three_eighth_self_pow_large_start {n k : ℕ} (hn : 38 ≤ n) + (hk : n < k) (hlarge : n ^ n * 2 ^ (3 * n / 8) < k ^ (n - 3 * n / 8)) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_self_pow_mul_top_pow_three_mul_div_eight_lt_start_pow hn hk + calc + n ^ n * (k + n - 1) ^ (3 * n / 8) ≤ n ^ n * (2 * k) ^ (3 * n / 8) := by + exact Nat.mul_le_mul_left (n ^ n) + (Nat.pow_le_pow_left (by omega : k + n - 1 ≤ 2 * k) (3 * n / 8)) + _ = n ^ n * (2 ^ (3 * n / 8) * k ^ (3 * n / 8)) := by + rw [Nat.mul_pow] + _ = (n ^ n * 2 ^ (3 * n / 8)) * k ^ (3 * n / 8) := by ring + _ < k ^ (n - 3 * n / 8) * k ^ (3 * n / 8) := by + exact Nat.mul_lt_mul_of_pos_right hlarge (pow_pos (by omega : 0 < k) (3 * n / 8)) + _ = k ^ n := by + rw [← pow_add] + congr 1 + omega + +/-- A simple sufficient condition for the pure-power large-start criterion. -/ +theorem consecutive_of_quadratic_start {n k : ℕ} (hn : 38 ≤ n) + (hkquad : n ^ 2 < k) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_three_eighth_self_pow_large_start hn (by nlinarith [hn, hkquad]) + let e := 3 * n / 8 + have htwo : 2 ^ e ≤ n ^ (n - 2 * e) := by + have h_exp : e ≤ 4 * (n - 2 * e) := by + dsimp [e] + omega + have h16 : 16 ≤ n := by omega + calc + 2 ^ e ≤ 2 ^ (4 * (n - 2 * e)) := + Nat.pow_le_pow_right (by norm_num : 0 < 2) h_exp + _ = 16 ^ (n - 2 * e) := by + rw [show 4 * (n - 2 * e) = (n - 2 * e) * 4 by ring, Nat.pow_mul'] + _ ≤ n ^ (n - 2 * e) := Nat.pow_le_pow_left h16 (n - 2 * e) + have hleft : n ^ n * 2 ^ e ≤ n ^ (2 * (n - e)) := by + calc + n ^ n * 2 ^ e ≤ n ^ n * n ^ (n - 2 * e) := + Nat.mul_le_mul_left (n ^ n) htwo + _ = n ^ (n + (n - 2 * e)) := by rw [← pow_add] + _ = n ^ (2 * (n - e)) := by + congr 1 + omega + have hmid : n ^ (2 * (n - e)) < k ^ (n - e) := by + rw [mul_comm 2 (n - e), Nat.pow_mul'] + exact Nat.pow_lt_pow_left hkquad (by omega : n - e ≠ 0) + exact hleft.trans_lt hmid + +/- Conditional consecutive form using only the elementary exponent `n - 1`. -/ +private lemma consecutive_of_factorial_mul_top_pow_sub_one_lt_start_pow {n k : ℕ} + (hn : 2 ≤ n) (hk : n < k) + (hbound : n ! * (k + n - 1) ^ (n - 1) < k ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_factorial_mul_top_pow_sub_one_lt_lower_pow + (by omega) hn (by omega) + simpa [show k + n - 1 + 1 - n = k by omega] using hbound + +/- Conditional consecutive form from the Erdős split estimate: after splitting the +factorization of `Nat.choose (k+n-1) n` at `sqrt (k+n-1)`, it is enough to prove that this +upper bound is already too small compared with the central-binomial lower bound. -/ +private lemma consecutive_of_mul_top_pow_sqrt_mul_primorial_lt_four_pow {n k : ℕ} + (hn : 4 ≤ n) (hk : n < k) + (hbound : + n * ((k + n - 1) ^ (Nat.sqrt (k + n - 1) + 1) * primorial n) < 4 ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_mul_top_pow_sqrt_mul_primorial_lt_four_pow + · exact hn + · omega + · exact hbound + +/-- Conditional consecutive form using the split `sqrt/primorial` factorization estimate and +the elementary lower bound `k ^ n / n! ≤ Nat.choose (k+n-1) n`. -/ +theorem consecutive_of_factorial_mul_top_pow_sqrt_mul_primorial_lt_start_pow {n k : ℕ} + (hn : 1 ≤ n) (hk : n < k) + (hbound : + n ! * ((k + n - 1) ^ (Nat.sqrt (k + n - 1) + 1) * primorial n) < k ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_factorial_mul_top_pow_sqrt_mul_primorial_lt_lower_pow + (by omega) (by omega) + simpa [show k + n - 1 + 1 - n = k by omega] using hbound + +/- Conditional consecutive form using the full Erdős prime-power layer estimate and the +elementary lower bound `k ^ n / n! ≤ Nat.choose (k+n-1) n`. -/ +private lemma consecutive_of_factorial_mul_prod_primorial_nthRoot_lt_start_pow {n k : ℕ} + (hn : 1 ≤ n) (hk : n < k) + (hbound : + n ! * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + primorial (Nat.nthRoot (j + 1) (k + n - 1))) < + k ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_factorial_mul_prod_primorial_nthRoot_lt_lower_pow + (by omega) (by omega) + simpa [show k + n - 1 + 1 - n = k by omega] using hbound + +/-- Conditional consecutive form using the sharpened Erdős layer product estimate and the +elementary lower bound `k ^ n / n! ≤ Nat.choose (k+n-1) n`. -/ +theorem consecutive_of_factorial_mul_prod_erdos_layers_lt_start_pow {n k : ℕ} + (hn : 1 ≤ n) (hk : n < k) + (hbound : + n ! * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial n else primorial (Nat.nthRoot (j + 1) (k + n - 1))) < + k ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_factorial_mul_prod_erdos_layers_lt_lower_pow + (by omega) (by omega) + simpa [show k + n - 1 + 1 - n = k by omega] using hbound + +/- Conditional consecutive form using the central-range Erdős layer product estimate. -/ +private lemma consecutive_of_factorial_mul_prod_erdos_central_layers_lt_start_pow {n k : ℕ} + (_hn : 1 ≤ n) (hk : n < k) (hcentral : k + n - 1 < 3 * n) + (hN6 : 6 ≤ k + n - 1) + (hbound : + n ! * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial ((k + n - 1) / 3) + else primorial (Nat.nthRoot (j + 1) (k + n - 1))) < + k ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_factorial_mul_prod_erdos_central_layers_lt_lower_pow + (by omega) (by omega) (by omega) hcentral hN6 + simpa [show k + n - 1 + 1 - n = k by omega] using hbound + +/-- Conditional consecutive form using the `N / 3` first-layer Erdős product estimate. +This is the same shape as the central-layer criterion, but without the central-range +assumption `k + n - 1 < 3 * n`. -/ +theorem consecutive_of_factorial_mul_prod_erdos_div_three_layers_lt_start_pow {n k : ℕ} + (_hn : 1 ≤ n) (hk : n < k) (hN6 : 6 ≤ k + n - 1) + (hbound : + n ! * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial ((k + n - 1) / 3) + else primorial (Nat.nthRoot (j + 1) (k + n - 1))) < + k ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + apply exists_large_prime_dvd_choose_of_factorial_mul_prod_erdos_div_three_layers_lt_lower_pow + (by omega) (by omega) (by omega) hN6 + simpa [show k + n - 1 + 1 - n = k by omega] using hbound + +/- Conditional consecutive form using the central-range Erdős layer product estimate and +Mathlib's central-binomial lower bound. -/ +private lemma consecutive_of_mul_prod_erdos_central_layers_lt_four_pow {n k : ℕ} + (hn : 4 ≤ n) (hk : n < k) (hcentral : k + n - 1 < 3 * n) + (hN6 : 6 ≤ k + n - 1) + (hbound : + n * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial ((k + n - 1) / 3) + else primorial (Nat.nthRoot (j + 1) (k + n - 1))) < + 4 ^ n) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_exists_prime_dvd_choose + exact exists_large_prime_dvd_choose_of_mul_prod_erdos_central_layers_lt_four_pow + hn (by omega) hcentral hN6 hbound + +/- A simple sufficient estimate for the preceding conditional theorem: if the starting point is +larger than `n ! * 2 ^ (n - 1)`, then the crude factorization bound already forces a prime +divisor greater than `n`. -/ +private lemma factorial_mul_top_pow_sub_one_lt_start_pow_of_large_start {n k : ℕ} + (hn : 1 ≤ n) (hk : n < k) (hlarge : n ! * 2 ^ (n - 1) < k) : + n ! * (k + n - 1) ^ (n - 1) < k ^ n := by + have hpow : (k + n - 1) ^ (n - 1) ≤ (2 * k) ^ (n - 1) := + Nat.pow_le_pow_left (by omega : k + n - 1 ≤ 2 * k) _ + have hmul : n ! * (k + n - 1) ^ (n - 1) ≤ n ! * (2 * k) ^ (n - 1) := + Nat.mul_le_mul_left _ hpow + have hstrict : n ! * (2 * k) ^ (n - 1) < k ^ n := by + calc + n ! * (2 * k) ^ (n - 1) + = (n ! * 2 ^ (n - 1)) * k ^ (n - 1) := by + rw [Nat.mul_pow] + ac_rfl + _ < k * k ^ (n - 1) := + Nat.mul_lt_mul_of_pos_right hlarge (by exact pow_pos (by omega : 0 < k) (n - 1)) + _ = k ^ (n - 1) * k := by rw [Nat.mul_comm] + _ = k ^ (n - 1 + 1) := by rw [pow_succ] + _ = k ^ n := by rw [Nat.sub_add_cancel hn] + exact hmul.trans_lt hstrict + +/-- A first unconditional-looking partial case of the consecutive form, valid for starts far +enough to make the elementary estimate work. -/ +theorem consecutive_of_large_start {n k : ℕ} (hn : 2 ≤ n) (hk : n < k) + (hlarge : n ! * 2 ^ (n - 1) < k) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + apply consecutive_of_factorial_mul_top_pow_sub_one_lt_start_pow hn hk + exact factorial_mul_top_pow_sub_one_lt_start_pow_of_large_start (by omega) hk hlarge + +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/ErdosKey.lean b/Mathlib/NumberTheory/SylvesterSchur/ErdosKey.lean new file mode 100644 index 00000000000000..f299e5e74c5112 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ErdosKey.lean @@ -0,0 +1,314 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Data.Nat.Choose.Dvd + +import Mathlib.NumberTheory.Bertrand +import Mathlib.Tactic.IntervalCases +import Mathlib.NumberTheory.SylvesterSchur.BlockReductions +import Mathlib.NumberTheory.SylvesterSchur.ResidualFinite +import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge +import Mathlib.NumberTheory.SylvesterSchur.ResidualLargeCertificates + +/-! +# Erdős key lemma + +This is the core of Erdős's 1934 proof of Sylvester-Schur. The binomial coefficient +`Nat.choose (k + n - 1) n` must have a prime factor `p` with `n < p` +whenever `1 ≤ n` and `n < k`. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur +namespace Internal + +open Finset Nat + +private lemma scaled_ternary_choose {N r : ℕ} (hr : 4 ≤ r) (hrN : 3 * r ≤ N) + (hbound : + r * (2 ^ r * ((3 * r) ^ r * + 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) < + 3 ^ r * 4 ^ r * N ^ r) : + ∃ p, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := + exists_prime_dvd_choose_of_scaled_ternary_erdos_layers_bound hr hrN hbound + +private lemma central_offset_div_three_choose {N r i : ℕ} + (hr : 4 ≤ r) (hi : i ≤ r) (hN : N = 2 * r + i) (hN6 : 6 ≤ N) + (hbound : + r * (2 ^ i * + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) + else primorial (Nat.nthRoot (j + 1) N))) < + 3 ^ i * 4 ^ r) : + ∃ p, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := + exists_prime_dvd_choose_of_central_offset_erdos_div_three_layers_bound + hr hi hN hN6 hbound + +private lemma exists_prime_dvd_choose_of_block_interval {n k p : ℕ} + (hp : p.Prime) (hp_gt : n < p) (hp_ge : k ≤ p) (hp_le : p ≤ k + n - 1) : + ∃ q, q.Prime ∧ n < q ∧ q ∣ Nat.choose (k + n - 1) n := + ⟨p, hp, hp_gt, prime_dvd_choose_of_mem_interval hp hp_gt hp_ge hp_le⟩ + +private lemma erdos_choose_prime_factor_gt_small_length + (n : ℕ) (hn : 2 ≤ n) (hn6 : n ≤ 6) (k : ℕ) (hk : n + 3 ≤ k) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + interval_cases n + · exact exists_prime_dvd_choose_of_large_prime_dvd_block + (consecutive_two (k := k) (by omega)) + · exact exists_prime_dvd_choose_of_large_prime_dvd_block + (consecutive_three (k := k) (by omega)) + · exact exists_prime_dvd_choose_of_large_prime_dvd_block + (consecutive_four (k := k) (by omega)) + · exact exists_prime_dvd_choose_of_large_prime_dvd_block + (consecutive_five (k := k) (by omega)) + · exact exists_prime_dvd_choose_of_large_prime_dvd_block + (consecutive_six (k := k) (by omega)) + +private lemma erdos_choose_prime_factor_gt_length_one (k : ℕ) (hk : 1 < k) : + ∃ p : ℕ, p.Prime ∧ 1 < p ∧ p ∣ Nat.choose (k + 1 - 1) 1 := by + obtain ⟨p, hp, hp_dvd⟩ := Nat.exists_prime_and_dvd (by omega : k ≠ 1) + exact ⟨p, hp, by linarith [hp.two_le], by simp [Nat.choose_one_right, hp_dvd]⟩ + +private lemma erdos_choose_prime_factor_gt_base_start (n : ℕ) (hn : 1 ≤ n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (n + 1 + n - 1) n := by + obtain ⟨q, hq_prime, hq_gt, hq_le⟩ := + Nat.exists_prime_lt_and_le_two_mul n (Nat.one_le_iff_ne_zero.mp hn) + have hq_dvd : q ∣ Nat.choose (n + (n + 1 - 1)) n := + Nat.Prime.dvd_choose_add hq_prime hq_gt (by omega) (by omega) + exact ⟨q, hq_prime, hq_gt, by + rwa [show n + (n + 1 - 1) = n + 1 + n - 1 from by omega] at hq_dvd⟩ + +private lemma erdos_choose_prime_factor_gt_second_start (n : ℕ) (hn : 2 ≤ n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (n + 2 + n - 1) n := by + obtain ⟨p, hp, hp_gt, hp_le⟩ := + Nat.exists_prime_lt_and_le_two_mul (n + 1) (Nat.succ_ne_zero n) + have hp_le_bd : p ≤ n + 2 + n - 1 := by + rcases Nat.eq_or_lt_of_le hp_le with heq | hlt + · exact absurd (heq ▸ hp) (Nat.not_prime_mul (by omega) (by omega)) + · omega + exact exists_prime_dvd_choose_of_block_interval hp (by omega) (by omega) hp_le_bd + +private lemma erdos_choose_prime_factor_gt_bound_dispatch_tail (n k : ℕ) + (hn : 7 ≤ n) (hk : n + 3 ≤ k) + (hblock_large : ¬ ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i) + (hprimeCounting_lower : k ^ n ≤ n ! * (k + n - 1) ^ Nat.primeCounting n) + (hfallback : + k ^ n ≤ n ! * (k + n - 1) ^ Nat.primeCounting n → + (38 ≤ n → k ≤ n ^ 2) → + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + have hk_le_quadratic_start_bound : 38 ≤ n → k ≤ n ^ 2 := by + intro hn38 + exact start_le_quadratic_of_no_large_prime_dvd_block hn38 hblock_large + by_cases herdos_three : + n ! * + 4 ^ (n + Nat.sqrt (k + n - 1) + + Nat.nthRoot 3 (k + n - 1) * Nat.log 2 (k + n - 1)) < + k ^ n + · exact exists_prime_dvd_choose_of_erdos_layers_three_layers_bound + (by omega) (by omega) herdos_three + by_cases herdos_four : + n ! * 4 ^ (n + Nat.sqrt (k + n - 1) * Nat.log 2 (k + n - 1)) < k ^ n + · exact exists_prime_dvd_choose_of_erdos_layers_four_pow_bound + (by omega) (by omega) herdos_four + exact hfallback hprimeCounting_lower hk_le_quadratic_start_bound + +private lemma erdos_choose_prime_factor_gt_bound_dispatch_core (n k : ℕ) + (hn : 7 ≤ n) (hk : n + 3 ≤ k) + (hfallback : + k ^ n ≤ n ! * (k + n - 1) ^ Nat.primeCounting n → + (38 ≤ n → k ≤ n ^ 2) → + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + by_cases hsmooth_count : 2 ^ Nat.primeCounting n * Nat.sqrt (k + n - 1) < n + · exact exists_prime_dvd_choose_of_smooth_count_bound hsmooth_count + by_cases hblock_large : ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i + · exact exists_prime_dvd_choose_of_large_prime_dvd_block hblock_large + by_cases hprimeCounting : n ! * (k + n - 1) ^ Nat.primeCounting n < k ^ n + · exact exists_prime_dvd_choose_of_primeCounting_bound (by omega) (by omega) hprimeCounting + by_cases hsqrt : + n ! * ((k + n - 1) ^ (Nat.sqrt (k + n - 1) + 1) * primorial n) < k ^ n + · exact exists_prime_dvd_choose_of_sqrt_primorial_bound (by omega) (by omega) hsqrt + by_cases hdiv_three_erdos : + n ! * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial ((k + n - 1) / 3) + else primorial (Nat.nthRoot (j + 1) (k + n - 1))) < + k ^ n + · exact exists_prime_dvd_choose_of_erdos_div_three_layers_bound + (by omega) (by omega) (by omega) hdiv_three_erdos + by_cases herdos : + n ! * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial n + else primorial (Nat.nthRoot (j + 1) (k + n - 1))) < + k ^ n + · exact exists_prime_dvd_choose_of_erdos_layers_bound (by omega) (by omega) herdos + by_cases hhalf : n ! * (k + n - 1) ^ (n / 2 + 1) < k ^ n + · exact exists_prime_dvd_choose_of_half_bound (by omega) (by omega) hhalf + by_cases hlarge : n ! * 2 ^ (n - 1) < k + · exact exists_prime_dvd_choose_of_large_start (by omega) (by omega) hlarge + exact erdos_choose_prime_factor_gt_bound_dispatch_tail n k hn hk hblock_large + (le_of_not_gt hprimeCounting) hfallback + +private lemma erdos_choose_prime_factor_gt_second_residual_large (n k : ℕ) + (hn945 : 945 ≤ n) (hk : n + 3 ≤ k) + (hscaled_ternary : + ¬ (3 * n ≤ k + n - 1 ∧ + n * (2 ^ n * ((3 * n) ^ n * + 4 ^ (n + Nat.sqrt (k + n - 1) + + Nat.nthRoot 3 (k + n - 1) * Nat.log 2 (k + n - 1)))) < + 3 ^ n * 4 ^ n * (k + n - 1) ^ n)) + (hcentral_offset : + ¬ (k + n - 1 < 3 * n ∧ + n * (2 ^ (k - n - 1) * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial ((k + n - 1) / 3) + else primorial (Nat.nthRoot (j + 1) (k + n - 1)))) < + 3 ^ (k - n - 1) * 4 ^ n)) + (hk_le_quadratic_start_bound : 38 ≤ n → k ≤ n ^ 2) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + by_cases hN3 : 3 * n ≤ k + n - 1 + · have hNhi : k + n - 1 ≤ n ^ 2 + n := by + have hkquad := hk_le_quadratic_start_bound (by omega : 38 ≤ n) + omega + exact False.elim <| hscaled_ternary ⟨hN3, + first_residual_large_scaled_ternary_bound hn945 hN3 hNhi⟩ + exact False.elim <| hcentral_offset ⟨by omega, + second_residual_large_central_offset_bound hn945 (by omega) (by omega)⟩ + +private lemma erdos_choose_prime_factor_gt_second_residual_finite (n k : ℕ) + (hn : 7 ≤ n) (hk : n + 3 ≤ k) (hnlt945 : n < 945) + (hprimeCounting_lower : k ^ n ≤ n ! * (k + n - 1) ^ Nat.primeCounting n) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + by_cases hn38 : 38 ≤ n + · by_cases hk1291 : 1291 ≤ k + · exact False.elim <| (not_lt_of_ge hprimeCounting_lower) <| + second_residual_mid_primeCounting_lt_start_pow hn38 hnlt945 hk1291 + have hklt1291 : k < 1291 := by omega + exact exists_prime_dvd_choose_of_large_prime_dvd_block + (second_residual_mid_has_large_prime_factor hn38 hnlt945 (by omega) hklt1291) + have hnlt38 : n < 38 := by omega + by_cases hk100 : 100 ≤ k + · exact False.elim <| (not_lt_of_ge hprimeCounting_lower) <| + second_residual_tiny_primeCounting_lt_start_pow hn hnlt38 hk100 + have hklt100 : k < 100 := by omega + exact exists_prime_dvd_choose_of_large_prime_dvd_block + (second_residual_tiny_has_large_prime_factor hn hnlt38 (by omega) hklt100) + +private lemma erdos_choose_prime_factor_gt_second_residual (n k : ℕ) + (hn : 7 ≤ n) (hk : n + 3 ≤ k) + (hprimeCounting_lower : k ^ n ≤ n ! * (k + n - 1) ^ Nat.primeCounting n) + (hk_le_quadratic_start_bound : 38 ≤ n → k ≤ n ^ 2) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + by_cases hscaled_ternary : + 3 * n ≤ k + n - 1 ∧ + n * (2 ^ n * ((3 * n) ^ n * + 4 ^ (n + Nat.sqrt (k + n - 1) + + Nat.nthRoot 3 (k + n - 1) * Nat.log 2 (k + n - 1)))) < + 3 ^ n * 4 ^ n * (k + n - 1) ^ n + · obtain ⟨hN3, hscaled_bound⟩ := hscaled_ternary + exact scaled_ternary_choose (N := k + n - 1) (r := n) (by omega) hN3 hscaled_bound + by_cases hcentral_offset : + k + n - 1 < 3 * n ∧ + n * (2 ^ (k - n - 1) * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial ((k + n - 1) / 3) + else primorial (Nat.nthRoot (j + 1) (k + n - 1)))) < + 3 ^ (k - n - 1) * 4 ^ n + · obtain ⟨hcentral_range, hcentral_bound⟩ := hcentral_offset + exact central_offset_div_three_choose (N := k + n - 1) (r := n) (i := k - n - 1) + (by omega) (by omega) (by omega) (by omega) hcentral_bound + by_cases hn945 : 945 ≤ n + · exact erdos_choose_prime_factor_gt_second_residual_large n k hn945 hk + hscaled_ternary hcentral_offset hk_le_quadratic_start_bound + have hnlt945 : n < 945 := by omega + exact erdos_choose_prime_factor_gt_second_residual_finite n k hn hk hnlt945 + hprimeCounting_lower + +private lemma erdos_choose_prime_factor_gt_of_bertrand_overshoot (n k t : ℕ) + (hn : 7 ≤ n) (hk : n + 3 ≤ k) (ht : t.Prime) + (ht_ge : t ≥ k) (ht_not_range : ¬ t ≤ k + n - 1) + (ht_le : t ≤ 2 * (n + 2)) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + have hk_n3 : k = n + 3 := by + by_contra hk_ne + have ht_val : t = 2 * n + 4 := by omega + have h2n4_not_prime : ¬ (2 * n + 4).Prime := by + rw [show 2 * n + 4 = 2 * (n + 2) from by ring] + exact Nat.not_prime_mul (by omega) (by omega) + exact h2n4_not_prime (ht_val ▸ ht) + subst hk_n3 + by_cases hn512 : 512 ≤ n + · simpa [gt_iff_lt, show n + 3 + n - 1 = 2 * n + 2 by omega] using + exists_large_prime_dvd_choose_of_mul_prod_erdos_central_layers_lt_four_pow + (N := 2 * n + 2) (r := n) (by omega) (by omega) (by omega) (by omega) + (central_erdos_layers_two_mul_add_two_lt_four_pow hn512) + simpa [gt_iff_lt, show n + 3 + n - 1 = 2 * n + 2 by omega] using + exists_prime_dvd_choose_two_mul_add_two_small hn (by omega : n < 512) + +private lemma erdos_choose_prime_factor_gt_bertrand_steps (n k : ℕ) + (hn : 7 ≤ n) (hk : n + 3 ≤ k) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + obtain ⟨r, hr, hr_gt, hr_le⟩ := + Nat.exists_prime_lt_and_le_two_mul (n + 1) (Nat.succ_ne_zero n) + by_cases hr_gek : r ≥ k + · exact exists_prime_dvd_choose_of_block_interval hr (by omega) hr_gek (by omega) + by_cases hr_easy : r = n + 2 ∧ ¬ r ∣ k - 1 ∧ ¬ r ∣ k - 2 + · obtain ⟨hr_n2, hr_not_one, hr_not_two⟩ := hr_easy + obtain ⟨i, hi, hr_dvd⟩ := exists_dvd_block_of_succ_succ_prime_not_dvd_pred + (n := n) (k := k) (s := r) (by omega) hr_n2 hr_not_one hr_not_two + exact ⟨r, hr, by omega, prime_dvd_seq_implies_choose hr (by omega) i hi hr_dvd⟩ + obtain ⟨t, ht, ht_gt, ht_le⟩ := + Nat.exists_prime_lt_and_le_two_mul (n + 2) (Nat.succ_ne_zero (n + 1)) + by_cases ht_gek : t ≥ k + · by_cases ht_range : t ≤ k + n - 1 + · exact exists_prime_dvd_choose_of_block_interval ht (by omega) ht_gek ht_range + exact erdos_choose_prime_factor_gt_of_bertrand_overshoot + n k t hn hk ht ht_gek ht_range ht_le + obtain ⟨B, hB, hB_gt, hB_le⟩ := + Nat.exists_prime_lt_and_le_two_mul (k - 1) (by omega) + by_cases hB_range : B ≤ k + n - 1 + · exact exists_prime_dvd_choose_of_block_interval hB (by omega) (by omega) hB_range + exact erdos_choose_prime_factor_gt_bound_dispatch_core n k hn hk + (erdos_choose_prime_factor_gt_second_residual n k hn hk) + +/- Hard case of the Erdős key lemma: for `2 ≤ n` and `n + 3 ≤ k`, +`Nat.choose (k + n - 1) n` has a prime factor greater than `n`. + +This packages the small-length cases, Bertrand steps, and residual estimates needed after +the direct absorption cases have been eliminated. -/ +private lemma erdos_choose_prime_factor_gt_hard + (n : ℕ) (hn : 2 ≤ n) (k : ℕ) (hk : n + 3 ≤ k) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + by_cases hn6 : n ≤ 6 + · exact erdos_choose_prime_factor_gt_small_length n hn hn6 k hk + have hn7 : 7 ≤ n := by omega + exact erdos_choose_prime_factor_gt_bertrand_steps n k hn7 hk + +/-- **Erdős key lemma** (1934): for `1 ≤ n < k`, the binomial coefficient +`Nat.choose (k + n - 1) n` has a prime factor strictly greater than `n`. + +The cases `n = 1`, `k = n + 1`, and `k = n + 2` are direct Bertrand arguments. +All later starts are handled by the consolidated hard-case estimate above. -/ +lemma erdos_choose_prime_factor_gt (n : ℕ) (hn : 1 ≤ n) (k : ℕ) (hk : n < k) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (k + n - 1) n := by + by_cases hn1 : n = 1 + · subst hn1 + exact erdos_choose_prime_factor_gt_length_one k hk + have hn2 : 2 ≤ n := by omega + by_cases hkn1 : k = n + 1 + · subst hkn1 + exact erdos_choose_prime_factor_gt_base_start n hn + by_cases hkn2 : k = n + 2 + · subst hkn2 + exact erdos_choose_prime_factor_gt_second_start n hn2 + exact erdos_choose_prime_factor_gt_hard n hn2 k (by omega) + +end Internal +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/ErdosLayers.lean b/Mathlib/NumberTheory/SylvesterSchur/ErdosLayers.lean new file mode 100644 index 00000000000000..64ebe64672f807 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ErdosLayers.lean @@ -0,0 +1,204 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Data.Nat.Choose.Central +public import Mathlib.Data.Nat.Factorial.BigOperators +public import Mathlib.NumberTheory.SylvesterSchur.ChooseFactorization +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Ring + +/-! +# Erdős layer products for Sylvester-Schur + +This file packages the Erdős layer-product estimates and the elementary +large-`n` inequalities used by the residual cases. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur + +open scoped BigOperators + +open Finset Nat + +/-! ### Erdős layer products -/ + +/- Scaling monotonicity for descending factorials. Termwise, +`N * (M - i) ≤ M * (N - i)` whenever `i ≤ M ≤ N`; multiplying over `i < r` +gives the comparison used to lift lower bounds from `Nat.choose M r` to +`Nat.choose N r`. -/ +private lemma pow_mul_descFactorial_le_pow_mul_descFactorial {M N r : ℕ} + (hrM : r ≤ M) (hMN : M ≤ N) : + N ^ r * M.descFactorial r ≤ M ^ r * N.descFactorial r := by + rw [Nat.descFactorial_eq_prod_range, Nat.descFactorial_eq_prod_range] + calc + N ^ r * ∏ i ∈ Finset.range r, (M - i) + = (∏ _i ∈ Finset.range r, N) * ∏ i ∈ Finset.range r, (M - i) := by + simp + _ = ∏ i ∈ Finset.range r, (N * (M - i)) := by + rw [Finset.prod_mul_distrib] + _ ≤ ∏ i ∈ Finset.range r, (M * (N - i)) := by + apply Finset.prod_le_prod' + intro i hi + have hir : i < r := Finset.mem_range.mp hi + have hiM : i ≤ M := by omega + let d := N - M + have hN : N = M + d := by + dsimp [d] + omega + have hNsub : N - i = (M - i) + d := by + dsimp [d] + omega + rw [hNsub, hN] + have hsub : M - i ≤ M := Nat.sub_le M i + nlinarith + _ = (∏ _i ∈ Finset.range r, M) * ∏ i ∈ Finset.range r, (N - i) := by + rw [Finset.prod_mul_distrib] + _ = M ^ r * ∏ i ∈ Finset.range r, (N - i) := by + simp + +/-- Scaled monotonicity for binomial coefficients: +`N^r * (M choose r) ≤ M^r * (N choose r)` for `r ≤ M ≤ N`. + +Equivalently, `(Nat.choose N r : ℚ) / N^r` is monotone decreasing in this range. +This form stays in `ℕ`, avoiding division. -/ +theorem pow_mul_choose_le_pow_mul_choose {M N r : ℕ} + (hrM : r ≤ M) (hMN : M ≤ N) : + N ^ r * Nat.choose M r ≤ M ^ r * Nat.choose N r := by + have hdesc := + pow_mul_descFactorial_le_pow_mul_descFactorial (M := M) (N := N) (r := r) + hrM hMN + rw [Nat.descFactorial_eq_factorial_mul_choose, + Nat.descFactorial_eq_factorial_mul_choose] at hdesc + have hmul : + r ! * (N ^ r * Nat.choose M r) ≤ r ! * (M ^ r * Nat.choose N r) := by + calc + r ! * (N ^ r * Nat.choose M r) = N ^ r * (r ! * Nat.choose M r) := by + ring + _ ≤ M ^ r * (r ! * Nat.choose N r) := hdesc + _ = r ! * (M ^ r * Nat.choose N r) := by + ring + exact Nat.le_of_mul_le_mul_left hmul (Nat.factorial_pos r) + +/- Contrapositive of the central-range Erdős layer bound. -/ +private lemma exists_large_prime_dvd_choose_of_prod_erdos_central_layers_lt_choose {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) (h2rN : 2 * r ≤ N) (hNlt3r : N < 3 * r) + (hN6 : 6 ≤ N) + (hbound : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N)) < + Nat.choose N r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + exact (not_lt_of_ge + (choose_le_prod_erdos_central_layers_of_no_large hN hrN h2rN hNlt3r hN6 hsmall)) + hbound + +/- Contrapositive of the `N / 3` first-layer Erdős bound. -/ +private lemma exists_large_prime_dvd_choose_of_prod_erdos_div_three_layers_lt_choose {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) (h2rN : 2 * r ≤ N) (hN6 : 6 ≤ N) + (hbound : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N)) < + Nat.choose N r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + exact (not_lt_of_ge + (choose_le_prod_erdos_div_three_layers_of_no_large hN hrN h2rN hN6 hsmall)) + hbound + +/- Rational lower-bound formulation using the central-range Erdős layer bound. -/ +private lemma exists_large_prime_dvd_choose_of_prod_erdos_central_layers_lt_lower_bound + {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) (h2rN : 2 * r ≤ N) + (hNlt3r : N < 3 * r) (hN6 : 6 ≤ N) + (hbound : + (((∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N) : ℕ) : ℚ) < + ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ))) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + exact exists_large_prime_dvd_choose_of_upper_lt_lower + (fun hsmall => + choose_le_prod_erdos_central_layers_of_no_large hN hrN h2rN hNlt3r hN6 hsmall) + hbound + +/- Rational lower-bound formulation using the `N / 3` first-layer Erdős bound. -/ +private lemma exists_large_prime_dvd_choose_of_prod_erdos_div_three_layers_lt_lower_bound + {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) (h2rN : 2 * r ≤ N) (hN6 : 6 ≤ N) + (hbound : + (((∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N) : ℕ) : + ℚ) < + ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ))) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + exact exists_large_prime_dvd_choose_of_upper_lt_lower + (fun hsmall => choose_le_prod_erdos_div_three_layers_of_no_large hN hrN h2rN hN6 hsmall) + hbound + +/-- Natural-number version of +`exists_large_prime_dvd_choose_of_prod_erdos_central_layers_lt_lower_bound`. -/ +theorem exists_large_prime_dvd_choose_of_factorial_mul_prod_erdos_central_layers_lt_lower_pow + {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) (h2rN : 2 * r ≤ N) + (hNlt3r : N < 3 * r) (hN6 : 6 ≤ N) + (hbound : + r ! * (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N)) < + (N + 1 - r) ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_prod_erdos_central_layers_lt_lower_bound + hN hrN h2rN hNlt3r hN6 + rw [lt_div_iff₀' (by exact_mod_cast Nat.factorial_pos r)] + norm_cast + +/-- Natural-number version of +`exists_large_prime_dvd_choose_of_prod_erdos_div_three_layers_lt_lower_bound`. -/ +theorem exists_large_prime_dvd_choose_of_factorial_mul_prod_erdos_div_three_layers_lt_lower_pow + {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) (h2rN : 2 * r ≤ N) (hN6 : 6 ≤ N) + (hbound : + r ! * (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N)) < + (N + 1 - r) ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_prod_erdos_div_three_layers_lt_lower_bound + hN hrN h2rN hN6 + rw [lt_div_iff₀' (by exact_mod_cast Nat.factorial_pos r)] + norm_cast + +/-- Near the central range, the central-binomial lower bound turns the central Erdős layer +estimate into a large-prime criterion. -/ +theorem exists_large_prime_dvd_choose_of_mul_prod_erdos_central_layers_lt_four_pow + {N r : ℕ} (hr : 4 ≤ r) (h2rN : 2 * r ≤ N) (hNlt3r : N < 3 * r) + (hN6 : 6 ≤ N) + (hbound : + r * (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N)) < + 4 ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_prod_erdos_central_layers_lt_choose + · omega + · omega + · exact h2rN + · exact hNlt3r + · exact hN6 + have hcentral_le : Nat.centralBinom r ≤ Nat.choose N r := by + rw [Nat.centralBinom_eq_two_mul_choose] + exact Nat.choose_le_choose r h2rN + have hlower : 4 ^ r < r * Nat.choose N r := by + exact (Nat.four_pow_lt_mul_centralBinom r hr).trans_le + (Nat.mul_le_mul_left r hcentral_le) + by_contra hnot + push Not at hnot + have hmul : + r * Nat.choose N r ≤ + r * (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N)) := + Nat.mul_le_mul_left r hnot + exact (not_lt_of_ge hbound.le) (hlower.trans_le hmul) + +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/ErdosPowerBounds.lean b/Mathlib/NumberTheory/SylvesterSchur/ErdosPowerBounds.lean new file mode 100644 index 00000000000000..65a9a153c91d45 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ErdosPowerBounds.lean @@ -0,0 +1,424 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.NumberTheory.SylvesterSchur.ErdosLayers +import Mathlib.Tactic.IntervalCases +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Ring + +/-! +# Power-of-four bounds for Sylvester-Schur + +This file proves reusable power-of-four bounds for the Erdős layer products +that occur in the residual Sylvester--Schur estimates. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur + +open scoped BigOperators + +open Finset Nat + +/-! ### Elementary root and power bounds -/ + +private lemma cube_le_two_pow_of_ten_le {m : ℕ} (hm : 10 ≤ m) : m ^ 3 ≤ 2 ^ m := by + induction m, hm using Nat.le_induction with + | base => norm_num + | succ m hm ih => + calc + (m + 1) ^ 3 ≤ 2 * m ^ 3 := by + nlinarith [hm, sq_nonneg (m : ℤ), sq_nonneg ((m : ℤ) - 3)] + _ ≤ 2 * 2 ^ m := Nat.mul_le_mul_left 2 ih + _ = 2 ^ (m + 1) := by ring + +private lemma sqrt_two_mul_add_two_le_div_fifteen {n : ℕ} (hn : 512 ≤ n) : + Nat.sqrt (2 * n + 2) ≤ n / 15 := by + let s := Nat.sqrt (2 * n + 2) + have hs2 : s ^ 2 ≤ 2 * n + 2 := by + dsimp [s] + exact Nat.sqrt_le' (2 * n + 2) + have hpoly : 225 * (2 * n + 2) ≤ n ^ 2 := by nlinarith [hn] + have hsq : (15 * s) ^ 2 ≤ n ^ 2 := by + calc + (15 * s) ^ 2 = 225 * s ^ 2 := by ring + _ ≤ 225 * (2 * n + 2) := Nat.mul_le_mul_left 225 hs2 + _ ≤ n ^ 2 := hpoly + have h15 : 15 * s ≤ n := by + exact (Nat.pow_le_pow_iff_left (by norm_num : 2 ≠ 0)).mp hsq + rw [Nat.le_div_iff_mul_le (by norm_num : 0 < 15)] + omega + +private lemma nthRoot_three_two_mul_add_two_sq_le_div_four {n : ℕ} (hn : 512 ≤ n) : + (Nat.nthRoot 3 (2 * n + 2)) ^ 2 ≤ n / 4 := by + let c := Nat.nthRoot 3 (2 * n + 2) + have hc3 : c ^ 3 ≤ 2 * n + 2 := by + dsimp [c] + exact Nat.pow_nthRoot_le (Or.inl (by norm_num : 3 ≠ 0)) + have hpoly : 64 * (2 * n + 2) ^ 2 ≤ n ^ 3 := by nlinarith [hn] + have hcube : (4 * c ^ 2) ^ 3 ≤ n ^ 3 := by + calc + (4 * c ^ 2) ^ 3 = 64 * (c ^ 3) ^ 2 := by ring + _ ≤ 64 * (2 * n + 2) ^ 2 := + Nat.mul_le_mul_left 64 (Nat.pow_le_pow_left hc3 2) + _ ≤ n ^ 3 := hpoly + have h4 : 4 * c ^ 2 ≤ n := by + exact (Nat.pow_le_pow_iff_left (by norm_num : 3 ≠ 0)).mp hcube + exact (Nat.le_div_iff_mul_le (by norm_num : 0 < 4)).mpr + (by simpa [c, two_mul, Nat.mul_comm, Nat.mul_left_comm, Nat.mul_assoc] using h4) + +private lemma log_two_two_mul_add_two_le_nthRoot_three {n : ℕ} (hn : 512 ≤ n) : + Nat.log 2 (2 * n + 2) ≤ Nat.nthRoot 3 (2 * n + 2) := by + let N := 2 * n + 2 + let c := Nat.nthRoot 3 N + have hc10 : 10 ≤ c := by + dsimp [c, N] + rw [Nat.le_nthRoot_iff (by norm_num : 3 ≠ 0)] + norm_num + omega + have hNlt : N < (c + 1) ^ 3 := by + exact (Nat.nthRoot_lt_iff (by norm_num : 3 ≠ 0)).mp (Nat.lt_succ_self c) + have hcube : (c + 1) ^ 3 ≤ 2 ^ (c + 1) := + cube_le_two_pow_of_ten_le (by omega : 10 ≤ c + 1) + have hNpow : N < 2 ^ (c + 1) := hNlt.trans_le hcube + have hlog : Nat.log 2 N < c + 1 := + Nat.log_lt_of_lt_pow (by dsimp [N]; omega) hNpow + dsimp [c, N] at hlog ⊢ + omega + +private lemma self_le_four_pow_div_one_twenty_eight_add_one {n : ℕ} (hn : 512 ≤ n) : + n ≤ 4 ^ (n / 128 + 1) := by + let m := n / 128 + have hm4 : 4 ≤ m := by + dsimp [m] + rw [Nat.le_div_iff_mul_le (by norm_num : 0 < 128)] + omega + have hnlt : n < 128 * (m + 1) := by + dsimp [m] + exact Nat.lt_mul_div_succ n (by norm_num : 0 < 128) + have hmul_general : ∀ m : ℕ, 4 ≤ m → 128 * (m + 1) ≤ 4 ^ (m + 1) := by + intro m hm + induction m, hm using Nat.le_induction with + | base => norm_num + | succ m hm ih => + calc + 128 * (m + 1 + 1) ≤ 4 * (128 * (m + 1)) := by nlinarith + _ ≤ 4 * 4 ^ (m + 1) := Nat.mul_le_mul_left 4 ih + _ = 4 ^ (m + 1 + 1) := by ring + exact hnlt.le.trans (hmul_general m hm4) + +private lemma two_pow_mul_four_pow_div_four_le_three_pow (i : ℕ) : + 2 ^ i * 4 ^ (i / 4) ≤ 3 ^ i := by + induction i using Nat.strong_induction_on with + | h i ih => + by_cases hi : i < 4 + · interval_cases i <;> norm_num + · have hle : i - 4 < i := by omega + have ih' := ih (i - 4) hle + have hidiv : i / 4 = (i - 4) / 4 + 1 := by omega + calc + 2 ^ i * 4 ^ (i / 4) + = 64 * (2 ^ (i - 4) * 4 ^ ((i - 4) / 4)) := by + rw [hidiv] + have hi4 : i = i - 4 + 4 := by omega + conv_lhs => rw [hi4] + rw [pow_add, pow_add] + norm_num + ring + _ ≤ 64 * 3 ^ (i - 4) := Nat.mul_le_mul_left 64 ih' + _ ≤ 81 * 3 ^ (i - 4) := Nat.mul_le_mul_right _ (by norm_num) + _ = 3 ^ i := by + have hi4 : i = i - 4 + 4 := by omega + rw [hi4, pow_add] + norm_num + ring + +private lemma nthRoot_two_le_sqrt (N : ℕ) : Nat.nthRoot 2 N ≤ Nat.sqrt N := by + rw [Nat.le_sqrt'] + exact Nat.pow_nthRoot_le (Or.inl (by norm_num : 2 ≠ 0)) + +private lemma nthRoot_le_sqrt_of_two_le {N m : ℕ} (hm : 2 ≤ m) : + Nat.nthRoot m N ≤ Nat.sqrt N := by + let s := Nat.sqrt N + have hNlt : N < (s + 1) ^ 2 := by + exact Nat.sqrt_lt'.mp (Nat.lt_succ_self s) + have hpow : (s + 1) ^ 2 ≤ (s + 1) ^ m := by + apply Nat.pow_le_pow_right + · omega + · exact hm + have hlt : Nat.nthRoot m N < s + 1 := by + rw [Nat.nthRoot_lt_iff (by omega : m ≠ 0)] + exact hNlt.trans_le hpow + dsimp [s] at hlt ⊢ + omega + +private lemma nthRoot_le_nthRoot_three_of_three_le {N m : ℕ} (hm : 3 ≤ m) : + Nat.nthRoot m N ≤ Nat.nthRoot 3 N := by + let c := Nat.nthRoot 3 N + have hNlt : N < (c + 1) ^ 3 := by + exact (Nat.nthRoot_lt_iff (by norm_num : 3 ≠ 0)).mp (Nat.lt_succ_self c) + have hpow : (c + 1) ^ 3 ≤ (c + 1) ^ m := by + apply Nat.pow_le_pow_right + · omega + · exact hm + have hlt : Nat.nthRoot m N < c + 1 := by + rw [Nat.nthRoot_lt_iff (by omega : m ≠ 0)] + exact hNlt.trans_le hpow + dsimp [c] at hlt ⊢ + omega + +/-! ### Power-of-four bounds for residual ranges -/ + +private lemma erdos_layers_tail_le_four_pow_of_nthRoot_le {N r B : ℕ} + {s : Finset ℕ} + (hroot : ∀ j ∈ s, Nat.nthRoot (j + 1) N ≤ B) + (hzero : ∀ j ∈ s, j ≠ 0) (hcard : s.card ≤ Nat.log 2 N) : + (∏ j ∈ s, if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + (4 ^ B) ^ Nat.log 2 N := by + calc + (∏ j ∈ s, if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) + ≤ ∏ _j ∈ s, 4 ^ B := by + exact Finset.prod_le_prod' fun j hj => by + have hj0 : j ≠ 0 := hzero j hj + simpa [hj0] using (primorial_mono (hroot j hj)).trans (primorial_le_four_pow B) + _ = (4 ^ B) ^ s.card := by rw [Finset.prod_const] + _ ≤ (4 ^ B) ^ Nat.log 2 N := + Nat.pow_le_pow_right (pow_pos (by norm_num : 0 < 4) B) hcard + +/- Bound the Erdős layer product after the zeroth and first layers. -/ +private lemma erdos_layers_tail_le_four_pow_cuberoot (N r : ℕ) : + (∏ j ∈ ((Finset.range (Nat.log 2 N)).erase 0).erase 1, + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + (4 ^ Nat.nthRoot 3 N) ^ Nat.log 2 N := by + exact erdos_layers_tail_le_four_pow_of_nthRoot_le + (s := ((Finset.range (Nat.log 2 N)).erase 0).erase 1) + (B := Nat.nthRoot 3 N) + (fun j hj => nthRoot_le_nthRoot_three_of_three_le (N := N) (m := j + 1) (by + have hj_ne1 : j ≠ 1 := by simpa using (Finset.mem_erase.mp hj).1 + have hj_ne0 : j ≠ 0 := (Finset.mem_erase.mp (Finset.mem_erase.mp hj).2).1 + omega)) + (fun j hj => (Finset.mem_erase.mp (Finset.mem_erase.mp hj).2).1) + (by + have hcard : + (((Finset.range (Nat.log 2 N)).erase 0).erase 1).card ≤ + (Finset.range (Nat.log 2 N)).card := + Finset.card_le_card fun j hj => + (Finset.mem_erase.mp (Finset.mem_erase.mp hj).2).2 + simpa using hcard) + +private lemma erdos_layers_le_four_pow_three_layers_of_zero_one_mem + (N r : ℕ) (h0 : 0 ∈ Finset.range (Nat.log 2 N)) + (h1 : 1 ∈ (Finset.range (Nat.log 2 N)).erase 0) : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N) := by + let c := Nat.nthRoot 3 N + have hf0 : primorial r ≤ 4 ^ r := primorial_le_four_pow r + have hf1 : primorial (Nat.nthRoot 2 N) ≤ 4 ^ Nat.sqrt N := + (primorial_mono (nthRoot_two_le_sqrt N)).trans (primorial_le_four_pow (Nat.sqrt N)) + have hrest : + (∏ j ∈ ((Finset.range (Nat.log 2 N)).erase 0).erase 1, + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + (4 ^ c) ^ Nat.log 2 N := by + simpa [c] using erdos_layers_tail_le_four_pow_cuberoot N r + calc + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) + = primorial r * + (primorial (Nat.nthRoot 2 N) * + ∏ j ∈ ((Finset.range (Nat.log 2 N)).erase 0).erase 1, + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) := by + rw [← Finset.mul_prod_erase (Finset.range (Nat.log 2 N)) + (fun j => if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) h0, + ← Finset.mul_prod_erase ((Finset.range (Nat.log 2 N)).erase 0) + (fun j => if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) + h1] + simp + _ ≤ 4 ^ r * (4 ^ Nat.sqrt N * (4 ^ c) ^ Nat.log 2 N) := + Nat.mul_le_mul hf0 (Nat.mul_le_mul hf1 hrest) + _ = 4 ^ (r + Nat.sqrt N + c * Nat.log 2 N) := by + rw [← pow_mul, ← pow_add, ← pow_add] + ring_nf + _ = 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N) := by + dsimp [c] + +private lemma erdos_layers_le_four_pow_three_layers_of_zero_mem_not_one_mem + (N r : ℕ) (h0 : 0 ∈ Finset.range (Nat.log 2 N)) + (h1 : 1 ∉ (Finset.range (Nat.log 2 N)).erase 0) : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N) := by + have hlog_pos : 0 < Nat.log 2 N := Finset.mem_range.mp h0 + have hlog_le_one : Nat.log 2 N ≤ 1 := by + by_contra hle + push Not at hle + have h1mem : 1 ∈ (Finset.range (Nat.log 2 N)).erase 0 := by + exact Finset.mem_erase.mpr ⟨by omega, Finset.mem_range.mpr (by omega)⟩ + exact h1 h1mem + have hlog : Nat.log 2 N = 1 := by omega + calc + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) + = primorial r := by simp [hlog] + _ ≤ 4 ^ r := primorial_le_four_pow r + _ ≤ 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N) := by + apply Nat.pow_le_pow_right (by norm_num : 0 < 4) + omega + +private lemma erdos_layers_le_four_pow_three_layers_of_zero_not_mem + (N r : ℕ) (h0 : 0 ∉ Finset.range (Nat.log 2 N)) : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N) := by + have hlog : Nat.log 2 N = 0 := by + rw [Finset.mem_range] at h0 + omega + simpa [hlog] using + Nat.succ_le_of_lt (pow_pos (by norm_num : 0 < 4) (r + Nat.sqrt N)) + +private lemma erdos_layers_le_four_pow_three_layers_aux (N r : ℕ) : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N) := by + by_cases h0 : 0 ∈ Finset.range (Nat.log 2 N) + · by_cases h1 : 1 ∈ (Finset.range (Nat.log 2 N)).erase 0 + · exact erdos_layers_le_four_pow_three_layers_of_zero_one_mem N r h0 h1 + · exact erdos_layers_le_four_pow_three_layers_of_zero_mem_not_one_mem N r h0 h1 + · exact erdos_layers_le_four_pow_three_layers_of_zero_not_mem N r h0 + +private lemma central_layers_two_mul_add_two_le_four_pow {n : ℕ} (hn : 512 ≤ n) : + (∏ j ∈ Finset.range (Nat.log 2 (2 * n + 2)), + if j = 0 then primorial ((2 * n + 2) / 3) + else primorial (Nat.nthRoot (j + 1) (2 * n + 2))) ≤ + 4 ^ ((2 * n + 2) / 3 + n / 15 + n / 4) := by + let N := 2 * n + 2 + let L := Nat.log 2 N + let c := Nat.nthRoot 3 N + have hsqrt : Nat.sqrt N ≤ n / 15 := by + dsimp [N] + simpa [two_mul, Nat.mul_comm, Nat.mul_left_comm, Nat.mul_assoc] using + sqrt_two_mul_add_two_le_div_fifteen hn + have hlog_le_c : L ≤ c := by + dsimp [L, c, N] + simpa [two_mul, Nat.mul_comm, Nat.mul_left_comm, Nat.mul_assoc] using + log_two_two_mul_add_two_le_nthRoot_three hn + have hc_sq : c ^ 2 ≤ n / 4 := by + dsimp [c, N] + simpa [two_mul, Nat.mul_comm, Nat.mul_left_comm, Nat.mul_assoc] using + nthRoot_three_two_mul_add_two_sq_le_div_four hn + have hcL : c * L ≤ n / 4 := by + calc + c * L ≤ c * c := Nat.mul_le_mul_left c hlog_le_c + _ = c ^ 2 := by ring + _ ≤ n / 4 := hc_sq + calc + (∏ j ∈ Finset.range (Nat.log 2 (2 * n + 2)), + if j = 0 then primorial ((2 * n + 2) / 3) + else primorial (Nat.nthRoot (j + 1) (2 * n + 2))) + ≤ 4 ^ (N / 3 + Nat.sqrt N + c * L) := by + simpa [N, L, c] using erdos_layers_le_four_pow_three_layers_aux N (N / 3) + _ ≤ 4 ^ ((2 * n + 2) / 3 + n / 15 + n / 4) := by + dsimp [N] at hsqrt hcL ⊢ + apply Nat.pow_le_pow_right (by norm_num : 0 < 4) + omega + +/-- Explicit large-`n` estimate for the central Erdős layer product at `N = 2 * n + 2`. -/ +theorem central_erdos_layers_two_mul_add_two_lt_four_pow {n : ℕ} (hn : 512 ≤ n) : + n * (∏ j ∈ Finset.range (Nat.log 2 (2 * n + 2)), + if j = 0 then primorial ((2 * n + 2) / 3) + else primorial (Nat.nthRoot (j + 1) (2 * n + 2))) < 4 ^ n := by + have hprod := central_layers_two_mul_add_two_le_four_pow hn + have hnfac := self_le_four_pow_div_one_twenty_eight_add_one hn + have hexp : (2 * n + 2) / 3 + n / 15 + n / 4 + (n / 128 + 1) < n := by + omega + calc + n * (∏ j ∈ Finset.range (Nat.log 2 (2 * n + 2)), + if j = 0 then primorial ((2 * n + 2) / 3) + else primorial (Nat.nthRoot (j + 1) (2 * n + 2))) + ≤ 4 ^ (n / 128 + 1) * 4 ^ ((2 * n + 2) / 3 + n / 15 + n / 4) := + Nat.mul_le_mul hnfac hprod + _ = 4 ^ ((n / 128 + 1) + ((2 * n + 2) / 3 + n / 15 + n / 4)) := by + rw [← pow_add] + _ < 4 ^ n := by + apply Nat.pow_lt_pow_right (by norm_num : 1 < 4) + omega + +private lemma erdos_layers_tail_le_four_pow_sqrt (N r : ℕ) : + (∏ j ∈ (Finset.range (Nat.log 2 N)).erase 0, + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + (4 ^ Nat.sqrt N) ^ Nat.log 2 N := by + exact erdos_layers_tail_le_four_pow_of_nthRoot_le + (s := (Finset.range (Nat.log 2 N)).erase 0) (B := Nat.sqrt N) + (fun j hj => nthRoot_le_sqrt_of_two_le (N := N) (m := j + 1) (by + have hj0 : j ≠ 0 := (Finset.mem_erase.mp hj).1 + omega)) + (fun j hj => (Finset.mem_erase.mp hj).1) + (by + have hcard : + ((Finset.range (Nat.log 2 N)).erase 0).card ≤ + (Finset.range (Nat.log 2 N)).card := + Finset.card_le_card fun j hj => (Finset.mem_erase.mp hj).2 + simpa using hcard) + +private lemma erdos_layers_le_four_pow_aux (N r : ℕ) : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + 4 ^ (r + Nat.sqrt N * Nat.log 2 N) := by + by_cases h0 : 0 ∈ Finset.range (Nat.log 2 N) + · have hf0 : primorial r ≤ 4 ^ r := primorial_le_four_pow r + have hrest : + (∏ j ∈ (Finset.range (Nat.log 2 N)).erase 0, + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + (4 ^ Nat.sqrt N) ^ Nat.log 2 N := + erdos_layers_tail_le_four_pow_sqrt N r + calc + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) + = primorial r * + ∏ j ∈ (Finset.range (Nat.log 2 N)).erase 0, + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N) := by + rw [← Finset.mul_prod_erase (Finset.range (Nat.log 2 N)) + (fun j => if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) + h0] + simp + _ ≤ 4 ^ r * (4 ^ Nat.sqrt N) ^ Nat.log 2 N := Nat.mul_le_mul hf0 hrest + _ = 4 ^ (r + Nat.sqrt N * Nat.log 2 N) := by + rw [← pow_mul, ← pow_add] + · have hlog : Nat.log 2 N = 0 := by + rw [Finset.mem_range] at h0 + omega + simpa [hlog] using Nat.succ_le_of_lt (pow_pos (by norm_num : 0 < 4) r) + +/- Coarse generic power-of-four bound for the `N / 3` first-layer Erdős product. -/ +private lemma erdos_div_three_layers_le_four_pow (N : ℕ) : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N)) ≤ + 4 ^ (N / 3 + Nat.sqrt N * Nat.log 2 N) := by + exact erdos_layers_le_four_pow_aux N (N / 3) + +/-- Coarse generic power-of-four bound for the Erdős product with first layer `r`. + +This is weaker than the full Erdős estimate, but much sharper than replacing the +first layer by `N / 3` when `N` is several multiples of `r`. -/ +theorem erdos_layers_le_four_pow (N r : ℕ) : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + 4 ^ (r + Nat.sqrt N * Nat.log 2 N) := by + exact erdos_layers_le_four_pow_aux N r + +/-- Three-layer version of `erdos_layers_le_four_pow`: the first layer contributes `r`, the +second contributes `sqrt N`, and all remaining layers are controlled by the cube root of `N`. + +This is the reusable form of the estimate used in Erdős's case split. -/ +theorem erdos_layers_le_four_pow_three_layers (N r : ℕ) : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) ≤ + 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N) := by + exact erdos_layers_le_four_pow_three_layers_aux N r + +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/LargePrimeCriteria.lean b/Mathlib/NumberTheory/SylvesterSchur/LargePrimeCriteria.lean new file mode 100644 index 00000000000000..f495c5f9db9631 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/LargePrimeCriteria.lean @@ -0,0 +1,360 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.NumberTheory.SylvesterSchur.ErdosPowerBounds + +/-! +# Large-prime criteria for Sylvester-Schur + +This file collects contrapositive criteria that turn explicit binomial +coefficient inequalities into large prime divisors. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur + +open scoped BigOperators + +open Finset Nat + +/- Contrapositive of the sharpened Erdős layer bound. -/ +private lemma exists_large_prime_dvd_choose_of_prod_erdos_layers_lt_choose {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) + (hbound : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) < + Nat.choose N r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + exact (not_lt_of_ge (choose_le_prod_erdos_layers_of_no_large hN hrN hsmall)) hbound + +/- Rational lower-bound formulation using the sharpened Erdős layer bound. -/ +private lemma exists_large_prime_dvd_choose_of_prod_erdos_layers_lt_lower_bound {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) + (hbound : + (((∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N) : ℕ) : ℚ) < + ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ))) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + exact exists_large_prime_dvd_choose_of_upper_lt_lower + (fun hsmall => choose_le_prod_erdos_layers_of_no_large hN hrN hsmall) hbound + +/-- Natural-number version of +`exists_large_prime_dvd_choose_of_prod_erdos_layers_lt_lower_bound`. -/ +theorem exists_large_prime_dvd_choose_of_factorial_mul_prod_erdos_layers_lt_lower_pow + {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) + (hbound : + r ! * (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial r else primorial (Nat.nthRoot (j + 1) N)) < + (N + 1 - r) ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_prod_erdos_layers_lt_lower_bound hN hrN + rw [lt_div_iff₀' (by exact_mod_cast Nat.factorial_pos r)] + norm_cast + +/- Contrapositive of the full Erdős prime-power layer bound. -/ +private lemma exists_large_prime_dvd_choose_of_prod_primorial_nthRoot_lt_choose {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) + (hbound : + (∏ j ∈ Finset.range (Nat.log 2 N), primorial (Nat.nthRoot (j + 1) N)) < + Nat.choose N r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + exact (not_lt_of_ge (choose_le_prod_primorial_nthRoot_of_no_large hN hrN hsmall)) + hbound + +/- Rational lower-bound formulation using the full Erdős prime-power layer bound. -/ +private lemma exists_large_prime_dvd_choose_of_prod_primorial_nthRoot_lt_lower_bound {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) + (hbound : + (((∏ j ∈ Finset.range (Nat.log 2 N), primorial (Nat.nthRoot (j + 1) N) : ℕ) : ℚ) < + ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ))) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + exact exists_large_prime_dvd_choose_of_upper_lt_lower + (fun hsmall => choose_le_prod_primorial_nthRoot_of_no_large hN hrN hsmall) hbound + +/-- Natural-number version of +`exists_large_prime_dvd_choose_of_prod_primorial_nthRoot_lt_lower_bound`. -/ +theorem exists_large_prime_dvd_choose_of_factorial_mul_prod_primorial_nthRoot_lt_lower_pow + {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) + (hbound : + r ! * (∏ j ∈ Finset.range (Nat.log 2 N), primorial (Nat.nthRoot (j + 1) N)) < + (N + 1 - r) ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_prod_primorial_nthRoot_lt_lower_bound hN hrN + rw [lt_div_iff₀' (by exact_mod_cast Nat.factorial_pos r)] + norm_cast + +private lemma choose_small_factorization_product_le_top_pow_sqrt {N r : ℕ} (hN : 0 < N) : + (∏ p ∈ (Finset.range (r + 1)).filter (fun p => p ≤ Nat.sqrt N), + p ^ (Nat.choose N r).factorization p) ≤ N ^ (Nat.sqrt N + 1) := by + classical + calc + (∏ p ∈ (Finset.range (r + 1)).filter (fun p => p ≤ Nat.sqrt N), + p ^ (Nat.choose N r).factorization p) ≤ + ∏ _p ∈ (Finset.range (r + 1)).filter (fun p => p ≤ Nat.sqrt N), N := by + apply Finset.prod_le_prod' + intro p hp + by_cases hp_prime : p.Prime + · exact Nat.pow_factorization_choose_le hN + · rw [Nat.factorization_eq_zero_of_not_prime _ hp_prime, pow_zero] + exact hN + _ = N ^ ((Finset.range (r + 1)).filter (fun p => p ≤ Nat.sqrt N)).card := by + rw [Finset.prod_const] + _ ≤ N ^ (Nat.sqrt N + 1) := by + apply Nat.pow_le_pow_right hN + have hcard : + ((Finset.range (r + 1)).filter (fun p => p ≤ Nat.sqrt N)).card ≤ + (Finset.range (Nat.sqrt N + 1)).card := + Finset.card_le_card fun p hp => by + rw [Finset.mem_filter, Finset.mem_range] at hp + exact Finset.mem_range.mpr (Nat.lt_succ_iff.mpr hp.2) + simpa using hcard + +private lemma choose_factorization_pow_le_self_of_sqrt_lt {N r p : ℕ} + (hp_prime : p.Prime) (hp_large : Nat.sqrt N < p) : + p ^ (Nat.choose N r).factorization p ≤ p := by + have hpow_le_one : (Nat.choose N r).factorization p ≤ 1 := + Nat.factorization_choose_le_one (Nat.sqrt_lt'.mp hp_large) + exact (Nat.pow_le_pow_right hp_prime.one_le hpow_le_one).trans_eq (pow_one p) + +private lemma choose_large_factorization_product_le_primorial (N r : ℕ) : + (∏ p ∈ (Finset.range (r + 1)).filter (fun p => ¬ p ≤ Nat.sqrt N), + p ^ (Nat.choose N r).factorization p) ≤ primorial r := by + classical + let large : Finset ℕ := (Finset.range (r + 1)).filter (fun p => ¬ p ≤ Nat.sqrt N) + let f : ℕ → ℕ := fun p => p ^ (Nat.choose N r).factorization p + have hfilter : ∏ p ∈ large, f p = ∏ p ∈ large.filter Nat.Prime, f p := by + exact (Finset.prod_filter_of_ne (s := large) (p := Nat.Prime) (f := f) (by + intro p _ hp_ne_one + contrapose! hp_ne_one + dsimp [f] + rw [Nat.factorization_eq_zero_of_not_prime _ hp_ne_one, pow_zero])).symm + rw [show (∏ p ∈ (Finset.range (r + 1)).filter (fun p => ¬ p ≤ Nat.sqrt N), + p ^ (Nat.choose N r).factorization p) = ∏ p ∈ large, f p by rfl, hfilter] + refine (Finset.prod_le_prod' + (s := large.filter Nat.Prime) (f := f) (g := fun p => p) fun p hp => ?_).trans ?_ + · obtain ⟨hlarge, hp_prime⟩ := Finset.mem_filter.mp hp + exact choose_factorization_pow_le_self_of_sqrt_lt hp_prime (by + dsimp [large] at hlarge + rw [Finset.mem_filter] at hlarge + omega) + dsimp [primorial] + apply Finset.prod_le_prod_of_subset_of_one_le' + · intro p hp + rw [Finset.mem_filter] at hp + rw [Finset.mem_filter] + dsimp [large] at hp + rw [Finset.mem_filter] at hp + exact ⟨hp.1.1, hp.2⟩ + · intro p hp _hp_not + exact (Finset.mem_filter.mp hp).2.one_le + +/- Erdős-style split of the no-large-prime factorization at `sqrt N`. + +Prime factors at most `sqrt N` each contribute at most `N`; prime factors above `sqrt N` +occur with multiplicity at most one, so their contribution is bounded by the primorial of `r`. +This is weaker than the full 1934 product estimate, but it is the next useful refinement beyond +the crude `N ^ Nat.primeCounting r` bound. -/ +private lemma choose_le_top_pow_sqrt_mul_primorial_of_no_large {N r : ℕ} (hN : 0 < N) + (hrN : r ≤ N) (hsmall : ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + Nat.choose N r ≤ N ^ (Nat.sqrt N + 1) * primorial r := by + classical + rw [← choose_eq_prod_small_prime_powers_of_no_large hrN hsmall] + let f : ℕ → ℕ := fun p => p ^ (Nat.choose N r).factorization p + let small : Finset ℕ := (Finset.range (r + 1)).filter (fun p => p ≤ Nat.sqrt N) + let large : Finset ℕ := (Finset.range (r + 1)).filter (fun p => ¬ p ≤ Nat.sqrt N) + have hsplit : + (∏ p ∈ Finset.range (r + 1), f p) = + (∏ p ∈ small, f p) * (∏ p ∈ large, f p) := by + dsimp [small, large] + exact (Finset.prod_filter_mul_prod_filter_not + (Finset.range (r + 1)) (fun p => p ≤ Nat.sqrt N) f).symm + rw [hsplit] + apply Nat.mul_le_mul + · simpa [small, f] using choose_small_factorization_product_le_top_pow_sqrt (N := N) (r := r) hN + · simpa [large, f] using choose_large_factorization_product_le_primorial N r + +/- Contrapositive of `choose_le_top_pow_sqrt_mul_primorial_of_no_large`. -/ +private lemma exists_large_prime_dvd_choose_of_top_pow_sqrt_mul_primorial_lt_choose {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) + (hbound : N ^ (Nat.sqrt N + 1) * primorial r < Nat.choose N r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + exact (not_lt_of_ge + (choose_le_top_pow_sqrt_mul_primorial_of_no_large hN hrN hsmall)) hbound + +/-- Near the central range, the central-binomial lower bound turns the split factorization bound +into a large-prime criterion. -/ +theorem exists_large_prime_dvd_choose_of_mul_top_pow_sqrt_mul_primorial_lt_four_pow + {N r : ℕ} (hr : 4 ≤ r) (hN : 2 * r ≤ N) + (hbound : r * (N ^ (Nat.sqrt N + 1) * primorial r) < 4 ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_top_pow_sqrt_mul_primorial_lt_choose + · omega + · omega + have hcentral_le : Nat.centralBinom r ≤ Nat.choose N r := by + rw [Nat.centralBinom_eq_two_mul_choose] + exact Nat.choose_le_choose r hN + have hlower : 4 ^ r < r * Nat.choose N r := by + exact (Nat.four_pow_lt_mul_centralBinom r hr).trans_le + (Nat.mul_le_mul_left r hcentral_le) + by_contra hnot + push Not at hnot + have hmul : r * Nat.choose N r ≤ r * (N ^ (Nat.sqrt N + 1) * primorial r) := + Nat.mul_le_mul_left r hnot + exact (not_lt_of_ge hbound.le) (hlower.trans_le hmul) + +/- Rational lower-bound formulation using the split `sqrt/primorial` upper bound. -/ +private lemma exists_large_prime_dvd_choose_of_top_pow_sqrt_mul_primorial_lt_lower_bound + {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) + (hbound : + (((N ^ (Nat.sqrt N + 1) * primorial r : ℕ) : ℚ) < + ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ))) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + exact exists_large_prime_dvd_choose_of_upper_lt_lower + (fun hsmall => choose_le_top_pow_sqrt_mul_primorial_of_no_large hN hrN hsmall) hbound + +/-- Natural-number version of +`exists_large_prime_dvd_choose_of_top_pow_sqrt_mul_primorial_lt_lower_bound`. -/ +theorem exists_large_prime_dvd_choose_of_factorial_mul_top_pow_sqrt_mul_primorial_lt_lower_pow + {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) + (hbound : r ! * (N ^ (Nat.sqrt N + 1) * primorial r) < (N + 1 - r) ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_top_pow_sqrt_mul_primorial_lt_lower_bound hN hrN + rw [lt_div_iff₀' (by exact_mod_cast Nat.factorial_pos r)] + norm_cast + +/- Contrapositive form of the factorization estimate: if `Nat.choose N r` is larger than the +no-large-prime upper bound, then it has a prime divisor exceeding `r`. -/ +private lemma exists_large_prime_dvd_choose_of_top_pow_primeCounting_lt_choose {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) + (hbound : N ^ Nat.primeCounting r < Nat.choose N r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + exact (not_lt_of_ge (choose_le_top_pow_primeCounting_of_no_large hN hrN hsmall)) hbound + +/- A variant using only the elementary estimate `Nat.primeCounting r ≤ r - 1`. -/ +private lemma exists_large_prime_dvd_choose_of_top_pow_sub_one_lt_choose {N r : ℕ} + (hN : 0 < N) (hr : 2 ≤ r) (hrN : r ≤ N) + (hbound : N ^ (r - 1) < Nat.choose N r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + exact (not_lt_of_ge (choose_le_top_pow_sub_one_of_no_large hN hr hrN hsmall)) hbound + +/- A variant using the formalized `π(r) ≤ r / 2 + 1` estimate. -/ +private lemma exists_large_prime_dvd_choose_of_top_pow_half_add_one_lt_choose {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) (hbound : N ^ (r / 2 + 1) < Nat.choose N r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + exact (not_lt_of_ge (choose_le_top_pow_half_add_one_of_no_large hN hrN hsmall)) hbound + +/- A variant using the explicit Erdős-style estimate `Nat.primeCounting r ≤ 3 * r / 8`. -/ +private lemma exists_large_prime_dvd_choose_of_top_pow_three_mul_div_eight_lt_choose + {N r : ℕ} (hN : 0 < N) (hr : 38 ≤ r) (hrN : r ≤ N) + (hbound : N ^ (3 * r / 8) < Nat.choose N r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + exact (not_lt_of_ge + (choose_le_top_pow_three_mul_div_eight_of_no_large hN hr hrN hsmall)) hbound + +/- A rational lower-bound formulation convenient for later analytic estimates. Once a separate +calculation proves that this lower bound already exceeds the no-large-prime upper bound, a large +prime divisor follows. -/ +private lemma exists_large_prime_dvd_choose_of_top_pow_primeCounting_lt_lower_bound {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) + (hbound : + ((N ^ Nat.primeCounting r : ℕ) : ℚ) < ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ)) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + exact exists_large_prime_dvd_choose_of_upper_lt_lower + (fun hsmall => choose_le_top_pow_primeCounting_of_no_large hN hrN hsmall) hbound + +/-- Natural-number version of +`exists_large_prime_dvd_choose_of_top_pow_primeCounting_lt_lower_bound`. -/ +theorem exists_large_prime_dvd_choose_of_factorial_mul_top_pow_primeCounting_lt_lower_pow + {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) + (hbound : r ! * N ^ Nat.primeCounting r < (N + 1 - r) ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_top_pow_primeCounting_lt_lower_bound hN hrN + rw [lt_div_iff₀' (by exact_mod_cast Nat.factorial_pos r)] + norm_cast + +/- Lower-bound criterion using the formalized `π(r) ≤ r / 2 + 1` estimate. -/ +private lemma exists_large_prime_dvd_choose_of_top_pow_half_add_one_lt_lower_bound {N r : ℕ} + (hN : 0 < N) (hrN : r ≤ N) + (hbound : ((N ^ (r / 2 + 1) : ℕ) : ℚ) < ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ)) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + exact exists_large_prime_dvd_choose_of_upper_lt_lower + (fun hsmall => choose_le_top_pow_half_add_one_of_no_large hN hrN hsmall) hbound + +/-- Natural-number version of +`exists_large_prime_dvd_choose_of_top_pow_half_add_one_lt_lower_bound`. -/ +theorem exists_large_prime_dvd_choose_of_factorial_mul_top_pow_half_add_one_lt_lower_pow + {N r : ℕ} (hN : 0 < N) (hrN : r ≤ N) + (hbound : r ! * N ^ (r / 2 + 1) < (N + 1 - r) ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_top_pow_half_add_one_lt_lower_bound hN hrN + rw [lt_div_iff₀' (by exact_mod_cast Nat.factorial_pos r)] + norm_cast + +/- Lower-bound criterion using the explicit `π(r) ≤ 3r/8` estimate. -/ +private lemma exists_large_prime_dvd_choose_of_top_pow_three_mul_div_eight_lt_lower_bound + {N r : ℕ} (hN : 0 < N) (hr : 38 ≤ r) (hrN : r ≤ N) + (hbound : + ((N ^ (3 * r / 8) : ℕ) : ℚ) < ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ)) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + exact exists_large_prime_dvd_choose_of_upper_lt_lower + (fun hsmall => choose_le_top_pow_three_mul_div_eight_of_no_large hN hr hrN hsmall) + hbound + +/-- Natural-number version of +`exists_large_prime_dvd_choose_of_top_pow_three_mul_div_eight_lt_lower_bound`. -/ +theorem exists_large_prime_dvd_choose_of_factorial_mul_top_pow_three_mul_div_eight_lt_lower_pow + {N r : ℕ} (hN : 0 < N) (hr : 38 ≤ r) (hrN : r ≤ N) + (hbound : r ! * N ^ (3 * r / 8) < (N + 1 - r) ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_top_pow_three_mul_div_eight_lt_lower_bound hN hr hrN + rw [lt_div_iff₀' (by exact_mod_cast Nat.factorial_pos r)] + norm_cast + +/-- A power-only variant of the `3r/8` criterion, using `r! ≤ r ^ r`. -/ +theorem exists_large_prime_dvd_choose_of_self_pow_mul_top_pow_three_mul_div_eight_lt_lower_pow + {N r : ℕ} (hN : 0 < N) (hr : 38 ≤ r) (hrN : r ≤ N) + (hbound : r ^ r * N ^ (3 * r / 8) < (N + 1 - r) ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_factorial_mul_top_pow_three_mul_div_eight_lt_lower_pow + hN hr hrN + exact (Nat.mul_le_mul_right (N ^ (3 * r / 8)) (Nat.factorial_le_pow r)).trans_lt + hbound + +/- The same lower-bound criterion with the elementary exponent `r - 1`. -/ +private lemma exists_large_prime_dvd_choose_of_top_pow_sub_one_lt_lower_bound {N r : ℕ} + (hN : 0 < N) (hr : 2 ≤ r) (hrN : r ≤ N) + (hbound : ((N ^ (r - 1) : ℕ) : ℚ) < ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ)) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + exact exists_large_prime_dvd_choose_of_upper_lt_lower + (fun hsmall => choose_le_top_pow_sub_one_of_no_large hN hr hrN hsmall) hbound + +/-- Natural-number version of +`exists_large_prime_dvd_choose_of_top_pow_sub_one_lt_lower_bound`. -/ +theorem exists_large_prime_dvd_choose_of_factorial_mul_top_pow_sub_one_lt_lower_pow + {N r : ℕ} (hN : 0 < N) (hr : 2 ≤ r) (hrN : r ≤ N) + (hbound : r ! * N ^ (r - 1) < (N + 1 - r) ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_top_pow_sub_one_lt_lower_bound hN hr hrN + rw [lt_div_iff₀' (by exact_mod_cast Nat.factorial_pos r)] + norm_cast + +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/Main.lean b/Mathlib/NumberTheory/SylvesterSchur/Main.lean new file mode 100644 index 00000000000000..2cbc0adb254b1a --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/Main.lean @@ -0,0 +1,91 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Data.Nat.Factorial.BigOperators +public import Mathlib.Data.Nat.Prime.Basic + +import Mathlib.NumberTheory.Bertrand +import Mathlib.NumberTheory.SylvesterSchur.Bridge +import Mathlib.NumberTheory.SylvesterSchur.ErdosKey + +/-! +# Sylvester-Schur theorem + +This file exposes the `Nat.ascFactorial` form of the Sylvester-Schur theorem, proved +through a private consecutive-block induction. + +## Main statements + +* `Nat.exists_prime_gt_and_dvd_ascFactorial`: among `k` consecutive natural numbers + starting at `n`, where `0 < k < n`, one term has a prime divisor greater than `k`. + +## Implementation notes + +The private induction uses Bertrand's postulate for the base block and the Erdős +binomial-coefficient argument in `Mathlib.NumberTheory.SylvesterSchur.ErdosKey` for the +induction step. + +## References + +The proof follows Erdős's proof of the Sylvester-Schur theorem. + +## Tags + +Sylvester-Schur theorem, prime divisors, binomial coefficients, ascending factorials +-/ + +namespace Nat + +open SylvesterSchur + +/-! ### Final induction -/ + +/- Internal induction proving the consecutive-integer form. + +The base block starts at `n + 1` and is Bertrand's postulate. The induction step shifts +the witness from the previous block unless it belongs to the lost left endpoint; in that +case the Erdős binomial-coefficient lemma supplies a new large prime in the current block. -/ +private lemma sylvester_schur_core {n k : ℕ} (hn : 1 ≤ n) (hk : n < k) : + ∃ i < n, ∃ p, p.Prime ∧ n < p ∧ p ∣ k + i := by + induction k using Nat.strong_induction_on with + | _ k ih => + by_cases hkn : k = n + 1 + · subst hkn + obtain ⟨p, hp_prime, hp_gt, hp_le⟩ := + Nat.exists_prime_lt_and_le_two_mul n (by omega) + refine ⟨p - (n + 1), by omega, p, hp_prime, hp_gt, ?_⟩ + rw [show n + 1 + (p - (n + 1)) = p by omega] + have hkm1_gt : n < k - 1 := by omega + have hkm1_lt : k - 1 < k := Nat.sub_lt (by omega) Nat.one_pos + obtain ⟨j, hj_lt, q, hq_prime, hq_gt, hq_dvd⟩ := ih (k - 1) hkm1_lt hkm1_gt + by_cases hj0 : j = 0 + · -- The induction witness is on the lost left endpoint, so use the binomial lemma. + obtain ⟨p, hp_prime, hp_gt, hp_dvd⟩ := + SylvesterSchur.Internal.erdos_choose_prime_factor_gt n hn k hk + obtain ⟨i, hi_lt, hi_dvd⟩ := + exists_dvd_consecutive_of_prime_dvd_choose n k p hp_prime hp_gt hp_dvd + exact ⟨i, hi_lt, p, hp_prime, hp_gt, hi_dvd⟩ + · refine ⟨j - 1, by omega, q, hq_prime, hq_gt, ?_⟩ + have heq : k - 1 + j = k + (j - 1) := by omega + rwa [heq] at hq_dvd + +end Nat + +@[expose] public section + +namespace Nat + +/-- Sylvester-Schur theorem in Mathlib's `Nat.ascFactorial` API form. -/ +theorem exists_prime_gt_and_dvd_ascFactorial {n k : ℕ} (hk : 0 < k) (hkn : k < n) : + ∃ p : ℕ, p.Prime ∧ k < p ∧ p ∣ n.ascFactorial k := by + obtain ⟨i, hi_lt, p, hp_prime, hp_gt, hp_dvd⟩ := + sylvester_schur_core (n := k) (k := n) hk hkn + refine ⟨p, hp_prime, hp_gt, ?_⟩ + rw [Nat.ascFactorial_eq_prod_range] + exact hp_dvd.trans (Finset.dvd_prod_of_mem _ (Finset.mem_range.mpr hi_lt)) + +end Nat diff --git a/Mathlib/NumberTheory/SylvesterSchur/PrimeCounting.lean b/Mathlib/NumberTheory/SylvesterSchur/PrimeCounting.lean new file mode 100644 index 00000000000000..872555daba523c --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/PrimeCounting.lean @@ -0,0 +1,112 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Data.Nat.Choose.Bounds +public import Mathlib.NumberTheory.PrimeCounting +import Mathlib.Tactic.IntervalCases + +/-! +# Prime-counting estimates for Sylvester-Schur + +This file contains the prime-counting estimates and the basic large-prime extraction +lemmas used in the Sylvester--Schur proof. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur + +open scoped BigOperators + +open Finset Nat + +/-! ### Prime-counting estimates -/ + +/-- Failure of the no-large-prime hypothesis produces a prime divisor of `Nat.choose N r` +strictly greater than `r`. -/ +theorem exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le {N r : ℕ} + (hsmall : ¬ ∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + by_contra h + exact hsmall fun p hp hdvd => le_of_not_gt fun hgt => h ⟨p, hp, hgt, hdvd⟩ + +/-- If a no-large-prime upper bound for `Nat.choose N r` is smaller than Mathlib's lower +bound, then `Nat.choose N r` has a prime divisor greater than `r`. -/ +theorem exists_large_prime_dvd_choose_of_upper_lt_lower {N r U : ℕ} + (hupper : + (∀ p : ℕ, p.Prime → p ∣ Nat.choose N r → p ≤ r) → Nat.choose N r ≤ U) + (hbound : (U : ℚ) < ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ)) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + have hupper_q : ((Nat.choose N r : ℕ) : ℚ) ≤ (U : ℚ) := by + exact_mod_cast hupper hsmall + have hlower : + ((N + 1 - r : ℕ) ^ r : ℚ) / (r ! : ℚ) ≤ ((Nat.choose N r : ℕ) : ℚ) := + Nat.pow_le_choose (α := ℚ) r N + exact (not_lt_of_ge (hlower.trans hupper_q)) hbound + +/-- A very elementary bound: there are at most `r - 1` primes up to `r`, since all such primes +lie in `{2, ..., r}`. -/ +theorem primeCounting_le_sub_one {r : ℕ} (hr : 2 ≤ r) : + Nat.primeCounting r ≤ r - 1 := by + rw [Nat.primeCounting, ← Nat.primesBelow_card_eq_primeCounting' (r + 1)] + have hsubset : + (r + 1).primesBelow ⊆ Finset.Icc 2 r := by + intro p hp + rw [Finset.mem_Icc] + exact ⟨(Nat.prime_of_mem_primesBelow hp).two_le, by + have hlt := Nat.lt_of_mem_primesBelow hp + omega⟩ + exact (Finset.card_le_card hsubset).trans_eq (by rw [card_Icc]; omega) + +/-- A Mathlib-derived linear prime-counting bound. This uses +`Nat.primeCounting'_add_le` with modulus `2`, rather than reproving the odd-prime counting +argument locally. -/ +theorem primeCounting_le_half_add_one (r : ℕ) : + Nat.primeCounting r ≤ r / 2 + 1 := by + by_cases hr : r ≤ 1 + · have hz : Nat.primeCounting r = 0 := Nat.primeCounting_eq_zero_iff.mpr hr + omega + · have hr2 : 2 ≤ r := by omega + have h := + Nat.primeCounting'_add_le (a := 2) (k := 3) (by decide) (by decide) (r - 2) + have harg : 3 + (r - 2) = r + 1 := by omega + have hpi3 : Nat.primeCounting' 3 = 1 := by decide + have htot : Nat.totient 2 = 1 := by decide + rw [harg, hpi3, htot, one_mul] at h + change Nat.primeCounting' (r + 1) ≤ r / 2 + 1 + omega + +/- An explicit prime-counting bound from residue classes modulo `30`. Beyond the primes below +`31`, every prime is coprime to `30`, and Mathlib's `Nat.primeCounting'_add_le` counts at most +one residue-class block plus a tail. -/ +private lemma primeCounting_le_mod_thirty (r : ℕ) : + Nat.primeCounting r ≤ 10 + 8 * ((r - 30) / 30 + 1) := by + by_cases hr : r ≤ 30 + · have hmono : Nat.primeCounting r ≤ Nat.primeCounting 30 := + Nat.monotone_primeCounting hr + have hpi30 : Nat.primeCounting 30 = 10 := by decide + omega + · have h := + Nat.primeCounting'_add_le (a := 30) (k := 31) (by decide) (by decide) (r - 30) + have harg : 31 + (r - 30) = r + 1 := by omega + have hpi31 : Nat.primeCounting' 31 = 10 := by decide + have htot : Nat.totient 30 = 8 := by decide + rw [harg, hpi31, htot] at h + change Nat.primeCounting' (r + 1) ≤ 10 + 8 * ((r - 30) / 30 + 1) + exact h + +/-- Erdős's `3r/8` prime-counting estimate. The infinite tail follows from the +residue-class estimate modulo `30`; the range `38 ≤ r < 91` is checked directly. -/ +theorem primeCounting_le_three_mul_div_eight {r : ℕ} (hr : 38 ≤ r) : + Nat.primeCounting r ≤ 3 * r / 8 := by + by_cases h91 : 91 ≤ r + · exact (primeCounting_le_mod_thirty r).trans (by omega) + · interval_cases r <;> decide + +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/ResidualFinite.lean b/Mathlib/NumberTheory/SylvesterSchur/ResidualFinite.lean new file mode 100644 index 00000000000000..51208f3f2d09a9 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ResidualFinite.lean @@ -0,0 +1,494 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Algebra.BigOperators.Group.Finset.Defs +public import Mathlib.Data.Nat.Choose.Basic +public import Mathlib.Data.Nat.Choose.Dvd +public import Mathlib.Data.Nat.Log +public import Mathlib.Data.Nat.NthRoot.Defs +public import Mathlib.Data.Nat.Prime.Basic +public import Mathlib.Data.Nat.Sqrt +public import Mathlib.NumberTheory.SylvesterSchur.BlockReductions + +/-! +# Finite residual checks for the Sylvester-Schur theorem + +This file contains the finite residual checks used by the Sylvester-Schur proof. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur +namespace Internal + +open Finset Nat + +private lemma three_mul_choose_two_mul_add_le_two_mul_choose_succ + {n i : ℕ} (hi : i + 1 ≤ n) : + 3 * Nat.choose (2 * n + i) n ≤ 2 * Nat.choose (2 * n + i + 1) n := by + have hchoose : + Nat.choose (2 * n + i + 1) n * (n + i + 1) = + Nat.choose (2 * n + i) n * (2 * n + i + 1) := by + have h := (Nat.choose_mul_succ_eq (2 * n + i) n).symm + have h1 : 2 * n + i + 1 - n = n + i + 1 := by omega + simpa [h1] using h + apply Nat.le_of_mul_le_mul_right _ (by omega : 0 < n + i + 1) + calc + (3 * Nat.choose (2 * n + i) n) * (n + i + 1) + = Nat.choose (2 * n + i) n * (3 * (n + i + 1)) := by ring + _ ≤ Nat.choose (2 * n + i) n * (2 * (2 * n + i + 1)) := by + apply Nat.mul_le_mul_left + omega + _ = 2 * (Nat.choose (2 * n + i) n * (2 * n + i + 1)) := by ring + _ = 2 * (Nat.choose (2 * n + i + 1) n * (n + i + 1)) := by + rw [← hchoose] + _ = (2 * Nat.choose (2 * n + i + 1) n) * (n + i + 1) := by ring + +private lemma three_pow_mul_centralBinom_le_two_pow_mul_choose_two_mul_add + {n i : ℕ} (hi : i ≤ n) : + 3 ^ i * Nat.centralBinom n ≤ 2 ^ i * Nat.choose (2 * n + i) n := by + induction i with + | zero => + simp [Nat.centralBinom, two_mul] + | succ i ih => + have hi' : i ≤ n := by omega + have hstep := ih hi' + have hratio : + 3 * Nat.choose (2 * n + i) n ≤ + 2 * Nat.choose (2 * n + i + 1) n := + three_mul_choose_two_mul_add_le_two_mul_choose_succ hi + calc + 3 ^ (i + 1) * Nat.centralBinom n + = 3 * (3 ^ i * Nat.centralBinom n) := by ring + _ ≤ 3 * (2 ^ i * Nat.choose (2 * n + i) n) := + Nat.mul_le_mul_left 3 hstep + _ = 2 ^ i * (3 * Nat.choose (2 * n + i) n) := by ring + _ ≤ 2 ^ i * (2 * Nat.choose (2 * n + i + 1) n) := + Nat.mul_le_mul_left _ hratio + _ = 2 ^ (i + 1) * Nat.choose (2 * n + (i + 1)) n := by ring_nf + +private lemma three_pow_mul_centralBinom_le_two_pow_mul_choose_three_mul (n : ℕ) : + 3 ^ n * Nat.centralBinom n ≤ 2 ^ n * Nat.choose (3 * n) n := by + convert + three_pow_mul_centralBinom_le_two_pow_mul_choose_two_mul_add (n := n) (i := n) le_rfl + using 1 + · ring_nf + +private lemma three_pow_mul_four_pow_lt_mul_two_pow_mul_choose_three_mul + {n : ℕ} (hn : 4 ≤ n) : + 3 ^ n * 4 ^ n < n * (2 ^ n * Nat.choose (3 * n) n) := by + have hcentral : 4 ^ n < n * Nat.centralBinom n := + Nat.four_pow_lt_mul_centralBinom n hn + have hmul : 3 ^ n * 4 ^ n < 3 ^ n * (n * Nat.centralBinom n) := + (Nat.mul_lt_mul_left (pow_pos (by norm_num : 0 < 3) n)).mpr hcentral + have hupper : + 3 ^ n * (n * Nat.centralBinom n) ≤ n * (2 ^ n * Nat.choose (3 * n) n) := by + calc + 3 ^ n * (n * Nat.centralBinom n) + = n * (3 ^ n * Nat.centralBinom n) := by ring + _ ≤ n * (2 ^ n * Nat.choose (3 * n) n) := + Nat.mul_le_mul_left n (three_pow_mul_centralBinom_le_two_pow_mul_choose_three_mul n) + exact hmul.trans_le hupper + +/-- In the first residual range, the scaled ternary lower bound contradicts the +three-layer Erdős upper bound unless `Nat.choose N r` has a prime divisor above `r`. -/ +lemma exists_prime_dvd_choose_of_scaled_ternary_erdos_layers_bound {N r : ℕ} + (hr : 4 ≤ r) (hrN : 3 * r ≤ N) + (hbound : + r * (2 ^ r * ((3 * r) ^ r * + 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) < + 3 ^ r * 4 ^ r * N ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + have hchoose_upper : + Nat.choose N r ≤ + 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N) := by + exact (choose_le_prod_erdos_layers_of_no_large (by omega) (by omega) hsmall).trans + (erdos_layers_le_four_pow_three_layers N r) + have hchoose_scaled : + N ^ r * Nat.choose (3 * r) r ≤ (3 * r) ^ r * Nat.choose N r := + pow_mul_choose_le_pow_mul_choose (M := 3 * r) (N := N) (r := r) + (by omega) hrN + have hcentral : + 3 ^ r * 4 ^ r < r * (2 ^ r * Nat.choose (3 * r) r) := + three_pow_mul_four_pow_lt_mul_two_pow_mul_choose_three_mul hr + have hcentral_scaled : + 3 ^ r * 4 ^ r * N ^ r < + r * (2 ^ r * (N ^ r * Nat.choose (3 * r) r)) := by + simpa [mul_assoc, mul_left_comm, mul_comm] using + Nat.mul_lt_mul_of_pos_right hcentral (pow_pos (by omega : 0 < N) r) + have hupper_scaled : + r * (2 ^ r * (N ^ r * Nat.choose (3 * r) r)) ≤ + r * (2 ^ r * ((3 * r) ^ r * + 4 ^ (r + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) := by + exact Nat.mul_le_mul_left r <| Nat.mul_le_mul_left (2 ^ r) <| + hchoose_scaled.trans <| Nat.mul_le_mul_left ((3 * r) ^ r) hchoose_upper + exact (not_lt_of_ge (le_of_lt (hcentral_scaled.trans_le hupper_scaled))) hbound + +/-- In the central residual range, the offset central-binomial lower bound contradicts +the `N / 3` first-layer estimate unless a large prime divides `Nat.choose N r`. -/ +lemma exists_prime_dvd_choose_of_central_offset_erdos_div_three_layers_bound + {N r i : ℕ} (hr : 4 ≤ r) (hi : i ≤ r) (hN : N = 2 * r + i) (hN6 : 6 ≤ N) + (hbound : + r * (2 ^ i * + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N))) < + 3 ^ i * 4 ^ r) : + ∃ p : ℕ, p.Prime ∧ r < p ∧ p ∣ Nat.choose N r := by + apply exists_large_prime_dvd_choose_of_not_forall_prime_dvd_le + intro hsmall + have hchoose_upper : + Nat.choose N r ≤ + ∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N) := by + exact choose_le_prod_erdos_div_three_layers_of_no_large (by omega) (by omega) + (by omega) hN6 hsmall + have hcentral : 4 ^ r < r * Nat.centralBinom r := + Nat.four_pow_lt_mul_centralBinom r hr + have hoffset : + 3 ^ i * Nat.centralBinom r ≤ 2 ^ i * Nat.choose N r := by + have h := + three_pow_mul_centralBinom_le_two_pow_mul_choose_two_mul_add (n := r) (i := i) hi + simpa [hN] using h + have hlower : + 3 ^ i * 4 ^ r < r * (2 ^ i * Nat.choose N r) := by + calc + 3 ^ i * 4 ^ r + < 3 ^ i * (r * Nat.centralBinom r) := + (Nat.mul_lt_mul_left (pow_pos (by norm_num : 0 < 3) i)).mpr hcentral + _ = r * (3 ^ i * Nat.centralBinom r) := by ring + _ ≤ r * (2 ^ i * Nat.choose N r) := + Nat.mul_le_mul_left r hoffset + have hupper_mul : + r * (2 ^ i * Nat.choose N r) ≤ + r * (2 ^ i * + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N))) := + Nat.mul_le_mul_left r (Nat.mul_le_mul_left (2 ^ i) hchoose_upper) + exact (not_lt_of_ge (le_of_lt (hlower.trans_le hupper_mul))) hbound + +/-- Small central-offset cases for `Nat.choose (2 * n + 2) n`, handled by an +explicit short prime-gap certificate. -/ +lemma exists_prime_dvd_choose_two_mul_add_two_small {n : ℕ} (hn7 : 7 ≤ n) + (hnlt : n < 512) : + ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ Nat.choose (2 * n + 2) n := by + have hchoose : ∀ p : ℕ, p.Prime → n + 3 ≤ p → p ≤ 2 * n + 2 → + p ∣ Nat.choose (2 * n + 2) n := by + intro p hp hp_low hp_high + have hd : p ∣ Nat.choose (n + (n + 2)) n := + hp.dvd_choose_add (by omega) (by omega) (by omega) + rwa [show n + (n + 2) = 2 * n + 2 by omega] at hd + by_cases hn11 : n < 11 + · exact ⟨13, by norm_num, by omega, hchoose 13 (by norm_num) (by omega) (by omega)⟩ + by_cases hn21 : n < 21 + · exact ⟨23, by norm_num, by omega, hchoose 23 (by norm_num) (by omega) (by omega)⟩ + by_cases hn35 : n < 35 + · exact ⟨37, by norm_num, by omega, hchoose 37 (by norm_num) (by omega) (by omega)⟩ + by_cases hn69 : n < 69 + · exact ⟨71, by norm_num, by omega, hchoose 71 (by norm_num) (by omega) (by omega)⟩ + by_cases hn135 : n < 135 + · exact ⟨137, by norm_num, by omega, hchoose 137 (by norm_num) (by omega) (by omega)⟩ + by_cases hn261 : n < 261 + · exact ⟨263, by norm_num, by omega, hchoose 263 (by norm_num) (by omega) (by omega)⟩ + exact ⟨521, by norm_num, by omega, hchoose 521 (by norm_num) (by omega) (by omega)⟩ + +private lemma exists_large_prime_factor_in_block_of_prime_near {n k p g : ℕ} + (hg : g < n) (hklo : n + 3 ≤ k) (hp : p.Prime) (hkp : k ≤ p) + (hp_le : p ≤ k + g) : + ∃ i < n, ∃ q : ℕ, q.Prime ∧ n < q ∧ q ∣ k + i := by + refine ⟨p - k, by omega, p, hp, by omega, ?_⟩ + have hsum : k + (p - k) = p := by omega + rw [hsum] + +private lemma exists_prime_near_seven_of_ge_ten_lt_100 {k : ℕ} + (hk10 : 10 ≤ k) (hklt : k < 100) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 7 := by + by_cases hk17 : k ≤ 17 + · exact ⟨17, by norm_num, by omega, by omega⟩ + by_cases hk23 : k ≤ 23 + · exact ⟨23, by norm_num, by omega, by omega⟩ + by_cases hk31 : k ≤ 31 + · exact ⟨31, by norm_num, by omega, by omega⟩ + by_cases hk37 : k ≤ 37 + · exact ⟨37, by norm_num, by omega, by omega⟩ + by_cases hk43 : k ≤ 43 + · exact ⟨43, by norm_num, by omega, by omega⟩ + by_cases hk47 : k ≤ 47 + · exact ⟨47, by norm_num, by omega, by omega⟩ + by_cases hk53 : k ≤ 53 + · exact ⟨53, by norm_num, by omega, by omega⟩ + by_cases hk61 : k ≤ 61 + · exact ⟨61, by norm_num, by omega, by omega⟩ + by_cases hk67 : k ≤ 67 + · exact ⟨67, by norm_num, by omega, by omega⟩ + by_cases hk73 : k ≤ 73 + · exact ⟨73, by norm_num, by omega, by omega⟩ + by_cases hk79 : k ≤ 79 + · exact ⟨79, by norm_num, by omega, by omega⟩ + by_cases hk83 : k ≤ 83 + · exact ⟨83, by norm_num, by omega, by omega⟩ + by_cases hk89 : k ≤ 89 + · exact ⟨89, by norm_num, by omega, by omega⟩ + by_cases hk97 : k ≤ 97 + · exact ⟨97, by norm_num, by omega, by omega⟩ + exact ⟨103, by norm_num, by omega, by omega⟩ + +private lemma exists_prime_near_six_low {k : ℕ} (hk10 : 10 ≤ k) (hk53 : k ≤ 53) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 6 := by + by_cases hk13 : k ≤ 13 + · exact ⟨13, by norm_num, by omega, by omega⟩ + by_cases hk19 : k ≤ 19 + · exact ⟨19, by norm_num, by omega, by omega⟩ + by_cases hk23 : k ≤ 23 + · exact ⟨23, by norm_num, by omega, by omega⟩ + by_cases hk29 : k ≤ 29 + · exact ⟨29, by norm_num, by omega, by omega⟩ + by_cases hk31 : k ≤ 31 + · exact ⟨31, by norm_num, by omega, by omega⟩ + by_cases hk37 : k ≤ 37 + · exact ⟨37, by norm_num, by omega, by omega⟩ + by_cases hk43 : k ≤ 43 + · exact ⟨43, by norm_num, by omega, by omega⟩ + by_cases hk47 : k ≤ 47 + · exact ⟨47, by norm_num, by omega, by omega⟩ + by_cases hk53 : k ≤ 53 + · exact ⟨53, by norm_num, by omega, by omega⟩ + omega + +private lemma exists_prime_near_six_high {k : ℕ} + (hk54 : 54 ≤ k) (hklt : k < 100) (hk90 : k ≠ 90) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 6 := by + by_cases hk59 : k ≤ 59 + · exact ⟨59, by norm_num, by omega, by omega⟩ + by_cases hk61 : k ≤ 61 + · exact ⟨61, by norm_num, by omega, by omega⟩ + by_cases hk67 : k ≤ 67 + · exact ⟨67, by norm_num, by omega, by omega⟩ + by_cases hk73 : k ≤ 73 + · exact ⟨73, by norm_num, by omega, by omega⟩ + by_cases hk79 : k ≤ 79 + · exact ⟨79, by norm_num, by omega, by omega⟩ + by_cases hk83 : k ≤ 83 + · exact ⟨83, by norm_num, by omega, by omega⟩ + by_cases hk89 : k ≤ 89 + · exact ⟨89, by norm_num, by omega, by omega⟩ + by_cases hk97 : k ≤ 97 + · exact ⟨97, by norm_num, by omega, by omega⟩ + exact ⟨101, by norm_num, by omega, by omega⟩ + +private lemma exists_prime_near_six_of_ge_ten_lt_100_ne_ninety {k : ℕ} + (hk10 : 10 ≤ k) (hklt : k < 100) (hk90 : k ≠ 90) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 6 := by + by_cases hk53 : k ≤ 53 + · exact exists_prime_near_six_low hk10 hk53 + exact exists_prime_near_six_high (by omega) hklt hk90 + +private lemma exists_prime_near_mid_range_low {k : ℕ} + (hk41 : 41 ≤ k) (hk331 : k ≤ 331) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 21 := by + by_cases hk61 : k ≤ 61 + · exact ⟨61, by norm_num, by omega, by omega⟩ + by_cases hk83 : k ≤ 83 + · exact ⟨83, by norm_num, by omega, by omega⟩ + by_cases hk103 : k ≤ 103 + · exact ⟨103, by norm_num, by omega, by omega⟩ + by_cases hk113 : k ≤ 113 + · exact ⟨113, by norm_num, by omega, by omega⟩ + by_cases hk131 : k ≤ 131 + · exact ⟨131, by norm_num, by omega, by omega⟩ + by_cases hk151 : k ≤ 151 + · exact ⟨151, by norm_num, by omega, by omega⟩ + by_cases hk173 : k ≤ 173 + · exact ⟨173, by norm_num, by omega, by omega⟩ + by_cases hk193 : k ≤ 193 + · exact ⟨193, by norm_num, by omega, by omega⟩ + by_cases hk211 : k ≤ 211 + · exact ⟨211, by norm_num, by omega, by omega⟩ + by_cases hk233 : k ≤ 233 + · exact ⟨233, by norm_num, by omega, by omega⟩ + by_cases hk251 : k ≤ 251 + · exact ⟨251, by norm_num, by omega, by omega⟩ + by_cases hk271 : k ≤ 271 + · exact ⟨271, by norm_num, by omega, by omega⟩ + by_cases hk293 : k ≤ 293 + · exact ⟨293, by norm_num, by omega, by omega⟩ + by_cases hk313 : k ≤ 313 + · exact ⟨313, by norm_num, by omega, by omega⟩ + exact ⟨331, by norm_num, by omega, by omega⟩ + +private lemma exists_prime_near_mid_range_middle {k : ℕ} + (hk332 : 332 ≤ k) (hk641 : k ≤ 641) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 21 := by + by_cases hk353 : k ≤ 353 + · exact ⟨353, by norm_num, by omega, by omega⟩ + by_cases hk373 : k ≤ 373 + · exact ⟨373, by norm_num, by omega, by omega⟩ + by_cases hk389 : k ≤ 389 + · exact ⟨389, by norm_num, by omega, by omega⟩ + by_cases hk409 : k ≤ 409 + · exact ⟨409, by norm_num, by omega, by omega⟩ + by_cases hk431 : k ≤ 431 + · exact ⟨431, by norm_num, by omega, by omega⟩ + by_cases hk449 : k ≤ 449 + · exact ⟨449, by norm_num, by omega, by omega⟩ + by_cases hk467 : k ≤ 467 + · exact ⟨467, by norm_num, by omega, by omega⟩ + by_cases hk487 : k ≤ 487 + · exact ⟨487, by norm_num, by omega, by omega⟩ + by_cases hk509 : k ≤ 509 + · exact ⟨509, by norm_num, by omega, by omega⟩ + by_cases hk523 : k ≤ 523 + · exact ⟨523, by norm_num, by omega, by omega⟩ + by_cases hk541 : k ≤ 541 + · exact ⟨541, by norm_num, by omega, by omega⟩ + by_cases hk563 : k ≤ 563 + · exact ⟨563, by norm_num, by omega, by omega⟩ + by_cases hk577 : k ≤ 577 + · exact ⟨577, by norm_num, by omega, by omega⟩ + by_cases hk599 : k ≤ 599 + · exact ⟨599, by norm_num, by omega, by omega⟩ + by_cases hk619 : k ≤ 619 + · exact ⟨619, by norm_num, by omega, by omega⟩ + exact ⟨641, by norm_num, by omega, by omega⟩ + +private lemma exists_prime_near_mid_range_high_low {k : ℕ} + (hk642 : 642 ≤ k) (hk809 : k ≤ 809) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 21 := by + by_cases hk661 : k ≤ 661 + · exact ⟨661, by norm_num, by omega, by omega⟩ + by_cases hk683 : k ≤ 683 + · exact ⟨683, by norm_num, by omega, by omega⟩ + by_cases hk701 : k ≤ 701 + · exact ⟨701, by norm_num, by omega, by omega⟩ + by_cases hk719 : k ≤ 719 + · exact ⟨719, by norm_num, by omega, by omega⟩ + by_cases hk739 : k ≤ 739 + · exact ⟨739, by norm_num, by omega, by omega⟩ + by_cases hk761 : k ≤ 761 + · exact ⟨761, by norm_num, by omega, by omega⟩ + by_cases hk773 : k ≤ 773 + · exact ⟨773, by norm_num, by omega, by omega⟩ + by_cases hk787 : k ≤ 787 + · exact ⟨787, by norm_num, by omega, by omega⟩ + by_cases hk809 : k ≤ 809 + · exact ⟨809, by norm_num, by omega, by omega⟩ + omega + +private lemma exists_prime_near_mid_range_high_top {k : ℕ} + (hk810 : 810 ≤ k) (hk997 : k ≤ 997) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 21 := by + by_cases hk829 : k ≤ 829 + · exact ⟨829, by norm_num, by omega, by omega⟩ + by_cases hk839 : k ≤ 839 + · exact ⟨839, by norm_num, by omega, by omega⟩ + by_cases hk859 : k ≤ 859 + · exact ⟨859, by norm_num, by omega, by omega⟩ + by_cases hk881 : k ≤ 881 + · exact ⟨881, by norm_num, by omega, by omega⟩ + by_cases hk887 : k ≤ 887 + · exact ⟨887, by norm_num, by omega, by omega⟩ + by_cases hk907 : k ≤ 907 + · exact ⟨907, by norm_num, by omega, by omega⟩ + by_cases hk929 : k ≤ 929 + · exact ⟨929, by norm_num, by omega, by omega⟩ + by_cases hk947 : k ≤ 947 + · exact ⟨947, by norm_num, by omega, by omega⟩ + by_cases hk967 : k ≤ 967 + · exact ⟨967, by norm_num, by omega, by omega⟩ + by_cases hk983 : k ≤ 983 + · exact ⟨983, by norm_num, by omega, by omega⟩ + exact ⟨997, by norm_num, by omega, by omega⟩ + +private lemma exists_prime_near_mid_range_high {k : ℕ} + (hk642 : 642 ≤ k) (hk997 : k ≤ 997) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 21 := by + by_cases hk809 : k ≤ 809 + · exact exists_prime_near_mid_range_high_low hk642 hk809 + exact exists_prime_near_mid_range_high_top (by omega) hk997 + +private lemma exists_prime_near_mid_range_top {k : ℕ} + (hk998 : 998 ≤ k) (hklt : k < 1291) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 21 := by + by_cases hk1019 : k ≤ 1019 + · exact ⟨1019, by norm_num, by omega, by omega⟩ + by_cases hk1039 : k ≤ 1039 + · exact ⟨1039, by norm_num, by omega, by omega⟩ + by_cases hk1061 : k ≤ 1061 + · exact ⟨1061, by norm_num, by omega, by omega⟩ + by_cases hk1069 : k ≤ 1069 + · exact ⟨1069, by norm_num, by omega, by omega⟩ + by_cases hk1091 : k ≤ 1091 + · exact ⟨1091, by norm_num, by omega, by omega⟩ + by_cases hk1109 : k ≤ 1109 + · exact ⟨1109, by norm_num, by omega, by omega⟩ + by_cases hk1129 : k ≤ 1129 + · exact ⟨1129, by norm_num, by omega, by omega⟩ + by_cases hk1151 : k ≤ 1151 + · exact ⟨1151, by norm_num, by omega, by omega⟩ + by_cases hk1171 : k ≤ 1171 + · exact ⟨1171, by norm_num, by omega, by omega⟩ + by_cases hk1193 : k ≤ 1193 + · exact ⟨1193, by norm_num, by omega, by omega⟩ + by_cases hk1213 : k ≤ 1213 + · exact ⟨1213, by norm_num, by omega, by omega⟩ + by_cases hk1231 : k ≤ 1231 + · exact ⟨1231, by norm_num, by omega, by omega⟩ + by_cases hk1249 : k ≤ 1249 + · exact ⟨1249, by norm_num, by omega, by omega⟩ + by_cases hk1259 : k ≤ 1259 + · exact ⟨1259, by norm_num, by omega, by omega⟩ + by_cases hk1279 : k ≤ 1279 + · exact ⟨1279, by norm_num, by omega, by omega⟩ + exact ⟨1301, by norm_num, by omega, by omega⟩ + +/- A prime-gap certificate for the mid residual range. + +For every `41 ≤ k < 1291`, one of the displayed primes lies in `[k, k + 21]`. +Since the mid residual has block length at least `38`, this prime is one of the + terms in the block. -/ +private lemma exists_prime_near_of_ge_forty_one_lt_1291 {k : ℕ} + (hk41 : 41 ≤ k) (hklt : k < 1291) : + ∃ p : ℕ, p.Prime ∧ k ≤ p ∧ p ≤ k + 21 := by + by_cases hk331 : k ≤ 331 + · exact exists_prime_near_mid_range_low hk41 hk331 + by_cases hk641 : k ≤ 641 + · exact exists_prime_near_mid_range_middle (by omega) hk641 + by_cases hk997 : k ≤ 997 + · exact exists_prime_near_mid_range_high (by omega) hk997 + exact exists_prime_near_mid_range_top (by omega) hklt + +/-- For `7 ≤ n < 38` and `k < 100`, a small prime-gap table supplies a block term +with a prime divisor greater than `n`. -/ +lemma second_residual_tiny_has_large_prime_factor {n k : ℕ} + (hn7 : 7 ≤ n) (hnlt : n < 38) (hklo : n + 3 ≤ k) (hklt : k < 100) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + by_cases hn8 : 8 ≤ n + · obtain ⟨p, hp, hkp, hp_le⟩ := + exists_prime_near_seven_of_ge_ten_lt_100 (by omega) hklt + exact exists_large_prime_factor_in_block_of_prime_near (by omega) hklo hp hkp hp_le + have hn_eq : n = 7 := by omega + subst n + by_cases hk90 : k = 90 + · subst k + exact ⟨4, by norm_num, 47, by norm_num, by norm_num, by norm_num⟩ + obtain ⟨p, hp, hkp, hp_le⟩ := + exists_prime_near_six_of_ge_ten_lt_100_ne_ninety (by omega) hklt hk90 + exact exists_large_prime_factor_in_block_of_prime_near (by omega) hklo hp hkp hp_le + +/-- For `38 ≤ n < 945` and `k < 1291`, a prime-gap table supplies a block term +with a prime divisor greater than `n`. -/ +lemma second_residual_mid_has_large_prime_factor {n k : ℕ} + (hn38 : 38 ≤ n) (hnlt : n < 945) (hklo : n + 3 ≤ k) (hklt : k < 1291) : + ∃ i < n, ∃ p : ℕ, p.Prime ∧ n < p ∧ p ∣ k + i := by + obtain ⟨p, hp, hkp, hp_le⟩ := + exists_prime_near_of_ge_forty_one_lt_1291 (by omega) hklt + exact exists_large_prime_factor_in_block_of_prime_near (by omega) hklo hp hkp hp_le + + +end Internal +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge.lean b/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge.lean new file mode 100644 index 00000000000000..5b082bbf2c8c5e --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge.lean @@ -0,0 +1,16 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge.CentralOffsetBound +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge.ScaledTernaryBound +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge.TinyPrimeCountingBound + +/-! +# Large residual estimates for the Sylvester-Schur theorem + +This module re-exports the large residual estimates used by the Sylvester-Schur proof. +-/ diff --git a/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/CentralOffsetBound.lean b/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/CentralOffsetBound.lean new file mode 100644 index 00000000000000..eb9470976aa474 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/CentralOffsetBound.lean @@ -0,0 +1,82 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.NumberTheory.SylvesterSchur.ErdosPowerBounds +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge.ScaledTernaryBound + +import Mathlib.Tactic.Linarith + +/-! +# Central-offset bound for the Sylvester-Schur large residual estimate + +This file contains the large residual estimate for the central-offset range +`k + n - 1 < 3 * n`. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur +namespace Internal + +private lemma central_layers_le_four_pow_of_lt_three_mul {n N : ℕ} + (hn : 945 ≤ n) (_hNlo : 2 * n ≤ N) (hNlt : N < 3 * n) : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N)) ≤ + 4 ^ (N / 3 + n / 15 + n / 5) := by + have hsqrt : Nat.sqrt N ≤ n / 15 := + sqrt_le_div_fifteen_of_le_four_mul (by omega : 900 ≤ n) (by omega : N ≤ 4 * n) + have hroot_log : Nat.nthRoot 3 N * Nat.log 2 N ≤ n / 5 := + nthRoot_three_mul_log_le_one_fifth_of_le_four_mul hn (by omega : N ≤ 4 * n) + have hlayers := erdos_layers_le_four_pow_three_layers N (N / 3) + calc + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N)) + ≤ 4 ^ (N / 3 + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N) := hlayers + _ ≤ 4 ^ (N / 3 + n / 15 + n / 5) := by + apply Nat.pow_le_pow_right (by norm_num : 0 < 4) + omega + +/-- Large-`n` residual estimate in the central-offset range `k + n - 1 < 3 * n`. -/ +lemma second_residual_large_central_offset_bound {n k : ℕ} + (hn : 945 ≤ n) (hk : n < k) (hcentral : k + n - 1 < 3 * n) : + n * (2 ^ (k - n - 1) * + (∏ j ∈ Finset.range (Nat.log 2 (k + n - 1)), + if j = 0 then primorial ((k + n - 1) / 3) + else primorial (Nat.nthRoot (j + 1) (k + n - 1)))) < + 3 ^ (k - n - 1) * 4 ^ n := by + let N := k + n - 1 + let i := k - n - 1 + let D := n / 128 + 1 + let E := N / 3 + n / 15 + n / 5 + have hNlo : 2 * n ≤ N := by + dsimp [N] + omega + have hprod : + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N)) ≤ + 4 ^ E := by + dsimp [E] + exact central_layers_le_four_pow_of_lt_three_mul hn hNlo (by simpa [N] using hcentral) + have hnfac : n ≤ 4 ^ D := by + dsimp [D] + exact self_le_four_pow_div_one_twenty_eight_add_one (by omega : 512 ≤ n) + have hleft : + n * (2 ^ i * + (∏ j ∈ Finset.range (Nat.log 2 N), + if j = 0 then primorial (N / 3) else primorial (Nat.nthRoot (j + 1) N))) ≤ + 4 ^ D * (2 ^ i * 4 ^ E) := + Nat.mul_le_mul hnfac (Nat.mul_le_mul_left (2 ^ i) hprod) + have hexp : 2 * D + i + 2 * E < 19 * (i / 12) + 2 * n := by + dsimp [D, E, i, N] + omega + have hright : 4 ^ D * (2 ^ i * 4 ^ E) < 3 ^ i * 4 ^ n := + four_pow_mul_two_pow_mul_four_pow_lt_three_pow_mul_four_pow hexp + simpa [N, i] using hleft.trans_lt hright + + +end Internal +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/PowerBounds.lean b/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/PowerBounds.lean new file mode 100644 index 00000000000000..ec7f6a3831dc0c --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/PowerBounds.lean @@ -0,0 +1,100 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Algebra.Group.Defs + +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Ring + +/-! +# Power bounds for large residual Sylvester-Schur estimates + +This file contains the algebraic cancellation and base-exponent estimates used by the large +residual estimates in the Sylvester-Schur proof. + +## Main statements + +* `self_le_four_pow_div_one_twenty_eight_add_one`: a coarse exponential upper bound on `n`. +* `two_pow_nineteen_mul_div_twelve_le_three_pow`: the binary-to-ternary comparison used in + endpoint estimates. +* `four_pow_mul_two_pow_mul_four_pow_lt_three_pow_mul_four_pow`: the common power comparison for + the central-offset residual estimate. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur +namespace Internal + +private lemma four_pow_eq_two_pow_two_mul (n : ℕ) : 4 ^ n = 2 ^ (2 * n) := by + rw [show 4 = 2 ^ 2 by norm_num, ← pow_mul] + +/-- A coarse exponential upper bound used to absorb a factor of `n` in large residual +estimates. -/ +lemma self_le_four_pow_div_one_twenty_eight_add_one {n : ℕ} (hn : 512 ≤ n) : + n ≤ 4 ^ (n / 128 + 1) := by + let m := n / 128 + have hm4 : 4 ≤ m := by + dsimp [m] + rw [Nat.le_div_iff_mul_le (by norm_num : 0 < 128)] + omega + have hnlt : n < 128 * (m + 1) := by + dsimp [m] + exact Nat.lt_mul_div_succ n (by norm_num : 0 < 128) + have hmul_general : ∀ m : ℕ, 4 ≤ m → 128 * (m + 1) ≤ 4 ^ (m + 1) := by + intro m hm + induction m, hm using Nat.le_induction with + | base => norm_num + | succ m hm ih => + calc + 128 * (m + 1 + 1) ≤ 4 * (128 * (m + 1)) := by nlinarith + _ ≤ 4 * 4 ^ (m + 1) := Nat.mul_le_mul_left 4 ih + _ = 4 ^ (m + 1 + 1) := by ring + exact hnlt.le.trans (hmul_general m hm4) + +/-- A binary-to-ternary comparison used to convert powers of `2` into powers of `3`. -/ +lemma two_pow_nineteen_mul_div_twelve_le_three_pow (n : ℕ) : + 2 ^ (19 * (n / 12)) ≤ 3 ^ n := by + let m := n / 12 + have hbase : 2 ^ 19 ≤ 3 ^ 12 := by norm_num + have hm : 12 * m ≤ n := by + dsimp [m] + exact Nat.mul_div_le n 12 + calc + 2 ^ (19 * (n / 12)) = (2 ^ 19) ^ m := by + dsimp [m] + rw [pow_mul] + norm_num + _ ≤ (3 ^ 12) ^ m := Nat.pow_le_pow_left hbase m + _ = 3 ^ (12 * m) := by rw [pow_mul] + _ ≤ 3 ^ n := Nat.pow_le_pow_right (by norm_num : 0 < 3) hm + +/-- The power comparison used after the central-offset residual estimate has been reduced to +exponents. -/ +lemma four_pow_mul_two_pow_mul_four_pow_lt_three_pow_mul_four_pow + {D E i n : ℕ} (hexp : 2 * D + i + 2 * E < 19 * (i / 12) + 2 * n) : + 4 ^ D * (2 ^ i * 4 ^ E) < 3 ^ i * 4 ^ n := by + have hpow : 4 ^ D * (2 ^ i * 4 ^ E) = 2 ^ (2 * D + i + 2 * E) := by + rw [four_pow_eq_two_pow_two_mul D, four_pow_eq_two_pow_two_mul E] + rw [← pow_add, ← pow_add] + congr 1 + ring + have hlt : 2 ^ (2 * D + i + 2 * E) < 2 ^ (19 * (i / 12) + 2 * n) := + Nat.pow_lt_pow_right (by norm_num : 1 < 2) hexp + have hright : 2 ^ (19 * (i / 12) + 2 * n) ≤ 3 ^ i * 4 ^ n := by + calc + 2 ^ (19 * (i / 12) + 2 * n) = 2 ^ (19 * (i / 12)) * 2 ^ (2 * n) := by + rw [pow_add] + _ ≤ 3 ^ i * 2 ^ (2 * n) := + Nat.mul_le_mul_right (2 ^ (2 * n)) (two_pow_nineteen_mul_div_twelve_le_three_pow i) + _ = 3 ^ i * 4 ^ n := by + rw [four_pow_eq_two_pow_two_mul n] + rw [hpow] + exact hlt.trans_le hright + +end Internal +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/ScaledTernaryBound.lean b/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/ScaledTernaryBound.lean new file mode 100644 index 00000000000000..0f8f429803577f --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/ScaledTernaryBound.lean @@ -0,0 +1,923 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Data.Nat.Log +public import Mathlib.Data.Nat.NthRoot.Defs +public import Mathlib.Data.Nat.Sqrt +public import Mathlib.NumberTheory.SylvesterSchur.ResidualLarge.PowerBounds + +import Mathlib.Analysis.SpecialFunctions.Pow.NthRootLemmas +import Mathlib.Tactic.IntervalCases +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Ring + +/-! +# Scaled ternary bound for the Sylvester-Schur large residual estimate + +This file dispatches the range `3 * n ≤ N ≤ n ^ 2 + n` from root-log estimates and +base-exponent bounds. + +## Main statements + +* `first_residual_large_scaled_ternary_bound`: the large residual estimate used when + `3 * n ≤ N ≤ n ^ 2 + n`. +* `sqrt_le_div_fifteen_of_le_four_mul` and + `nthRoot_three_mul_log_le_one_fifth_of_le_four_mul`: reusable estimates for the central + range `N ≤ 4 * n`. + +## Implementation notes + +The proof follows the same large/small split pattern as Mathlib's proof of Bertrand's postulate: +first reduce the product estimate to an exponent inequality, then cover the remaining range by +explicit monotone estimates. The interval split +`[3, 4]`, `(4, 8]`, `(8, 16]`, `(16, 64]`, `(64, 512]`, and `(512, n + 1]` +controls the size of `N / n`. The apparently arbitrary numerical cutoffs in the private +`Nat.nthRoot 3` lemmas are local certificates for bounding +`Nat.nthRoot 3 N * Nat.log 2 N`; they are kept private because they are proof data, not public +API. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur +namespace Internal + +/-! ### Algebraic reductions -/ + +private lemma four_pow_eq_two_pow_two_mul (n : ℕ) : 4 ^ n = 2 ^ (2 * n) := by + rw [show 4 = 2 ^ 2 by norm_num, ← pow_mul] + +private lemma scaled_ternary_bound_of_cancelled {n N A : ℕ} + (h : n * (2 ^ n * (n ^ n * 4 ^ A)) < N ^ n) : + n * (2 ^ n * ((3 * n) ^ n * 4 ^ (n + A))) < + 3 ^ n * 4 ^ n * N ^ n := by + have hpos : 0 < 3 ^ n * 4 ^ n := by positivity + calc + n * (2 ^ n * ((3 * n) ^ n * 4 ^ (n + A))) + = 3 ^ n * 4 ^ n * (n * (2 ^ n * (n ^ n * 4 ^ A))) := by + rw [Nat.mul_pow, pow_add] + ring + _ < 3 ^ n * 4 ^ n * N ^ n := Nat.mul_lt_mul_of_pos_left h hpos + +private lemma cancelled_bound_of_base_pow_exponent_cap {n N B A E : ℕ} + (hnpos : 0 < n) (hNlo : B * n < N) (hA : A ≤ E) + (hbase : n * (2 ^ n * 4 ^ E) < B ^ n) : + n * (2 ^ n * (n ^ n * 4 ^ A)) < N ^ n := by + have hA4 : 4 ^ A ≤ 4 ^ E := Nat.pow_le_pow_right (by norm_num : 0 < 4) hA + have hleft_le : + n * (2 ^ n * (n ^ n * 4 ^ A)) ≤ (n * (2 ^ n * 4 ^ E)) * n ^ n := by + calc + n * (2 ^ n * (n ^ n * 4 ^ A)) = (n * (2 ^ n * 4 ^ A)) * n ^ n := by + ring + _ ≤ (n * (2 ^ n * 4 ^ E)) * n ^ n := by + exact Nat.mul_le_mul_right _ + (Nat.mul_le_mul_left n (Nat.mul_le_mul_left (2 ^ n) hA4)) + have hright_lt : (n * (2 ^ n * 4 ^ E)) * n ^ n < B ^ n * n ^ n := + Nat.mul_lt_mul_of_pos_right hbase (pow_pos hnpos n) + have hBN_le : (B * n) ^ n ≤ N ^ n := Nat.pow_le_pow_left hNlo.le n + have hBN : (B * n) ^ n = B ^ n * n ^ n := by rw [Nat.mul_pow] + exact hleft_le.trans_lt (hright_lt.trans_le (by simpa [hBN] using hBN_le)) + +private lemma cancelled_bound_of_base_pow_exponent_cap_le {n N B A E : ℕ} + (hnpos : 0 < n) (hNlo : B * n ≤ N) (hA : A ≤ E) + (hbase : n * (2 ^ n * 4 ^ E) < B ^ n) : + n * (2 ^ n * (n ^ n * 4 ^ A)) < N ^ n := by + have hA4 : 4 ^ A ≤ 4 ^ E := Nat.pow_le_pow_right (by norm_num : 0 < 4) hA + have hleft_le : + n * (2 ^ n * (n ^ n * 4 ^ A)) ≤ (n * (2 ^ n * 4 ^ E)) * n ^ n := by + calc + n * (2 ^ n * (n ^ n * 4 ^ A)) = (n * (2 ^ n * 4 ^ A)) * n ^ n := by + ring + _ ≤ (n * (2 ^ n * 4 ^ E)) * n ^ n := by + exact Nat.mul_le_mul_right _ + (Nat.mul_le_mul_left n (Nat.mul_le_mul_left (2 ^ n) hA4)) + have hright_lt : (n * (2 ^ n * 4 ^ E)) * n ^ n < B ^ n * n ^ n := + Nat.mul_lt_mul_of_pos_right hbase (pow_pos hnpos n) + have hBN_le : (B * n) ^ n ≤ N ^ n := Nat.pow_le_pow_left hNlo n + have hBN : (B * n) ^ n = B ^ n * n ^ n := by rw [Nat.mul_pow] + exact hleft_le.trans_lt (hright_lt.trans_le (by simpa [hBN] using hBN_le)) + +private lemma base_two_pow_exp {b D E n : ℕ} (hn_self : n ≤ 2 ^ D) + (hExp : D + n + 2 * E < b * n) : + n * (2 ^ n * 4 ^ E) < (2 ^ b) ^ n := by + have hleft : + n * (2 ^ n * 4 ^ E) ≤ 2 ^ D * (2 ^ n * 4 ^ E) := + Nat.mul_le_mul_right _ hn_self + have hpow : 2 ^ D * (2 ^ n * 4 ^ E) = 2 ^ (D + n + 2 * E) := by + rw [four_pow_eq_two_pow_two_mul E] + rw [← pow_add, ← pow_add] + congr 1 + ring + have hlt : 2 ^ (D + n + 2 * E) < 2 ^ (b * n) := + Nat.pow_lt_pow_right (by norm_num : 1 < 2) hExp + have hrhs : 2 ^ (b * n) = (2 ^ b) ^ n := by rw [pow_mul] + exact hleft.trans_lt (by simpa [hpow, hrhs] using hlt) + +private lemma self_le_two_pow_two_mul_div_one_twenty_eight_add_one {n : ℕ} + (hn : 512 ≤ n) : + n ≤ 2 ^ (2 * (n / 128 + 1)) := by + have hself := self_le_four_pow_div_one_twenty_eight_add_one hn + have hpow : 4 ^ (n / 128 + 1) = 2 ^ (2 * (n / 128 + 1)) := + four_pow_eq_two_pow_two_mul (n / 128 + 1) + rwa [hpow] at hself + +private lemma range_3_base_exp {n : ℕ} (hn : 945 ≤ n) : + n * (2 ^ n * 4 ^ (4 * n / 15)) < 3 ^ n := by + let D := 2 * (n / 128 + 1) + have hn_self : n ≤ 2 ^ D := by + dsimp [D] + exact self_le_two_pow_two_mul_div_one_twenty_eight_add_one (by omega : 512 ≤ n) + have hleft : + n * (2 ^ n * 4 ^ (4 * n / 15)) ≤ 2 ^ D * (2 ^ n * 4 ^ (4 * n / 15)) := + Nat.mul_le_mul_right _ hn_self + have hpow : 2 ^ D * (2 ^ n * 4 ^ (4 * n / 15)) = + 2 ^ (D + n + 2 * (4 * n / 15)) := by + rw [four_pow_eq_two_pow_two_mul (4 * n / 15)] + rw [← pow_add, ← pow_add] + congr 1 + ring + have hexp : D + n + 2 * (4 * n / 15) < 19 * (n / 12) := by + dsimp [D] + omega + have hlt : 2 ^ (D + n + 2 * (4 * n / 15)) < 2 ^ (19 * (n / 12)) := + Nat.pow_lt_pow_right (by norm_num : 1 < 2) hexp + exact hleft.trans_lt (by + rw [hpow] + exact hlt.trans_le (two_pow_nineteen_mul_div_twelve_le_three_pow n)) + +private lemma range_4_base_exp {n : ℕ} (hn : 945 ≤ n) : + n * (2 ^ n * 4 ^ (2 * n / 5)) < 4 ^ n := by + simpa using + base_two_pow_exp (b := 2) (D := 2 * (n / 128 + 1)) (E := 2 * n / 5) + (self_le_two_pow_two_mul_div_one_twenty_eight_add_one (by omega : 512 ≤ n)) + (by omega) + +private lemma range_8_base_exp {n : ℕ} (hn : 945 ≤ n) : + n * (2 ^ n * 4 ^ (3 * n / 4)) < 8 ^ n := by + simpa using + base_two_pow_exp (b := 3) (D := 2 * (n / 128 + 1)) (E := 3 * n / 4) + (self_le_two_pow_two_mul_div_one_twenty_eight_add_one (by omega : 512 ≤ n)) + (by omega) + +private lemma range_16_base_exp {n : ℕ} (hn : 945 ≤ n) : + n * (2 ^ n * 4 ^ n) < 16 ^ n := by + simpa using + base_two_pow_exp (b := 4) (D := 2 * (n / 128 + 1)) (E := n) + (self_le_two_pow_two_mul_div_one_twenty_eight_add_one (by omega : 512 ≤ n)) + (by omega) + +private lemma range_64_base_exp {n : ℕ} (hn : 945 ≤ n) : + n * (2 ^ n * 4 ^ (9 * n / 4)) < 64 ^ n := by + simpa using + base_two_pow_exp (b := 6) (D := 2 * (n / 128 + 1)) (E := 9 * n / 4) + (self_le_two_pow_two_mul_div_one_twenty_eight_add_one (by omega : 512 ≤ n)) + (by omega) + +private lemma range_512_base_exp (n : ℕ) : + n * (2 ^ n * 4 ^ (3 * n)) < 512 ^ n := by + have hn4 : n < 4 ^ n := + Nat.lt_of_lt_of_le Nat.lt_two_pow_self (Nat.pow_le_pow_left (by norm_num : 2 ≤ 4) n) + have h4 : 4 ^ n = 2 ^ (2 * n) := + four_pow_eq_two_pow_two_mul n + have h43 : 4 ^ (3 * n) = 2 ^ (2 * (3 * n)) := + four_pow_eq_two_pow_two_mul (3 * n) + have h512 : 512 ^ n = 2 ^ (9 * n) := by + rw [show 512 = 2 ^ 9 by norm_num, ← pow_mul] + calc + n * (2 ^ n * 4 ^ (3 * n)) + < 4 ^ n * (2 ^ n * 4 ^ (3 * n)) := + Nat.mul_lt_mul_of_pos_right hn4 (by positivity) + _ = 512 ^ n := by + rw [h4, h43, h512] + rw [← pow_add, ← pow_add] + congr 1 + ring + + +private lemma sqrt_le_self_of_le_sq_add_self {n N : ℕ} (hNhi : N ≤ n ^ 2 + n) : + Nat.sqrt N ≤ n := by + calc + Nat.sqrt N ≤ Nat.sqrt (n ^ 2 + n) := Nat.sqrt_le_sqrt hNhi + _ = n := Nat.sqrt_add_eq' n (by omega) + +private lemma pow_six_step_of_ten_le {s : ℕ} (hs : 10 ≤ s) : + (s + 2) ^ 6 ≤ 4 * (s + 1) ^ 6 := by + have hcube : (s + 2) ^ 3 ≤ 2 * (s + 1) ^ 3 := by + nlinarith [hs, sq_nonneg (s : ℤ)] + have hsquare := Nat.pow_le_pow_left hcube 2 + calc + (s + 2) ^ 6 = ((s + 2) ^ 3) ^ 2 := by ring + _ ≤ (2 * (s + 1) ^ 3) ^ 2 := hsquare + _ = 4 * (s + 1) ^ 6 := by ring + +private lemma sqrt_succ_pow_six_le_two_pow_two_mul_add_one {s : ℕ} (hs : 10 ≤ s) : + (s + 1) ^ 6 ≤ 2 ^ (2 * s + 1) := by + induction s, hs using Nat.le_induction with + | base => norm_num + | succ s hs ih => + calc + (s + 1 + 1) ^ 6 = (s + 2) ^ 6 := by ring + _ ≤ 4 * (s + 1) ^ 6 := pow_six_step_of_ten_le hs + _ ≤ 4 * 2 ^ (2 * s + 1) := Nat.mul_le_mul_left 4 ih + _ = 2 ^ (2 * (s + 1) + 1) := by + rw [show 4 = 2 ^ 2 by norm_num, ← pow_add] + congr 1 + ring + +private lemma log_two_le_two_mul_sqrt_nthRoot_three {N : ℕ} + (hc : 100 ≤ Nat.nthRoot 3 N) : + Nat.log 2 N ≤ 2 * Nat.sqrt (Nat.nthRoot 3 N) := by + let c := Nat.nthRoot 3 N + let s := Nat.sqrt c + have hs10 : 10 ≤ s := by + dsimp [s] + rw [Nat.le_sqrt] + omega + have hNlt : N < (c + 1) ^ 3 := by + dsimp [c] + exact (Nat.nthRoot_lt_iff (by norm_num : 3 ≠ 0)).mp (Nat.lt_succ_self _) + have hc_succ : c + 1 ≤ (s + 1) ^ 2 := by + dsimp [s] + exact Nat.succ_le_succ_sqrt' c + have hcube : (c + 1) ^ 3 ≤ (s + 1) ^ 6 := by + calc + (c + 1) ^ 3 ≤ ((s + 1) ^ 2) ^ 3 := Nat.pow_le_pow_left hc_succ 3 + _ = (s + 1) ^ 6 := by ring + have hpow : (c + 1) ^ 3 ≤ 2 ^ (2 * s + 1) := + hcube.trans (sqrt_succ_pow_six_le_two_pow_two_mul_add_one hs10) + have hloglt : Nat.log 2 N < 2 * s + 1 := + Nat.log_lt_of_lt_pow' (by omega) (hNlt.trans_le hpow) + dsimp [c, s] at hloglt ⊢ + omega + +private lemma nthRoot_three_mul_log_le_of_nthRoot_lt {N A e M : ℕ} + (hroot : Nat.nthRoot 3 N < A) (hpow : A ^ 3 ≤ 2 ^ e) (he : e ≠ 0) + (hbound : (A - 1) * (e - 1) ≤ M) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ M := by + have hNlt : N < A ^ 3 := by + exact (Nat.nthRoot_lt_iff (by norm_num : 3 ≠ 0)).mp hroot + have hloglt : Nat.log 2 N < e := + Nat.log_lt_of_lt_pow' he (hNlt.trans_le hpow) + have hroot_le : Nat.nthRoot 3 N ≤ A - 1 := by omega + have hlog_le : Nat.log 2 N ≤ e - 1 := by omega + exact (Nat.mul_le_mul hroot_le hlog_le).trans hbound + +private lemma nthRoot_three_mul_log_le_mul_pred_of_nthRoot_lt {N A e : ℕ} + (hroot : Nat.nthRoot 3 N < A) (hpow : A ^ 3 ≤ 2 ^ e) (he : e ≠ 0) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ Nat.nthRoot 3 N * (e - 1) := by + have hNlt : N < A ^ 3 := by + exact (Nat.nthRoot_lt_iff (by norm_num : 3 ≠ 0)).mp hroot + have hloglt : Nat.log 2 N < e := + Nat.log_lt_of_lt_pow' he (hNlt.trans_le hpow) + exact Nat.mul_le_mul_left _ (by omega) + +private lemma nthRoot_three_pow_le_of_le {N M : ℕ} (hNM : N ≤ M) : + (Nat.nthRoot 3 N) ^ 3 ≤ M := + (Nat.pow_nthRoot_le (Or.inl (by norm_num : 3 ≠ 0))).trans hNM + +private lemma first_residual_large_root_log_le_two_mul_self {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ n ^ 2 + n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 2 * n := by + let c := Nat.nthRoot 3 N + let s := Nat.sqrt c + have hc3n : c ^ 3 ≤ n ^ 2 + n := by + simpa [c] using nthRoot_three_pow_le_of_le hNhi + by_cases hc100lt : c < 100 + · simpa [c] using + nthRoot_three_mul_log_le_of_nthRoot_lt + (N := N) (A := 100) (e := 20) (M := 2 * n) + (by simpa [c] using hc100lt) (by norm_num) (by norm_num) (by omega) + · have hc100 : 100 ≤ c := by omega + have hlog : Nat.log 2 N ≤ 2 * s := by + dsimp [s, c] + exact log_two_le_two_mul_sqrt_nthRoot_three (N := N) (by simpa [c] using hc100) + have hs2 : s ^ 2 ≤ c := by + dsimp [s] + exact Nat.sqrt_le' c + have hcs_sq : (c * s) ^ 2 ≤ n ^ 2 + n := by + calc + (c * s) ^ 2 = c ^ 2 * s ^ 2 := by ring + _ ≤ c ^ 2 * c := Nat.mul_le_mul_left (c ^ 2) hs2 + _ = c ^ 3 := by ring + _ ≤ n ^ 2 + n := hc3n + have hcsn : c * s ≤ n := by + simpa [Nat.sqrt_eq'] using + sqrt_le_self_of_le_sq_add_self (n := n) (N := (c * s) ^ 2) hcs_sq + calc + c * Nat.log 2 N ≤ c * (2 * s) := Nat.mul_le_mul_left c hlog + _ = 2 * (c * s) := by ring + _ ≤ 2 * n := Nat.mul_le_mul_left 2 hcsn + +private lemma first_residual_large_exponent_le_three_mul_self {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ n ^ 2 + n) : + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n := by + have hsqrt : Nat.sqrt N ≤ n := sqrt_le_self_of_le_sq_add_self hNhi + have hroot_log : Nat.nthRoot 3 N * Nat.log 2 N ≤ 2 * n := + first_residual_large_root_log_le_two_mul_self hn hNhi + omega + +private lemma sqrt_le_div_of_sq_mul_le {a B n N : ℕ} (ha : 0 < a) + (hpoly : a ^ 2 * (B * n) ≤ n ^ 2) (hNhi : N ≤ B * n) : + Nat.sqrt N ≤ n / a := by + let s := Nat.sqrt N + have hs2 : s ^ 2 ≤ N := by + dsimp [s] + simpa [pow_two] using Nat.sqrt_le N + have hsq : (a * s) ^ 2 ≤ n ^ 2 := by + calc + (a * s) ^ 2 = a ^ 2 * s ^ 2 := by ring + _ ≤ a ^ 2 * N := Nat.mul_le_mul_left (a ^ 2) hs2 + _ ≤ a ^ 2 * (B * n) := Nat.mul_le_mul_left (a ^ 2) hNhi + _ ≤ n ^ 2 := hpoly + have hle : a * s ≤ n := + (Nat.pow_le_pow_iff_left (by norm_num : 2 ≠ 0)).mp hsq + rw [Nat.le_div_iff_mul_le ha] + simpa [s, Nat.mul_comm] using hle + +/-- If `N ≤ 4 * n` and `n` is large enough, then `sqrt N` is at most `n / 15`. -/ +lemma sqrt_le_div_fifteen_of_le_four_mul {n N : ℕ} (hn : 900 ≤ n) + (hNhi : N ≤ 4 * n) : + Nat.sqrt N ≤ n / 15 := by + exact sqrt_le_div_of_sq_mul_le (a := 15) (B := 4) (by norm_num) + (by nlinarith [hn]) hNhi + +private lemma const_log_product_le_one_fifth_of_le_four_mul {c n m : ℕ} + (hquad : 20 * m ≤ c ^ 2) (hc3n : c ^ 3 ≤ 4 * n) : + c * m ≤ n / 5 := by + rw [Nat.le_div_iff_mul_le (by norm_num : 0 < 5)] + apply Nat.le_of_mul_le_mul_left (c := 4) + · have hcubic : (20 * m) * c ≤ c ^ 3 := by + calc + (20 * m) * c ≤ c ^ 2 * c := Nat.mul_le_mul_right c hquad + _ = c ^ 3 := by ring + calc + 4 * (c * m * 5) = (20 * m) * c := by ring + _ ≤ c ^ 3 := hcubic + _ ≤ 4 * n := hc3n + · norm_num + +private lemma nthRoot_three_mul_log_le_one_fifth_of_lt {n N A e m : ℕ} + (hroot : Nat.nthRoot 3 N < A) (hpow : A ^ 3 ≤ 2 ^ e) (he : e ≠ 0) + (hpred : e - 1 ≤ m) + (hquad : 20 * m ≤ (Nat.nthRoot 3 N) ^ 2) + (hc3n : (Nat.nthRoot 3 N) ^ 3 ≤ 4 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ n / 5 := by + have hlog := + nthRoot_three_mul_log_le_mul_pred_of_nthRoot_lt hroot hpow he + exact hlog.trans <| (Nat.mul_le_mul_left _ hpred).trans <| + const_log_product_le_one_fifth_of_le_four_mul hquad hc3n + +private lemma nthRoot_three_mul_log_le_one_fifth_of_nthRoot_ge + {n N : ℕ} (hroot : 100 ≤ Nat.nthRoot 3 N) + (hc3n : (Nat.nthRoot 3 N) ^ 3 ≤ 4 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ n / 5 := by + let c := Nat.nthRoot 3 N + let s := Nat.sqrt c + have hlog : Nat.log 2 N ≤ 2 * s := by + dsimp [s, c] + exact log_two_le_two_mul_sqrt_nthRoot_three (N := N) (by simpa [c] using hroot) + have hs_le_c : s ≤ c := by + dsimp [s] + exact Nat.sqrt_le_self c + have h40 : 40 * s ≤ c ^ 2 := by + calc + 40 * s ≤ c * s := Nat.mul_le_mul_right s (by omega) + _ ≤ c * c := Nat.mul_le_mul_left c hs_le_c + _ = c ^ 2 := by ring + have h10cs : 10 * (c * s) ≤ n := by + apply Nat.le_of_mul_le_mul_left (c := 4) + · calc + 4 * (10 * (c * s)) = (40 * s) * c := by ring + _ ≤ c ^ 2 * c := Nat.mul_le_mul_right c h40 + _ = c ^ 3 := by ring + _ ≤ 4 * n := by simpa [c] using hc3n + · norm_num + have htarget : c * (2 * s) ≤ n / 5 := by + rw [Nat.le_div_iff_mul_le (by norm_num : 0 < 5)] + calc + c * (2 * s) * 5 = 10 * (c * s) := by ring + _ ≤ n := h10cs + calc + c * Nat.log 2 N ≤ c * (2 * s) := Nat.mul_le_mul_left c hlog + _ ≤ n / 5 := htarget + +private lemma nthRoot_three_mul_log_le_one_fifth_of_ge_sixteen + {n N : ℕ} (hroot16 : 16 ≤ Nat.nthRoot 3 N) + (hc3n : (Nat.nthRoot 3 N) ^ 3 ≤ 4 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ n / 5 := by + let c := Nat.nthRoot 3 N + have hc16 : 16 ≤ c := by simpa [c] using hroot16 + by_cases hc20lt : c < 20 + · simpa [c] using + nthRoot_three_mul_log_le_one_fifth_of_lt + (N := N) (A := 20) (e := 13) (m := 12) + (by simpa [c] using hc20lt) (by norm_num) (by norm_num) (by omega) + (by nlinarith [hc16]) (by simpa [c] using hc3n) + by_cases hc32lt : c < 32 + · simpa [c] using + nthRoot_three_mul_log_le_one_fifth_of_lt + (N := N) (A := 32) (e := 15) (m := 14) + (by simpa [c] using hc32lt) (by norm_num) (by norm_num) (by omega) + (by nlinarith [Nat.le_of_not_gt hc20lt]) (by simpa [c] using hc3n) + by_cases hc64lt : c < 64 + · simpa [c] using + nthRoot_three_mul_log_le_one_fifth_of_lt + (N := N) (A := 64) (e := 18) (m := 17) + (by simpa [c] using hc64lt) (by norm_num) (by norm_num) (by omega) + (by nlinarith [Nat.le_of_not_gt hc32lt]) (by simpa [c] using hc3n) + by_cases hc100lt : c < 100 + · simpa [c] using + nthRoot_three_mul_log_le_one_fifth_of_lt + (N := N) (A := 100) (e := 20) (m := 19) + (by simpa [c] using hc100lt) (by norm_num) (by norm_num) (by omega) + (by nlinarith [Nat.le_of_not_gt hc64lt]) (by simpa [c] using hc3n) + have hc100 : 100 ≤ c := by omega + simpa [c] using + nthRoot_three_mul_log_le_one_fifth_of_nthRoot_ge + (N := N) (n := n) (by simpa [c] using hc100) (by simpa [c] using hc3n) + +/-- In the range `N ≤ 4 * n`, the `Nat.nthRoot 3 N * Nat.log 2 N` contribution is at +most `n / 5`. -/ +lemma nthRoot_three_mul_log_le_one_fifth_of_le_four_mul {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ 4 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ n / 5 := by + let c := Nat.nthRoot 3 N + have hc3n : c ^ 3 ≤ 4 * n := by + simpa [c] using nthRoot_three_pow_le_of_le hNhi + by_cases hc16lt : c < 16 + · simpa [c] using + nthRoot_three_mul_log_le_of_nthRoot_lt + (N := N) (A := 16) (e := 12) (M := n / 5) + (by simpa [c] using hc16lt) (by norm_num) (by norm_num) (by omega) + exact nthRoot_three_mul_log_le_one_fifth_of_ge_sixteen + (by simpa [c] using Nat.le_of_not_gt hc16lt) (by simpa [c] using hc3n) + +private lemma first_residual_large_exponent_le_four_fifteenths {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ 4 * n) : + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N ≤ 4 * n / 15 := by + have hsqrt : Nat.sqrt N ≤ n / 15 := + sqrt_le_div_fifteen_of_le_four_mul (by omega : 900 ≤ n) hNhi + have hroot_log : Nat.nthRoot 3 N * Nat.log 2 N ≤ n / 5 := + nthRoot_three_mul_log_le_one_fifth_of_le_four_mul hn hNhi + omega + + +private lemma sqrt_le_div_ten_of_le_eight_mul {n N : ℕ} (hn : 800 ≤ n) + (hNhi : N ≤ 8 * n) : + Nat.sqrt N ≤ n / 10 := by + exact sqrt_le_div_of_sq_mul_le (a := 10) (B := 8) (by norm_num) + (by nlinarith [hn]) hNhi + +private lemma cube_succ_le_two_pow_three_mul_div_four_add_one {c : ℕ} (hc : 15 ≤ c) : + (c + 1) ^ 3 ≤ 2 ^ (3 * c / 4 + 1) := by + induction c using Nat.strong_induction_on with + | h c ih => + by_cases hsmall : c < 19 + · interval_cases c <;> norm_num + · have hc19 : 19 ≤ c := by omega + have hprev15 : 15 ≤ c - 4 := by omega + have hprev := ih (c - 4) (by omega) hprev15 + have hpoly : (c + 1) ^ 3 ≤ 8 * ((c - 4) + 1) ^ 3 := by + have hsub : (c - 4) + 1 = c - 3 := by omega + calc + (c + 1) ^ 3 ≤ (2 * (c - 3)) ^ 3 := Nat.pow_le_pow_left (by omega) 3 + _ = 8 * (c - 3) ^ 3 := by ring + _ = 8 * ((c - 4) + 1) ^ 3 := by rw [hsub] + have hpow : 8 * 2 ^ (3 * (c - 4) / 4 + 1) = 2 ^ (3 * c / 4 + 1) := by + have hdiv : 3 * c / 4 = 3 * (c - 4) / 4 + 3 := by omega + rw [hdiv, show 8 = 2 ^ 3 by norm_num, ← pow_add] + congr 1 + ring + exact hpoly.trans (by simpa [hpow] using Nat.mul_le_mul_left 8 hprev) + +private lemma log_two_le_three_mul_nthRoot_three_div_four {N : ℕ} + (hc : 15 ≤ Nat.nthRoot 3 N) : + Nat.log 2 N ≤ 3 * Nat.nthRoot 3 N / 4 := by + let c := Nat.nthRoot 3 N + have hNlt : N < (c + 1) ^ 3 := by + dsimp [c] + exact (Nat.nthRoot_lt_iff (by norm_num : 3 ≠ 0)).mp (Nat.lt_succ_self _) + have hcube : (c + 1) ^ 3 ≤ 2 ^ (3 * c / 4 + 1) := + cube_succ_le_two_pow_three_mul_div_four_add_one (by simpa [c] using hc) + have hloglt : Nat.log 2 N < 3 * c / 4 + 1 := + Nat.log_lt_of_lt_pow' (by omega) (hNlt.trans_le hcube) + dsimp [c] at hloglt ⊢ + omega + +private lemma mul_three_mul_div_four_le_mul_div_of_scaled_sq {a b c n : ℕ} + (hb : 0 < b) (hsq : 3 * b * c ^ 2 ≤ 4 * (a * n)) : + c * (3 * c / 4) ≤ a * n / b := by + have hdivmul : 4 * (3 * c / 4) ≤ 3 * c := by + simpa [Nat.mul_comm, Nat.mul_left_comm, Nat.mul_assoc] using + Nat.div_mul_le_self (3 * c) 4 + rw [Nat.le_div_iff_mul_le hb] + apply Nat.le_of_mul_le_mul_left (c := 4) + · calc + 4 * (c * (3 * c / 4) * b) = b * c * (4 * (3 * c / 4)) := by ring + _ ≤ b * c * (3 * c) := Nat.mul_le_mul_left (b * c) hdivmul + _ = 3 * b * c ^ 2 := by ring + _ ≤ 4 * (a * n) := hsq + · norm_num + +private lemma nthRoot_three_mul_log_le_mul_div_of_scaled_sq {a b n N : ℕ} + (hroot : 15 ≤ Nat.nthRoot 3 N) (hb : 0 < b) + (hsq : 3 * b * (Nat.nthRoot 3 N) ^ 2 ≤ 4 * (a * n)) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ a * n / b := by + let c := Nat.nthRoot 3 N + have hlog : Nat.log 2 N ≤ 3 * c / 4 := by + dsimp [c] + exact log_two_le_three_mul_nthRoot_three_div_four (N := N) (by simpa [c] using hroot) + calc + c * Nat.log 2 N ≤ c * (3 * c / 4) := Nat.mul_le_mul_left c hlog + _ ≤ a * n / b := mul_three_mul_div_four_le_mul_div_of_scaled_sq + (a := a) (b := b) hb (by simpa [c] using hsq) + +private lemma first_residual_large_root_log_le_three_tenths_of_le_eight_mul {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ 8 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 10 := by + let c := Nat.nthRoot 3 N + by_cases hc20 : c < 20 + · simpa [c] using + nthRoot_three_mul_log_le_of_nthRoot_lt + (N := N) (A := 20) (e := 13) (M := 3 * n / 10) + (by simpa [c] using hc20) (by norm_num) (by norm_num) (by omega) + · have hc20le : 20 ≤ c := by omega + have hc15 : 15 ≤ c := by omega + have hc3n : c ^ 3 ≤ 8 * n := by + simpa [c] using nthRoot_three_pow_le_of_le hNhi + have h5 : 5 * c ^ 2 ≤ 2 * n := by + nlinarith [hc20le, hc3n] + simpa [c] using + nthRoot_three_mul_log_le_mul_div_of_scaled_sq (a := 3) (b := 10) (n := n) + (N := N) (by simpa [c] using hc15) (by norm_num) (by nlinarith [h5]) + +private lemma first_residual_large_exponent_le_two_fifths {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ 8 * n) : + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N ≤ 2 * n / 5 := by + have hsqrt : Nat.sqrt N ≤ n / 10 := + sqrt_le_div_ten_of_le_eight_mul (by omega : 800 ≤ n) hNhi + have hroot_log : Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 10 := + first_residual_large_root_log_le_three_tenths_of_le_eight_mul hn hNhi + omega + + +private lemma sqrt_le_div_seven_of_le_sixteen_mul {n N : ℕ} (hn : 784 ≤ n) + (hNhi : N ≤ 16 * n) : + Nat.sqrt N ≤ n / 7 := by + exact sqrt_le_div_of_sq_mul_le (a := 7) (B := 16) (by norm_num) + (by nlinarith [hn]) hNhi + +private lemma first_residual_large_root_log_le_three_fifths_of_le_sixteen_mul {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ 16 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 5 := by + let c := Nat.nthRoot 3 N + by_cases hc20 : c < 20 + · simpa [c] using + nthRoot_three_mul_log_le_of_nthRoot_lt + (N := N) (A := 20) (e := 13) (M := 3 * n / 5) + (by simpa [c] using hc20) (by norm_num) (by norm_num) (by omega) + · have hc20le : 20 ≤ c := by omega + have hc15 : 15 ≤ c := by omega + have hc3n : c ^ 3 ≤ 16 * n := by + simpa [c] using nthRoot_three_pow_le_of_le hNhi + have h5 : 5 * c ^ 2 ≤ 4 * n := by + nlinarith [hc20le, hc3n] + simpa [c] using + nthRoot_three_mul_log_le_mul_div_of_scaled_sq (a := 3) (b := 5) (n := n) + (N := N) (by simpa [c] using hc15) (by norm_num) (by nlinarith [h5]) + +private lemma first_residual_large_exponent_le_three_fourths {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ 16 * n) : + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 4 := by + have hsqrt : Nat.sqrt N ≤ n / 7 := + sqrt_le_div_seven_of_le_sixteen_mul (by omega : 784 ≤ n) hNhi + have hroot_log : Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 5 := + first_residual_large_root_log_le_three_fifths_of_le_sixteen_mul hn hNhi + omega + + +private lemma sqrt_le_div_three_of_le_sixty_four_mul {n N : ℕ} (hn : 576 ≤ n) + (hNhi : N ≤ 64 * n) : + Nat.sqrt N ≤ n / 3 := by + exact sqrt_le_div_of_sq_mul_le (a := 3) (B := 64) (by norm_num) + (by nlinarith [hn]) hNhi + +private lemma const_log_product_le_two_thirds_of_le_sixty_four_mul {c n m : ℕ} + (hquad : 96 * m ≤ c ^ 2) (hc3n : c ^ 3 ≤ 64 * n) : + c * m ≤ 2 * n / 3 := by + rw [Nat.le_div_iff_mul_le (by norm_num : 0 < 3)] + apply Nat.le_of_mul_le_mul_left (c := 32) + · have hcubic : (96 * m) * c ≤ c ^ 3 := by + calc + (96 * m) * c ≤ c ^ 2 * c := Nat.mul_le_mul_right c hquad + _ = c ^ 3 := by ring + calc + 32 * (c * m * 3) = (96 * m) * c := by ring + _ ≤ c ^ 3 := hcubic + _ ≤ 64 * n := hc3n + _ = 32 * (2 * n) := by ring + · norm_num + +private lemma nthRoot_three_mul_log_le_two_thirds_of_lt {n N A e m : ℕ} + (hroot : Nat.nthRoot 3 N < A) (hpow : A ^ 3 ≤ 2 ^ e) (he : e ≠ 0) + (hpred : e - 1 ≤ m) + (hquad : 96 * m ≤ (Nat.nthRoot 3 N) ^ 2) + (hc3n : (Nat.nthRoot 3 N) ^ 3 ≤ 64 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 2 * n / 3 := by + have hlog := + nthRoot_three_mul_log_le_mul_pred_of_nthRoot_lt hroot hpow he + exact hlog.trans <| (Nat.mul_le_mul_left _ hpred).trans <| + const_log_product_le_two_thirds_of_le_sixty_four_mul hquad hc3n + +private lemma nthRoot_three_mul_log_le_two_thirds_of_nthRoot_ge + {n N : ℕ} (hroot : 72 ≤ Nat.nthRoot 3 N) + (hc3n : (Nat.nthRoot 3 N) ^ 3 ≤ 64 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 2 * n / 3 := by + let c := Nat.nthRoot 3 N + have hroot_c : 72 ≤ c := by + dsimp [c] + exact hroot + have hc15 : 15 ≤ c := by omega + have hsquare : 9 * c ^ 2 ≤ 8 * n := by + apply Nat.le_of_mul_le_mul_left (c := 8) + · have hc_sq : 72 * c ^ 2 ≤ c ^ 3 := by + calc + 72 * c ^ 2 ≤ c * c ^ 2 := + Nat.mul_le_mul_right (c ^ 2) hroot_c + _ = c ^ 3 := by ring + calc + 8 * (9 * c ^ 2) = 72 * c ^ 2 := by ring + _ ≤ c ^ 3 := hc_sq + _ ≤ 64 * n := by simpa [c] using hc3n + _ = 8 * (8 * n) := by ring + · norm_num + simpa [c] using + nthRoot_three_mul_log_le_mul_div_of_scaled_sq (a := 2) (b := 3) (n := n) + (N := N) (by simpa [c] using hc15) (by norm_num) (by nlinarith [hsquare]) + +private lemma first_residual_large_root_log_le_two_thirds_of_le_sixty_four_mul {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ 64 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 2 * n / 3 := by + let c := Nat.nthRoot 3 N + have hc3n : c ^ 3 ≤ 64 * n := by + simpa [c] using nthRoot_three_pow_le_of_le hNhi + by_cases hc40lt : c < 40 + · simpa [c] using + nthRoot_three_mul_log_le_of_nthRoot_lt + (N := N) (A := 40) (e := 16) (M := 2 * n / 3) + (by simpa [c] using hc40lt) (by norm_num) (by norm_num) (by omega) + by_cases hc42lt : c < 42 + · simpa [c] using + nthRoot_three_mul_log_le_two_thirds_of_lt + (N := N) (A := 42) (e := 17) (m := 16) + (by simpa [c] using hc42lt) (by norm_num) (by norm_num) (by omega) + (by nlinarith [Nat.le_of_not_gt hc40lt]) (by simpa [c] using hc3n) + by_cases hc72lt : c < 72 + · simpa [c] using + nthRoot_three_mul_log_le_two_thirds_of_lt + (N := N) (A := 72) (e := 19) (m := 18) + (by simpa [c] using hc72lt) (by norm_num) (by norm_num) (by omega) + (by nlinarith [Nat.le_of_not_gt hc42lt]) (by simpa [c] using hc3n) + · have hc72 : 72 ≤ c := by omega + simpa [c] using + nthRoot_three_mul_log_le_two_thirds_of_nthRoot_ge + (N := N) (n := n) (by simpa [c] using hc72) (by simpa [c] using hc3n) + +private lemma first_residual_large_exponent_le_self {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ 64 * n) : + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N ≤ n := by + have hsqrt : Nat.sqrt N ≤ n / 3 := + sqrt_le_div_three_of_le_sixty_four_mul (by omega : 576 ≤ n) hNhi + have hroot_log : Nat.nthRoot 3 N * Nat.log 2 N ≤ 2 * n / 3 := + first_residual_large_root_log_le_two_thirds_of_le_sixty_four_mul hn hNhi + omega + + +private lemma sqrt_le_three_mul_div_four_of_le_five_twelve_mul {n N : ℕ} (hn : 911 ≤ n) + (hNhi : N ≤ 512 * n) : + Nat.sqrt N ≤ 3 * n / 4 := by + let s := Nat.sqrt N + have hs2 : s ^ 2 ≤ N := by + dsimp [s] + simpa [pow_two] using Nat.sqrt_le N + have hpoly : 16 * (512 * n) ≤ (3 * n) ^ 2 := by nlinarith [hn] + have hsq : (4 * s) ^ 2 ≤ (3 * n) ^ 2 := by + calc + (4 * s) ^ 2 = 16 * s ^ 2 := by ring + _ ≤ 16 * N := Nat.mul_le_mul_left 16 hs2 + _ ≤ 16 * (512 * n) := Nat.mul_le_mul_left 16 hNhi + _ ≤ (3 * n) ^ 2 := hpoly + have h4 : 4 * s ≤ 3 * n := by + exact (Nat.pow_le_pow_iff_left (by norm_num : 2 ≠ 0)).mp hsq + rw [Nat.le_div_iff_mul_le (by norm_num : 0 < 4)] + simpa [s, Nat.mul_comm] using h4 + +private lemma const_log_product_le_three_halves {c n m : ℕ} + (hquad : 1024 * m ≤ 3 * c ^ 2) (hc3n : c ^ 3 ≤ 512 * n) : + c * m ≤ 3 * n / 2 := by + rw [Nat.le_div_iff_mul_le (by norm_num : 0 < 2)] + apply Nat.le_of_mul_le_mul_left (c := 512) + · have hcubic : (1024 * m) * c ≤ 3 * c ^ 3 := by + calc + (1024 * m) * c ≤ (3 * c ^ 2) * c := Nat.mul_le_mul_right c hquad + _ = 3 * c ^ 3 := by ring + calc + 512 * (c * m * 2) = (1024 * m) * c := by ring + _ ≤ 3 * c ^ 3 := hcubic + _ ≤ 3 * (512 * n) := Nat.mul_le_mul_left 3 hc3n + _ = 512 * (3 * n) := by ring + · norm_num + +private lemma nthRoot_three_mul_log_le_three_halves_of_lt {n N A e m : ℕ} + (hroot : Nat.nthRoot 3 N < A) (hpow : A ^ 3 ≤ 2 ^ e) (he : e ≠ 0) + (hpred : e - 1 ≤ m) + (hquad : 1024 * m ≤ 3 * (Nat.nthRoot 3 N) ^ 2) + (hc3n : (Nat.nthRoot 3 N) ^ 3 ≤ 512 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 2 := by + have hlog := + nthRoot_three_mul_log_le_mul_pred_of_nthRoot_lt hroot hpow he + exact hlog.trans <| (Nat.mul_le_mul_left _ hpred).trans <| + const_log_product_le_three_halves hquad hc3n + +private lemma nthRoot_three_sq_le_two_mul_of_ge_two_fifty_six + {n N : ℕ} (hroot : 256 ≤ Nat.nthRoot 3 N) + (hc3n : (Nat.nthRoot 3 N) ^ 3 ≤ 512 * n) : + (Nat.nthRoot 3 N) ^ 2 ≤ 2 * n := by + let c := Nat.nthRoot 3 N + apply Nat.le_of_mul_le_mul_left (c := 256) + · have hc_sq : 256 * c ^ 2 ≤ c ^ 3 := by + calc + 256 * c ^ 2 ≤ c * c ^ 2 := Nat.mul_le_mul_right (c ^ 2) (by simpa [c] using hroot) + _ = c ^ 3 := by ring + calc + 256 * c ^ 2 ≤ c ^ 3 := hc_sq + _ ≤ 512 * n := by simpa [c] using hc3n + _ = 256 * (2 * n) := by ring + · norm_num + +private lemma nthRoot_three_mul_log_le_three_halves_of_sq_le + {n N : ℕ} (hroot : 15 ≤ Nat.nthRoot 3 N) + (hsq : (Nat.nthRoot 3 N) ^ 2 ≤ 2 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 2 := by + exact nthRoot_three_mul_log_le_mul_div_of_scaled_sq (a := 3) (b := 2) (n := n) + (N := N) hroot (by norm_num) (by nlinarith [hsq]) + +private lemma nthRoot_three_mul_log_le_three_halves_of_lt_eighty_one + {n N : ℕ} (hroot79 : 79 ≤ Nat.nthRoot 3 N) + (hroot81 : Nat.nthRoot 3 N < 81) + (hc3n : (Nat.nthRoot 3 N) ^ 3 ≤ 512 * n) (hNhi : N ≤ 512 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 2 := by + let c := Nat.nthRoot 3 N + by_cases hNpow19 : N < 2 ^ 19 + · have hloglt : Nat.log 2 N < 19 := Nat.log_lt_of_lt_pow' (by norm_num) hNpow19 + have hLle : Nat.log 2 N ≤ 18 := by omega + have hprod : c * Nat.log 2 N ≤ c * 18 := Nat.mul_le_mul_left c hLle + have hc_bound : c * 18 ≤ 3 * n / 2 := + const_log_product_le_three_halves (c := c) (n := n) (m := 18) + (by nlinarith [hroot79]) (by simpa [c] using hc3n) + dsimp [c] at hprod ⊢ + exact hprod.trans hc_bound + · have hn1024 : 1024 ≤ n := by nlinarith [Nat.le_of_not_gt hNpow19, hNhi] + simpa [c] using + nthRoot_three_mul_log_le_of_nthRoot_lt + (N := N) (A := 81) (e := 20) (M := 3 * n / 2) + (by simpa [c] using hroot81) (by norm_num) (by norm_num) (by omega) + +private lemma nthRoot_three_mul_log_le_three_halves_of_ge_seventy_nine + {n N : ℕ} (hroot79 : 79 ≤ Nat.nthRoot 3 N) + (hc3n : (Nat.nthRoot 3 N) ^ 3 ≤ 512 * n) (hNhi : N ≤ 512 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 2 := by + let c := Nat.nthRoot 3 N + have hc79 : 79 ≤ c := by simpa [c] using hroot79 + by_cases hc81lt : c < 81 + · simpa [c] using + nthRoot_three_mul_log_le_three_halves_of_lt_eighty_one + (N := N) (n := n) (by simpa [c] using hc79) + (by simpa [c] using hc81lt) (by simpa [c] using hc3n) hNhi + by_cases hc91lt : c < 91 + · simpa [c] using + nthRoot_three_mul_log_le_three_halves_of_lt + (N := N) (A := 91) (e := 20) (m := 19) + (by simpa [c] using hc91lt) (by norm_num) (by norm_num) (by omega) + (by nlinarith [Nat.le_of_not_gt hc81lt]) (by simpa [c] using hc3n) + by_cases hc128lt : c < 128 + · simpa [c] using + nthRoot_three_mul_log_le_three_halves_of_lt + (N := N) (A := 128) (e := 21) (m := 20) + (by simpa [c] using hc128lt) (by norm_num) (by norm_num) (by omega) + (by nlinarith [Nat.le_of_not_gt hc91lt]) (by simpa [c] using hc3n) + by_cases hc256lt : c < 256 + · simpa [c] using + nthRoot_three_mul_log_le_three_halves_of_lt + (N := N) (A := 256) (e := 24) (m := 23) + (by simpa [c] using hc256lt) (by norm_num) (by norm_num) (by omega) + (by nlinarith [Nat.le_of_not_gt hc128lt]) (by simpa [c] using hc3n) + have hc256 : 256 ≤ c := by omega + simpa [c] using + nthRoot_three_mul_log_le_three_halves_of_sq_le + (N := N) (n := n) (by simpa [c] using (by omega : 15 ≤ c)) + (nthRoot_three_sq_le_two_mul_of_ge_two_fifty_six + (N := N) (n := n) (by simpa [c] using hc256) (by simpa [c] using hc3n)) + +private lemma first_residual_large_root_log_le_three_halves_of_le_five_twelve_mul + {n N : ℕ} (hn : 945 ≤ n) (hNhi : N ≤ 512 * n) : + Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 2 := by + let c := Nat.nthRoot 3 N + have hc3n : c ^ 3 ≤ 512 * n := by + simpa [c] using nthRoot_three_pow_le_of_le hNhi + by_cases hc79lt : c < 79 + · simpa [c] using + nthRoot_three_mul_log_le_of_nthRoot_lt + (N := N) (A := 79) (e := 19) (M := 3 * n / 2) + (by simpa [c] using hc79lt) (by norm_num) (by norm_num) (by omega) + exact nthRoot_three_mul_log_le_three_halves_of_ge_seventy_nine + (by simpa [c] using Nat.le_of_not_gt hc79lt) (by simpa [c] using hc3n) hNhi + +private lemma first_residual_large_exponent_le_nine_fourths {n N : ℕ} + (hn : 945 ≤ n) (hNhi : N ≤ 512 * n) : + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N ≤ 9 * n / 4 := by + have hsqrt : Nat.sqrt N ≤ 3 * n / 4 := + sqrt_le_three_mul_div_four_of_le_five_twelve_mul (by omega : 911 ≤ n) hNhi + have hroot_log : Nat.nthRoot 3 N * Nat.log 2 N ≤ 3 * n / 2 := + first_residual_large_root_log_le_three_halves_of_le_five_twelve_mul hn hNhi + omega + +/-! ### Range dispatch -/ + +private lemma first_residual_large_cancelled_bound_range_3_4 {n N : ℕ} + (hn : 945 ≤ n) (hNlo : 3 * n ≤ N) (hNhi : N ≤ 4 * n) : + n * (2 ^ n * (n ^ n * + 4 ^ (Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) < N ^ n := by + exact cancelled_bound_of_base_pow_exponent_cap_le (B := 3) (E := 4 * n / 15) + (by omega) hNlo (first_residual_large_exponent_le_four_fifteenths hn hNhi) + (range_3_base_exp hn) + +private lemma first_residual_large_cancelled_bound_range_4_8 {n N : ℕ} + (hn : 945 ≤ n) (hNlo : 4 * n < N) (hNhi : N ≤ 8 * n) : + n * (2 ^ n * (n ^ n * + 4 ^ (Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) < N ^ n := by + exact cancelled_bound_of_base_pow_exponent_cap (B := 4) (E := 2 * n / 5) (by omega) + hNlo (first_residual_large_exponent_le_two_fifths hn hNhi) (range_4_base_exp hn) + +private lemma first_residual_large_cancelled_bound_range_8_16 {n N : ℕ} + (hn : 945 ≤ n) (hNlo : 8 * n < N) (hNhi : N ≤ 16 * n) : + n * (2 ^ n * (n ^ n * + 4 ^ (Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) < N ^ n := by + exact cancelled_bound_of_base_pow_exponent_cap (B := 8) (E := 3 * n / 4) (by omega) + hNlo (first_residual_large_exponent_le_three_fourths hn hNhi) (range_8_base_exp hn) + +private lemma first_residual_large_cancelled_bound_range_16_64 {n N : ℕ} + (hn : 945 ≤ n) (hNlo : 16 * n < N) (hNhi : N ≤ 64 * n) : + n * (2 ^ n * (n ^ n * + 4 ^ (Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) < N ^ n := by + exact cancelled_bound_of_base_pow_exponent_cap (B := 16) (E := n) (by omega) + hNlo (first_residual_large_exponent_le_self hn hNhi) (range_16_base_exp hn) + +private lemma first_residual_large_cancelled_bound_range_64_512 {n N : ℕ} + (hn : 945 ≤ n) (hNlo : 64 * n < N) (hNhi : N ≤ 512 * n) : + n * (2 ^ n * (n ^ n * + 4 ^ (Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) < N ^ n := by + exact cancelled_bound_of_base_pow_exponent_cap (B := 64) (E := 9 * n / 4) (by omega) + hNlo (first_residual_large_exponent_le_nine_fourths hn hNhi) (range_64_base_exp hn) + +private lemma first_residual_large_cancelled_bound_range_512 {n N : ℕ} + (hn : 945 ≤ n) (hNlo : 512 * n < N) (hNhi : N ≤ n ^ 2 + n) : + n * (2 ^ n * (n ^ n * + 4 ^ (Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) < N ^ n := by + exact cancelled_bound_of_base_pow_exponent_cap (B := 512) (E := 3 * n) (by omega) + hNlo (first_residual_large_exponent_le_three_mul_self hn hNhi) (range_512_base_exp n) + +private lemma first_residual_large_cancelled_bound {n N : ℕ} + (hn : 945 ≤ n) (hNlo : 3 * n ≤ N) (hNhi : N ≤ n ^ 2 + n) : + n * (2 ^ n * (n ^ n * + 4 ^ (Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) < N ^ n := by + by_cases hN4 : N ≤ 4 * n + · exact first_residual_large_cancelled_bound_range_3_4 hn hNlo hN4 + by_cases hN8 : N ≤ 8 * n + · exact first_residual_large_cancelled_bound_range_4_8 hn (by omega) hN8 + by_cases hN16 : N ≤ 16 * n + · exact first_residual_large_cancelled_bound_range_8_16 hn (by omega) hN16 + by_cases hN64 : N ≤ 64 * n + · exact first_residual_large_cancelled_bound_range_16_64 hn (by omega) hN64 + by_cases hN512 : N ≤ 512 * n + · exact first_residual_large_cancelled_bound_range_64_512 hn (by omega) hN512 + exact first_residual_large_cancelled_bound_range_512 hn (by omega) hNhi + +/-- Large-`n` first residual estimate: after scaling to the ternary lower bound, +the Erdős three-layer upper bound is too small throughout `3 * n ≤ N ≤ n ^ 2 + n`. -/ +lemma first_residual_large_scaled_ternary_bound {n N : ℕ} + (hn : 945 ≤ n) (hNlo : 3 * n ≤ N) (hNhi : N ≤ n ^ 2 + n) : + n * (2 ^ n * ((3 * n) ^ n * + 4 ^ (n + Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N))) < + 3 ^ n * 4 ^ n * N ^ n := by + simpa [Nat.add_assoc] using + scaled_ternary_bound_of_cancelled (n := n) (N := N) + (A := Nat.sqrt N + Nat.nthRoot 3 N * Nat.log 2 N) + (first_residual_large_cancelled_bound hn hNlo hNhi) + +end Internal +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/TinyPrimeCountingBound.lean b/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/TinyPrimeCountingBound.lean new file mode 100644 index 00000000000000..4093d83d67e278 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ResidualLarge/TinyPrimeCountingBound.lean @@ -0,0 +1,62 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Data.Nat.Factorial.Basic +public import Mathlib.NumberTheory.PrimeCounting + +import Mathlib.Tactic.IntervalCases +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Ring + +/-! +# Tiny prime-counting bound for the Sylvester-Schur residual estimate + +This file contains the small residual range `7 ≤ n < 38` used by the Sylvester-Schur proof. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur +namespace Internal + +private lemma mul_top_pow_lt_start_pow_of_two_mul_top_le_three_mul_start + {F N k e n : ℕ} (he : e ≤ n) (hkpos : 0 < k) + (htop : 2 * N ≤ 3 * k) + (hconst : F * 3 ^ e < 2 ^ e * k ^ (n - e)) : + F * N ^ e < k ^ n := by + have htop_pow : 2 ^ e * N ^ e ≤ 3 ^ e * k ^ e := by + simpa [Nat.mul_pow] using Nat.pow_le_pow_left htop e + have hscaled_le : 2 ^ e * (F * N ^ e) ≤ F * (3 ^ e * k ^ e) := by + calc + 2 ^ e * (F * N ^ e) = F * (2 ^ e * N ^ e) := by ring + _ ≤ F * (3 ^ e * k ^ e) := Nat.mul_le_mul_left F htop_pow + have hscaled_lt : F * (3 ^ e * k ^ e) < 2 ^ e * k ^ n := by + calc + F * (3 ^ e * k ^ e) = (F * 3 ^ e) * k ^ e := by ring + _ < (2 ^ e * k ^ (n - e)) * k ^ e := + Nat.mul_lt_mul_of_pos_right hconst (pow_pos hkpos e) + _ = 2 ^ e * (k ^ (n - e) * k ^ e) := by ring + _ = 2 ^ e * k ^ ((n - e) + e) := by rw [pow_add] + _ = 2 ^ e * k ^ n := by rw [Nat.sub_add_cancel he] + exact Nat.lt_of_mul_lt_mul_left (hscaled_le.trans_lt hscaled_lt) + +/-- The small residual range `7 ≤ n < 38` satisfies the prime-counting conditional +estimate once `100 ≤ k`. -/ +lemma second_residual_tiny_primeCounting_lt_start_pow {n k : ℕ} + (hn7 : 7 ≤ n) (hnlt38 : n < 38) (hk100 : 100 ≤ k) : + Nat.factorial n * (k + n - 1) ^ Nat.primeCounting n < k ^ n := by + interval_cases n + all_goals + apply mul_top_pow_lt_start_pow_of_two_mul_top_le_three_mul_start + · decide + · omega + · omega + · exact lt_of_lt_of_le (by decide) (Nat.mul_le_mul_left _ + (Nat.pow_le_pow_left hk100 _)) + +end Internal +end Nat.SylvesterSchur diff --git a/Mathlib/NumberTheory/SylvesterSchur/ResidualLargeCertificates.lean b/Mathlib/NumberTheory/SylvesterSchur/ResidualLargeCertificates.lean new file mode 100644 index 00000000000000..1295f15be121e3 --- /dev/null +++ b/Mathlib/NumberTheory/SylvesterSchur/ResidualLargeCertificates.lean @@ -0,0 +1,716 @@ +/- +Copyright (c) 2026 Meta Platforms, Inc. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Kiezun +-/ +module + +public import Mathlib.Data.Nat.Factorial.Basic +public import Mathlib.NumberTheory.PrimeCounting + +import Mathlib.Tactic.IntervalCases +import Mathlib.Tactic.NormNum.NatFactorial +import Mathlib.NumberTheory.SylvesterSchur.ResidualFinite + +/-! +# Finite certificates for the large residual Sylvester-Schur estimates + +This file contains the explicit prime-counting and endpoint power certificates used for the +mid residual range in `Mathlib.NumberTheory.SylvesterSchur.ResidualLarge`. + +## Main statements + +* `second_residual_mid_primeCounting_lt_start_pow`: the finite prime-counting estimate for + `38 ≤ n < 945` and `1291 ≤ k`. + +## Implementation notes + +The prime-counting certificates avoid one large computation by sieving with the primes up to +`29`, covering the remaining candidate set by private interval chunks, and exposing only the +resulting prime-counting bounds. The endpoint power certificates are similarly hidden behind +mathematical inequalities for the relevant segments. The numerical constants in this file are +certificate data for those interval and endpoint checks, not downstream API. +-/ + +@[expose] public section + +namespace Nat.SylvesterSchur +namespace Internal + +open Finset Nat + +private def smallSievePrimes : Finset ℕ := {2, 3, 5, 7, 11, 13, 17, 19, 23, 29} + +private def smallSieveProduct : ℕ := 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 + +private def factorialSieveCandidates (n : ℕ) : Finset ℕ := + (Finset.range (n + 1)).filter (fun m => m ≠ 1 ∧ Nat.Coprime smallSieveProduct m) + +private lemma prime_mem_smallSievePrimes_of_le_twenty_nine {p : ℕ} + (hp : p.Prime) (hp29 : p ≤ 29) : + p ∈ smallSievePrimes := by + have hp2 : 2 ≤ p := hp.two_le + interval_cases p <;> try norm_num [Nat.Prime] at hp <;> norm_num [smallSievePrimes] + +private lemma prime_coprime_smallSieveProduct_of_twenty_nine_lt {p : ℕ} + (hp : p.Prime) (hp29 : 29 < p) : + Nat.Coprime smallSieveProduct p := by + have hfac : Nat.Coprime (Nat.factorial 29) p := (hp.coprime_factorial_of_lt hp29).symm + have hdiv : smallSieveProduct ∣ Nat.factorial 29 := by + norm_num [smallSieveProduct, Nat.factorial] + exact hfac.of_dvd_left hdiv + +private lemma primeCounting_le_small_sieve (n : ℕ) : + Nat.primeCounting n ≤ smallSievePrimes.card + (factorialSieveCandidates n).card := by + rw [Nat.primeCounting, Nat.primeCounting', Nat.count_eq_card_filter_range] + let counted := (Finset.range (n + 1)).filter Nat.Prime + have hsubset : counted ⊆ smallSievePrimes ∪ factorialSieveCandidates n := by + intro p hp + have hp_mem_range : p ∈ Finset.range (n + 1) := (Finset.mem_filter.mp hp).1 + have hpr : p.Prime := (Finset.mem_filter.mp hp).2 + by_cases hp29 : p ≤ 29 + · exact Finset.mem_union_left _ + (prime_mem_smallSievePrimes_of_le_twenty_nine hpr hp29) + · exact Finset.mem_union_right _ <| Finset.mem_filter.mpr ⟨hp_mem_range, hpr.ne_one, + prime_coprime_smallSieveProduct_of_twenty_nine_lt hpr (by omega)⟩ + exact (Finset.card_le_card hsubset).trans (Finset.card_union_le _ _) + +private lemma primeCounting_le_of_factorial_sieve_card {n c B : ℕ} + (hcard : (factorialSieveCandidates n).card = c) + (hbound : smallSievePrimes.card + c ≤ B) : + Nat.primeCounting n ≤ B := by + exact (primeCounting_le_small_sieve n).trans (by rwa [hcard]) + +private def sieveChunk (lo hi : ℕ) : Finset ℕ := + (Finset.Icc lo hi).filter (fun m => m ≠ 1 ∧ Nat.Coprime smallSieveProduct m) + +private def finsetUnionList : List (Finset ℕ) → Finset ℕ + | [] => ∅ + | s :: ss => s ∪ finsetUnionList ss + +private def finsetCardSum : List (Finset ℕ) → ℕ + | [] => 0 + | s :: ss => s.card + finsetCardSum ss + +private lemma card_finsetUnionList_le_cardSum (l : List (Finset ℕ)) : + (finsetUnionList l).card ≤ finsetCardSum l := by + induction l with + | nil => simp [finsetUnionList, finsetCardSum] + | cons s ss ih => + exact (Finset.card_union_le s (finsetUnionList ss)).trans + (Nat.add_le_add_left ih s.card) + +private lemma factorialSieveCandidates_card_le_of_chunks {n B : ℕ} + {chunks : List (Finset ℕ)} (hcover : factorialSieveCandidates n ⊆ finsetUnionList chunks) + (hcard : finsetCardSum chunks ≤ B) : + (factorialSieveCandidates n).card ≤ B := + (Finset.card_le_card hcover).trans ((card_finsetUnionList_le_cardSum chunks).trans hcard) + +private def sieveChunksOfBounds (bounds : List (ℕ × ℕ)) : List (Finset ℕ) := + bounds.map fun b => sieveChunk b.1 b.2 + +private lemma mem_finsetUnionList_sieveChunksOfBounds {bounds : List (ℕ × ℕ)} + {b : ℕ × ℕ} {m : ℕ} (hb : b ∈ bounds) + (hmprop : m ≠ 1 ∧ Nat.Coprime smallSieveProduct m) (hlo : b.1 ≤ m) + (hhi : m ≤ b.2) : + m ∈ finsetUnionList (sieveChunksOfBounds bounds) := by + induction bounds with + | nil => simp at hb + | cons c cs ih => + rw [List.mem_cons] at hb + change m ∈ sieveChunk c.1 c.2 ∪ finsetUnionList (sieveChunksOfBounds cs) + rw [Finset.mem_union] + rcases hb with hbc | hb + · subst c + left + rw [sieveChunk, Finset.mem_filter] + exact ⟨Finset.mem_Icc.mpr ⟨hlo, hhi⟩, hmprop⟩ + · right + exact ih hb + +private lemma factorialSieveCandidates_subset_sieveChunksOfBounds {n : ℕ} + {bounds : List (ℕ × ℕ)} + (hcover : ∀ {m : ℕ}, m ≤ n → ∃ b ∈ bounds, b.1 ≤ m ∧ m ≤ b.2) : + factorialSieveCandidates n ⊆ finsetUnionList (sieveChunksOfBounds bounds) := by + intro m hm + have hm_range : m ∈ Finset.range (n + 1) := (Finset.mem_filter.mp hm).1 + have hmle : m ≤ n := by + simpa using Nat.lt_succ_iff.mp (Finset.mem_range.mp hm_range) + have hmprop : m ≠ 1 ∧ Nat.Coprime smallSieveProduct m := (Finset.mem_filter.mp hm).2 + rcases hcover hmle with ⟨b, hb, hblo, hbhi⟩ + exact mem_finsetUnionList_sieveChunksOfBounds hb hmprop hblo hbhi + +private lemma sieveChunk_card_le_0_99 : (sieveChunk 0 99).card ≤ 15 := by decide + +private lemma sieveChunk_card_le_100_199 : (sieveChunk 100 199).card ≤ 21 := by decide + +private lemma sieveChunk_card_le_200_299 : (sieveChunk 200 299).card ≤ 16 := by decide + +private lemma sieveChunk_card_le_300_399 : (sieveChunk 300 399).card ≤ 16 := by decide + +private lemma sieveChunk_card_le_400_499 : (sieveChunk 400 499).card ≤ 17 := by decide + +private lemma sieveChunk_card_le_500_509 : (sieveChunk 500 509).card ≤ 2 := by decide + +private lemma sieveChunk_card_le_500_599 : (sieveChunk 500 599).card ≤ 14 := by decide + +private lemma sieveChunk_card_le_600_699 : (sieveChunk 600 699).card ≤ 16 := by decide + +private lemma sieveChunk_card_le_700_715 : (sieveChunk 700 715).card ≤ 2 := by decide + +private lemma sieveChunk_card_le_700_799 : (sieveChunk 700 799).card ≤ 14 := by decide + +private lemma sieveChunk_card_le_800_855 : (sieveChunk 800 855).card ≤ 8 := by decide + +private lemma sieveChunk_card_le_800_899 : (sieveChunk 800 899).card ≤ 15 := by decide + +private lemma sieveChunk_card_le_900_917 : (sieveChunk 900 917).card ≤ 2 := by decide + +private lemma sieveChunk_card_le_900_940 : (sieveChunk 900 940).card ≤ 5 := by decide + +private lemma sieveChunk_card_le_900_944 : (sieveChunk 900 944).card ≤ 6 := by decide + +/-! ### Prime-counting endpoint certificates -/ + +/- These private rows are certificate data for the mid residual range. The public statement +below packages the table as a single mathematical estimate. -/ +private lemma primeCounting_le_75 : Nat.primeCounting 75 ≤ 21 := + primeCounting_le_of_factorial_sieve_card (c := 11) (by decide) (by decide) + +private lemma primeCounting_le_157 : Nat.primeCounting 157 ≤ 37 := + primeCounting_le_of_factorial_sieve_card (c := 27) (by decide) (by decide) + +private lemma primeCounting_le_309 : Nat.primeCounting 309 ≤ 63 := + primeCounting_le_of_factorial_sieve_card (c := 53) (by decide) (by decide) + +private def sieveBounds509 : List (ℕ × ℕ) := + [(0, 99), (100, 199), (200, 299), (300, 399), (400, 499), (500, 509)] + +private def sieveChunks509 : List (Finset ℕ) := + sieveChunksOfBounds sieveBounds509 + +private lemma factorialSieveCandidates_subset_sieveChunks509 : + factorialSieveCandidates 509 ⊆ finsetUnionList sieveChunks509 := by + exact factorialSieveCandidates_subset_sieveChunksOfBounds (bounds := sieveBounds509) <| by + intro m hm + simp [sieveBounds509] + omega + +private lemma factorialSieveCandidates_card_le_509 : + (factorialSieveCandidates 509).card ≤ 87 := + factorialSieveCandidates_card_le_of_chunks factorialSieveCandidates_subset_sieveChunks509 <| by + have h0 := sieveChunk_card_le_0_99 + have h1 := sieveChunk_card_le_100_199 + have h2 := sieveChunk_card_le_200_299 + have h3 := sieveChunk_card_le_300_399 + have h4 := sieveChunk_card_le_400_499 + have h5 := sieveChunk_card_le_500_509 + simp [sieveChunks509, sieveChunksOfBounds, sieveBounds509, finsetCardSum] + omega + +private lemma primeCounting_le_509 : Nat.primeCounting 509 ≤ 97 := + (primeCounting_le_small_sieve 509).trans <| by + have hsmall : smallSievePrimes.card = 10 := by decide + have hcard := factorialSieveCandidates_card_le_509 + omega + +private def sieveBounds715 : List (ℕ × ℕ) := + [(0, 99), (100, 199), (200, 299), (300, 399), (400, 499), (500, 599), + (600, 699), (700, 715)] + +private def sieveChunks715 : List (Finset ℕ) := + sieveChunksOfBounds sieveBounds715 + +private lemma factorialSieveCandidates_subset_sieveChunks715 : + factorialSieveCandidates 715 ⊆ finsetUnionList sieveChunks715 := by + exact factorialSieveCandidates_subset_sieveChunksOfBounds (bounds := sieveBounds715) <| by + intro m hm + simp [sieveBounds715] + omega + +private lemma factorialSieveCandidates_card_le_715 : + (factorialSieveCandidates 715).card ≤ 117 := + factorialSieveCandidates_card_le_of_chunks factorialSieveCandidates_subset_sieveChunks715 <| by + have h0 := sieveChunk_card_le_0_99 + have h1 := sieveChunk_card_le_100_199 + have h2 := sieveChunk_card_le_200_299 + have h3 := sieveChunk_card_le_300_399 + have h4 := sieveChunk_card_le_400_499 + have h5 := sieveChunk_card_le_500_599 + have h6 := sieveChunk_card_le_600_699 + have h7 := sieveChunk_card_le_700_715 + simp [sieveChunks715, sieveChunksOfBounds, sieveBounds715, finsetCardSum] + omega + +private lemma primeCounting_le_715 : Nat.primeCounting 715 ≤ 127 := + (primeCounting_le_small_sieve 715).trans <| by + have hsmall : smallSievePrimes.card = 10 := by decide + have hcard := factorialSieveCandidates_card_le_715 + omega + +private def sieveBounds855 : List (ℕ × ℕ) := + [(0, 99), (100, 199), (200, 299), (300, 399), (400, 499), (500, 599), + (600, 699), (700, 799), (800, 855)] + +private def sieveChunks855 : List (Finset ℕ) := + sieveChunksOfBounds sieveBounds855 + +private lemma factorialSieveCandidates_subset_sieveChunks855 : + factorialSieveCandidates 855 ⊆ finsetUnionList sieveChunks855 := by + exact factorialSieveCandidates_subset_sieveChunksOfBounds (bounds := sieveBounds855) <| by + intro m hm + simp [sieveBounds855] + omega + +private lemma factorialSieveCandidates_card_le_855 : + (factorialSieveCandidates 855).card ≤ 137 := + factorialSieveCandidates_card_le_of_chunks factorialSieveCandidates_subset_sieveChunks855 <| by + have h0 := sieveChunk_card_le_0_99 + have h1 := sieveChunk_card_le_100_199 + have h2 := sieveChunk_card_le_200_299 + have h3 := sieveChunk_card_le_300_399 + have h4 := sieveChunk_card_le_400_499 + have h5 := sieveChunk_card_le_500_599 + have h6 := sieveChunk_card_le_600_699 + have h7 := sieveChunk_card_le_700_799 + have h8 := sieveChunk_card_le_800_855 + simp [sieveChunks855, sieveChunksOfBounds, sieveBounds855, finsetCardSum] + omega + +private lemma primeCounting_le_855 : Nat.primeCounting 855 ≤ 147 := + (primeCounting_le_small_sieve 855).trans <| by + have hsmall : smallSievePrimes.card = 10 := by decide + have hcard := factorialSieveCandidates_card_le_855 + omega + +private def sieveBounds917 : List (ℕ × ℕ) := + [(0, 99), (100, 199), (200, 299), (300, 399), (400, 499), (500, 599), + (600, 699), (700, 799), (800, 899), (900, 917)] + +private def sieveChunks917 : List (Finset ℕ) := + sieveChunksOfBounds sieveBounds917 + +private lemma factorialSieveCandidates_subset_sieveChunks917 : + factorialSieveCandidates 917 ⊆ finsetUnionList sieveChunks917 := by + exact factorialSieveCandidates_subset_sieveChunksOfBounds (bounds := sieveBounds917) <| by + intro m hm + simp [sieveBounds917] + omega + +private lemma factorialSieveCandidates_card_le_917 : + (factorialSieveCandidates 917).card ≤ 146 := + factorialSieveCandidates_card_le_of_chunks factorialSieveCandidates_subset_sieveChunks917 <| by + have h0 := sieveChunk_card_le_0_99 + have h1 := sieveChunk_card_le_100_199 + have h2 := sieveChunk_card_le_200_299 + have h3 := sieveChunk_card_le_300_399 + have h4 := sieveChunk_card_le_400_499 + have h5 := sieveChunk_card_le_500_599 + have h6 := sieveChunk_card_le_600_699 + have h7 := sieveChunk_card_le_700_799 + have h8 := sieveChunk_card_le_800_899 + have h9 := sieveChunk_card_le_900_917 + simp [sieveChunks917, sieveChunksOfBounds, sieveBounds917, finsetCardSum] + omega + +private lemma primeCounting_le_917 : Nat.primeCounting 917 ≤ 156 := + (primeCounting_le_small_sieve 917).trans <| by + have hsmall : smallSievePrimes.card = 10 := by decide + have hcard := factorialSieveCandidates_card_le_917 + omega + +private def sieveBounds940 : List (ℕ × ℕ) := + [(0, 99), (100, 199), (200, 299), (300, 399), (400, 499), (500, 599), + (600, 699), (700, 799), (800, 899), (900, 940)] + +private def sieveChunks940 : List (Finset ℕ) := + sieveChunksOfBounds sieveBounds940 + +private lemma factorialSieveCandidates_subset_sieveChunks940 : + factorialSieveCandidates 940 ⊆ finsetUnionList sieveChunks940 := by + exact factorialSieveCandidates_subset_sieveChunksOfBounds (bounds := sieveBounds940) <| by + intro m hm + simp [sieveBounds940] + omega + +private lemma factorialSieveCandidates_card_le_940 : + (factorialSieveCandidates 940).card ≤ 149 := + factorialSieveCandidates_card_le_of_chunks factorialSieveCandidates_subset_sieveChunks940 <| by + have h0 := sieveChunk_card_le_0_99 + have h1 := sieveChunk_card_le_100_199 + have h2 := sieveChunk_card_le_200_299 + have h3 := sieveChunk_card_le_300_399 + have h4 := sieveChunk_card_le_400_499 + have h5 := sieveChunk_card_le_500_599 + have h6 := sieveChunk_card_le_600_699 + have h7 := sieveChunk_card_le_700_799 + have h8 := sieveChunk_card_le_800_899 + have h9 := sieveChunk_card_le_900_940 + simp [sieveChunks940, sieveChunksOfBounds, sieveBounds940, finsetCardSum] + omega + +private lemma primeCounting_le_940 : Nat.primeCounting 940 ≤ 159 := + (primeCounting_le_small_sieve 940).trans <| by + have hsmall : smallSievePrimes.card = 10 := by decide + have hcard := factorialSieveCandidates_card_le_940 + omega + +private def sieveBounds944 : List (ℕ × ℕ) := + [(0, 99), (100, 199), (200, 299), (300, 399), (400, 499), (500, 599), + (600, 699), (700, 799), (800, 899), (900, 944)] + +private def sieveChunks944 : List (Finset ℕ) := + sieveChunksOfBounds sieveBounds944 + +private lemma factorialSieveCandidates_subset_sieveChunks944 : + factorialSieveCandidates 944 ⊆ finsetUnionList sieveChunks944 := by + exact factorialSieveCandidates_subset_sieveChunksOfBounds (bounds := sieveBounds944) <| by + intro m hm + simp [sieveBounds944] + omega + +private lemma factorialSieveCandidates_card_le_944 : + (factorialSieveCandidates 944).card ≤ 150 := + factorialSieveCandidates_card_le_of_chunks factorialSieveCandidates_subset_sieveChunks944 <| by + have h0 := sieveChunk_card_le_0_99 + have h1 := sieveChunk_card_le_100_199 + have h2 := sieveChunk_card_le_200_299 + have h3 := sieveChunk_card_le_300_399 + have h4 := sieveChunk_card_le_400_499 + have h5 := sieveChunk_card_le_500_599 + have h6 := sieveChunk_card_le_600_699 + have h7 := sieveChunk_card_le_700_799 + have h8 := sieveChunk_card_le_800_899 + have h9 := sieveChunk_card_le_900_944 + simp [sieveChunks944, sieveChunksOfBounds, sieveBounds944, finsetCardSum] + omega + +private lemma primeCounting_le_944 : Nat.primeCounting 944 ≤ 160 := + (primeCounting_le_small_sieve 944).trans <| by + have hsmall : smallSievePrimes.card = 10 := by decide + have hcard := factorialSieveCandidates_card_le_944 + omega + +/-! ### Power endpoint certificates -/ + +/- A small binary-power certificate keeps the following endpoint checks from relying on a +raised exponentiation evaluator threshold. -/ +private def pow1291_1 : ℕ := 1291 +private def pow1291_2 : ℕ := pow1291_1 * pow1291_1 +private def pow1291_4 : ℕ := pow1291_2 * pow1291_2 +private def pow1291_8 : ℕ := pow1291_4 * pow1291_4 +private def pow1291_16 : ℕ := pow1291_8 * pow1291_8 +private def pow1291_32 : ℕ := pow1291_16 * pow1291_16 +private def pow1291_64 : ℕ := pow1291_32 * pow1291_32 +private def pow1291_128 : ℕ := pow1291_64 * pow1291_64 +private def pow1291_256 : ℕ := pow1291_128 * pow1291_128 +private def pow1291_512 : ℕ := pow1291_256 * pow1291_256 + +private lemma pow1291_1_eq : 1291 ^ 1 = pow1291_1 := by + norm_num [pow1291_1] + +private lemma pow1291_2_eq : 1291 ^ 2 = pow1291_2 := by + norm_num [pow1291_2, pow1291_1] + +private lemma pow1291_4_eq : 1291 ^ 4 = pow1291_4 := by + rw [show 4 = 2 * 2 by norm_num, pow_mul, pow1291_2_eq, pow_two, pow1291_4] + +private lemma pow1291_8_eq : 1291 ^ 8 = pow1291_8 := by + rw [show 8 = 4 * 2 by norm_num, pow_mul, pow1291_4_eq, pow_two, pow1291_8] + +private lemma pow1291_16_eq : 1291 ^ 16 = pow1291_16 := by + rw [show 16 = 8 * 2 by norm_num, pow_mul, pow1291_8_eq, pow_two, pow1291_16] + +private lemma pow1291_32_eq : 1291 ^ 32 = pow1291_32 := by + rw [show 32 = 16 * 2 by norm_num, pow_mul, pow1291_16_eq, pow_two, + pow1291_32] + +private lemma pow1291_64_eq : 1291 ^ 64 = pow1291_64 := by + rw [show 64 = 32 * 2 by norm_num, pow_mul, pow1291_32_eq, pow_two, + pow1291_64] + +private lemma pow1291_128_eq : 1291 ^ 128 = pow1291_128 := by + rw [show 128 = 64 * 2 by norm_num, pow_mul, pow1291_64_eq, pow_two, + pow1291_128] + +private lemma pow1291_256_eq : 1291 ^ 256 = pow1291_256 := by + rw [show 256 = 128 * 2 by norm_num, pow_mul, pow1291_128_eq, pow_two, + pow1291_256] + +private lemma pow1291_512_eq : 1291 ^ 512 = pow1291_512 := by + rw [show 512 = 256 * 2 by norm_num, pow_mul, pow1291_256_eq, pow_two, + pow1291_512] + +private lemma pow1291_17_eq : 1291 ^ 17 = pow1291_16 * pow1291_1 := by + rw [show 17 = 16 + 1 by norm_num] + rw [pow_add] + rw [pow1291_16_eq, pow1291_1_eq] + +private lemma pow1291_39_eq : + 1291 ^ 39 = pow1291_32 * pow1291_4 * pow1291_2 * pow1291_1 := by + rw [show 39 = 32 + 4 + 2 + 1 by norm_num] + rw [pow_add, pow_add, pow_add] + rw [pow1291_32_eq, pow1291_4_eq, pow1291_2_eq, pow1291_1_eq] + +private lemma pow1291_95_eq : + 1291 ^ 95 = pow1291_64 * pow1291_16 * pow1291_8 * pow1291_4 * + pow1291_2 * pow1291_1 := by + rw [show 95 = 64 + 16 + 8 + 4 + 2 + 1 by norm_num] + rw [pow_add, pow_add, pow_add, pow_add, pow_add] + rw [pow1291_64_eq, pow1291_16_eq, pow1291_8_eq, pow1291_4_eq, + pow1291_2_eq, pow1291_1_eq] + +private lemma pow1291_213_eq : + 1291 ^ 213 = pow1291_128 * pow1291_64 * pow1291_16 * pow1291_4 * + pow1291_1 := by + rw [show 213 = 128 + 64 + 16 + 4 + 1 by norm_num] + rw [pow_add, pow_add, pow_add, pow_add] + rw [pow1291_128_eq, pow1291_64_eq, pow1291_16_eq, pow1291_4_eq, + pow1291_1_eq] + +private lemma pow1291_383_eq : + 1291 ^ 383 = pow1291_256 * pow1291_64 * pow1291_32 * pow1291_16 * + pow1291_8 * pow1291_4 * pow1291_2 * pow1291_1 := by + rw [show 383 = 256 + 64 + 32 + 16 + 8 + 4 + 2 + 1 by norm_num] + rw [pow_add, pow_add, pow_add, pow_add, pow_add, pow_add, pow_add] + rw [pow1291_256_eq, pow1291_64_eq, pow1291_32_eq, pow1291_16_eq, + pow1291_8_eq, pow1291_4_eq, pow1291_2_eq, pow1291_1_eq] + +private lemma pow1291_569_eq : + 1291 ^ 569 = pow1291_512 * pow1291_32 * pow1291_16 * pow1291_8 * + pow1291_1 := by + rw [show 569 = 512 + 32 + 16 + 8 + 1 by norm_num] + rw [pow_add, pow_add, pow_add, pow_add] + rw [pow1291_512_eq, pow1291_32_eq, pow1291_16_eq, pow1291_8_eq, + pow1291_1_eq] + +private lemma pow1291_700_eq : + 1291 ^ 700 = pow1291_512 * pow1291_128 * pow1291_32 * pow1291_16 * + pow1291_8 * pow1291_4 := by + rw [show 700 = 512 + 128 + 32 + 16 + 8 + 4 by norm_num] + rw [pow_add, pow_add, pow_add, pow_add, pow_add] + rw [pow1291_512_eq, pow1291_128_eq, pow1291_32_eq, pow1291_16_eq, + pow1291_8_eq, pow1291_4_eq] + +private lemma pow1291_759_eq : + 1291 ^ 759 = pow1291_512 * pow1291_128 * pow1291_64 * pow1291_32 * + pow1291_16 * pow1291_4 * pow1291_2 * pow1291_1 := by + rw [show 759 = 512 + 128 + 64 + 32 + 16 + 4 + 2 + 1 by norm_num] + rw [pow_add, pow_add, pow_add, pow_add, pow_add, pow_add, pow_add] + rw [pow1291_512_eq, pow1291_128_eq, pow1291_64_eq, pow1291_32_eq, + pow1291_16_eq, pow1291_4_eq, pow1291_2_eq, pow1291_1_eq] + +private lemma pow1291_781_eq : + 1291 ^ 781 = pow1291_512 * pow1291_256 * pow1291_8 * pow1291_4 * + pow1291_1 := by + rw [show 781 = 512 + 256 + 8 + 4 + 1 by norm_num] + rw [pow_add, pow_add, pow_add, pow_add] + rw [pow1291_512_eq, pow1291_256_eq, pow1291_8_eq, pow1291_4_eq, + pow1291_1_eq] + +private lemma second_residual_mid_base_38 : + Nat.factorial 38 * 26 ^ 21 < 15 ^ 21 * 1291 ^ (38 - 21) := by + rw [show 38 - 21 = 17 by norm_num, pow1291_17_eq] + norm_num [Nat.factorial_eq_factorialBinarySplitting, Nat.factorialBinarySplitting, + pow1291_512, pow1291_256, pow1291_128, pow1291_64, pow1291_32, pow1291_16, + pow1291_8, pow1291_4, pow1291_2, pow1291_1] + +private lemma second_residual_mid_base_76 : + Nat.factorial 76 * 26 ^ 37 < 15 ^ 37 * 1291 ^ (76 - 37) := by + rw [show 76 - 37 = 39 by norm_num, pow1291_39_eq] + norm_num [Nat.factorial_eq_factorialBinarySplitting, Nat.factorialBinarySplitting, + pow1291_512, pow1291_256, pow1291_128, pow1291_64, pow1291_32, pow1291_16, + pow1291_8, pow1291_4, pow1291_2, pow1291_1] + +private lemma second_residual_mid_base_158 : + Nat.factorial 158 * 26 ^ 63 < 15 ^ 63 * 1291 ^ (158 - 63) := by + rw [show 158 - 63 = 95 by norm_num, pow1291_95_eq] + norm_num [Nat.factorial_eq_factorialBinarySplitting, Nat.factorialBinarySplitting, + pow1291_512, pow1291_256, pow1291_128, pow1291_64, pow1291_32, pow1291_16, + pow1291_8, pow1291_4, pow1291_2, pow1291_1] + +private lemma second_residual_mid_base_310 : + Nat.factorial 310 * 26 ^ 97 < 15 ^ 97 * 1291 ^ (310 - 97) := by + rw [show 310 - 97 = 213 by norm_num, pow1291_213_eq] + norm_num [Nat.factorial_eq_factorialBinarySplitting, Nat.factorialBinarySplitting, + pow1291_512, pow1291_256, pow1291_128, pow1291_64, pow1291_32, pow1291_16, + pow1291_8, pow1291_4, pow1291_2, pow1291_1] + +private lemma second_residual_mid_base_510 : + Nat.factorial 510 * 26 ^ 127 < 15 ^ 127 * 1291 ^ (510 - 127) := by + rw [show 510 - 127 = 383 by norm_num, pow1291_383_eq] + norm_num [Nat.factorial_eq_factorialBinarySplitting, Nat.factorialBinarySplitting, + pow1291_512, pow1291_256, pow1291_128, pow1291_64, pow1291_32, pow1291_16, + pow1291_8, pow1291_4, pow1291_2, pow1291_1] + +private lemma second_residual_mid_base_716 : + Nat.factorial 716 * 26 ^ 147 < 15 ^ 147 * 1291 ^ (716 - 147) := by + rw [show 716 - 147 = 569 by norm_num, pow1291_569_eq] + norm_num [Nat.factorial_eq_factorialBinarySplitting, Nat.factorialBinarySplitting, + pow1291_512, pow1291_256, pow1291_128, pow1291_64, pow1291_32, pow1291_16, + pow1291_8, pow1291_4, pow1291_2, pow1291_1] + +private lemma second_residual_mid_base_856 : + Nat.factorial 856 * 26 ^ 156 < 15 ^ 156 * 1291 ^ (856 - 156) := by + rw [show 856 - 156 = 700 by norm_num, pow1291_700_eq] + norm_num [Nat.factorial_eq_factorialBinarySplitting, Nat.factorialBinarySplitting, + pow1291_512, pow1291_256, pow1291_128, pow1291_64, pow1291_32, pow1291_16, + pow1291_8, pow1291_4, pow1291_2, pow1291_1] + +private lemma second_residual_mid_base_918 : + Nat.factorial 918 * 26 ^ 159 < 15 ^ 159 * 1291 ^ (918 - 159) := by + rw [show 918 - 159 = 759 by norm_num, pow1291_759_eq] + norm_num [Nat.factorial_eq_factorialBinarySplitting, Nat.factorialBinarySplitting, + pow1291_512, pow1291_256, pow1291_128, pow1291_64, pow1291_32, pow1291_16, + pow1291_8, pow1291_4, pow1291_2, pow1291_1] + +private lemma second_residual_mid_base_941 : + Nat.factorial 941 * 26 ^ 160 < 15 ^ 160 * 1291 ^ (941 - 160) := by + rw [show 941 - 160 = 781 by norm_num, pow1291_781_eq] + norm_num [Nat.factorial_eq_factorialBinarySplitting, Nat.factorialBinarySplitting, + pow1291_512, pow1291_256, pow1291_128, pow1291_64, pow1291_32, pow1291_16, + pow1291_8, pow1291_4, pow1291_2, pow1291_1] + +/-! ### Mid residual estimate -/ + +private lemma mul_top_pow_lt_start_pow_of_scaled_top_le_start + {F N k e n a b : ℕ} (he : e ≤ n) (hkpos : 0 < k) + (htop : b * N ≤ a * k) + (hconst : F * a ^ e < b ^ e * k ^ (n - e)) : + F * N ^ e < k ^ n := by + have htop_pow : b ^ e * N ^ e ≤ a ^ e * k ^ e := by + simpa [Nat.mul_pow] using Nat.pow_le_pow_left htop e + have hscaled_le : b ^ e * (F * N ^ e) ≤ F * (a ^ e * k ^ e) := by + calc + b ^ e * (F * N ^ e) = F * (b ^ e * N ^ e) := by ring + _ ≤ F * (a ^ e * k ^ e) := Nat.mul_le_mul_left F htop_pow + have hscaled_lt : F * (a ^ e * k ^ e) < b ^ e * k ^ n := by + calc + F * (a ^ e * k ^ e) = (F * a ^ e) * k ^ e := by ring + _ < (b ^ e * k ^ (n - e)) * k ^ e := + Nat.mul_lt_mul_of_pos_right hconst (pow_pos hkpos e) + _ = b ^ e * (k ^ (n - e) * k ^ e) := by ring + _ = b ^ e * k ^ ((n - e) + e) := by rw [pow_add] + _ = b ^ e * k ^ n := by rw [Nat.sub_add_cancel he] + exact Nat.lt_of_mul_lt_mul_left (hscaled_le.trans_lt hscaled_lt) + +private lemma primeCounting_le_self (n : ℕ) : Nat.primeCounting n ≤ n := by + rw [Nat.primeCounting, Nat.primeCounting'] + refine (Nat.count_mono_left (n := n + 1) (p := Nat.Prime) + (q := fun m : ℕ => m ≠ 0) ?_).trans_eq ?_ + · intro k _ hk + exact hk.ne_zero + rw [add_comm n 1, Nat.count_add] + simp [Nat.count_succ] + +private lemma factorial_scaled_bound_step {m P : ℕ} (hP : P ≤ m) (hm : m + 1 < 1291) + (h : Nat.factorial m * 26 ^ P < 15 ^ P * 1291 ^ (m - P)) : + Nat.factorial (m + 1) * 26 ^ P < 15 ^ P * 1291 ^ (m + 1 - P) := by + have hmul : + (m + 1) * (Nat.factorial m * 26 ^ P) < + 1291 * (15 ^ P * 1291 ^ (m - P)) := + Nat.mul_lt_mul_of_lt_of_le hm h.le (by positivity) + calc + Nat.factorial (m + 1) * 26 ^ P = (m + 1) * (Nat.factorial m * 26 ^ P) := by + rw [Nat.factorial_succ] + ring + _ < 1291 * (15 ^ P * 1291 ^ (m - P)) := hmul + _ = 15 ^ P * 1291 ^ (m + 1 - P) := by + have hsub : m + 1 - P = (m - P) + 1 := by omega + rw [hsub, pow_add] + ring + +private lemma factorial_scaled_bound_of_le {lo n P : ℕ} (hlo : lo ≤ n) (hn : n < 1291) + (hP : P ≤ lo) + (hbase : Nat.factorial lo * 26 ^ P < 15 ^ P * 1291 ^ (lo - P)) : + Nat.factorial n * 26 ^ P < 15 ^ P * 1291 ^ (n - P) := by + induction n, hlo using Nat.le_induction with + | base => exact hbase + | succ m hm ih => + exact factorial_scaled_bound_step (hP.trans hm) (by omega) (ih (by omega)) + +private lemma scaled_pow_le_of_le {e P n k : ℕ} (heP : e ≤ P) (hPn : P ≤ n) + (hk15 : 15 ≤ k) : + 15 ^ P * k ^ (n - P) ≤ 15 ^ e * k ^ (n - e) := by + have hpow : 15 ^ (P - e) ≤ k ^ (P - e) := Nat.pow_le_pow_left hk15 _ + calc + 15 ^ P * k ^ (n - P) = 15 ^ e * (15 ^ (P - e) * k ^ (n - P)) := by + nth_rewrite 1 [show P = e + (P - e) by omega] + rw [pow_add] + ring + _ ≤ 15 ^ e * (k ^ (P - e) * k ^ (n - P)) := + Nat.mul_le_mul_left _ (Nat.mul_le_mul_right _ hpow) + _ = 15 ^ e * k ^ ((P - e) + (n - P)) := by rw [pow_add] + _ = 15 ^ e * k ^ (n - e) := by + congr 2 + omega + +private lemma factorial_mul_scaled_primeCounting_lt_of_segment {lo n P k : ℕ} + (hlo : lo ≤ n) (hn : n < 1291) (hPlo : P ≤ lo) (hpi : Nat.primeCounting n ≤ P) + (hbase : Nat.factorial lo * 26 ^ P < 15 ^ P * 1291 ^ (lo - P)) + (hk : 1291 ≤ k) : + Nat.factorial n * 26 ^ Nat.primeCounting n < + 15 ^ Nat.primeCounting n * k ^ (n - Nat.primeCounting n) := by + have hfixed1291 := factorial_scaled_bound_of_le hlo hn hPlo hbase + have hfixedk : + Nat.factorial n * 26 ^ P < 15 ^ P * k ^ (n - P) := + hfixed1291.trans_le (Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hk _)) + have hlhs : + Nat.factorial n * 26 ^ Nat.primeCounting n ≤ Nat.factorial n * 26 ^ P := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_right (by norm_num : 0 < 26) hpi) + have hrhs : + 15 ^ P * k ^ (n - P) ≤ + 15 ^ Nat.primeCounting n * k ^ (n - Nat.primeCounting n) := + scaled_pow_le_of_le hpi (hPlo.trans hlo) (by omega) + exact hlhs.trans_lt (hfixedk.trans_le hrhs) + +/-- The mid residual range `38 ≤ n < 945` satisfies the prime-counting conditional +estimate once `1291 ≤ k`, using the finite certificates in this file. -/ +lemma second_residual_mid_primeCounting_lt_start_pow {n k : ℕ} + (hn38 : 38 ≤ n) (hnlt945 : n < 945) (hk1291 : 1291 ≤ k) : + Nat.factorial n * (k + n - 1) ^ Nat.primeCounting n < k ^ n := by + have hkpos : 0 < k := by omega + have htop : 15 * (k + n - 1) ≤ 26 * k := by omega + apply mul_top_pow_lt_start_pow_of_scaled_top_le_start (a := 26) (b := 15) + · exact primeCounting_le_self _ + · exact hkpos + · exact htop + · by_cases hn75 : n ≤ 75 + · have hpi := (Nat.monotone_primeCounting hn75).trans primeCounting_le_75 + exact factorial_mul_scaled_primeCounting_lt_of_segment hn38 (by omega) (by norm_num) + hpi second_residual_mid_base_38 hk1291 + by_cases hn157 : n ≤ 157 + · have hpi := (Nat.monotone_primeCounting hn157).trans primeCounting_le_157 + exact factorial_mul_scaled_primeCounting_lt_of_segment (by omega : 76 ≤ n) + (by omega) (by norm_num) hpi second_residual_mid_base_76 hk1291 + by_cases hn309 : n ≤ 309 + · have hpi := (Nat.monotone_primeCounting hn309).trans primeCounting_le_309 + exact factorial_mul_scaled_primeCounting_lt_of_segment (by omega : 158 ≤ n) + (by omega) (by norm_num) hpi second_residual_mid_base_158 hk1291 + by_cases hn509 : n ≤ 509 + · have hpi := (Nat.monotone_primeCounting hn509).trans primeCounting_le_509 + exact factorial_mul_scaled_primeCounting_lt_of_segment (by omega : 310 ≤ n) + (by omega) (by norm_num) hpi second_residual_mid_base_310 hk1291 + by_cases hn715 : n ≤ 715 + · have hpi := (Nat.monotone_primeCounting hn715).trans primeCounting_le_715 + exact factorial_mul_scaled_primeCounting_lt_of_segment (by omega : 510 ≤ n) + (by omega) (by norm_num) hpi second_residual_mid_base_510 hk1291 + by_cases hn855 : n ≤ 855 + · have hpi := (Nat.monotone_primeCounting hn855).trans primeCounting_le_855 + exact factorial_mul_scaled_primeCounting_lt_of_segment (by omega : 716 ≤ n) + (by omega) (by norm_num) hpi second_residual_mid_base_716 hk1291 + by_cases hn917 : n ≤ 917 + · have hpi := (Nat.monotone_primeCounting hn917).trans primeCounting_le_917 + exact factorial_mul_scaled_primeCounting_lt_of_segment (by omega : 856 ≤ n) + (by omega) (by norm_num) hpi second_residual_mid_base_856 hk1291 + by_cases hn940 : n ≤ 940 + · have hpi := (Nat.monotone_primeCounting hn940).trans primeCounting_le_940 + exact factorial_mul_scaled_primeCounting_lt_of_segment (by omega : 918 ≤ n) + (by omega) (by norm_num) hpi second_residual_mid_base_918 hk1291 + have hn944 : n ≤ 944 := by omega + have hpi := (Nat.monotone_primeCounting hn944).trans primeCounting_le_944 + exact factorial_mul_scaled_primeCounting_lt_of_segment (by omega : 941 ≤ n) + (by omega) (by norm_num) hpi second_residual_mid_base_941 hk1291 + +end Internal +end Nat.SylvesterSchur From ecae7ee66e59e265cae960d7f06668c1207893b2 Mon Sep 17 00:00:00 2001 From: Adam Kiezun Date: Tue, 12 May 2026 09:02:35 -0400 Subject: [PATCH 2/2] =?UTF-8?q?doc(NumberTheory):=20cite=20Erd=C5=91s=20fo?= =?UTF-8?q?r=20Sylvester-Schur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mathlib/NumberTheory/SylvesterSchur/Main.lean | 3 ++- docs/references.bib | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Mathlib/NumberTheory/SylvesterSchur/Main.lean b/Mathlib/NumberTheory/SylvesterSchur/Main.lean index 2cbc0adb254b1a..2efd85ecd04841 100644 --- a/Mathlib/NumberTheory/SylvesterSchur/Main.lean +++ b/Mathlib/NumberTheory/SylvesterSchur/Main.lean @@ -31,7 +31,8 @@ induction step. ## References -The proof follows Erdős's proof of the Sylvester-Schur theorem. +The proof follows Erdős's proof of the Sylvester-Schur theorem +[Erdős, *A theorem of Sylvester and Schur*][erdos1934SylvesterSchur]. ## Tags diff --git a/docs/references.bib b/docs/references.bib index ebf9ebfd35a88a..8a6eb79e5043b0 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -1886,6 +1886,19 @@ @Book{ engelking1989 mrreviewer = {Gary\ Gruenhage} } +@Article{ erdos1934SylvesterSchur, + author = {Erd{\H{o}}s, Paul}, + title = {A theorem of {S}ylvester and {S}chur}, + journal = {J. London Math. Soc.}, + fjournal = {Journal of the London Mathematical Society}, + volume = {s1-9}, + year = {1934}, + number = {4}, + pages = {282--288}, + doi = {10.1112/jlms/s1-9.4.282}, + url = {https://doi.org/10.1112/jlms/s1-9.4.282} +} + @Article{ erdosrenyisos, author = {P. Erd\"os and A. R\'enyi and V. S\'os}, title = {On a problem of graph theory},