From 97a308e9a652e01ae7d4c27db6934d29f0bb1153 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 15:46:22 -0800 Subject: [PATCH 01/70] initial vsc --- Mathlib/NumberTheory/Bernoulli.lean | 1121 +++++++++++++++++++++++++++ 1 file changed, 1121 insertions(+) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 2269398b06990d..0013c6e7129d2c 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -383,3 +383,1124 @@ theorem sum_Ico_pow (n p : ℕ) : _ = ∑ i ∈ range p.succ.succ, f' i := by simp_rw [sum_range_succ'] end Faulhaber + +section vonStaudtClausen + +noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := + if (p - 1 : ℕ) ∣ k then 1 else 0 + +lemma von_staudt_clausen_zero : + bernoulli (2 * 0) + ∑ p ∈ Finset.range (2 * 0 + 2) with p.Prime ∧ (p - 1) ∣ 2 * 0, + (1 : ℚ) / p ∈ Set.range Int.cast := by + have h1 : bernoulli (2 * 0) = 1 := by norm_num [bernoulli_zero] + have h2 : ∑ p ∈ Finset.range (2 * 0 + 2) with p.Prime ∧ (p - 1) ∣ 2 * 0, (1 : ℚ) / p = 0 := by + norm_num + decide + rw [h1, h2] + exact ⟨1, by norm_num⟩ + +lemma zmod_pow_eq_one_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) ∣ l) + (a : ZMod p) (ha : a ≠ 0) : a ^ l = 1 := by + haveI : Fact p.Prime := ⟨hp⟩ + obtain ⟨k, hk⟩ := hdvd + simp only [hk, pow_mul, ZMod.pow_card_sub_one_eq_one ha, one_pow] + +lemma card_filter_range_ne_zero (p : ℕ) (_hp : p.Prime) : + (Finset.range p |>.filter (· ≠ 0)).card = p - 1 := by + simp only [Finset.filter_ne', Finset.card_erase_of_mem (Finset.mem_range.mpr _hp.pos), + Finset.card_range] + +lemma zmod_nat_sub_one_eq_neg_one (p : ℕ) (hp : 0 < p) : ((p - 1 : ℕ) : ZMod p) = -1 := by + simp [Nat.cast_sub hp] + +lemma cast_ne_zero_of_mem_filter (p _l : ℕ) (_hp : p.Prime) (v : ℕ) + (hv : v ∈ (Finset.range p).filter (· ≠ 0)) : (v : ZMod p) ≠ 0 := by + simp only [Finset.mem_filter, Finset.mem_range] at hv + intro h + have h1 : (p : ℕ) ∣ v := by simpa [ZMod.natCast_eq_zero_iff] using h + have h2 : p ≤ v := Nat.le_of_dvd (by omega) h1 + omega + +lemma power_sum_eq_neg_one_mod_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) ∣ l) : + (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = -1 := by + have h1 : ∀ v ∈ (Finset.range p).filter (· ≠ 0), (v : ZMod p) ^ l = 1 := fun v hv => + zmod_pow_eq_one_of_dvd p l hp hdvd (v : ZMod p) (cast_ne_zero_of_mem_filter p l hp v hv) + rw [Finset.sum_congr rfl h1, Finset.sum_const, card_filter_range_ne_zero p hp, + nsmul_eq_mul, mul_one] + exact zmod_nat_sub_one_eq_neg_one p hp.pos + +lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : + (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = + ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := by + have hcast := cast_ne_zero_of_mem_filter p l (Fact.out : p.Prime) + refine Finset.sum_bij' (fun v _ => (isUnit_iff_ne_zero.mpr (hcast v ‹_›)).unit) + (fun u _ => (u : ZMod p).val) ?_ ?_ ?_ ?_ ?_ + · intro v hv + exact Finset.mem_univ _ + · intro u _ + simp only [Finset.mem_filter, Finset.mem_range] + constructor + · exact ZMod.val_lt (u : ZMod p) + · intro h + have hu : (u : ZMod p) ≠ 0 := Units.ne_zero u + simp only [ZMod.val_eq_zero] at h + exact hu h + · intro v hv + simp only [Finset.mem_filter, Finset.mem_range] at hv + have : (v : ZMod p).val = v := ZMod.val_cast_of_lt hv.1 + simp only [IsUnit.unit_spec, this] + · intro u _ + ext + simp only [IsUnit.unit_spec, ZMod.natCast_zmod_val] + · intro v _ + simp only [IsUnit.unit_spec] + +lemma prime_ne_two_of_not_dvd_sub_one (p l : ℕ) (_hp : p.Prime) (hndvd : ¬(p - 1) ∣ l) : + p ≠ 2 := fun h => by subst h; simp at hndvd + +lemma generator_orderOf_eq (p : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) + (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : + orderOf g = p - 1 := by + have h1 : Fintype.card (Subgroup.zpowers g) = orderOf g := Fintype.card_zpowers + have h3 : Fintype.card (ZMod p)ˣ = p - 1 := ZMod.card_units p + aesop + +lemma pow_injective_on_range (p : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) + (hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : + Set.InjOn (fun i => g ^ i) (Finset.range (p - 1) : Set ℕ) := by + intro i hi j hj heq + simp only [Finset.coe_range, Set.mem_Iio] at hi hj + have hord : orderOf g = p - 1 := generator_orderOf_eq p g hg + have hfin : IsOfFinOrder g := isOfFinOrder_of_finite g + rw [IsOfFinOrder.pow_eq_pow_iff_modEq hfin, hord] at heq + exact Nat.ModEq.eq_of_lt_of_lt heq hi hj + +lemma units_pow_coe_eq (p l : ℕ) (g : (ZMod p)ˣ) (i : ℕ) : + ((g ^ i : (ZMod p)ˣ) : ZMod p) ^ l = ((g : ZMod p) ^ l) ^ i := by + simp [← pow_mul, mul_comm] + +lemma sum_units_eq_sum_range (p l : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) + (hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : + (∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l) = + ∑ i ∈ Finset.range (p - 1), ((g : ZMod p) ^ l) ^ i := by + have hord : orderOf g = p - 1 := generator_orderOf_eq p g hg + have himg : Finset.image (fun i => g ^ i) (Finset.range (orderOf g)) = Finset.univ := + IsCyclic.image_range_orderOf hg + rw [hord] at himg + conv_lhs => rw [← himg] + rw [Finset.sum_image (pow_injective_on_range p g hg)] + congr 1 + ext i + exact units_pow_coe_eq p l g i + +lemma generator_pow_ne_one (p l : ℕ) [hp : Fact p.Prime] (_hp2 : p ≠ 2) + (hndvd : ¬(p - 1) ∣ l) (g : (ZMod p)ˣ) + (hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : + (g : ZMod p) ^ l ≠ 1 := by + have h_order : orderOf g = p - 1 := by + simp only [orderOf_eq_card_of_forall_mem_zpowers hg, Nat.card_eq_fintype_card, ZMod.card_units] + intro h + exact hndvd (h_order ▸ orderOf_dvd_of_pow_eq_one (Units.ext (by simpa using h))) + +lemma geom_sum_of_root_of_unity (p : ℕ) [hp : Fact p.Prime] (x : ZMod p) + (hx1 : x ≠ 1) (hxp : x ^ (p - 1) = 1) : + ∑ i ∈ Finset.range (p - 1), x ^ i = 0 := by + have h_sum : ∑ i ∈ Finset.range (p - 1), x ^ i = (x ^ (p - 1) - 1) / (x - 1) := + geom_sum_eq hx1 (p - 1) + aesop + +lemma generator_pow_card_sub_one_eq_one (p l : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) + (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : + ((g : ZMod p) ^ l) ^ (p - 1) = 1 := by + have h2 : (g : ZMod p) ^ l ≠ 0 := by aesop + exact ZMod.pow_card_sub_one_eq_one h2 + +lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hp2 : p ≠ 2) + (hndvd : ¬(p - 1) ∣ l) : + (∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l) = 0 := by + haveI : IsCyclic (ZMod p)ˣ := ZMod.isCyclic_units_prime hp.out + obtain ⟨g, hg⟩ := IsCyclic.exists_generator (α := (ZMod p)ˣ) + rw [sum_units_eq_sum_range p l g hg] + apply geom_sum_of_root_of_unity p + · exact generator_pow_ne_one p l hp2 hndvd g hg + · exact generator_pow_card_sub_one_eq_one p l g hg + +lemma power_sum_eq_zero_mod_of_not_dvd (p l : ℕ) (hp : p.Prime) (hndvd : ¬(p - 1) ∣ l) : + (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = 0 := by + haveI : Fact p.Prime := ⟨hp⟩ + have hp2 : p ≠ 2 := prime_ne_two_of_not_dvd_sub_one p l hp hndvd + rw [sum_pow_eq_sum_units_pow p l] + exact sum_units_pow_eq_zero_of_not_dvd p l hp2 hndvd + +lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : + (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + + (if (p - 1 : ℕ) ∣ l then (1 : ZMod p) else 0) = 0 := by + by_cases h : (p - 1) ∣ l + · simp only [h, ↓reduceIte] + rw [power_sum_eq_neg_one_mod_of_dvd p l hp h] + ring + · simp only [h, ↓reduceIte, add_zero] + exact power_sum_eq_zero_mod_of_not_dvd p l hp h + +lemma mem_range_int_cast_iff (q : ℚ) : + q ∈ Set.range Int.cast ↔ q.den = 1 := by + constructor + · intro ⟨z, hz⟩ + simp only [← hz] + norm_cast + · intro h + use q.num + have hq : (q.num : ℚ) / q.den = q := Rat.num_div_den q + rw [← hq, h] + simp + +lemma is_integer_of_coprime_all_primes (q : ℚ) + (h : ∀ p : ℕ, p.Prime → q.den.Coprime p) : + q ∈ Set.range Int.cast := by + have h1 : q.den = 1 := by + by_contra hne + obtain ⟨p, hp, hpdvd⟩ := Nat.exists_prime_and_dvd (by omega : q.den ≠ 1) + have hcop := h p hp + have : p ∣ Nat.gcd q.den p := Nat.dvd_gcd hpdvd (dvd_refl p) + rw [Nat.coprime_iff_gcd_eq_one.mp hcop] at this + have : p ≤ 1 := Nat.le_of_dvd (by norm_num) this + linarith [hp.two_le] + use q.num + have hq : (q.num : ℚ) / q.den = q := Rat.num_div_den q + rw [← hq, h1] + simp + +def pIntegral (p : ℕ) (x : ℚ) : Prop := x.den.Coprime p + +lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : + (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by + classical + induction' s using Finset.induction_on with a s has ih + · simp + · rw [Finset.sum_insert has, Finset.prod_insert has] + exact dvd_trans (Rat.add_den_dvd (f a) (∑ x ∈ s, f x)) (mul_dvd_mul_left _ ih) + +lemma pIntegral_sum {ι : Type*} (p : ℕ) (s : Finset ι) (f : ι → ℚ) + (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := + Nat.Coprime.coprime_dvd_left (sum_den_dvd_prod_den s f) + (Nat.Coprime.prod_left fun i hi => hf i hi) + +lemma prod_den_coprime_p (k p : ℕ) (hp : p.Prime) : + (∏ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, + ((1 : ℚ) / q).den).Coprime p := by + apply Nat.Coprime.prod_left + intro q hq + have h1 : q.Prime := (Finset.mem_filter.mp hq).2.1 + have h2 : q ≠ p := (Finset.mem_filter.mp hq).2.2.2 + have h3 : ((1 : ℚ) / q).den = q := by + have h5 : (q : ℕ) ≠ 0 := Nat.Prime.ne_zero h1 + field_simp [h5] + simp_all + rw [h3] + exact (Nat.coprime_primes h1 hp).mpr h2 + +lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : + (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = + vonStaudtIndicator (2 * k) p / p + + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by + have h3 : ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q = + (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) + + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by + have h4 : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = + ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q := rfl + rw [h4] + have h5 : p < 2 * k + 2 ∨ ¬(p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) := by + by_cases h51 : p < 2 * k + 2 + · exact Or.inl h51 + · exact Or.inr (by tauto) + cases h5 with + | inl h5 => + have h7 : p < 2 * k + 2 := h5 + have h8 : p ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) ↔ + p.Prime ∧ (p - 1) ∣ 2 * k := by + simp [Finset.mem_filter, Finset.mem_range] + tauto + have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = + (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) := by + have h10 : (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) ↔ (p.Prime ∧ (p - 1) ∣ 2 * k) := by + constructor <;> intro h11 + · exact ⟨h11.1, h11.2.1⟩ + · exact ⟨h11.1, h11.2, by omega⟩ + simp [h10] + rw [h9] + by_cases h10 : p.Prime ∧ (p - 1) ∣ 2 * k + · have h13 : p ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) := by + simp [Finset.mem_filter, Finset.mem_range] at h8 ⊢ + tauto + have h14 : ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q = + ∑ q ∈ (Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2))).erase p, (1 : ℚ) / q + (1 : ℚ) / p := by + rw [← Finset.insert_erase h13, Finset.sum_insert (Finset.notMem_erase p _)] + simp_all [Finset.mem_filter, Finset.mem_range] + have h17 : ∑ q ∈ (Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2))).erase p, (1 : ℚ) / q = + ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)), (1 : ℚ) / q := by + have h18 : (Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2))).erase p = + Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)) := by + apply Finset.ext + intro q + simp only [Finset.mem_filter, Finset.mem_erase, Finset.mem_range] + cases q <;> simp_all [Nat.Prime] + tauto + rw [h18] + have h19 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) = (1 : ℚ) / p := by simp [h10] + rw [h14, h17, h19] + ring_nf + · have h13 : ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q = + ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)), (1 : ℚ) / q := by + have h14 : Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) = + Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)) := by + apply Finset.ext + intro q + simp only [Finset.mem_filter, Finset.mem_range] + by_cases hq : q = p <;> simp_all [Nat.Prime] + rw [h14] + have h15 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) = 0 := by simp [h10] + rw [h13, h15] + ring_nf + | inr h5 => + have h8 : ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q = + ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)), (1 : ℚ) / q := by + have h9 : Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) = + Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)) := by + apply Finset.ext + intro q + simp only [Finset.mem_filter, Finset.mem_range] + by_cases hq : q = p <;> simp_all [Nat.Prime] + omega + rw [h9] + have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = 0 := by simp [h5] + rw [h8, h9] + ring_nf + have h4 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = + vonStaudtIndicator (2 * k) p / p := by + by_cases h5 : (p - 1 : ℕ) ∣ 2 * k + · have h7 : vonStaudtIndicator (2 * k) p = 1 := by simp [vonStaudtIndicator, h5] + have h9 : p < 2 * k + 2 := by + have h14 : p - 1 ≤ 2 * k := Nat.le_of_dvd (by nlinarith) h5 + omega + have h10 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = (1 : ℚ) / p := by + simp [hp, h5, h9] + have h11 : vonStaudtIndicator (2 * k) p / p = (1 : ℚ) / p := by rw [h7] + rw [h10, h11] + · have h7 : vonStaudtIndicator (2 * k) p = 0 := by simp [vonStaudtIndicator, h5] + have h8 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = 0 := by + by_cases h9 : p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2 + · exact absurd h9.2.1 h5 + · simp [h9] + have h9 : vonStaudtIndicator (2 * k) p / p = 0 := by rw [h7]; simp + rw [h8, h9] + calc (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = + (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) + + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := h3 + _ = vonStaudtIndicator (2 * k) p / p + + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by rw [h4] + +lemma pIntegral_of_int (p : ℕ) (z : ℤ) : pIntegral p z := by simp_all [pIntegral] + +lemma ordCompl_coprime_of_prime (p M : ℕ) (hp : p.Prime) (hM : M ≠ 0) : + (M / p ^ M.factorization p).Coprime p := + (Nat.coprime_ordCompl hp hM).symm + +lemma pIntegral_of_den_dvd_coprime (p : ℕ) (x : ℚ) (M : ℕ) + (hdvd : x.den ∣ M) (hcop : M.Coprime p) : pIntegral p x := + hcop.coprime_dvd_left hdvd + +lemma ordCompl_ne_zero (p M : ℕ) (_hp : p.Prime) (hM : M ≠ 0) : + M / p ^ M.factorization p ≠ 0 := + (Nat.ordCompl_pos p hM).ne' + +lemma pow_div_eq_pow_sub_div_ordCompl (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) + (hv : M.factorization p ≤ N) : + (p : ℚ)^N / M = (p : ℚ)^(N - M.factorization p) / (M / p ^ M.factorization p) := by + set e := M.factorization p with he + set M' := M / p ^ e with hM' + have hdecomp : p ^ e * M' = M := Nat.ordProj_mul_ordCompl_eq_self M p + have hM'_ne : M' ≠ 0 := ordCompl_ne_zero p M hp hM + have hM_cast : (M : ℚ) = (p ^ e : ℕ) * (M' : ℕ) := by rw [← hdecomp]; simp + rw [hM_cast] + have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr hp.ne_zero + have hpe_ne : (p : ℚ) ^ e ≠ 0 := pow_ne_zero e hp_ne + rw [div_mul_eq_div_div] + congr 1 + · rw [Nat.cast_pow, div_eq_iff hpe_ne, ← pow_add, Nat.sub_add_cancel hv] + · field_simp; simp + +lemma den_pow_div_dvd (p M' k : ℕ) (_hM' : M' ≠ 0) : + ((p : ℚ)^k / M').den ∣ M' := by + have h1 : ((p : ℚ) ^ k / M') = Rat.divInt (p ^ k : ℤ) (M' : ℤ) := by norm_cast; simp + rw [h1] + have h2 : ↑(Rat.divInt (p ^ k : ℤ) (M' : ℤ)).den ∣ (M' : ℤ) := by apply Rat.den_dvd + norm_cast at h2 ⊢ + +lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) + (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ)^N / M) := by + set M' := M / p ^ M.factorization p with hM'_def + have hM'_ne : M' ≠ 0 := ordCompl_ne_zero p M hp hM + have hM'_cop : M'.Coprime p := ordCompl_coprime_of_prime p M hp hM + rw [pow_div_eq_pow_sub_div_ordCompl p M N hp hM hv] + have hcast : (M : ℚ) / (p : ℚ) ^ M.factorization p = (M' : ℚ) := by + rw [hM'_def] + simp only [← Nat.cast_pow] + rw [Nat.cast_div_charZero (Nat.ordProj_dvd M p)] + rw [hcast] + have hdvd : ((p : ℚ)^(N - M.factorization p) / M').den ∣ M' := + den_pow_div_dvd p M' (N - M.factorization p) hM'_ne + exact pIntegral_of_den_dvd_coprime p _ M' hdvd hM'_cop + +lemma valuation_bound (p n : ℕ) (hp : p.Prime) (_hn : n ≥ 1) : + (n + 1).factorization p ≤ n := + Nat.factorization_le_of_le_pow <| + calc n + 1 = (n + 1).choose 1 := by simp + _ ≤ 2 ^ n := Nat.choose_succ_le_two_pow n 1 + _ ≤ p ^ n := Nat.pow_le_pow_left hp.two_le n + +lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : + pIntegral p ((p : ℚ)^(2*k) / (2*k + 1)) := by + have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by push_cast; ring + rw [h] + apply pIntegral_pow_div p (2*k + 1) (2*k) hp + · omega + · exact valuation_bound p (2*k) hp (by omega) + +lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : + pIntegral 2 (bernoulli 1 * (2*k) * (2 : ℚ)^(2*k - 1) / (2*k)) := by + have h1 : bernoulli 1 = -1 / 2 := by norm_num [bernoulli_one] + rw [h1] + have h2 : ((-1 / 2 : ℚ) * (2 * k : ℚ) * (2 : ℚ) ^ (2 * k - 1) / (2 * k : ℚ)) = + (-((2 : ℚ) ^ (2 * k - 1)) / 2 : ℚ) := by + have h3 : (2 * k : ℚ) ≠ 0 := by positivity + field_simp [h3] + rw [h2] + have h3 : (-((2 : ℚ) ^ (2 * k - 1)) / 2 : ℚ) = (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 := by norm_cast + rw [h3] + have h4 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by + have h8 : (2 : ℤ) ^ (2 * k - 1) = (2 : ℤ) ^ (2 * k - 2) * 2 := by + have h9 : (2 * k - 1 : ℕ) = (2 * k - 2 : ℕ) + 1 := by omega + have h10 : (2 : ℤ) ^ (2 * k - 1) = (2 : ℤ) ^ ((2 * k - 2 : ℕ) + 1) := by rw [h9] + rw [h10] + have h11 : (2 : ℤ) ^ ((2 * k - 2 : ℕ) + 1) = (2 : ℤ) ^ (2 * k - 2) * 2 := by + simp [pow_add, pow_one, mul_comm] + rw [h11] + have h9 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by + have h10 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) = (-((2 : ℤ) ^ (2 * k - 2) : ℤ) * 2 : ℚ) := by + norm_cast at h8 ⊢ + simp [h8] + rw [h10] + field_simp + exact h9 + rw [h4] + norm_num [pIntegral] + +lemma i1_term_simplify (k p : ℕ) (hk : k > 0) : + bernoulli 1 * (2*k) * (p : ℚ)^(2*k - 1) / (2*k) = -(p : ℚ)^(2*k - 1) / 2 := by + have h1 : bernoulli 1 = (-1 : ℚ) / 2 := by norm_num [bernoulli] + rw [h1] + have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega + field_simp [h2] + +lemma two_coprime_odd_prime (p : ℕ) (hp : p.Prime) (hp2 : p ≠ 2) : + Nat.Coprime 2 p := + Odd.coprime_two_left (Nat.Prime.odd_of_ne_two hp hp2) + +lemma den_neg_pow_div_two_dvd_two (k p : ℕ) : + (-(p : ℚ)^(2*k - 1) / 2).den ∣ 2 := by + rw [neg_div, Rat.den_neg_eq_den, ← Nat.cast_pow] + conv_lhs => rw [show (2 : ℚ) = (2 : ℕ) from rfl, Rat.natCast_div_eq_divInt] + have h := Rat.den_dvd (p ^ (2 * k - 1)) 2 + exact Int.natCast_dvd_natCast.mp h + +lemma pIntegral_neg_pow_div_two (k p : ℕ) (hp : p.Prime) (hp2 : p ≠ 2) : + pIntegral p (-(p : ℚ)^(2*k - 1) / 2) := by + unfold pIntegral + exact Nat.Coprime.of_dvd_left (den_neg_pow_div_two_dvd_two k p) (two_coprime_odd_prime p hp hp2) + +lemma pIntegral_i1_term_p_odd (k p : ℕ) (hk : k > 0) (hp : p.Prime) (hp2 : p ≠ 2) : + pIntegral p (bernoulli 1 * (2*k) * (p : ℚ)^(2*k - 1) / (2*k)) := by + rw [i1_term_simplify k p hk] + exact pIntegral_neg_pow_div_two k p hp hp2 + +lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : + pIntegral p (bernoulli 1 * (2*k) * (p : ℚ)^(2*k - 1) / (2*k)) := by + obtain rfl | hp2 := eq_or_ne p 2 + · exact pIntegral_i1_term_p_eq_two k hk + · exact pIntegral_i1_term_p_odd k p hk hp hp2 + +lemma pIntegral_odd_term (i _p : ℕ) (hi_odd : Odd i) (hi_ge3 : i ≥ 3) : + bernoulli i = 0 := by + have h1 : 1 < i := by grind + aesop + +lemma pIntegral_mul (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : + pIntegral p (x * y) := + Nat.Coprime.of_dvd_left (Rat.mul_den_dvd x y) (Nat.Coprime.mul_left hx hy) + +lemma pIntegral_mul_int (p : ℕ) (x : ℚ) (z : ℤ) (hx : pIntegral p x) : + pIntegral p (z * x) := by + have h_z_den : (z : ℚ).den = 1 := by aesop + have h_den_dvd : (z * x : ℚ).den ∣ (z : ℚ).den * x.den := Rat.mul_den_dvd z x + have h1 : (z * x : ℚ).den ∣ x.den := by aesop + have h2 : Nat.Coprime (z * x : ℚ).den p := Nat.Coprime.coprime_dvd_left h1 hx + aesop + +lemma pIntegral_mul_nat (p : ℕ) (x : ℚ) (n : ℕ) (hx : pIntegral p x) : + pIntegral p (n * x) := + pIntegral_mul_int p x n hx + +lemma valuation_bound_d_plus_1_p2_d2 : + (2 + 1).factorization 2 ≤ 2 - 1 := by norm_num + +lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) := by + have h : ∀ n : ℕ, n ≥ 3 → n + 1 ≤ 2 ^ (n - 1) := by + intro n hn + induction' hn with n hn IH + · norm_num + · cases n with + | zero => contradiction + | succ n => + cases n with + | zero => contradiction + | succ n => + cases n with + | zero => contradiction + | succ n => + simp [pow_succ, mul_assoc] at IH ⊢ + omega + exact h d hd + +lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : + d + 1 ≤ p ^ (d - 1) := by + have h1 : d + 1 ≤ p ^ (d - 1) := by + have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by + intro d hd + induction' hd with d hd IH + · norm_num + omega + · cases d with + | zero => contradiction + | succ d => + cases d with + | zero => contradiction + | succ d => + simp_all [Nat.pow_succ, Nat.mul_assoc] + have h4 : p ^ d ≥ 1 := Nat.one_le_pow _ _ (by omega) + nlinarith + exact h2 d hd + exact h1 + +lemma pIntegral_pow_div_factor (k m p : ℕ) (_hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : + pIntegral p ((p : ℚ)^(2*(k-m)) / (2*(↑k - ↑m) + 1)) := by + set d := k - m with hd + have hd_pos : d ≥ 1 := by omega + have hcast : (↑k : ℚ) - ↑m = ↑d := by rw [hd, Nat.cast_sub (le_of_lt hm_lt)] + rw [hcast] + have hcast2 : (2 : ℚ) * ↑d + 1 = ↑(2 * d + 1) := by push_cast; ring + rw [hcast2] + apply pIntegral_pow_div p (2 * d + 1) (2 * d) hp + · omega + · have hn : 2 * d ≥ 1 := by omega + exact valuation_bound p (2 * d) hp hn + +lemma pIntegral_T1 (k m p : ℕ) (_hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) + (ih : pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : + pIntegral p ((bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k).choose (2*m)) * + (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1)) := by + have h_eq : (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k).choose (2*m)) * + (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1) = + ((bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k).choose (2*m))) * + ((p : ℚ)^(2*(k-m)) / (2*(k-m) + 1)) := by ring + rw [h_eq] + apply pIntegral_mul + · apply pIntegral_mul + · exact ih + · exact pIntegral_of_int p ((2*k).choose (2*m)) + · exact pIntegral_pow_div_factor k m p hm_pos hm_lt hp + +lemma valuation_three_le_one (p : ℕ) (hp : p.Prime) : (3 : ℕ).factorization p ≤ 1 := by + rcases hp.eq_two_or_odd with rfl | hp_odd + · exact valuation_bound_d_plus_1_p2_d2 + · rcases eq_or_ne p 3 with rfl | hp_ne_3 + · simp [Nat.Prime.factorization_self hp] + · have h : ¬ p ∣ 3 := by + intro hdvd + have hp_le_3 : p ≤ 3 := Nat.le_of_dvd (by omega) hdvd + have hp_ge_2 : p ≥ 2 := hp.two_le + interval_cases p <;> simp_all + simp [Nat.factorization_eq_zero_of_not_dvd h] + +lemma two_d_plus_one_le_pow_two (d : ℕ) (hd : d ≥ 2) : 2 * d + 1 ≤ 2 ^ (2 * d - 1) := by + have h2d_ge_3 : 2 * d ≥ 3 := by omega + have := pow_two_ge_succ_of_ge_three (2 * d) h2d_ge_3 + omega + +lemma valuation_bound_2d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 1) : + (2 * d + 1).factorization p ≤ 2 * d - 1 := by + rcases eq_or_lt_of_le hd with rfl | hd' + · simp only [mul_one] + exact valuation_three_le_one p hp + · have hd2 : d ≥ 2 := hd' + apply Nat.factorization_le_of_le_pow + calc 2 * d + 1 ≤ 2 ^ (2 * d - 1) := two_d_plus_one_le_pow_two d hd2 + _ ≤ p ^ (2 * d - 1) := Nat.pow_le_pow_left hp.two_le _ + +lemma pIntegral_T2 (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : + pIntegral p (vonStaudtIndicator (2*m) p * ((2*k).choose (2*m)) * (p : ℚ)^(2*(k-m) - 1) / + (2*(k-m) + 1)) := by + set d := k - m with hd_def + have hd_pos : d ≥ 1 := by omega + unfold vonStaudtIndicator + split_ifs with he + · simp only [one_mul] + have hd_eq : (2 : ℚ) * (↑k - ↑m) + 1 = ↑(2 * d + 1) := by + simp only [hd_def] + have hkm : m ≤ k := le_of_lt hm_lt + rw [← Nat.cast_sub hkm] + push_cast + ring + rw [hd_eq] + have hN_ne_zero : (2 * d + 1 : ℕ) ≠ 0 := by omega + have hvaluation : (2 * d + 1).factorization p ≤ 2 * d - 1 := + valuation_bound_2d_plus_1 p d hp hd_pos + have h_pow_pIntegral : pIntegral p ((p : ℚ)^(2 * d - 1) / ↑(2 * d + 1)) := + pIntegral_pow_div p (2 * d + 1) (2 * d - 1) hp hN_ne_zero hvaluation + have h_rw : (↑((2 * k).choose (2 * m)) : ℚ) * ↑p ^ (2 * d - 1) / ↑(2 * d + 1) = + (↑((2 * k).choose (2 * m)) : ℚ) * (↑p ^ (2 * d - 1) / ↑(2 * d + 1)) := by ring + rw [h_rw] + exact pIntegral_mul_nat p ((p : ℚ)^(2 * d - 1) / ↑(2 * d + 1)) ((2*k).choose (2*m)) h_pow_pIntegral + · simp only [zero_mul, zero_div] + exact pIntegral_of_int p 0 + +lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : + B * (p : ℚ)^(2*d) = (B + I / p) * (p : ℚ)^(2*d) - I * (p : ℚ)^(2*d - 1) := by + have h1 : (B + I / p) * (p : ℚ)^(2*d) - I * (p : ℚ)^(2*d - 1) = + B * (p : ℚ)^(2*d) + I * (p : ℚ)^(2*d - 1) - I * (p : ℚ)^(2*d - 1) := by + have h2 : (B + I / p) * (p : ℚ)^(2*d) = B * (p : ℚ)^(2*d) + I * (p : ℚ)^(2*d - 1) := by + by_cases h : (p : ℚ) = 0 + · have h3 : (p : ℕ) = 0 := by norm_cast at h ⊢ + have h4 : 2 * d ≥ 1 := by omega + have h5 : (p : ℚ)^(2*d) = 0 := by rw [h3]; norm_cast; simp; omega + have h6 : (p : ℚ)^(2*d - 1) = 0 := by + have h7 : (2 * d : ℕ) - 1 ≥ 0 := by omega + have h8 : (p : ℕ) = 0 := by norm_cast at h ⊢ + rw [h8]; norm_cast; simp; omega + simp_all + · have h3 : (p : ℚ) ≠ 0 := by exact_mod_cast h + calc (B + I / p) * (p : ℚ)^(2*d) = B * (p : ℚ)^(2*d) + (I / p) * (p : ℚ)^(2*d) := by ring + _ = B * (p : ℚ)^(2*d) + I * (p : ℚ)^(2*d - 1) := by + have h4 : (I / p : ℚ) * (p : ℚ)^(2*d) = I * (p : ℚ)^(2*d - 1) := by + calc (I / p : ℚ) * (p : ℚ)^(2*d) = I * (p : ℚ)^(2*d) / p := by ring + _ = I * (p : ℚ)^(2*d - 1) := by + have h5 : (p : ℚ)^(2*d) = (p : ℚ)^(2*d - 1) * p := by + have h7 : (2 * d : ℕ) - 1 + 1 = 2 * d := by omega + calc (p : ℚ)^(2*d) = (p : ℚ)^((2*d - 1) + 1) := by rw [h7] + _ = (p : ℚ)^(2*d - 1) * (p : ℚ)^1 := by rw [pow_add] + _ = (p : ℚ)^(2*d - 1) * p := by simp [pow_one] + rw [h5] + field_simp [h3] + rw [h4] + rw [h2] + linarith + +lemma even_term_eq_T1_sub_T2 (k m p : ℕ) (hm_lt : m < k) : + (bernoulli (2*m) * ((2*k).choose (2*m)) * (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1) : ℚ) = + (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k).choose (2*m)) * + (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1) - + vonStaudtIndicator (2*m) p * ((2*k).choose (2*m)) * (p : ℚ)^(2*(k-m) - 1) / (2*(k-m) + 1) := by + have hd : k - m ≥ 1 := by omega + have h := core_algebraic_identity (bernoulli (2*m)) (vonStaudtIndicator (2*m) p) p (k - m) hd + set C := ((2*k).choose (2*m) : ℚ) + set N := (2 * (k - m) + 1 : ℚ) + calc bernoulli (2*m) * C * (p : ℚ)^(2*(k-m)) / N + = (bernoulli (2*m) * (p : ℚ)^(2*(k-m))) * C / N := by ring + _ = ((bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * (p : ℚ)^(2*(k-m)) - + vonStaudtIndicator (2*m) p * (p : ℚ)^(2*(k-m) - 1)) * C / N := by rw [h] + _ = (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * C * (p : ℚ)^(2*(k-m)) / N - + vonStaudtIndicator (2*m) p * C * (p : ℚ)^(2*(k-m) - 1) / N := by ring + +lemma pIntegral_sub (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : + pIntegral p (x - y) := + Nat.Coprime.coprime_dvd_left (Rat.sub_den_dvd x y) (Nat.Coprime.mul_left hx hy) + +lemma pIntegral_even_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) + (ih : pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : + pIntegral p (bernoulli (2*m) * ((2*k).choose (2*m)) * (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1)) := by + rw [even_term_eq_T1_sub_T2 k m p hm_lt] + exact pIntegral_sub p _ _ (pIntegral_T1 k m p hk hm_pos hm_lt hp ih) + (pIntegral_T2 k m p hk hm_pos hm_lt hp) + +theorem i1_term_forms_eq (k p : ℕ) (hk : k > 0) : + bernoulli 1 * (2 * ↑k) * (p : ℚ) ^ (2 * k - 1) / (2 * ↑k) = + bernoulli 1 * ↑(2 * k + 1) * (p : ℚ) ^ (2 * k - 1) / (2 * ↑k + 1) := by + have h1 : (2 : ℚ) * k ≠ 0 := by positivity + have h2 : (2 : ℚ) * k + 1 ≠ 0 := by positivity + simp only [show (↑(2 * k + 1) : ℚ) = 2 * ↑k + 1 by norm_cast] + field_simp [h1, h2] + +lemma pIntegral_i1_term_in_sum (k p : ℕ) (hk : k > 0) (hp : p.Prime) : + pIntegral p (bernoulli 1 * ((2*k + 1).choose 1) * (p : ℚ)^(2*k - 1) / (2*k + 1)) := by + simp only [Nat.choose_one_right] + rw [← i1_term_forms_eq k p hk] + exact pIntegral_i1_term k p hk hp + +lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : + (d + 1).factorization p ≤ d - 1 := by + obtain hp2 | hp3 := hp.eq_two_or_odd + · subst hp2 + obtain rfl | hd3 := eq_or_lt_of_le hd + · exact valuation_bound_d_plus_1_p2_d2 + · apply Nat.factorization_le_of_le_pow + exact pow_two_ge_succ_of_ge_three _ hd3 + · apply Nat.factorization_le_of_le_pow + apply pow_ge_succ_of_ge_three + · have hne2 : p ≠ 2 := fun h => by simp [h] at hp3 + have h1lt : 1 < p := hp.one_lt + omega + · exact hd + +lemma nat_sub_add_eq (k m : ℕ) (hm_lt : m < k) : + 2 * k + 1 - 2 * m = 2 * k - 2 * m + 1 := by grind + +lemma denom_cast_eq (k m : ℕ) (hm_lt : m < k) : + ((2 * k - 2 * m + 1 : ℕ) : ℚ) = 2 * ↑k - 2 * ↑m + 1 := by + have h : 2 * m ≤ 2 * k := by omega + simp only [Nat.cast_sub h, Nat.cast_add, Nat.cast_mul, Nat.cast_ofNat, Nat.cast_one] + +lemma choose_mul_succ_rat (k m : ℕ) : + ((2*k).choose (2*m) : ℚ) * ((2*k + 1 : ℕ) : ℚ) = + ((2*k + 1).choose (2*m)) * ((2*k + 1 - 2*m) : ℕ) := by + have h := Nat.choose_mul_succ_eq (2*k) (2*m) + exact_mod_cast h + +lemma choose_div_core (k m : ℕ) (hm_lt : m < k) : + ((2*k + 1).choose (2*m) : ℚ) / (2*k + 1) = + ((2*k).choose (2*m) : ℚ) / (2*k - 2*m + 1) := by + have h_denom : (2 * (k : ℚ) - 2 * m + 1) = ((2 * k - 2 * m + 1 : ℕ) : ℚ) := + (denom_cast_eq k m hm_lt).symm + conv_rhs => rw [h_denom] + have h_nat := (nat_sub_add_eq k m hm_lt).symm + simp only [h_nat] + have h_lhs_denom : (2 * (k : ℚ) + 1) = ((2 * k + 1 : ℕ) : ℚ) := by push_cast; ring + conv_lhs => rw [h_lhs_denom] + have hk_pos : ((2*k + 1 : ℕ) : ℚ) ≠ 0 := by positivity + have hd_pos : ((2*k + 1 - 2*m : ℕ) : ℚ) ≠ 0 := by simp only [Nat.cast_ne_zero]; omega + rw [div_eq_div_iff hk_pos hd_pos] + exact (choose_mul_succ_rat k m).symm + +lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : + ((2*k + 1).choose (2*m) : ℚ) * x / (2*k + 1) = + ((2*k).choose (2*m) : ℚ) * x / (2*k - 2*m + 1) := by + have h := choose_div_core k m hm_lt + rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, + mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] + +lemma pIntegral_case_one (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt : m < k) + (hp : p.Prime) (hd : 2 * k - 2 * m ≥ 2) : + pIntegral p (((2*k).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m - 1) / (2*k - 2*m + 1)) := by + set d := 2 * k - 2 * m with hd_def + have hd_ne_zero : d ≠ 0 := by omega + have hd_plus_one_ne_zero : d + 1 ≠ 0 := by omega + have h_exp : 2 * k - 2 * m - 1 = d - 1 := by omega + have hkm : 2 * m ≤ 2 * k := by omega + have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by + have heq : d = 2 * k - 2 * m := rfl + rw [heq, Nat.cast_add (2 * k - 2 * m) 1, Nat.cast_sub hkm] + push_cast + ring + rw [h_exp, h_denom_rat] + have h_pow_integral : pIntegral p ((p : ℚ)^(d - 1) / ((d + 1 : ℕ) : ℚ)) := by + apply pIntegral_pow_div p (d + 1) (d - 1) hp hd_plus_one_ne_zero + exact valuation_bound_d_plus_1 p d hp hd + have h_eq : ((2*k).choose (2*m) : ℚ) * (p : ℚ)^(d - 1) / ((d + 1 : ℕ) : ℚ) = + ((2*k).choose (2*m) : ℕ) * ((p : ℚ)^(d - 1) / ((d + 1 : ℕ) : ℚ)) := by ring + rw [h_eq] + exact pIntegral_mul_nat p _ _ h_pow_integral + +lemma pIntegral_second_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) + (hp : p.Prime) : + pIntegral p (vonStaudtIndicator (2*m) p * ((2*k + 1).choose (2*m)) * (p : ℚ)^(2*k - 2*m - 1) / + (2*k + 1)) := by + unfold vonStaudtIndicator + split_ifs with h + · simp only [one_mul] + have hd : 2 * k - 2 * m ≥ 2 := by omega + rw [choose_div_simplify k m _ hm_lt] + exact pIntegral_case_one k m p hk hm_pos hm_lt hp hd + · simp only [zero_mul, zero_div] + unfold pIntegral + rw [Rat.den_zero] + exact Nat.coprime_one_left_iff p |>.mpr trivial + +lemma even_term_decomposition_identity (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) : + (bernoulli (2*m) * ((2*k + 1).choose (2*m)) * (p : ℚ)^(2*k - 2*m) / (2*k + 1) : ℚ) = + (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k + 1).choose (2*m)) * + (p : ℚ)^(2*k - 2*m) / (2*k + 1) - + vonStaudtIndicator (2*m) p * ((2*k + 1).choose (2*m)) * (p : ℚ)^(2*k - 2*m - 1) / (2*k + 1) := by + have h2 : (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - + vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k + 1) = (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / + (2 * k + 1) : ℚ) := by + have h3 : (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - + vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k + 1) = (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / + (2 * k + 1)) + (vonStaudtIndicator (2 * m) p / p * ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) - + (vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k + 1)) := by ring_nf + rw [h3] + have h4 : (vonStaudtIndicator (2 * m) p / p * ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) - + (vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k + 1)) = 0 := by + by_cases h5 : (p - 1 : ℕ) ∣ (2 * m) + · have h6 : vonStaudtIndicator (2 * m) p = (1 : ℚ) := by simp [vonStaudtIndicator, h5] + rw [h6] + have h7 : (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / + (2 * k + 1) - + (1 : ℚ) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k + 1) = 0 := by + have h10 : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) ^ (2 * k - 2 * m - 1) * (p : ℚ) := by + have h102 : (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1 : ℕ) + 1 := by omega + have h104 : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) ^ ((2 * k - 2 * m - 1 : ℕ) + 1) := by + rw [h102] + simp [pow_add, pow_one] + rw [h104] + simp [pow_add, pow_one] + have h11 : (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / + (2 * k + 1) = + (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * + ((p : ℚ) ^ (2 * k - 2 * m - 1) * (p : ℚ)) / (2 * k + 1) := by rw [h10] + rw [h11] + have h12 : (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * + ((p : ℚ) ^ (2 * k - 2 * m - 1) * (p : ℚ)) / (2 * k + 1) = + (1 : ℚ) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k + 1) := by + have h121 : (p : ℚ) ≠ 0 := by + by_contra h121 + have h122 : (p : ℕ) = 0 := by norm_cast at h121 ⊢ + have h123 : p > 0 := by by_contra _; simp_all + omega + field_simp [h121] + rw [h12] + ring_nf + linarith + · have h6 : vonStaudtIndicator (2 * m) p = (0 : ℚ) := by simp [vonStaudtIndicator, h5] + rw [h6] + norm_num + linarith + linarith + +lemma pIntegral_coeff_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) + (hp : p.Prime) : + pIntegral p (((2*k + 1).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m) / (2*k + 1)) := by + have hsimp := choose_div_simplify k m ((p : ℚ)^(2*k - 2*m)) hm_lt + rw [hsimp] + have hd_ge_2 : 2 * k - 2 * m ≥ 2 := by omega + have hp_factor : ((2*k).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m) / (2*k - 2*m + 1) = + (p : ℚ) * (((2*k).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m - 1) / + (2*k - 2*m + 1)) := by + have hpow : (p : ℚ)^(2*k - 2*m) = (p : ℚ) * (p : ℚ)^(2*k - 2*m - 1) := by + have heq : 2*k - 2*m - 1 + 1 = 2*k - 2*m := by omega + conv_lhs => rw [← heq, pow_succ'] + rw [hpow] + ring + rw [hp_factor] + apply pIntegral_mul + · exact pIntegral_of_int p p + · exact pIntegral_case_one k m p hk hm_pos hm_lt hp hd_ge_2 + +lemma pIntegral_first_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) + (hp : p.Prime) + (ih : pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : + pIntegral p ((bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k + 1).choose (2*m)) * + (p : ℚ)^(2*k - 2*m) / (2*k + 1)) := by + rw [show (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k + 1).choose (2*m)) * + (p : ℚ)^(2*k - 2*m) / (2*k + 1) = (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * + (((2*k + 1).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m) / (2*k + 1)) by ring] + exact pIntegral_mul p _ _ ih (pIntegral_coeff_term k m p hk hm_pos hm_lt hp) + +lemma pIntegral_even_term_in_sum (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) + (hp : p.Prime) (ih : pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : + pIntegral p (bernoulli (2*m) * ((2*k + 1).choose (2*m)) * (p : ℚ)^(2*k - 2*m) / (2*k + 1)) := by + rw [even_term_decomposition_identity k m p hk hm_pos hm_lt] + exact pIntegral_sub p _ _ (pIntegral_first_term k m p hk hm_pos hm_lt hp ih) + (pIntegral_second_term k m p hk hm_pos hm_lt hp) + +lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) + (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : + pIntegral p (∑ i ∈ Finset.range (2*k), + bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k - i) / (2*k + 1)) := by + apply pIntegral_sum + intro i hi + rw [Finset.mem_range] at hi + rcases i with _ | _ | i + · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] + exact pIntegral_i0_term k p hk hp + · simp only [zero_add] + exact pIntegral_i1_term_in_sum k p hk hp + · set j := i + 2 with hj_def + have hj_ge2 : j ≥ 2 := by omega + have hj_lt : j < 2*k := by omega + rcases Nat.even_or_odd j with ⟨m, hm⟩ | hodd + · have hm_pos : m ≥ 1 := by omega + have hm_lt : m < k := by omega + have hj_eq : j = 2 * m := by omega + simp only [hj_eq] + exact pIntegral_even_term_in_sum k m p hk hm_pos hm_lt hp (ih m (by omega) hm_lt) + · have hj_ge3 : j ≥ 3 := by rcases hodd with ⟨r, hr⟩; omega + simp only [pIntegral_odd_term j p hodd hj_ge3, zero_mul, zero_div] + unfold pIntegral + simp only [Rat.den_zero] + exact Nat.coprime_one_left_iff p |>.mpr trivial + +lemma power_sum_eq_faulhaber (k p : ℕ) : + (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = + ∑ i ∈ Finset.range (2*k + 1), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / + (2*k + 1) := by + grind only [sum_range_pow] + +lemma faulhaber_top_term (k p : ℕ) : + bernoulli (2*k) * ((2*k + 1).choose (2*k)) * (p : ℚ)^(2*k + 1 - 2*k) / (2*k + 1) = + p * bernoulli (2*k) := by + have h1 : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by + have h2 : (2 * k + 1).choose (2 * k) = (2 * k + 1).choose 1 := by + rw [← Nat.choose_symm_of_eq_add] + ring_nf + rw [h2, Nat.choose_one_right] + have h2 : (2 * k + 1 - 2 * k : ℕ) = 1 := by omega + rw [h1, h2, pow_one] + have h4 : (2 * k + 1 : ℚ) ≠ 0 := by positivity + field_simp [h4] + ring_nf + field_simp [h4] + norm_cast + ring_nf + +lemma int_sum_cast_eq_zmod_sum (p l : ℕ) : + (↑(∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ l) : ZMod p) = + ∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l := by simp + +lemma int_indicator_cast_eq_zmod (p l : ℕ) : + (↑(if (p - 1 : ℕ) ∣ l then (1 : ℤ) else 0) : ZMod p) = + if (p - 1 : ℕ) ∣ l then (1 : ZMod p) else 0 := by + split_ifs with h <;> simp [Int.cast_one, Int.cast_zero] + +lemma power_sum_indicator_divisible_by_p (k p : ℕ) (_hk : k > 0) (hp : p.Prime) : + ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) + + (if (p - 1 : ℕ) ∣ (2*k) then 1 else 0) = p * T := by + have h_cast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) + + (if (p - 1 : ℕ) ∣ (2*k) then 1 else 0)) : ZMod p) = 0 := by + simp only [Int.cast_add] + rw [int_sum_cast_eq_zmod_sum, int_indicator_cast_eq_zmod] + exact power_sum_add_indicator_eq_zero p (2*k) hp + rw [ZMod.intCast_zmod_eq_zero_iff_dvd] at h_cast + exact h_cast + +lemma faulhaber_split_top_term (k p : ℕ) : + (∑ i ∈ Finset.range (2*k + 1), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / + (2*k + 1)) = + (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / + (2*k + 1)) + + bernoulli (2*k) * ((2*k + 1).choose (2*k)) * (p : ℚ)^(2*k + 1 - 2*k) / (2*k + 1) := by + have h3 : Finset.range (2 * k + 1) = Finset.range (2 * k) ∪ {2 * k} := by + ext x; simp [Finset.mem_range]; omega + have h4 : Disjoint (Finset.range (2 * k)) ({2 * k} : Finset ℕ) := by + simp [Finset.disjoint_left]; omega + rw [h3, Finset.sum_union h4, Finset.sum_singleton] + +lemma rat_power_sum_eq_filter_ne_zero (k p : ℕ) (hk : k > 0) : + (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by + have h1 : (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = + ∑ v ∈ Finset.range p, if v = 0 then 0 else (v : ℚ)^(2*k) := by + apply Finset.sum_congr rfl + intro v _ + by_cases h : v = 0 + · simp [h] + have : k ≠ 0 := by omega + simp [this] + · have h2 : (v : ℚ) ≠ 0 := by norm_cast + simp [h] + have h2 : ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ)^(2*k)) = + ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) := by + calc ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ)^(2*k)) = + ∑ v ∈ Finset.range p, (if v ≠ 0 then (v : ℚ)^(2*k) else 0) := by + apply Finset.sum_congr rfl + intro v _ + by_cases h : v = 0 <;> simp [h] + _ = ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) := by rw [Finset.sum_filter] + have h3 : ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) = + ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by simp [Finset.sum_filter] + calc (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = + ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ)^(2*k)) := by rw [h1] + _ = ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) := by rw [h2] + _ = ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by rw [h3] + +lemma remainder_div_p (k p : ℕ) (hp : p.Prime) : + (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / + (2*k + 1)) / p = + (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k - i) / + (2*k + 1)) := by + have h0 : (∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = + ∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by + have h1 : ∀ i ∈ Finset.range (2 * k), ((bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = + (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k - i) / + (2 * k + 1 : ℚ) := by + intro i hi + have h2 : i < 2 * k := Finset.mem_range.mp hi + have h5 : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero hp + have h6 : ((p : ℚ) : ℚ) ^ (2 * k + 1 - i : ℕ) = (p : ℚ) ^ ((2 * k - i : ℕ) + 1 : ℕ) := by + have h7 : (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 := by omega + rw [h7] + rw [h6] + have h7 : ((p : ℚ) : ℚ) ^ ((2 * k - i : ℕ) + 1 : ℕ) = (p : ℚ) ^ (2 * k - i : ℕ) * (p : ℚ) := by + rw [pow_succ] + rw [h7] + field_simp [h5] + calc (∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = + ∑ i ∈ Finset.range (2 * k), ((bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) := by rw [Finset.sum_div] + _ = ∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by + apply Finset.sum_congr rfl + intro i hi + rw [h1 i hi] + exact_mod_cast h0 + +lemma algebraic_rearrangement (k p : ℕ) (T : ℤ) (hp : p.Prime) + (hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) + vonStaudtIndicator (2*k) p = + (p : ℚ) * (T : ℚ)) + (hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) = + (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / + (2*k + 1)) + p * bernoulli (2*k)) : + bernoulli (2*k) + vonStaudtIndicator (2*k) p / p = + T - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / + (2*k + 1)) / p := by + have h7 : bernoulli (2*k) + (1 / (p : ℚ)) * vonStaudtIndicator (2*k) p = + (T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * + (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) := by + have h8 : (p : ℚ) ≠ 0 := by norm_cast; simp_all [hp.ne_zero] + have h9 : (p : ℚ) * bernoulli (2*k) + (p : ℚ) * ((1 / (p : ℚ)) * vonStaudtIndicator (2*k) p) = + (p : ℚ) * ((T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2*k), bernoulli i * + ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / (2*k + 1))) := by + calc (p : ℚ) * bernoulli (2*k) + (p : ℚ) * ((1 / (p : ℚ)) * vonStaudtIndicator (2*k) p) = + (p : ℚ) * bernoulli (2*k) + vonStaudtIndicator (2*k) p := by field_simp [h8] + _ = (p : ℚ) * bernoulli (2*k) + vonStaudtIndicator (2*k) p := by rfl + _ = (p : ℚ) * (T : ℚ) - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * + (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) := by linarith + _ = (p : ℚ) * ((T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2*k), bernoulli i * + ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / (2*k + 1))) := by field_simp [h8] + have h11 : bernoulli (2*k) + (1 / (p : ℚ)) * vonStaudtIndicator (2*k) p = + (T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * + (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) := by + apply mul_left_cancel₀ (show (p : ℚ) ≠ 0 by exact_mod_cast hp.ne_zero) + linarith + linarith + have h8 : bernoulli (2*k) + vonStaudtIndicator (2*k) p / p = + T - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / + (2*k + 1)) / p := by + have h9 : (p : ℚ) ≠ 0 := by norm_cast; simp_all [hp.ne_zero] + calc bernoulli (2*k) + vonStaudtIndicator (2*k) p / p = + bernoulli (2*k) + (1 / (p : ℚ)) * vonStaudtIndicator (2*k) p := by field_simp [h9] + _ = (T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * + (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) := by exact h7 + _ = T - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * + (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) / p := by field_simp [h9] + exact h8 + +lemma divisibility_to_rat_eq (k p : ℕ) (T : ℤ) (_hp : p.Prime) + (hT : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) + + (if (p - 1 : ℕ) ∣ (2*k) then 1 else 0) = p * T) : + (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) + vonStaudtIndicator (2*k) p = p * T := by + have h1 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) : ℚ) = + ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by norm_cast + have h2 : ((if (p - 1 : ℕ) ∣ (2*k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = + vonStaudtIndicator (2*k) p := by + split_ifs at * <;> simp_all [vonStaudtIndicator] + have h3 : ((p : ℤ) * T : ℚ) = p * T := by norm_cast + have h4 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) : ℚ) + + ((if (p - 1 : ℕ) ∣ (2*k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = (p : ℚ) * T := by + norm_cast at hT ⊢ + calc (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) + vonStaudtIndicator (2*k) p = + ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) : ℚ) + + ((if (p - 1 : ℕ) ∣ (2*k) then (1 : ℤ) else (0 : ℤ)) : ℚ) := by rw [h1, h2] + _ = (p : ℚ) * T := by rw [h4] + _ = p * T := by simp + +lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Prime) : + ∃ T : ℤ, bernoulli (2*k) + vonStaudtIndicator (2*k) p / p = + T - (∑ i ∈ Finset.range (2*k), + bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k - i) / (2*k + 1)) := by + obtain ⟨T, hT⟩ := power_sum_indicator_divisible_by_p k p hk hp + use T + have hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) + vonStaudtIndicator (2*k) p = + p * T := divisibility_to_rat_eq k p T hp hT + have hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) = + (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * + (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) + p * bernoulli (2*k) := by + rw [← rat_power_sum_eq_filter_ne_zero k p hk, power_sum_eq_faulhaber, + faulhaber_split_top_term, faulhaber_top_term] + have hAlg := algebraic_rearrangement k p T hp hT' hFaul + rw [hAlg, remainder_div_p k p hp] + +lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) : + (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den.Coprime p := by + induction k using Nat.strong_induction_on with + | _ k ih => + obtain ⟨T, hT⟩ := bernoulli_plus_indicator_rearrangement k p hk hp + rw [hT] + have hT_int : pIntegral p (T : ℚ) := pIntegral_of_int p T + have hR : pIntegral p (∑ i ∈ Finset.range (2*k), + bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k - i) / (2*k + 1)) := by + apply pIntegral_remainder k p hk hp + intro m hm_pos hm_lt + exact ih m hm_lt hm_pos + exact pIntegral_sub p T _ hT_int hR + +lemma pIntegral_add (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : + pIntegral p (x + y) := + Nat.Coprime.coprime_dvd_left (Rat.add_den_dvd x y) (Nat.Coprime.mul_left hx hy) + +lemma sum_other_primes_coprime_p_pos (k p : ℕ) (_hk : k > 0) (hp : p.Prime) : + (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, + (1 : ℚ) / q).den.Coprime p := by + apply Nat.Coprime.of_dvd_left + · exact sum_den_dvd_prod_den _ _ + · exact prod_den_coprime_p k p hp + +lemma coprime_add_of_coprime_den (q1 q2 : ℚ) (p : ℕ) (h1 : q1.den.Coprime p) + (h2 : q2.den.Coprime p) : + (q1 + q2).den.Coprime p := + Nat.Coprime.of_dvd_left (Rat.add_den_dvd q1 q2) (h1.mul_left h2) + +lemma von_staudt_coprime_all_primes_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) : + (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with + q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den.Coprime p := by + rw [sum_primes_eq_indicator_add_rest k p hk hp] + rw [← add_assoc] + exact coprime_add_of_coprime_den _ _ p + (bernoulli_plus_indicator_coprime_p_pos k p hk hp) + (sum_other_primes_coprime_p_pos k p hk hp) + +lemma von_staudt_clausen_pos (k : ℕ) (hk : k > 0) : + bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, + (1 : ℚ) / p ∈ Set.range Int.cast := by + apply is_integer_of_coprime_all_primes + exact fun p hp => von_staudt_coprime_all_primes_pos k p hk hp + +theorem von_staudt_clausen (k : ℕ) : + bernoulli (2 * k) + + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, + (1 : ℚ) / p ∈ Set.range Int.cast := by + rcases Nat.eq_zero_or_pos k with rfl | hk + · exact von_staudt_clausen_zero + · exact von_staudt_clausen_pos k hk + +end vonStaudtClausen From 0c0b4280e2c62e6016696995a91a92c2a6ea2abe Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 17:35:51 -0800 Subject: [PATCH 02/70] style(NumberTheory/Bernoulli): fix lines exceeding 100 char limit Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 343 +++++++++++++++++++--------- 1 file changed, 237 insertions(+), 106 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 0013c6e7129d2c..a0705d123260b6 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -9,6 +9,19 @@ public import Mathlib.Algebra.BigOperators.Field public import Mathlib.RingTheory.PowerSeries.Inverse public import Mathlib.RingTheory.PowerSeries.Exp +public import Mathlib.Data.Matrix.Basic +public import Mathlib.FieldTheory.Finite.Basic +public import Mathlib.Algebra.Field.GeomSum +public import Mathlib.GroupTheory.SpecificGroups.Cyclic +public import Mathlib.RingTheory.ZMod.UnitsCyclic +public import Mathlib.Data.Nat.GCD.BigOperators +public import Mathlib.Data.Nat.Factorization.Basic +public import Mathlib.Data.Nat.Factorization.Defs +public import Mathlib.Data.Rat.Lemmas +public import Mathlib.Data.Nat.Choose.Bounds +public import Mathlib.Tactic.Cases +public import Mathlib.Tactic.IntervalCases + /-! # Bernoulli numbers @@ -48,7 +61,8 @@ then defined as `bernoulli := (-1)^n * bernoulli'`. ## Main theorems -`sum_bernoulli : ∑ k ∈ Finset.range n, (n.choose k : ℚ) * bernoulli k = if n = 1 then 1 else 0` +`sum_bernoulli : ∑ k ∈ Finset.range n, (n.choose k : ℚ) * bernoulli k = + if n = 1 then 1 else 0` -/ @[expose] public section @@ -83,7 +97,8 @@ theorem bernoulli'_spec (n : ℕ) : exact Finset.sum_eq_zero (fun x hx => by rw [choose_symm (le_of_lt (mem_range.1 hx)), sub_self]) theorem bernoulli'_spec' (n : ℕ) : - (∑ k ∈ antidiagonal n, ((k.1 + k.2).choose k.2 : ℚ) / (k.2 + 1) * bernoulli' k.1) = 1 := by + (∑ k ∈ antidiagonal n, + ((k.1 + k.2).choose k.2 : ℚ) / (k.2 + 1) * bernoulli' k.1) = 1 := by refine ((sum_antidiagonal_eq_sum_range_succ_mk _ n).trans ?_).trans (bernoulli'_spec n) refine sum_congr rfl fun x hx => ?_ simp only [add_tsub_cancel_of_le, mem_range_succ_iff.mp hx, cast_sub] @@ -199,7 +214,8 @@ theorem bernoulli_two : bernoulli 2 = 6⁻¹ := by theorem bernoulli_eq_zero_of_odd {n : ℕ} (h_odd : Odd n) (hlt : 1 < n) : bernoulli n = 0 := by rw [bernoulli, bernoulli'_eq_zero_of_odd h_odd hlt, mul_zero] -theorem bernoulli_eq_bernoulli'_of_ne_one {n : ℕ} (hn : n ≠ 1) : bernoulli n = bernoulli' n := by +theorem bernoulli_eq_bernoulli'_of_ne_one {n : ℕ} (hn : n ≠ 1) : + bernoulli n = bernoulli' n := by cases hn.lt_or_gt with | inl hlt => simp [lt_one_iff.mp hlt] | inr hgt => @@ -265,7 +281,8 @@ theorem bernoulliPowerSeries_mul_exp_sub_one : bernoulliPowerSeries A * (exp A - have hfact : ∀ m, (m ! : ℚ) ≠ 0 := fun m => mod_cast factorial_ne_zero m have hite2 : ite (n.succ = 0) 1 0 = (0 : ℚ) := if_neg n.succ_ne_zero simp only [CharP.cast_eq_zero, zero_add, inv_one, map_one, sub_self, mul_zero] - rw [← map_zero (algebraMap ℚ A), ← zero_div (n.succ ! : ℚ), ← hite2, ← bernoulli_spec', sum_div] + rw [← map_zero (algebraMap ℚ A), ← zero_div (n.succ ! : ℚ), ← hite2, + ← bernoulli_spec', sum_div] refine congr_arg (algebraMap ℚ A) (sum_congr rfl fun x h => eq_div_of_mul_eq (hfact n.succ) ?_) rw [mem_antidiagonal] at h rw [← h, add_choose, cast_div_charZero (factorial_mul_factorial_dvd_factorial_add _ _)] @@ -279,7 +296,8 @@ See https://proofwiki.org/wiki/Faulhaber%27s_Formula and [orosi2018faulhaber] fo the proof provided here. -/ theorem sum_range_pow (n p : ℕ) : (∑ k ∈ range n, (k : ℚ) ^ p) = - ∑ i ∈ range (p + 1), bernoulli i * ((p + 1).choose i) * (n : ℚ) ^ (p + 1 - i) / (p + 1) := by + ∑ i ∈ range (p + 1), + bernoulli i * ((p + 1).choose i) * (n : ℚ) ^ (p + 1 - i) / (p + 1) := by have hne : ∀ m : ℕ, (m ! : ℚ) ≠ 0 := fun m => mod_cast factorial_ne_zero m -- compute the Cauchy product of two power series have h_cauchy : @@ -295,11 +313,14 @@ theorem sum_range_pow (n p : ℕ) : simp only [exp_pow_eq_rescale_exp, rescale, RingHom.coe_mk] -- manipulate factorials and binomial coefficients have h : m < q + 1 := by simpa using h - rw [choose_eq_factorial_div_factorial h.le, eq_comm, div_eq_iff (hne q.succ), succ_eq_add_one, - mul_assoc _ _ (q.succ ! : ℚ), mul_comm _ (q.succ ! : ℚ), ← mul_assoc, div_mul_eq_mul_div] + rw [choose_eq_factorial_div_factorial h.le, eq_comm, + div_eq_iff (hne q.succ), succ_eq_add_one, + mul_assoc _ _ (q.succ ! : ℚ), mul_comm _ (q.succ ! : ℚ), + ← mul_assoc, div_mul_eq_mul_div] simp only [MonoidHom.coe_mk, OneHom.coe_mk, coeff_exp, Algebra.algebraMap_self, one_div, map_inv₀, map_natCast, coeff_mk] - rw [mul_comm ((n : ℚ) ^ (q - m + 1)), ← mul_assoc _ _ ((n : ℚ) ^ (q - m + 1)), ← one_div, + rw [mul_comm ((n : ℚ) ^ (q - m + 1)), + ← mul_assoc _ _ ((n : ℚ) ^ (q - m + 1)), ← one_div, mul_one_div, div_div, tsub_add_eq_add_tsub (le_of_lt_succ h), cast_div, cast_mul] · ring · exact factorial_mul_factorial_dvd_factorial h.le @@ -312,7 +333,8 @@ theorem sum_range_pow (n p : ℕ) : suffices (mk fun p => ∑ k ∈ range n, (k : ℚ) ^ p * algebraMap ℚ ℚ p !⁻¹) = mk fun p => - ∑ i ∈ range (p + 1), bernoulli i * (p + 1).choose i * (n : ℚ) ^ (p + 1 - i) / (p + 1)! by + ∑ i ∈ range (p + 1), + bernoulli i * (p + 1).choose i * (n : ℚ) ^ (p + 1 - i) / (p + 1)! by rw [← div_eq_iff (hne p), div_eq_mul_inv, sum_mul] rw [PowerSeries.ext_iff] at this simpa using this p @@ -344,24 +366,29 @@ $$\sum_{k=1}^{n} k^p = \sum_{i=0}^p (-1)^iB_i\binom{p+1}{i}\frac{n^{p+1-i}}{p+1} Deduced from `sum_range_pow`. -/ theorem sum_Ico_pow (n p : ℕ) : (∑ k ∈ Ico 1 (n + 1), (k : ℚ) ^ p) = - ∑ i ∈ range (p + 1), bernoulli' i * (p + 1).choose i * (n : ℚ) ^ (p + 1 - i) / (p + 1) := by + ∑ i ∈ range (p + 1), + bernoulli' i * (p + 1).choose i * (n : ℚ) ^ (p + 1 - i) / (p + 1) := by rw [← Nat.cast_succ] -- dispose of the trivial case cases p with | zero => simp | succ p => let f i := bernoulli i * p.succ.succ.choose i * (n : ℚ) ^ (p.succ.succ - i) / p.succ.succ let f' i := bernoulli' i * p.succ.succ.choose i * (n : ℚ) ^ (p.succ.succ - i) / p.succ.succ - suffices (∑ k ∈ Ico 1 n.succ, (k : ℚ) ^ p.succ) = ∑ i ∈ range p.succ.succ, f' i by convert this + suffices (∑ k ∈ Ico 1 n.succ, (k : ℚ) ^ p.succ) = + ∑ i ∈ range p.succ.succ, f' i by convert this -- prove some algebraic facts that will make things easier for us later on have hle := Nat.le_add_left 1 n have hne : (p + 1 + 1 : ℚ) ≠ 0 := by norm_cast - have h1 : ∀ r : ℚ, r * (p + 1 + 1) * (n : ℚ) ^ p.succ / (p + 1 + 1 : ℚ) = r * (n : ℚ) ^ p.succ := + have h1 : ∀ r : ℚ, + r * (p + 1 + 1) * (n : ℚ) ^ p.succ / (p + 1 + 1 : ℚ) = r * (n : ℚ) ^ p.succ := fun r => by rw [mul_div_right_comm, mul_div_cancel_right₀ _ hne] have h2 : f 1 + (n : ℚ) ^ p.succ = 1 / 2 * (n : ℚ) ^ p.succ := by simp_rw [f, bernoulli_one, choose_one_right, succ_sub_succ_eq_sub, cast_succ, tsub_zero, h1] ring have : - (∑ i ∈ range p, bernoulli (i + 2) * (p + 2).choose (i + 2) * (n : ℚ) ^ (p - i) / ↑(p + 2)) = - ∑ i ∈ range p, bernoulli' (i + 2) * (p + 2).choose (i + 2) * (n : ℚ) ^ (p - i) / ↑(p + 2) := + (∑ i ∈ range p, bernoulli (i + 2) * (p + 2).choose (i + 2) * + (n : ℚ) ^ (p - i) / ↑(p + 2)) = + ∑ i ∈ range p, bernoulli' (i + 2) * (p + 2).choose (i + 2) * + (n : ℚ) ^ (p - i) / ↑(p + 2) := sum_congr rfl fun i _ => by rw [bernoulli_eq_bernoulli'_of_ne_one (succ_succ_ne_one i)] calc (-- replace sum over `Ico` with sum over `range` and simplify @@ -393,7 +420,8 @@ lemma von_staudt_clausen_zero : bernoulli (2 * 0) + ∑ p ∈ Finset.range (2 * 0 + 2) with p.Prime ∧ (p - 1) ∣ 2 * 0, (1 : ℚ) / p ∈ Set.range Int.cast := by have h1 : bernoulli (2 * 0) = 1 := by norm_num [bernoulli_zero] - have h2 : ∑ p ∈ Finset.range (2 * 0 + 2) with p.Prime ∧ (p - 1) ∣ 2 * 0, (1 : ℚ) / p = 0 := by + have h2 : ∑ p ∈ Finset.range (2 * 0 + 2) with + p.Prime ∧ (p - 1) ∣ 2 * 0, (1 : ℚ) / p = 0 := by norm_num decide rw [h1, h2] @@ -433,7 +461,8 @@ lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := by have hcast := cast_ne_zero_of_mem_filter p l (Fact.out : p.Prime) - refine Finset.sum_bij' (fun v _ => (isUnit_iff_ne_zero.mpr (hcast v ‹_›)).unit) + refine Finset.sum_bij' (fun v hv => ⟨(v : ZMod p), (v : ZMod p)⁻¹, + mul_inv_cancel₀ (hcast v hv), inv_mul_cancel₀ (hcast v hv)⟩) (fun u _ => (u : ZMod p).val) ?_ ?_ ?_ ?_ ?_ · intro v hv exact Finset.mem_univ _ @@ -448,12 +477,12 @@ lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : · intro v hv simp only [Finset.mem_filter, Finset.mem_range] at hv have : (v : ZMod p).val = v := ZMod.val_cast_of_lt hv.1 - simp only [IsUnit.unit_spec, this] + simp only [Units.val_mk, this] · intro u _ ext - simp only [IsUnit.unit_spec, ZMod.natCast_zmod_val] + simp only [Units.val_mk, ZMod.natCast_zmod_val] · intro v _ - simp only [IsUnit.unit_spec] + simp only [Units.val_mk] lemma prime_ne_two_of_not_dvd_sub_one (p l : ℕ) (_hp : p.Prime) (hndvd : ¬(p - 1) ∣ l) : p ≠ 2 := fun h => by subst h; simp at hndvd @@ -512,7 +541,7 @@ lemma geom_sum_of_root_of_unity (p : ℕ) [hp : Fact p.Prime] (x : ZMod p) lemma generator_pow_card_sub_one_eq_one (p l : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : ((g : ZMod p) ^ l) ^ (p - 1) = 1 := by - have h2 : (g : ZMod p) ^ l ≠ 0 := by aesop + have h2 : (g : ZMod p) ^ l ≠ 0 := pow_ne_zero _ (Units.ne_zero g) exact ZMod.pow_card_sub_one_eq_one h2 lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hp2 : p ≠ 2) @@ -602,12 +631,20 @@ lemma prod_den_coprime_p (k p : ℕ) (hp : p.Prime) : lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = vonStaudtIndicator (2 * k) p / p + - ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by - have h3 : ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q = - (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) + - ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by - have h4 : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = - ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q := rfl + ∑ q ∈ Finset.range (2 * k + 2) with + q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by + have h3 : + ∑ q ∈ Finset.range (2 * k + 2) with + q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q = + (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) + then (1 : ℚ) / p else 0) + + ∑ q ∈ Finset.range (2 * k + 2) with + q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by + have h4 : + (∑ q ∈ Finset.range (2 * k + 2) with + q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = + ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2)), (1 : ℚ) / q := rfl rw [h4] have h5 : p < 2 * k + 2 ∨ ¬(p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) := by by_cases h51 : p < 2 * k + 2 @@ -616,63 +653,106 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : cases h5 with | inl h5 => have h7 : p < 2 * k + 2 := h5 - have h8 : p ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) ↔ - p.Prime ∧ (p - 1) ∣ 2 * k := by + have h8 : p ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2)) ↔ p.Prime ∧ (p - 1) ∣ 2 * k := by simp [Finset.mem_filter, Finset.mem_range] tauto - have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = - (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) := by - have h10 : (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) ↔ (p.Prime ∧ (p - 1) ∣ 2 * k) := by + have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) + then (1 : ℚ) / p else 0) = + (if (p.Prime ∧ (p - 1) ∣ 2 * k) + then (1 : ℚ) / p else 0) := by + have h10 : (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) ↔ + (p.Prime ∧ (p - 1) ∣ 2 * k) := by constructor <;> intro h11 · exact ⟨h11.1, h11.2.1⟩ · exact ⟨h11.1, h11.2, by omega⟩ simp [h10] rw [h9] by_cases h10 : p.Prime ∧ (p - 1) ∣ 2 * k - · have h13 : p ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) := by + · have h13 : p ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2)) := by simp [Finset.mem_filter, Finset.mem_range] at h8 ⊢ tauto - have h14 : ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q = - ∑ q ∈ (Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2))).erase p, (1 : ℚ) / q + (1 : ℚ) / p := by + have h14 : ∑ q ∈ Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2)), (1 : ℚ) / q = + ∑ q ∈ (Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2))).erase p, + (1 : ℚ) / q + (1 : ℚ) / p := by rw [← Finset.insert_erase h13, Finset.sum_insert (Finset.notMem_erase p _)] simp_all [Finset.mem_filter, Finset.mem_range] - have h17 : ∑ q ∈ (Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2))).erase p, (1 : ℚ) / q = - ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)), (1 : ℚ) / q := by - have h18 : (Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2))).erase p = - Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)) := by + have h17 : ∑ q ∈ (Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2))).erase p, + (1 : ℚ) / q = + ∑ q ∈ Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + (Finset.range (2 * k + 2)), + (1 : ℚ) / q := by + have h18 : (Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2))).erase p = + Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + (Finset.range (2 * k + 2)) := by apply Finset.ext intro q simp only [Finset.mem_filter, Finset.mem_erase, Finset.mem_range] cases q <;> simp_all [Nat.Prime] tauto rw [h18] - have h19 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) = (1 : ℚ) / p := by simp [h10] + have h19 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) + then (1 : ℚ) / p else 0) = (1 : ℚ) / p := by + simp [h10] rw [h14, h17, h19] ring_nf - · have h13 : ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q = - ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)), (1 : ℚ) / q := by - have h14 : Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) = - Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)) := by + · have h13 : ∑ q ∈ Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2)), (1 : ℚ) / q = + ∑ q ∈ Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + (Finset.range (2 * k + 2)), + (1 : ℚ) / q := by + have h14 : Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2)) = + Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + (Finset.range (2 * k + 2)) := by apply Finset.ext intro q simp only [Finset.mem_filter, Finset.mem_range] by_cases hq : q = p <;> simp_all [Nat.Prime] rw [h14] - have h15 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) = 0 := by simp [h10] + have h15 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) + then (1 : ℚ) / p else 0) = 0 := by + simp [h10] rw [h13, h15] ring_nf | inr h5 => - have h8 : ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q = - ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)), (1 : ℚ) / q := by - have h9 : Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) = - Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)) := by + have h8 : ∑ q ∈ Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2)), (1 : ℚ) / q = + ∑ q ∈ Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + (Finset.range (2 * k + 2)), + (1 : ℚ) / q := by + have h9 : Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2)) = + Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + (Finset.range (2 * k + 2)) := by apply Finset.ext intro q simp only [Finset.mem_filter, Finset.mem_range] by_cases hq : q = p <;> simp_all [Nat.Prime] omega rw [h9] - have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = 0 := by simp [h5] + have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) + then (1 : ℚ) / p else 0) = 0 := by + simp [h5] rw [h8, h9] ring_nf have h4 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = @@ -682,22 +762,31 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : have h9 : p < 2 * k + 2 := by have h14 : p - 1 ≤ 2 * k := Nat.le_of_dvd (by nlinarith) h5 omega - have h10 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = (1 : ℚ) / p := by + have h10 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) + then (1 : ℚ) / p else 0) = (1 : ℚ) / p := by simp [hp, h5, h9] have h11 : vonStaudtIndicator (2 * k) p / p = (1 : ℚ) / p := by rw [h7] rw [h10, h11] - · have h7 : vonStaudtIndicator (2 * k) p = 0 := by simp [vonStaudtIndicator, h5] - have h8 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = 0 := by + · have h7 : vonStaudtIndicator (2 * k) p = 0 := by + simp [vonStaudtIndicator, h5] + have h8 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) + then (1 : ℚ) / p else 0) = 0 := by by_cases h9 : p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2 · exact absurd h9.2.1 h5 · simp [h9] have h9 : vonStaudtIndicator (2 * k) p / p = 0 := by rw [h7]; simp rw [h8, h9] - calc (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = - (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) + - ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := h3 + calc (∑ q ∈ Finset.range (2 * k + 2) with + q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = + (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) + then (1 : ℚ) / p else 0) + + ∑ q ∈ Finset.range (2 * k + 2) with + q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, + (1 : ℚ) / q := h3 _ = vonStaudtIndicator (2 * k) p / p + - ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by rw [h4] + ∑ q ∈ Finset.range (2 * k + 2) with + q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, + (1 : ℚ) / q := by rw [h4] lemma pIntegral_of_int (p : ℕ) (z : ℤ) : pIntegral p z := by simp_all [pIntegral] @@ -775,9 +864,11 @@ lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : have h3 : (2 * k : ℚ) ≠ 0 := by positivity field_simp [h3] rw [h2] - have h3 : (-((2 : ℚ) ^ (2 * k - 1)) / 2 : ℚ) = (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 := by norm_cast + have h3 : (-((2 : ℚ) ^ (2 * k - 1)) / 2 : ℚ) = + (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 := by norm_cast rw [h3] - have h4 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by + have h4 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = + (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by have h8 : (2 : ℤ) ^ (2 * k - 1) = (2 : ℤ) ^ (2 * k - 2) * 2 := by have h9 : (2 * k - 1 : ℕ) = (2 * k - 2 : ℕ) + 1 := by omega have h10 : (2 : ℤ) ^ (2 * k - 1) = (2 : ℤ) ^ ((2 * k - 2 : ℕ) + 1) := by rw [h9] @@ -785,8 +876,10 @@ lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : have h11 : (2 : ℤ) ^ ((2 * k - 2 : ℕ) + 1) = (2 : ℤ) ^ (2 * k - 2) * 2 := by simp [pow_add, pow_one, mul_comm] rw [h11] - have h9 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by - have h10 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) = (-((2 : ℤ) ^ (2 * k - 2) : ℤ) * 2 : ℚ) := by + have h9 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = + (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by + have h10 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) = + (-((2 : ℤ) ^ (2 * k - 2) : ℤ) * 2 : ℚ) := by norm_cast at h8 ⊢ simp [h8] rw [h10] @@ -851,7 +944,8 @@ lemma pIntegral_mul_nat (p : ℕ) (x : ℚ) (n : ℕ) (hx : pIntegral p x) : pIntegral_mul_int p x n hx lemma valuation_bound_d_plus_1_p2_d2 : - (2 + 1).factorization 2 ≤ 2 - 1 := by norm_num + (2 + 1).factorization 2 ≤ 2 - 1 := by + simp [Nat.factorization_eq_zero_of_not_dvd (show ¬(2 ∣ 3) by decide)] lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) := by have h : ∀ n : ℕ, n ≥ 3 → n + 1 ≤ 2 ^ (n - 1) := by @@ -966,10 +1060,13 @@ lemma pIntegral_T2 (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt : m < valuation_bound_2d_plus_1 p d hp hd_pos have h_pow_pIntegral : pIntegral p ((p : ℚ)^(2 * d - 1) / ↑(2 * d + 1)) := pIntegral_pow_div p (2 * d + 1) (2 * d - 1) hp hN_ne_zero hvaluation - have h_rw : (↑((2 * k).choose (2 * m)) : ℚ) * ↑p ^ (2 * d - 1) / ↑(2 * d + 1) = - (↑((2 * k).choose (2 * m)) : ℚ) * (↑p ^ (2 * d - 1) / ↑(2 * d + 1)) := by ring + have h_rw : + (↑((2 * k).choose (2 * m)) : ℚ) * ↑p ^ (2 * d - 1) / ↑(2 * d + 1) = + (↑((2 * k).choose (2 * m)) : ℚ) * + (↑p ^ (2 * d - 1) / ↑(2 * d + 1)) := by ring rw [h_rw] - exact pIntegral_mul_nat p ((p : ℚ)^(2 * d - 1) / ↑(2 * d + 1)) ((2*k).choose (2*m)) h_pow_pIntegral + exact pIntegral_mul_nat p ((p : ℚ)^(2 * d - 1) / ↑(2 * d + 1)) + ((2*k).choose (2*m)) h_pow_pIntegral · simp only [zero_mul, zero_div] exact pIntegral_of_int p 0 @@ -988,7 +1085,8 @@ lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : rw [h8]; norm_cast; simp; omega simp_all · have h3 : (p : ℚ) ≠ 0 := by exact_mod_cast h - calc (B + I / p) * (p : ℚ)^(2*d) = B * (p : ℚ)^(2*d) + (I / p) * (p : ℚ)^(2*d) := by ring + calc (B + I / p) * (p : ℚ)^(2*d) = + B * (p : ℚ)^(2*d) + (I / p) * (p : ℚ)^(2*d) := by ring _ = B * (p : ℚ)^(2*d) + I * (p : ℚ)^(2*d - 1) := by have h4 : (I / p : ℚ) * (p : ℚ)^(2*d) = I * (p : ℚ)^(2*d - 1) := by calc (I / p : ℚ) * (p : ℚ)^(2*d) = I * (p : ℚ)^(2*d) / p := by ring @@ -1008,7 +1106,8 @@ lemma even_term_eq_T1_sub_T2 (k m p : ℕ) (hm_lt : m < k) : (bernoulli (2*m) * ((2*k).choose (2*m)) * (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1) : ℚ) = (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k).choose (2*m)) * (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1) - - vonStaudtIndicator (2*m) p * ((2*k).choose (2*m)) * (p : ℚ)^(2*(k-m) - 1) / (2*(k-m) + 1) := by + vonStaudtIndicator (2*m) p * ((2*k).choose (2*m)) * + (p : ℚ)^(2*(k-m) - 1) / (2*(k-m) + 1) := by have hd : k - m ≥ 1 := by omega have h := core_algebraic_identity (bernoulli (2*m)) (vonStaudtIndicator (2*m) p) p (k - m) hd set C := ((2*k).choose (2*m) : ℚ) @@ -1024,9 +1123,12 @@ lemma pIntegral_sub (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p pIntegral p (x - y) := Nat.Coprime.coprime_dvd_left (Rat.sub_den_dvd x y) (Nat.Coprime.mul_left hx hy) -lemma pIntegral_even_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) - (ih : pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : - pIntegral p (bernoulli (2*m) * ((2*k).choose (2*m)) * (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1)) := by +lemma pIntegral_even_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) + (hm_lt : m < k) (hp : p.Prime) + (ih : pIntegral p + (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : + pIntegral p (bernoulli (2*m) * ((2*k).choose (2*m)) * + (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1)) := by rw [even_term_eq_T1_sub_T2 k m p hm_lt] exact pIntegral_sub p _ _ (pIntegral_T1 k m p hk hm_pos hm_lt hp ih) (pIntegral_T2 k m p hk hm_pos hm_lt hp) @@ -1133,28 +1235,51 @@ lemma pIntegral_second_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt rw [Rat.den_zero] exact Nat.coprime_one_left_iff p |>.mpr trivial -lemma even_term_decomposition_identity (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) : - (bernoulli (2*m) * ((2*k + 1).choose (2*m)) * (p : ℚ)^(2*k - 2*m) / (2*k + 1) : ℚ) = - (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k + 1).choose (2*m)) * +lemma even_term_decomposition_identity (k m p : ℕ) (hk : k > 0) + (hm_pos : m ≥ 1) (hm_lt : m < k) : + (bernoulli (2*m) * ((2*k + 1).choose (2*m)) * + (p : ℚ)^(2*k - 2*m) / (2*k + 1) : ℚ) = + (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * + ((2*k + 1).choose (2*m)) * (p : ℚ)^(2*k - 2*m) / (2*k + 1) - - vonStaudtIndicator (2*m) p * ((2*k + 1).choose (2*m)) * (p : ℚ)^(2*k - 2*m - 1) / (2*k + 1) := by - have h2 : (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k + 1).choose (2 * m)) * + vonStaudtIndicator (2*m) p * ((2*k + 1).choose (2*m)) * + (p : ℚ)^(2*k - 2*m - 1) / (2*k + 1) := by + have h2 : (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * + ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - - vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k + 1) = (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / + vonStaudtIndicator (2 * m) p * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k + 1) = (bernoulli (2 * m) * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) : ℚ) := by - have h3 : (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k + 1).choose (2 * m)) * + have h3 : (bernoulli (2 * m) + + vonStaudtIndicator (2 * m) p / p) * + ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - - vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k + 1) = (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / - (2 * k + 1)) + (vonStaudtIndicator (2 * m) p / p * ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) - - (vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / + vonStaudtIndicator (2 * m) p * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k + 1) = (bernoulli (2 * m) * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / + (2 * k + 1)) + + (vonStaudtIndicator (2 * m) p / p * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / + (2 * k + 1)) - + (vonStaudtIndicator (2 * m) p * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1)) := by ring_nf rw [h3] - have h4 : (vonStaudtIndicator (2 * m) p / p * ((2 * k + 1).choose (2 * m)) * + have h4 : (vonStaudtIndicator (2 * m) p / p * + ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) - - (vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / + (vonStaudtIndicator (2 * m) p * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1)) = 0 := by by_cases h5 : (p - 1 : ℕ) ∣ (2 * m) · have h6 : vonStaudtIndicator (2 * m) p = (1 : ℚ) := by simp [vonStaudtIndicator, h5] @@ -1163,9 +1288,12 @@ lemma even_term_decomposition_identity (k m p : ℕ) (hk : k > 0) (hm_pos : m (2 * k + 1) - (1 : ℚ) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1) = 0 := by - have h10 : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) ^ (2 * k - 2 * m - 1) * (p : ℚ) := by - have h102 : (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1 : ℕ) + 1 := by omega - have h104 : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) ^ ((2 * k - 2 * m - 1 : ℕ) + 1) := by + have h10 : (p : ℚ) ^ (2 * k - 2 * m) = + (p : ℚ) ^ (2 * k - 2 * m - 1) * (p : ℚ) := by + have h102 : (2 * k - 2 * m : ℕ) = + (2 * k - 2 * m - 1 : ℕ) + 1 := by omega + have h104 : (p : ℚ) ^ (2 * k - 2 * m) = + (p : ℚ) ^ ((2 * k - 2 * m - 1 : ℕ) + 1) := by rw [h102] simp [pow_add, pow_one] rw [h104] @@ -1204,8 +1332,9 @@ lemma pIntegral_coeff_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt (p : ℚ) * (((2*k).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m - 1) / (2*k - 2*m + 1)) := by have hpow : (p : ℚ)^(2*k - 2*m) = (p : ℚ) * (p : ℚ)^(2*k - 2*m - 1) := by - have heq : 2*k - 2*m - 1 + 1 = 2*k - 2*m := by omega - conv_lhs => rw [← heq, pow_succ'] + have heq : (2*k - 2*m : ℕ) = (2*k - 2*m - 1) + 1 := by omega + conv_lhs => rw [heq] + exact pow_succ' _ _ rw [hpow] ring rw [hp_factor] @@ -1224,14 +1353,18 @@ lemma pIntegral_first_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt exact pIntegral_mul p _ _ ih (pIntegral_coeff_term k m p hk hm_pos hm_lt hp) lemma pIntegral_even_term_in_sum (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) - (hp : p.Prime) (ih : pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : - pIntegral p (bernoulli (2*m) * ((2*k + 1).choose (2*m)) * (p : ℚ)^(2*k - 2*m) / (2*k + 1)) := by + (hp : p.Prime) + (ih : pIntegral p + (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : + pIntegral p (bernoulli (2*m) * ((2*k + 1).choose (2*m)) * + (p : ℚ)^(2*k - 2*m) / (2*k + 1)) := by rw [even_term_decomposition_identity k m p hk hm_pos hm_lt] exact pIntegral_sub p _ _ (pIntegral_first_term k m p hk hm_pos hm_lt hp ih) (pIntegral_second_term k m p hk hm_pos hm_lt hp) lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) - (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : + (ih : ∀ m, 0 < m → m < k → + pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : pIntegral p (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k - i) / (2*k + 1)) := by apply pIntegral_sum @@ -1301,7 +1434,8 @@ lemma power_sum_indicator_divisible_by_p (k p : ℕ) (_hk : k > 0) (hp : p.Prime exact h_cast lemma faulhaber_split_top_term (k p : ℕ) : - (∑ i ∈ Finset.range (2*k + 1), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / + (∑ i ∈ Finset.range (2*k + 1), + bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) = (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) + @@ -1313,7 +1447,8 @@ lemma faulhaber_split_top_term (k p : ℕ) : rw [h3, Finset.sum_union h4, Finset.sum_singleton] lemma rat_power_sum_eq_filter_ne_zero (k p : ℕ) (hk : k > 0) : - (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by + (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = + ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by have h1 : (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = ∑ v ∈ Finset.range p, if v = 0 then 0 else (v : ℚ)^(2*k) := by apply Finset.sum_congr rfl @@ -1331,7 +1466,8 @@ lemma rat_power_sum_eq_filter_ne_zero (k p : ℕ) (hk : k > 0) : apply Finset.sum_congr rfl intro v _ by_cases h : v = 0 <;> simp [h] - _ = ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) := by rw [Finset.sum_filter] + _ = ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) := by + rw [Finset.sum_filter] have h3 : ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) = ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by simp [Finset.sum_filter] calc (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = @@ -1355,23 +1491,18 @@ lemma remainder_div_p (k p : ℕ) (hp : p.Prime) : intro i hi have h2 : i < 2 * k := Finset.mem_range.mp hi have h5 : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero hp - have h6 : ((p : ℚ) : ℚ) ^ (2 * k + 1 - i : ℕ) = (p : ℚ) ^ ((2 * k - i : ℕ) + 1 : ℕ) := by + have h6 : ((p : ℚ) : ℚ) ^ (2 * k + 1 - i : ℕ) = + (p : ℚ) ^ ((2 * k - i : ℕ) + 1 : ℕ) := by have h7 : (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 := by omega rw [h7] rw [h6] - have h7 : ((p : ℚ) : ℚ) ^ ((2 * k - i : ℕ) + 1 : ℕ) = (p : ℚ) ^ (2 * k - i : ℕ) * (p : ℚ) := by + have h7 : ((p : ℚ) : ℚ) ^ ((2 * k - i : ℕ) + 1 : ℕ) = + (p : ℚ) ^ (2 * k - i : ℕ) * (p : ℚ) := by rw [pow_succ] rw [h7] field_simp [h5] - calc (∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = - ∑ i ∈ Finset.range (2 * k), ((bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) := by rw [Finset.sum_div] - _ = ∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * - (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by - apply Finset.sum_congr rfl - intro i hi - rw [h1 i hi] + rw [Finset.sum_div] + exact Finset.sum_congr rfl fun i hi => h1 i hi exact_mod_cast h0 lemma algebraic_rearrangement (k p : ℕ) (T : ℤ) (hp : p.Prime) From 80fd7688b5f9ceab1a5899d75b203f5c51dd03ec Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 18:03:21 -0800 Subject: [PATCH 03/70] style(NumberTheory/Bernoulli): fix linter warnings in vonStaudtClausen section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove unused `Units.val_mk` from simp calls - Convert deprecated `induction'` to `induction` in three lemmas - Fix whitespace: `2*m` → `2 * m`, `2*k` → `2 * k`, `)^(` → `) ^ (` - Fix resulting lines exceeding 100 char limit - Add `set_option linter.style.longFile 1800` for file length Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 468 +++++++++++++++------------- 1 file changed, 252 insertions(+), 216 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index a0705d123260b6..06f3063751b51d 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -65,6 +65,8 @@ then defined as `bernoulli := (-1)^n * bernoulli'`. if n = 1 then 1 else 0` -/ +set_option linter.style.longFile 1800 + @[expose] public section @@ -477,12 +479,12 @@ lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : · intro v hv simp only [Finset.mem_filter, Finset.mem_range] at hv have : (v : ZMod p).val = v := ZMod.val_cast_of_lt hv.1 - simp only [Units.val_mk, this] + simp only [this] · intro u _ ext - simp only [Units.val_mk, ZMod.natCast_zmod_val] + simp only [ZMod.natCast_zmod_val] · intro v _ - simp only [Units.val_mk] + simp lemma prime_ne_two_of_not_dvd_sub_one (p l : ℕ) (_hp : p.Prime) (hndvd : ¬(p - 1) ∣ l) : p ≠ 2 := fun h => by subst h; simp at hndvd @@ -604,9 +606,10 @@ def pIntegral (p : ℕ) (x : ℚ) : Prop := x.den.Coprime p lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by classical - induction' s using Finset.induction_on with a s has ih - · simp - · rw [Finset.sum_insert has, Finset.prod_insert has] + induction s using Finset.induction_on with + | empty => simp + | @insert a s has ih => + rw [Finset.sum_insert has, Finset.prod_insert has] exact dvd_trans (Rat.add_den_dvd (f a) (∑ x ∈ s, f x)) (mul_dvd_mul_left _ ih) lemma pIntegral_sum {ι : Type*} (p : ℕ) (s : Finset ι) (f : ι → ℚ) @@ -804,7 +807,7 @@ lemma ordCompl_ne_zero (p M : ℕ) (_hp : p.Prime) (hM : M ≠ 0) : lemma pow_div_eq_pow_sub_div_ordCompl (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) (hv : M.factorization p ≤ N) : - (p : ℚ)^N / M = (p : ℚ)^(N - M.factorization p) / (M / p ^ M.factorization p) := by + (p : ℚ)^N / M = (p : ℚ) ^ (N - M.factorization p) / (M / p ^ M.factorization p) := by set e := M.factorization p with he set M' := M / p ^ e with hM' have hdecomp : p ^ e * M' = M := Nat.ordProj_mul_ordCompl_eq_self M p @@ -836,7 +839,7 @@ lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) simp only [← Nat.cast_pow] rw [Nat.cast_div_charZero (Nat.ordProj_dvd M p)] rw [hcast] - have hdvd : ((p : ℚ)^(N - M.factorization p) / M').den ∣ M' := + have hdvd : ((p : ℚ) ^ (N - M.factorization p) / M').den ∣ M' := den_pow_div_dvd p M' (N - M.factorization p) hM'_ne exact pIntegral_of_den_dvd_coprime p _ M' hdvd hM'_cop @@ -848,15 +851,15 @@ lemma valuation_bound (p n : ℕ) (hp : p.Prime) (_hn : n ≥ 1) : _ ≤ p ^ n := Nat.pow_le_pow_left hp.two_le n lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : - pIntegral p ((p : ℚ)^(2*k) / (2*k + 1)) := by + pIntegral p ((p : ℚ) ^ (2 * k) / (2 * k + 1)) := by have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by push_cast; ring rw [h] - apply pIntegral_pow_div p (2*k + 1) (2*k) hp + apply pIntegral_pow_div p (2 * k + 1) (2 * k) hp · omega - · exact valuation_bound p (2*k) hp (by omega) + · exact valuation_bound p (2 * k) hp (by omega) lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : - pIntegral 2 (bernoulli 1 * (2*k) * (2 : ℚ)^(2*k - 1) / (2*k)) := by + pIntegral 2 (bernoulli 1 * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) := by have h1 : bernoulli 1 = -1 / 2 := by norm_num [bernoulli_one] rw [h1] have h2 : ((-1 / 2 : ℚ) * (2 * k : ℚ) * (2 : ℚ) ^ (2 * k - 1) / (2 * k : ℚ)) = @@ -889,7 +892,7 @@ lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : norm_num [pIntegral] lemma i1_term_simplify (k p : ℕ) (hk : k > 0) : - bernoulli 1 * (2*k) * (p : ℚ)^(2*k - 1) / (2*k) = -(p : ℚ)^(2*k - 1) / 2 := by + bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = -(p : ℚ) ^ (2 * k - 1) / 2 := by have h1 : bernoulli 1 = (-1 : ℚ) / 2 := by norm_num [bernoulli] rw [h1] have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega @@ -900,24 +903,24 @@ lemma two_coprime_odd_prime (p : ℕ) (hp : p.Prime) (hp2 : p ≠ 2) : Odd.coprime_two_left (Nat.Prime.odd_of_ne_two hp hp2) lemma den_neg_pow_div_two_dvd_two (k p : ℕ) : - (-(p : ℚ)^(2*k - 1) / 2).den ∣ 2 := by + (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by rw [neg_div, Rat.den_neg_eq_den, ← Nat.cast_pow] conv_lhs => rw [show (2 : ℚ) = (2 : ℕ) from rfl, Rat.natCast_div_eq_divInt] have h := Rat.den_dvd (p ^ (2 * k - 1)) 2 exact Int.natCast_dvd_natCast.mp h lemma pIntegral_neg_pow_div_two (k p : ℕ) (hp : p.Prime) (hp2 : p ≠ 2) : - pIntegral p (-(p : ℚ)^(2*k - 1) / 2) := by + pIntegral p (-(p : ℚ) ^ (2 * k - 1) / 2) := by unfold pIntegral exact Nat.Coprime.of_dvd_left (den_neg_pow_div_two_dvd_two k p) (two_coprime_odd_prime p hp hp2) lemma pIntegral_i1_term_p_odd (k p : ℕ) (hk : k > 0) (hp : p.Prime) (hp2 : p ≠ 2) : - pIntegral p (bernoulli 1 * (2*k) * (p : ℚ)^(2*k - 1) / (2*k)) := by + pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by rw [i1_term_simplify k p hk] exact pIntegral_neg_pow_div_two k p hp hp2 lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : - pIntegral p (bernoulli 1 * (2*k) * (p : ℚ)^(2*k - 1) / (2*k)) := by + pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by obtain rfl | hp2 := eq_or_ne p 2 · exact pIntegral_i1_term_p_eq_two k hk · exact pIntegral_i1_term_p_odd k p hk hp hp2 @@ -950,19 +953,19 @@ lemma valuation_bound_d_plus_1_p2_d2 : lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) := by have h : ∀ n : ℕ, n ≥ 3 → n + 1 ≤ 2 ^ (n - 1) := by intro n hn - induction' hn with n hn IH - · norm_num - · cases n with - | zero => contradiction - | succ n => - cases n with - | zero => contradiction - | succ n => - cases n with - | zero => contradiction - | succ n => - simp [pow_succ, mul_assoc] at IH ⊢ - omega + induction hn with + | refl => norm_num + | @step m hm IH => + have hm : (3 : ℕ) ≤ m := hm + have IH := IH + have h1 : 2 ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by omega) + have h2 : m - 1 + 1 = m := by omega + have h3 : 2 ^ (m - 1) * 2 = 2 ^ m := by + conv_rhs => rw [← h2] + exact (pow_succ 2 (m - 1)).symm + calc m + 1 + 1 ≤ 2 ^ (m - 1) + 1 := by omega + _ ≤ 2 ^ (m - 1) * 2 := by nlinarith + _ = 2 ^ m := h3 exact h d hd lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : @@ -970,23 +973,27 @@ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : have h1 : d + 1 ≤ p ^ (d - 1) := by have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by intro d hd - induction' hd with d hd IH - · norm_num + induction hd with + | refl => + norm_num omega - · cases d with - | zero => contradiction - | succ d => - cases d with - | zero => contradiction - | succ d => - simp_all [Nat.pow_succ, Nat.mul_assoc] - have h4 : p ^ d ≥ 1 := Nat.one_le_pow _ _ (by omega) + | @step m hm IH => + have hm : (2 : ℕ) ≤ m := hm + have IH := IH + have hm1 : m - 1 + 1 = m := by omega + have h3 : p ^ (m - 1) * p = p ^ m := by + conv_rhs => rw [← hm1] + exact (pow_succ p (m - 1)).symm + calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by omega + _ ≤ p ^ (m - 1) * p := by + have : p ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by omega) nlinarith + _ = p ^ m := h3 exact h2 d hd exact h1 lemma pIntegral_pow_div_factor (k m p : ℕ) (_hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : - pIntegral p ((p : ℚ)^(2*(k-m)) / (2*(↑k - ↑m) + 1)) := by + pIntegral p ((p : ℚ) ^ (2*(k-m)) / (2*(↑k - ↑m) + 1)) := by set d := k - m with hd have hd_pos : d ≥ 1 := by omega have hcast : (↑k : ℚ) - ↑m = ↑d := by rw [hd, Nat.cast_sub (le_of_lt hm_lt)] @@ -999,18 +1006,18 @@ lemma pIntegral_pow_div_factor (k m p : ℕ) (_hm_pos : m ≥ 1) (hm_lt : m < k) exact valuation_bound p (2 * d) hp hn lemma pIntegral_T1 (k m p : ℕ) (_hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) - (ih : pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : - pIntegral p ((bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k).choose (2*m)) * - (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1)) := by - have h_eq : (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k).choose (2*m)) * - (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1) = - ((bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k).choose (2*m))) * - ((p : ℚ)^(2*(k-m)) / (2*(k-m) + 1)) := by ring + (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : + pIntegral p ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k).choose (2 * m)) * + (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1)) := by + have h_eq : (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k).choose (2 * m)) * + (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1) = + ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k).choose (2 * m))) * + ((p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1)) := by ring rw [h_eq] apply pIntegral_mul · apply pIntegral_mul · exact ih - · exact pIntegral_of_int p ((2*k).choose (2*m)) + · exact pIntegral_of_int p ((2 * k).choose (2 * m)) · exact pIntegral_pow_div_factor k m p hm_pos hm_lt hp lemma valuation_three_le_one (p : ℕ) (hp : p.Prime) : (3 : ℕ).factorization p ≤ 1 := by @@ -1041,7 +1048,7 @@ lemma valuation_bound_2d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 1) : _ ≤ p ^ (2 * d - 1) := Nat.pow_le_pow_left hp.two_le _ lemma pIntegral_T2 (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : - pIntegral p (vonStaudtIndicator (2*m) p * ((2*k).choose (2*m)) * (p : ℚ)^(2*(k-m) - 1) / + pIntegral p (vonStaudtIndicator (2 * m) p * ((2 * k).choose (2 * m)) * (p : ℚ) ^ (2*(k-m) - 1) / (2*(k-m) + 1)) := by set d := k - m with hd_def have hd_pos : d ≥ 1 := by omega @@ -1058,44 +1065,44 @@ lemma pIntegral_T2 (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt : m < have hN_ne_zero : (2 * d + 1 : ℕ) ≠ 0 := by omega have hvaluation : (2 * d + 1).factorization p ≤ 2 * d - 1 := valuation_bound_2d_plus_1 p d hp hd_pos - have h_pow_pIntegral : pIntegral p ((p : ℚ)^(2 * d - 1) / ↑(2 * d + 1)) := + have h_pow_pIntegral : pIntegral p ((p : ℚ) ^ (2 * d - 1) / ↑(2 * d + 1)) := pIntegral_pow_div p (2 * d + 1) (2 * d - 1) hp hN_ne_zero hvaluation have h_rw : (↑((2 * k).choose (2 * m)) : ℚ) * ↑p ^ (2 * d - 1) / ↑(2 * d + 1) = (↑((2 * k).choose (2 * m)) : ℚ) * (↑p ^ (2 * d - 1) / ↑(2 * d + 1)) := by ring rw [h_rw] - exact pIntegral_mul_nat p ((p : ℚ)^(2 * d - 1) / ↑(2 * d + 1)) - ((2*k).choose (2*m)) h_pow_pIntegral + exact pIntegral_mul_nat p ((p : ℚ) ^ (2 * d - 1) / ↑(2 * d + 1)) + ((2 * k).choose (2 * m)) h_pow_pIntegral · simp only [zero_mul, zero_div] exact pIntegral_of_int p 0 lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : - B * (p : ℚ)^(2*d) = (B + I / p) * (p : ℚ)^(2*d) - I * (p : ℚ)^(2*d - 1) := by - have h1 : (B + I / p) * (p : ℚ)^(2*d) - I * (p : ℚ)^(2*d - 1) = - B * (p : ℚ)^(2*d) + I * (p : ℚ)^(2*d - 1) - I * (p : ℚ)^(2*d - 1) := by - have h2 : (B + I / p) * (p : ℚ)^(2*d) = B * (p : ℚ)^(2*d) + I * (p : ℚ)^(2*d - 1) := by + B * (p : ℚ) ^ (2*d) = (B + I / p) * (p : ℚ) ^ (2*d) - I * (p : ℚ) ^ (2*d - 1) := by + have h1 : (B + I / p) * (p : ℚ) ^ (2*d) - I * (p : ℚ) ^ (2*d - 1) = + B * (p : ℚ) ^ (2*d) + I * (p : ℚ) ^ (2*d - 1) - I * (p : ℚ) ^ (2*d - 1) := by + have h2 : (B + I / p) * (p : ℚ) ^ (2*d) = B * (p : ℚ) ^ (2*d) + I * (p : ℚ) ^ (2*d - 1) := by by_cases h : (p : ℚ) = 0 · have h3 : (p : ℕ) = 0 := by norm_cast at h ⊢ have h4 : 2 * d ≥ 1 := by omega - have h5 : (p : ℚ)^(2*d) = 0 := by rw [h3]; norm_cast; simp; omega - have h6 : (p : ℚ)^(2*d - 1) = 0 := by + have h5 : (p : ℚ) ^ (2*d) = 0 := by rw [h3]; norm_cast; simp; omega + have h6 : (p : ℚ) ^ (2*d - 1) = 0 := by have h7 : (2 * d : ℕ) - 1 ≥ 0 := by omega have h8 : (p : ℕ) = 0 := by norm_cast at h ⊢ rw [h8]; norm_cast; simp; omega simp_all · have h3 : (p : ℚ) ≠ 0 := by exact_mod_cast h - calc (B + I / p) * (p : ℚ)^(2*d) = - B * (p : ℚ)^(2*d) + (I / p) * (p : ℚ)^(2*d) := by ring - _ = B * (p : ℚ)^(2*d) + I * (p : ℚ)^(2*d - 1) := by - have h4 : (I / p : ℚ) * (p : ℚ)^(2*d) = I * (p : ℚ)^(2*d - 1) := by - calc (I / p : ℚ) * (p : ℚ)^(2*d) = I * (p : ℚ)^(2*d) / p := by ring - _ = I * (p : ℚ)^(2*d - 1) := by - have h5 : (p : ℚ)^(2*d) = (p : ℚ)^(2*d - 1) * p := by + calc (B + I / p) * (p : ℚ) ^ (2*d) = + B * (p : ℚ) ^ (2*d) + (I / p) * (p : ℚ) ^ (2*d) := by ring + _ = B * (p : ℚ) ^ (2*d) + I * (p : ℚ) ^ (2*d - 1) := by + have h4 : (I / p : ℚ) * (p : ℚ) ^ (2*d) = I * (p : ℚ) ^ (2*d - 1) := by + calc (I / p : ℚ) * (p : ℚ) ^ (2*d) = I * (p : ℚ) ^ (2*d) / p := by ring + _ = I * (p : ℚ) ^ (2*d - 1) := by + have h5 : (p : ℚ) ^ (2*d) = (p : ℚ) ^ (2*d - 1) * p := by have h7 : (2 * d : ℕ) - 1 + 1 = 2 * d := by omega - calc (p : ℚ)^(2*d) = (p : ℚ)^((2*d - 1) + 1) := by rw [h7] - _ = (p : ℚ)^(2*d - 1) * (p : ℚ)^1 := by rw [pow_add] - _ = (p : ℚ)^(2*d - 1) * p := by simp [pow_one] + calc (p : ℚ) ^ (2*d) = (p : ℚ) ^ ((2*d - 1) + 1) := by rw [h7] + _ = (p : ℚ) ^ (2*d - 1) * (p : ℚ)^1 := by rw [pow_add] + _ = (p : ℚ) ^ (2*d - 1) * p := by simp [pow_one] rw [h5] field_simp [h3] rw [h4] @@ -1103,21 +1110,21 @@ lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : linarith lemma even_term_eq_T1_sub_T2 (k m p : ℕ) (hm_lt : m < k) : - (bernoulli (2*m) * ((2*k).choose (2*m)) * (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1) : ℚ) = - (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k).choose (2*m)) * - (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1) - - vonStaudtIndicator (2*m) p * ((2*k).choose (2*m)) * - (p : ℚ)^(2*(k-m) - 1) / (2*(k-m) + 1) := by + (bernoulli (2 * m) * ((2 * k).choose (2 * m)) * (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1) : ℚ) = + (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k).choose (2 * m)) * + (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1) - + vonStaudtIndicator (2 * m) p * ((2 * k).choose (2 * m)) * + (p : ℚ) ^ (2*(k-m) - 1) / (2*(k-m) + 1) := by have hd : k - m ≥ 1 := by omega - have h := core_algebraic_identity (bernoulli (2*m)) (vonStaudtIndicator (2*m) p) p (k - m) hd - set C := ((2*k).choose (2*m) : ℚ) + have h := core_algebraic_identity (bernoulli (2 * m)) (vonStaudtIndicator (2 * m) p) p (k - m) hd + set C := ((2 * k).choose (2 * m) : ℚ) set N := (2 * (k - m) + 1 : ℚ) - calc bernoulli (2*m) * C * (p : ℚ)^(2*(k-m)) / N - = (bernoulli (2*m) * (p : ℚ)^(2*(k-m))) * C / N := by ring - _ = ((bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * (p : ℚ)^(2*(k-m)) - - vonStaudtIndicator (2*m) p * (p : ℚ)^(2*(k-m) - 1)) * C / N := by rw [h] - _ = (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * C * (p : ℚ)^(2*(k-m)) / N - - vonStaudtIndicator (2*m) p * C * (p : ℚ)^(2*(k-m) - 1) / N := by ring + calc bernoulli (2 * m) * C * (p : ℚ) ^ (2*(k-m)) / N + = (bernoulli (2 * m) * (p : ℚ) ^ (2*(k-m))) * C / N := by ring + _ = ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * (p : ℚ) ^ (2*(k-m)) - + vonStaudtIndicator (2 * m) p * (p : ℚ) ^ (2*(k-m) - 1)) * C / N := by rw [h] + _ = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * C * (p : ℚ) ^ (2*(k-m)) / N - + vonStaudtIndicator (2 * m) p * C * (p : ℚ) ^ (2*(k-m) - 1) / N := by ring lemma pIntegral_sub (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x - y) := @@ -1126,9 +1133,9 @@ lemma pIntegral_sub (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p lemma pIntegral_even_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) (ih : pIntegral p - (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : - pIntegral p (bernoulli (2*m) * ((2*k).choose (2*m)) * - (p : ℚ)^(2*(k-m)) / (2*(k-m) + 1)) := by + (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : + pIntegral p (bernoulli (2 * m) * ((2 * k).choose (2 * m)) * + (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1)) := by rw [even_term_eq_T1_sub_T2 k m p hm_lt] exact pIntegral_sub p _ _ (pIntegral_T1 k m p hk hm_pos hm_lt hp ih) (pIntegral_T2 k m p hk hm_pos hm_lt hp) @@ -1142,7 +1149,7 @@ theorem i1_term_forms_eq (k p : ℕ) (hk : k > 0) : field_simp [h1, h2] lemma pIntegral_i1_term_in_sum (k p : ℕ) (hk : k > 0) (hp : p.Prime) : - pIntegral p (bernoulli 1 * ((2*k + 1).choose 1) * (p : ℚ)^(2*k - 1) / (2*k + 1)) := by + pIntegral p (bernoulli 1 * ((2 * k + 1).choose 1) * (p : ℚ) ^ (2 * k - 1) / (2 * k + 1)) := by simp only [Nat.choose_one_right] rw [← i1_term_forms_eq k p hk] exact pIntegral_i1_term k p hk hp @@ -1171,14 +1178,14 @@ lemma denom_cast_eq (k m : ℕ) (hm_lt : m < k) : simp only [Nat.cast_sub h, Nat.cast_add, Nat.cast_mul, Nat.cast_ofNat, Nat.cast_one] lemma choose_mul_succ_rat (k m : ℕ) : - ((2*k).choose (2*m) : ℚ) * ((2*k + 1 : ℕ) : ℚ) = - ((2*k + 1).choose (2*m)) * ((2*k + 1 - 2*m) : ℕ) := by - have h := Nat.choose_mul_succ_eq (2*k) (2*m) + ((2 * k).choose (2 * m) : ℚ) * ((2 * k + 1 : ℕ) : ℚ) = + ((2 * k + 1).choose (2 * m)) * ((2 * k + 1 - 2 * m) : ℕ) := by + have h := Nat.choose_mul_succ_eq (2 * k) (2 * m) exact_mod_cast h lemma choose_div_core (k m : ℕ) (hm_lt : m < k) : - ((2*k + 1).choose (2*m) : ℚ) / (2*k + 1) = - ((2*k).choose (2*m) : ℚ) / (2*k - 2*m + 1) := by + ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = + ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by have h_denom : (2 * (k : ℚ) - 2 * m + 1) = ((2 * k - 2 * m + 1 : ℕ) : ℚ) := (denom_cast_eq k m hm_lt).symm conv_rhs => rw [h_denom] @@ -1186,21 +1193,23 @@ lemma choose_div_core (k m : ℕ) (hm_lt : m < k) : simp only [h_nat] have h_lhs_denom : (2 * (k : ℚ) + 1) = ((2 * k + 1 : ℕ) : ℚ) := by push_cast; ring conv_lhs => rw [h_lhs_denom] - have hk_pos : ((2*k + 1 : ℕ) : ℚ) ≠ 0 := by positivity - have hd_pos : ((2*k + 1 - 2*m : ℕ) : ℚ) ≠ 0 := by simp only [Nat.cast_ne_zero]; omega + have hk_pos : ((2 * k + 1 : ℕ) : ℚ) ≠ 0 := by positivity + have hd_pos : ((2 * k + 1 - 2 * m : ℕ) : ℚ) ≠ 0 := by simp only [Nat.cast_ne_zero]; omega rw [div_eq_div_iff hk_pos hd_pos] exact (choose_mul_succ_rat k m).symm lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : - ((2*k + 1).choose (2*m) : ℚ) * x / (2*k + 1) = - ((2*k).choose (2*m) : ℚ) * x / (2*k - 2*m + 1) := by + ((2 * k + 1).choose (2 * m) : ℚ) * x / (2 * k + 1) = + ((2 * k).choose (2 * m) : ℚ) * x / (2 * k - 2 * m + 1) := by have h := choose_div_core k m hm_lt rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] lemma pIntegral_case_one (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * k - 2 * m ≥ 2) : - pIntegral p (((2*k).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m - 1) / (2*k - 2*m + 1)) := by + pIntegral p (((2 * k).choose (2 * m) : ℚ) * + (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def have hd_ne_zero : d ≠ 0 := by omega have hd_plus_one_ne_zero : d + 1 ≠ 0 := by omega @@ -1212,18 +1221,20 @@ lemma pIntegral_case_one (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt push_cast ring rw [h_exp, h_denom_rat] - have h_pow_integral : pIntegral p ((p : ℚ)^(d - 1) / ((d + 1 : ℕ) : ℚ)) := by + have h_pow_integral : pIntegral p ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by apply pIntegral_pow_div p (d + 1) (d - 1) hp hd_plus_one_ne_zero exact valuation_bound_d_plus_1 p d hp hd - have h_eq : ((2*k).choose (2*m) : ℚ) * (p : ℚ)^(d - 1) / ((d + 1 : ℕ) : ℚ) = - ((2*k).choose (2*m) : ℕ) * ((p : ℚ)^(d - 1) / ((d + 1 : ℕ) : ℚ)) := by ring + have h_eq : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ) = + ((2 * k).choose (2 * m) : ℕ) * ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by ring rw [h_eq] exact pIntegral_mul_nat p _ _ h_pow_integral lemma pIntegral_second_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : - pIntegral p (vonStaudtIndicator (2*m) p * ((2*k + 1).choose (2*m)) * (p : ℚ)^(2*k - 2*m - 1) / - (2*k + 1)) := by + pIntegral p (vonStaudtIndicator (2 * m) p * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k + 1)) := by unfold vonStaudtIndicator split_ifs with h · simp only [one_mul] @@ -1237,13 +1248,13 @@ lemma pIntegral_second_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt lemma even_term_decomposition_identity (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) : - (bernoulli (2*m) * ((2*k + 1).choose (2*m)) * - (p : ℚ)^(2*k - 2*m) / (2*k + 1) : ℚ) = - (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * - ((2*k + 1).choose (2*m)) * - (p : ℚ)^(2*k - 2*m) / (2*k + 1) - - vonStaudtIndicator (2*m) p * ((2*k + 1).choose (2*m)) * - (p : ℚ)^(2*k - 2*m - 1) / (2*k + 1) := by + (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) : ℚ) = + (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - + vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1) := by have h2 : (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - @@ -1324,15 +1335,15 @@ lemma even_term_decomposition_identity (k m p : ℕ) (hk : k > 0) lemma pIntegral_coeff_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : - pIntegral p (((2*k + 1).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m) / (2*k + 1)) := by - have hsimp := choose_div_simplify k m ((p : ℚ)^(2*k - 2*m)) hm_lt + pIntegral p (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by + have hsimp := choose_div_simplify k m ((p : ℚ) ^ (2 * k - 2 * m)) hm_lt rw [hsimp] have hd_ge_2 : 2 * k - 2 * m ≥ 2 := by omega - have hp_factor : ((2*k).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m) / (2*k - 2*m + 1) = - (p : ℚ) * (((2*k).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m - 1) / - (2*k - 2*m + 1)) := by - have hpow : (p : ℚ)^(2*k - 2*m) = (p : ℚ) * (p : ℚ)^(2*k - 2*m - 1) := by - have heq : (2*k - 2*m : ℕ) = (2*k - 2*m - 1) + 1 := by omega + have hp_factor : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k - 2 * m + 1) = + (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / + (2 * k - 2 * m + 1)) := by + have hpow : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) := by + have heq : (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1) + 1 := by omega conv_lhs => rw [heq] exact pow_succ' _ _ rw [hpow] @@ -1344,29 +1355,33 @@ lemma pIntegral_coeff_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt lemma pIntegral_first_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) - (ih : pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : - pIntegral p ((bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k + 1).choose (2*m)) * - (p : ℚ)^(2*k - 2*m) / (2*k + 1)) := by - rw [show (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * ((2*k + 1).choose (2*m)) * - (p : ℚ)^(2*k - 2*m) / (2*k + 1) = (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p) * - (((2*k + 1).choose (2*m) : ℚ) * (p : ℚ)^(2*k - 2*m) / (2*k + 1)) by ring] + (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : + pIntegral p ((bernoulli (2 * m) + + vonStaudtIndicator (2 * m) p / p) * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by + rw [show (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = + (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * + (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) by ring] exact pIntegral_mul p _ _ ih (pIntegral_coeff_term k m p hk hm_pos hm_lt hp) lemma pIntegral_even_term_in_sum (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) (ih : pIntegral p - (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : - pIntegral p (bernoulli (2*m) * ((2*k + 1).choose (2*m)) * - (p : ℚ)^(2*k - 2*m) / (2*k + 1)) := by + (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : + pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by rw [even_term_decomposition_identity k m p hk hm_pos hm_lt] exact pIntegral_sub p _ _ (pIntegral_first_term k m p hk hm_pos hm_lt hp ih) (pIntegral_second_term k m p hk hm_pos hm_lt hp) lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) (ih : ∀ m, 0 < m → m < k → - pIntegral p (bernoulli (2*m) + vonStaudtIndicator (2*m) p / p)) : - pIntegral p (∑ i ∈ Finset.range (2*k), - bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k - i) / (2*k + 1)) := by + pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : + pIntegral p (∑ i ∈ Finset.range (2 * k), + bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by apply pIntegral_sum intro i hi rw [Finset.mem_range] at hi @@ -1377,7 +1392,7 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) exact pIntegral_i1_term_in_sum k p hk hp · set j := i + 2 with hj_def have hj_ge2 : j ≥ 2 := by omega - have hj_lt : j < 2*k := by omega + have hj_lt : j < 2 * k := by omega rcases Nat.even_or_odd j with ⟨m, hm⟩ | hodd · have hm_pos : m ≥ 1 := by omega have hm_lt : m < k := by omega @@ -1391,14 +1406,15 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) exact Nat.coprime_one_left_iff p |>.mpr trivial lemma power_sum_eq_faulhaber (k p : ℕ) : - (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = - ∑ i ∈ Finset.range (2*k + 1), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / - (2*k + 1) := by + (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = + ∑ i ∈ Finset.range (2 * k + 1), bernoulli i * + ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1) := by grind only [sum_range_pow] lemma faulhaber_top_term (k p : ℕ) : - bernoulli (2*k) * ((2*k + 1).choose (2*k)) * (p : ℚ)^(2*k + 1 - 2*k) / (2*k + 1) = - p * bernoulli (2*k) := by + bernoulli (2 * k) * ((2 * k + 1).choose (2 * k)) * (p : ℚ) ^ (2 * k + 1 - 2 * k) / (2 * k + 1) = + p * bernoulli (2 * k) := by have h1 : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by have h2 : (2 * k + 1).choose (2 * k) = (2 * k + 1).choose 1 := by rw [← Nat.choose_symm_of_eq_add] @@ -1423,23 +1439,24 @@ lemma int_indicator_cast_eq_zmod (p l : ℕ) : split_ifs with h <;> simp [Int.cast_one, Int.cast_zero] lemma power_sum_indicator_divisible_by_p (k p : ℕ) (_hk : k > 0) (hp : p.Prime) : - ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) + - (if (p - 1 : ℕ) ∣ (2*k) then 1 else 0) = p * T := by - have h_cast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) + - (if (p - 1 : ℕ) ∣ (2*k) then 1 else 0)) : ZMod p) = 0 := by + ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T := by + have h_cast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0)) : ZMod p) = 0 := by simp only [Int.cast_add] rw [int_sum_cast_eq_zmod_sum, int_indicator_cast_eq_zmod] - exact power_sum_add_indicator_eq_zero p (2*k) hp + exact power_sum_add_indicator_eq_zero p (2 * k) hp rw [ZMod.intCast_zmod_eq_zero_iff_dvd] at h_cast exact h_cast lemma faulhaber_split_top_term (k p : ℕ) : - (∑ i ∈ Finset.range (2*k + 1), - bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / - (2*k + 1)) = - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / - (2*k + 1)) + - bernoulli (2*k) * ((2*k + 1).choose (2*k)) * (p : ℚ)^(2*k + 1 - 2*k) / (2*k + 1) := by + (∑ i ∈ Finset.range (2 * k + 1), + bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / + (2 * k + 1)) = + (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / + (2 * k + 1)) + + bernoulli (2 * k) * ((2 * k + 1).choose (2 * k)) * + (p : ℚ) ^ (2 * k + 1 - 2 * k) / (2 * k + 1) := by have h3 : Finset.range (2 * k + 1) = Finset.range (2 * k) ∪ {2 * k} := by ext x; simp [Finset.mem_range]; omega have h4 : Disjoint (Finset.range (2 * k)) ({2 * k} : Finset ℕ) := by @@ -1447,10 +1464,10 @@ lemma faulhaber_split_top_term (k p : ℕ) : rw [h3, Finset.sum_union h4, Finset.sum_singleton] lemma rat_power_sum_eq_filter_ne_zero (k p : ℕ) (hk : k > 0) : - (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = - ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by - have h1 : (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = - ∑ v ∈ Finset.range p, if v = 0 then 0 else (v : ℚ)^(2*k) := by + (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = + ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by + have h1 : (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = + ∑ v ∈ Finset.range p, if v = 0 then 0 else (v : ℚ) ^ (2 * k) := by apply Finset.sum_congr rfl intro v _ by_cases h : v = 0 @@ -1459,27 +1476,27 @@ lemma rat_power_sum_eq_filter_ne_zero (k p : ℕ) (hk : k > 0) : simp [this] · have h2 : (v : ℚ) ≠ 0 := by norm_cast simp [h] - have h2 : ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ)^(2*k)) = - ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) := by - calc ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ)^(2*k)) = - ∑ v ∈ Finset.range p, (if v ≠ 0 then (v : ℚ)^(2*k) else 0) := by + have h2 : ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ) ^ (2 * k)) = + ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ) ^ (2 * k) := by + calc ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ) ^ (2 * k)) = + ∑ v ∈ Finset.range p, (if v ≠ 0 then (v : ℚ) ^ (2 * k) else 0) := by apply Finset.sum_congr rfl intro v _ by_cases h : v = 0 <;> simp [h] - _ = ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) := by + _ = ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ) ^ (2 * k) := by rw [Finset.sum_filter] - have h3 : ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) = - ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by simp [Finset.sum_filter] - calc (∑ v ∈ Finset.range p, (v : ℚ)^(2*k)) = - ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ)^(2*k)) := by rw [h1] - _ = ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ)^(2*k) := by rw [h2] - _ = ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by rw [h3] + have h3 : ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ) ^ (2 * k) = + ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by simp [Finset.sum_filter] + calc (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = + ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ) ^ (2 * k)) := by rw [h1] + _ = ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ) ^ (2 * k) := by rw [h2] + _ = ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by rw [h3] lemma remainder_div_p (k p : ℕ) (hp : p.Prime) : - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / - (2*k + 1)) / p = - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k - i) / - (2*k + 1)) := by + (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / + (2 * k + 1)) / p = + (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / + (2 * k + 1)) := by have h0 : (∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = ∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * @@ -1506,76 +1523,95 @@ lemma remainder_div_p (k p : ℕ) (hp : p.Prime) : exact_mod_cast h0 lemma algebraic_rearrangement (k p : ℕ) (T : ℤ) (hp : p.Prime) - (hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) + vonStaudtIndicator (2*k) p = + (hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = (p : ℚ) * (T : ℚ)) - (hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) = - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / - (2*k + 1)) + p * bernoulli (2*k)) : - bernoulli (2*k) + vonStaudtIndicator (2*k) p / p = - T - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / - (2*k + 1)) / p := by - have h7 : bernoulli (2*k) + (1 / (p : ℚ)) * vonStaudtIndicator (2*k) p = - (T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * - (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) := by + (hFaul : (∑ v ∈ Finset.range p with v ≠ 0, + (v : ℚ) ^ (2 * k)) = + (∑ i ∈ Finset.range (2 * k), bernoulli i * + ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / + (2 * k + 1)) + p * bernoulli (2 * k)) : + bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = + T - (∑ i ∈ Finset.range (2 * k), bernoulli i * + ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by + have h7 : bernoulli (2 * k) + + (1 / (p : ℚ)) * vonStaudtIndicator (2 * k) p = + (T : ℚ) - (1 / (p : ℚ)) * + (∑ i ∈ Finset.range (2 * k), bernoulli i * + ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) := by have h8 : (p : ℚ) ≠ 0 := by norm_cast; simp_all [hp.ne_zero] - have h9 : (p : ℚ) * bernoulli (2*k) + (p : ℚ) * ((1 / (p : ℚ)) * vonStaudtIndicator (2*k) p) = - (p : ℚ) * ((T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2*k), bernoulli i * - ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / (2*k + 1))) := by - calc (p : ℚ) * bernoulli (2*k) + (p : ℚ) * ((1 / (p : ℚ)) * vonStaudtIndicator (2*k) p) = - (p : ℚ) * bernoulli (2*k) + vonStaudtIndicator (2*k) p := by field_simp [h8] - _ = (p : ℚ) * bernoulli (2*k) + vonStaudtIndicator (2*k) p := by rfl - _ = (p : ℚ) * (T : ℚ) - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * - (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) := by linarith - _ = (p : ℚ) * ((T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2*k), bernoulli i * - ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / (2*k + 1))) := by field_simp [h8] - have h11 : bernoulli (2*k) + (1 / (p : ℚ)) * vonStaudtIndicator (2*k) p = - (T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * - (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) := by + have h9 : (p : ℚ) * bernoulli (2 * k) + + (p : ℚ) * ((1 / (p : ℚ)) * + vonStaudtIndicator (2 * k) p) = + (p : ℚ) * ((T : ℚ) - (1 / (p : ℚ)) * + (∑ i ∈ Finset.range (2 * k), bernoulli i * + ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / + (2 * k + 1))) := by + calc (p : ℚ) * bernoulli (2 * k) + (p : ℚ) * ((1 / (p : ℚ)) * vonStaudtIndicator (2 * k) p) = + (p : ℚ) * bernoulli (2 * k) + vonStaudtIndicator (2 * k) p := by field_simp [h8] + _ = (p : ℚ) * bernoulli (2 * k) + vonStaudtIndicator (2 * k) p := by rfl + _ = (p : ℚ) * (T : ℚ) - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) := by linarith + _ = (p : ℚ) * ((T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2 * k), bernoulli i * + ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1))) := by field_simp [h8] + have h11 : bernoulli (2 * k) + + (1 / (p : ℚ)) * vonStaudtIndicator (2 * k) p = + (T : ℚ) - (1 / (p : ℚ)) * + (∑ i ∈ Finset.range (2 * k), bernoulli i * + ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) := by apply mul_left_cancel₀ (show (p : ℚ) ≠ 0 by exact_mod_cast hp.ne_zero) linarith linarith - have h8 : bernoulli (2*k) + vonStaudtIndicator (2*k) p / p = - T - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k + 1 - i) / - (2*k + 1)) / p := by + have h8 : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = + T - (∑ i ∈ Finset.range (2 * k), bernoulli i * + ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by have h9 : (p : ℚ) ≠ 0 := by norm_cast; simp_all [hp.ne_zero] - calc bernoulli (2*k) + vonStaudtIndicator (2*k) p / p = - bernoulli (2*k) + (1 / (p : ℚ)) * vonStaudtIndicator (2*k) p := by field_simp [h9] - _ = (T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * - (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) := by exact h7 - _ = T - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * - (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) / p := by field_simp [h9] + calc bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = + bernoulli (2 * k) + (1 / (p : ℚ)) * vonStaudtIndicator (2 * k) p := by field_simp [h9] + _ = (T : ℚ) - (1 / (p : ℚ)) * + (∑ i ∈ Finset.range (2 * k), bernoulli i * + ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / + (2 * k + 1)) := by exact h7 + _ = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by field_simp [h9] exact h8 lemma divisibility_to_rat_eq (k p : ℕ) (T : ℤ) (_hp : p.Prime) - (hT : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) + - (if (p - 1 : ℕ) ∣ (2*k) then 1 else 0) = p * T) : - (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) + vonStaudtIndicator (2*k) p = p * T := by - have h1 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) : ℚ) = - ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k) := by norm_cast - have h2 : ((if (p - 1 : ℕ) ∣ (2*k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = - vonStaudtIndicator (2*k) p := by + (hT : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T) : + (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + + vonStaudtIndicator (2 * k) p = p * T := by + have h1 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) = + ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by norm_cast + have h2 : ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = + vonStaudtIndicator (2 * k) p := by split_ifs at * <;> simp_all [vonStaudtIndicator] have h3 : ((p : ℤ) * T : ℚ) = p * T := by norm_cast - have h4 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) : ℚ) + - ((if (p - 1 : ℕ) ∣ (2*k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = (p : ℚ) * T := by + have h4 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + + ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = (p : ℚ) * T := by norm_cast at hT ⊢ - calc (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) + vonStaudtIndicator (2*k) p = - ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ)^(2*k)) : ℚ) + - ((if (p - 1 : ℕ) ∣ (2*k) then (1 : ℤ) else (0 : ℤ)) : ℚ) := by rw [h1, h2] + calc (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = + ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + + ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) := by rw [h1, h2] _ = (p : ℚ) * T := by rw [h4] _ = p * T := by simp lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Prime) : - ∃ T : ℤ, bernoulli (2*k) + vonStaudtIndicator (2*k) p / p = - T - (∑ i ∈ Finset.range (2*k), - bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k - i) / (2*k + 1)) := by + ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = + T - (∑ i ∈ Finset.range (2 * k), + bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by obtain ⟨T, hT⟩ := power_sum_indicator_divisible_by_p k p hk hp use T - have hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) + vonStaudtIndicator (2*k) p = + have hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = p * T := divisibility_to_rat_eq k p T hp hT - have hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ)^(2*k)) = - (∑ i ∈ Finset.range (2*k), bernoulli i * ((2*k + 1).choose i) * - (p : ℚ)^(2*k + 1 - i) / (2*k + 1)) + p * bernoulli (2*k) := by + have hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = + (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by rw [← rat_power_sum_eq_filter_ne_zero k p hk, power_sum_eq_faulhaber, faulhaber_split_top_term, faulhaber_top_term] have hAlg := algebraic_rearrangement k p T hp hT' hFaul @@ -1588,8 +1624,8 @@ lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) (hp : p.Pr obtain ⟨T, hT⟩ := bernoulli_plus_indicator_rearrangement k p hk hp rw [hT] have hT_int : pIntegral p (T : ℚ) := pIntegral_of_int p T - have hR : pIntegral p (∑ i ∈ Finset.range (2*k), - bernoulli i * ((2*k + 1).choose i) * (p : ℚ)^(2*k - i) / (2*k + 1)) := by + have hR : pIntegral p (∑ i ∈ Finset.range (2 * k), + bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by apply pIntegral_remainder k p hk hp intro m hm_pos hm_lt exact ih m hm_lt hm_pos From 231c7e17a13e54c77836a5c94f4347ce7fb36546 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 18:17:48 -0800 Subject: [PATCH 04/70] style(NumberTheory/Bernoulli): golf proofs in vonStaudtClausen section Simplify several proofs by inlining single-use haves, using pow_succ, removing redundant intermediate steps, and leveraging Finset.sum_filter. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 75 +++++++---------------------- 1 file changed, 17 insertions(+), 58 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 06f3063751b51d..433e9c07ca8098 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -448,8 +448,7 @@ lemma cast_ne_zero_of_mem_filter (p _l : ℕ) (_hp : p.Prime) (v : ℕ) simp only [Finset.mem_filter, Finset.mem_range] at hv intro h have h1 : (p : ℕ) ∣ v := by simpa [ZMod.natCast_eq_zero_iff] using h - have h2 : p ≤ v := Nat.le_of_dvd (by omega) h1 - omega + exact absurd (Nat.le_of_dvd (by omega) h1) (by omega) lemma power_sum_eq_neg_one_mod_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) ∣ l) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = -1 := by @@ -536,15 +535,13 @@ lemma generator_pow_ne_one (p l : ℕ) [hp : Fact p.Prime] (_hp2 : p ≠ 2) lemma geom_sum_of_root_of_unity (p : ℕ) [hp : Fact p.Prime] (x : ZMod p) (hx1 : x ≠ 1) (hxp : x ^ (p - 1) = 1) : ∑ i ∈ Finset.range (p - 1), x ^ i = 0 := by - have h_sum : ∑ i ∈ Finset.range (p - 1), x ^ i = (x ^ (p - 1) - 1) / (x - 1) := - geom_sum_eq hx1 (p - 1) + have := geom_sum_eq hx1 (p - 1) aesop lemma generator_pow_card_sub_one_eq_one (p l : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : ((g : ZMod p) ^ l) ^ (p - 1) = 1 := by - have h2 : (g : ZMod p) ^ l ≠ 0 := pow_ne_zero _ (Units.ne_zero g) - exact ZMod.pow_card_sub_one_eq_one h2 + exact ZMod.pow_card_sub_one_eq_one (pow_ne_zero _ (Units.ne_zero g)) lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hp2 : p ≠ 2) (hndvd : ¬(p - 1) ∣ l) : @@ -860,12 +857,10 @@ lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : pIntegral 2 (bernoulli 1 * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) := by - have h1 : bernoulli 1 = -1 / 2 := by norm_num [bernoulli_one] - rw [h1] + rw [show bernoulli 1 = -1 / 2 from by norm_num [bernoulli_one]] have h2 : ((-1 / 2 : ℚ) * (2 * k : ℚ) * (2 : ℚ) ^ (2 * k - 1) / (2 * k : ℚ)) = (-((2 : ℚ) ^ (2 * k - 1)) / 2 : ℚ) := by - have h3 : (2 * k : ℚ) ≠ 0 := by positivity - field_simp [h3] + field_simp [show (2 * k : ℚ) ≠ 0 from by positivity] rw [h2] have h3 : (-((2 : ℚ) ^ (2 * k - 1)) / 2 : ℚ) = (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 := by norm_cast @@ -874,11 +869,7 @@ lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by have h8 : (2 : ℤ) ^ (2 * k - 1) = (2 : ℤ) ^ (2 * k - 2) * 2 := by have h9 : (2 * k - 1 : ℕ) = (2 * k - 2 : ℕ) + 1 := by omega - have h10 : (2 : ℤ) ^ (2 * k - 1) = (2 : ℤ) ^ ((2 * k - 2 : ℕ) + 1) := by rw [h9] - rw [h10] - have h11 : (2 : ℤ) ^ ((2 * k - 2 : ℕ) + 1) = (2 : ℤ) ^ (2 * k - 2) * 2 := by - simp [pow_add, pow_one, mul_comm] - rw [h11] + rw [h9, pow_succ] have h9 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by have h10 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) = @@ -1084,12 +1075,8 @@ lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : have h2 : (B + I / p) * (p : ℚ) ^ (2*d) = B * (p : ℚ) ^ (2*d) + I * (p : ℚ) ^ (2*d - 1) := by by_cases h : (p : ℚ) = 0 · have h3 : (p : ℕ) = 0 := by norm_cast at h ⊢ - have h4 : 2 * d ≥ 1 := by omega have h5 : (p : ℚ) ^ (2*d) = 0 := by rw [h3]; norm_cast; simp; omega - have h6 : (p : ℚ) ^ (2*d - 1) = 0 := by - have h7 : (2 * d : ℕ) - 1 ≥ 0 := by omega - have h8 : (p : ℕ) = 0 := by norm_cast at h ⊢ - rw [h8]; norm_cast; simp; omega + have h6 : (p : ℚ) ^ (2*d - 1) = 0 := by rw [h3]; norm_cast; simp; omega simp_all · have h3 : (p : ℚ) ≠ 0 := by exact_mod_cast h calc (B + I / p) * (p : ℚ) ^ (2*d) = @@ -1301,14 +1288,8 @@ lemma even_term_decomposition_identity (k m p : ℕ) (hk : k > 0) (2 * k + 1) = 0 := by have h10 : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) ^ (2 * k - 2 * m - 1) * (p : ℚ) := by - have h102 : (2 * k - 2 * m : ℕ) = - (2 * k - 2 * m - 1 : ℕ) + 1 := by omega - have h104 : (p : ℚ) ^ (2 * k - 2 * m) = - (p : ℚ) ^ ((2 * k - 2 * m - 1 : ℕ) + 1) := by - rw [h102] - simp [pow_add, pow_one] - rw [h104] - simp [pow_add, pow_one] + have h102 : (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1 : ℕ) + 1 := by omega + conv_lhs => rw [h102, pow_succ] have h11 : (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * @@ -1416,10 +1397,7 @@ lemma faulhaber_top_term (k p : ℕ) : bernoulli (2 * k) * ((2 * k + 1).choose (2 * k)) * (p : ℚ) ^ (2 * k + 1 - 2 * k) / (2 * k + 1) = p * bernoulli (2 * k) := by have h1 : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by - have h2 : (2 * k + 1).choose (2 * k) = (2 * k + 1).choose 1 := by - rw [← Nat.choose_symm_of_eq_add] - ring_nf - rw [h2, Nat.choose_one_right] + rw [← Nat.choose_symm_of_eq_add (by omega : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] have h2 : (2 * k + 1 - 2 * k : ℕ) = 1 := by omega rw [h1, h2, pow_one] have h4 : (2 * k + 1 : ℚ) ≠ 0 := by positivity @@ -1466,31 +1444,13 @@ lemma faulhaber_split_top_term (k p : ℕ) : lemma rat_power_sum_eq_filter_ne_zero (k p : ℕ) (hk : k > 0) : (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by - have h1 : (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.range p, if v = 0 then 0 else (v : ℚ) ^ (2 * k) := by - apply Finset.sum_congr rfl - intro v _ - by_cases h : v = 0 - · simp [h] - have : k ≠ 0 := by omega - simp [this] - · have h2 : (v : ℚ) ≠ 0 := by norm_cast - simp [h] - have h2 : ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ) ^ (2 * k) := by - calc ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.range p, (if v ≠ 0 then (v : ℚ) ^ (2 * k) else 0) := by - apply Finset.sum_congr rfl - intro v _ - by_cases h : v = 0 <;> simp [h] - _ = ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ) ^ (2 * k) := by - rw [Finset.sum_filter] - have h3 : ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ) ^ (2 * k) = - ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by simp [Finset.sum_filter] - calc (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.range p, (if v = 0 then 0 else (v : ℚ) ^ (2 * k)) := by rw [h1] - _ = ∑ v ∈ Finset.filter (· ≠ 0) (Finset.range p), (v : ℚ) ^ (2 * k) := by rw [h2] - _ = ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by rw [h3] + conv_lhs => + arg 2; ext v + rw [show (v : ℚ) ^ (2 * k) = if v ≠ 0 then (v : ℚ) ^ (2 * k) else 0 by + split_ifs with h + · rfl + · simp [show v = 0 by omega, show 2 * k ≠ 0 from by omega]] + rw [Finset.sum_filter] lemma remainder_div_p (k p : ℕ) (hp : p.Prime) : (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / @@ -1552,7 +1512,6 @@ lemma algebraic_rearrangement (k p : ℕ) (T : ℤ) (hp : p.Prime) (2 * k + 1))) := by calc (p : ℚ) * bernoulli (2 * k) + (p : ℚ) * ((1 / (p : ℚ)) * vonStaudtIndicator (2 * k) p) = (p : ℚ) * bernoulli (2 * k) + vonStaudtIndicator (2 * k) p := by field_simp [h8] - _ = (p : ℚ) * bernoulli (2 * k) + vonStaudtIndicator (2 * k) p := by rfl _ = (p : ℚ) * (T : ℚ) - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) := by linarith _ = (p : ℚ) * ((T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2 * k), bernoulli i * From cead7cdfa8bc51aa32328a4a140d961e3a0bd657 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 18:47:16 -0800 Subject: [PATCH 05/70] style(NumberTheory/Bernoulli): remove redundant haves and inline omega proofs Remove `have IH := IH` identity bindings, unwrap redundant `have h1 := ...; exact h1` wrapping, inline single-use omega equalities into pow_succ rewrites, and merge consecutive single-use rewrite steps. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 70 ++++++++++------------------- 1 file changed, 24 insertions(+), 46 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 433e9c07ca8098..d482b48bd84794 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -868,8 +868,7 @@ lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : have h4 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by have h8 : (2 : ℤ) ^ (2 * k - 1) = (2 : ℤ) ^ (2 * k - 2) * 2 := by - have h9 : (2 * k - 1 : ℕ) = (2 * k - 2 : ℕ) + 1 := by omega - rw [h9, pow_succ] + rw [show (2 * k - 1 : ℕ) = (2 * k - 2 : ℕ) + 1 from by omega, pow_succ] have h9 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by have h10 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) = @@ -948,40 +947,29 @@ lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - | refl => norm_num | @step m hm IH => have hm : (3 : ℕ) ≤ m := hm - have IH := IH have h1 : 2 ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by omega) - have h2 : m - 1 + 1 = m := by omega - have h3 : 2 ^ (m - 1) * 2 = 2 ^ m := by - conv_rhs => rw [← h2] - exact (pow_succ 2 (m - 1)).symm calc m + 1 + 1 ≤ 2 ^ (m - 1) + 1 := by omega _ ≤ 2 ^ (m - 1) * 2 := by nlinarith - _ = 2 ^ m := h3 + _ = 2 ^ m := by conv_rhs => rw [show m = m - 1 + 1 from by omega]; exact pow_succ .. exact h d hd lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 ≤ p ^ (d - 1) := by - have h1 : d + 1 ≤ p ^ (d - 1) := by - have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by - intro d hd - induction hd with - | refl => - norm_num - omega - | @step m hm IH => - have hm : (2 : ℕ) ≤ m := hm - have IH := IH - have hm1 : m - 1 + 1 = m := by omega - have h3 : p ^ (m - 1) * p = p ^ m := by - conv_rhs => rw [← hm1] - exact (pow_succ p (m - 1)).symm - calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by omega - _ ≤ p ^ (m - 1) * p := by - have : p ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by omega) - nlinarith - _ = p ^ m := h3 - exact h2 d hd - exact h1 + have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by + intro d hd + induction hd with + | refl => + norm_num + omega + | @step m hm IH => + have hm : (2 : ℕ) ≤ m := hm + calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by omega + _ ≤ p ^ (m - 1) * p := by + have : p ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by omega) + nlinarith + _ = p ^ m := by + conv_rhs => rw [show m = m - 1 + 1 from by omega]; exact pow_succ .. + exact h2 d hd lemma pIntegral_pow_div_factor (k m p : ℕ) (_hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : pIntegral p ((p : ℚ) ^ (2*(k-m)) / (2*(↑k - ↑m) + 1)) := by @@ -1086,10 +1074,8 @@ lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : calc (I / p : ℚ) * (p : ℚ) ^ (2*d) = I * (p : ℚ) ^ (2*d) / p := by ring _ = I * (p : ℚ) ^ (2*d - 1) := by have h5 : (p : ℚ) ^ (2*d) = (p : ℚ) ^ (2*d - 1) * p := by - have h7 : (2 * d : ℕ) - 1 + 1 = 2 * d := by omega - calc (p : ℚ) ^ (2*d) = (p : ℚ) ^ ((2*d - 1) + 1) := by rw [h7] - _ = (p : ℚ) ^ (2*d - 1) * (p : ℚ)^1 := by rw [pow_add] - _ = (p : ℚ) ^ (2*d - 1) * p := by simp [pow_one] + conv_lhs => + rw [show 2 * d = (2 * d - 1) + 1 from by omega, pow_succ] rw [h5] field_simp [h3] rw [h4] @@ -1288,8 +1274,8 @@ lemma even_term_decomposition_identity (k m p : ℕ) (hk : k > 0) (2 * k + 1) = 0 := by have h10 : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) ^ (2 * k - 2 * m - 1) * (p : ℚ) := by - have h102 : (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1 : ℕ) + 1 := by omega - conv_lhs => rw [h102, pow_succ] + conv_lhs => + rw [show (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1 : ℕ) + 1 from by omega, pow_succ] have h11 : (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * @@ -1324,8 +1310,8 @@ lemma pIntegral_coeff_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by have hpow : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) := by - have heq : (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1) + 1 := by omega - conv_lhs => rw [heq] + conv_lhs => + rw [show (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1) + 1 from by omega] exact pow_succ' _ _ rw [hpow] ring @@ -1468,15 +1454,7 @@ lemma remainder_div_p (k p : ℕ) (hp : p.Prime) : intro i hi have h2 : i < 2 * k := Finset.mem_range.mp hi have h5 : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero hp - have h6 : ((p : ℚ) : ℚ) ^ (2 * k + 1 - i : ℕ) = - (p : ℚ) ^ ((2 * k - i : ℕ) + 1 : ℕ) := by - have h7 : (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 := by omega - rw [h7] - rw [h6] - have h7 : ((p : ℚ) : ℚ) ^ ((2 * k - i : ℕ) + 1 : ℕ) = - (p : ℚ) ^ (2 * k - i : ℕ) * (p : ℚ) := by - rw [pow_succ] - rw [h7] + rw [show (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 from by omega, pow_succ] field_simp [h5] rw [Finset.sum_div] exact Finset.sum_congr rfl fun i hi => h1 i hi From 2ee24153a5b9d04ceb0de8e0131872548c6982e4 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 19:28:32 -0800 Subject: [PATCH 06/70] style(NumberTheory/Bernoulli): inline 13 single-use helper lemmas into callers Merge trivial single-use helper lemmas directly into their sole call sites to reduce declaration count and improve code locality. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 92 +++++++---------------------- 1 file changed, 20 insertions(+), 72 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index d482b48bd84794..0f31d24a8e6138 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -440,9 +440,6 @@ lemma card_filter_range_ne_zero (p : ℕ) (_hp : p.Prime) : simp only [Finset.filter_ne', Finset.card_erase_of_mem (Finset.mem_range.mpr _hp.pos), Finset.card_range] -lemma zmod_nat_sub_one_eq_neg_one (p : ℕ) (hp : 0 < p) : ((p - 1 : ℕ) : ZMod p) = -1 := by - simp [Nat.cast_sub hp] - lemma cast_ne_zero_of_mem_filter (p _l : ℕ) (_hp : p.Prime) (v : ℕ) (hv : v ∈ (Finset.range p).filter (· ≠ 0)) : (v : ZMod p) ≠ 0 := by simp only [Finset.mem_filter, Finset.mem_range] at hv @@ -456,7 +453,7 @@ lemma power_sum_eq_neg_one_mod_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) zmod_pow_eq_one_of_dvd p l hp hdvd (v : ZMod p) (cast_ne_zero_of_mem_filter p l hp v hv) rw [Finset.sum_congr rfl h1, Finset.sum_const, card_filter_range_ne_zero p hp, nsmul_eq_mul, mul_one] - exact zmod_nat_sub_one_eq_neg_one p hp.pos + simp [Nat.cast_sub hp.pos] lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = @@ -485,9 +482,6 @@ lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : · intro v _ simp -lemma prime_ne_two_of_not_dvd_sub_one (p l : ℕ) (_hp : p.Prime) (hndvd : ¬(p - 1) ∣ l) : - p ≠ 2 := fun h => by subst h; simp at hndvd - lemma generator_orderOf_eq (p : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : orderOf g = p - 1 := by @@ -505,10 +499,6 @@ lemma pow_injective_on_range (p : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) rw [IsOfFinOrder.pow_eq_pow_iff_modEq hfin, hord] at heq exact Nat.ModEq.eq_of_lt_of_lt heq hi hj -lemma units_pow_coe_eq (p l : ℕ) (g : (ZMod p)ˣ) (i : ℕ) : - ((g ^ i : (ZMod p)ˣ) : ZMod p) ^ l = ((g : ZMod p) ^ l) ^ i := by - simp [← pow_mul, mul_comm] - lemma sum_units_eq_sum_range (p l : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) (hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : (∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l) = @@ -521,7 +511,7 @@ lemma sum_units_eq_sum_range (p l : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) rw [Finset.sum_image (pow_injective_on_range p g hg)] congr 1 ext i - exact units_pow_coe_eq p l g i + simp [← pow_mul, mul_comm] lemma generator_pow_ne_one (p l : ℕ) [hp : Fact p.Prime] (_hp2 : p ≠ 2) (hndvd : ¬(p - 1) ∣ l) (g : (ZMod p)ˣ) @@ -556,7 +546,7 @@ lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hp2 : p lemma power_sum_eq_zero_mod_of_not_dvd (p l : ℕ) (hp : p.Prime) (hndvd : ¬(p - 1) ∣ l) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = 0 := by haveI : Fact p.Prime := ⟨hp⟩ - have hp2 : p ≠ 2 := prime_ne_two_of_not_dvd_sub_one p l hp hndvd + have hp2 : p ≠ 2 := fun h => by subst h; simp at hndvd rw [sum_pow_eq_sum_units_pow p l] exact sum_units_pow_eq_zero_of_not_dvd p l hp2 hndvd @@ -790,25 +780,13 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : lemma pIntegral_of_int (p : ℕ) (z : ℤ) : pIntegral p z := by simp_all [pIntegral] -lemma ordCompl_coprime_of_prime (p M : ℕ) (hp : p.Prime) (hM : M ≠ 0) : - (M / p ^ M.factorization p).Coprime p := - (Nat.coprime_ordCompl hp hM).symm - -lemma pIntegral_of_den_dvd_coprime (p : ℕ) (x : ℚ) (M : ℕ) - (hdvd : x.den ∣ M) (hcop : M.Coprime p) : pIntegral p x := - hcop.coprime_dvd_left hdvd - -lemma ordCompl_ne_zero (p M : ℕ) (_hp : p.Prime) (hM : M ≠ 0) : - M / p ^ M.factorization p ≠ 0 := - (Nat.ordCompl_pos p hM).ne' - lemma pow_div_eq_pow_sub_div_ordCompl (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) (hv : M.factorization p ≤ N) : (p : ℚ)^N / M = (p : ℚ) ^ (N - M.factorization p) / (M / p ^ M.factorization p) := by set e := M.factorization p with he set M' := M / p ^ e with hM' have hdecomp : p ^ e * M' = M := Nat.ordProj_mul_ordCompl_eq_self M p - have hM'_ne : M' ≠ 0 := ordCompl_ne_zero p M hp hM + have hM'_ne : M' ≠ 0 := (Nat.ordCompl_pos p hM).ne' have hM_cast : (M : ℚ) = (p ^ e : ℕ) * (M' : ℕ) := by rw [← hdecomp]; simp rw [hM_cast] have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr hp.ne_zero @@ -828,8 +806,8 @@ lemma den_pow_div_dvd (p M' k : ℕ) (_hM' : M' ≠ 0) : lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ)^N / M) := by set M' := M / p ^ M.factorization p with hM'_def - have hM'_ne : M' ≠ 0 := ordCompl_ne_zero p M hp hM - have hM'_cop : M'.Coprime p := ordCompl_coprime_of_prime p M hp hM + have hM'_ne : M' ≠ 0 := (Nat.ordCompl_pos p hM).ne' + have hM'_cop : M'.Coprime p := (Nat.coprime_ordCompl hp hM).symm rw [pow_div_eq_pow_sub_div_ordCompl p M N hp hM hv] have hcast : (M : ℚ) / (p : ℚ) ^ M.factorization p = (M' : ℚ) := by rw [hM'_def] @@ -838,7 +816,7 @@ lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) rw [hcast] have hdvd : ((p : ℚ) ^ (N - M.factorization p) / M').den ∣ M' := den_pow_div_dvd p M' (N - M.factorization p) hM'_ne - exact pIntegral_of_den_dvd_coprime p _ M' hdvd hM'_cop + exact hM'_cop.coprime_dvd_left hdvd lemma valuation_bound (p n : ℕ) (hp : p.Prime) (_hn : n ≥ 1) : (n + 1).factorization p ≤ n := @@ -881,17 +859,6 @@ lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : rw [h4] norm_num [pIntegral] -lemma i1_term_simplify (k p : ℕ) (hk : k > 0) : - bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = -(p : ℚ) ^ (2 * k - 1) / 2 := by - have h1 : bernoulli 1 = (-1 : ℚ) / 2 := by norm_num [bernoulli] - rw [h1] - have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega - field_simp [h2] - -lemma two_coprime_odd_prime (p : ℕ) (hp : p.Prime) (hp2 : p ≠ 2) : - Nat.Coprime 2 p := - Odd.coprime_two_left (Nat.Prime.odd_of_ne_two hp hp2) - lemma den_neg_pow_div_two_dvd_two (k p : ℕ) : (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by rw [neg_div, Rat.den_neg_eq_den, ← Nat.cast_pow] @@ -902,11 +869,15 @@ lemma den_neg_pow_div_two_dvd_two (k p : ℕ) : lemma pIntegral_neg_pow_div_two (k p : ℕ) (hp : p.Prime) (hp2 : p ≠ 2) : pIntegral p (-(p : ℚ) ^ (2 * k - 1) / 2) := by unfold pIntegral - exact Nat.Coprime.of_dvd_left (den_neg_pow_div_two_dvd_two k p) (two_coprime_odd_prime p hp hp2) + exact Nat.Coprime.of_dvd_left (den_neg_pow_div_two_dvd_two k p) + (Odd.coprime_two_left (hp.odd_of_ne_two hp2)) lemma pIntegral_i1_term_p_odd (k p : ℕ) (hk : k > 0) (hp : p.Prime) (hp2 : p ≠ 2) : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by - rw [i1_term_simplify k p hk] + rw [show bernoulli 1 = (-1 : ℚ) / 2 from by norm_num [bernoulli]] + have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega + field_simp [h2] + rw [show -(↑↑p ^ (2 * k - 1) / (2 : ℚ)) = -↑↑p ^ (2 * k - 1) / 2 from by ring] exact pIntegral_neg_pow_div_two k p hp hp2 lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : @@ -1142,34 +1113,21 @@ lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : omega · exact hd -lemma nat_sub_add_eq (k m : ℕ) (hm_lt : m < k) : - 2 * k + 1 - 2 * m = 2 * k - 2 * m + 1 := by grind - -lemma denom_cast_eq (k m : ℕ) (hm_lt : m < k) : - ((2 * k - 2 * m + 1 : ℕ) : ℚ) = 2 * ↑k - 2 * ↑m + 1 := by - have h : 2 * m ≤ 2 * k := by omega - simp only [Nat.cast_sub h, Nat.cast_add, Nat.cast_mul, Nat.cast_ofNat, Nat.cast_one] - -lemma choose_mul_succ_rat (k m : ℕ) : - ((2 * k).choose (2 * m) : ℚ) * ((2 * k + 1 : ℕ) : ℚ) = - ((2 * k + 1).choose (2 * m)) * ((2 * k + 1 - 2 * m) : ℕ) := by - have h := Nat.choose_mul_succ_eq (2 * k) (2 * m) - exact_mod_cast h - lemma choose_div_core (k m : ℕ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by - have h_denom : (2 * (k : ℚ) - 2 * m + 1) = ((2 * k - 2 * m + 1 : ℕ) : ℚ) := - (denom_cast_eq k m hm_lt).symm + have h_denom : (2 * (k : ℚ) - 2 * m + 1) = ((2 * k - 2 * m + 1 : ℕ) : ℚ) := by + have h : 2 * m ≤ 2 * k := by omega + simp only [Nat.cast_sub h, Nat.cast_add, Nat.cast_mul, Nat.cast_ofNat, Nat.cast_one] conv_rhs => rw [h_denom] - have h_nat := (nat_sub_add_eq k m hm_lt).symm - simp only [h_nat] + have h_nat : 2 * k + 1 - 2 * m = 2 * k - 2 * m + 1 := by grind + simp only [h_nat.symm] have h_lhs_denom : (2 * (k : ℚ) + 1) = ((2 * k + 1 : ℕ) : ℚ) := by push_cast; ring conv_lhs => rw [h_lhs_denom] have hk_pos : ((2 * k + 1 : ℕ) : ℚ) ≠ 0 := by positivity have hd_pos : ((2 * k + 1 - 2 * m : ℕ) : ℚ) ≠ 0 := by simp only [Nat.cast_ne_zero]; omega rw [div_eq_div_iff hk_pos hd_pos] - exact (choose_mul_succ_rat k m).symm + exact_mod_cast (Nat.choose_mul_succ_eq (2 * k) (2 * m)).symm lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) * x / (2 * k + 1) = @@ -1393,22 +1351,12 @@ lemma faulhaber_top_term (k p : ℕ) : norm_cast ring_nf -lemma int_sum_cast_eq_zmod_sum (p l : ℕ) : - (↑(∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ l) : ZMod p) = - ∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l := by simp - -lemma int_indicator_cast_eq_zmod (p l : ℕ) : - (↑(if (p - 1 : ℕ) ∣ l then (1 : ℤ) else 0) : ZMod p) = - if (p - 1 : ℕ) ∣ l then (1 : ZMod p) else 0 := by - split_ifs with h <;> simp [Int.cast_one, Int.cast_zero] - lemma power_sum_indicator_divisible_by_p (k p : ℕ) (_hk : k > 0) (hp : p.Prime) : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T := by have h_cast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0)) : ZMod p) = 0 := by - simp only [Int.cast_add] - rw [int_sum_cast_eq_zmod_sum, int_indicator_cast_eq_zmod] + push_cast exact power_sum_add_indicator_eq_zero p (2 * k) hp rw [ZMod.intCast_zmod_eq_zero_iff_dvd] at h_cast exact h_cast From b8c3f4bd8c7e057836231093bbe6039dc9f114f4 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 20:15:18 -0800 Subject: [PATCH 07/70] style(NumberTheory/Bernoulli): golf long proofs with field_simp/ring Golf 4 verbose proofs by replacing manual have-chains with field_simp/ring, leveraging core_algebraic_identity, and eliminating redundant cast round-trips. Net savings: ~130 lines. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 200 +++++----------------------- 1 file changed, 34 insertions(+), 166 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 0f31d24a8e6138..3f3c30cb264aa2 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -65,7 +65,6 @@ then defined as `bernoulli := (-1)^n * bernoulli'`. if n = 1 then 1 else 0` -/ -set_option linter.style.longFile 1800 @[expose] public section @@ -836,27 +835,12 @@ lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : pIntegral 2 (bernoulli 1 * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) := by rw [show bernoulli 1 = -1 / 2 from by norm_num [bernoulli_one]] - have h2 : ((-1 / 2 : ℚ) * (2 * k : ℚ) * (2 : ℚ) ^ (2 * k - 1) / (2 * k : ℚ)) = - (-((2 : ℚ) ^ (2 * k - 1)) / 2 : ℚ) := by - field_simp [show (2 * k : ℚ) ≠ 0 from by positivity] - rw [h2] - have h3 : (-((2 : ℚ) ^ (2 * k - 1)) / 2 : ℚ) = - (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 := by norm_cast - rw [h3] - have h4 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = - (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by - have h8 : (2 : ℤ) ^ (2 * k - 1) = (2 : ℤ) ^ (2 * k - 2) * 2 := by - rw [show (2 * k - 1 : ℕ) = (2 * k - 2 : ℕ) + 1 from by omega, pow_succ] - have h9 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) / 2 = - (-((2 : ℤ) ^ (2 * k - 2) : ℤ) : ℚ) := by - have h10 : (-((2 : ℤ) ^ (2 * k - 1) : ℤ) : ℚ) = - (-((2 : ℤ) ^ (2 * k - 2) : ℤ) * 2 : ℚ) := by - norm_cast at h8 ⊢ - simp [h8] - rw [h10] - field_simp - exact h9 - rw [h4] + have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = + (-(2 : ℤ) ^ (2 * k - 2) : ℤ) := by + have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by + rw [show 2 * k - 1 = (2 * k - 2) + 1 from by omega, pow_succ] + rw [hpow]; push_cast; field_simp [show (2 * k : ℚ) ≠ 0 from by positivity] + rw [h] norm_num [pIntegral] lemma den_neg_pow_div_two_dvd_two (k p : ℕ) : @@ -1029,29 +1013,11 @@ lemma pIntegral_T2 (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt : m < lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : B * (p : ℚ) ^ (2*d) = (B + I / p) * (p : ℚ) ^ (2*d) - I * (p : ℚ) ^ (2*d - 1) := by - have h1 : (B + I / p) * (p : ℚ) ^ (2*d) - I * (p : ℚ) ^ (2*d - 1) = - B * (p : ℚ) ^ (2*d) + I * (p : ℚ) ^ (2*d - 1) - I * (p : ℚ) ^ (2*d - 1) := by - have h2 : (B + I / p) * (p : ℚ) ^ (2*d) = B * (p : ℚ) ^ (2*d) + I * (p : ℚ) ^ (2*d - 1) := by - by_cases h : (p : ℚ) = 0 - · have h3 : (p : ℕ) = 0 := by norm_cast at h ⊢ - have h5 : (p : ℚ) ^ (2*d) = 0 := by rw [h3]; norm_cast; simp; omega - have h6 : (p : ℚ) ^ (2*d - 1) = 0 := by rw [h3]; norm_cast; simp; omega - simp_all - · have h3 : (p : ℚ) ≠ 0 := by exact_mod_cast h - calc (B + I / p) * (p : ℚ) ^ (2*d) = - B * (p : ℚ) ^ (2*d) + (I / p) * (p : ℚ) ^ (2*d) := by ring - _ = B * (p : ℚ) ^ (2*d) + I * (p : ℚ) ^ (2*d - 1) := by - have h4 : (I / p : ℚ) * (p : ℚ) ^ (2*d) = I * (p : ℚ) ^ (2*d - 1) := by - calc (I / p : ℚ) * (p : ℚ) ^ (2*d) = I * (p : ℚ) ^ (2*d) / p := by ring - _ = I * (p : ℚ) ^ (2*d - 1) := by - have h5 : (p : ℚ) ^ (2*d) = (p : ℚ) ^ (2*d - 1) * p := by - conv_lhs => - rw [show 2 * d = (2 * d - 1) + 1 from by omega, pow_succ] - rw [h5] - field_simp [h3] - rw [h4] - rw [h2] - linarith + have hpow : (p : ℚ) ^ (2*d) = (p : ℚ) ^ (2*d - 1) * p := by + conv_lhs => rw [show 2 * d = (2 * d - 1) + 1 from by omega, pow_succ] + rcases eq_or_ne (p : ℚ) 0 with hp | hp + · simp [hp, zero_pow (show 2 * d - 1 ≠ 0 from by omega)] + · rw [hpow]; field_simp [hp]; ring lemma even_term_eq_T1_sub_T2 (k m p : ℕ) (hm_lt : m < k) : (bernoulli (2 * m) * ((2 * k).choose (2 * m)) * (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1) : ℚ) = @@ -1147,10 +1113,7 @@ lemma pIntegral_case_one (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt have h_exp : 2 * k - 2 * m - 1 = d - 1 := by omega have hkm : 2 * m ≤ 2 * k := by omega have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by - have heq : d = 2 * k - 2 * m := rfl - rw [heq, Nat.cast_add (2 * k - 2 * m) 1, Nat.cast_sub hkm] - push_cast - ring + simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat] have h_pow_integral : pIntegral p ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by apply pIntegral_pow_div p (d + 1) (d - 1) hp hd_plus_one_ne_zero @@ -1177,8 +1140,8 @@ lemma pIntegral_second_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt rw [Rat.den_zero] exact Nat.coprime_one_left_iff p |>.mpr trivial -lemma even_term_decomposition_identity (k m p : ℕ) (hk : k > 0) - (hm_pos : m ≥ 1) (hm_lt : m < k) : +lemma even_term_decomposition_identity (k m p : ℕ) (_hk : k > 0) + (_hm_pos : m ≥ 1) (hm_lt : m < k) : (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) : ℚ) = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * @@ -1186,77 +1149,19 @@ lemma even_term_decomposition_identity (k m p : ℕ) (hk : k > 0) (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1) := by - have h2 : (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - - vonStaudtIndicator (2 * m) p * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k + 1) = (bernoulli (2 * m) * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / - (2 * k + 1) : ℚ) := by - have h3 : (bernoulli (2 * m) + - vonStaudtIndicator (2 * m) p / p) * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - - vonStaudtIndicator (2 * m) p * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k + 1) = (bernoulli (2 * m) * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / - (2 * k + 1)) + - (vonStaudtIndicator (2 * m) p / p * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / - (2 * k + 1)) - - (vonStaudtIndicator (2 * m) p * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k + 1)) := by ring_nf - rw [h3] - have h4 : (vonStaudtIndicator (2 * m) p / p * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) - - (vonStaudtIndicator (2 * m) p * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k + 1)) = 0 := by - by_cases h5 : (p - 1 : ℕ) ∣ (2 * m) - · have h6 : vonStaudtIndicator (2 * m) p = (1 : ℚ) := by simp [vonStaudtIndicator, h5] - rw [h6] - have h7 : (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / - (2 * k + 1) - - (1 : ℚ) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k + 1) = 0 := by - have h10 : (p : ℚ) ^ (2 * k - 2 * m) = - (p : ℚ) ^ (2 * k - 2 * m - 1) * (p : ℚ) := by - conv_lhs => - rw [show (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1 : ℕ) + 1 from by omega, pow_succ] - have h11 : (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / - (2 * k + 1) = - (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * - ((p : ℚ) ^ (2 * k - 2 * m - 1) * (p : ℚ)) / (2 * k + 1) := by rw [h10] - rw [h11] - have h12 : (1 : ℚ) / p * ((2 * k + 1).choose (2 * m)) * - ((p : ℚ) ^ (2 * k - 2 * m - 1) * (p : ℚ)) / (2 * k + 1) = - (1 : ℚ) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k + 1) := by - have h121 : (p : ℚ) ≠ 0 := by - by_contra h121 - have h122 : (p : ℕ) = 0 := by norm_cast at h121 ⊢ - have h123 : p > 0 := by by_contra _; simp_all - omega - field_simp [h121] - rw [h12] - ring_nf - linarith - · have h6 : vonStaudtIndicator (2 * m) p = (0 : ℚ) := by simp [vonStaudtIndicator, h5] - rw [h6] - norm_num - linarith - linarith + have hrw : 2 * k - 2 * m = 2 * (k - m) := by omega + simp only [hrw] + have h := core_algebraic_identity (bernoulli (2 * m)) + (vonStaudtIndicator (2 * m) p) p (k - m) (by omega) + set C := ((2 * k + 1).choose (2 * m) : ℚ) + set N := (2 * k + 1 : ℚ) + calc bernoulli (2 * m) * C * (p : ℚ) ^ (2 * (k - m)) / N + = (bernoulli (2 * m) * (p : ℚ) ^ (2 * (k - m))) * C / N := by ring + _ = ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / ↑p) * + (p : ℚ) ^ (2 * (k - m)) - + vonStaudtIndicator (2 * m) p * (p : ℚ) ^ (2 * (k - m) - 1)) * + C / N := by rw [h] + _ = _ := by ring lemma pIntegral_coeff_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : @@ -1421,50 +1326,13 @@ lemma algebraic_rearrangement (k p : ℕ) (T : ℤ) (hp : p.Prime) T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by - have h7 : bernoulli (2 * k) + - (1 / (p : ℚ)) * vonStaudtIndicator (2 * k) p = - (T : ℚ) - (1 / (p : ℚ)) * - (∑ i ∈ Finset.range (2 * k), bernoulli i * - ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) := by - have h8 : (p : ℚ) ≠ 0 := by norm_cast; simp_all [hp.ne_zero] - have h9 : (p : ℚ) * bernoulli (2 * k) + - (p : ℚ) * ((1 / (p : ℚ)) * - vonStaudtIndicator (2 * k) p) = - (p : ℚ) * ((T : ℚ) - (1 / (p : ℚ)) * - (∑ i ∈ Finset.range (2 * k), bernoulli i * - ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / - (2 * k + 1))) := by - calc (p : ℚ) * bernoulli (2 * k) + (p : ℚ) * ((1 / (p : ℚ)) * vonStaudtIndicator (2 * k) p) = - (p : ℚ) * bernoulli (2 * k) + vonStaudtIndicator (2 * k) p := by field_simp [h8] - _ = (p : ℚ) * (T : ℚ) - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) := by linarith - _ = (p : ℚ) * ((T : ℚ) - (1 / (p : ℚ)) * (∑ i ∈ Finset.range (2 * k), bernoulli i * - ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1))) := by field_simp [h8] - have h11 : bernoulli (2 * k) + - (1 / (p : ℚ)) * vonStaudtIndicator (2 * k) p = - (T : ℚ) - (1 / (p : ℚ)) * - (∑ i ∈ Finset.range (2 * k), bernoulli i * - ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) := by - apply mul_left_cancel₀ (show (p : ℚ) ≠ 0 by exact_mod_cast hp.ne_zero) - linarith - linarith - have h8 : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = - T - (∑ i ∈ Finset.range (2 * k), bernoulli i * - ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by - have h9 : (p : ℚ) ≠ 0 := by norm_cast; simp_all [hp.ne_zero] - calc bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = - bernoulli (2 * k) + (1 / (p : ℚ)) * vonStaudtIndicator (2 * k) p := by field_simp [h9] - _ = (T : ℚ) - (1 / (p : ℚ)) * - (∑ i ∈ Finset.range (2 * k), bernoulli i * - ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / - (2 * k + 1)) := by exact h7 - _ = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by field_simp [h9] - exact h8 + have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast hp.ne_zero + set S := (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + have key : (p : ℚ) * bernoulli (2 * k) + vonStaudtIndicator (2 * k) p = + (p : ℚ) * T - S := by linarith + field_simp [hp_ne] + linarith lemma divisibility_to_rat_eq (k p : ℕ) (T : ℤ) (_hp : p.Prime) (hT : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + From df32f12422cb89d82866a4ab318019fb99fd88e5 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 20:34:22 -0800 Subject: [PATCH 08/70] style(NumberTheory/Bernoulli): inline 9 single-use short lemmas into callers Remove lemmas with 1-2 line proof bodies that are used only once or not at all, inlining their proofs at call sites to reduce indirection. Dead code removed: pIntegral_add, pIntegral_even_term Inlined: geom_sum_of_root_of_unity, generator_pow_card_sub_one_eq_one, pIntegral_neg_pow_div_two, pIntegral_odd_term, power_sum_eq_faulhaber, coprime_add_of_coprime_den, von_staudt_clausen_pos Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 83 ++++++----------------------- 1 file changed, 17 insertions(+), 66 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 3f3c30cb264aa2..80c177163cd7e8 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -521,26 +521,16 @@ lemma generator_pow_ne_one (p l : ℕ) [hp : Fact p.Prime] (_hp2 : p ≠ 2) intro h exact hndvd (h_order ▸ orderOf_dvd_of_pow_eq_one (Units.ext (by simpa using h))) -lemma geom_sum_of_root_of_unity (p : ℕ) [hp : Fact p.Prime] (x : ZMod p) - (hx1 : x ≠ 1) (hxp : x ^ (p - 1) = 1) : - ∑ i ∈ Finset.range (p - 1), x ^ i = 0 := by - have := geom_sum_eq hx1 (p - 1) - aesop - -lemma generator_pow_card_sub_one_eq_one (p l : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) - (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : - ((g : ZMod p) ^ l) ^ (p - 1) = 1 := by - exact ZMod.pow_card_sub_one_eq_one (pow_ne_zero _ (Units.ne_zero g)) - lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hp2 : p ≠ 2) (hndvd : ¬(p - 1) ∣ l) : (∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l) = 0 := by haveI : IsCyclic (ZMod p)ˣ := ZMod.isCyclic_units_prime hp.out obtain ⟨g, hg⟩ := IsCyclic.exists_generator (α := (ZMod p)ˣ) rw [sum_units_eq_sum_range p l g hg] - apply geom_sum_of_root_of_unity p - · exact generator_pow_ne_one p l hp2 hndvd g hg - · exact generator_pow_card_sub_one_eq_one p l g hg + have hx1 := generator_pow_ne_one p l hp2 hndvd g hg + have hxp := ZMod.pow_card_sub_one_eq_one (pow_ne_zero l (Units.ne_zero g)) + have := geom_sum_eq hx1 (p - 1) + aesop lemma power_sum_eq_zero_mod_of_not_dvd (p l : ℕ) (hp : p.Prime) (hndvd : ¬(p - 1) ∣ l) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = 0 := by @@ -850,19 +840,15 @@ lemma den_neg_pow_div_two_dvd_two (k p : ℕ) : have h := Rat.den_dvd (p ^ (2 * k - 1)) 2 exact Int.natCast_dvd_natCast.mp h -lemma pIntegral_neg_pow_div_two (k p : ℕ) (hp : p.Prime) (hp2 : p ≠ 2) : - pIntegral p (-(p : ℚ) ^ (2 * k - 1) / 2) := by - unfold pIntegral - exact Nat.Coprime.of_dvd_left (den_neg_pow_div_two_dvd_two k p) - (Odd.coprime_two_left (hp.odd_of_ne_two hp2)) - lemma pIntegral_i1_term_p_odd (k p : ℕ) (hk : k > 0) (hp : p.Prime) (hp2 : p ≠ 2) : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by rw [show bernoulli 1 = (-1 : ℚ) / 2 from by norm_num [bernoulli]] have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega field_simp [h2] rw [show -(↑↑p ^ (2 * k - 1) / (2 : ℚ)) = -↑↑p ^ (2 * k - 1) / 2 from by ring] - exact pIntegral_neg_pow_div_two k p hp hp2 + unfold pIntegral + exact Nat.Coprime.of_dvd_left (den_neg_pow_div_two_dvd_two k p) + (Odd.coprime_two_left (hp.odd_of_ne_two hp2)) lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by @@ -870,11 +856,6 @@ lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : · exact pIntegral_i1_term_p_eq_two k hk · exact pIntegral_i1_term_p_odd k p hk hp hp2 -lemma pIntegral_odd_term (i _p : ℕ) (hi_odd : Odd i) (hi_ge3 : i ≥ 3) : - bernoulli i = 0 := by - have h1 : 1 < i := by grind - aesop - lemma pIntegral_mul (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := Nat.Coprime.of_dvd_left (Rat.mul_den_dvd x y) (Nat.Coprime.mul_left hx hy) @@ -1040,16 +1021,6 @@ lemma pIntegral_sub (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p pIntegral p (x - y) := Nat.Coprime.coprime_dvd_left (Rat.sub_den_dvd x y) (Nat.Coprime.mul_left hx hy) -lemma pIntegral_even_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) - (hm_lt : m < k) (hp : p.Prime) - (ih : pIntegral p - (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : - pIntegral p (bernoulli (2 * m) * ((2 * k).choose (2 * m)) * - (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1)) := by - rw [even_term_eq_T1_sub_T2 k m p hm_lt] - exact pIntegral_sub p _ _ (pIntegral_T1 k m p hk hm_pos hm_lt hp ih) - (pIntegral_T2 k m p hk hm_pos hm_lt hp) - theorem i1_term_forms_eq (k p : ℕ) (hk : k > 0) : bernoulli 1 * (2 * ↑k) * (p : ℚ) ^ (2 * k - 1) / (2 * ↑k) = bernoulli 1 * ↑(2 * k + 1) * (p : ℚ) ^ (2 * k - 1) / (2 * ↑k + 1) := by @@ -1229,19 +1200,12 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) have hj_eq : j = 2 * m := by omega simp only [hj_eq] exact pIntegral_even_term_in_sum k m p hk hm_pos hm_lt hp (ih m (by omega) hm_lt) - · have hj_ge3 : j ≥ 3 := by rcases hodd with ⟨r, hr⟩; omega - simp only [pIntegral_odd_term j p hodd hj_ge3, zero_mul, zero_div] + · simp only [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; omega), + zero_mul, zero_div] unfold pIntegral simp only [Rat.den_zero] exact Nat.coprime_one_left_iff p |>.mpr trivial -lemma power_sum_eq_faulhaber (k p : ℕ) : - (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = - ∑ i ∈ Finset.range (2 * k + 1), bernoulli i * - ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1) := by - grind only [sum_range_pow] - lemma faulhaber_top_term (k p : ℕ) : bernoulli (2 * k) * ((2 * k + 1).choose (2 * k)) * (p : ℚ) ^ (2 * k + 1 - 2 * k) / (2 * k + 1) = p * bernoulli (2 * k) := by @@ -1365,8 +1329,9 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Pr have hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by - rw [← rat_power_sum_eq_filter_ne_zero k p hk, power_sum_eq_faulhaber, - faulhaber_split_top_term, faulhaber_top_term] + rw [← rat_power_sum_eq_filter_ne_zero k p hk] + simp only [sum_range_pow]; push_cast + rw [faulhaber_split_top_term, faulhaber_top_term] have hAlg := algebraic_rearrangement k p T hp hT' hFaul rw [hAlg, remainder_div_p k p hp] @@ -1384,10 +1349,6 @@ lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) (hp : p.Pr exact ih m hm_lt hm_pos exact pIntegral_sub p T _ hT_int hR -lemma pIntegral_add (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : - pIntegral p (x + y) := - Nat.Coprime.coprime_dvd_left (Rat.add_den_dvd x y) (Nat.Coprime.mul_left hx hy) - lemma sum_other_primes_coprime_p_pos (k p : ℕ) (_hk : k > 0) (hp : p.Prime) : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q).den.Coprime p := by @@ -1395,25 +1356,14 @@ lemma sum_other_primes_coprime_p_pos (k p : ℕ) (_hk : k > 0) (hp : p.Prime) : · exact sum_den_dvd_prod_den _ _ · exact prod_den_coprime_p k p hp -lemma coprime_add_of_coprime_den (q1 q2 : ℚ) (p : ℕ) (h1 : q1.den.Coprime p) - (h2 : q2.den.Coprime p) : - (q1 + q2).den.Coprime p := - Nat.Coprime.of_dvd_left (Rat.add_den_dvd q1 q2) (h1.mul_left h2) - lemma von_staudt_coprime_all_primes_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den.Coprime p := by rw [sum_primes_eq_indicator_add_rest k p hk hp] rw [← add_assoc] - exact coprime_add_of_coprime_den _ _ p - (bernoulli_plus_indicator_coprime_p_pos k p hk hp) - (sum_other_primes_coprime_p_pos k p hk hp) - -lemma von_staudt_clausen_pos (k : ℕ) (hk : k > 0) : - bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, - (1 : ℚ) / p ∈ Set.range Int.cast := by - apply is_integer_of_coprime_all_primes - exact fun p hp => von_staudt_coprime_all_primes_pos k p hk hp + exact Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) + ((bernoulli_plus_indicator_coprime_p_pos k p hk hp).mul_left + (sum_other_primes_coprime_p_pos k p hk hp)) theorem von_staudt_clausen (k : ℕ) : bernoulli (2 * k) + @@ -1421,6 +1371,7 @@ theorem von_staudt_clausen (k : ℕ) : (1 : ℚ) / p ∈ Set.range Int.cast := by rcases Nat.eq_zero_or_pos k with rfl | hk · exact von_staudt_clausen_zero - · exact von_staudt_clausen_pos k hk + · exact is_integer_of_coprime_all_primes _ + (fun p hp => von_staudt_coprime_all_primes_pos k p hk hp) end vonStaudtClausen From 6c004ca21982769f3817b976b4ba4607eb69bec6 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 20:40:33 -0800 Subject: [PATCH 09/70] style(NumberTheory/Bernoulli): merge and inline consecutive omega haves Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 34 ++++++++++------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 80c177163cd7e8..ec9f047ea738f4 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -948,8 +948,7 @@ lemma valuation_three_le_one (p : ℕ) (hp : p.Prime) : (3 : ℕ).factorization simp [Nat.factorization_eq_zero_of_not_dvd h] lemma two_d_plus_one_le_pow_two (d : ℕ) (hd : d ≥ 2) : 2 * d + 1 ≤ 2 ^ (2 * d - 1) := by - have h2d_ge_3 : 2 * d ≥ 3 := by omega - have := pow_two_ge_succ_of_ge_three (2 * d) h2d_ge_3 + have := pow_two_ge_succ_of_ge_three (2 * d) (by omega) omega lemma valuation_bound_2d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 1) : @@ -1006,8 +1005,8 @@ lemma even_term_eq_T1_sub_T2 (k m p : ℕ) (hm_lt : m < k) : (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1) - vonStaudtIndicator (2 * m) p * ((2 * k).choose (2 * m)) * (p : ℚ) ^ (2*(k-m) - 1) / (2*(k-m) + 1) := by - have hd : k - m ≥ 1 := by omega - have h := core_algebraic_identity (bernoulli (2 * m)) (vonStaudtIndicator (2 * m) p) p (k - m) hd + have h := core_algebraic_identity (bernoulli (2 * m)) (vonStaudtIndicator (2 * m) p) p (k - m) + (by omega) set C := ((2 * k).choose (2 * m) : ℚ) set N := (2 * (k - m) + 1 : ℚ) calc bernoulli (2 * m) * C * (p : ℚ) ^ (2*(k-m)) / N @@ -1054,8 +1053,8 @@ lemma choose_div_core (k m : ℕ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by have h_denom : (2 * (k : ℚ) - 2 * m + 1) = ((2 * k - 2 * m + 1 : ℕ) : ℚ) := by - have h : 2 * m ≤ 2 * k := by omega - simp only [Nat.cast_sub h, Nat.cast_add, Nat.cast_mul, Nat.cast_ofNat, Nat.cast_one] + simp only [Nat.cast_sub (by omega : 2 * m ≤ 2 * k), Nat.cast_add, Nat.cast_mul, + Nat.cast_ofNat, Nat.cast_one] conv_rhs => rw [h_denom] have h_nat : 2 * k + 1 - 2 * m = 2 * k - 2 * m + 1 := by grind simp only [h_nat.symm] @@ -1079,10 +1078,8 @@ lemma pIntegral_case_one (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def - have hd_ne_zero : d ≠ 0 := by omega - have hd_plus_one_ne_zero : d + 1 ≠ 0 := by omega - have h_exp : 2 * k - 2 * m - 1 = d - 1 := by omega - have hkm : 2 * m ≤ 2 * k := by omega + have ⟨hd_ne_zero, hd_plus_one_ne_zero, h_exp, hkm⟩ : + d ≠ 0 ∧ d + 1 ≠ 0 ∧ 2 * k - 2 * m - 1 = d - 1 ∧ 2 * m ≤ 2 * k := by omega have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat] @@ -1103,9 +1100,8 @@ lemma pIntegral_second_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt unfold vonStaudtIndicator split_ifs with h · simp only [one_mul] - have hd : 2 * k - 2 * m ≥ 2 := by omega rw [choose_div_simplify k m _ hm_lt] - exact pIntegral_case_one k m p hk hm_pos hm_lt hp hd + exact pIntegral_case_one k m p hk hm_pos hm_lt hp (by omega) · simp only [zero_mul, zero_div] unfold pIntegral rw [Rat.den_zero] @@ -1120,8 +1116,7 @@ lemma even_term_decomposition_identity (k m p : ℕ) (_hk : k > 0) (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1) := by - have hrw : 2 * k - 2 * m = 2 * (k - m) := by omega - simp only [hrw] + simp only [show 2 * k - 2 * m = 2 * (k - m) from by omega] have h := core_algebraic_identity (bernoulli (2 * m)) (vonStaudtIndicator (2 * m) p) p (k - m) (by omega) set C := ((2 * k + 1).choose (2 * m) : ℚ) @@ -1139,7 +1134,6 @@ lemma pIntegral_coeff_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt pIntegral p (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by have hsimp := choose_div_simplify k m ((p : ℚ) ^ (2 * k - 2 * m)) hm_lt rw [hsimp] - have hd_ge_2 : 2 * k - 2 * m ≥ 2 := by omega have hp_factor : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k - 2 * m + 1) = (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by @@ -1152,7 +1146,7 @@ lemma pIntegral_coeff_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt rw [hp_factor] apply pIntegral_mul · exact pIntegral_of_int p p - · exact pIntegral_case_one k m p hk hm_pos hm_lt hp hd_ge_2 + · exact pIntegral_case_one k m p hk hm_pos hm_lt hp (by omega) lemma pIntegral_first_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) @@ -1192,12 +1186,9 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) · simp only [zero_add] exact pIntegral_i1_term_in_sum k p hk hp · set j := i + 2 with hj_def - have hj_ge2 : j ≥ 2 := by omega have hj_lt : j < 2 * k := by omega rcases Nat.even_or_odd j with ⟨m, hm⟩ | hodd - · have hm_pos : m ≥ 1 := by omega - have hm_lt : m < k := by omega - have hj_eq : j = 2 * m := by omega + · have ⟨hm_pos, hm_lt, hj_eq⟩ : m ≥ 1 ∧ m < k ∧ j = 2 * m := by omega simp only [hj_eq] exact pIntegral_even_term_in_sum k m p hk hm_pos hm_lt hp (ih m (by omega) hm_lt) · simp only [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; omega), @@ -1211,8 +1202,7 @@ lemma faulhaber_top_term (k p : ℕ) : p * bernoulli (2 * k) := by have h1 : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by rw [← Nat.choose_symm_of_eq_add (by omega : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] - have h2 : (2 * k + 1 - 2 * k : ℕ) = 1 := by omega - rw [h1, h2, pow_one] + rw [h1, show (2 * k + 1 - 2 * k : ℕ) = 1 from by omega, pow_one] have h4 : (2 * k + 1 : ℚ) ≠ 0 := by positivity field_simp [h4] ring_nf From f0d4ccd09abac364c51016fab142d3a386321d29 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 21:19:03 -0800 Subject: [PATCH 10/70] style(NumberTheory/Bernoulli): remove unused haves and minor cleanup Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index ec9f047ea738f4..b0e898adc7b64b 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -252,7 +252,6 @@ theorem bernoulli_spec' (n : ℕ) : rw [if_neg (succ_ne_zero _)] -- algebra facts have h₁ : (1, n) ∈ antidiagonal n.succ := by simp [mem_antidiagonal, add_comm] - have h₂ : (n : ℚ) + 1 ≠ 0 := by norm_cast have h₃ : (1 + n).choose n = n + 1 := by simp [add_comm] -- key equation: the corresponding fact for `bernoulli'` have H := bernoulli'_spec' n.succ @@ -422,9 +421,7 @@ lemma von_staudt_clausen_zero : (1 : ℚ) / p ∈ Set.range Int.cast := by have h1 : bernoulli (2 * 0) = 1 := by norm_num [bernoulli_zero] have h2 : ∑ p ∈ Finset.range (2 * 0 + 2) with - p.Prime ∧ (p - 1) ∣ 2 * 0, (1 : ℚ) / p = 0 := by - norm_num - decide + p.Prime ∧ (p - 1) ∣ 2 * 0, (1 : ℚ) / p = 0 := by norm_num; decide rw [h1, h2] exact ⟨1, by norm_num⟩ @@ -862,10 +859,9 @@ lemma pIntegral_mul (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p lemma pIntegral_mul_int (p : ℕ) (x : ℚ) (z : ℤ) (hx : pIntegral p x) : pIntegral p (z * x) := by - have h_z_den : (z : ℚ).den = 1 := by aesop - have h_den_dvd : (z * x : ℚ).den ∣ (z : ℚ).den * x.den := Rat.mul_den_dvd z x + have _ := Rat.mul_den_dvd z x have h1 : (z * x : ℚ).den ∣ x.den := by aesop - have h2 : Nat.Coprime (z * x : ℚ).den p := Nat.Coprime.coprime_dvd_left h1 hx + have h2 := Nat.Coprime.coprime_dvd_left h1 hx aesop lemma pIntegral_mul_nat (p : ℕ) (x : ℚ) (n : ℕ) (hx : pIntegral p x) : @@ -1074,8 +1070,7 @@ lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : lemma pIntegral_case_one (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * k - 2 * m ≥ 2) : - pIntegral p (((2 * k).choose (2 * m) : ℚ) * - (p : ℚ) ^ (2 * k - 2 * m - 1) / + pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def have ⟨hd_ne_zero, hd_plus_one_ne_zero, h_exp, hkm⟩ : @@ -1093,10 +1088,8 @@ lemma pIntegral_case_one (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt lemma pIntegral_second_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : - pIntegral p (vonStaudtIndicator (2 * m) p * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k + 1)) := by + pIntegral p (vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1)) := by unfold vonStaudtIndicator split_ifs with h · simp only [one_mul] @@ -1163,9 +1156,7 @@ lemma pIntegral_first_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt exact pIntegral_mul p _ _ ih (pIntegral_coeff_term k m p hk hm_pos hm_lt hp) lemma pIntegral_even_term_in_sum (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) - (hp : p.Prime) - (ih : pIntegral p - (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : + (hp : p.Prime) (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by rw [even_term_decomposition_identity k m p hk hm_pos hm_lt] @@ -1173,8 +1164,7 @@ lemma pIntegral_even_term_in_sum (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) ( (pIntegral_second_term k m p hk hm_pos hm_lt hp) lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) - (ih : ∀ m, 0 < m → m < k → - pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : + (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by apply pIntegral_sum @@ -1298,7 +1288,6 @@ lemma divisibility_to_rat_eq (k p : ℕ) (T : ℤ) (_hp : p.Prime) have h2 : ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = vonStaudtIndicator (2 * k) p := by split_ifs at * <;> simp_all [vonStaudtIndicator] - have h3 : ((p : ℤ) * T : ℚ) = p * T := by norm_cast have h4 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = (p : ℚ) * T := by norm_cast at hT ⊢ From 8150f9bbe065b9d75f1c338d27c6c6738ad5f3e3 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 21:22:22 -0800 Subject: [PATCH 11/70] minimize imports --- Mathlib/NumberTheory/Bernoulli.lean | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index b0e898adc7b64b..50224b9587634f 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -6,21 +6,10 @@ Authors: Johan Commelin, Kevin Buzzard module public import Mathlib.Algebra.BigOperators.Field -public import Mathlib.RingTheory.PowerSeries.Inverse -public import Mathlib.RingTheory.PowerSeries.Exp - -public import Mathlib.Data.Matrix.Basic -public import Mathlib.FieldTheory.Finite.Basic public import Mathlib.Algebra.Field.GeomSum -public import Mathlib.GroupTheory.SpecificGroups.Cyclic -public import Mathlib.RingTheory.ZMod.UnitsCyclic -public import Mathlib.Data.Nat.GCD.BigOperators -public import Mathlib.Data.Nat.Factorization.Basic -public import Mathlib.Data.Nat.Factorization.Defs -public import Mathlib.Data.Rat.Lemmas public import Mathlib.Data.Nat.Choose.Bounds -public import Mathlib.Tactic.Cases -public import Mathlib.Tactic.IntervalCases +public import Mathlib.RingTheory.PowerSeries.Exp +public import Mathlib.RingTheory.ZMod.UnitsCyclic /-! # Bernoulli numbers @@ -1354,3 +1343,5 @@ theorem von_staudt_clausen (k : ℕ) : (fun p hp => von_staudt_coprime_all_primes_pos k p hk hp) end vonStaudtClausen + +#min_imports From 0bb93d95ef1efa142edb020e5e91b2a62c115860 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 21:27:46 -0800 Subject: [PATCH 12/70] revert some claude moves --- Mathlib/NumberTheory/Bernoulli.lean | 39 ++++++++++------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 50224b9587634f..73ac7ddfd3e5c0 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -87,8 +87,7 @@ theorem bernoulli'_spec (n : ℕ) : exact Finset.sum_eq_zero (fun x hx => by rw [choose_symm (le_of_lt (mem_range.1 hx)), sub_self]) theorem bernoulli'_spec' (n : ℕ) : - (∑ k ∈ antidiagonal n, - ((k.1 + k.2).choose k.2 : ℚ) / (k.2 + 1) * bernoulli' k.1) = 1 := by + (∑ k ∈ antidiagonal n, ((k.1 + k.2).choose k.2 : ℚ) / (k.2 + 1) * bernoulli' k.1) = 1 := by refine ((sum_antidiagonal_eq_sum_range_succ_mk _ n).trans ?_).trans (bernoulli'_spec n) refine sum_congr rfl fun x hx => ?_ simp only [add_tsub_cancel_of_le, mem_range_succ_iff.mp hx, cast_sub] @@ -204,8 +203,7 @@ theorem bernoulli_two : bernoulli 2 = 6⁻¹ := by theorem bernoulli_eq_zero_of_odd {n : ℕ} (h_odd : Odd n) (hlt : 1 < n) : bernoulli n = 0 := by rw [bernoulli, bernoulli'_eq_zero_of_odd h_odd hlt, mul_zero] -theorem bernoulli_eq_bernoulli'_of_ne_one {n : ℕ} (hn : n ≠ 1) : - bernoulli n = bernoulli' n := by +theorem bernoulli_eq_bernoulli'_of_ne_one {n : ℕ} (hn : n ≠ 1) : bernoulli n = bernoulli' n := by cases hn.lt_or_gt with | inl hlt => simp [lt_one_iff.mp hlt] | inr hgt => @@ -270,8 +268,7 @@ theorem bernoulliPowerSeries_mul_exp_sub_one : bernoulliPowerSeries A * (exp A - have hfact : ∀ m, (m ! : ℚ) ≠ 0 := fun m => mod_cast factorial_ne_zero m have hite2 : ite (n.succ = 0) 1 0 = (0 : ℚ) := if_neg n.succ_ne_zero simp only [CharP.cast_eq_zero, zero_add, inv_one, map_one, sub_self, mul_zero] - rw [← map_zero (algebraMap ℚ A), ← zero_div (n.succ ! : ℚ), ← hite2, - ← bernoulli_spec', sum_div] + rw [← map_zero (algebraMap ℚ A), ← zero_div (n.succ ! : ℚ), ← hite2, ← bernoulli_spec', sum_div] refine congr_arg (algebraMap ℚ A) (sum_congr rfl fun x h => eq_div_of_mul_eq (hfact n.succ) ?_) rw [mem_antidiagonal] at h rw [← h, add_choose, cast_div_charZero (factorial_mul_factorial_dvd_factorial_add _ _)] @@ -285,8 +282,7 @@ See https://proofwiki.org/wiki/Faulhaber%27s_Formula and [orosi2018faulhaber] fo the proof provided here. -/ theorem sum_range_pow (n p : ℕ) : (∑ k ∈ range n, (k : ℚ) ^ p) = - ∑ i ∈ range (p + 1), - bernoulli i * ((p + 1).choose i) * (n : ℚ) ^ (p + 1 - i) / (p + 1) := by + ∑ i ∈ range (p + 1), bernoulli i * ((p + 1).choose i) * (n : ℚ) ^ (p + 1 - i) / (p + 1) := by have hne : ∀ m : ℕ, (m ! : ℚ) ≠ 0 := fun m => mod_cast factorial_ne_zero m -- compute the Cauchy product of two power series have h_cauchy : @@ -302,14 +298,11 @@ theorem sum_range_pow (n p : ℕ) : simp only [exp_pow_eq_rescale_exp, rescale, RingHom.coe_mk] -- manipulate factorials and binomial coefficients have h : m < q + 1 := by simpa using h - rw [choose_eq_factorial_div_factorial h.le, eq_comm, - div_eq_iff (hne q.succ), succ_eq_add_one, - mul_assoc _ _ (q.succ ! : ℚ), mul_comm _ (q.succ ! : ℚ), - ← mul_assoc, div_mul_eq_mul_div] + rw [choose_eq_factorial_div_factorial h.le, eq_comm, div_eq_iff (hne q.succ), succ_eq_add_one, + mul_assoc _ _ (q.succ ! : ℚ), mul_comm _ (q.succ ! : ℚ), ← mul_assoc, div_mul_eq_mul_div] simp only [MonoidHom.coe_mk, OneHom.coe_mk, coeff_exp, Algebra.algebraMap_self, one_div, map_inv₀, map_natCast, coeff_mk] - rw [mul_comm ((n : ℚ) ^ (q - m + 1)), - ← mul_assoc _ _ ((n : ℚ) ^ (q - m + 1)), ← one_div, + rw [mul_comm ((n : ℚ) ^ (q - m + 1)), ← mul_assoc _ _ ((n : ℚ) ^ (q - m + 1)), ← one_div, mul_one_div, div_div, tsub_add_eq_add_tsub (le_of_lt_succ h), cast_div, cast_mul] · ring · exact factorial_mul_factorial_dvd_factorial h.le @@ -322,8 +315,7 @@ theorem sum_range_pow (n p : ℕ) : suffices (mk fun p => ∑ k ∈ range n, (k : ℚ) ^ p * algebraMap ℚ ℚ p !⁻¹) = mk fun p => - ∑ i ∈ range (p + 1), - bernoulli i * (p + 1).choose i * (n : ℚ) ^ (p + 1 - i) / (p + 1)! by + ∑ i ∈ range (p + 1), bernoulli i * (p + 1).choose i * (n : ℚ) ^ (p + 1 - i) / (p + 1)! by rw [← div_eq_iff (hne p), div_eq_mul_inv, sum_mul] rw [PowerSeries.ext_iff] at this simpa using this p @@ -355,29 +347,24 @@ $$\sum_{k=1}^{n} k^p = \sum_{i=0}^p (-1)^iB_i\binom{p+1}{i}\frac{n^{p+1-i}}{p+1} Deduced from `sum_range_pow`. -/ theorem sum_Ico_pow (n p : ℕ) : (∑ k ∈ Ico 1 (n + 1), (k : ℚ) ^ p) = - ∑ i ∈ range (p + 1), - bernoulli' i * (p + 1).choose i * (n : ℚ) ^ (p + 1 - i) / (p + 1) := by + ∑ i ∈ range (p + 1), bernoulli' i * (p + 1).choose i * (n : ℚ) ^ (p + 1 - i) / (p + 1) := by rw [← Nat.cast_succ] -- dispose of the trivial case cases p with | zero => simp | succ p => let f i := bernoulli i * p.succ.succ.choose i * (n : ℚ) ^ (p.succ.succ - i) / p.succ.succ let f' i := bernoulli' i * p.succ.succ.choose i * (n : ℚ) ^ (p.succ.succ - i) / p.succ.succ - suffices (∑ k ∈ Ico 1 n.succ, (k : ℚ) ^ p.succ) = - ∑ i ∈ range p.succ.succ, f' i by convert this + suffices (∑ k ∈ Ico 1 n.succ, (k : ℚ) ^ p.succ) = ∑ i ∈ range p.succ.succ, f' i by convert this -- prove some algebraic facts that will make things easier for us later on have hle := Nat.le_add_left 1 n have hne : (p + 1 + 1 : ℚ) ≠ 0 := by norm_cast - have h1 : ∀ r : ℚ, - r * (p + 1 + 1) * (n : ℚ) ^ p.succ / (p + 1 + 1 : ℚ) = r * (n : ℚ) ^ p.succ := + have h1 : ∀ r : ℚ, r * (p + 1 + 1) * (n : ℚ) ^ p.succ / (p + 1 + 1 : ℚ) = r * (n : ℚ) ^ p.succ := fun r => by rw [mul_div_right_comm, mul_div_cancel_right₀ _ hne] have h2 : f 1 + (n : ℚ) ^ p.succ = 1 / 2 * (n : ℚ) ^ p.succ := by simp_rw [f, bernoulli_one, choose_one_right, succ_sub_succ_eq_sub, cast_succ, tsub_zero, h1] ring have : - (∑ i ∈ range p, bernoulli (i + 2) * (p + 2).choose (i + 2) * - (n : ℚ) ^ (p - i) / ↑(p + 2)) = - ∑ i ∈ range p, bernoulli' (i + 2) * (p + 2).choose (i + 2) * - (n : ℚ) ^ (p - i) / ↑(p + 2) := + (∑ i ∈ range p, bernoulli (i + 2) * (p + 2).choose (i + 2) * (n : ℚ) ^ (p - i) / ↑(p + 2)) = + ∑ i ∈ range p, bernoulli' (i + 2) * (p + 2).choose (i + 2) * (n : ℚ) ^ (p - i) / ↑(p + 2) := sum_congr rfl fun i _ => by rw [bernoulli_eq_bernoulli'_of_ne_one (succ_succ_ne_one i)] calc (-- replace sum over `Ico` with sum over `range` and simplify From 65b06cb711e9c5528aa55cf24303f9e0abf99471 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 21:36:18 -0800 Subject: [PATCH 13/70] wrap lines in sum_primes_eq_indicator_add_rest --- Mathlib/NumberTheory/Bernoulli.lean | 113 +++++++++------------------- 1 file changed, 37 insertions(+), 76 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 73ac7ddfd3e5c0..51ad7f4049b875 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -582,21 +582,14 @@ lemma prod_den_coprime_p (k p : ℕ) (hp : p.Prime) : lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = - vonStaudtIndicator (2 * k) p / p + - ∑ q ∈ Finset.range (2 * k + 2) with + vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by - have h3 : - ∑ q ∈ Finset.range (2 * k + 2) with - q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q = - (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) - then (1 : ℚ) / p else 0) + - ∑ q ∈ Finset.range (2 * k + 2) with - q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by - have h4 : - (∑ q ∈ Finset.range (2 * k + 2) with - q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = - ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2)), (1 : ℚ) / q := rfl + have h3 : ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q = + (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) + + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by + have h4 : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = + ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2)), (1 : ℚ) / q := rfl rw [h4] have h5 : p < 2 * k + 2 ∨ ¬(p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) := by by_cases h51 : p < 2 * k + 2 @@ -609,12 +602,9 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (Finset.range (2 * k + 2)) ↔ p.Prime ∧ (p - 1) ∣ 2 * k := by simp [Finset.mem_filter, Finset.mem_range] tauto - have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) - then (1 : ℚ) / p else 0) = - (if (p.Prime ∧ (p - 1) ∣ 2 * k) - then (1 : ℚ) / p else 0) := by - have h10 : (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) ↔ - (p.Prime ∧ (p - 1) ∣ 2 * k) := by + have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = + (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) := by + have h10 : (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) ↔ (p.Prime ∧ (p - 1) ∣ 2 * k) := by constructor <;> intro h11 · exact ⟨h11.1, h11.2.1⟩ · exact ⟨h11.1, h11.2, by omega⟩ @@ -625,76 +615,53 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (Finset.range (2 * k + 2)) := by simp [Finset.mem_filter, Finset.mem_range] at h8 ⊢ tauto - have h14 : ∑ q ∈ Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2)), (1 : ℚ) / q = - ∑ q ∈ (Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2))).erase p, + have h14 : ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2)), (1 : ℚ) / q = ∑ q ∈ (Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2))).erase p, (1 : ℚ) / q + (1 : ℚ) / p := by rw [← Finset.insert_erase h13, Finset.sum_insert (Finset.notMem_erase p _)] simp_all [Finset.mem_filter, Finset.mem_range] - have h17 : ∑ q ∈ (Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2))).erase p, - (1 : ℚ) / q = - ∑ q ∈ Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) - (Finset.range (2 * k + 2)), - (1 : ℚ) / q := by - have h18 : (Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2))).erase p = - Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) - (Finset.range (2 * k + 2)) := by + have h17 : ∑ q ∈ (Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2))).erase p, (1 : ℚ) / q = + ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + (Finset.range (2 * k + 2)), (1 : ℚ) / q := by + have h18 : (Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + (Finset.range (2 * k + 2))).erase p = Finset.filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)) := by apply Finset.ext intro q simp only [Finset.mem_filter, Finset.mem_erase, Finset.mem_range] cases q <;> simp_all [Nat.Prime] tauto rw [h18] - have h19 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) - then (1 : ℚ) / p else 0) = (1 : ℚ) / p := by + have h19 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) = (1 : ℚ) / p := by simp [h10] rw [h14, h17, h19] ring_nf - · have h13 : ∑ q ∈ Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + · have h13 : ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q = - ∑ q ∈ Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) - (Finset.range (2 * k + 2)), - (1 : ℚ) / q := by - have h14 : Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) + ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + (Finset.range (2 * k + 2)), (1 : ℚ) / q := by + have h14 : Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) = - Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)) := by apply Finset.ext intro q simp only [Finset.mem_filter, Finset.mem_range] by_cases hq : q = p <;> simp_all [Nat.Prime] rw [h14] - have h15 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) - then (1 : ℚ) / p else 0) = 0 := by + have h15 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) = 0 := by simp [h10] rw [h13, h15] ring_nf | inr h5 => have h8 : ∑ q ∈ Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2)), (1 : ℚ) / q = - ∑ q ∈ Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) - (Finset.range (2 * k + 2)), - (1 : ℚ) / q := by - have h9 : Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2)) = - Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q = + ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) + (Finset.range (2 * k + 2)), (1 : ℚ) / q := by + have h9 : Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) = + Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)) := by apply Finset.ext intro q @@ -702,8 +669,7 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : by_cases hq : q = p <;> simp_all [Nat.Prime] omega rw [h9] - have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) - then (1 : ℚ) / p else 0) = 0 := by + have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = 0 := by simp [h5] rw [h8, h9] ring_nf @@ -730,15 +696,10 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : rw [h8, h9] calc (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = - (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) - then (1 : ℚ) / p else 0) + - ∑ q ∈ Finset.range (2 * k + 2) with - q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, - (1 : ℚ) / q := h3 - _ = vonStaudtIndicator (2 * k) p / p + - ∑ q ∈ Finset.range (2 * k + 2) with - q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, - (1 : ℚ) / q := by rw [h4] + (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) + + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := h3 + _ = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with + q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by rw [h4] lemma pIntegral_of_int (p : ℕ) (z : ℤ) : pIntegral p z := by simp_all [pIntegral] From 1d9df813a188f88dd136574f70a2ad43d51938c1 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 21:55:02 -0800 Subject: [PATCH 14/70] refactor(NumberTheory/Bernoulli): simplify sum_primes_eq_indicator_add_rest Replace ~120-line proof with ~15-line proof using by_cases on divisibility, Finset.add_sum_erase for the positive case, and Finset.filter_congr for the negative case. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 134 ++++------------------------ 1 file changed, 16 insertions(+), 118 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 51ad7f4049b875..69b4d825ff511f 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -584,122 +584,22 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by - have h3 : ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q = - (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) + - ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by - have h4 : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = - ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2)), (1 : ℚ) / q := rfl - rw [h4] - have h5 : p < 2 * k + 2 ∨ ¬(p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) := by - by_cases h51 : p < 2 * k + 2 - · exact Or.inl h51 - · exact Or.inr (by tauto) - cases h5 with - | inl h5 => - have h7 : p < 2 * k + 2 := h5 - have h8 : p ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2)) ↔ p.Prime ∧ (p - 1) ∣ 2 * k := by - simp [Finset.mem_filter, Finset.mem_range] - tauto - have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = - (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) := by - have h10 : (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) ↔ (p.Prime ∧ (p - 1) ∣ 2 * k) := by - constructor <;> intro h11 - · exact ⟨h11.1, h11.2.1⟩ - · exact ⟨h11.1, h11.2, by omega⟩ - simp [h10] - rw [h9] - by_cases h10 : p.Prime ∧ (p - 1) ∣ 2 * k - · have h13 : p ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2)) := by - simp [Finset.mem_filter, Finset.mem_range] at h8 ⊢ - tauto - have h14 : ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2)), (1 : ℚ) / q = ∑ q ∈ (Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2))).erase p, - (1 : ℚ) / q + (1 : ℚ) / p := by - rw [← Finset.insert_erase h13, Finset.sum_insert (Finset.notMem_erase p _)] - simp_all [Finset.mem_filter, Finset.mem_range] - have h17 : ∑ q ∈ (Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2))).erase p, (1 : ℚ) / q = - ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) - (Finset.range (2 * k + 2)), (1 : ℚ) / q := by - have h18 : (Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2))).erase p = Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) (Finset.range (2 * k + 2)) := by - apply Finset.ext - intro q - simp only [Finset.mem_filter, Finset.mem_erase, Finset.mem_range] - cases q <;> simp_all [Nat.Prime] - tauto - rw [h18] - have h19 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) = (1 : ℚ) / p := by - simp [h10] - rw [h14, h17, h19] - ring_nf - · have h13 : ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2)), (1 : ℚ) / q = - ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) - (Finset.range (2 * k + 2)), (1 : ℚ) / q := by - have h14 : Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) - (Finset.range (2 * k + 2)) = - Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) - (Finset.range (2 * k + 2)) := by - apply Finset.ext - intro q - simp only [Finset.mem_filter, Finset.mem_range] - by_cases hq : q = p <;> simp_all [Nat.Prime] - rw [h14] - have h15 : (if (p.Prime ∧ (p - 1) ∣ 2 * k) then (1 : ℚ) / p else 0) = 0 := by - simp [h10] - rw [h13, h15] - ring_nf - | inr h5 => - have h8 : ∑ q ∈ Finset.filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)), (1 : ℚ) / q = - ∑ q ∈ Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) - (Finset.range (2 * k + 2)), (1 : ℚ) / q := by - have h9 : Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) (Finset.range (2 * k + 2)) = - Finset.filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p) - (Finset.range (2 * k + 2)) := by - apply Finset.ext - intro q - simp only [Finset.mem_filter, Finset.mem_range] - by_cases hq : q = p <;> simp_all [Nat.Prime] - omega - rw [h9] - have h9 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = 0 := by - simp [h5] - rw [h8, h9] - ring_nf - have h4 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) = - vonStaudtIndicator (2 * k) p / p := by - by_cases h5 : (p - 1 : ℕ) ∣ 2 * k - · have h7 : vonStaudtIndicator (2 * k) p = 1 := by simp [vonStaudtIndicator, h5] - have h9 : p < 2 * k + 2 := by - have h14 : p - 1 ≤ 2 * k := Nat.le_of_dvd (by nlinarith) h5 - omega - have h10 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) - then (1 : ℚ) / p else 0) = (1 : ℚ) / p := by - simp [hp, h5, h9] - have h11 : vonStaudtIndicator (2 * k) p / p = (1 : ℚ) / p := by rw [h7] - rw [h10, h11] - · have h7 : vonStaudtIndicator (2 * k) p = 0 := by - simp [vonStaudtIndicator, h5] - have h8 : (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) - then (1 : ℚ) / p else 0) = 0 := by - by_cases h9 : p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2 - · exact absurd h9.2.1 h5 - · simp [h9] - have h9 : vonStaudtIndicator (2 * k) p / p = 0 := by rw [h7]; simp - rw [h8, h9] - calc (∑ q ∈ Finset.range (2 * k + 2) with - q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = - (if (p.Prime ∧ (p - 1) ∣ 2 * k ∧ p < 2 * k + 2) then (1 : ℚ) / p else 0) + - ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := h3 - _ = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with - q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by rw [h4] + by_cases hdvd : (p - 1 : ℕ) ∣ 2 * k + · -- p is in the filtered set; extract its term + have hp_mem : p ∈ (Finset.range (2 * k + 2)).filter + (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) := by + simp only [Finset.mem_filter, Finset.mem_range] + exact ⟨by have := Nat.le_of_dvd (by omega) hdvd; omega, hp, hdvd⟩ + rw [← Finset.add_sum_erase _ _ hp_mem] + simp only [vonStaudtIndicator, if_pos hdvd] + congr 1 + apply Finset.sum_congr _ (fun _ _ => rfl) + ext q; simp only [Finset.mem_erase, Finset.mem_filter, Finset.mem_range]; tauto + · -- p is not in the filtered set; indicator is 0, filter sets are equal + simp only [vonStaudtIndicator, if_neg hdvd, zero_div, zero_add] + exact Finset.sum_congr (Finset.filter_congr fun q _ => + ⟨fun ⟨hpr, hd⟩ => ⟨hpr, hd, fun h => hdvd (h ▸ hd)⟩, + fun ⟨hpr, hd, _⟩ => ⟨hpr, hd⟩⟩) fun _ _ => rfl lemma pIntegral_of_int (p : ℕ) (z : ℤ) : pIntegral p z := by simp_all [pIntegral] @@ -1291,5 +1191,3 @@ theorem von_staudt_clausen (k : ℕ) : (fun p hp => von_staudt_coprime_all_primes_pos k p hk hp) end vonStaudtClausen - -#min_imports From 56384d41309bfbac63b213070bd463e007dfc2e5 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 5 Feb 2026 22:23:17 -0800 Subject: [PATCH 15/70] fix(NumberTheory/Bernoulli): add docstrings and remove unused arguments Add missing documentation for `vonStaudtIndicator` and `pIntegral`. Remove unused arguments from `cast_ne_zero_of_mem_filter`, `generator_pow_ne_one`, `sum_units_pow_eq_zero_of_not_dvd`, `den_pow_div_dvd`, `valuation_bound`, `pIntegral_pow_div_factor`, and `pIntegral_T1`, along with their call sites. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 69b4d825ff511f..8c9df4661153e6 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -389,6 +389,7 @@ end Faulhaber section vonStaudtClausen +/-- Indicator function that is `1` if `(p - 1) ∣ k` and `0` otherwise. -/ noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1 : ℕ) ∣ k then 1 else 0 @@ -412,7 +413,7 @@ lemma card_filter_range_ne_zero (p : ℕ) (_hp : p.Prime) : simp only [Finset.filter_ne', Finset.card_erase_of_mem (Finset.mem_range.mpr _hp.pos), Finset.card_range] -lemma cast_ne_zero_of_mem_filter (p _l : ℕ) (_hp : p.Prime) (v : ℕ) +lemma cast_ne_zero_of_mem_filter (p : ℕ) (v : ℕ) (hv : v ∈ (Finset.range p).filter (· ≠ 0)) : (v : ZMod p) ≠ 0 := by simp only [Finset.mem_filter, Finset.mem_range] at hv intro h @@ -422,7 +423,7 @@ lemma cast_ne_zero_of_mem_filter (p _l : ℕ) (_hp : p.Prime) (v : ℕ) lemma power_sum_eq_neg_one_mod_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) ∣ l) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = -1 := by have h1 : ∀ v ∈ (Finset.range p).filter (· ≠ 0), (v : ZMod p) ^ l = 1 := fun v hv => - zmod_pow_eq_one_of_dvd p l hp hdvd (v : ZMod p) (cast_ne_zero_of_mem_filter p l hp v hv) + zmod_pow_eq_one_of_dvd p l hp hdvd (v : ZMod p) (cast_ne_zero_of_mem_filter p v hv) rw [Finset.sum_congr rfl h1, Finset.sum_const, card_filter_range_ne_zero p hp, nsmul_eq_mul, mul_one] simp [Nat.cast_sub hp.pos] @@ -430,7 +431,7 @@ lemma power_sum_eq_neg_one_mod_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := by - have hcast := cast_ne_zero_of_mem_filter p l (Fact.out : p.Prime) + have hcast := cast_ne_zero_of_mem_filter p refine Finset.sum_bij' (fun v hv => ⟨(v : ZMod p), (v : ZMod p)⁻¹, mul_inv_cancel₀ (hcast v hv), inv_mul_cancel₀ (hcast v hv)⟩) (fun u _ => (u : ZMod p).val) ?_ ?_ ?_ ?_ ?_ @@ -485,7 +486,7 @@ lemma sum_units_eq_sum_range (p l : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) ext i simp [← pow_mul, mul_comm] -lemma generator_pow_ne_one (p l : ℕ) [hp : Fact p.Prime] (_hp2 : p ≠ 2) +lemma generator_pow_ne_one (p l : ℕ) [hp : Fact p.Prime] (hndvd : ¬(p - 1) ∣ l) (g : (ZMod p)ˣ) (hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : (g : ZMod p) ^ l ≠ 1 := by @@ -494,13 +495,13 @@ lemma generator_pow_ne_one (p l : ℕ) [hp : Fact p.Prime] (_hp2 : p ≠ 2) intro h exact hndvd (h_order ▸ orderOf_dvd_of_pow_eq_one (Units.ext (by simpa using h))) -lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hp2 : p ≠ 2) +lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hndvd : ¬(p - 1) ∣ l) : (∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l) = 0 := by haveI : IsCyclic (ZMod p)ˣ := ZMod.isCyclic_units_prime hp.out obtain ⟨g, hg⟩ := IsCyclic.exists_generator (α := (ZMod p)ˣ) rw [sum_units_eq_sum_range p l g hg] - have hx1 := generator_pow_ne_one p l hp2 hndvd g hg + have hx1 := generator_pow_ne_one p l hndvd g hg have hxp := ZMod.pow_card_sub_one_eq_one (pow_ne_zero l (Units.ne_zero g)) have := geom_sum_eq hx1 (p - 1) aesop @@ -508,9 +509,8 @@ lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hp2 : p lemma power_sum_eq_zero_mod_of_not_dvd (p l : ℕ) (hp : p.Prime) (hndvd : ¬(p - 1) ∣ l) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = 0 := by haveI : Fact p.Prime := ⟨hp⟩ - have hp2 : p ≠ 2 := fun h => by subst h; simp at hndvd rw [sum_pow_eq_sum_units_pow p l] - exact sum_units_pow_eq_zero_of_not_dvd p l hp2 hndvd + exact sum_units_pow_eq_zero_of_not_dvd p l hndvd lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + @@ -550,6 +550,7 @@ lemma is_integer_of_coprime_all_primes (q : ℚ) rw [← hq, h1] simp +/-- A rational number `x` is `p`-integral if `p` does not divide its denominator. -/ def pIntegral (p : ℕ) (x : ℚ) : Prop := x.den.Coprime p lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : @@ -619,7 +620,7 @@ lemma pow_div_eq_pow_sub_div_ordCompl (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0 · rw [Nat.cast_pow, div_eq_iff hpe_ne, ← pow_add, Nat.sub_add_cancel hv] · field_simp; simp -lemma den_pow_div_dvd (p M' k : ℕ) (_hM' : M' ≠ 0) : +lemma den_pow_div_dvd (p M' k : ℕ) : ((p : ℚ)^k / M').den ∣ M' := by have h1 : ((p : ℚ) ^ k / M') = Rat.divInt (p ^ k : ℤ) (M' : ℤ) := by norm_cast; simp rw [h1] @@ -638,10 +639,10 @@ lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) rw [Nat.cast_div_charZero (Nat.ordProj_dvd M p)] rw [hcast] have hdvd : ((p : ℚ) ^ (N - M.factorization p) / M').den ∣ M' := - den_pow_div_dvd p M' (N - M.factorization p) hM'_ne + den_pow_div_dvd p M' (N - M.factorization p) exact hM'_cop.coprime_dvd_left hdvd -lemma valuation_bound (p n : ℕ) (hp : p.Prime) (_hn : n ≥ 1) : +lemma valuation_bound (p n : ℕ) (hp : p.Prime) : (n + 1).factorization p ≤ n := Nat.factorization_le_of_le_pow <| calc n + 1 = (n + 1).choose 1 := by simp @@ -654,7 +655,7 @@ lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : rw [h] apply pIntegral_pow_div p (2 * k + 1) (2 * k) hp · omega - · exact valuation_bound p (2 * k) hp (by omega) + · exact valuation_bound p (2 * k) hp lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : pIntegral 2 (bernoulli 1 * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) := by @@ -740,7 +741,7 @@ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : conv_rhs => rw [show m = m - 1 + 1 from by omega]; exact pow_succ .. exact h2 d hd -lemma pIntegral_pow_div_factor (k m p : ℕ) (_hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : +lemma pIntegral_pow_div_factor (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : pIntegral p ((p : ℚ) ^ (2*(k-m)) / (2*(↑k - ↑m) + 1)) := by set d := k - m with hd have hd_pos : d ≥ 1 := by omega @@ -750,10 +751,9 @@ lemma pIntegral_pow_div_factor (k m p : ℕ) (_hm_pos : m ≥ 1) (hm_lt : m < k) rw [hcast2] apply pIntegral_pow_div p (2 * d + 1) (2 * d) hp · omega - · have hn : 2 * d ≥ 1 := by omega - exact valuation_bound p (2 * d) hp hn + · exact valuation_bound p (2 * d) hp -lemma pIntegral_T1 (k m p : ℕ) (_hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) +lemma pIntegral_T1 (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k).choose (2 * m)) * (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1)) := by @@ -766,7 +766,7 @@ lemma pIntegral_T1 (k m p : ℕ) (_hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k · apply pIntegral_mul · exact ih · exact pIntegral_of_int p ((2 * k).choose (2 * m)) - · exact pIntegral_pow_div_factor k m p hm_pos hm_lt hp + · exact pIntegral_pow_div_factor k m p hm_lt hp lemma valuation_three_le_one (p : ℕ) (hp : p.Prime) : (3 : ℕ).factorization p ≤ 1 := by rcases hp.eq_two_or_odd with rfl | hp_odd From 7442b7092304b8eb1150fa268b12f6d00d9592cc Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Fri, 6 Feb 2026 06:38:39 -0800 Subject: [PATCH 16/70] fix(NumberTheory/Bernoulli): remove remaining unused arguments Remove unused arguments from pIntegral_T2, pIntegral_case_one, even_term_decomposition_identity, power_sum_indicator_divisible_by_p, divisibility_to_rat_eq, sum_other_primes_coprime_p_pos, and cascading unused arguments in pIntegral_second_term, pIntegral_coeff_term, pIntegral_first_term, and pIntegral_even_term_in_sum. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 43 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 8c9df4661153e6..02949db7f03f59 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -794,7 +794,7 @@ lemma valuation_bound_2d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 1) : calc 2 * d + 1 ≤ 2 ^ (2 * d - 1) := two_d_plus_one_le_pow_two d hd2 _ ≤ p ^ (2 * d - 1) := Nat.pow_le_pow_left hp.two_le _ -lemma pIntegral_T2 (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt : m < k) (hp : p.Prime) : +lemma pIntegral_T2 (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : pIntegral p (vonStaudtIndicator (2 * m) p * ((2 * k).choose (2 * m)) * (p : ℚ) ^ (2*(k-m) - 1) / (2*(k-m) + 1)) := by set d := k - m with hd_def @@ -905,7 +905,7 @@ lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] -lemma pIntegral_case_one (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt : m < k) +lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * k - 2 * m ≥ 2) : pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by @@ -923,7 +923,7 @@ lemma pIntegral_case_one (k m p : ℕ) (_hk : k > 0) (_hm_pos : m ≥ 1) (hm_lt rw [h_eq] exact pIntegral_mul_nat p _ _ h_pow_integral -lemma pIntegral_second_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) +lemma pIntegral_second_term (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : pIntegral p (vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1)) := by @@ -931,14 +931,13 @@ lemma pIntegral_second_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt split_ifs with h · simp only [one_mul] rw [choose_div_simplify k m _ hm_lt] - exact pIntegral_case_one k m p hk hm_pos hm_lt hp (by omega) + exact pIntegral_case_one k m p hm_lt hp (by omega) · simp only [zero_mul, zero_div] unfold pIntegral rw [Rat.den_zero] exact Nat.coprime_one_left_iff p |>.mpr trivial -lemma even_term_decomposition_identity (k m p : ℕ) (_hk : k > 0) - (_hm_pos : m ≥ 1) (hm_lt : m < k) : +lemma even_term_decomposition_identity (k m p : ℕ) (hm_lt : m < k) : (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) : ℚ) = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * @@ -959,7 +958,7 @@ lemma even_term_decomposition_identity (k m p : ℕ) (_hk : k > 0) C / N := by rw [h] _ = _ := by ring -lemma pIntegral_coeff_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) +lemma pIntegral_coeff_term (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : pIntegral p (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by have hsimp := choose_div_simplify k m ((p : ℚ) ^ (2 * k - 2 * m)) hm_lt @@ -976,9 +975,9 @@ lemma pIntegral_coeff_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt rw [hp_factor] apply pIntegral_mul · exact pIntegral_of_int p p - · exact pIntegral_case_one k m p hk hm_pos hm_lt hp (by omega) + · exact pIntegral_case_one k m p hm_lt hp (by omega) -lemma pIntegral_first_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) +lemma pIntegral_first_term (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p ((bernoulli (2 * m) + @@ -990,15 +989,15 @@ lemma pIntegral_first_term (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) by ring] - exact pIntegral_mul p _ _ ih (pIntegral_coeff_term k m p hk hm_pos hm_lt hp) + exact pIntegral_mul p _ _ ih (pIntegral_coeff_term k m p hm_lt hp) -lemma pIntegral_even_term_in_sum (k m p : ℕ) (hk : k > 0) (hm_pos : m ≥ 1) (hm_lt : m < k) +lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by - rw [even_term_decomposition_identity k m p hk hm_pos hm_lt] - exact pIntegral_sub p _ _ (pIntegral_first_term k m p hk hm_pos hm_lt hp ih) - (pIntegral_second_term k m p hk hm_pos hm_lt hp) + rw [even_term_decomposition_identity k m p hm_lt] + exact pIntegral_sub p _ _ (pIntegral_first_term k m p hm_lt hp ih) + (pIntegral_second_term k m p hm_lt hp) lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : @@ -1015,9 +1014,9 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) · set j := i + 2 with hj_def have hj_lt : j < 2 * k := by omega rcases Nat.even_or_odd j with ⟨m, hm⟩ | hodd - · have ⟨hm_pos, hm_lt, hj_eq⟩ : m ≥ 1 ∧ m < k ∧ j = 2 * m := by omega + · have ⟨_, hm_lt, hj_eq⟩ : m ≥ 1 ∧ m < k ∧ j = 2 * m := by omega simp only [hj_eq] - exact pIntegral_even_term_in_sum k m p hk hm_pos hm_lt hp (ih m (by omega) hm_lt) + exact pIntegral_even_term_in_sum k m p hm_lt hp (ih m (by omega) hm_lt) · simp only [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; omega), zero_mul, zero_div] unfold pIntegral @@ -1037,7 +1036,7 @@ lemma faulhaber_top_term (k p : ℕ) : norm_cast ring_nf -lemma power_sum_indicator_divisible_by_p (k p : ℕ) (_hk : k > 0) (hp : p.Prime) : +lemma power_sum_indicator_divisible_by_p (k p : ℕ) (hp : p.Prime) : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T := by have h_cast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + @@ -1115,7 +1114,7 @@ lemma algebraic_rearrangement (k p : ℕ) (T : ℤ) (hp : p.Prime) field_simp [hp_ne] linarith -lemma divisibility_to_rat_eq (k p : ℕ) (T : ℤ) (_hp : p.Prime) +lemma divisibility_to_rat_eq (k p : ℕ) (T : ℤ) (hT : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + @@ -1138,10 +1137,10 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Pr ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by - obtain ⟨T, hT⟩ := power_sum_indicator_divisible_by_p k p hk hp + obtain ⟨T, hT⟩ := power_sum_indicator_divisible_by_p k p hp use T have hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = - p * T := divisibility_to_rat_eq k p T hp hT + p * T := divisibility_to_rat_eq k p T hT have hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by @@ -1165,7 +1164,7 @@ lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) (hp : p.Pr exact ih m hm_lt hm_pos exact pIntegral_sub p T _ hT_int hR -lemma sum_other_primes_coprime_p_pos (k p : ℕ) (_hk : k > 0) (hp : p.Prime) : +lemma sum_other_primes_coprime_p_pos (k p : ℕ) (hp : p.Prime) : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q).den.Coprime p := by apply Nat.Coprime.of_dvd_left @@ -1179,7 +1178,7 @@ lemma von_staudt_coprime_all_primes_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) rw [← add_assoc] exact Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) ((bernoulli_plus_indicator_coprime_p_pos k p hk hp).mul_left - (sum_other_primes_coprime_p_pos k p hk hp)) + (sum_other_primes_coprime_p_pos k p hp)) theorem von_staudt_clausen (k : ℕ) : bernoulli (2 * k) + From 09b4889182a66b8ce2e49cb16bd112c081254370 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Fri, 6 Feb 2026 06:47:37 -0800 Subject: [PATCH 17/70] more wrapping --- Mathlib/NumberTheory/Bernoulli.lean | 30 ++++++++++------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 02949db7f03f59..53feec730c8701 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -620,8 +620,7 @@ lemma pow_div_eq_pow_sub_div_ordCompl (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0 · rw [Nat.cast_pow, div_eq_iff hpe_ne, ← pow_add, Nat.sub_add_cancel hv] · field_simp; simp -lemma den_pow_div_dvd (p M' k : ℕ) : - ((p : ℚ)^k / M').den ∣ M' := by +lemma den_pow_div_dvd (p M' k : ℕ) : ((p : ℚ)^k / M').den ∣ M' := by have h1 : ((p : ℚ) ^ k / M') = Rat.divInt (p ^ k : ℤ) (M' : ℤ) := by norm_cast; simp rw [h1] have h2 : ↑(Rat.divInt (p ^ k : ℤ) (M' : ℤ)).den ∣ (M' : ℤ) := by apply Rat.den_dvd @@ -642,8 +641,7 @@ lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) den_pow_div_dvd p M' (N - M.factorization p) exact hM'_cop.coprime_dvd_left hdvd -lemma valuation_bound (p n : ℕ) (hp : p.Prime) : - (n + 1).factorization p ≤ n := +lemma valuation_bound (p n : ℕ) (hp : p.Prime) : (n + 1).factorization p ≤ n := Nat.factorization_le_of_le_pow <| calc n + 1 = (n + 1).choose 1 := by simp _ ≤ 2 ^ n := Nat.choose_succ_le_two_pow n 1 @@ -668,8 +666,7 @@ lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : rw [h] norm_num [pIntegral] -lemma den_neg_pow_div_two_dvd_two (k p : ℕ) : - (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by +lemma den_neg_pow_div_two_dvd_two (k p : ℕ) : (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by rw [neg_div, Rat.den_neg_eq_den, ← Nat.cast_pow] conv_lhs => rw [show (2 : ℚ) = (2 : ℕ) from rfl, Rat.natCast_div_eq_divInt] have h := Rat.den_dvd (p ^ (2 * k - 1)) 2 @@ -702,12 +699,10 @@ lemma pIntegral_mul_int (p : ℕ) (x : ℚ) (z : ℤ) (hx : pIntegral p x) : have h2 := Nat.Coprime.coprime_dvd_left h1 hx aesop -lemma pIntegral_mul_nat (p : ℕ) (x : ℚ) (n : ℕ) (hx : pIntegral p x) : - pIntegral p (n * x) := +lemma pIntegral_mul_nat (p : ℕ) (x : ℚ) (n : ℕ) (hx : pIntegral p x) : pIntegral p (n * x) := pIntegral_mul_int p x n hx -lemma valuation_bound_d_plus_1_p2_d2 : - (2 + 1).factorization 2 ≤ 2 - 1 := by +lemma valuation_bound_d_plus_1_p2_d2 : (2 + 1).factorization 2 ≤ 2 - 1 := by simp [Nat.factorization_eq_zero_of_not_dvd (show ¬(2 ∣ 3) by decide)] lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) := by @@ -723,8 +718,7 @@ lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - _ = 2 ^ m := by conv_rhs => rw [show m = m - 1 + 1 from by omega]; exact pow_succ .. exact h d hd -lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : - d + 1 ≤ p ^ (d - 1) := by +lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 ≤ p ^ (d - 1) := by have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by intro d hd induction hd with @@ -905,8 +899,7 @@ lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] -lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) - (hp : p.Prime) (hd : 2 * k - 2 * m ≥ 2) : +lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * k - 2 * m ≥ 2) : pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def @@ -923,8 +916,7 @@ lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) rw [h_eq] exact pIntegral_mul_nat p _ _ h_pow_integral -lemma pIntegral_second_term (k m p : ℕ) (hm_lt : m < k) - (hp : p.Prime) : +lemma pIntegral_second_term (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : pIntegral p (vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1)) := by unfold vonStaudtIndicator @@ -958,8 +950,7 @@ lemma even_term_decomposition_identity (k m p : ℕ) (hm_lt : m < k) : C / N := by rw [h] _ = _ := by ring -lemma pIntegral_coeff_term (k m p : ℕ) (hm_lt : m < k) - (hp : p.Prime) : +lemma pIntegral_coeff_term (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : pIntegral p (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by have hsimp := choose_div_simplify k m ((p : ℚ) ^ (2 * k - 2 * m)) hm_lt rw [hsimp] @@ -977,8 +968,7 @@ lemma pIntegral_coeff_term (k m p : ℕ) (hm_lt : m < k) · exact pIntegral_of_int p p · exact pIntegral_case_one k m p hm_lt hp (by omega) -lemma pIntegral_first_term (k m p : ℕ) (hm_lt : m < k) - (hp : p.Prime) +lemma pIntegral_first_term (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * From b708270752e808ea241f73e88bb2d4e431320e8d Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Fri, 6 Feb 2026 06:54:38 -0800 Subject: [PATCH 18/70] refactor(NumberTheory/Bernoulli): group pIntegral closure lemmas together Move pIntegral_of_int, pIntegral_mul, pIntegral_mul_int, pIntegral_mul_nat, and pIntegral_sub to directly after pIntegral_sum so all basic pIntegral closure properties are co-located. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 40 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 53feec730c8701..e52e3170f3b0f0 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -567,6 +567,26 @@ lemma pIntegral_sum {ι : Type*} (p : ℕ) (s : Finset ι) (f : ι → ℚ) Nat.Coprime.coprime_dvd_left (sum_den_dvd_prod_den s f) (Nat.Coprime.prod_left fun i hi => hf i hi) +lemma pIntegral_of_int (p : ℕ) (z : ℤ) : pIntegral p z := by simp_all [pIntegral] + +lemma pIntegral_mul (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : + pIntegral p (x * y) := + Nat.Coprime.of_dvd_left (Rat.mul_den_dvd x y) (Nat.Coprime.mul_left hx hy) + +lemma pIntegral_mul_int (p : ℕ) (x : ℚ) (z : ℤ) (hx : pIntegral p x) : + pIntegral p (z * x) := by + have _ := Rat.mul_den_dvd z x + have h1 : (z * x : ℚ).den ∣ x.den := by aesop + have h2 := Nat.Coprime.coprime_dvd_left h1 hx + aesop + +lemma pIntegral_mul_nat (p : ℕ) (x : ℚ) (n : ℕ) (hx : pIntegral p x) : pIntegral p (n * x) := + pIntegral_mul_int p x n hx + +lemma pIntegral_sub (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : + pIntegral p (x - y) := + Nat.Coprime.coprime_dvd_left (Rat.sub_den_dvd x y) (Nat.Coprime.mul_left hx hy) + lemma prod_den_coprime_p (k p : ℕ) (hp : p.Prime) : (∏ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, ((1 : ℚ) / q).den).Coprime p := by @@ -602,8 +622,6 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : ⟨fun ⟨hpr, hd⟩ => ⟨hpr, hd, fun h => hdvd (h ▸ hd)⟩, fun ⟨hpr, hd, _⟩ => ⟨hpr, hd⟩⟩) fun _ _ => rfl -lemma pIntegral_of_int (p : ℕ) (z : ℤ) : pIntegral p z := by simp_all [pIntegral] - lemma pow_div_eq_pow_sub_div_ordCompl (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) (hv : M.factorization p ≤ N) : (p : ℚ)^N / M = (p : ℚ) ^ (N - M.factorization p) / (M / p ^ M.factorization p) := by @@ -688,20 +706,6 @@ lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : · exact pIntegral_i1_term_p_eq_two k hk · exact pIntegral_i1_term_p_odd k p hk hp hp2 -lemma pIntegral_mul (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : - pIntegral p (x * y) := - Nat.Coprime.of_dvd_left (Rat.mul_den_dvd x y) (Nat.Coprime.mul_left hx hy) - -lemma pIntegral_mul_int (p : ℕ) (x : ℚ) (z : ℤ) (hx : pIntegral p x) : - pIntegral p (z * x) := by - have _ := Rat.mul_den_dvd z x - have h1 : (z * x : ℚ).den ∣ x.den := by aesop - have h2 := Nat.Coprime.coprime_dvd_left h1 hx - aesop - -lemma pIntegral_mul_nat (p : ℕ) (x : ℚ) (n : ℕ) (hx : pIntegral p x) : pIntegral p (n * x) := - pIntegral_mul_int p x n hx - lemma valuation_bound_d_plus_1_p2_d2 : (2 + 1).factorization 2 ≤ 2 - 1 := by simp [Nat.factorization_eq_zero_of_not_dvd (show ¬(2 ∣ 3) by decide)] @@ -843,10 +847,6 @@ lemma even_term_eq_T1_sub_T2 (k m p : ℕ) (hm_lt : m < k) : _ = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * C * (p : ℚ) ^ (2*(k-m)) / N - vonStaudtIndicator (2 * m) p * C * (p : ℚ) ^ (2*(k-m) - 1) / N := by ring -lemma pIntegral_sub (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : - pIntegral p (x - y) := - Nat.Coprime.coprime_dvd_left (Rat.sub_den_dvd x y) (Nat.Coprime.mul_left hx hy) - theorem i1_term_forms_eq (k p : ℕ) (hk : k > 0) : bernoulli 1 * (2 * ↑k) * (p : ℚ) ^ (2 * k - 1) / (2 * ↑k) = bernoulli 1 * ↑(2 * k + 1) * (p : ℚ) ^ (2 * k - 1) / (2 * ↑k + 1) := by From 4a14bf6506ee511f291de6b0559fd30868e53a46 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Fri, 6 Feb 2026 06:57:22 -0800 Subject: [PATCH 19/70] minor --- Mathlib/NumberTheory/Bernoulli.lean | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index e52e3170f3b0f0..1f7882ca81903d 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -607,8 +607,7 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by by_cases hdvd : (p - 1 : ℕ) ∣ 2 * k · -- p is in the filtered set; extract its term - have hp_mem : p ∈ (Finset.range (2 * k + 2)).filter - (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) := by + have hp_mem : p ∈ (Finset.range (2 * k + 2)).filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) := by simp only [Finset.mem_filter, Finset.mem_range] exact ⟨by have := Nat.le_of_dvd (by omega) hdvd; omega, hp, hdvd⟩ rw [← Finset.add_sum_erase _ _ hp_mem] @@ -1171,8 +1170,7 @@ lemma von_staudt_coprime_all_primes_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) (sum_other_primes_coprime_p_pos k p hp)) theorem von_staudt_clausen (k : ℕ) : - bernoulli (2 * k) + - ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, + bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast := by rcases Nat.eq_zero_or_pos k with rfl | hk · exact von_staudt_clausen_zero From a2b55002d816389818d2fafbe5a1028d08b9ee9b Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Fri, 6 Feb 2026 07:02:08 -0800 Subject: [PATCH 20/70] refactor(NumberTheory/Bernoulli): remove pIntegral_nat_mul MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove pIntegral_nat_mul and use pIntegral_int_mul directly at call sites, relying on Lean's automatic ℕ → ℤ coercion. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 1f7882ca81903d..8bd420a869f38a 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -573,16 +573,12 @@ lemma pIntegral_mul (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p pIntegral p (x * y) := Nat.Coprime.of_dvd_left (Rat.mul_den_dvd x y) (Nat.Coprime.mul_left hx hy) -lemma pIntegral_mul_int (p : ℕ) (x : ℚ) (z : ℤ) (hx : pIntegral p x) : - pIntegral p (z * x) := by +lemma pIntegral_int_mul (p : ℕ) (x : ℚ) (z : ℤ) (hx : pIntegral p x) : pIntegral p (z * x) := by have _ := Rat.mul_den_dvd z x have h1 : (z * x : ℚ).den ∣ x.den := by aesop have h2 := Nat.Coprime.coprime_dvd_left h1 hx aesop -lemma pIntegral_mul_nat (p : ℕ) (x : ℚ) (n : ℕ) (hx : pIntegral p x) : pIntegral p (n * x) := - pIntegral_mul_int p x n hx - lemma pIntegral_sub (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x - y) := Nat.Coprime.coprime_dvd_left (Rat.sub_den_dvd x y) (Nat.Coprime.mul_left hx hy) @@ -816,7 +812,7 @@ lemma pIntegral_T2 (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : (↑((2 * k).choose (2 * m)) : ℚ) * (↑p ^ (2 * d - 1) / ↑(2 * d + 1)) := by ring rw [h_rw] - exact pIntegral_mul_nat p ((p : ℚ) ^ (2 * d - 1) / ↑(2 * d + 1)) + exact pIntegral_int_mul p ((p : ℚ) ^ (2 * d - 1) / ↑(2 * d + 1)) ((2 * k).choose (2 * m)) h_pow_pIntegral · simp only [zero_mul, zero_div] exact pIntegral_of_int p 0 @@ -913,7 +909,7 @@ lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * have h_eq : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ) = ((2 * k).choose (2 * m) : ℕ) * ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by ring rw [h_eq] - exact pIntegral_mul_nat p _ _ h_pow_integral + exact pIntegral_int_mul p _ _ h_pow_integral lemma pIntegral_second_term (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : pIntegral p (vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * From ef90c669220cb8119590c8bdcdb5ba1aaa9b573a Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Fri, 6 Feb 2026 07:05:30 -0800 Subject: [PATCH 21/70] refactor(NumberTheory/Bernoulli): inline von_staudt_clausen_zero Merge the single-use von_staudt_clausen_zero lemma directly into the k = 0 case of von_staudt_clausen. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 8bd420a869f38a..6ba886bfbddb1c 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -393,15 +393,6 @@ section vonStaudtClausen noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1 : ℕ) ∣ k then 1 else 0 -lemma von_staudt_clausen_zero : - bernoulli (2 * 0) + ∑ p ∈ Finset.range (2 * 0 + 2) with p.Prime ∧ (p - 1) ∣ 2 * 0, - (1 : ℚ) / p ∈ Set.range Int.cast := by - have h1 : bernoulli (2 * 0) = 1 := by norm_num [bernoulli_zero] - have h2 : ∑ p ∈ Finset.range (2 * 0 + 2) with - p.Prime ∧ (p - 1) ∣ 2 * 0, (1 : ℚ) / p = 0 := by norm_num; decide - rw [h1, h2] - exact ⟨1, by norm_num⟩ - lemma zmod_pow_eq_one_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) ∣ l) (a : ZMod p) (ha : a ≠ 0) : a ^ l = 1 := by haveI : Fact p.Prime := ⟨hp⟩ @@ -1169,7 +1160,11 @@ theorem von_staudt_clausen (k : ℕ) : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast := by rcases Nat.eq_zero_or_pos k with rfl | hk - · exact von_staudt_clausen_zero + · have h1 : bernoulli (2 * 0) = 1 := by norm_num [bernoulli_zero] + have h2 : ∑ p ∈ Finset.range (2 * 0 + 2) with + p.Prime ∧ (p - 1) ∣ 2 * 0, (1 : ℚ) / p = 0 := by norm_num; decide + rw [h1, h2] + exact ⟨1, by norm_num⟩ · exact is_integer_of_coprime_all_primes _ (fun p hp => von_staudt_coprime_all_primes_pos k p hk hp) From a6f90181ae255fcfcef8723654421fae95af07fd Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Fri, 6 Feb 2026 07:26:40 -0800 Subject: [PATCH 22/70] more golf --- Mathlib/NumberTheory/Bernoulli.lean | 45 +++++++++-------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 6ba886bfbddb1c..49e167d6e3966a 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -420,8 +420,7 @@ lemma power_sum_eq_neg_one_mod_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) simp [Nat.cast_sub hp.pos] lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : - (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = - ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := by + (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := by have hcast := cast_ne_zero_of_mem_filter p refine Finset.sum_bij' (fun v hv => ⟨(v : ZMod p), (v : ZMod p)⁻¹, mul_inv_cancel₀ (hcast v hv), inv_mul_cancel₀ (hcast v hv)⟩) @@ -447,8 +446,7 @@ lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : simp lemma generator_orderOf_eq (p : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) - (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : - orderOf g = p - 1 := by + (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : orderOf g = p - 1 := by have h1 : Fintype.card (Subgroup.zpowers g) = orderOf g := Fintype.card_zpowers have h3 : Fintype.card (ZMod p)ˣ = p - 1 := ZMod.card_units p aesop @@ -580,13 +578,9 @@ lemma prod_den_coprime_p (k p : ℕ) (hp : p.Prime) : apply Nat.Coprime.prod_left intro q hq have h1 : q.Prime := (Finset.mem_filter.mp hq).2.1 - have h2 : q ≠ p := (Finset.mem_filter.mp hq).2.2.2 - have h3 : ((1 : ℚ) / q).den = q := by - have h5 : (q : ℕ) ≠ 0 := Nat.Prime.ne_zero h1 - field_simp [h5] - simp_all - rw [h3] - exact (Nat.coprime_primes h1 hp).mpr h2 + have h2 : ((1 : ℚ) / q).den = q := by have := Nat.Prime.ne_zero h1; simp_all + rw [h2] + exact (Nat.coprime_primes h1 hp).mpr (Finset.mem_filter.mp hq).2.2.2 lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = @@ -712,9 +706,7 @@ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by intro d hd induction hd with - | refl => - norm_num - omega + | refl => norm_num; omega | @step m hm IH => have hm : (2 : ℕ) ≤ m := hm calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by omega @@ -1024,11 +1016,9 @@ lemma power_sum_indicator_divisible_by_p (k p : ℕ) (hp : p.Prime) : lemma faulhaber_split_top_term (k p : ℕ) : (∑ i ∈ Finset.range (2 * k + 1), - bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / - (2 * k + 1)) = + bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) = (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / - (2 * k + 1)) + - bernoulli (2 * k) * ((2 * k + 1).choose (2 * k)) * + (2 * k + 1)) + bernoulli (2 * k) * ((2 * k + 1).choose (2 * k)) * (p : ℚ) ^ (2 * k + 1 - 2 * k) / (2 * k + 1) := by have h3 : Finset.range (2 * k + 1) = Finset.range (2 * k) ∪ {2 * k} := by ext x; simp [Finset.mem_range]; omega @@ -1072,21 +1062,12 @@ lemma remainder_div_p (k p : ℕ) (hp : p.Prime) : lemma algebraic_rearrangement (k p : ℕ) (T : ℤ) (hp : p.Prime) (hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = (p : ℚ) * (T : ℚ)) - (hFaul : (∑ v ∈ Finset.range p with v ≠ 0, - (v : ℚ) ^ (2 * k)) = - (∑ i ∈ Finset.range (2 * k), bernoulli i * - ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / - (2 * k + 1)) + p * bernoulli (2 * k)) : - bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = - T - (∑ i ∈ Finset.range (2 * k), bernoulli i * - ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by + (hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = + (∑ i ∈ Finset.range (2 * k), bernoulli i * + ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k)) : + bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), + bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast hp.ne_zero - set S := (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) - have key : (p : ℚ) * bernoulli (2 * k) + vonStaudtIndicator (2 * k) p = - (p : ℚ) * T - S := by linarith field_simp [hp_ne] linarith From 19111c7ce0df1936e52d20f1b4f776b293e7081d Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Fri, 6 Feb 2026 07:32:46 -0800 Subject: [PATCH 23/70] refactor(NumberTheory/Bernoulli): inline i1_term_forms_eq Remove single-use i1_term_forms_eq and replace it with a shorter `convert` + `push_cast` + `field_simp` proof inside pIntegral_i1_term_in_sum. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 49e167d6e3966a..990a2c14397a75 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -825,19 +825,12 @@ lemma even_term_eq_T1_sub_T2 (k m p : ℕ) (hm_lt : m < k) : _ = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * C * (p : ℚ) ^ (2*(k-m)) / N - vonStaudtIndicator (2 * m) p * C * (p : ℚ) ^ (2*(k-m) - 1) / N := by ring -theorem i1_term_forms_eq (k p : ℕ) (hk : k > 0) : - bernoulli 1 * (2 * ↑k) * (p : ℚ) ^ (2 * k - 1) / (2 * ↑k) = - bernoulli 1 * ↑(2 * k + 1) * (p : ℚ) ^ (2 * k - 1) / (2 * ↑k + 1) := by - have h1 : (2 : ℚ) * k ≠ 0 := by positivity - have h2 : (2 : ℚ) * k + 1 ≠ 0 := by positivity - simp only [show (↑(2 * k + 1) : ℚ) = 2 * ↑k + 1 by norm_cast] - field_simp [h1, h2] - lemma pIntegral_i1_term_in_sum (k p : ℕ) (hk : k > 0) (hp : p.Prime) : pIntegral p (bernoulli 1 * ((2 * k + 1).choose 1) * (p : ℚ) ^ (2 * k - 1) / (2 * k + 1)) := by simp only [Nat.choose_one_right] - rw [← i1_term_forms_eq k p hk] - exact pIntegral_i1_term k p hk hp + convert pIntegral_i1_term k p hk hp using 1 + push_cast + field_simp lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by @@ -998,11 +991,8 @@ lemma faulhaber_top_term (k p : ℕ) : rw [← Nat.choose_symm_of_eq_add (by omega : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] rw [h1, show (2 * k + 1 - 2 * k : ℕ) = 1 from by omega, pow_one] have h4 : (2 * k + 1 : ℚ) ≠ 0 := by positivity - field_simp [h4] - ring_nf - field_simp [h4] norm_cast - ring_nf + field_simp [h4] lemma power_sum_indicator_divisible_by_p (k p : ℕ) (hp : p.Prime) : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + From d46963a6444b03953d2549aadd420b549bb62004 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 7 Feb 2026 21:03:14 -0800 Subject: [PATCH 24/70] remove unused lemmas & add docstring --- Mathlib/NumberTheory/Bernoulli.lean | 117 ++++------------------------ 1 file changed, 14 insertions(+), 103 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 990a2c14397a75..d4137f07aa6f6c 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -421,29 +421,14 @@ lemma power_sum_eq_neg_one_mod_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := by - have hcast := cast_ne_zero_of_mem_filter p - refine Finset.sum_bij' (fun v hv => ⟨(v : ZMod p), (v : ZMod p)⁻¹, - mul_inv_cancel₀ (hcast v hv), inv_mul_cancel₀ (hcast v hv)⟩) - (fun u _ => (u : ZMod p).val) ?_ ?_ ?_ ?_ ?_ - · intro v hv - exact Finset.mem_univ _ - · intro u _ - simp only [Finset.mem_filter, Finset.mem_range] - constructor - · exact ZMod.val_lt (u : ZMod p) - · intro h - have hu : (u : ZMod p) ≠ 0 := Units.ne_zero u - simp only [ZMod.val_eq_zero] at h - exact hu h - · intro v hv - simp only [Finset.mem_filter, Finset.mem_range] at hv - have : (v : ZMod p).val = v := ZMod.val_cast_of_lt hv.1 - simp only [this] - · intro u _ - ext - simp only [ZMod.natCast_zmod_val] - · intro v _ - simp + refine Finset.sum_bij' + (fun v hv => Units.mk0 (↑v) (cast_ne_zero_of_mem_filter p v hv)) + (fun u _ => (u : ZMod p).val) + (fun _ _ => Finset.mem_univ _) + (fun u _ => by simp [Finset.mem_filter, ZMod.val_lt, ZMod.val_eq_zero, u.ne_zero]) + (fun v hv => by simp [ZMod.val_cast_of_lt (Finset.mem_range.mp (Finset.mem_filter.mp hv).1)]) + (fun u _ => Units.ext (ZMod.natCast_zmod_val _)) + (fun _ _ => rfl) lemma generator_orderOf_eq (p : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : orderOf g = p - 1 := by @@ -475,10 +460,8 @@ lemma sum_units_eq_sum_range (p l : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) ext i simp [← pow_mul, mul_comm] -lemma generator_pow_ne_one (p l : ℕ) [hp : Fact p.Prime] - (hndvd : ¬(p - 1) ∣ l) (g : (ZMod p)ˣ) - (hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : - (g : ZMod p) ^ l ≠ 1 := by +lemma generator_pow_ne_one (p l : ℕ) [hp : Fact p.Prime] (hndvd : ¬(p - 1) ∣ l) (g : (ZMod p)ˣ) + (hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : (g : ZMod p) ^ l ≠ 1 := by have h_order : orderOf g = p - 1 := by simp only [orderOf_eq_card_of_forall_mem_zpowers hg, Nat.card_eq_fintype_card, ZMod.card_units] intro h @@ -511,20 +494,7 @@ lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : · simp only [h, ↓reduceIte, add_zero] exact power_sum_eq_zero_mod_of_not_dvd p l hp h -lemma mem_range_int_cast_iff (q : ℚ) : - q ∈ Set.range Int.cast ↔ q.den = 1 := by - constructor - · intro ⟨z, hz⟩ - simp only [← hz] - norm_cast - · intro h - use q.num - have hq : (q.num : ℚ) / q.den = q := Rat.num_div_den q - rw [← hq, h] - simp - -lemma is_integer_of_coprime_all_primes (q : ℚ) - (h : ∀ p : ℕ, p.Prime → q.den.Coprime p) : +lemma is_integer_of_coprime_all_primes (q : ℚ) (h : ∀ p : ℕ, p.Prime → q.den.Coprime p) : q ∈ Set.range Int.cast := by have h1 : q.den = 1 := by by_contra hne @@ -729,21 +699,6 @@ lemma pIntegral_pow_div_factor (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : · omega · exact valuation_bound p (2 * d) hp -lemma pIntegral_T1 (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) - (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : - pIntegral p ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k).choose (2 * m)) * - (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1)) := by - have h_eq : (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k).choose (2 * m)) * - (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1) = - ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k).choose (2 * m))) * - ((p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1)) := by ring - rw [h_eq] - apply pIntegral_mul - · apply pIntegral_mul - · exact ih - · exact pIntegral_of_int p ((2 * k).choose (2 * m)) - · exact pIntegral_pow_div_factor k m p hm_lt hp - lemma valuation_three_le_one (p : ℕ) (hp : p.Prime) : (3 : ℕ).factorization p ≤ 1 := by rcases hp.eq_two_or_odd with rfl | hp_odd · exact valuation_bound_d_plus_1_p2_d2 @@ -770,36 +725,6 @@ lemma valuation_bound_2d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 1) : calc 2 * d + 1 ≤ 2 ^ (2 * d - 1) := two_d_plus_one_le_pow_two d hd2 _ ≤ p ^ (2 * d - 1) := Nat.pow_le_pow_left hp.two_le _ -lemma pIntegral_T2 (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : - pIntegral p (vonStaudtIndicator (2 * m) p * ((2 * k).choose (2 * m)) * (p : ℚ) ^ (2*(k-m) - 1) / - (2*(k-m) + 1)) := by - set d := k - m with hd_def - have hd_pos : d ≥ 1 := by omega - unfold vonStaudtIndicator - split_ifs with he - · simp only [one_mul] - have hd_eq : (2 : ℚ) * (↑k - ↑m) + 1 = ↑(2 * d + 1) := by - simp only [hd_def] - have hkm : m ≤ k := le_of_lt hm_lt - rw [← Nat.cast_sub hkm] - push_cast - ring - rw [hd_eq] - have hN_ne_zero : (2 * d + 1 : ℕ) ≠ 0 := by omega - have hvaluation : (2 * d + 1).factorization p ≤ 2 * d - 1 := - valuation_bound_2d_plus_1 p d hp hd_pos - have h_pow_pIntegral : pIntegral p ((p : ℚ) ^ (2 * d - 1) / ↑(2 * d + 1)) := - pIntegral_pow_div p (2 * d + 1) (2 * d - 1) hp hN_ne_zero hvaluation - have h_rw : - (↑((2 * k).choose (2 * m)) : ℚ) * ↑p ^ (2 * d - 1) / ↑(2 * d + 1) = - (↑((2 * k).choose (2 * m)) : ℚ) * - (↑p ^ (2 * d - 1) / ↑(2 * d + 1)) := by ring - rw [h_rw] - exact pIntegral_int_mul p ((p : ℚ) ^ (2 * d - 1) / ↑(2 * d + 1)) - ((2 * k).choose (2 * m)) h_pow_pIntegral - · simp only [zero_mul, zero_div] - exact pIntegral_of_int p 0 - lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : B * (p : ℚ) ^ (2*d) = (B + I / p) * (p : ℚ) ^ (2*d) - I * (p : ℚ) ^ (2*d - 1) := by have hpow : (p : ℚ) ^ (2*d) = (p : ℚ) ^ (2*d - 1) * p := by @@ -808,23 +733,6 @@ lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : · simp [hp, zero_pow (show 2 * d - 1 ≠ 0 from by omega)] · rw [hpow]; field_simp [hp]; ring -lemma even_term_eq_T1_sub_T2 (k m p : ℕ) (hm_lt : m < k) : - (bernoulli (2 * m) * ((2 * k).choose (2 * m)) * (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1) : ℚ) = - (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k).choose (2 * m)) * - (p : ℚ) ^ (2*(k-m)) / (2*(k-m) + 1) - - vonStaudtIndicator (2 * m) p * ((2 * k).choose (2 * m)) * - (p : ℚ) ^ (2*(k-m) - 1) / (2*(k-m) + 1) := by - have h := core_algebraic_identity (bernoulli (2 * m)) (vonStaudtIndicator (2 * m) p) p (k - m) - (by omega) - set C := ((2 * k).choose (2 * m) : ℚ) - set N := (2 * (k - m) + 1 : ℚ) - calc bernoulli (2 * m) * C * (p : ℚ) ^ (2*(k-m)) / N - = (bernoulli (2 * m) * (p : ℚ) ^ (2*(k-m))) * C / N := by ring - _ = ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * (p : ℚ) ^ (2*(k-m)) - - vonStaudtIndicator (2 * m) p * (p : ℚ) ^ (2*(k-m) - 1)) * C / N := by rw [h] - _ = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * C * (p : ℚ) ^ (2*(k-m)) / N - - vonStaudtIndicator (2 * m) p * C * (p : ℚ) ^ (2*(k-m) - 1) / N := by ring - lemma pIntegral_i1_term_in_sum (k p : ℕ) (hk : k > 0) (hp : p.Prime) : pIntegral p (bernoulli 1 * ((2 * k + 1).choose 1) * (p : ℚ) ^ (2 * k - 1) / (2 * k + 1)) := by simp only [Nat.choose_one_right] @@ -1127,6 +1035,9 @@ lemma von_staudt_coprime_all_primes_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) ((bernoulli_plus_indicator_coprime_p_pos k p hk hp).mul_left (sum_other_primes_coprime_p_pos k p hp)) +/-- **von Staudt-Clausen theorem:** For any natural number $k$, the sum +$$B_{2k} + \sum_{p - 1 \mid 2k} \frac{1}{p}$$ is an integer. +-/ theorem von_staudt_clausen (k : ℕ) : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast := by From 5d73b9ed4345ec748defb2c65de0746d2bfad315 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 7 Feb 2026 21:47:14 -0800 Subject: [PATCH 25/70] refactor(NumberTheory/Bernoulli): inline single-use lemmas Inline ~20 single-use helper lemmas into their callers, reducing the file from ~1053 to 884 lines and from ~80 to 60 definitions. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 519 ++++++++++------------------ 1 file changed, 175 insertions(+), 344 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index d4137f07aa6f6c..381c7df84bb548 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -393,17 +393,6 @@ section vonStaudtClausen noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1 : ℕ) ∣ k then 1 else 0 -lemma zmod_pow_eq_one_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) ∣ l) - (a : ZMod p) (ha : a ≠ 0) : a ^ l = 1 := by - haveI : Fact p.Prime := ⟨hp⟩ - obtain ⟨k, hk⟩ := hdvd - simp only [hk, pow_mul, ZMod.pow_card_sub_one_eq_one ha, one_pow] - -lemma card_filter_range_ne_zero (p : ℕ) (_hp : p.Prime) : - (Finset.range p |>.filter (· ≠ 0)).card = p - 1 := by - simp only [Finset.filter_ne', Finset.card_erase_of_mem (Finset.mem_range.mpr _hp.pos), - Finset.card_range] - lemma cast_ne_zero_of_mem_filter (p : ℕ) (v : ℕ) (hv : v ∈ (Finset.range p).filter (· ≠ 0)) : (v : ZMod p) ≠ 0 := by simp only [Finset.mem_filter, Finset.mem_range] at hv @@ -413,77 +402,44 @@ lemma cast_ne_zero_of_mem_filter (p : ℕ) (v : ℕ) lemma power_sum_eq_neg_one_mod_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) ∣ l) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = -1 := by - have h1 : ∀ v ∈ (Finset.range p).filter (· ≠ 0), (v : ZMod p) ^ l = 1 := fun v hv => - zmod_pow_eq_one_of_dvd p l hp hdvd (v : ZMod p) (cast_ne_zero_of_mem_filter p v hv) - rw [Finset.sum_congr rfl h1, Finset.sum_const, card_filter_range_ne_zero p hp, + haveI : Fact p.Prime := ⟨hp⟩ + have h1 : ∀ v ∈ (Finset.range p).filter (· ≠ 0), (v : ZMod p) ^ l = 1 := by + intro v hv; obtain ⟨k, hk⟩ := hdvd + simp only [hk, pow_mul, ZMod.pow_card_sub_one_eq_one (cast_ne_zero_of_mem_filter p v hv), + one_pow] + rw [Finset.sum_congr rfl h1, Finset.sum_const, Finset.filter_ne', + Finset.card_erase_of_mem (Finset.mem_range.mpr hp.pos), Finset.card_range, nsmul_eq_mul, mul_one] simp [Nat.cast_sub hp.pos] -lemma sum_pow_eq_sum_units_pow (p l : ℕ) [Fact p.Prime] : - (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := by - refine Finset.sum_bij' - (fun v hv => Units.mk0 (↑v) (cast_ne_zero_of_mem_filter p v hv)) - (fun u _ => (u : ZMod p).val) - (fun _ _ => Finset.mem_univ _) - (fun u _ => by simp [Finset.mem_filter, ZMod.val_lt, ZMod.val_eq_zero, u.ne_zero]) - (fun v hv => by simp [ZMod.val_cast_of_lt (Finset.mem_range.mp (Finset.mem_filter.mp hv).1)]) - (fun u _ => Units.ext (ZMod.natCast_zmod_val _)) - (fun _ _ => rfl) - lemma generator_orderOf_eq (p : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : orderOf g = p - 1 := by have h1 : Fintype.card (Subgroup.zpowers g) = orderOf g := Fintype.card_zpowers have h3 : Fintype.card (ZMod p)ˣ = p - 1 := ZMod.card_units p aesop -lemma pow_injective_on_range (p : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) - (hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : - Set.InjOn (fun i => g ^ i) (Finset.range (p - 1) : Set ℕ) := by - intro i hi j hj heq - simp only [Finset.coe_range, Set.mem_Iio] at hi hj - have hord : orderOf g = p - 1 := generator_orderOf_eq p g hg - have hfin : IsOfFinOrder g := isOfFinOrder_of_finite g - rw [IsOfFinOrder.pow_eq_pow_iff_modEq hfin, hord] at heq - exact Nat.ModEq.eq_of_lt_of_lt heq hi hj - -lemma sum_units_eq_sum_range (p l : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) - (hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : - (∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l) = - ∑ i ∈ Finset.range (p - 1), ((g : ZMod p) ^ l) ^ i := by - have hord : orderOf g = p - 1 := generator_orderOf_eq p g hg - have himg : Finset.image (fun i => g ^ i) (Finset.range (orderOf g)) = Finset.univ := - IsCyclic.image_range_orderOf hg - rw [hord] at himg - conv_lhs => rw [← himg] - rw [Finset.sum_image (pow_injective_on_range p g hg)] - congr 1 - ext i - simp [← pow_mul, mul_comm] - -lemma generator_pow_ne_one (p l : ℕ) [hp : Fact p.Prime] (hndvd : ¬(p - 1) ∣ l) (g : (ZMod p)ˣ) - (hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : (g : ZMod p) ^ l ≠ 1 := by - have h_order : orderOf g = p - 1 := by - simp only [orderOf_eq_card_of_forall_mem_zpowers hg, Nat.card_eq_fintype_card, ZMod.card_units] - intro h - exact hndvd (h_order ▸ orderOf_dvd_of_pow_eq_one (Units.ext (by simpa using h))) - lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hndvd : ¬(p - 1) ∣ l) : (∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l) = 0 := by haveI : IsCyclic (ZMod p)ˣ := ZMod.isCyclic_units_prime hp.out obtain ⟨g, hg⟩ := IsCyclic.exists_generator (α := (ZMod p)ˣ) - rw [sum_units_eq_sum_range p l g hg] - have hx1 := generator_pow_ne_one p l hndvd g hg + -- Rewrite sum over units as geometric sum using generator + have hord : orderOf g = p - 1 := generator_orderOf_eq p g hg + have himg := IsCyclic.image_range_orderOf hg + rw [hord] at himg; conv_lhs => rw [← himg] + rw [Finset.sum_image (fun i (hi : i ∈ _) j hj heq => by + simp only [Finset.coe_range, Set.mem_Iio] at hi hj + rw [IsOfFinOrder.pow_eq_pow_iff_modEq (isOfFinOrder_of_finite g), hord] at heq + exact Nat.ModEq.eq_of_lt_of_lt heq hi hj)] + simp_rw [show ∀ i, (↑(g ^ i) : ZMod p) ^ l = ((g : ZMod p) ^ l) ^ i from + fun i => by simp [← pow_mul, mul_comm]] + -- Apply geometric sum formula + have hx1 : (g : ZMod p) ^ l ≠ 1 := by + intro h; exact hndvd (hord ▸ orderOf_dvd_of_pow_eq_one (Units.ext (by simpa using h))) have hxp := ZMod.pow_card_sub_one_eq_one (pow_ne_zero l (Units.ne_zero g)) have := geom_sum_eq hx1 (p - 1) aesop -lemma power_sum_eq_zero_mod_of_not_dvd (p l : ℕ) (hp : p.Prime) (hndvd : ¬(p - 1) ∣ l) : - (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = 0 := by - haveI : Fact p.Prime := ⟨hp⟩ - rw [sum_pow_eq_sum_units_pow p l] - exact sum_units_pow_eq_zero_of_not_dvd p l hndvd - lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + (if (p - 1 : ℕ) ∣ l then (1 : ZMod p) else 0) = 0 := by @@ -492,7 +448,20 @@ lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : rw [power_sum_eq_neg_one_mod_of_dvd p l hp h] ring · simp only [h, ↓reduceIte, add_zero] - exact power_sum_eq_zero_mod_of_not_dvd p l hp h + haveI : Fact p.Prime := ⟨hp⟩ + have : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = + ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := + Finset.sum_bij' + (fun v hv => Units.mk0 (v : ZMod p) (cast_ne_zero_of_mem_filter p v hv)) + (fun u _ => (u : ZMod p).val) + (fun _ _ => Finset.mem_univ _) + (fun u _ => by simp [Finset.mem_filter, ZMod.val_lt, ZMod.val_eq_zero, u.ne_zero]) + (fun v hv => by + simp [ZMod.val_cast_of_lt (Finset.mem_range.mp (Finset.mem_filter.mp hv).1)]) + (fun u _ => Units.ext (ZMod.natCast_zmod_val _)) + (fun _ _ => rfl) + rw [this] + exact sum_units_pow_eq_zero_of_not_dvd p l h lemma is_integer_of_coprime_all_primes (q : ℚ) (h : ∀ p : ℕ, p.Prime → q.den.Coprime p) : q ∈ Set.range Int.cast := by @@ -572,41 +541,27 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : ⟨fun ⟨hpr, hd⟩ => ⟨hpr, hd, fun h => hdvd (h ▸ hd)⟩, fun ⟨hpr, hd, _⟩ => ⟨hpr, hd⟩⟩) fun _ _ => rfl -lemma pow_div_eq_pow_sub_div_ordCompl (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) - (hv : M.factorization p ≤ N) : - (p : ℚ)^N / M = (p : ℚ) ^ (N - M.factorization p) / (M / p ^ M.factorization p) := by - set e := M.factorization p with he - set M' := M / p ^ e with hM' - have hdecomp : p ^ e * M' = M := Nat.ordProj_mul_ordCompl_eq_self M p - have hM'_ne : M' ≠ 0 := (Nat.ordCompl_pos p hM).ne' - have hM_cast : (M : ℚ) = (p ^ e : ℕ) * (M' : ℕ) := by rw [← hdecomp]; simp - rw [hM_cast] - have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr hp.ne_zero - have hpe_ne : (p : ℚ) ^ e ≠ 0 := pow_ne_zero e hp_ne - rw [div_mul_eq_div_div] - congr 1 - · rw [Nat.cast_pow, div_eq_iff hpe_ne, ← pow_add, Nat.sub_add_cancel hv] - · field_simp; simp - -lemma den_pow_div_dvd (p M' k : ℕ) : ((p : ℚ)^k / M').den ∣ M' := by - have h1 : ((p : ℚ) ^ k / M') = Rat.divInt (p ^ k : ℤ) (M' : ℤ) := by norm_cast; simp - rw [h1] - have h2 : ↑(Rat.divInt (p ^ k : ℤ) (M' : ℤ)).den ∣ (M' : ℤ) := by apply Rat.den_dvd - norm_cast at h2 ⊢ - lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ)^N / M) := by - set M' := M / p ^ M.factorization p with hM'_def + set e := M.factorization p + set M' := M / p ^ e with hM'_def have hM'_ne : M' ≠ 0 := (Nat.ordCompl_pos p hM).ne' have hM'_cop : M'.Coprime p := (Nat.coprime_ordCompl hp hM).symm - rw [pow_div_eq_pow_sub_div_ordCompl p M N hp hM hv] - have hcast : (M : ℚ) / (p : ℚ) ^ M.factorization p = (M' : ℚ) := by - rw [hM'_def] - simp only [← Nat.cast_pow] - rw [Nat.cast_div_charZero (Nat.ordProj_dvd M p)] - rw [hcast] - have hdvd : ((p : ℚ) ^ (N - M.factorization p) / M').den ∣ M' := - den_pow_div_dvd p M' (N - M.factorization p) + -- Rewrite p^N / M as p^(N-e) / M' where M' = M / p^e is coprime to p + have hdecomp : p ^ e * M' = M := Nat.ordProj_mul_ordCompl_eq_self M p + have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr hp.ne_zero + have hpe_ne : (p : ℚ) ^ e ≠ 0 := pow_ne_zero e hp_ne + have hrw : (p : ℚ) ^ N / M = (p : ℚ) ^ (N - e) / M' := by + have hM_cast : (M : ℚ) = (p ^ e : ℕ) * (M' : ℕ) := by rw [← hdecomp]; simp + rw [hM_cast, div_mul_eq_div_div] + congr 1 + · rw [Nat.cast_pow, div_eq_iff hpe_ne, ← pow_add, Nat.sub_add_cancel hv] + rw [hrw] + have hdvd : ((p : ℚ) ^ (N - e) / M').den ∣ M' := by + have h1 : ((p : ℚ) ^ (N - e) / M') = Rat.divInt (p ^ (N - e) : ℤ) (M' : ℤ) := by + norm_cast; simp + rw [h1] + exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _) exact hM'_cop.coprime_dvd_left hdvd lemma valuation_bound (p n : ℕ) (hp : p.Prime) : (n + 1).factorization p ≤ n := @@ -623,38 +578,26 @@ lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : · omega · exact valuation_bound p (2 * k) hp -lemma pIntegral_i1_term_p_eq_two (k : ℕ) (hk : k > 0) : - pIntegral 2 (bernoulli 1 * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) := by - rw [show bernoulli 1 = -1 / 2 from by norm_num [bernoulli_one]] - have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = - (-(2 : ℤ) ^ (2 * k - 2) : ℤ) := by - have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by - rw [show 2 * k - 1 = (2 * k - 2) + 1 from by omega, pow_succ] - rw [hpow]; push_cast; field_simp [show (2 * k : ℚ) ≠ 0 from by positivity] - rw [h] - norm_num [pIntegral] - -lemma den_neg_pow_div_two_dvd_two (k p : ℕ) : (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by - rw [neg_div, Rat.den_neg_eq_den, ← Nat.cast_pow] - conv_lhs => rw [show (2 : ℚ) = (2 : ℕ) from rfl, Rat.natCast_div_eq_divInt] - have h := Rat.den_dvd (p ^ (2 * k - 1)) 2 - exact Int.natCast_dvd_natCast.mp h - -lemma pIntegral_i1_term_p_odd (k p : ℕ) (hk : k > 0) (hp : p.Prime) (hp2 : p ≠ 2) : - pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by - rw [show bernoulli 1 = (-1 : ℚ) / 2 from by norm_num [bernoulli]] - have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega - field_simp [h2] - rw [show -(↑↑p ^ (2 * k - 1) / (2 : ℚ)) = -↑↑p ^ (2 * k - 1) / 2 from by ring] - unfold pIntegral - exact Nat.Coprime.of_dvd_left (den_neg_pow_div_two_dvd_two k p) - (Odd.coprime_two_left (hp.odd_of_ne_two hp2)) - lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by obtain rfl | hp2 := eq_or_ne p 2 - · exact pIntegral_i1_term_p_eq_two k hk - · exact pIntegral_i1_term_p_odd k p hk hp hp2 + · rw [show bernoulli 1 = -1 / 2 from by norm_num [bernoulli_one]] + have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = + (-(2 : ℤ) ^ (2 * k - 2) : ℤ) := by + have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by + rw [show 2 * k - 1 = (2 * k - 2) + 1 from by omega, pow_succ] + rw [hpow]; push_cast; field_simp [show (2 * k : ℚ) ≠ 0 from by positivity] + simp only [Nat.cast_ofNat, h]; norm_num [pIntegral] + · rw [show bernoulli 1 = (-1 : ℚ) / 2 from by norm_num [bernoulli]] + have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega + field_simp [h2] + rw [show -(↑↑p ^ (2 * k - 1) / (2 : ℚ)) = -↑↑p ^ (2 * k - 1) / 2 from by ring] + unfold pIntegral + have hdvd : (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by + rw [neg_div, Rat.den_neg_eq_den, ← Nat.cast_pow] + conv_lhs => rw [show (2 : ℚ) = (2 : ℕ) from rfl, Rat.natCast_div_eq_divInt] + exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _) + exact Nat.Coprime.of_dvd_left hdvd (Odd.coprime_two_left (hp.odd_of_ne_two hp2)) lemma valuation_bound_d_plus_1_p2_d2 : (2 + 1).factorization 2 ≤ 2 - 1 := by simp [Nat.factorization_eq_zero_of_not_dvd (show ¬(2 ∣ 3) by decide)] @@ -687,44 +630,6 @@ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 conv_rhs => rw [show m = m - 1 + 1 from by omega]; exact pow_succ .. exact h2 d hd -lemma pIntegral_pow_div_factor (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : - pIntegral p ((p : ℚ) ^ (2*(k-m)) / (2*(↑k - ↑m) + 1)) := by - set d := k - m with hd - have hd_pos : d ≥ 1 := by omega - have hcast : (↑k : ℚ) - ↑m = ↑d := by rw [hd, Nat.cast_sub (le_of_lt hm_lt)] - rw [hcast] - have hcast2 : (2 : ℚ) * ↑d + 1 = ↑(2 * d + 1) := by push_cast; ring - rw [hcast2] - apply pIntegral_pow_div p (2 * d + 1) (2 * d) hp - · omega - · exact valuation_bound p (2 * d) hp - -lemma valuation_three_le_one (p : ℕ) (hp : p.Prime) : (3 : ℕ).factorization p ≤ 1 := by - rcases hp.eq_two_or_odd with rfl | hp_odd - · exact valuation_bound_d_plus_1_p2_d2 - · rcases eq_or_ne p 3 with rfl | hp_ne_3 - · simp [Nat.Prime.factorization_self hp] - · have h : ¬ p ∣ 3 := by - intro hdvd - have hp_le_3 : p ≤ 3 := Nat.le_of_dvd (by omega) hdvd - have hp_ge_2 : p ≥ 2 := hp.two_le - interval_cases p <;> simp_all - simp [Nat.factorization_eq_zero_of_not_dvd h] - -lemma two_d_plus_one_le_pow_two (d : ℕ) (hd : d ≥ 2) : 2 * d + 1 ≤ 2 ^ (2 * d - 1) := by - have := pow_two_ge_succ_of_ge_three (2 * d) (by omega) - omega - -lemma valuation_bound_2d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 1) : - (2 * d + 1).factorization p ≤ 2 * d - 1 := by - rcases eq_or_lt_of_le hd with rfl | hd' - · simp only [mul_one] - exact valuation_three_le_one p hp - · have hd2 : d ≥ 2 := hd' - apply Nat.factorization_le_of_le_pow - calc 2 * d + 1 ≤ 2 ^ (2 * d - 1) := two_d_plus_one_le_pow_two d hd2 - _ ≤ p ^ (2 * d - 1) := Nat.pow_le_pow_left hp.two_le _ - lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : B * (p : ℚ) ^ (2*d) = (B + I / p) * (p : ℚ) ^ (2*d) - I * (p : ℚ) ^ (2*d - 1) := by have hpow : (p : ℚ) ^ (2*d) = (p : ℚ) ^ (2*d - 1) * p := by @@ -733,13 +638,6 @@ lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : · simp [hp, zero_pow (show 2 * d - 1 ≠ 0 from by omega)] · rw [hpow]; field_simp [hp]; ring -lemma pIntegral_i1_term_in_sum (k p : ℕ) (hk : k > 0) (hp : p.Prime) : - pIntegral p (bernoulli 1 * ((2 * k + 1).choose 1) * (p : ℚ) ^ (2 * k - 1) / (2 * k + 1)) := by - simp only [Nat.choose_one_right] - convert pIntegral_i1_term k p hk hp using 1 - push_cast - field_simp - lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by obtain hp2 | hp3 := hp.eq_two_or_odd @@ -795,78 +693,56 @@ lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * rw [h_eq] exact pIntegral_int_mul p _ _ h_pow_integral -lemma pIntegral_second_term (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : - pIntegral p (vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1)) := by - unfold vonStaudtIndicator - split_ifs with h - · simp only [one_mul] - rw [choose_div_simplify k m _ hm_lt] - exact pIntegral_case_one k m p hm_lt hp (by omega) - · simp only [zero_mul, zero_div] - unfold pIntegral - rw [Rat.den_zero] - exact Nat.coprime_one_left_iff p |>.mpr trivial - -lemma even_term_decomposition_identity (k m p : ℕ) (hm_lt : m < k) : - (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * +lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) + (hp : p.Prime) (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : + pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by + have hdecomp : (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) : ℚ) = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1) := by - simp only [show 2 * k - 2 * m = 2 * (k - m) from by omega] - have h := core_algebraic_identity (bernoulli (2 * m)) - (vonStaudtIndicator (2 * m) p) p (k - m) (by omega) - set C := ((2 * k + 1).choose (2 * m) : ℚ) - set N := (2 * k + 1 : ℚ) - calc bernoulli (2 * m) * C * (p : ℚ) ^ (2 * (k - m)) / N - = (bernoulli (2 * m) * (p : ℚ) ^ (2 * (k - m))) * C / N := by ring - _ = ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / ↑p) * - (p : ℚ) ^ (2 * (k - m)) - - vonStaudtIndicator (2 * m) p * (p : ℚ) ^ (2 * (k - m) - 1)) * - C / N := by rw [h] - _ = _ := by ring - -lemma pIntegral_coeff_term (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) : - pIntegral p (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by - have hsimp := choose_div_simplify k m ((p : ℚ) ^ (2 * k - 2 * m)) hm_lt - rw [hsimp] - have hp_factor : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k - 2 * m + 1) = - (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k - 2 * m + 1)) := by - have hpow : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) := by - conv_lhs => - rw [show (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1) + 1 from by omega] - exact pow_succ' _ _ - rw [hpow] - ring - rw [hp_factor] - apply pIntegral_mul - · exact pIntegral_of_int p p - · exact pIntegral_case_one k m p hm_lt hp (by omega) - -lemma pIntegral_first_term (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) - (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : - pIntegral p ((bernoulli (2 * m) + - vonStaudtIndicator (2 * m) p / p) * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by - rw [show (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = - (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * - (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) by ring] - exact pIntegral_mul p _ _ ih (pIntegral_coeff_term k m p hm_lt hp) - -lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) - (hp : p.Prime) (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : - pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by - rw [even_term_decomposition_identity k m p hm_lt] - exact pIntegral_sub p _ _ (pIntegral_first_term k m p hm_lt hp ih) - (pIntegral_second_term k m p hm_lt hp) + simp only [show 2 * k - 2 * m = 2 * (k - m) from by omega] + have h := core_algebraic_identity (bernoulli (2 * m)) + (vonStaudtIndicator (2 * m) p) p (k - m) (by omega) + set C := ((2 * k + 1).choose (2 * m) : ℚ) + set N := (2 * k + 1 : ℚ) + calc bernoulli (2 * m) * C * (p : ℚ) ^ (2 * (k - m)) / N + = (bernoulli (2 * m) * (p : ℚ) ^ (2 * (k - m))) * C / N := by ring + _ = ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / ↑p) * + (p : ℚ) ^ (2 * (k - m)) - + vonStaudtIndicator (2 * m) p * (p : ℚ) ^ (2 * (k - m) - 1)) * + C / N := by rw [h] + _ = _ := by ring + rw [hdecomp] + apply pIntegral_sub + · rw [show (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * + ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = + (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * + (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) by ring] + apply pIntegral_mul _ _ _ ih + rw [choose_div_simplify k m ((p : ℚ) ^ (2 * k - 2 * m)) hm_lt] + have hp_factor : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / + (2 * k - 2 * m + 1) = (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * + (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by + have hpow : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) := by + conv_lhs => + rw [show (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1) + 1 from by omega] + exact pow_succ' _ _ + rw [hpow]; ring + rw [hp_factor] + exact pIntegral_mul _ _ _ (pIntegral_of_int p p) (pIntegral_case_one k m p hm_lt hp (by omega)) + · unfold vonStaudtIndicator + split_ifs with h + · simp only [one_mul] + rw [choose_div_simplify k m _ hm_lt] + exact pIntegral_case_one k m p hm_lt hp (by omega) + · simp only [zero_mul, zero_div]; unfold pIntegral + rw [Rat.den_zero] + exact Nat.coprime_one_left_iff p |>.mpr trivial lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : @@ -878,8 +754,9 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] exact pIntegral_i0_term k p hk hp - · simp only [zero_add] - exact pIntegral_i1_term_in_sum k p hk hp + · simp only [zero_add, Nat.choose_one_right] + convert pIntegral_i1_term k p hk hp using 1 + push_cast; field_simp · set j := i + 2 with hj_def have hj_lt : j < 2 * k := by omega rcases Nat.even_or_odd j with ⟨m, hm⟩ | hodd @@ -892,54 +769,64 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) simp only [Rat.den_zero] exact Nat.coprime_one_left_iff p |>.mpr trivial -lemma faulhaber_top_term (k p : ℕ) : - bernoulli (2 * k) * ((2 * k + 1).choose (2 * k)) * (p : ℚ) ^ (2 * k + 1 - 2 * k) / (2 * k + 1) = - p * bernoulli (2 * k) := by - have h1 : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by - rw [← Nat.choose_symm_of_eq_add (by omega : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] - rw [h1, show (2 * k + 1 - 2 * k : ℕ) = 1 from by omega, pow_one] - have h4 : (2 * k + 1 : ℚ) ≠ 0 := by positivity - norm_cast - field_simp [h4] - -lemma power_sum_indicator_divisible_by_p (k p : ℕ) (hp : p.Prime) : - ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + - (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T := by - have h_cast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + - (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0)) : ZMod p) = 0 := by - push_cast - exact power_sum_add_indicator_eq_zero p (2 * k) hp - rw [ZMod.intCast_zmod_eq_zero_iff_dvd] at h_cast - exact h_cast - -lemma faulhaber_split_top_term (k p : ℕ) : - (∑ i ∈ Finset.range (2 * k + 1), - bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) = - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / - (2 * k + 1)) + bernoulli (2 * k) * ((2 * k + 1).choose (2 * k)) * - (p : ℚ) ^ (2 * k + 1 - 2 * k) / (2 * k + 1) := by - have h3 : Finset.range (2 * k + 1) = Finset.range (2 * k) ∪ {2 * k} := by - ext x; simp [Finset.mem_range]; omega - have h4 : Disjoint (Finset.range (2 * k)) ({2 * k} : Finset ℕ) := by - simp [Finset.disjoint_left]; omega - rw [h3, Finset.sum_union h4, Finset.sum_singleton] - -lemma rat_power_sum_eq_filter_ne_zero (k p : ℕ) (hk : k > 0) : - (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by - conv_lhs => - arg 2; ext v - rw [show (v : ℚ) ^ (2 * k) = if v ≠ 0 then (v : ℚ) ^ (2 * k) else 0 by - split_ifs with h - · rfl - · simp [show v = 0 by omega, show 2 * k ≠ 0 from by omega]] - rw [Finset.sum_filter] - -lemma remainder_div_p (k p : ℕ) (hp : p.Prime) : - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / - (2 * k + 1)) / p = - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / - (2 * k + 1)) := by +lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Prime) : + ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = + T - (∑ i ∈ Finset.range (2 * k), + bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by + have hDiv : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T := by + have h_cast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0)) : ZMod p) = 0 := by + push_cast; exact power_sum_add_indicator_eq_zero p (2 * k) hp + rw [ZMod.intCast_zmod_eq_zero_iff_dvd] at h_cast; exact h_cast + obtain ⟨T, hT⟩ := hDiv + use T + have hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + + vonStaudtIndicator (2 * k) p = p * T := by + have h1 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) = + ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by norm_cast + have h2 : ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = + vonStaudtIndicator (2 * k) p := by + split_ifs at * <;> simp_all [vonStaudtIndicator] + have h4 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + + ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = (p : ℚ) * T := by + norm_cast at hT ⊢ + calc (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = + ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + + ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) := by rw [h1, h2] + _ = (p : ℚ) * T := by rw [h4] + _ = p * T := by simp + have hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = + (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by + have hfilter : (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = + ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by + conv_lhs => + arg 2; ext v + rw [show (v : ℚ) ^ (2 * k) = if v ≠ 0 then (v : ℚ) ^ (2 * k) else 0 by + split_ifs with h + · rfl + · simp [show v = 0 by omega, show 2 * k ≠ 0 from by omega]] + rw [Finset.sum_filter] + rw [← hfilter] + simp only [sum_range_pow]; push_cast + have hsplit : Finset.range (2 * k + 1) = Finset.range (2 * k) ∪ {2 * k} := by + ext x; simp [Finset.mem_range]; omega + have hdisjoint : Disjoint (Finset.range (2 * k)) ({2 * k} : Finset ℕ) := by + simp [Finset.disjoint_left]; omega + rw [hsplit, Finset.sum_union hdisjoint, Finset.sum_singleton] + congr 1 + have h1 : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by + rw [← Nat.choose_symm_of_eq_add (by omega : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] + rw [h1, show (2 * k + 1 - 2 * k : ℕ) = 1 from by omega, pow_one] + have h4 : (2 * k + 1 : ℚ) ≠ 0 := by positivity + norm_cast; field_simp [h4] + have hAlg : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = + T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by + have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast hp.ne_zero + field_simp [hp_ne]; linarith + rw [hAlg]; congr 1 have h0 : (∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = ∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * @@ -957,54 +844,6 @@ lemma remainder_div_p (k p : ℕ) (hp : p.Prime) : exact Finset.sum_congr rfl fun i hi => h1 i hi exact_mod_cast h0 -lemma algebraic_rearrangement (k p : ℕ) (T : ℤ) (hp : p.Prime) - (hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = - (p : ℚ) * (T : ℚ)) - (hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = - (∑ i ∈ Finset.range (2 * k), bernoulli i * - ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k)) : - bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), - bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by - have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast hp.ne_zero - field_simp [hp_ne] - linarith - -lemma divisibility_to_rat_eq (k p : ℕ) (T : ℤ) - (hT : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + - (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T) : - (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + - vonStaudtIndicator (2 * k) p = p * T := by - have h1 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) = - ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by norm_cast - have h2 : ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = - vonStaudtIndicator (2 * k) p := by - split_ifs at * <;> simp_all [vonStaudtIndicator] - have h4 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + - ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = (p : ℚ) * T := by - norm_cast at hT ⊢ - calc (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = - ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + - ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) := by rw [h1, h2] - _ = (p : ℚ) * T := by rw [h4] - _ = p * T := by simp - -lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Prime) : - ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = - T - (∑ i ∈ Finset.range (2 * k), - bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by - obtain ⟨T, hT⟩ := power_sum_indicator_divisible_by_p k p hp - use T - have hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = - p * T := divisibility_to_rat_eq k p T hT - have hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by - rw [← rat_power_sum_eq_filter_ne_zero k p hk] - simp only [sum_range_pow]; push_cast - rw [faulhaber_split_top_term, faulhaber_top_term] - have hAlg := algebraic_rearrangement k p T hp hT' hFaul - rw [hAlg, remainder_div_p k p hp] - lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den.Coprime p := by induction k using Nat.strong_induction_on with @@ -1019,21 +858,13 @@ lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) (hp : p.Pr exact ih m hm_lt hm_pos exact pIntegral_sub p T _ hT_int hR -lemma sum_other_primes_coprime_p_pos (k p : ℕ) (hp : p.Prime) : - (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, - (1 : ℚ) / q).den.Coprime p := by - apply Nat.Coprime.of_dvd_left - · exact sum_den_dvd_prod_den _ _ - · exact prod_den_coprime_p k p hp - lemma von_staudt_coprime_all_primes_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den.Coprime p := by - rw [sum_primes_eq_indicator_add_rest k p hk hp] - rw [← add_assoc] + rw [sum_primes_eq_indicator_add_rest k p hk hp, ← add_assoc] exact Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) ((bernoulli_plus_indicator_coprime_p_pos k p hk hp).mul_left - (sum_other_primes_coprime_p_pos k p hp)) + (Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) (prod_den_coprime_p k p hp))) /-- **von Staudt-Clausen theorem:** For any natural number $k$, the sum $$B_{2k} + \sum_{p - 1 \mid 2k} \frac{1}{p}$$ is an integer. From 4c210e96190c9b3684cfb1a22639f58c75655387 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 7 Feb 2026 22:04:31 -0800 Subject: [PATCH 26/70] small styling --- Mathlib/NumberTheory/Bernoulli.lean | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 381c7df84bb548..c87a6a412b089d 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -418,8 +418,7 @@ lemma generator_orderOf_eq (p : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) have h3 : Fintype.card (ZMod p)ˣ = p - 1 := ZMod.card_units p aesop -lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] - (hndvd : ¬(p - 1) ∣ l) : +lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hndvd : ¬(p - 1) ∣ l) : (∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l) = 0 := by haveI : IsCyclic (ZMod p)ˣ := ZMod.isCyclic_units_prime hp.out obtain ⟨g, hg⟩ := IsCyclic.exists_generator (α := (ZMod p)ˣ) @@ -631,8 +630,8 @@ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 exact h2 d hd lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : - B * (p : ℚ) ^ (2*d) = (B + I / p) * (p : ℚ) ^ (2*d) - I * (p : ℚ) ^ (2*d - 1) := by - have hpow : (p : ℚ) ^ (2*d) = (p : ℚ) ^ (2*d - 1) * p := by + B * (p : ℚ) ^ (2 * d) = (B + I / p) * (p : ℚ) ^ (2 * d) - I * (p : ℚ) ^ (2 * d - 1) := by + have hpow : (p : ℚ) ^ (2 * d) = (p : ℚ) ^ (2 * d - 1) * p := by conv_lhs => rw [show 2 * d = (2 * d - 1) + 1 from by omega, pow_succ] rcases eq_or_ne (p : ℚ) 0 with hp | hp · simp [hp, zero_pow (show 2 * d - 1 ≠ 0 from by omega)] From 3e07cbd16a6b9e11768122ef8a2e14e229259ebf Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 7 Feb 2026 22:14:44 -0800 Subject: [PATCH 27/70] refactor(NumberTheory/Bernoulli): use FiniteField.sum_pow_units for power sums Replace 4 hand-rolled lemmas (power_sum_eq_neg_one_mod_of_dvd, generator_orderOf_eq, sum_units_pow_eq_zero_of_not_dvd, cast_ne_zero_of_mem_filter) with a single application of FiniteField.sum_pow_units in power_sum_add_indicator_eq_zero. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 85 +++++++---------------------- 1 file changed, 20 insertions(+), 65 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index c87a6a412b089d..0824d79d681ada 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -9,6 +9,7 @@ public import Mathlib.Algebra.BigOperators.Field public import Mathlib.Algebra.Field.GeomSum public import Mathlib.Data.Nat.Choose.Bounds public import Mathlib.RingTheory.PowerSeries.Exp +public import Mathlib.FieldTheory.Finite.Basic public import Mathlib.RingTheory.ZMod.UnitsCyclic /-! @@ -393,74 +394,28 @@ section vonStaudtClausen noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1 : ℕ) ∣ k then 1 else 0 -lemma cast_ne_zero_of_mem_filter (p : ℕ) (v : ℕ) - (hv : v ∈ (Finset.range p).filter (· ≠ 0)) : (v : ZMod p) ≠ 0 := by - simp only [Finset.mem_filter, Finset.mem_range] at hv - intro h - have h1 : (p : ℕ) ∣ v := by simpa [ZMod.natCast_eq_zero_iff] using h - exact absurd (Nat.le_of_dvd (by omega) h1) (by omega) - -lemma power_sum_eq_neg_one_mod_of_dvd (p l : ℕ) (hp : p.Prime) (hdvd : (p - 1) ∣ l) : - (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = -1 := by - haveI : Fact p.Prime := ⟨hp⟩ - have h1 : ∀ v ∈ (Finset.range p).filter (· ≠ 0), (v : ZMod p) ^ l = 1 := by - intro v hv; obtain ⟨k, hk⟩ := hdvd - simp only [hk, pow_mul, ZMod.pow_card_sub_one_eq_one (cast_ne_zero_of_mem_filter p v hv), - one_pow] - rw [Finset.sum_congr rfl h1, Finset.sum_const, Finset.filter_ne', - Finset.card_erase_of_mem (Finset.mem_range.mpr hp.pos), Finset.card_range, - nsmul_eq_mul, mul_one] - simp [Nat.cast_sub hp.pos] - -lemma generator_orderOf_eq (p : ℕ) [hp : Fact p.Prime] (g : (ZMod p)ˣ) - (_hg : ∀ x : (ZMod p)ˣ, x ∈ Subgroup.zpowers g) : orderOf g = p - 1 := by - have h1 : Fintype.card (Subgroup.zpowers g) = orderOf g := Fintype.card_zpowers - have h3 : Fintype.card (ZMod p)ˣ = p - 1 := ZMod.card_units p - aesop - -lemma sum_units_pow_eq_zero_of_not_dvd (p l : ℕ) [hp : Fact p.Prime] (hndvd : ¬(p - 1) ∣ l) : - (∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l) = 0 := by - haveI : IsCyclic (ZMod p)ˣ := ZMod.isCyclic_units_prime hp.out - obtain ⟨g, hg⟩ := IsCyclic.exists_generator (α := (ZMod p)ˣ) - -- Rewrite sum over units as geometric sum using generator - have hord : orderOf g = p - 1 := generator_orderOf_eq p g hg - have himg := IsCyclic.image_range_orderOf hg - rw [hord] at himg; conv_lhs => rw [← himg] - rw [Finset.sum_image (fun i (hi : i ∈ _) j hj heq => by - simp only [Finset.coe_range, Set.mem_Iio] at hi hj - rw [IsOfFinOrder.pow_eq_pow_iff_modEq (isOfFinOrder_of_finite g), hord] at heq - exact Nat.ModEq.eq_of_lt_of_lt heq hi hj)] - simp_rw [show ∀ i, (↑(g ^ i) : ZMod p) ^ l = ((g : ZMod p) ^ l) ^ i from - fun i => by simp [← pow_mul, mul_comm]] - -- Apply geometric sum formula - have hx1 : (g : ZMod p) ^ l ≠ 1 := by - intro h; exact hndvd (hord ▸ orderOf_dvd_of_pow_eq_one (Units.ext (by simpa using h))) - have hxp := ZMod.pow_card_sub_one_eq_one (pow_ne_zero l (Units.ne_zero g)) - have := geom_sum_eq hx1 (p - 1) - aesop - lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + (if (p - 1 : ℕ) ∣ l then (1 : ZMod p) else 0) = 0 := by - by_cases h : (p - 1) ∣ l - · simp only [h, ↓reduceIte] - rw [power_sum_eq_neg_one_mod_of_dvd p l hp h] - ring - · simp only [h, ↓reduceIte, add_zero] - haveI : Fact p.Prime := ⟨hp⟩ - have : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = - ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := - Finset.sum_bij' - (fun v hv => Units.mk0 (v : ZMod p) (cast_ne_zero_of_mem_filter p v hv)) - (fun u _ => (u : ZMod p).val) - (fun _ _ => Finset.mem_univ _) - (fun u _ => by simp [Finset.mem_filter, ZMod.val_lt, ZMod.val_eq_zero, u.ne_zero]) - (fun v hv => by - simp [ZMod.val_cast_of_lt (Finset.mem_range.mp (Finset.mem_filter.mp hv).1)]) - (fun u _ => Units.ext (ZMod.natCast_zmod_val _)) - (fun _ _ => rfl) - rw [this] - exact sum_units_pow_eq_zero_of_not_dvd p l h + haveI : Fact p.Prime := ⟨hp⟩ + have cast_ne : ∀ v, v ∈ (Finset.range p).filter (· ≠ 0) → (v : ZMod p) ≠ 0 := by + intro v hv h + simp only [Finset.mem_filter, Finset.mem_range] at hv + have h1 : (p : ℕ) ∣ v := by simpa [ZMod.natCast_eq_zero_iff] using h + exact absurd (Nat.le_of_dvd (by omega) h1) (by omega) + have hbij : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = + ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := + Finset.sum_bij' + (fun v hv => Units.mk0 (v : ZMod p) (cast_ne v hv)) + (fun u _ => (u : ZMod p).val) + (fun _ _ => Finset.mem_univ _) + (fun u _ => by simp [Finset.mem_filter, ZMod.val_lt, ZMod.val_eq_zero, u.ne_zero]) + (fun v hv => by + simp [ZMod.val_cast_of_lt (Finset.mem_range.mp (Finset.mem_filter.mp hv).1)]) + (fun u _ => Units.ext (ZMod.natCast_zmod_val _)) + (fun _ _ => rfl) + rw [hbij, FiniteField.sum_pow_units, ZMod.card] + split_ifs <;> ring lemma is_integer_of_coprime_all_primes (q : ℚ) (h : ∀ p : ℕ, p.Prime → q.den.Coprime p) : q ∈ Set.range Int.cast := by From 3a620bc284d2c72a6c561fd90d6b499b0c9e2be5 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 14 Feb 2026 12:13:12 -0800 Subject: [PATCH 28/70] refactor: inline core_algebraic_identity in Bernoulli proof --- Mathlib/NumberTheory/Bernoulli.lean | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 0824d79d681ada..3958b464321c29 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -584,14 +584,6 @@ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 conv_rhs => rw [show m = m - 1 + 1 from by omega]; exact pow_succ .. exact h2 d hd -lemma core_algebraic_identity (B I : ℚ) (p d : ℕ) (hd : d ≥ 1) : - B * (p : ℚ) ^ (2 * d) = (B + I / p) * (p : ℚ) ^ (2 * d) - I * (p : ℚ) ^ (2 * d - 1) := by - have hpow : (p : ℚ) ^ (2 * d) = (p : ℚ) ^ (2 * d - 1) * p := by - conv_lhs => rw [show 2 * d = (2 * d - 1) + 1 from by omega, pow_succ] - rcases eq_or_ne (p : ℚ) 0 with hp | hp - · simp [hp, zero_pow (show 2 * d - 1 ≠ 0 from by omega)] - · rw [hpow]; field_simp [hp]; ring - lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by obtain hp2 | hp3 := hp.eq_two_or_odd @@ -659,8 +651,14 @@ lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1) := by simp only [show 2 * k - 2 * m = 2 * (k - m) from by omega] - have h := core_algebraic_identity (bernoulli (2 * m)) - (vonStaudtIndicator (2 * m) p) p (k - m) (by omega) + have h : bernoulli (2 * m) * (p : ℚ) ^ (2 * (k - m)) = + (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * (p : ℚ) ^ (2 * (k - m)) - + vonStaudtIndicator (2 * m) p * (p : ℚ) ^ (2 * (k - m) - 1) := by + have hpow : (p : ℚ) ^ (2 * (k - m)) = (p : ℚ) ^ (2 * (k - m) - 1) * p := by + conv_lhs => rw [show 2 * (k - m) = (2 * (k - m) - 1) + 1 from by omega, pow_succ] + rcases eq_or_ne (p : ℚ) 0 with hp0 | hp0 + · simp [hp0, zero_pow (show 2 * (k - m) - 1 ≠ 0 from by omega)] + · rw [hpow]; field_simp [hp0]; ring set C := ((2 * k + 1).choose (2 * m) : ℚ) set N := (2 * k + 1 : ℚ) calc bernoulli (2 * m) * C * (p : ℚ) ^ (2 * (k - m)) / N From 114ff9fe0dff2f8b30239a838da6d39a21adcb72 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 14 Feb 2026 13:22:58 -0800 Subject: [PATCH 29/70] docs: add Rado-proof docstrings in Bernoulli --- Mathlib/NumberTheory/Bernoulli.lean | 42 ++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 3958b464321c29..7e858ac618558b 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -49,10 +49,20 @@ This formula is true for all $n$ and in particular $B_0=1$. Note that this is th for positive Bernoulli numbers, which we call `bernoulli'`. The negative Bernoulli numbers are then defined as `bernoulli := (-1)^n * bernoulli'`. +The proof of von Staudt-Clausen's theorem follows Rado's JLMS 1934 paper +"A New Proof of a Theorem of v. Staudt" + ## Main theorems -`sum_bernoulli : ∑ k ∈ Finset.range n, (n.choose k : ℚ) * bernoulli k = +* `sum_bernoulli : ∑ k ∈ Finset.range n, (n.choose k : ℚ) * bernoulli k = if n = 1 then 1 else 0` +* `von_staudt_clausen : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) + with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast ` + +## References + +* https://en.wikipedia.org/wiki/Bernoulli_number +* [R. Rado, *A New Proof of a Theorem of v. Staudt*][Rado1934] -/ @@ -390,10 +400,17 @@ end Faulhaber section vonStaudtClausen +/-! +Here we formalize Rado's proof of von Staudt-Clausen's theorem, which states that for any $k \ge 0$, +$$B_{2k} + \sum_{p \text{ prime}, (p - 1) \mid 2k} \frac{1}{p} \in \mathbb{Z}.$$ +Rado's proof is based on Faulhaber's theorem and induction on $k$. +-/ + /-- Indicator function that is `1` if `(p - 1) ∣ k` and `0` otherwise. -/ noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1 : ℕ) ∣ k then 1 else 0 +/-- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + (if (p - 1 : ℕ) ∣ l then (1 : ZMod p) else 0) = 0 := by @@ -417,6 +434,7 @@ lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : rw [hbij, FiniteField.sum_pow_units, ZMod.card] split_ifs <;> ring +/-- If a rational number is $p$-integral for all primes $p$, then it is an integer. -/ lemma is_integer_of_coprime_all_primes (q : ℚ) (h : ∀ p : ℕ, p.Prime → q.den.Coprime p) : q ∈ Set.range Int.cast := by have h1 : q.den = 1 := by @@ -465,6 +483,8 @@ lemma pIntegral_sub (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p pIntegral p (x - y) := Nat.Coprime.coprime_dvd_left (Rat.sub_den_dvd x y) (Nat.Coprime.mul_left hx hy) +/-- Denominators of the "other primes" part of the indicator sum +stay coprime to a fixed prime `p`. -/ lemma prod_den_coprime_p (k p : ℕ) (hp : p.Prime) : (∏ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, ((1 : ℚ) / q).den).Coprime p := by @@ -475,6 +495,8 @@ lemma prod_den_coprime_p (k p : ℕ) (hp : p.Prime) : rw [h2] exact (Nat.coprime_primes h1 hp).mpr (Finset.mem_filter.mp hq).2.2.2 +/-- Splits the prime-indexed correction sum into the `p`-term (`vonStaudtIndicator / p`) +plus the rest. -/ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with @@ -495,6 +517,7 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : ⟨fun ⟨hpr, hd⟩ => ⟨hpr, hd, fun h => hdvd (h ▸ hd)⟩, fun ⟨hpr, hd, _⟩ => ⟨hpr, hd⟩⟩) fun _ _ => rfl +/-- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ)^N / M) := by set e := M.factorization p @@ -518,12 +541,14 @@ lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _) exact hM'_cop.coprime_dvd_left hdvd +/-- Basic valuation bound used for the `i = 0` term in the Faulhaber expansion. -/ lemma valuation_bound (p n : ℕ) (hp : p.Prime) : (n + 1).factorization p ≤ n := Nat.factorization_le_of_le_pow <| calc n + 1 = (n + 1).choose 1 := by simp _ ≤ 2 ^ n := Nat.choose_succ_le_two_pow n 1 _ ≤ p ^ n := Nat.pow_le_pow_left hp.two_le n +/-- The `i = 0` Faulhaber term is `p`-integral. -/ lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : pIntegral p ((p : ℚ) ^ (2 * k) / (2 * k + 1)) := by have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by push_cast; ring @@ -532,6 +557,7 @@ lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : · omega · exact valuation_bound p (2 * k) hp +/-- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by obtain rfl | hp2 := eq_or_ne p 2 @@ -553,9 +579,11 @@ lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _) exact Nat.Coprime.of_dvd_left hdvd (Odd.coprime_two_left (hp.odd_of_ne_two hp2)) +/-- The exceptional base case of the inequality argument (`p = 2`, `d = 2`). -/ lemma valuation_bound_d_plus_1_p2_d2 : (2 + 1).factorization 2 ≤ 2 - 1 := by simp [Nat.factorization_eq_zero_of_not_dvd (show ¬(2 ∣ 3) by decide)] +/-- Auxiliary growth inequality: for `d ≥ 3`, we have `d + 1 ≤ 2^(d - 1)`. -/ lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) := by have h : ∀ n : ℕ, n ≥ 3 → n + 1 ≤ 2 ^ (n - 1) := by intro n hn @@ -569,6 +597,7 @@ lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - _ = 2 ^ m := by conv_rhs => rw [show m = m - 1 + 1 from by omega]; exact pow_succ .. exact h d hd +/-- Auxiliary growth inequality: for `p ≥ 3` and `d ≥ 2`, we have `d + 1 ≤ p^(d - 1)`. -/ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 ≤ p ^ (d - 1) := by have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by intro d hd @@ -584,6 +613,7 @@ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 conv_rhs => rw [show m = m - 1 + 1 from by omega]; exact pow_succ .. exact h2 d hd +/-- Main valuation estimate behind the contradiction step for even-index summands. -/ lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by obtain hp2 | hp3 := hp.eq_two_or_odd @@ -599,6 +629,7 @@ lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : omega · exact hd +/-- Rewrites the binomial coefficient denominator exactly as in Rado's summand. -/ lemma choose_div_core (k m : ℕ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by @@ -615,6 +646,7 @@ lemma choose_div_core (k m : ℕ) (hm_lt : m < k) : rw [div_eq_div_iff hk_pos hd_pos] exact_mod_cast (Nat.choose_mul_succ_eq (2 * k) (2 * m)).symm +/-- Multiplicative form of `choose_div_core`, used to move factors around in the even case. -/ lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) * x / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) * x / (2 * k - 2 * m + 1) := by @@ -622,6 +654,7 @@ lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] +/-- `p`-integrality of the core even-index summand after denominator normalization. -/ lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * k - 2 * m ≥ 2) : pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by @@ -639,6 +672,8 @@ lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * rw [h_eq] exact pIntegral_int_mul p _ _ h_pow_integral +/-- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` +to prove `p`-integrality of the even term. -/ lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * @@ -696,6 +731,7 @@ lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) rw [Rat.den_zero] exact Nat.coprime_one_left_iff p |>.mpr trivial +/-- The full remainder sum in Faulhaber's formula is `p`-integral. -/ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ Finset.range (2 * k), @@ -721,6 +757,8 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) simp only [Rat.den_zero] exact Nat.coprime_one_left_iff p |>.mpr trivial +/-- Rearranges the Faulhaber identity and power-sum congruence to isolate +`bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Prime) : ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), @@ -796,6 +834,7 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Pr exact Finset.sum_congr rfl fun i hi => h1 i hi exact_mod_cast h0 +/-- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is coprime to `p`. -/ lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den.Coprime p := by induction k using Nat.strong_induction_on with @@ -810,6 +849,7 @@ lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) (hp : p.Pr exact ih m hm_lt hm_pos exact pIntegral_sub p T _ hT_int hR +/-- Extends the fixed-prime coprimality result to the full prime correction sum. -/ lemma von_staudt_coprime_all_primes_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) : (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den.Coprime p := by From d5377ba795882f008a245e086fa1ec9f502333ca Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 14 Feb 2026 13:27:00 -0800 Subject: [PATCH 30/70] add reference and author --- Mathlib/NumberTheory/Bernoulli.lean | 2 +- docs/references.bib | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 7e858ac618558b..2f4a61cac2eb67 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2020 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Johan Commelin, Kevin Buzzard +Authors: Johan Commelin, Kevin Buzzard, Seewoo Lee -/ module diff --git a/docs/references.bib b/docs/references.bib index 1d4d86147edff1..07a7c78f2172a8 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -4365,6 +4365,17 @@ @Book{ Quillen1967 mrnumber = {223432} } +@article{ Rado1934, + title = {A new proof of a theorem of V. Staudt}, + author = {Rado, R}, + journal = {Journal of the London Mathematical Society}, + volume = {1}, + number = {2}, + pages = {85--88}, + year = {1934}, + publisher = {Oxford University Press} +} + @InCollection{ ribenboim1971, author = {Ribenboim, Paulo}, title = {\'{E}pimorphismes de modules qui sont n\'{e}cessairement From f21dbe6ee82562e7b9713cb6336a9739b413d16e Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 14 Feb 2026 13:30:35 -0800 Subject: [PATCH 31/70] refactor: golf pIntegral and range-sum steps in Bernoulli --- Mathlib/NumberTheory/Bernoulli.lean | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 2f4a61cac2eb67..f386133475293d 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -453,6 +453,8 @@ lemma is_integer_of_coprime_all_primes (q : ℚ) (h : ∀ p : ℕ, p.Prime → q /-- A rational number `x` is `p`-integral if `p` does not divide its denominator. -/ def pIntegral (p : ℕ) (x : ℚ) : Prop := x.den.Coprime p +@[simp] lemma pIntegral_zero (p : ℕ) : pIntegral p (0 : ℚ) := by simp [pIntegral] + lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by classical @@ -727,9 +729,7 @@ lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) · simp only [one_mul] rw [choose_div_simplify k m _ hm_lt] exact pIntegral_case_one k m p hm_lt hp (by omega) - · simp only [zero_mul, zero_div]; unfold pIntegral - rw [Rat.den_zero] - exact Nat.coprime_one_left_iff p |>.mpr trivial + · simp /-- The full remainder sum in Faulhaber's formula is `p`-integral. -/ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) @@ -751,11 +751,7 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) · have ⟨_, hm_lt, hj_eq⟩ : m ≥ 1 ∧ m < k ∧ j = 2 * m := by omega simp only [hj_eq] exact pIntegral_even_term_in_sum k m p hm_lt hp (ih m (by omega) hm_lt) - · simp only [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; omega), - zero_mul, zero_div] - unfold pIntegral - simp only [Rat.den_zero] - exact Nat.coprime_one_left_iff p |>.mpr trivial + · simp [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; omega)] /-- Rearranges the Faulhaber identity and power-sum congruence to isolate `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ @@ -800,11 +796,7 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Pr rw [Finset.sum_filter] rw [← hfilter] simp only [sum_range_pow]; push_cast - have hsplit : Finset.range (2 * k + 1) = Finset.range (2 * k) ∪ {2 * k} := by - ext x; simp [Finset.mem_range]; omega - have hdisjoint : Disjoint (Finset.range (2 * k)) ({2 * k} : Finset ℕ) := by - simp [Finset.disjoint_left]; omega - rw [hsplit, Finset.sum_union hdisjoint, Finset.sum_singleton] + rw [Finset.sum_range_succ] congr 1 have h1 : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by rw [← Nat.choose_symm_of_eq_add (by omega : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] From 49d28867c04882063fd7deb7d053af254c736b60 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 14 Feb 2026 13:32:03 -0800 Subject: [PATCH 32/70] refactor: simplify cast transport in bernoulli rearrangement --- Mathlib/NumberTheory/Bernoulli.lean | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index f386133475293d..9faa0771f89117 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -769,18 +769,20 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Pr use T have hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = p * T := by - have h1 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) = + have hsum : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) = ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by norm_cast - have h2 : ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = + have hind : ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = vonStaudtIndicator (2 * k) p := by - split_ifs at * <;> simp_all [vonStaudtIndicator] - have h4 : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + + by_cases hd : (p - 1 : ℕ) ∣ (2 * k) <;> simp [vonStaudtIndicator, hd] + have hTq : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = (p : ℚ) * T := by norm_cast at hT ⊢ - calc (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = - ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + - ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) := by rw [h1, h2] - _ = (p : ℚ) * T := by rw [h4] + calc + (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = + ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + + ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) := by + rw [← hsum, ← hind] + _ = (p : ℚ) * T := by exact hTq _ = p * T := by simp have hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * From f32268beaef86c645a235b601296c6bf1de8ff6e Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 14 Feb 2026 13:42:26 -0800 Subject: [PATCH 33/70] article -> Article --- docs/references.bib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/references.bib b/docs/references.bib index 6606bdf9666739..502985089123a0 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -4415,7 +4415,7 @@ @Book{ Quillen1967 mrnumber = {223432} } -@article{ Rado1934, +@Article{ Rado1934, title = {A new proof of a theorem of V. Staudt}, author = {Rado, R}, journal = {Journal of the London Mathematical Society}, From f5674aa193c3b34573432cb83ee4eaf70f20750c Mon Sep 17 00:00:00 2001 From: Seewoo Lee <49933279+seewoo5@users.noreply.github.com> Date: Sat, 21 Feb 2026 16:25:23 -0800 Subject: [PATCH 34/70] Update Mathlib/NumberTheory/Bernoulli.lean Co-authored-by: Kenny Lau --- Mathlib/NumberTheory/Bernoulli.lean | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 9faa0771f89117..6974c96df0d9f4 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -859,11 +859,7 @@ theorem von_staudt_clausen (k : ℕ) : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast := by rcases Nat.eq_zero_or_pos k with rfl | hk - · have h1 : bernoulli (2 * 0) = 1 := by norm_num [bernoulli_zero] - have h2 : ∑ p ∈ Finset.range (2 * 0 + 2) with - p.Prime ∧ (p - 1) ∣ 2 * 0, (1 : ℚ) / p = 0 := by norm_num; decide - rw [h1, h2] - exact ⟨1, by norm_num⟩ + · exact ⟨1, by decide +kernel⟩ · exact is_integer_of_coprime_all_primes _ (fun p hp => von_staudt_coprime_all_primes_pos k p hk hp) From 7f148f4c4f82cbeea5362df391826eb8a7c3edce Mon Sep 17 00:00:00 2001 From: Seewoo Lee <49933279+seewoo5@users.noreply.github.com> Date: Mon, 9 Mar 2026 16:52:21 -0700 Subject: [PATCH 35/70] Apply suggestions from code review Co-authored-by: Michael Stoll <99838730+MichaelStollBayreuth@users.noreply.github.com> --- Mathlib/NumberTheory/Bernoulli.lean | 41 ++++++++++++----------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index a174be8116f0b7..1ccbdf3e7ecf5e 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -404,6 +404,8 @@ end Faulhaber section vonStaudtClausen /-! +### The von Staudt-Clausen Theorem + Here we formalize Rado's proof of von Staudt-Clausen's theorem, which states that for any $k \ge 0$, $$B_{2k} + \sum_{p \text{ prime}, (p - 1) \mid 2k} \frac{1}{p} \in \mathbb{Z}.$$ Rado's proof is based on Faulhaber's theorem and induction on $k$. @@ -421,21 +423,21 @@ lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : have cast_ne : ∀ v, v ∈ (Finset.range p).filter (· ≠ 0) → (v : ZMod p) ≠ 0 := by intro v hv h simp only [Finset.mem_filter, Finset.mem_range] at hv - have h1 : (p : ℕ) ∣ v := by simpa [ZMod.natCast_eq_zero_iff] using h - exact absurd (Nat.le_of_dvd (by omega) h1) (by omega) + have h1 : p ∣ v := (ZMod.natCast_eq_zero_iff v p).mp h + exact absurd (Nat.le_of_dvd (by lia) h1) (by lia) have hbij : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := Finset.sum_bij' (fun v hv => Units.mk0 (v : ZMod p) (cast_ne v hv)) (fun u _ => (u : ZMod p).val) (fun _ _ => Finset.mem_univ _) - (fun u _ => by simp [Finset.mem_filter, ZMod.val_lt, ZMod.val_eq_zero, u.ne_zero]) + (fun u _ => by simp [ZMod.val_lt, u.ne_zero]) (fun v hv => by simp [ZMod.val_cast_of_lt (Finset.mem_range.mp (Finset.mem_filter.mp hv).1)]) (fun u _ => Units.ext (ZMod.natCast_zmod_val _)) (fun _ _ => rfl) rw [hbij, FiniteField.sum_pow_units, ZMod.card] - split_ifs <;> ring + grind /-- If a rational number is $p$-integral for all primes $p$, then it is an integer. -/ lemma is_integer_of_coprime_all_primes (q : ℚ) (h : ∀ p : ℕ, p.Prime → q.den.Coprime p) : @@ -515,7 +517,7 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : simp only [vonStaudtIndicator, if_pos hdvd] congr 1 apply Finset.sum_congr _ (fun _ _ => rfl) - ext q; simp only [Finset.mem_erase, Finset.mem_filter, Finset.mem_range]; tauto + grind · -- p is not in the filtered set; indicator is 0, filter sets are equal simp only [vonStaudtIndicator, if_neg hdvd, zero_div, zero_add] exact Finset.sum_congr (Finset.filter_congr fun q _ => @@ -556,7 +558,7 @@ lemma valuation_bound (p n : ℕ) (hp : p.Prime) : (n + 1).factorization p ≤ n /-- The `i = 0` Faulhaber term is `p`-integral. -/ lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : pIntegral p ((p : ℚ) ^ (2 * k) / (2 * k + 1)) := by - have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by push_cast; ring + have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by norm_cast rw [h] apply pIntegral_pow_div p (2 * k + 1) (2 * k) hp · omega @@ -566,18 +568,16 @@ lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by obtain rfl | hp2 := eq_or_ne p 2 - · rw [show bernoulli 1 = -1 / 2 from by norm_num [bernoulli_one]] + · rw [bernoulli_one] have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = (-(2 : ℤ) ^ (2 * k - 2) : ℤ) := by - have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by - rw [show 2 * k - 1 = (2 * k - 2) + 1 from by omega, pow_succ] - rw [hpow]; push_cast; field_simp [show (2 * k : ℚ) ≠ 0 from by positivity] + have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by rw [← pow_succ]; lia + rw [hpow]; push_cast; field_simp simp only [Nat.cast_ofNat, h]; norm_num [pIntegral] · rw [show bernoulli 1 = (-1 : ℚ) / 2 from by norm_num [bernoulli]] have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega field_simp [h2] - rw [show -(↑↑p ^ (2 * k - 1) / (2 : ℚ)) = -↑↑p ^ (2 * k - 1) / 2 from by ring] - unfold pIntegral + rw [neg_div', pIntegral] have hdvd : (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by rw [neg_div, Rat.den_neg_eq_den, ← Nat.cast_pow] conv_lhs => rw [show (2 : ℚ) = (2 : ℕ) from rfl, Rat.natCast_div_eq_divInt] @@ -638,18 +638,11 @@ lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : lemma choose_div_core (k m : ℕ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by - have h_denom : (2 * (k : ℚ) - 2 * m + 1) = ((2 * k - 2 * m + 1 : ℕ) : ℚ) := by - simp only [Nat.cast_sub (by omega : 2 * m ≤ 2 * k), Nat.cast_add, Nat.cast_mul, - Nat.cast_ofNat, Nat.cast_one] - conv_rhs => rw [h_denom] - have h_nat : 2 * k + 1 - 2 * m = 2 * k - 2 * m + 1 := by grind - simp only [h_nat.symm] - have h_lhs_denom : (2 * (k : ℚ) + 1) = ((2 * k + 1 : ℕ) : ℚ) := by push_cast; ring - conv_lhs => rw [h_lhs_denom] - have hk_pos : ((2 * k + 1 : ℕ) : ℚ) ≠ 0 := by positivity - have hd_pos : ((2 * k + 1 - 2 * m : ℕ) : ℚ) ≠ 0 := by simp only [Nat.cast_ne_zero]; omega - rw [div_eq_div_iff hk_pos hd_pos] - exact_mod_cast (Nat.choose_mul_succ_eq (2 * k) (2 * m)).symm + rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia)] + conv_rhs => norm_cast; rw [Nat.choose_mul_succ_eq] + rw [show 2 * (k : ℚ) - 2 * (m : ℚ) = 2 * (k - m : ℕ) by rw [cast_sub hm_lt.le]; ring] + norm_cast + grind /-- Multiplicative form of `choose_div_core`, used to move factors around in the even case. -/ lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : From 0e36861a56e57d6201b0e026935222d5a54dfcf7 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Mon, 9 Mar 2026 16:57:26 -0700 Subject: [PATCH 36/70] change function notations --- Mathlib/NumberTheory/Bernoulli.lean | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 1ccbdf3e7ecf5e..aed9570ed5dbd1 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -428,14 +428,14 @@ lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : have hbij : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := Finset.sum_bij' - (fun v hv => Units.mk0 (v : ZMod p) (cast_ne v hv)) - (fun u _ => (u : ZMod p).val) - (fun _ _ => Finset.mem_univ _) - (fun u _ => by simp [ZMod.val_lt, u.ne_zero]) - (fun v hv => by + (fun v hv ↦ Units.mk0 (v : ZMod p) (cast_ne v hv)) + (fun u _ ↦ (u : ZMod p).val) + (fun _ _ ↦ Finset.mem_univ _) + (fun u _ ↦ by simp [ZMod.val_lt, u.ne_zero]) + (fun v hv ↦ by simp [ZMod.val_cast_of_lt (Finset.mem_range.mp (Finset.mem_filter.mp hv).1)]) - (fun u _ => Units.ext (ZMod.natCast_zmod_val _)) - (fun _ _ => rfl) + (fun u _ ↦ Units.ext (ZMod.natCast_zmod_val _)) + (fun _ _ ↦ rfl) rw [hbij, FiniteField.sum_pow_units, ZMod.card] grind @@ -472,7 +472,7 @@ lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : lemma pIntegral_sum {ι : Type*} (p : ℕ) (s : Finset ι) (f : ι → ℚ) (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := Nat.Coprime.coprime_dvd_left (sum_den_dvd_prod_den s f) - (Nat.Coprime.prod_left fun i hi => hf i hi) + (Nat.Coprime.prod_left fun i hi ↦ hf i hi) lemma pIntegral_of_int (p : ℕ) (z : ℤ) : pIntegral p z := by simp_all [pIntegral] @@ -510,19 +510,19 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by by_cases hdvd : (p - 1 : ℕ) ∣ 2 * k · -- p is in the filtered set; extract its term - have hp_mem : p ∈ (Finset.range (2 * k + 2)).filter (fun q => q.Prime ∧ (q - 1) ∣ 2 * k) := by + have hp_mem : p ∈ (Finset.range (2 * k + 2)).filter (fun q ↦ q.Prime ∧ (q - 1) ∣ 2 * k) := by simp only [Finset.mem_filter, Finset.mem_range] exact ⟨by have := Nat.le_of_dvd (by omega) hdvd; omega, hp, hdvd⟩ rw [← Finset.add_sum_erase _ _ hp_mem] simp only [vonStaudtIndicator, if_pos hdvd] congr 1 - apply Finset.sum_congr _ (fun _ _ => rfl) + apply Finset.sum_congr _ (fun _ _ ↦ rfl) grind · -- p is not in the filtered set; indicator is 0, filter sets are equal simp only [vonStaudtIndicator, if_neg hdvd, zero_div, zero_add] - exact Finset.sum_congr (Finset.filter_congr fun q _ => - ⟨fun ⟨hpr, hd⟩ => ⟨hpr, hd, fun h => hdvd (h ▸ hd)⟩, - fun ⟨hpr, hd, _⟩ => ⟨hpr, hd⟩⟩) fun _ _ => rfl + exact Finset.sum_congr (Finset.filter_congr fun q _ ↦ + ⟨fun ⟨hpr, hd⟩ ↦ ⟨hpr, hd, fun h ↦ hdvd (h ▸ hd)⟩, + fun ⟨hpr, hd, _⟩ ↦ ⟨hpr, hd⟩⟩) fun _ _ ↦ rfl /-- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) @@ -629,7 +629,7 @@ lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : exact pow_two_ge_succ_of_ge_three _ hd3 · apply Nat.factorization_le_of_le_pow apply pow_ge_succ_of_ge_three - · have hne2 : p ≠ 2 := fun h => by simp [h] at hp3 + · have hne2 : p ≠ 2 := fun h ↦ by simp [h] at hp3 have h1lt : 1 < p := hp.one_lt omega · exact hd @@ -821,7 +821,7 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Pr rw [show (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 from by omega, pow_succ] field_simp [h5] rw [Finset.sum_div] - exact Finset.sum_congr rfl fun i hi => h1 i hi + exact Finset.sum_congr rfl fun i hi ↦ h1 i hi exact_mod_cast h0 /-- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is coprime to `p`. -/ @@ -857,6 +857,6 @@ theorem von_staudt_clausen (k : ℕ) : rcases Nat.eq_zero_or_pos k with rfl | hk · exact ⟨1, by decide +kernel⟩ · exact is_integer_of_coprime_all_primes _ - (fun p hp => von_staudt_coprime_all_primes_pos k p hk hp) + (fun p hp ↦ von_staudt_coprime_all_primes_pos k p hk hp) end vonStaudtClausen From b8d57febf08fb27c458e68a6cddee43512f24d73 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Mon, 9 Mar 2026 23:03:13 -0700 Subject: [PATCH 37/70] change definition of pIntegral using padicValuation --- Mathlib/NumberTheory/Bernoulli.lean | 225 ++++++++++++++++------------ 1 file changed, 130 insertions(+), 95 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index aed9570ed5dbd1..6a9e1fa21c6aa9 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -11,6 +11,7 @@ public import Mathlib.Data.Nat.Choose.Bounds public import Mathlib.RingTheory.PowerSeries.Exp public import Mathlib.FieldTheory.Finite.Basic public import Mathlib.RingTheory.ZMod.UnitsCyclic +public import Mathlib.NumberTheory.Padics.PadicNumbers /-! # Bernoulli numbers @@ -57,7 +58,7 @@ The proof of von Staudt-Clausen's theorem follows Rado's JLMS 1934 paper * `sum_bernoulli : ∑ k ∈ Finset.range n, (n.choose k : ℚ) * bernoulli k = if n = 1 then 1 else 0` * `von_staudt_clausen : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) - with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast ` + with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast` ## References @@ -412,14 +413,12 @@ Rado's proof is based on Faulhaber's theorem and induction on $k$. -/ /-- Indicator function that is `1` if `(p - 1) ∣ k` and `0` otherwise. -/ -noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := - if (p - 1 : ℕ) ∣ k then 1 else 0 +noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1 : ℕ) ∣ k then 1 else 0 /-- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ -lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : +lemma power_sum_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + (if (p - 1 : ℕ) ∣ l then (1 : ZMod p) else 0) = 0 := by - haveI : Fact p.Prime := ⟨hp⟩ have cast_ne : ∀ v, v ∈ (Finset.range p).filter (· ≠ 0) → (v : ZMod p) ≠ 0 := by intro v hv h simp only [Finset.mem_filter, Finset.mem_range] at hv @@ -440,25 +439,25 @@ lemma power_sum_add_indicator_eq_zero (p l : ℕ) (hp : p.Prime) : grind /-- If a rational number is $p$-integral for all primes $p$, then it is an integer. -/ -lemma is_integer_of_coprime_all_primes (q : ℚ) (h : ∀ p : ℕ, p.Prime → q.den.Coprime p) : +lemma Rat.mem_range_intCast_of_not_prime_dvd (q : ℚ) (h : ∀ p : ℕ, p.Prime → ¬ p ∣ q.den) : q ∈ Set.range Int.cast := by - have h1 : q.den = 1 := by - by_contra hne - obtain ⟨p, hp, hpdvd⟩ := Nat.exists_prime_and_dvd (by omega : q.den ≠ 1) - have hcop := h p hp - have : p ∣ Nat.gcd q.den p := Nat.dvd_gcd hpdvd (dvd_refl p) - rw [Nat.coprime_iff_gcd_eq_one.mp hcop] at this - have : p ≤ 1 := Nat.le_of_dvd (by norm_num) this - linarith [hp.two_le] - use q.num - have hq : (q.num : ℚ) / q.den = q := Rat.num_div_den q - rw [← hq, h1] - simp + rw [Set.mem_range] + refine ⟨q.num, Rat.coe_int_num_of_den_eq_one ?_⟩ + contrapose! h + exact ne_one_iff_exists_prime_dvd.mp h /-- A rational number `x` is `p`-integral if `p` does not divide its denominator. -/ -def pIntegral (p : ℕ) (x : ℚ) : Prop := x.den.Coprime p +def pIntegral (p : ℕ) (x : ℚ) [Fact p.Prime] : Prop := Rat.padicValuation p x ≤ 1 + +lemma pIntegral_iff_not_dvd_den (p : ℕ) (x : ℚ) [Fact p.Prime] : pIntegral p x ↔ ¬ p ∣ x.den := by + simp only [pIntegral, Rat.padicValuation_le_one_iff] + +lemma pIntegral_iff_padicValuation_le_one (p : ℕ) (x : ℚ) [Fact p.Prime] : + pIntegral p x ↔ Rat.padicValuation p x ≤ 1 := by rfl + -@[simp] lemma pIntegral_zero (p : ℕ) : pIntegral p (0 : ℚ) := by simp [pIntegral] +@[simp] lemma pIntegral_zero (p : ℕ) [Fact p.Prime] : pIntegral p (0 : ℚ) := + (pIntegral_iff_not_dvd_den p _).2 (by simpa using Nat.Prime.not_dvd_one Fact.out) lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by @@ -469,30 +468,52 @@ lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : rw [Finset.sum_insert has, Finset.prod_insert has] exact dvd_trans (Rat.add_den_dvd (f a) (∑ x ∈ s, f x)) (mul_dvd_mul_left _ ih) -lemma pIntegral_sum {ι : Type*} (p : ℕ) (s : Finset ι) (f : ι → ℚ) - (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := - Nat.Coprime.coprime_dvd_left (sum_den_dvd_prod_den s f) - (Nat.Coprime.prod_left fun i hi ↦ hf i hi) - -lemma pIntegral_of_int (p : ℕ) (z : ℤ) : pIntegral p z := by simp_all [pIntegral] - -lemma pIntegral_mul (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : - pIntegral p (x * y) := - Nat.Coprime.of_dvd_left (Rat.mul_den_dvd x y) (Nat.Coprime.mul_left hx hy) - -lemma pIntegral_int_mul (p : ℕ) (x : ℚ) (z : ℤ) (hx : pIntegral p x) : pIntegral p (z * x) := by - have _ := Rat.mul_den_dvd z x - have h1 : (z * x : ℚ).den ∣ x.den := by aesop - have h2 := Nat.Coprime.coprime_dvd_left h1 hx - aesop - -lemma pIntegral_sub (p : ℕ) (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : - pIntegral p (x - y) := - Nat.Coprime.coprime_dvd_left (Rat.sub_den_dvd x y) (Nat.Coprime.mul_left hx hy) +lemma pIntegral_sum {ι : Type*} (p : ℕ) [Fact p.Prime] (s : Finset ι) (f : ι → ℚ) + (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := by + have hcop : (∑ i ∈ s, f i).den.Coprime p := Nat.Coprime.coprime_dvd_left (sum_den_dvd_prod_den s f) + (Nat.Coprime.prod_left fun i hi ↦ by + have hfi_not : ¬ p ∣ (f i).den := (pIntegral_iff_not_dvd_den p (f i)).1 (hf i hi) + exact ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 hfi_not).symm) + exact (pIntegral_iff_not_dvd_den p _).2 + ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) + +lemma pIntegral_of_int (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := by + exact (pIntegral_iff_not_dvd_den p _).2 + (by simpa using (Nat.Prime.not_dvd_one (Fact.out : p.Prime))) + +lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : + pIntegral p (x * y) := by + have hxcop : x.den.Coprime p := by + have hxnot : ¬ p ∣ x.den := (pIntegral_iff_not_dvd_den p x).1 hx + exact ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 hxnot).symm + have hycop : y.den.Coprime p := by + have hynot : ¬ p ∣ y.den := (pIntegral_iff_not_dvd_den p y).1 hy + exact ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 hynot).symm + have hcop : (x * y).den.Coprime p := Nat.Coprime.of_dvd_left (Rat.mul_den_dvd x y) + (Nat.Coprime.mul_left hxcop hycop) + exact (pIntegral_iff_not_dvd_den p _).2 + ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) + +lemma pIntegral_int_mul (p : ℕ) [Fact p.Prime] (x : ℚ) (z : ℤ) (hx : pIntegral p x) : + pIntegral p (z * x) := by + simpa [mul_comm] using pIntegral_mul p (z : ℚ) x (pIntegral_of_int p z) hx + +lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : + pIntegral p (x - y) := by + have hxcop : x.den.Coprime p := by + have hxnot : ¬ p ∣ x.den := (pIntegral_iff_not_dvd_den p x).1 hx + exact ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 hxnot).symm + have hycop : y.den.Coprime p := by + have hynot : ¬ p ∣ y.den := (pIntegral_iff_not_dvd_den p y).1 hy + exact ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 hynot).symm + have hcop : (x - y).den.Coprime p := Nat.Coprime.coprime_dvd_left (Rat.sub_den_dvd x y) + (Nat.Coprime.mul_left hxcop hycop) + exact (pIntegral_iff_not_dvd_den p _).2 + ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) /-- Denominators of the "other primes" part of the indicator sum stay coprime to a fixed prime `p`. -/ -lemma prod_den_coprime_p (k p : ℕ) (hp : p.Prime) : +lemma prod_den_coprime_p (k p : ℕ) [Fact p.Prime] : (∏ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, ((1 : ℚ) / q).den).Coprime p := by apply Nat.Coprime.prod_left @@ -500,11 +521,11 @@ lemma prod_den_coprime_p (k p : ℕ) (hp : p.Prime) : have h1 : q.Prime := (Finset.mem_filter.mp hq).2.1 have h2 : ((1 : ℚ) / q).den = q := by have := Nat.Prime.ne_zero h1; simp_all rw [h2] - exact (Nat.coprime_primes h1 hp).mpr (Finset.mem_filter.mp hq).2.2.2 + exact (Nat.coprime_primes h1 Fact.out).mpr (Finset.mem_filter.mp hq).2.2.2 /-- Splits the prime-indexed correction sum into the `p`-term (`vonStaudtIndicator / p`) plus the rest. -/ -lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : +lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) [Fact p.Prime] : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by @@ -512,7 +533,7 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : · -- p is in the filtered set; extract its term have hp_mem : p ∈ (Finset.range (2 * k + 2)).filter (fun q ↦ q.Prime ∧ (q - 1) ∣ 2 * k) := by simp only [Finset.mem_filter, Finset.mem_range] - exact ⟨by have := Nat.le_of_dvd (by omega) hdvd; omega, hp, hdvd⟩ + exact ⟨by have := Nat.le_of_dvd (by omega) hdvd; omega, (Fact.out : p.Prime), hdvd⟩ rw [← Finset.add_sum_erase _ _ hp_mem] simp only [vonStaudtIndicator, if_pos hdvd] congr 1 @@ -525,15 +546,15 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) (hp : p.Prime) : fun ⟨hpr, hd, _⟩ ↦ ⟨hpr, hd⟩⟩) fun _ _ ↦ rfl /-- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ -lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) +lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ)^N / M) := by set e := M.factorization p set M' := M / p ^ e with hM'_def have hM'_ne : M' ≠ 0 := (Nat.ordCompl_pos p hM).ne' - have hM'_cop : M'.Coprime p := (Nat.coprime_ordCompl hp hM).symm + have hM'_cop : M'.Coprime p := (Nat.coprime_ordCompl (Fact.out : p.Prime) hM).symm -- Rewrite p^N / M as p^(N-e) / M' where M' = M / p^e is coprime to p have hdecomp : p ^ e * M' = M := Nat.ordProj_mul_ordCompl_eq_self M p - have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr hp.ne_zero + have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero (Fact.out : p.Prime)) have hpe_ne : (p : ℚ) ^ e ≠ 0 := pow_ne_zero e hp_ne have hrw : (p : ℚ) ^ N / M = (p : ℚ) ^ (N - e) / M' := by have hM_cast : (M : ℚ) = (p ^ e : ℕ) * (M' : ℕ) := by rw [← hdecomp]; simp @@ -546,43 +567,47 @@ lemma pIntegral_pow_div (p M N : ℕ) (hp : p.Prime) (hM : M ≠ 0) norm_cast; simp rw [h1] exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _) - exact hM'_cop.coprime_dvd_left hdvd + have hcop : ((p : ℚ) ^ (N - e) / M').den.Coprime p := hM'_cop.coprime_dvd_left hdvd + exact (pIntegral_iff_not_dvd_den p _).2 + ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) /-- Basic valuation bound used for the `i = 0` term in the Faulhaber expansion. -/ -lemma valuation_bound (p n : ℕ) (hp : p.Prime) : (n + 1).factorization p ≤ n := +lemma valuation_bound (p n : ℕ) [Fact p.Prime] : (n + 1).factorization p ≤ n := Nat.factorization_le_of_le_pow <| calc n + 1 = (n + 1).choose 1 := by simp _ ≤ 2 ^ n := Nat.choose_succ_le_two_pow n 1 - _ ≤ p ^ n := Nat.pow_le_pow_left hp.two_le n + _ ≤ p ^ n := Nat.pow_le_pow_left ((Fact.out : p.Prime).two_le) n /-- The `i = 0` Faulhaber term is `p`-integral. -/ -lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : +lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : pIntegral p ((p : ℚ) ^ (2 * k) / (2 * k + 1)) := by have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by norm_cast rw [h] - apply pIntegral_pow_div p (2 * k + 1) (2 * k) hp + apply pIntegral_pow_div p (2 * k + 1) (2 * k) · omega - · exact valuation_bound p (2 * k) hp + · exact valuation_bound p (2 * k) /-- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ -lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) (hp : p.Prime) : +lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by + rw [bernoulli_one] obtain rfl | hp2 := eq_or_ne p 2 - · rw [bernoulli_one] - have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = + · have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = (-(2 : ℤ) ^ (2 * k - 2) : ℤ) := by have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by rw [← pow_succ]; lia rw [hpow]; push_cast; field_simp - simp only [Nat.cast_ofNat, h]; norm_num [pIntegral] - · rw [show bernoulli 1 = (-1 : ℚ) / 2 from by norm_num [bernoulli]] - have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega + simpa [h] using (pIntegral_of_int (p := 2) (z := (-(2 : ℤ) ^ (2 * k - 2)))) + · have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega field_simp [h2] - rw [neg_div', pIntegral] + rw [neg_div'] have hdvd : (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by rw [neg_div, Rat.den_neg_eq_den, ← Nat.cast_pow] conv_lhs => rw [show (2 : ℚ) = (2 : ℕ) from rfl, Rat.natCast_div_eq_divInt] exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _) - exact Nat.Coprime.of_dvd_left hdvd (Odd.coprime_two_left (hp.odd_of_ne_two hp2)) + have hcop : (-(p : ℚ) ^ (2 * k - 1) / 2).den.Coprime p := Nat.Coprime.of_dvd_left hdvd + (Odd.coprime_two_left ((Fact.out : p.Prime).odd_of_ne_two hp2)) + exact (pIntegral_iff_not_dvd_den p _).2 + ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) /-- The exceptional base case of the inequality argument (`p = 2`, `d = 2`). -/ lemma valuation_bound_d_plus_1_p2_d2 : (2 + 1).factorization 2 ≤ 2 - 1 := by @@ -619,9 +644,9 @@ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 exact h2 d hd /-- Main valuation estimate behind the contradiction step for even-index summands. -/ -lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : +lemma valuation_bound_d_plus_1 (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by - obtain hp2 | hp3 := hp.eq_two_or_odd + obtain hp2 | hp3 := (Fact.out : p.Prime).eq_two_or_odd · subst hp2 obtain rfl | hd3 := eq_or_lt_of_le hd · exact valuation_bound_d_plus_1_p2_d2 @@ -630,7 +655,7 @@ lemma valuation_bound_d_plus_1 (p d : ℕ) (hp : p.Prime) (hd : d ≥ 2) : · apply Nat.factorization_le_of_le_pow apply pow_ge_succ_of_ge_three · have hne2 : p ≠ 2 := fun h ↦ by simp [h] at hp3 - have h1lt : 1 < p := hp.one_lt + have h1lt : 1 < p := (Fact.out : p.Prime).one_lt omega · exact hd @@ -653,7 +678,7 @@ lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] /-- `p`-integrality of the core even-index summand after denominator normalization. -/ -lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * k - 2 * m ≥ 2) : +lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (hd : 2 * k - 2 * m ≥ 2) : pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def @@ -663,8 +688,8 @@ lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat] have h_pow_integral : pIntegral p ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by - apply pIntegral_pow_div p (d + 1) (d - 1) hp hd_plus_one_ne_zero - exact valuation_bound_d_plus_1 p d hp hd + apply pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero + exact valuation_bound_d_plus_1 p d hd have h_eq : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ) = ((2 * k).choose (2 * m) : ℕ) * ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by ring rw [h_eq] @@ -672,8 +697,8 @@ lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) (hp : p.Prime) (hd : 2 * /-- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` to prove `p`-integrality of the even term. -/ -lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) - (hp : p.Prime) (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : +lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] + (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by have hdecomp : (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * @@ -719,16 +744,16 @@ lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) exact pow_succ' _ _ rw [hpow]; ring rw [hp_factor] - exact pIntegral_mul _ _ _ (pIntegral_of_int p p) (pIntegral_case_one k m p hm_lt hp (by omega)) + exact pIntegral_mul _ _ _ (pIntegral_of_int p p) (pIntegral_case_one k m p hm_lt (by omega)) · unfold vonStaudtIndicator split_ifs with h · simp only [one_mul] rw [choose_div_simplify k m _ hm_lt] - exact pIntegral_case_one k m p hm_lt hp (by omega) + exact pIntegral_case_one k m p hm_lt (by omega) · simp /-- The full remainder sum in Faulhaber's formula is `p`-integral. -/ -lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) +lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) [Fact p.Prime] (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by @@ -737,21 +762,21 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) (hp : p.Prime) rw [Finset.mem_range] at hi rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] - exact pIntegral_i0_term k p hk hp + exact pIntegral_i0_term k p hk · simp only [zero_add, Nat.choose_one_right] - convert pIntegral_i1_term k p hk hp using 1 + convert pIntegral_i1_term k p hk using 1 push_cast; field_simp · set j := i + 2 with hj_def have hj_lt : j < 2 * k := by omega rcases Nat.even_or_odd j with ⟨m, hm⟩ | hodd · have ⟨_, hm_lt, hj_eq⟩ : m ≥ 1 ∧ m < k ∧ j = 2 * m := by omega simp only [hj_eq] - exact pIntegral_even_term_in_sum k m p hm_lt hp (ih m (by omega) hm_lt) + exact pIntegral_even_term_in_sum k m p hm_lt (ih m (by omega) hm_lt) · simp [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; omega)] /-- Rearranges the Faulhaber identity and power-sum congruence to isolate `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ -lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Prime) : +lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by @@ -759,7 +784,7 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Pr (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T := by have h_cast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0)) : ZMod p) = 0 := by - push_cast; exact power_sum_add_indicator_eq_zero p (2 * k) hp + push_cast; exact power_sum_add_indicator_eq_zero p (2 * k) rw [ZMod.intCast_zmod_eq_zero_iff_dvd] at h_cast; exact h_cast obtain ⟨T, hT⟩ := hDiv use T @@ -804,7 +829,7 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Pr have hAlg : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by - have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast hp.ne_zero + have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast (Fact.out : p.Prime).ne_zero field_simp [hp_ne]; linarith rw [hAlg]; congr 1 have h0 : (∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * @@ -817,36 +842,44 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) (hp : p.Pr (2 * k + 1 : ℚ) := by intro i hi have h2 : i < 2 * k := Finset.mem_range.mp hi - have h5 : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero hp + have h5 : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero (Fact.out : p.Prime) rw [show (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 from by omega, pow_succ] field_simp [h5] rw [Finset.sum_div] exact Finset.sum_congr rfl fun i hi ↦ h1 i hi exact_mod_cast h0 -/-- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is coprime to `p`. -/ -lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) : - (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den.Coprime p := by +/-- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ +lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) [Fact p.Prime] : + ¬ p ∣ (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := by induction k using Nat.strong_induction_on with | _ k ih => - obtain ⟨T, hT⟩ := bernoulli_plus_indicator_rearrangement k p hk hp + obtain ⟨T, hT⟩ := bernoulli_plus_indicator_rearrangement k p hk rw [hT] have hT_int : pIntegral p (T : ℚ) := pIntegral_of_int p T have hR : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by - apply pIntegral_remainder k p hk hp + apply pIntegral_remainder k p hk intro m hm_pos hm_lt - exact ih m hm_lt hm_pos - exact pIntegral_sub p T _ hT_int hR + exact (pIntegral_iff_not_dvd_den p _).2 (ih m hm_lt hm_pos) + exact (pIntegral_iff_not_dvd_den p _).1 (pIntegral_sub p T _ hT_int hR) /-- Extends the fixed-prime coprimality result to the full prime correction sum. -/ -lemma von_staudt_coprime_all_primes_pos (k p : ℕ) (hk : k > 0) (hp : p.Prime) : - (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with - q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den.Coprime p := by - rw [sum_primes_eq_indicator_add_rest k p hk hp, ← add_assoc] - exact Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) - ((bernoulli_plus_indicator_coprime_p_pos k p hk hp).mul_left - (Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) (prod_den_coprime_p k p hp))) +lemma von_staudt_coprime_all_primes_pos (k p : ℕ) (hk : k > 0) [Fact p.Prime] : + ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with + q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den := by + rw [sum_primes_eq_indicator_add_rest k p hk, ← add_assoc] + have h₁ : p.Coprime (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := + (Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 + (bernoulli_plus_indicator_coprime_p_pos k p hk) + have h₂ : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, + (1 : ℚ) / q).den.Coprime p := Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) + (prod_den_coprime_p k p) + have hcop : (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p + + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, + (1 : ℚ) / q).den.Coprime p := Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) + (h₁.symm.mul_left h₂) + exact (Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm /-- **von Staudt-Clausen theorem:** For any natural number $k$, the sum $$B_{2k} + \sum_{p - 1 \mid 2k} \frac{1}{p}$$ is an integer. @@ -856,7 +889,9 @@ theorem von_staudt_clausen (k : ℕ) : (1 : ℚ) / p ∈ Set.range Int.cast := by rcases Nat.eq_zero_or_pos k with rfl | hk · exact ⟨1, by decide +kernel⟩ - · exact is_integer_of_coprime_all_primes _ - (fun p hp ↦ von_staudt_coprime_all_primes_pos k p hk hp) + · exact Rat.mem_range_intCast_of_not_prime_dvd _ + (fun p hp ↦ by + letI : Fact p.Prime := ⟨hp⟩ + exact von_staudt_coprime_all_primes_pos k p hk) end vonStaudtClausen From 2b3fbbbb5abe1486451c4572f2d898e675eb9a64 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Mon, 9 Mar 2026 23:24:09 -0700 Subject: [PATCH 38/70] use lia and golf pIntegral lemma proofs --- Mathlib/NumberTheory/Bernoulli.lean | 83 +++++++++++------------------ 1 file changed, 32 insertions(+), 51 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 6a9e1fa21c6aa9..bc4eebff016d7d 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -455,7 +455,6 @@ lemma pIntegral_iff_not_dvd_den (p : ℕ) (x : ℚ) [Fact p.Prime] : pIntegral p lemma pIntegral_iff_padicValuation_le_one (p : ℕ) (x : ℚ) [Fact p.Prime] : pIntegral p x ↔ Rat.padicValuation p x ≤ 1 := by rfl - @[simp] lemma pIntegral_zero (p : ℕ) [Fact p.Prime] : pIntegral p (0 : ℚ) := (pIntegral_iff_not_dvd_den p _).2 (by simpa using Nat.Prime.not_dvd_one Fact.out) @@ -477,39 +476,21 @@ lemma pIntegral_sum {ι : Type*} (p : ℕ) [Fact p.Prime] (s : Finset ι) (f : exact (pIntegral_iff_not_dvd_den p _).2 ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) -lemma pIntegral_of_int (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := by - exact (pIntegral_iff_not_dvd_den p _).2 - (by simpa using (Nat.Prime.not_dvd_one (Fact.out : p.Prime))) +lemma pIntegral_of_int (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := + (pIntegral_iff_not_dvd_den p _).2 (by simpa using (Nat.Prime.not_dvd_one Fact.out)) lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := by - have hxcop : x.den.Coprime p := by - have hxnot : ¬ p ∣ x.den := (pIntegral_iff_not_dvd_den p x).1 hx - exact ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 hxnot).symm - have hycop : y.den.Coprime p := by - have hynot : ¬ p ∣ y.den := (pIntegral_iff_not_dvd_den p y).1 hy - exact ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 hynot).symm - have hcop : (x * y).den.Coprime p := Nat.Coprime.of_dvd_left (Rat.mul_den_dvd x y) - (Nat.Coprime.mul_left hxcop hycop) - exact (pIntegral_iff_not_dvd_den p _).2 - ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) + simp only [pIntegral, map_mul] at * + exact mul_le_one' hx hy lemma pIntegral_int_mul (p : ℕ) [Fact p.Prime] (x : ℚ) (z : ℤ) (hx : pIntegral p x) : pIntegral p (z * x) := by - simpa [mul_comm] using pIntegral_mul p (z : ℚ) x (pIntegral_of_int p z) hx + simpa [mul_comm] using pIntegral_mul p z x (pIntegral_of_int p z) hx lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x - y) := by - have hxcop : x.den.Coprime p := by - have hxnot : ¬ p ∣ x.den := (pIntegral_iff_not_dvd_den p x).1 hx - exact ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 hxnot).symm - have hycop : y.den.Coprime p := by - have hynot : ¬ p ∣ y.den := (pIntegral_iff_not_dvd_den p y).1 hy - exact ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 hynot).symm - have hcop : (x - y).den.Coprime p := Nat.Coprime.coprime_dvd_left (Rat.sub_den_dvd x y) - (Nat.Coprime.mul_left hxcop hycop) - exact (pIntegral_iff_not_dvd_den p _).2 - ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) + simpa [pIntegral] using (Rat.padicValuation p).map_sub_le hx hy /-- Denominators of the "other primes" part of the indicator sum stay coprime to a fixed prime `p`. -/ @@ -533,7 +514,7 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) [Fact p.Prime] : · -- p is in the filtered set; extract its term have hp_mem : p ∈ (Finset.range (2 * k + 2)).filter (fun q ↦ q.Prime ∧ (q - 1) ∣ 2 * k) := by simp only [Finset.mem_filter, Finset.mem_range] - exact ⟨by have := Nat.le_of_dvd (by omega) hdvd; omega, (Fact.out : p.Prime), hdvd⟩ + exact ⟨by have := Nat.le_of_dvd (by lia) hdvd; lia, (Fact.out : p.Prime), hdvd⟩ rw [← Finset.add_sum_erase _ _ hp_mem] simp only [vonStaudtIndicator, if_pos hdvd] congr 1 @@ -584,7 +565,7 @@ lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by norm_cast rw [h] apply pIntegral_pow_div p (2 * k + 1) (2 * k) - · omega + · lia · exact valuation_bound p (2 * k) /-- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ @@ -597,7 +578,7 @@ lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by rw [← pow_succ]; lia rw [hpow]; push_cast; field_simp simpa [h] using (pIntegral_of_int (p := 2) (z := (-(2 : ℤ) ^ (2 * k - 2)))) - · have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; omega + · have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; lia field_simp [h2] rw [neg_div'] have hdvd : (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by @@ -621,10 +602,10 @@ lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - | refl => norm_num | @step m hm IH => have hm : (3 : ℕ) ≤ m := hm - have h1 : 2 ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by omega) - calc m + 1 + 1 ≤ 2 ^ (m - 1) + 1 := by omega + have h1 : 2 ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by lia) + calc m + 1 + 1 ≤ 2 ^ (m - 1) + 1 := by lia _ ≤ 2 ^ (m - 1) * 2 := by nlinarith - _ = 2 ^ m := by conv_rhs => rw [show m = m - 1 + 1 from by omega]; exact pow_succ .. + _ = 2 ^ m := by conv_rhs => rw [show m = m - 1 + 1 by lia]; exact pow_succ .. exact h d hd /-- Auxiliary growth inequality: for `p ≥ 3` and `d ≥ 2`, we have `d + 1 ≤ p^(d - 1)`. -/ @@ -632,15 +613,15 @@ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by intro d hd induction hd with - | refl => norm_num; omega + | refl => norm_num; lia | @step m hm IH => have hm : (2 : ℕ) ≤ m := hm - calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by omega + calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by lia _ ≤ p ^ (m - 1) * p := by - have : p ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by omega) + have : p ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by lia) nlinarith _ = p ^ m := by - conv_rhs => rw [show m = m - 1 + 1 from by omega]; exact pow_succ .. + conv_rhs => rw [show m = m - 1 + 1 by lia]; exact pow_succ .. exact h2 d hd /-- Main valuation estimate behind the contradiction step for even-index summands. -/ @@ -656,7 +637,7 @@ lemma valuation_bound_d_plus_1 (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : apply pow_ge_succ_of_ge_three · have hne2 : p ≠ 2 := fun h ↦ by simp [h] at hp3 have h1lt : 1 < p := (Fact.out : p.Prime).one_lt - omega + lia · exact hd /-- Rewrites the binomial coefficient denominator exactly as in Rado's summand. -/ @@ -683,7 +664,7 @@ lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (hd : 2 * (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def have ⟨hd_ne_zero, hd_plus_one_ne_zero, h_exp, hkm⟩ : - d ≠ 0 ∧ d + 1 ≠ 0 ∧ 2 * k - 2 * m - 1 = d - 1 ∧ 2 * m ≤ 2 * k := by omega + d ≠ 0 ∧ d + 1 ≠ 0 ∧ 2 * k - 2 * m - 1 = d - 1 ∧ 2 * m ≤ 2 * k := by lia have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat] @@ -708,14 +689,14 @@ lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1) := by - simp only [show 2 * k - 2 * m = 2 * (k - m) from by omega] + simp only [show 2 * k - 2 * m = 2 * (k - m) by lia] have h : bernoulli (2 * m) * (p : ℚ) ^ (2 * (k - m)) = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * (p : ℚ) ^ (2 * (k - m)) - vonStaudtIndicator (2 * m) p * (p : ℚ) ^ (2 * (k - m) - 1) := by have hpow : (p : ℚ) ^ (2 * (k - m)) = (p : ℚ) ^ (2 * (k - m) - 1) * p := by - conv_lhs => rw [show 2 * (k - m) = (2 * (k - m) - 1) + 1 from by omega, pow_succ] + conv_lhs => rw [show 2 * (k - m) = (2 * (k - m) - 1) + 1 by lia, pow_succ] rcases eq_or_ne (p : ℚ) 0 with hp0 | hp0 - · simp [hp0, zero_pow (show 2 * (k - m) - 1 ≠ 0 from by omega)] + · simp [hp0, zero_pow (show 2 * (k - m) - 1 ≠ 0 by lia)] · rw [hpow]; field_simp [hp0]; ring set C := ((2 * k + 1).choose (2 * m) : ℚ) set N := (2 * k + 1 : ℚ) @@ -740,16 +721,16 @@ lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by have hpow : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) := by conv_lhs => - rw [show (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1) + 1 from by omega] + rw [show (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1) + 1 by lia] exact pow_succ' _ _ rw [hpow]; ring rw [hp_factor] - exact pIntegral_mul _ _ _ (pIntegral_of_int p p) (pIntegral_case_one k m p hm_lt (by omega)) + exact pIntegral_mul _ _ _ (pIntegral_of_int p p) (pIntegral_case_one k m p hm_lt (by lia)) · unfold vonStaudtIndicator split_ifs with h · simp only [one_mul] rw [choose_div_simplify k m _ hm_lt] - exact pIntegral_case_one k m p hm_lt (by omega) + exact pIntegral_case_one k m p hm_lt (by lia) · simp /-- The full remainder sum in Faulhaber's formula is `p`-integral. -/ @@ -767,12 +748,12 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) [Fact p.Prime] convert pIntegral_i1_term k p hk using 1 push_cast; field_simp · set j := i + 2 with hj_def - have hj_lt : j < 2 * k := by omega + have hj_lt : j < 2 * k := by lia rcases Nat.even_or_odd j with ⟨m, hm⟩ | hodd - · have ⟨_, hm_lt, hj_eq⟩ : m ≥ 1 ∧ m < k ∧ j = 2 * m := by omega + · have ⟨_, hm_lt, hj_eq⟩ : m ≥ 1 ∧ m < k ∧ j = 2 * m := by lia simp only [hj_eq] - exact pIntegral_even_term_in_sum k m p hm_lt (ih m (by omega) hm_lt) - · simp [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; omega)] + exact pIntegral_even_term_in_sum k m p hm_lt (ih m (by lia) hm_lt) + · simp [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; lia)] /-- Rearranges the Faulhaber identity and power-sum congruence to isolate `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ @@ -815,15 +796,15 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) [Fact p.Pr rw [show (v : ℚ) ^ (2 * k) = if v ≠ 0 then (v : ℚ) ^ (2 * k) else 0 by split_ifs with h · rfl - · simp [show v = 0 by omega, show 2 * k ≠ 0 from by omega]] + · simp [show v = 0 by lia, show 2 * k ≠ 0 by lia]] rw [Finset.sum_filter] rw [← hfilter] simp only [sum_range_pow]; push_cast rw [Finset.sum_range_succ] congr 1 have h1 : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by - rw [← Nat.choose_symm_of_eq_add (by omega : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] - rw [h1, show (2 * k + 1 - 2 * k : ℕ) = 1 from by omega, pow_one] + rw [← Nat.choose_symm_of_eq_add (by lia : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] + rw [h1, show (2 * k + 1 - 2 * k : ℕ) = 1 by lia, pow_one] have h4 : (2 * k + 1 : ℚ) ≠ 0 := by positivity norm_cast; field_simp [h4] have hAlg : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = @@ -843,7 +824,7 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) [Fact p.Pr intro i hi have h2 : i < 2 * k := Finset.mem_range.mp hi have h5 : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero (Fact.out : p.Prime) - rw [show (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 from by omega, pow_succ] + rw [show (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 by lia, pow_succ] field_simp [h5] rw [Finset.sum_div] exact Finset.sum_congr rfl fun i hi ↦ h1 i hi From c9e5e09f3a91382999250496937e9644c74c447e Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Mon, 9 Mar 2026 23:37:39 -0700 Subject: [PATCH 39/70] renaming --- Mathlib/NumberTheory/Bernoulli.lean | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index bc4eebff016d7d..475771c0e51661 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -560,7 +560,7 @@ lemma valuation_bound (p n : ℕ) [Fact p.Prime] : (n + 1).factorization p ≤ n _ ≤ p ^ n := Nat.pow_le_pow_left ((Fact.out : p.Prime).two_le) n /-- The `i = 0` Faulhaber term is `p`-integral. -/ -lemma pIntegral_i0_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +lemma pIntegral_i0_term (k p : ℕ) [Fact p.Prime] : pIntegral p ((p : ℚ) ^ (2 * k) / (2 * k + 1)) := by have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by norm_cast rw [h] @@ -743,7 +743,7 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) [Fact p.Prime] rw [Finset.mem_range] at hi rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] - exact pIntegral_i0_term k p hk + exact pIntegral_i0_term k p · simp only [zero_add, Nat.choose_one_right] convert pIntegral_i1_term k p hk using 1 push_cast; field_simp @@ -831,7 +831,7 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) [Fact p.Pr exact_mod_cast h0 /-- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ -lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +lemma bernoulli_plus_indicator_den_not_dvd_of_pos (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := by induction k using Nat.strong_induction_on with | _ k ih => @@ -845,14 +845,14 @@ lemma bernoulli_plus_indicator_coprime_p_pos (k p : ℕ) (hk : k > 0) [Fact p.Pr exact (pIntegral_iff_not_dvd_den p _).2 (ih m hm_lt hm_pos) exact (pIntegral_iff_not_dvd_den p _).1 (pIntegral_sub p T _ hT_int hR) -/-- Extends the fixed-prime coprimality result to the full prime correction sum. -/ -lemma von_staudt_coprime_all_primes_pos (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +/-- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ +lemma von_staudt_sum_den_not_dvd_of_pos (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den := by rw [sum_primes_eq_indicator_add_rest k p hk, ← add_assoc] have h₁ : p.Coprime (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := (Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 - (bernoulli_plus_indicator_coprime_p_pos k p hk) + (bernoulli_plus_indicator_den_not_dvd_of_pos k p hk) have h₂ : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q).den.Coprime p := Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) (prod_den_coprime_p k p) @@ -873,6 +873,6 @@ theorem von_staudt_clausen (k : ℕ) : · exact Rat.mem_range_intCast_of_not_prime_dvd _ (fun p hp ↦ by letI : Fact p.Prime := ⟨hp⟩ - exact von_staudt_coprime_all_primes_pos k p hk) + exact von_staudt_sum_den_not_dvd_of_pos k p hk) end vonStaudtClausen From 6a5443977bc5129cdd53ee7e4796244e7d49cd26 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Tue, 10 Mar 2026 08:38:26 -0700 Subject: [PATCH 40/70] better renaming? --- Mathlib/NumberTheory/Bernoulli.lean | 137 ++++++++++++++-------------- 1 file changed, 68 insertions(+), 69 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 475771c0e51661..e9c6dfe008cf50 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -57,7 +57,7 @@ The proof of von Staudt-Clausen's theorem follows Rado's JLMS 1934 paper * `sum_bernoulli : ∑ k ∈ Finset.range n, (n.choose k : ℚ) * bernoulli k = if n = 1 then 1 else 0` -* `von_staudt_clausen : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) +* `vonStaudt_clausen : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast` ## References @@ -416,7 +416,7 @@ Rado's proof is based on Faulhaber's theorem and induction on $k$. noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1 : ℕ) ∣ k then 1 else 0 /-- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ -lemma power_sum_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : +lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + (if (p - 1 : ℕ) ∣ l then (1 : ZMod p) else 0) = 0 := by have cast_ne : ∀ v, v ∈ (Finset.range p).filter (· ≠ 0) → (v : ZMod p) ≠ 0 := by @@ -439,7 +439,7 @@ lemma power_sum_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : grind /-- If a rational number is $p$-integral for all primes $p$, then it is an integer. -/ -lemma Rat.mem_range_intCast_of_not_prime_dvd (q : ℚ) (h : ∀ p : ℕ, p.Prime → ¬ p ∣ q.den) : +lemma Rat.isInt_of_forall_prime_not_dvd_den (q : ℚ) (h : ∀ p : ℕ, p.Prime → ¬ p ∣ q.den) : q ∈ Set.range Int.cast := by rw [Set.mem_range] refine ⟨q.num, Rat.coe_int_num_of_den_eq_one ?_⟩ @@ -449,14 +449,14 @@ lemma Rat.mem_range_intCast_of_not_prime_dvd (q : ℚ) (h : ∀ p : ℕ, p.Prime /-- A rational number `x` is `p`-integral if `p` does not divide its denominator. -/ def pIntegral (p : ℕ) (x : ℚ) [Fact p.Prime] : Prop := Rat.padicValuation p x ≤ 1 -lemma pIntegral_iff_not_dvd_den (p : ℕ) (x : ℚ) [Fact p.Prime] : pIntegral p x ↔ ¬ p ∣ x.den := by +lemma pIntegral_iff_not_dvd (p : ℕ) (x : ℚ) [Fact p.Prime] : pIntegral p x ↔ ¬ p ∣ x.den := by simp only [pIntegral, Rat.padicValuation_le_one_iff] -lemma pIntegral_iff_padicValuation_le_one (p : ℕ) (x : ℚ) [Fact p.Prime] : +lemma pIntegral_iff_padicValuation (p : ℕ) (x : ℚ) [Fact p.Prime] : pIntegral p x ↔ Rat.padicValuation p x ≤ 1 := by rfl @[simp] lemma pIntegral_zero (p : ℕ) [Fact p.Prime] : pIntegral p (0 : ℚ) := - (pIntegral_iff_not_dvd_den p _).2 (by simpa using Nat.Prime.not_dvd_one Fact.out) + (pIntegral_iff_not_dvd p _).2 (by simpa using Nat.Prime.not_dvd_one Fact.out) lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by @@ -471,22 +471,21 @@ lemma pIntegral_sum {ι : Type*} (p : ℕ) [Fact p.Prime] (s : Finset ι) (f : (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := by have hcop : (∑ i ∈ s, f i).den.Coprime p := Nat.Coprime.coprime_dvd_left (sum_den_dvd_prod_den s f) (Nat.Coprime.prod_left fun i hi ↦ by - have hfi_not : ¬ p ∣ (f i).den := (pIntegral_iff_not_dvd_den p (f i)).1 (hf i hi) - exact ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 hfi_not).symm) - exact (pIntegral_iff_not_dvd_den p _).2 - ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) + have hfi_not : ¬ p ∣ (f i).den := (pIntegral_iff_not_dvd p (f i)).1 (hf i hi) + exact ((Nat.Prime.coprime_iff_not_dvd Fact.out).2 hfi_not).symm) + exact (pIntegral_iff_not_dvd p _).2 ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm) -lemma pIntegral_of_int (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := - (pIntegral_iff_not_dvd_den p _).2 (by simpa using (Nat.Prime.not_dvd_one Fact.out)) +lemma pIntegral_intCast (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := + (pIntegral_iff_not_dvd p _).2 (by simpa using (Nat.Prime.not_dvd_one Fact.out)) lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := by simp only [pIntegral, map_mul] at * exact mul_le_one' hx hy -lemma pIntegral_int_mul (p : ℕ) [Fact p.Prime] (x : ℚ) (z : ℤ) (hx : pIntegral p x) : +lemma pIntegral_intCast_mul (p : ℕ) [Fact p.Prime] (x : ℚ) (z : ℤ) (hx : pIntegral p x) : pIntegral p (z * x) := by - simpa [mul_comm] using pIntegral_mul p z x (pIntegral_of_int p z) hx + simpa [mul_comm] using pIntegral_mul p z x (pIntegral_intCast p z) hx lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x - y) := by @@ -494,7 +493,7 @@ lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (h /-- Denominators of the "other primes" part of the indicator sum stay coprime to a fixed prime `p`. -/ -lemma prod_den_coprime_p (k p : ℕ) [Fact p.Prime] : +lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : (∏ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, ((1 : ℚ) / q).den).Coprime p := by apply Nat.Coprime.prod_left @@ -506,7 +505,7 @@ lemma prod_den_coprime_p (k p : ℕ) [Fact p.Prime] : /-- Splits the prime-indexed correction sum into the `p`-term (`vonStaudtIndicator / p`) plus the rest. -/ -lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +lemma sum_one_div_prime_eq_vonStaudtIndicator_div_add (k p : ℕ) (hk : k > 0) [Fact p.Prime] : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by @@ -514,7 +513,7 @@ lemma sum_primes_eq_indicator_add_rest (k p : ℕ) (hk : k > 0) [Fact p.Prime] : · -- p is in the filtered set; extract its term have hp_mem : p ∈ (Finset.range (2 * k + 2)).filter (fun q ↦ q.Prime ∧ (q - 1) ∣ 2 * k) := by simp only [Finset.mem_filter, Finset.mem_range] - exact ⟨by have := Nat.le_of_dvd (by lia) hdvd; lia, (Fact.out : p.Prime), hdvd⟩ + exact ⟨by have := Nat.le_of_dvd (by lia) hdvd; lia, Fact.out, hdvd⟩ rw [← Finset.add_sum_erase _ _ hp_mem] simp only [vonStaudtIndicator, if_pos hdvd] congr 1 @@ -532,10 +531,10 @@ lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) set e := M.factorization p set M' := M / p ^ e with hM'_def have hM'_ne : M' ≠ 0 := (Nat.ordCompl_pos p hM).ne' - have hM'_cop : M'.Coprime p := (Nat.coprime_ordCompl (Fact.out : p.Prime) hM).symm + have hM'_cop : M'.Coprime p := (Nat.coprime_ordCompl Fact.out hM).symm -- Rewrite p^N / M as p^(N-e) / M' where M' = M / p^e is coprime to p have hdecomp : p ^ e * M' = M := Nat.ordProj_mul_ordCompl_eq_self M p - have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero (Fact.out : p.Prime)) + have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero Fact.out) have hpe_ne : (p : ℚ) ^ e ≠ 0 := pow_ne_zero e hp_ne have hrw : (p : ℚ) ^ N / M = (p : ℚ) ^ (N - e) / M' := by have hM_cast : (M : ℚ) = (p ^ e : ℕ) * (M' : ℕ) := by rw [← hdecomp]; simp @@ -549,27 +548,27 @@ lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) rw [h1] exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _) have hcop : ((p : ℚ) ^ (N - e) / M').den.Coprime p := hM'_cop.coprime_dvd_left hdvd - exact (pIntegral_iff_not_dvd_den p _).2 - ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) + exact (pIntegral_iff_not_dvd p _).2 + ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm) /-- Basic valuation bound used for the `i = 0` term in the Faulhaber expansion. -/ -lemma valuation_bound (p n : ℕ) [Fact p.Prime] : (n + 1).factorization p ≤ n := +lemma factorization_succ_le (p n : ℕ) [Fact p.Prime] : (n + 1).factorization p ≤ n := Nat.factorization_le_of_le_pow <| calc n + 1 = (n + 1).choose 1 := by simp _ ≤ 2 ^ n := Nat.choose_succ_le_two_pow n 1 _ ≤ p ^ n := Nat.pow_le_pow_left ((Fact.out : p.Prime).two_le) n /-- The `i = 0` Faulhaber term is `p`-integral. -/ -lemma pIntegral_i0_term (k p : ℕ) [Fact p.Prime] : +lemma pIntegral_pow_div_two_mul_succ (k p : ℕ) [Fact p.Prime] : pIntegral p ((p : ℚ) ^ (2 * k) / (2 * k + 1)) := by have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by norm_cast rw [h] apply pIntegral_pow_div p (2 * k + 1) (2 * k) · lia - · exact valuation_bound p (2 * k) + · exact factorization_succ_le p (2 * k) /-- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ -lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by rw [bernoulli_one] obtain rfl | hp2 := eq_or_ne p 2 @@ -577,7 +576,7 @@ lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : (-(2 : ℤ) ^ (2 * k - 2) : ℤ) := by have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by rw [← pow_succ]; lia rw [hpow]; push_cast; field_simp - simpa [h] using (pIntegral_of_int (p := 2) (z := (-(2 : ℤ) ^ (2 * k - 2)))) + simpa [h] using (pIntegral_intCast _ (z := (-(2 : ℤ) ^ (2 * k - 2)))) · have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; lia field_simp [h2] rw [neg_div'] @@ -587,15 +586,15 @@ lemma pIntegral_i1_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _) have hcop : (-(p : ℚ) ^ (2 * k - 1) / 2).den.Coprime p := Nat.Coprime.of_dvd_left hdvd (Odd.coprime_two_left ((Fact.out : p.Prime).odd_of_ne_two hp2)) - exact (pIntegral_iff_not_dvd_den p _).2 - ((Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm) + exact (pIntegral_iff_not_dvd p _).2 + ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm) /-- The exceptional base case of the inequality argument (`p = 2`, `d = 2`). -/ -lemma valuation_bound_d_plus_1_p2_d2 : (2 + 1).factorization 2 ≤ 2 - 1 := by +lemma factorization_two_three_le_one : (2 + 1).factorization 2 ≤ 2 - 1 := by simp [Nat.factorization_eq_zero_of_not_dvd (show ¬(2 ∣ 3) by decide)] /-- Auxiliary growth inequality: for `d ≥ 3`, we have `d + 1 ≤ 2^(d - 1)`. -/ -lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) := by +lemma succ_le_two_pow_sub_one (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) := by have h : ∀ n : ℕ, n ≥ 3 → n + 1 ≤ 2 ^ (n - 1) := by intro n hn induction hn with @@ -609,7 +608,7 @@ lemma pow_two_ge_succ_of_ge_three (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - exact h d hd /-- Auxiliary growth inequality: for `p ≥ 3` and `d ≥ 2`, we have `d + 1 ≤ p^(d - 1)`. -/ -lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 ≤ p ^ (d - 1) := by +lemma succ_le_pow_sub_one (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 ≤ p ^ (d - 1) := by have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by intro d hd induction hd with @@ -625,23 +624,23 @@ lemma pow_ge_succ_of_ge_three (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 exact h2 d hd /-- Main valuation estimate behind the contradiction step for even-index summands. -/ -lemma valuation_bound_d_plus_1 (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : +lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by obtain hp2 | hp3 := (Fact.out : p.Prime).eq_two_or_odd · subst hp2 obtain rfl | hd3 := eq_or_lt_of_le hd - · exact valuation_bound_d_plus_1_p2_d2 + · exact factorization_two_three_le_one · apply Nat.factorization_le_of_le_pow - exact pow_two_ge_succ_of_ge_three _ hd3 + exact succ_le_two_pow_sub_one _ hd3 · apply Nat.factorization_le_of_le_pow - apply pow_ge_succ_of_ge_three + apply succ_le_pow_sub_one · have hne2 : p ≠ 2 := fun h ↦ by simp [h] at hp3 have h1lt : 1 < p := (Fact.out : p.Prime).one_lt lia · exact hd /-- Rewrites the binomial coefficient denominator exactly as in Rado's summand. -/ -lemma choose_div_core (k m : ℕ) (hm_lt : m < k) : +lemma choose_two_mul_succ_div_eq (k m : ℕ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia)] @@ -650,16 +649,16 @@ lemma choose_div_core (k m : ℕ) (hm_lt : m < k) : norm_cast grind -/-- Multiplicative form of `choose_div_core`, used to move factors around in the even case. -/ -lemma choose_div_simplify (k m : ℕ) (x : ℚ) (hm_lt : m < k) : +/-- Multiplicative variant of `choose_two_mul_succ_div_eq`. -/ +lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) * x / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) * x / (2 * k - 2 * m + 1) := by - have h := choose_div_core k m hm_lt + have h := choose_two_mul_succ_div_eq k m hm_lt rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] /-- `p`-integrality of the core even-index summand after denominator normalization. -/ -lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (hd : 2 * k - 2 * m ≥ 2) : +lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (hd : 2 * k - 2 * m ≥ 2) : pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def @@ -670,15 +669,15 @@ lemma pIntegral_case_one (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (hd : 2 * rw [h_exp, h_denom_rat] have h_pow_integral : pIntegral p ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by apply pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero - exact valuation_bound_d_plus_1 p d hd + exact factorization_succ_le_sub_one p d hd have h_eq : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ) = ((2 * k).choose (2 * m) : ℕ) * ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by ring rw [h_eq] - exact pIntegral_int_mul p _ _ h_pow_integral + exact pIntegral_intCast_mul p _ _ h_pow_integral /-- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` to prove `p`-integrality of the even term. -/ -lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] +lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by @@ -715,7 +714,7 @@ lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) by ring] apply pIntegral_mul _ _ _ ih - rw [choose_div_simplify k m ((p : ℚ) ^ (2 * k - 2 * m)) hm_lt] + rw [choose_two_mul_succ_mul_div_eq k m ((p : ℚ) ^ (2 * k - 2 * m)) hm_lt] have hp_factor : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k - 2 * m + 1) = (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by @@ -725,16 +724,16 @@ lemma pIntegral_even_term_in_sum (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] exact pow_succ' _ _ rw [hpow]; ring rw [hp_factor] - exact pIntegral_mul _ _ _ (pIntegral_of_int p p) (pIntegral_case_one k m p hm_lt (by lia)) + exact pIntegral_mul _ _ _ (pIntegral_intCast p p) (pIntegral_choose_mul_pow_div k m p hm_lt (by lia)) · unfold vonStaudtIndicator split_ifs with h · simp only [one_mul] - rw [choose_div_simplify k m _ hm_lt] - exact pIntegral_case_one k m p hm_lt (by lia) + rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt] + exact pIntegral_choose_mul_pow_div k m p hm_lt (by lia) · simp /-- The full remainder sum in Faulhaber's formula is `p`-integral. -/ -lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) [Fact p.Prime] +lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by @@ -743,21 +742,21 @@ lemma pIntegral_remainder (k p : ℕ) (hk : k > 0) [Fact p.Prime] rw [Finset.mem_range] at hi rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] - exact pIntegral_i0_term k p + exact pIntegral_pow_div_two_mul_succ k p · simp only [zero_add, Nat.choose_one_right] - convert pIntegral_i1_term k p hk using 1 + convert pIntegral_bernoulli_one_term k p hk using 1 push_cast; field_simp · set j := i + 2 with hj_def have hj_lt : j < 2 * k := by lia rcases Nat.even_or_odd j with ⟨m, hm⟩ | hodd · have ⟨_, hm_lt, hj_eq⟩ : m ≥ 1 ∧ m < k ∧ j = 2 * m := by lia simp only [hj_eq] - exact pIntegral_even_term_in_sum k m p hm_lt (ih m (by lia) hm_lt) + exact pIntegral_bernoulli_even_term k m p hm_lt (ih m (by lia) hm_lt) · simp [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; lia)] /-- Rearranges the Faulhaber identity and power-sum congruence to isolate `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ -lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +lemma bernoulli_add_vonStaudtIndicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by @@ -765,7 +764,7 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) [Fact p.Pr (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T := by have h_cast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0)) : ZMod p) = 0 := by - push_cast; exact power_sum_add_indicator_eq_zero p (2 * k) + push_cast; exact sum_pow_add_indicator_eq_zero p (2 * k) rw [ZMod.intCast_zmod_eq_zero_iff_dvd] at h_cast; exact h_cast obtain ⟨T, hT⟩ := hDiv use T @@ -823,7 +822,7 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) [Fact p.Pr (2 * k + 1 : ℚ) := by intro i hi have h2 : i < 2 * k := Finset.mem_range.mp hi - have h5 : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero (Fact.out : p.Prime) + have h5 : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero Fact.out rw [show (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 by lia, pow_succ] field_simp [h5] rw [Finset.sum_div] @@ -831,48 +830,48 @@ lemma bernoulli_plus_indicator_rearrangement (k p : ℕ) (hk : k > 0) [Fact p.Pr exact_mod_cast h0 /-- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ -lemma bernoulli_plus_indicator_den_not_dvd_of_pos (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +lemma bernoulli_add_vonStaudtIndicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := by induction k using Nat.strong_induction_on with | _ k ih => - obtain ⟨T, hT⟩ := bernoulli_plus_indicator_rearrangement k p hk + obtain ⟨T, hT⟩ := bernoulli_add_vonStaudtIndicator_eq_sub k p hk rw [hT] - have hT_int : pIntegral p (T : ℚ) := pIntegral_of_int p T + have hT_int : pIntegral p (T : ℚ) := pIntegral_intCast p T have hR : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by - apply pIntegral_remainder k p hk + apply pIntegral_faulhaber_sum k p hk intro m hm_pos hm_lt - exact (pIntegral_iff_not_dvd_den p _).2 (ih m hm_lt hm_pos) - exact (pIntegral_iff_not_dvd_den p _).1 (pIntegral_sub p T _ hT_int hR) + exact (pIntegral_iff_not_dvd p _).2 (ih m hm_lt hm_pos) + exact (pIntegral_iff_not_dvd p _).1 (pIntegral_sub p T _ hT_int hR) /-- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ -lemma von_staudt_sum_den_not_dvd_of_pos (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den := by - rw [sum_primes_eq_indicator_add_rest k p hk, ← add_assoc] + rw [sum_one_div_prime_eq_vonStaudtIndicator_div_add k p hk, ← add_assoc] have h₁ : p.Coprime (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := - (Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).2 - (bernoulli_plus_indicator_den_not_dvd_of_pos k p hk) + (Nat.Prime.coprime_iff_not_dvd Fact.out).2 + (bernoulli_add_vonStaudtIndicator_den_not_dvd k p hk) have h₂ : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q).den.Coprime p := Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) - (prod_den_coprime_p k p) + (prod_one_div_prime_den_coprime k p) have hcop : (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q).den.Coprime p := Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) (h₁.symm.mul_left h₂) - exact (Nat.Prime.coprime_iff_not_dvd (Fact.out : p.Prime)).1 hcop.symm + exact (Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm /-- **von Staudt-Clausen theorem:** For any natural number $k$, the sum $$B_{2k} + \sum_{p - 1 \mid 2k} \frac{1}{p}$$ is an integer. -/ -theorem von_staudt_clausen (k : ℕ) : +theorem vonStaudt_clausen (k : ℕ) : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast := by rcases Nat.eq_zero_or_pos k with rfl | hk · exact ⟨1, by decide +kernel⟩ - · exact Rat.mem_range_intCast_of_not_prime_dvd _ + · exact Rat.isInt_of_forall_prime_not_dvd_den _ (fun p hp ↦ by letI : Fact p.Prime := ⟨hp⟩ - exact von_staudt_sum_den_not_dvd_of_pos k p hk) + exact vonStaudt_sum_den_not_dvd k p hk) end vonStaudtClausen From ac94b94deceef535e0ece3776a415520a5f28fae Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Wed, 11 Mar 2026 07:58:43 -0700 Subject: [PATCH 41/70] minor --- Mathlib/NumberTheory/Bernoulli.lean | 43 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index e9c6dfe008cf50..23ab485faad3f6 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -467,15 +467,25 @@ lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : rw [Finset.sum_insert has, Finset.prod_insert has] exact dvd_trans (Rat.add_den_dvd (f a) (∑ x ∈ s, f x)) (mul_dvd_mul_left _ ih) +lemma pIntegral_add (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : + pIntegral p (x + y) := by + simpa [pIntegral] using (Rat.padicValuation p).map_add_le hx hy + +lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : + pIntegral p (x - y) := by + simpa [pIntegral] using (Rat.padicValuation p).map_sub_le hx hy + lemma pIntegral_sum {ι : Type*} (p : ℕ) [Fact p.Prime] (s : Finset ι) (f : ι → ℚ) (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := by - have hcop : (∑ i ∈ s, f i).den.Coprime p := Nat.Coprime.coprime_dvd_left (sum_den_dvd_prod_den s f) - (Nat.Coprime.prod_left fun i hi ↦ by - have hfi_not : ¬ p ∣ (f i).den := (pIntegral_iff_not_dvd p (f i)).1 (hf i hi) - exact ((Nat.Prime.coprime_iff_not_dvd Fact.out).2 hfi_not).symm) - exact (pIntegral_iff_not_dvd p _).2 ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm) + classical + induction s using Finset.induction_on with + | empty => simp [pIntegral_zero] + | @insert a s ha ih => + rw [Finset.sum_insert ha] + refine pIntegral_add p _ _ (hf a (Finset.mem_insert_self a s)) ?_ + exact ih (fun i hi ↦ hf i (Finset.mem_insert_of_mem hi)) -lemma pIntegral_intCast (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := +lemma pIntegral_ofInt (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := (pIntegral_iff_not_dvd p _).2 (by simpa using (Nat.Prime.not_dvd_one Fact.out)) lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : @@ -483,14 +493,6 @@ lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (h simp only [pIntegral, map_mul] at * exact mul_le_one' hx hy -lemma pIntegral_intCast_mul (p : ℕ) [Fact p.Prime] (x : ℚ) (z : ℤ) (hx : pIntegral p x) : - pIntegral p (z * x) := by - simpa [mul_comm] using pIntegral_mul p z x (pIntegral_intCast p z) hx - -lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : - pIntegral p (x - y) := by - simpa [pIntegral] using (Rat.padicValuation p).map_sub_le hx hy - /-- Denominators of the "other primes" part of the indicator sum stay coprime to a fixed prime `p`. -/ lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : @@ -576,7 +578,7 @@ lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : (-(2 : ℤ) ^ (2 * k - 2) : ℤ) := by have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by rw [← pow_succ]; lia rw [hpow]; push_cast; field_simp - simpa [h] using (pIntegral_intCast _ (z := (-(2 : ℤ) ^ (2 * k - 2)))) + simpa [h] using (pIntegral_ofInt _ (z := (-(2 : ℤ) ^ (2 * k - 2)))) · have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; lia field_simp [h2] rw [neg_div'] @@ -658,7 +660,8 @@ lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < k) : mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] /-- `p`-integrality of the core even-index summand after denominator normalization. -/ -lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (hd : 2 * k - 2 * m ≥ 2) : +lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] + (hd : 2 * k - 2 * m ≥ 2) : pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def @@ -673,7 +676,9 @@ lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] have h_eq : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ) = ((2 * k).choose (2 * m) : ℕ) * ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by ring rw [h_eq] - exact pIntegral_intCast_mul p _ _ h_pow_integral + have hchoose : pIntegral p ((2 * k).choose (2 * m) : ℚ) := by + simpa using (pIntegral_ofInt p ((2 * k).choose (2 * m))) + exact pIntegral_mul p _ _ hchoose h_pow_integral /-- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` to prove `p`-integrality of the even term. -/ @@ -724,7 +729,7 @@ lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] exact pow_succ' _ _ rw [hpow]; ring rw [hp_factor] - exact pIntegral_mul _ _ _ (pIntegral_intCast p p) (pIntegral_choose_mul_pow_div k m p hm_lt (by lia)) + exact pIntegral_mul _ _ _ (pIntegral_ofInt p p) (pIntegral_choose_mul_pow_div k m p hm_lt (by lia)) · unfold vonStaudtIndicator split_ifs with h · simp only [one_mul] @@ -836,7 +841,7 @@ lemma bernoulli_add_vonStaudtIndicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fac | _ k ih => obtain ⟨T, hT⟩ := bernoulli_add_vonStaudtIndicator_eq_sub k p hk rw [hT] - have hT_int : pIntegral p (T : ℚ) := pIntegral_intCast p T + have hT_int : pIntegral p (T : ℚ) := pIntegral_ofInt p T have hR : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by apply pIntegral_faulhaber_sum k p hk From b75cb0afbf39d62215b3c86a0bf3c20aa3aa8f69 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 21 Mar 2026 14:14:48 -0700 Subject: [PATCH 42/70] wip --- Mathlib/NumberTheory/Bernoulli.lean | 239 +++++++++++++++------------- 1 file changed, 130 insertions(+), 109 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 23ab485faad3f6..bc9ac293ab52f2 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -57,7 +57,7 @@ The proof of von Staudt-Clausen's theorem follows Rado's JLMS 1934 paper * `sum_bernoulli : ∑ k ∈ Finset.range n, (n.choose k : ℚ) * bernoulli k = if n = 1 then 1 else 0` -* `vonStaudt_clausen : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) +* `bernoulli.vonStaudt_clausen : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast` ## References @@ -412,22 +412,28 @@ $$B_{2k} + \sum_{p \text{ prime}, (p - 1) \mid 2k} \frac{1}{p} \in \mathbb{Z}.$$ Rado's proof is based on Faulhaber's theorem and induction on $k$. -/ +namespace bernoulli + /-- Indicator function that is `1` if `(p - 1) ∣ k` and `0` otherwise. -/ -noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1 : ℕ) ∣ k then 1 else 0 +private noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := + if (p - 1 : ℕ) ∣ k then 1 else 0 + +private lemma natCast_ne_zero_of_mem_filter_range {p v : ℕ} + (hv : v ∈ (Finset.range p).filter (· ≠ 0)) : (v : ZMod p) ≠ 0 := by + intro h + rcases Finset.mem_filter.mp hv with ⟨hv_range, hv_ne_zero⟩ + have hv_lt : v < p := Finset.mem_range.mp hv_range + have h1 : p ∣ v := (ZMod.natCast_eq_zero_iff v p).mp h + exact (Nat.not_le_of_lt hv_lt) (Nat.le_of_dvd (Nat.pos_of_ne_zero hv_ne_zero) h1) /-- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ -lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : +private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + (if (p - 1 : ℕ) ∣ l then (1 : ZMod p) else 0) = 0 := by - have cast_ne : ∀ v, v ∈ (Finset.range p).filter (· ≠ 0) → (v : ZMod p) ≠ 0 := by - intro v hv h - simp only [Finset.mem_filter, Finset.mem_range] at hv - have h1 : p ∣ v := (ZMod.natCast_eq_zero_iff v p).mp h - exact absurd (Nat.le_of_dvd (by lia) h1) (by lia) have hbij : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := Finset.sum_bij' - (fun v hv ↦ Units.mk0 (v : ZMod p) (cast_ne v hv)) + (fun v hv ↦ Units.mk0 (v : ZMod p) (natCast_ne_zero_of_mem_filter_range hv)) (fun u _ ↦ (u : ZMod p).val) (fun _ _ ↦ Finset.mem_univ _) (fun u _ ↦ by simp [ZMod.val_lt, u.ne_zero]) @@ -439,7 +445,8 @@ lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : grind /-- If a rational number is $p$-integral for all primes $p$, then it is an integer. -/ -lemma Rat.isInt_of_forall_prime_not_dvd_den (q : ℚ) (h : ∀ p : ℕ, p.Prime → ¬ p ∣ q.den) : +private lemma isInt_of_forall_prime_not_dvd_den (q : ℚ) + (h : ∀ p : ℕ, p.Prime → ¬ p ∣ q.den) : q ∈ Set.range Int.cast := by rw [Set.mem_range] refine ⟨q.num, Rat.coe_int_num_of_den_eq_one ?_⟩ @@ -447,18 +454,16 @@ lemma Rat.isInt_of_forall_prime_not_dvd_den (q : ℚ) (h : ∀ p : ℕ, p.Prime exact ne_one_iff_exists_prime_dvd.mp h /-- A rational number `x` is `p`-integral if `p` does not divide its denominator. -/ -def pIntegral (p : ℕ) (x : ℚ) [Fact p.Prime] : Prop := Rat.padicValuation p x ≤ 1 +private def pIntegral (p : ℕ) (x : ℚ) [Fact p.Prime] : Prop := Rat.padicValuation p x ≤ 1 -lemma pIntegral_iff_not_dvd (p : ℕ) (x : ℚ) [Fact p.Prime] : pIntegral p x ↔ ¬ p ∣ x.den := by +private lemma pIntegral_iff_not_dvd (p : ℕ) (x : ℚ) [Fact p.Prime] : + pIntegral p x ↔ ¬ p ∣ x.den := by simp only [pIntegral, Rat.padicValuation_le_one_iff] -lemma pIntegral_iff_padicValuation (p : ℕ) (x : ℚ) [Fact p.Prime] : - pIntegral p x ↔ Rat.padicValuation p x ≤ 1 := by rfl - -@[simp] lemma pIntegral_zero (p : ℕ) [Fact p.Prime] : pIntegral p (0 : ℚ) := +@[simp] private lemma pIntegral_zero (p : ℕ) [Fact p.Prime] : pIntegral p (0 : ℚ) := (pIntegral_iff_not_dvd p _).2 (by simpa using Nat.Prime.not_dvd_one Fact.out) -lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : +private lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by classical induction s using Finset.induction_on with @@ -467,15 +472,17 @@ lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : rw [Finset.sum_insert has, Finset.prod_insert has] exact dvd_trans (Rat.add_den_dvd (f a) (∑ x ∈ s, f x)) (mul_dvd_mul_left _ ih) -lemma pIntegral_add (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : +private lemma pIntegral_add (p : ℕ) [Fact p.Prime] (x y : ℚ) + (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x + y) := by simpa [pIntegral] using (Rat.padicValuation p).map_add_le hx hy -lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : +private lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) + (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x - y) := by simpa [pIntegral] using (Rat.padicValuation p).map_sub_le hx hy -lemma pIntegral_sum {ι : Type*} (p : ℕ) [Fact p.Prime] (s : Finset ι) (f : ι → ℚ) +private lemma pIntegral_sum {ι : Type*} (p : ℕ) [Fact p.Prime] (s : Finset ι) (f : ι → ℚ) (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := by classical induction s using Finset.induction_on with @@ -485,17 +492,18 @@ lemma pIntegral_sum {ι : Type*} (p : ℕ) [Fact p.Prime] (s : Finset ι) (f : refine pIntegral_add p _ _ (hf a (Finset.mem_insert_self a s)) ?_ exact ih (fun i hi ↦ hf i (Finset.mem_insert_of_mem hi)) -lemma pIntegral_ofInt (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := +private lemma pIntegral_ofInt (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := (pIntegral_iff_not_dvd p _).2 (by simpa using (Nat.Prime.not_dvd_one Fact.out)) -lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : +private lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) + (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := by simp only [pIntegral, map_mul] at * exact mul_le_one' hx hy /-- Denominators of the "other primes" part of the indicator sum stay coprime to a fixed prime `p`. -/ -lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : +private lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : (∏ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, ((1 : ℚ) / q).den).Coprime p := by apply Nat.Coprime.prod_left @@ -507,7 +515,7 @@ lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : /-- Splits the prime-indexed correction sum into the `p`-term (`vonStaudtIndicator / p`) plus the rest. -/ -lemma sum_one_div_prime_eq_vonStaudtIndicator_div_add (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [Fact p.Prime] : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by @@ -528,7 +536,7 @@ lemma sum_one_div_prime_eq_vonStaudtIndicator_div_add (k p : ℕ) (hk : k > 0) [ fun ⟨hpr, hd, _⟩ ↦ ⟨hpr, hd⟩⟩) fun _ _ ↦ rfl /-- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ -lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) +private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ)^N / M) := by set e := M.factorization p set M' := M / p ^ e with hM'_def @@ -554,14 +562,14 @@ lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm) /-- Basic valuation bound used for the `i = 0` term in the Faulhaber expansion. -/ -lemma factorization_succ_le (p n : ℕ) [Fact p.Prime] : (n + 1).factorization p ≤ n := +private lemma factorization_succ_le (p n : ℕ) [Fact p.Prime] : (n + 1).factorization p ≤ n := Nat.factorization_le_of_le_pow <| calc n + 1 = (n + 1).choose 1 := by simp _ ≤ 2 ^ n := Nat.choose_succ_le_two_pow n 1 _ ≤ p ^ n := Nat.pow_le_pow_left ((Fact.out : p.Prime).two_le) n /-- The `i = 0` Faulhaber term is `p`-integral. -/ -lemma pIntegral_pow_div_two_mul_succ (k p : ℕ) [Fact p.Prime] : +private lemma pIntegral_pow_div_two_mul_succ (k p : ℕ) [Fact p.Prime] : pIntegral p ((p : ℚ) ^ (2 * k) / (2 * k + 1)) := by have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by norm_cast rw [h] @@ -570,7 +578,7 @@ lemma pIntegral_pow_div_two_mul_succ (k p : ℕ) [Fact p.Prime] : · exact factorization_succ_le p (2 * k) /-- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ -lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by rw [bernoulli_one] obtain rfl | hp2 := eq_or_ne p 2 @@ -592,11 +600,11 @@ lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm) /-- The exceptional base case of the inequality argument (`p = 2`, `d = 2`). -/ -lemma factorization_two_three_le_one : (2 + 1).factorization 2 ≤ 2 - 1 := by +private lemma factorization_two_three_le_one : (2 + 1).factorization 2 ≤ 2 - 1 := by simp [Nat.factorization_eq_zero_of_not_dvd (show ¬(2 ∣ 3) by decide)] /-- Auxiliary growth inequality: for `d ≥ 3`, we have `d + 1 ≤ 2^(d - 1)`. -/ -lemma succ_le_two_pow_sub_one (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) := by +private lemma succ_le_two_pow_sub_one (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) := by have h : ∀ n : ℕ, n ≥ 3 → n + 1 ≤ 2 ^ (n - 1) := by intro n hn induction hn with @@ -606,11 +614,13 @@ lemma succ_le_two_pow_sub_one (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) : have h1 : 2 ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by lia) calc m + 1 + 1 ≤ 2 ^ (m - 1) + 1 := by lia _ ≤ 2 ^ (m - 1) * 2 := by nlinarith - _ = 2 ^ m := by conv_rhs => rw [show m = m - 1 + 1 by lia]; exact pow_succ .. + _ = 2 ^ m := by conv_rhs => + rw [show m = m - 1 + 1 by lia] + exact pow_succ .. exact h d hd /-- Auxiliary growth inequality: for `p ≥ 3` and `d ≥ 2`, we have `d + 1 ≤ p^(d - 1)`. -/ -lemma succ_le_pow_sub_one (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 ≤ p ^ (d - 1) := by +private lemma succ_le_pow_sub_one (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 ≤ p ^ (d - 1) := by have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by intro d hd induction hd with @@ -626,7 +636,7 @@ lemma succ_le_pow_sub_one (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 ≤ exact h2 d hd /-- Main valuation estimate behind the contradiction step for even-index summands. -/ -lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : +private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by obtain hp2 | hp3 := (Fact.out : p.Prime).eq_two_or_odd · subst hp2 @@ -642,7 +652,7 @@ lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : · exact hd /-- Rewrites the binomial coefficient denominator exactly as in Rado's summand. -/ -lemma choose_two_mul_succ_div_eq (k m : ℕ) (hm_lt : m < k) : +private lemma choose_two_mul_succ_div_eq (k m : ℕ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia)] @@ -652,7 +662,7 @@ lemma choose_two_mul_succ_div_eq (k m : ℕ) (hm_lt : m < k) : grind /-- Multiplicative variant of `choose_two_mul_succ_div_eq`. -/ -lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < k) : +private lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) * x / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) * x / (2 * k - 2 * m + 1) := by have h := choose_two_mul_succ_div_eq k m hm_lt @@ -660,7 +670,7 @@ lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < k) : mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] /-- `p`-integrality of the core even-index summand after denominator normalization. -/ -lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] +private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (hd : 2 * k - 2 * m ≥ 2) : pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by @@ -682,7 +692,7 @@ lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] /-- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` to prove `p`-integrality of the even term. -/ -lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] +private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by @@ -729,7 +739,8 @@ lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] exact pow_succ' _ _ rw [hpow]; ring rw [hp_factor] - exact pIntegral_mul _ _ _ (pIntegral_ofInt p p) (pIntegral_choose_mul_pow_div k m p hm_lt (by lia)) + exact pIntegral_mul _ _ _ (pIntegral_ofInt p p) + (pIntegral_choose_mul_pow_div k m p hm_lt (by lia)) · unfold vonStaudtIndicator split_ifs with h · simp only [one_mul] @@ -738,7 +749,7 @@ lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] · simp /-- The full remainder sum in Faulhaber's formula is `p`-integral. -/ -lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] +private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by @@ -759,87 +770,95 @@ lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] exact pIntegral_bernoulli_even_term k m p hm_lt (ih m (by lia) hm_lt) · simp [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; lia)] +private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : + ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + + vonStaudtIndicator (2 * k) p = p * T := by + -- Get divisibility in ℤ from the ZMod result + have ⟨T, hT⟩ : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + + (if (p - 1 : ℕ) ∣ 2 * k then 1 else 0) = p * T := by + have : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + + (if (p - 1 : ℕ) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := by + push_cast; exact sum_pow_add_indicator_eq_zero p (2 * k) + exact (ZMod.intCast_zmod_eq_zero_iff_dvd _ _).mp this + refine ⟨T, ?_⟩ + have : vonStaudtIndicator (2 * k) p = + ((if (p - 1 : ℕ) ∣ 2 * k then (1 : ℤ) else 0) : ℚ) := by + by_cases hd : (p - 1 : ℕ) ∣ 2 * k <;> simp [vonStaudtIndicator, hd] + rw [this]; exact_mod_cast hT + +private lemma sum_range_pow_eq_sum_range_filter_ne_zero (k p : ℕ) (hk : 0 < k) : + (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = + ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by + have hpow : 2 * k ≠ 0 := by lia + rw [Finset.sum_filter] + refine Finset.sum_congr rfl ?_ + intro v hv + by_cases hv0 : v = 0 + · subst hv0 + simp [hpow] + · simp [hv0] + +private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : + (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = + (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by + rw [← sum_range_pow_eq_sum_range_filter_ne_zero k p hk] + simp only [sum_range_pow] + push_cast + rw [Finset.sum_range_succ] + congr 1 + have hchoose : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by + rw [← Nat.choose_symm_of_eq_add (by lia : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] + rw [hchoose, show (2 * k + 1 - 2 * k : ℕ) = 1 by lia, pow_one] + have hdenom : (2 * k + 1 : ℚ) ≠ 0 := by positivity + norm_cast + field_simp [hdenom] + +private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : + (∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = + ∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by + have h1 : ∀ i ∈ Finset.range (2 * k), ((bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = + (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k - i) / + (2 * k + 1 : ℚ) := by + intro i hi + have hi' : i < 2 * k := Finset.mem_range.mp hi + have hp_ne : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero Fact.out + rw [show (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 by lia, pow_succ] + field_simp [hp_ne] + rw [Finset.sum_div] + exact Finset.sum_congr rfl fun i hi ↦ h1 i hi + /-- Rearranges the Faulhaber identity and power-sum congruence to isolate `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ -lemma bernoulli_add_vonStaudtIndicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by - have hDiv : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + - (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0) = p * T := by - have h_cast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + - (if (p - 1 : ℕ) ∣ (2 * k) then 1 else 0)) : ZMod p) = 0 := by - push_cast; exact sum_pow_add_indicator_eq_zero p (2 * k) - rw [ZMod.intCast_zmod_eq_zero_iff_dvd] at h_cast; exact h_cast - obtain ⟨T, hT⟩ := hDiv + obtain ⟨T, hT⟩ := exists_int_sum_pow_add_indicator_eq k p use T - have hT' : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + - vonStaudtIndicator (2 * k) p = p * T := by - have hsum : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) = - ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by norm_cast - have hind : ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = - vonStaudtIndicator (2 * k) p := by - by_cases hd : (p - 1 : ℕ) ∣ (2 * k) <;> simp [vonStaudtIndicator, hd] - have hTq : ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + - ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) = (p : ℚ) * T := by - norm_cast at hT ⊢ - calc - (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = - ((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) : ℚ) + - ((if (p - 1 : ℕ) ∣ (2 * k) then (1 : ℤ) else (0 : ℤ)) : ℚ) := by - rw [← hsum, ← hind] - _ = (p : ℚ) * T := by exact hTq - _ = p * T := by simp have hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by - have hfilter : (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by - conv_lhs => - arg 2; ext v - rw [show (v : ℚ) ^ (2 * k) = if v ≠ 0 then (v : ℚ) ^ (2 * k) else 0 by - split_ifs with h - · rfl - · simp [show v = 0 by lia, show 2 * k ≠ 0 by lia]] - rw [Finset.sum_filter] - rw [← hfilter] - simp only [sum_range_pow]; push_cast - rw [Finset.sum_range_succ] - congr 1 - have h1 : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by - rw [← Nat.choose_symm_of_eq_add (by lia : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] - rw [h1, show (2 * k + 1 - 2 * k : ℕ) = 1 by lia, pow_one] - have h4 : (2 * k + 1 : ℚ) ≠ 0 := by positivity - norm_cast; field_simp [h4] + (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * + (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := + sum_pow_filter_eq_faulhaber k p hk + have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast (Fact.out : p.Prime).ne_zero have hAlg : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by - have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast (Fact.out : p.Prime).ne_zero - field_simp [hp_ne]; linarith - rw [hAlg]; congr 1 - have h0 : (∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = - ∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * - (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by - have h1 : ∀ i ∈ Finset.range (2 * k), ((bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = - (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k - i) / - (2 * k + 1 : ℚ) := by - intro i hi - have h2 : i < 2 * k := Finset.mem_range.mp hi - have h5 : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero Fact.out - rw [show (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 by lia, pow_succ] - field_simp [h5] - rw [Finset.sum_div] - exact Finset.sum_congr rfl fun i hi ↦ h1 i hi - exact_mod_cast h0 + field_simp [hp_ne] + linarith [hT, hFaul] + rw [hAlg] + congr 1 + simpa using faulhaber_sum_div_prime_eq k p /-- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ -lemma bernoulli_add_vonStaudtIndicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := by induction k using Nat.strong_induction_on with | _ k ih => - obtain ⟨T, hT⟩ := bernoulli_add_vonStaudtIndicator_eq_sub k p hk + obtain ⟨T, hT⟩ := bernoulli_add_indicator_eq_sub k p hk rw [hT] have hT_int : pIntegral p (T : ℚ) := pIntegral_ofInt p T have hR : pIntegral p (∑ i ∈ Finset.range (2 * k), @@ -850,13 +869,13 @@ lemma bernoulli_add_vonStaudtIndicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fac exact (pIntegral_iff_not_dvd p _).1 (pIntegral_sub p T _ hT_int hR) /-- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ -lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den := by - rw [sum_one_div_prime_eq_vonStaudtIndicator_div_add k p hk, ← add_assoc] + rw [sum_one_div_prime_eq_indicator_div_add k p hk, ← add_assoc] have h₁ : p.Coprime (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := (Nat.Prime.coprime_iff_not_dvd Fact.out).2 - (bernoulli_add_vonStaudtIndicator_den_not_dvd k p hk) + (bernoulli_add_indicator_den_not_dvd k p hk) have h₂ : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q).den.Coprime p := Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) (prod_one_div_prime_den_coprime k p) @@ -874,9 +893,11 @@ theorem vonStaudt_clausen (k : ℕ) : (1 : ℚ) / p ∈ Set.range Int.cast := by rcases Nat.eq_zero_or_pos k with rfl | hk · exact ⟨1, by decide +kernel⟩ - · exact Rat.isInt_of_forall_prime_not_dvd_den _ + · exact isInt_of_forall_prime_not_dvd_den _ (fun p hp ↦ by letI : Fact p.Prime := ⟨hp⟩ exact vonStaudt_sum_den_not_dvd k p hk) +end bernoulli + end vonStaudtClausen From db3cd3333b97641b74dd39f099297318548661b1 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Mon, 6 Apr 2026 22:53:57 -0700 Subject: [PATCH 43/70] refactor: inline single-use helper lemmas in von Staudt-Clausen proof Inline 11 single-use private lemmas into their sole callers, reducing the von Staudt-Clausen proof section by 76 lines without changing the proof strategy. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 178 ++++++++-------------------- 1 file changed, 51 insertions(+), 127 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 7cfd8424384430..e6a80d9be80dcd 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -415,14 +415,6 @@ namespace bernoulli private noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1 : ℕ) ∣ k then 1 else 0 -private lemma natCast_ne_zero_of_mem_filter_range {p v : ℕ} - (hv : v ∈ (Finset.range p).filter (· ≠ 0)) : (v : ZMod p) ≠ 0 := by - intro h - rcases Finset.mem_filter.mp hv with ⟨hv_range, hv_ne_zero⟩ - have hv_lt : v < p := Finset.mem_range.mp hv_range - have h1 : p ∣ v := (ZMod.natCast_eq_zero_iff v p).mp h - exact (Nat.not_le_of_lt hv_lt) (Nat.le_of_dvd (Nat.pos_of_ne_zero hv_ne_zero) h1) - /-- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + @@ -430,7 +422,10 @@ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : have hbij : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := Finset.sum_bij' - (fun v hv ↦ Units.mk0 (v : ZMod p) (natCast_ne_zero_of_mem_filter_range hv)) + (fun v hv ↦ Units.mk0 (v : ZMod p) (by + obtain ⟨hlt, hne⟩ := Finset.mem_filter.mp hv + exact fun h ↦ absurd (Nat.le_of_dvd (Nat.pos_of_ne_zero hne) + ((ZMod.natCast_eq_zero_iff v p).mp h)) (Nat.not_le_of_lt (Finset.mem_range.mp hlt)))) (fun u _ ↦ (u : ZMod p).val) (fun _ _ ↦ Finset.mem_univ _) (fun u _ ↦ by simp [ZMod.val_lt, u.ne_zero]) @@ -441,15 +436,6 @@ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : rw [hbij, FiniteField.sum_pow_units, ZMod.card] grind -/-- If a rational number is $p$-integral for all primes $p$, then it is an integer. -/ -private lemma isInt_of_forall_prime_not_dvd_den (q : ℚ) - (h : ∀ p : ℕ, p.Prime → ¬ p ∣ q.den) : - q ∈ Set.range Int.cast := by - rw [Set.mem_range] - refine ⟨q.num, Rat.coe_int_num_of_den_eq_one ?_⟩ - contrapose! h - exact ne_one_iff_exists_prime_dvd.mp h - /-- A rational number `x` is `p`-integral if `p` does not divide its denominator. -/ private def pIntegral (p : ℕ) (x : ℚ) [Fact p.Prime] : Prop := Rat.padicValuation p x ≤ 1 @@ -457,9 +443,6 @@ private lemma pIntegral_iff_not_dvd (p : ℕ) (x : ℚ) [Fact p.Prime] : pIntegral p x ↔ ¬ p ∣ x.den := by simp only [pIntegral, Rat.padicValuation_le_one_iff] -@[simp] private lemma pIntegral_zero (p : ℕ) [Fact p.Prime] : pIntegral p (0 : ℚ) := - (pIntegral_iff_not_dvd p _).2 (by simpa using Nat.Prime.not_dvd_one Fact.out) - private lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by classical @@ -469,11 +452,6 @@ private lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) rw [Finset.sum_insert has, Finset.prod_insert has] exact dvd_trans (Rat.add_den_dvd (f a) (∑ x ∈ s, f x)) (mul_dvd_mul_left _ ih) -private lemma pIntegral_add (p : ℕ) [Fact p.Prime] (x y : ℚ) - (hx : pIntegral p x) (hy : pIntegral p y) : - pIntegral p (x + y) := by - simpa [pIntegral] using (Rat.padicValuation p).map_add_le hx hy - private lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x - y) := by @@ -483,11 +461,12 @@ private lemma pIntegral_sum {ι : Type*} (p : ℕ) [Fact p.Prime] (s : Finset ι (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := by classical induction s using Finset.induction_on with - | empty => simp [pIntegral_zero] + | empty => simp [pIntegral] | @insert a s ha ih => - rw [Finset.sum_insert ha] - refine pIntegral_add p _ _ (hf a (Finset.mem_insert_self a s)) ?_ - exact ih (fun i hi ↦ hf i (Finset.mem_insert_of_mem hi)) + simp only [Finset.sum_insert ha, pIntegral] + exact (Rat.padicValuation p).map_add_le + (hf a (Finset.mem_insert_self a s)) + (ih (fun i hi ↦ hf i (Finset.mem_insert_of_mem hi))) private lemma pIntegral_ofInt (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := (pIntegral_iff_not_dvd p _).2 (by simpa using (Nat.Prime.not_dvd_one Fact.out)) @@ -558,22 +537,6 @@ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) exact (pIntegral_iff_not_dvd p _).2 ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm) -/-- Basic valuation bound used for the `i = 0` term in the Faulhaber expansion. -/ -private lemma factorization_succ_le (p n : ℕ) [Fact p.Prime] : (n + 1).factorization p ≤ n := - Nat.factorization_le_of_le_pow <| - calc n + 1 = (n + 1).choose 1 := by simp - _ ≤ 2 ^ n := Nat.choose_succ_le_two_pow n 1 - _ ≤ p ^ n := Nat.pow_le_pow_left ((Fact.out : p.Prime).two_le) n - -/-- The `i = 0` Faulhaber term is `p`-integral. -/ -private lemma pIntegral_pow_div_two_mul_succ (k p : ℕ) [Fact p.Prime] : - pIntegral p ((p : ℚ) ^ (2 * k) / (2 * k + 1)) := by - have h : (2 * k + 1 : ℚ) = ↑(2 * k + 1) := by norm_cast - rw [h] - apply pIntegral_pow_div p (2 * k + 1) (2 * k) - · lia - · exact factorization_succ_le p (2 * k) - /-- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by @@ -596,73 +559,37 @@ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prim exact (pIntegral_iff_not_dvd p _).2 ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm) -/-- The exceptional base case of the inequality argument (`p = 2`, `d = 2`). -/ -private lemma factorization_two_three_le_one : (2 + 1).factorization 2 ≤ 2 - 1 := by - simp [Nat.factorization_eq_zero_of_not_dvd (show ¬(2 ∣ 3) by decide)] - -/-- Auxiliary growth inequality: for `d ≥ 3`, we have `d + 1 ≤ 2^(d - 1)`. -/ -private lemma succ_le_two_pow_sub_one (d : ℕ) (hd : d ≥ 3) : d + 1 ≤ 2 ^ (d - 1) := by - have h : ∀ n : ℕ, n ≥ 3 → n + 1 ≤ 2 ^ (n - 1) := by - intro n hn - induction hn with - | refl => norm_num - | @step m hm IH => - have hm : (3 : ℕ) ≤ m := hm - have h1 : 2 ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by lia) - calc m + 1 + 1 ≤ 2 ^ (m - 1) + 1 := by lia - _ ≤ 2 ^ (m - 1) * 2 := by nlinarith - _ = 2 ^ m := by conv_rhs => - rw [show m = m - 1 + 1 by lia] - exact pow_succ .. - exact h d hd - -/-- Auxiliary growth inequality: for `p ≥ 3` and `d ≥ 2`, we have `d + 1 ≤ p^(d - 1)`. -/ -private lemma succ_le_pow_sub_one (p d : ℕ) (hp : 3 ≤ p) (hd : d ≥ 2) : d + 1 ≤ p ^ (d - 1) := by - have h2 : ∀ d : ℕ, d ≥ 2 → d + 1 ≤ p ^ (d - 1) := by - intro d hd - induction hd with - | refl => norm_num; lia - | @step m hm IH => - have hm : (2 : ℕ) ≤ m := hm - calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by lia - _ ≤ p ^ (m - 1) * p := by - have : p ^ (m - 1) ≥ 1 := Nat.one_le_pow _ _ (by lia) - nlinarith - _ = p ^ m := by - conv_rhs => rw [show m = m - 1 + 1 by lia]; exact pow_succ .. - exact h2 d hd - /-- Main valuation estimate behind the contradiction step for even-index summands. -/ private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by - obtain hp2 | hp3 := (Fact.out : p.Prime).eq_two_or_odd - · subst hp2 - obtain rfl | hd3 := eq_or_lt_of_le hd - · exact factorization_two_three_le_one - · apply Nat.factorization_le_of_le_pow - exact succ_le_two_pow_sub_one _ hd3 - · apply Nat.factorization_le_of_le_pow - apply succ_le_pow_sub_one - · have hne2 : p ≠ 2 := fun h ↦ by simp [h] at hp3 - have h1lt : 1 < p := (Fact.out : p.Prime).one_lt - lia - · exact hd - -/-- Rewrites the binomial coefficient denominator exactly as in Rado's summand. -/ -private lemma choose_two_mul_succ_div_eq (k m : ℕ) (hm_lt : m < k) : - ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = - ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by - rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia)] - conv_rhs => norm_cast; rw [Nat.choose_mul_succ_eq] - rw [show 2 * (k : ℚ) - 2 * (m : ℚ) = 2 * (k - m : ℕ) by rw [cast_sub hm_lt.le]; ring] - norm_cast - grind - -/-- Multiplicative variant of `choose_two_mul_succ_div_eq`. -/ + -- Special case: p = 2, d = 2 (since 3 is not divisible by 2) + obtain ⟨rfl, rfl⟩ | hne : (p = 2 ∧ d = 2) ∨ ¬(p = 2 ∧ d = 2) := by tauto + · simp [Nat.factorization_eq_zero_of_not_dvd (show ¬(2 ∣ 3) by decide)] + · -- For all other prime p and d ≥ 2, we have d + 1 ≤ p^(d-1) + apply Nat.factorization_le_of_le_pow + have hp2 := (Fact.out : p.Prime).two_le + suffices ∀ n : ℕ, n ≥ 2 → ¬(p = 2 ∧ n = 2) → n + 1 ≤ p ^ (n - 1) from this d hd hne + intro n hn hne' + induction hn with + | refl => norm_num at hne' ⊢; omega + | @step m hm IH => + by_cases hm2 : p = 2 ∧ m = 2 + · obtain ⟨rfl, rfl⟩ := hm2; norm_num + · calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by linarith [IH hm2] + _ ≤ p ^ (m - 1) * p := by nlinarith [Nat.one_le_pow (m - 1) p (by lia)] + _ = p ^ m := by rw [show m = m - 1 + 1 by lia]; exact pow_succ .. + +/-- Multiplicative variant of the binomial coefficient denominator rewrite +as in Rado's summand. -/ private lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) * x / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) * x / (2 * k - 2 * m + 1) := by - have h := choose_two_mul_succ_div_eq k m hm_lt + have h : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = + ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by + rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia)] + conv_rhs => norm_cast; rw [Nat.choose_mul_succ_eq] + rw [show 2 * (k : ℚ) - 2 * (m : ℚ) = 2 * (k - m : ℕ) by rw [cast_sub hm_lt.le]; ring] + norm_cast; grind rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] @@ -743,7 +670,7 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact · simp only [one_mul] rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt] exact pIntegral_choose_mul_pow_div k m p hm_lt (by lia) - · simp + · simp only [zero_mul, zero_div, pIntegral, map_zero]; exact bot_le /-- The full remainder sum in Faulhaber's formula is `p`-integral. -/ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] @@ -755,7 +682,11 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] rw [Finset.mem_range] at hi rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] - exact pIntegral_pow_div_two_mul_succ k p + rw [show (2 * k + 1 : ℚ) = ↑(2 * k + 1) from by norm_cast] + exact pIntegral_pow_div p (2 * k + 1) (2 * k) (by lia) + (Nat.factorization_le_of_le_pow <| calc 2 * k + 1 = (2 * k + 1).choose 1 := by simp + _ ≤ 2 ^ (2 * k) := Nat.choose_succ_le_two_pow _ 1 + _ ≤ p ^ (2 * k) := Nat.pow_le_pow_left (Fact.out : p.Prime).two_le _) · simp only [zero_add, Nat.choose_one_right] convert pIntegral_bernoulli_one_term k p hk using 1 push_cast; field_simp @@ -765,7 +696,8 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] · have ⟨_, hm_lt, hj_eq⟩ : m ≥ 1 ∧ m < k ∧ j = 2 * m := by lia simp only [hj_eq] exact pIntegral_bernoulli_even_term k m p hm_lt (ih m (by lia) hm_lt) - · simp [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; lia)] + · simp only [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; lia), + zero_mul, zero_div, pIntegral, map_zero]; exact bot_le private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + @@ -783,23 +715,14 @@ private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : by_cases hd : (p - 1 : ℕ) ∣ 2 * k <;> simp [vonStaudtIndicator, hd] rw [this]; exact_mod_cast hT -private lemma sum_range_pow_eq_sum_range_filter_ne_zero (k p : ℕ) (hk : 0 < k) : - (∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k) := by - have hpow : 2 * k ≠ 0 := by lia - rw [Finset.sum_filter] - refine Finset.sum_congr rfl ?_ - intro v hv - by_cases hv0 : v = 0 - · subst hv0 - simp [hpow] - · simp [hv0] - private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by - rw [← sum_range_pow_eq_sum_range_filter_ne_zero k p hk] + rw [show (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = + ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) from by + rw [Finset.sum_filter]; exact Finset.sum_congr rfl fun v _ ↦ by + by_cases hv : v = 0 <;> simp [hv, show 2 * k ≠ 0 by lia]] simp only [sum_range_pow] push_cast rw [Finset.sum_range_succ] @@ -890,10 +813,11 @@ theorem vonStaudt_clausen (k : ℕ) : (1 : ℚ) / p ∈ Set.range Int.cast := by rcases Nat.eq_zero_or_pos k with rfl | hk · exact ⟨1, by decide +kernel⟩ - · exact isInt_of_forall_prime_not_dvd_den _ - (fun p hp ↦ by - letI : Fact p.Prime := ⟨hp⟩ - exact vonStaudt_sum_den_not_dvd k p hk) + · rw [Set.mem_range] + refine ⟨_, Rat.coe_int_num_of_den_eq_one ?_⟩ + by_contra h + obtain ⟨p, hp, hdvd⟩ := ne_one_iff_exists_prime_dvd.mp h + exact absurd hdvd (by letI : Fact p.Prime := ⟨hp⟩; exact vonStaudt_sum_den_not_dvd k p hk) end bernoulli From 9462b047d8bba9aa0438cd9c9de14d669a52c0ed Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Mon, 6 Apr 2026 23:10:19 -0700 Subject: [PATCH 44/70] refactor: shorten verbose proofs in von Staudt-Clausen Compress four proofs by using field_simp/ring, inlining intermediates, and chaining rewrites: pIntegral_bernoulli_even_term (-18 lines), faulhaber_sum_div_prime_eq (-6), sum_pow_filter_eq_faulhaber (-5), pIntegral_pow_div (-6). Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 97 +++++++++-------------------- 1 file changed, 31 insertions(+), 66 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index e6a80d9be80dcd..a46e3f4e68e5f0 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -514,28 +514,21 @@ private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [F /-- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ)^N / M) := by - set e := M.factorization p - set M' := M / p ^ e with hM'_def - have hM'_ne : M' ≠ 0 := (Nat.ordCompl_pos p hM).ne' + set e := M.factorization p; set M' := M / p ^ e have hM'_cop : M'.Coprime p := (Nat.coprime_ordCompl Fact.out hM).symm + have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero Fact.out) -- Rewrite p^N / M as p^(N-e) / M' where M' = M / p^e is coprime to p have hdecomp : p ^ e * M' = M := Nat.ordProj_mul_ordCompl_eq_self M p - have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero Fact.out) - have hpe_ne : (p : ℚ) ^ e ≠ 0 := pow_ne_zero e hp_ne have hrw : (p : ℚ) ^ N / M = (p : ℚ) ^ (N - e) / M' := by - have hM_cast : (M : ℚ) = (p ^ e : ℕ) * (M' : ℕ) := by rw [← hdecomp]; simp - rw [hM_cast, div_mul_eq_div_div] - congr 1 - · rw [Nat.cast_pow, div_eq_iff hpe_ne, ← pow_add, Nat.sub_add_cancel hv] + rw [show (M : ℚ) = (p ^ e : ℕ) * (M' : ℕ) by rw [← hdecomp]; simp, + Nat.cast_pow, div_mul_eq_div_div]; congr 1 + rw [div_eq_iff (pow_ne_zero e hp_ne), ← pow_add, Nat.sub_add_cancel hv] rw [hrw] - have hdvd : ((p : ℚ) ^ (N - e) / M').den ∣ M' := by - have h1 : ((p : ℚ) ^ (N - e) / M') = Rat.divInt (p ^ (N - e) : ℤ) (M' : ℤ) := by - norm_cast; simp - rw [h1] - exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _) - have hcop : ((p : ℚ) ^ (N - e) / M').den.Coprime p := hM'_cop.coprime_dvd_left hdvd - exact (pIntegral_iff_not_dvd p _).2 - ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm) + exact (pIntegral_iff_not_dvd p _).2 ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 + (hM'_cop.coprime_dvd_left (by + rw [show ((p : ℚ) ^ (N - e) / (M' : ℚ)) = Rat.divInt (p ^ (N - e) : ℤ) (M' : ℤ) by + norm_cast; simp] + exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _))).symm) /-- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : @@ -620,31 +613,18 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by + have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero Fact.out) + set P := (p : ℚ) ^ (2 * k - 2 * m - 1) + have hpow : (p : ℚ) ^ (2 * k - 2 * m) = P * p := by + conv_lhs => rw [show 2 * k - 2 * m = (2 * k - 2 * m - 1) + 1 by lia, pow_succ] have hdecomp : (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) : ℚ) = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k + 1) := by - simp only [show 2 * k - 2 * m = 2 * (k - m) by lia] - have h : bernoulli (2 * m) * (p : ℚ) ^ (2 * (k - m)) = - (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * (p : ℚ) ^ (2 * (k - m)) - - vonStaudtIndicator (2 * m) p * (p : ℚ) ^ (2 * (k - m) - 1) := by - have hpow : (p : ℚ) ^ (2 * (k - m)) = (p : ℚ) ^ (2 * (k - m) - 1) * p := by - conv_lhs => rw [show 2 * (k - m) = (2 * (k - m) - 1) + 1 by lia, pow_succ] - rcases eq_or_ne (p : ℚ) 0 with hp0 | hp0 - · simp [hp0, zero_pow (show 2 * (k - m) - 1 ≠ 0 by lia)] - · rw [hpow]; field_simp [hp0]; ring - set C := ((2 * k + 1).choose (2 * m) : ℚ) - set N := (2 * k + 1 : ℚ) - calc bernoulli (2 * m) * C * (p : ℚ) ^ (2 * (k - m)) / N - = (bernoulli (2 * m) * (p : ℚ) ^ (2 * (k - m))) * C / N := by ring - _ = ((bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / ↑p) * - (p : ℚ) ^ (2 * (k - m)) - - vonStaudtIndicator (2 * m) p * (p : ℚ) ^ (2 * (k - m) - 1)) * - C / N := by rw [h] - _ = _ := by ring + P / (2 * k + 1) := by + rw [hpow]; field_simp [hp_ne]; ring rw [hdecomp] apply pIntegral_sub · rw [show (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * @@ -653,16 +633,9 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) by ring] apply pIntegral_mul _ _ _ ih - rw [choose_two_mul_succ_mul_div_eq k m ((p : ℚ) ^ (2 * k - 2 * m)) hm_lt] - have hp_factor : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / - (2 * k - 2 * m + 1) = (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * - (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by - have hpow : (p : ℚ) ^ (2 * k - 2 * m) = (p : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) := by - conv_lhs => - rw [show (2 * k - 2 * m : ℕ) = (2 * k - 2 * m - 1) + 1 by lia] - exact pow_succ' _ _ - rw [hpow]; ring - rw [hp_factor] + rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt, + show ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k - 2 * m + 1) = + (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * P / (2 * k - 2 * m + 1)) by rw [hpow]; ring] exact pIntegral_mul _ _ _ (pIntegral_ofInt p p) (pIntegral_choose_mul_pow_div k m p hm_lt (by lia)) · unfold vonStaudtIndicator @@ -682,7 +655,7 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] rw [Finset.mem_range] at hi rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] - rw [show (2 * k + 1 : ℚ) = ↑(2 * k + 1) from by norm_cast] + rw [show (2 * k + 1 : ℚ) = ↑(2 * k + 1) by norm_cast] exact pIntegral_pow_div p (2 * k + 1) (2 * k) (by lia) (Nat.factorization_le_of_le_pow <| calc 2 * k + 1 = (2 * k + 1).choose 1 := by simp _ ≤ 2 ^ (2 * k) := Nat.choose_succ_le_two_pow _ 1 @@ -720,36 +693,28 @@ private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by rw [show (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) from by + ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) by rw [Finset.sum_filter]; exact Finset.sum_congr rfl fun v _ ↦ by - by_cases hv : v = 0 <;> simp [hv, show 2 * k ≠ 0 by lia]] - simp only [sum_range_pow] + by_cases hv : v = 0 <;> simp [hv, show 2 * k ≠ 0 by lia], + sum_range_pow, Finset.sum_range_succ] push_cast - rw [Finset.sum_range_succ] congr 1 - have hchoose : (2 * k + 1).choose (2 * k) = 2 * k + 1 := by - rw [← Nat.choose_symm_of_eq_add (by lia : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right] - rw [hchoose, show (2 * k + 1 - 2 * k : ℕ) = 1 by lia, pow_one] - have hdenom : (2 * k + 1 : ℚ) ≠ 0 := by positivity - norm_cast - field_simp [hdenom] + rw [show (2 * k + 1).choose (2 * k) = 2 * k + 1 by + rw [← Nat.choose_symm_of_eq_add (by lia : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right], + show (2 * k + 1 - 2 * k : ℕ) = 1 by lia, pow_one] + push_cast; field_simp [show (2 * k + 1 : ℚ) ≠ 0 by positivity] private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : (∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = ∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by - have h1 : ∀ i ∈ Finset.range (2 * k), ((bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = - (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k - i) / - (2 * k + 1 : ℚ) := by - intro i hi - have hi' : i < 2 * k := Finset.mem_range.mp hi - have hp_ne : (p : ℚ) ≠ 0 := by norm_cast; exact Nat.Prime.ne_zero Fact.out + have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast (Fact.out : p.Prime).ne_zero + rw [Finset.sum_div] + exact Finset.sum_congr rfl fun i hi ↦ by + have := Finset.mem_range.mp hi rw [show (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 by lia, pow_succ] field_simp [hp_ne] - rw [Finset.sum_div] - exact Finset.sum_congr rfl fun i hi ↦ h1 i hi /-- Rearranges the Faulhaber identity and power-sum congruence to isolate `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ From 2e45cb032519175ae8bcbf1e9f5142690da341d1 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Mon, 6 Apr 2026 23:24:58 -0700 Subject: [PATCH 45/70] refactor: use shorter tactics in von Staudt-Clausen proof Replace pIntegral_sum induction with Valuation.map_sum_le, use Nat.choose_succ_self_right, positivity, omega, and inline intermediate hypotheses in several lemmas. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 82 ++++++++++------------------- 1 file changed, 28 insertions(+), 54 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index a46e3f4e68e5f0..1a9d1a7bb4e5eb 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -453,27 +453,18 @@ private lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) exact dvd_trans (Rat.add_den_dvd (f a) (∑ x ∈ s, f x)) (mul_dvd_mul_left _ ih) private lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) - (hx : pIntegral p x) (hy : pIntegral p y) : - pIntegral p (x - y) := by + (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x - y) := by simpa [pIntegral] using (Rat.padicValuation p).map_sub_le hx hy private lemma pIntegral_sum {ι : Type*} (p : ℕ) [Fact p.Prime] (s : Finset ι) (f : ι → ℚ) - (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := by - classical - induction s using Finset.induction_on with - | empty => simp [pIntegral] - | @insert a s ha ih => - simp only [Finset.sum_insert ha, pIntegral] - exact (Rat.padicValuation p).map_add_le - (hf a (Finset.mem_insert_self a s)) - (ih (fun i hi ↦ hf i (Finset.mem_insert_of_mem hi))) + (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := + (Rat.padicValuation p).map_sum_le hf private lemma pIntegral_ofInt (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := (pIntegral_iff_not_dvd p _).2 (by simpa using (Nat.Prime.not_dvd_one Fact.out)) private lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) - (hx : pIntegral p x) (hy : pIntegral p y) : - pIntegral p (x * y) := by + (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := by simp only [pIntegral, map_mul] at * exact mul_le_one' hx hy @@ -485,7 +476,7 @@ private lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : apply Nat.Coprime.prod_left intro q hq have h1 : q.Prime := (Finset.mem_filter.mp hq).2.1 - have h2 : ((1 : ℚ) / q).den = q := by have := Nat.Prime.ne_zero h1; simp_all + have h2 : ((1 : ℚ) / q).den = q := by simp [h1.ne_zero] rw [h2] exact (Nat.coprime_primes h1 Fact.out).mpr (Finset.mem_filter.mp hq).2.2.2 @@ -540,7 +531,7 @@ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prim have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by rw [← pow_succ]; lia rw [hpow]; push_cast; field_simp simpa [h] using (pIntegral_ofInt _ (z := (-(2 : ℤ) ^ (2 * k - 2)))) - · have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by norm_cast; lia + · have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by positivity field_simp [h2] rw [neg_div'] have hdvd : (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by @@ -567,7 +558,8 @@ private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d | refl => norm_num at hne' ⊢; omega | @step m hm IH => by_cases hm2 : p = 2 ∧ m = 2 - · obtain ⟨rfl, rfl⟩ := hm2; norm_num + · obtain ⟨rfl, rfl⟩ := hm2 + norm_num · calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by linarith [IH hm2] _ ≤ p ^ (m - 1) * p := by nlinarith [Nat.one_le_pow (m - 1) p (by lia)] _ = p ^ m := by rw [show m = m - 1 + 1 by lia]; exact pow_succ .. @@ -597,15 +589,10 @@ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat] - have h_pow_integral : pIntegral p ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by - apply pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero - exact factorization_succ_le_sub_one p d hd - have h_eq : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ) = - ((2 * k).choose (2 * m) : ℕ) * ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) := by ring - rw [h_eq] - have hchoose : pIntegral p ((2 * k).choose (2 * m) : ℚ) := by - simpa using (pIntegral_ofInt p ((2 * k).choose (2 * m))) - exact pIntegral_mul p _ _ hchoose h_pow_integral + rw [show ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ) = + ((2 * k).choose (2 * m) : ℕ) * ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) by ring] + exact pIntegral_mul p _ _ (by exact_mod_cast pIntegral_ofInt p ((2 * k).choose (2 * m))) + (pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero (factorization_succ_le_sub_one p d hd)) /-- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` to prove `p`-integrality of the even term. -/ @@ -655,21 +642,18 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] rw [Finset.mem_range] at hi rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] - rw [show (2 * k + 1 : ℚ) = ↑(2 * k + 1) by norm_cast] - exact pIntegral_pow_div p (2 * k + 1) (2 * k) (by lia) + exact_mod_cast pIntegral_pow_div p (2 * k + 1) (2 * k) (by lia) (Nat.factorization_le_of_le_pow <| calc 2 * k + 1 = (2 * k + 1).choose 1 := by simp _ ≤ 2 ^ (2 * k) := Nat.choose_succ_le_two_pow _ 1 _ ≤ p ^ (2 * k) := Nat.pow_le_pow_left (Fact.out : p.Prime).two_le _) · simp only [zero_add, Nat.choose_one_right] convert pIntegral_bernoulli_one_term k p hk using 1 push_cast; field_simp - · set j := i + 2 with hj_def - have hj_lt : j < 2 * k := by lia - rcases Nat.even_or_odd j with ⟨m, hm⟩ | hodd - · have ⟨_, hm_lt, hj_eq⟩ : m ≥ 1 ∧ m < k ∧ j = 2 * m := by lia - simp only [hj_eq] + · rcases Nat.even_or_odd (i + 2) with ⟨m, hm⟩ | hodd + · have hm_lt : m < k := by lia + simp only [show i + 2 = 2 * m by lia] exact pIntegral_bernoulli_even_term k m p hm_lt (ih m (by lia) hm_lt) - · simp only [bernoulli_eq_zero_of_odd hodd (by rcases hodd with ⟨r, hr⟩; lia), + · simp only [bernoulli_eq_zero_of_odd hodd (by omega), zero_mul, zero_div, pIntegral, map_zero]; exact bot_le private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : @@ -699,9 +683,7 @@ private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : sum_range_pow, Finset.sum_range_succ] push_cast congr 1 - rw [show (2 * k + 1).choose (2 * k) = 2 * k + 1 by - rw [← Nat.choose_symm_of_eq_add (by lia : 2 * k + 1 = 1 + 2 * k), Nat.choose_one_right], - show (2 * k + 1 - 2 * k : ℕ) = 1 by lia, pow_one] + rw [Nat.choose_succ_self_right, show (2 * k + 1 - 2 * k : ℕ) = 1 by omega, pow_one] push_cast; field_simp [show (2 * k + 1 : ℚ) ≠ 0 by positivity] private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : @@ -709,7 +691,7 @@ private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = ∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by - have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast (Fact.out : p.Prime).ne_zero + have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero rw [Finset.sum_div] exact Finset.sum_congr rfl fun i hi ↦ by have := Finset.mem_range.mp hi @@ -728,15 +710,12 @@ private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Pr (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := sum_pow_filter_eq_faulhaber k p hk - have hp_ne : (p : ℚ) ≠ 0 := by exact_mod_cast (Fact.out : p.Prime).ne_zero + have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero have hAlg : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by - field_simp [hp_ne] - linarith [hT, hFaul] - rw [hAlg] - congr 1 - simpa using faulhaber_sum_div_prime_eq k p + field_simp [hp_ne]; linarith [hT, hFaul] + rw [hAlg]; congr 1; simpa using faulhaber_sum_div_prime_eq k p /-- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : @@ -758,17 +737,12 @@ private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den := by rw [sum_one_div_prime_eq_indicator_div_add k p hk, ← add_assoc] - have h₁ : p.Coprime (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := - (Nat.Prime.coprime_iff_not_dvd Fact.out).2 - (bernoulli_add_indicator_den_not_dvd k p hk) - have h₂ : (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, - (1 : ℚ) / q).den.Coprime p := Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) - (prod_one_div_prime_den_coprime k p) - have hcop : (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p + - ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, - (1 : ℚ) / q).den.Coprime p := Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) - (h₁.symm.mul_left h₂) - exact (Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm + exact (Nat.Prime.coprime_iff_not_dvd Fact.out).1 + (Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) + (((Nat.Prime.coprime_iff_not_dvd Fact.out).2 + (bernoulli_add_indicator_den_not_dvd k p hk)).symm.mul_left + (Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) + (prod_one_div_prime_den_coprime k p)))).symm /-- **von Staudt-Clausen theorem:** For any natural number $k$, the sum $$B_{2k} + \sum_{p - 1 \mid 2k} \frac{1}{p}$$ is an integer. From 9a99e15b108fa00d093dafbbf2c636799e7bc8a9 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Mon, 6 Apr 2026 23:35:57 -0700 Subject: [PATCH 46/70] refactor: shorten pIntegral_bernoulli_one_term and pIntegral_bernoulli_even_term In the odd prime case, reuse pIntegral_pow_div instead of manually tracking denominator divisibility and coprimality. Factor out pIntegral_choose_mul_pow_div to avoid duplication across branches, and use mul_assoc/mul_div_assoc instead of verbose show-by-ring. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 47 +++++++++++------------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 1a9d1a7bb4e5eb..eddd92be114079 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -531,17 +531,15 @@ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prim have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by rw [← pow_succ]; lia rw [hpow]; push_cast; field_simp simpa [h] using (pIntegral_ofInt _ (z := (-(2 : ℤ) ^ (2 * k - 2)))) - · have h2 : ((2 * k : ℕ) : ℚ) ≠ 0 := by positivity - field_simp [h2] - rw [neg_div'] - have hdvd : (-(p : ℚ) ^ (2 * k - 1) / 2).den ∣ 2 := by - rw [neg_div, Rat.den_neg_eq_den, ← Nat.cast_pow] - conv_lhs => rw [show (2 : ℚ) = (2 : ℕ) from rfl, Rat.natCast_div_eq_divInt] - exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _) - have hcop : (-(p : ℚ) ^ (2 * k - 1) / 2).den.Coprime p := Nat.Coprime.of_dvd_left hdvd - (Odd.coprime_two_left ((Fact.out : p.Prime).odd_of_ne_two hp2)) - exact (pIntegral_iff_not_dvd p _).2 - ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop.symm) + · have hrw : (-1 / 2 : ℚ) * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = + (-1 : ℤ) * ((p : ℚ) ^ (2 * k - 1) / 2) := by + field_simp [show ((2 * k : ℕ) : ℚ) ≠ 0 by positivity]; push_cast; ring + rw [hrw] + exact pIntegral_mul p _ _ (by exact_mod_cast pIntegral_ofInt p (-1)) + (pIntegral_pow_div p 2 (2 * k - 1) two_ne_zero (by + rw [Nat.factorization_eq_zero_of_not_dvd (fun h ↦ by + have := Nat.le_of_dvd two_pos h; have := (Fact.out : p.Prime).two_le; omega)] + exact Nat.zero_le _)) /-- Main valuation estimate behind the contradiction step for even-index summands. -/ private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : @@ -604,32 +602,23 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact set P := (p : ℚ) ^ (2 * k - 2 * m - 1) have hpow : (p : ℚ) ^ (2 * k - 2 * m) = P * p := by conv_lhs => rw [show 2 * k - 2 * m = (2 * k - 2 * m - 1) + 1 by lia, pow_succ] - have hdecomp : (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) : ℚ) = + have hdecomp : bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * + (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - + ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) - vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * - P / (2 * k + 1) := by - rw [hpow]; field_simp [hp_ne]; ring + P / (2 * k + 1) := by rw [hpow]; field_simp [hp_ne]; ring rw [hdecomp] + have hcmp := pIntegral_choose_mul_pow_div k m p hm_lt (by lia) apply pIntegral_sub - · rw [show (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * - ((2 * k + 1).choose (2 * m)) * - (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = - (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * - (((2 * k + 1).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) by ring] + · rw [mul_assoc, mul_div_assoc] apply pIntegral_mul _ _ _ ih rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt, show ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k - 2 * m + 1) = (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * P / (2 * k - 2 * m + 1)) by rw [hpow]; ring] - exact pIntegral_mul _ _ _ (pIntegral_ofInt p p) - (pIntegral_choose_mul_pow_div k m p hm_lt (by lia)) - · unfold vonStaudtIndicator - split_ifs with h - · simp only [one_mul] - rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt] - exact pIntegral_choose_mul_pow_div k m p hm_lt (by lia) + exact pIntegral_mul _ _ _ (pIntegral_ofInt p p) hcmp + · unfold vonStaudtIndicator; split_ifs + · simp only [one_mul]; rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt]; exact hcmp · simp only [zero_mul, zero_div, pIntegral, map_zero]; exact bot_le /-- The full remainder sum in Faulhaber's formula is `p`-integral. -/ From fc7e1ebd4ba4d555be1657344dad05f6dfe90f7b Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Mon, 6 Apr 2026 23:46:39 -0700 Subject: [PATCH 47/70] style: remove redundant type casts in von Staudt-Clausen proof MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecessary `: ℕ` annotations on expressions already in ℕ (e.g., `(p - 1 : ℕ)` → `(p - 1)`, `(2 * k + 1 - i : ℕ)` → `2 * k + 1 - i`), redundant `: ℤ` on ℤ expressions, `(bernoulli i : ℚ)` where `bernoulli` already returns ℚ, and similar. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index eddd92be114079..8c5dde6f99e77c 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -413,12 +413,12 @@ namespace bernoulli /-- Indicator function that is `1` if `(p - 1) ∣ k` and `0` otherwise. -/ private noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := - if (p - 1 : ℕ) ∣ k then 1 else 0 + if (p - 1) ∣ k then 1 else 0 /-- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + - (if (p - 1 : ℕ) ∣ l then (1 : ZMod p) else 0) = 0 := by + (if (p - 1) ∣ l then (1 : ZMod p) else 0) = 0 := by have hbij : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := Finset.sum_bij' @@ -486,7 +486,7 @@ private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [F (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by - by_cases hdvd : (p - 1 : ℕ) ∣ 2 * k + by_cases hdvd : (p - 1) ∣ 2 * k · -- p is in the filtered set; extract its term have hp_mem : p ∈ (Finset.range (2 * k + 2)).filter (fun q ↦ q.Prime ∧ (q - 1) ∣ 2 * k) := by simp only [Finset.mem_filter, Finset.mem_range] @@ -511,7 +511,7 @@ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) -- Rewrite p^N / M as p^(N-e) / M' where M' = M / p^e is coprime to p have hdecomp : p ^ e * M' = M := Nat.ordProj_mul_ordCompl_eq_self M p have hrw : (p : ℚ) ^ N / M = (p : ℚ) ^ (N - e) / M' := by - rw [show (M : ℚ) = (p ^ e : ℕ) * (M' : ℕ) by rw [← hdecomp]; simp, + rw [show (M : ℚ) = ↑(p ^ e) * ↑M' by rw [← hdecomp]; simp, Nat.cast_pow, div_mul_eq_div_div]; congr 1 rw [div_eq_iff (pow_ne_zero e hp_ne), ← pow_add, Nat.sub_add_cancel hv] rw [hrw] @@ -527,13 +527,13 @@ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prim rw [bernoulli_one] obtain rfl | hp2 := eq_or_ne p 2 · have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = - (-(2 : ℤ) ^ (2 * k - 2) : ℤ) := by + -(2 : ℤ) ^ (2 * k - 2) := by have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by rw [← pow_succ]; lia rw [hpow]; push_cast; field_simp - simpa [h] using (pIntegral_ofInt _ (z := (-(2 : ℤ) ^ (2 * k - 2)))) + simpa [h] using pIntegral_ofInt _ (-(2 : ℤ) ^ (2 * k - 2)) · have hrw : (-1 / 2 : ℚ) * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = (-1 : ℤ) * ((p : ℚ) ^ (2 * k - 1) / 2) := by - field_simp [show ((2 * k : ℕ) : ℚ) ≠ 0 by positivity]; push_cast; ring + field_simp [show (2 * k : ℚ) ≠ 0 by positivity]; push_cast; ring rw [hrw] exact pIntegral_mul p _ _ (by exact_mod_cast pIntegral_ofInt p (-1)) (pIntegral_pow_div p 2 (2 * k - 1) two_ne_zero (by @@ -588,7 +588,7 @@ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat] rw [show ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ) = - ((2 * k).choose (2 * m) : ℕ) * ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) by ring] + (2 * k).choose (2 * m) * ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) by ring] exact pIntegral_mul p _ _ (by exact_mod_cast pIntegral_ofInt p ((2 * k).choose (2 * m))) (pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero (factorization_succ_le_sub_one p d hd)) @@ -650,15 +650,15 @@ private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : vonStaudtIndicator (2 * k) p = p * T := by -- Get divisibility in ℤ from the ZMod result have ⟨T, hT⟩ : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + - (if (p - 1 : ℕ) ∣ 2 * k then 1 else 0) = p * T := by + (if (p - 1) ∣ 2 * k then 1 else 0) = p * T := by have : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + - (if (p - 1 : ℕ) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := by + (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := by push_cast; exact sum_pow_add_indicator_eq_zero p (2 * k) exact (ZMod.intCast_zmod_eq_zero_iff_dvd _ _).mp this refine ⟨T, ?_⟩ have : vonStaudtIndicator (2 * k) p = - ((if (p - 1 : ℕ) ∣ 2 * k then (1 : ℤ) else 0) : ℚ) := by - by_cases hd : (p - 1 : ℕ) ∣ 2 * k <;> simp [vonStaudtIndicator, hd] + ((if (p - 1) ∣ 2 * k then (1 : ℤ) else 0) : ℚ) := by + by_cases hd : (p - 1) ∣ 2 * k <;> simp [vonStaudtIndicator, hd] rw [this]; exact_mod_cast hT private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : @@ -672,19 +672,19 @@ private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : sum_range_pow, Finset.sum_range_succ] push_cast congr 1 - rw [Nat.choose_succ_self_right, show (2 * k + 1 - 2 * k : ℕ) = 1 by omega, pow_one] + rw [Nat.choose_succ_self_right, show 2 * k + 1 - 2 * k = 1 by omega, pow_one] push_cast; field_simp [show (2 * k + 1 : ℚ) ≠ 0 by positivity] private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : - (∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = - ∑ i ∈ Finset.range (2 * k), (bernoulli i : ℚ) * ((2 * k + 1).choose i : ℚ) * + ∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero rw [Finset.sum_div] exact Finset.sum_congr rfl fun i hi ↦ by have := Finset.mem_range.mp hi - rw [show (2 * k + 1 - i : ℕ) = (2 * k - i : ℕ) + 1 by lia, pow_succ] + rw [show 2 * k + 1 - i = (2 * k - i) + 1 by lia, pow_succ] field_simp [hp_ne] /-- Rearranges the Faulhaber identity and power-sum congruence to isolate From 83e659351abc9e630abbca3a492fdb2de8054718 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Tue, 7 Apr 2026 00:44:22 -0700 Subject: [PATCH 48/70] refactor: use fewer, more powerful tactics in von Staudt-Clausen proof Simplify bijection forward map using `mt` + `Nat.not_dvd_of_pos_of_lt`, replace `rw [show ... by ring]` with `mul_div_assoc`, inline single-use `have` statements, use `push_cast; ring` instead of `norm_cast; grind`, and remove unnecessary `conv_lhs`. Co-Authored-By: Claude Opus 4.6 --- Mathlib/NumberTheory/Bernoulli.lean | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 8c5dde6f99e77c..3aa5c0ae6fe461 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -422,15 +422,13 @@ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : have hbij : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := Finset.sum_bij' - (fun v hv ↦ Units.mk0 (v : ZMod p) (by + (fun v hv ↦ Units.mk0 (v : ZMod p) (mt (ZMod.natCast_eq_zero_iff v p).mp (by obtain ⟨hlt, hne⟩ := Finset.mem_filter.mp hv - exact fun h ↦ absurd (Nat.le_of_dvd (Nat.pos_of_ne_zero hne) - ((ZMod.natCast_eq_zero_iff v p).mp h)) (Nat.not_le_of_lt (Finset.mem_range.mp hlt)))) + exact Nat.not_dvd_of_pos_of_lt (Nat.pos_of_ne_zero hne) (Finset.mem_range.mp hlt)))) (fun u _ ↦ (u : ZMod p).val) (fun _ _ ↦ Finset.mem_univ _) (fun u _ ↦ by simp [ZMod.val_lt, u.ne_zero]) - (fun v hv ↦ by - simp [ZMod.val_cast_of_lt (Finset.mem_range.mp (Finset.mem_filter.mp hv).1)]) + (fun v hv ↦ by simp [ZMod.val_cast_of_lt (Finset.mem_range.mp (Finset.mem_filter.mp hv).1)]) (fun u _ ↦ Units.ext (ZMod.natCast_zmod_val _)) (fun _ _ ↦ rfl) rw [hbij, FiniteField.sum_pow_units, ZMod.card] @@ -528,8 +526,7 @@ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prim obtain rfl | hp2 := eq_or_ne p 2 · have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = -(2 : ℤ) ^ (2 * k - 2) := by - have hpow : (2 : ℚ) ^ (2 * k - 1) = (2 : ℚ) ^ (2 * k - 2) * 2 := by rw [← pow_succ]; lia - rw [hpow]; push_cast; field_simp + rw [show 2 * k - 1 = (2 * k - 2) + 1 by omega, pow_succ]; push_cast; field_simp simpa [h] using pIntegral_ofInt _ (-(2 : ℤ) ^ (2 * k - 2)) · have hrw : (-1 / 2 : ℚ) * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = (-1 : ℤ) * ((p : ℚ) ^ (2 * k - 1) / 2) := by @@ -571,8 +568,7 @@ private lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia)] conv_rhs => norm_cast; rw [Nat.choose_mul_succ_eq] - rw [show 2 * (k : ℚ) - 2 * (m : ℚ) = 2 * (k - m : ℕ) by rw [cast_sub hm_lt.le]; ring] - norm_cast; grind + push_cast [Nat.cast_sub (show 2 * m ≤ 2 * k + 1 by lia)]; ring rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] @@ -586,9 +582,7 @@ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p d ≠ 0 ∧ d + 1 ≠ 0 ∧ 2 * k - 2 * m - 1 = d - 1 ∧ 2 * m ≤ 2 * k := by lia have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring - rw [h_exp, h_denom_rat] - rw [show ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ) = - (2 * k).choose (2 * m) * ((p : ℚ) ^ (d - 1) / ((d + 1 : ℕ) : ℚ)) by ring] + rw [h_exp, h_denom_rat, mul_div_assoc] exact pIntegral_mul p _ _ (by exact_mod_cast pIntegral_ofInt p ((2 * k).choose (2 * m))) (pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero (factorization_succ_le_sub_one p d hd)) @@ -601,7 +595,7 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero Fact.out) set P := (p : ℚ) ^ (2 * k - 2 * m - 1) have hpow : (p : ℚ) ^ (2 * k - 2 * m) = P * p := by - conv_lhs => rw [show 2 * k - 2 * m = (2 * k - 2 * m - 1) + 1 by lia, pow_succ] + rw [show 2 * k - 2 * m = (2 * k - 2 * m - 1) + 1 by lia, pow_succ] have hdecomp : bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * @@ -658,7 +652,7 @@ private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : refine ⟨T, ?_⟩ have : vonStaudtIndicator (2 * k) p = ((if (p - 1) ∣ 2 * k then (1 : ℤ) else 0) : ℚ) := by - by_cases hd : (p - 1) ∣ 2 * k <;> simp [vonStaudtIndicator, hd] + unfold vonStaudtIndicator; split_ifs <;> simp rw [this]; exact_mod_cast hT private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : @@ -695,15 +689,11 @@ private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Pr bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by obtain ⟨T, hT⟩ := exists_int_sum_pow_add_indicator_eq k p use T - have hFaul : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * - (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := - sum_pow_filter_eq_faulhaber k p hk have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero have hAlg : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by - field_simp [hp_ne]; linarith [hT, hFaul] + field_simp [hp_ne]; linarith [hT, sum_pow_filter_eq_faulhaber k p hk] rw [hAlg]; congr 1; simpa using faulhaber_sum_div_prime_eq k p /-- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ From 7f53e32be426b2089fc71991317cb11dae0e4743 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Thu, 16 Apr 2026 10:25:48 -0700 Subject: [PATCH 49/70] more golfs --- Mathlib/NumberTheory/Bernoulli.lean | 88 ++++++++++++++++------------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 3aa5c0ae6fe461..7cf83a2af414bb 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -503,39 +503,44 @@ private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [F /-- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ)^N / M) := by - set e := M.factorization p; set M' := M / p ^ e + set e := M.factorization p + set M' := M / p ^ e have hM'_cop : M'.Coprime p := (Nat.coprime_ordCompl Fact.out hM).symm have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero Fact.out) -- Rewrite p^N / M as p^(N-e) / M' where M' = M / p^e is coprime to p have hdecomp : p ^ e * M' = M := Nat.ordProj_mul_ordCompl_eq_self M p + have hM_eq : (M : ℚ) = ↑(p ^ e) * ↑M' := by rw [← hdecomp]; simp have hrw : (p : ℚ) ^ N / M = (p : ℚ) ^ (N - e) / M' := by - rw [show (M : ℚ) = ↑(p ^ e) * ↑M' by rw [← hdecomp]; simp, - Nat.cast_pow, div_mul_eq_div_div]; congr 1 + rw [hM_eq, Nat.cast_pow, div_mul_eq_div_div] + congr 1 rw [div_eq_iff (pow_ne_zero e hp_ne), ← pow_add, Nat.sub_add_cancel hv] + have hM'_eq : ((p : ℚ) ^ (N - e) / (M' : ℚ)) = Rat.divInt (p ^ (N - e) : ℤ) (M' : ℤ) := by + norm_cast + simp rw [hrw] exact (pIntegral_iff_not_dvd p _).2 ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 (hM'_cop.coprime_dvd_left (by - rw [show ((p : ℚ) ^ (N - e) / (M' : ℚ)) = Rat.divInt (p ^ (N - e) : ℤ) (M' : ℤ) by - norm_cast; simp] - exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _))).symm) + rw [hM'_eq]; exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _))).symm) /-- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by rw [bernoulli_one] obtain rfl | hp2 := eq_or_ne p 2 - · have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = + · have hsub : 2 * k - 1 = (2 * k - 2) + 1 := by lia + have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = -(2 : ℤ) ^ (2 * k - 2) := by - rw [show 2 * k - 1 = (2 * k - 2) + 1 by omega, pow_succ]; push_cast; field_simp + rw [hsub, pow_succ]; push_cast; field_simp simpa [h] using pIntegral_ofInt _ (-(2 : ℤ) ^ (2 * k - 2)) - · have hrw : (-1 / 2 : ℚ) * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = + · have hk_ne : (2 * k : ℚ) ≠ 0 := by positivity + have hrw : (-1 / 2 : ℚ) * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = (-1 : ℤ) * ((p : ℚ) ^ (2 * k - 1) / 2) := by - field_simp [show (2 * k : ℚ) ≠ 0 by positivity]; push_cast; ring + field_simp [hk_ne]; push_cast; ring rw [hrw] exact pIntegral_mul p _ _ (by exact_mod_cast pIntegral_ofInt p (-1)) (pIntegral_pow_div p 2 (2 * k - 1) two_ne_zero (by rw [Nat.factorization_eq_zero_of_not_dvd (fun h ↦ by - have := Nat.le_of_dvd two_pos h; have := (Fact.out : p.Prime).two_le; omega)] + have := Nat.le_of_dvd two_pos h; have := (Fact.out : p.Prime).two_le; lia)] exact Nat.zero_le _)) /-- Main valuation estimate behind the contradiction step for even-index summands. -/ @@ -543,21 +548,22 @@ private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d (d + 1).factorization p ≤ d - 1 := by -- Special case: p = 2, d = 2 (since 3 is not divisible by 2) obtain ⟨rfl, rfl⟩ | hne : (p = 2 ∧ d = 2) ∨ ¬(p = 2 ∧ d = 2) := by tauto - · simp [Nat.factorization_eq_zero_of_not_dvd (show ¬(2 ∣ 3) by decide)] + · simp [Nat.factorization_eq_zero_of_not_dvd (by decide : ¬(2 ∣ 3))] · -- For all other prime p and d ≥ 2, we have d + 1 ≤ p^(d-1) apply Nat.factorization_le_of_le_pow have hp2 := (Fact.out : p.Prime).two_le suffices ∀ n : ℕ, n ≥ 2 → ¬(p = 2 ∧ n = 2) → n + 1 ≤ p ^ (n - 1) from this d hd hne intro n hn hne' induction hn with - | refl => norm_num at hne' ⊢; omega + | refl => norm_num at hne' ⊢; lia | @step m hm IH => by_cases hm2 : p = 2 ∧ m = 2 · obtain ⟨rfl, rfl⟩ := hm2 norm_num - · calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by linarith [IH hm2] + · have hm_eq : m = m - 1 + 1 := by lia + calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by linarith [IH hm2] _ ≤ p ^ (m - 1) * p := by nlinarith [Nat.one_le_pow (m - 1) p (by lia)] - _ = p ^ m := by rw [show m = m - 1 + 1 by lia]; exact pow_succ .. + _ = p ^ m := by rw [hm_eq]; exact pow_succ .. /-- Multiplicative variant of the binomial coefficient denominator rewrite as in Rado's summand. -/ @@ -566,9 +572,10 @@ private lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < ((2 * k).choose (2 * m) : ℚ) * x / (2 * k - 2 * m + 1) := by have h : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by + have hm_le : 2 * m ≤ 2 * k + 1 := by lia rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia)] conv_rhs => norm_cast; rw [Nat.choose_mul_succ_eq] - push_cast [Nat.cast_sub (show 2 * m ≤ 2 * k + 1 by lia)]; ring + push_cast [Nat.cast_sub hm_le]; ring rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] @@ -595,7 +602,7 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero Fact.out) set P := (p : ℚ) ^ (2 * k - 2 * m - 1) have hpow : (p : ℚ) ^ (2 * k - 2 * m) = P * p := by - rw [show 2 * k - 2 * m = (2 * k - 2 * m - 1) + 1 by lia, pow_succ] + rw [(by lia : 2 * k - 2 * m = (2 * k - 2 * m - 1) + 1), pow_succ] have hdecomp : bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * @@ -607,9 +614,11 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact apply pIntegral_sub · rw [mul_assoc, mul_div_assoc] apply pIntegral_mul _ _ _ ih - rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt, - show ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k - 2 * m + 1) = - (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * P / (2 * k - 2 * m + 1)) by rw [hpow]; ring] + have hpow_mul : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / + (2 * k - 2 * m + 1) = + (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * P / (2 * k - 2 * m + 1)) := by + rw [hpow]; ring + rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt, hpow_mul] exact pIntegral_mul _ _ _ (pIntegral_ofInt p p) hcmp · unfold vonStaudtIndicator; split_ifs · simp only [one_mul]; rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt]; exact hcmp @@ -633,10 +642,10 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] convert pIntegral_bernoulli_one_term k p hk using 1 push_cast; field_simp · rcases Nat.even_or_odd (i + 2) with ⟨m, hm⟩ | hodd - · have hm_lt : m < k := by lia - simp only [show i + 2 = 2 * m by lia] - exact pIntegral_bernoulli_even_term k m p hm_lt (ih m (by lia) hm_lt) - · simp only [bernoulli_eq_zero_of_odd hodd (by omega), + · have ⟨hm_pos, hm_lt, hi_eq⟩ : 0 < m ∧ m < k ∧ i + 2 = 2 * m := by lia + simp only [hi_eq] + exact pIntegral_bernoulli_even_term k m p hm_lt (ih m hm_pos hm_lt) + · simp only [bernoulli_eq_zero_of_odd hodd (by lia), zero_mul, zero_div, pIntegral, map_zero]; exact bot_le private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : @@ -659,15 +668,17 @@ private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by - rw [show (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) by + have hfilter : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = + ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) := by rw [Finset.sum_filter]; exact Finset.sum_congr rfl fun v _ ↦ by - by_cases hv : v = 0 <;> simp [hv, show 2 * k ≠ 0 by lia], - sum_range_pow, Finset.sum_range_succ] + by_cases hv : v = 0 <;> simp [hv, (by lia : 2 * k ≠ 0)] + have hsub : 2 * k + 1 - 2 * k = 1 := by lia + have hne : (2 * k + 1 : ℚ) ≠ 0 := by positivity + rw [hfilter, sum_range_pow, Finset.sum_range_succ] push_cast congr 1 - rw [Nat.choose_succ_self_right, show 2 * k + 1 - 2 * k = 1 by omega, pow_one] - push_cast; field_simp [show (2 * k + 1 : ℚ) ≠ 0 by positivity] + rw [Nat.choose_succ_self_right, hsub, pow_one] + push_cast; field_simp [hne] private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * @@ -677,8 +688,9 @@ private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero rw [Finset.sum_div] exact Finset.sum_congr rfl fun i hi ↦ by - have := Finset.mem_range.mp hi - rw [show 2 * k + 1 - i = (2 * k - i) + 1 by lia, pow_succ] + have hi_lt := Finset.mem_range.mp hi + have hsub : 2 * k + 1 - i = (2 * k - i) + 1 := by lia + rw [hsub, pow_succ] field_simp [hp_ne] /-- Rearranges the Faulhaber identity and power-sum congruence to isolate @@ -716,12 +728,12 @@ private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den := by rw [sum_one_div_prime_eq_indicator_div_add k p hk, ← add_assoc] - exact (Nat.Prime.coprime_iff_not_dvd Fact.out).1 - (Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) - (((Nat.Prime.coprime_iff_not_dvd Fact.out).2 - (bernoulli_add_indicator_den_not_dvd k p hk)).symm.mul_left - (Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) - (prod_one_div_prime_den_coprime k p)))).symm + have hcop_ind := ((Nat.Prime.coprime_iff_not_dvd Fact.out).2 + (bernoulli_add_indicator_den_not_dvd k p hk)).symm + have hcop_rest := Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) + (prod_one_div_prime_den_coprime k p) + have hcop := (Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) (hcop_ind.mul_left hcop_rest)).symm + exact (Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop /-- **von Staudt-Clausen theorem:** For any natural number $k$, the sum $$B_{2k} + \sum_{p - 1 \mid 2k} \frac{1}{p}$$ is an integer. From a8bf2db95a4ce7c3ae427f9ccb64854c71745ca8 Mon Sep 17 00:00:00 2001 From: Seewoo Lee <49933279+seewoo5@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:20:53 -0700 Subject: [PATCH 50/70] Apply suggestions from code review Co-authored-by: Michael Stoll <99838730+MichaelStollBayreuth@users.noreply.github.com> --- Mathlib/NumberTheory/Bernoulli.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 7cf83a2af414bb..3cec04d70d916d 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -411,7 +411,7 @@ Rado's proof is based on Faulhaber's theorem and induction on $k$. namespace bernoulli -/-- Indicator function that is `1` if `(p - 1) ∣ k` and `0` otherwise. -/ +/- Indicator function that is `1` if `(p - 1) ∣ k` and `0` otherwise. -/ private noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1) ∣ k then 1 else 0 @@ -502,7 +502,7 @@ private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [F /-- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) - (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ)^N / M) := by + (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ) ^ N / M) := by set e := M.factorization p set M' := M / p ^ e have hM'_cop : M'.Coprime p := (Nat.coprime_ordCompl Fact.out hM).symm @@ -747,7 +747,7 @@ theorem vonStaudt_clausen (k : ℕ) : refine ⟨_, Rat.coe_int_num_of_den_eq_one ?_⟩ by_contra h obtain ⟨p, hp, hdvd⟩ := ne_one_iff_exists_prime_dvd.mp h - exact absurd hdvd (by letI : Fact p.Prime := ⟨hp⟩; exact vonStaudt_sum_den_not_dvd k p hk) + exact absurd hdvd (by let : Fact p.Prime := ⟨hp⟩; exact vonStaudt_sum_den_not_dvd k p hk) end bernoulli From 19b7ee059c7085eafb399974773d85a9db22d57a Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Tue, 21 Apr 2026 14:21:49 -0700 Subject: [PATCH 51/70] renaming --- Mathlib/NumberTheory/Bernoulli.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 3cec04d70d916d..727a55270a4cec 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -441,7 +441,7 @@ private lemma pIntegral_iff_not_dvd (p : ℕ) (x : ℚ) [Fact p.Prime] : pIntegral p x ↔ ¬ p ∣ x.den := by simp only [pIntegral, Rat.padicValuation_le_one_iff] -private lemma sum_den_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : +private lemma den_sum_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by classical induction s using Finset.induction_on with @@ -730,7 +730,7 @@ private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] rw [sum_one_div_prime_eq_indicator_div_add k p hk, ← add_assoc] have hcop_ind := ((Nat.Prime.coprime_iff_not_dvd Fact.out).2 (bernoulli_add_indicator_den_not_dvd k p hk)).symm - have hcop_rest := Nat.Coprime.of_dvd_left (sum_den_dvd_prod_den _ _) + have hcop_rest := Nat.Coprime.of_dvd_left (den_sum_dvd_prod_den _ _) (prod_one_div_prime_den_coprime k p) have hcop := (Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) (hcop_ind.mul_left hcop_rest)).symm exact (Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop From 64379e7c59f53feec603b92b5da25e24f0735af2 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Tue, 21 Apr 2026 14:50:36 -0700 Subject: [PATCH 52/70] pIntegral as abbrev --- Mathlib/NumberTheory/Bernoulli.lean | 46 ++++++++++------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 727a55270a4cec..234cad7410d148 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -435,11 +435,7 @@ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : grind /-- A rational number `x` is `p`-integral if `p` does not divide its denominator. -/ -private def pIntegral (p : ℕ) (x : ℚ) [Fact p.Prime] : Prop := Rat.padicValuation p x ≤ 1 - -private lemma pIntegral_iff_not_dvd (p : ℕ) (x : ℚ) [Fact p.Prime] : - pIntegral p x ↔ ¬ p ∣ x.den := by - simp only [pIntegral, Rat.padicValuation_le_one_iff] +private abbrev pIntegral (p : ℕ) (x : ℚ) [Fact p.Prime] : Prop := Rat.padicValuation p x ≤ 1 private lemma den_sum_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by @@ -450,21 +446,9 @@ private lemma den_sum_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) rw [Finset.sum_insert has, Finset.prod_insert has] exact dvd_trans (Rat.add_den_dvd (f a) (∑ x ∈ s, f x)) (mul_dvd_mul_left _ ih) -private lemma pIntegral_sub (p : ℕ) [Fact p.Prime] (x y : ℚ) - (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x - y) := by - simpa [pIntegral] using (Rat.padicValuation p).map_sub_le hx hy - -private lemma pIntegral_sum {ι : Type*} (p : ℕ) [Fact p.Prime] (s : Finset ι) (f : ι → ℚ) - (hf : ∀ i ∈ s, pIntegral p (f i)) : pIntegral p (∑ i ∈ s, f i) := - (Rat.padicValuation p).map_sum_le hf - -private lemma pIntegral_ofInt (p : ℕ) [Fact p.Prime] (z : ℤ) : pIntegral p z := - (pIntegral_iff_not_dvd p _).2 (by simpa using (Nat.Prime.not_dvd_one Fact.out)) - private lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) - (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := by - simp only [pIntegral, map_mul] at * - exact mul_le_one' hx hy + (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := + ((Rat.padicValuation p).map_mul x y).trans_le (mul_le_one' hx hy) /-- Denominators of the "other primes" part of the indicator sum stay coprime to a fixed prime `p`. -/ @@ -518,7 +502,7 @@ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) norm_cast simp rw [hrw] - exact (pIntegral_iff_not_dvd p _).2 ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 + exact Rat.padicValuation_le_one_iff.2 ((Nat.Prime.coprime_iff_not_dvd Fact.out).1 (hM'_cop.coprime_dvd_left (by rw [hM'_eq]; exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _))).symm) @@ -531,13 +515,13 @@ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prim have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = -(2 : ℤ) ^ (2 * k - 2) := by rw [hsub, pow_succ]; push_cast; field_simp - simpa [h] using pIntegral_ofInt _ (-(2 : ℤ) ^ (2 * k - 2)) + simpa [h] using Int.padicValuation_le_one _ (-(2 : ℤ) ^ (2 * k - 2)) · have hk_ne : (2 * k : ℚ) ≠ 0 := by positivity have hrw : (-1 / 2 : ℚ) * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = (-1 : ℤ) * ((p : ℚ) ^ (2 * k - 1) / 2) := by field_simp [hk_ne]; push_cast; ring rw [hrw] - exact pIntegral_mul p _ _ (by exact_mod_cast pIntegral_ofInt p (-1)) + exact pIntegral_mul p _ _ (by exact_mod_cast Int.padicValuation_le_one p (-1)) (pIntegral_pow_div p 2 (2 * k - 1) two_ne_zero (by rw [Nat.factorization_eq_zero_of_not_dvd (fun h ↦ by have := Nat.le_of_dvd two_pos h; have := (Fact.out : p.Prime).two_le; lia)] @@ -590,7 +574,7 @@ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat, mul_div_assoc] - exact pIntegral_mul p _ _ (by exact_mod_cast pIntegral_ofInt p ((2 * k).choose (2 * m))) + exact pIntegral_mul p _ _ (by exact_mod_cast Int.padicValuation_le_one p ((2 * k).choose (2 * m))) (pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero (factorization_succ_le_sub_one p d hd)) /-- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` @@ -611,7 +595,7 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact P / (2 * k + 1) := by rw [hpow]; field_simp [hp_ne]; ring rw [hdecomp] have hcmp := pIntegral_choose_mul_pow_div k m p hm_lt (by lia) - apply pIntegral_sub + apply (Rat.padicValuation p).map_sub_le · rw [mul_assoc, mul_div_assoc] apply pIntegral_mul _ _ _ ih have hpow_mul : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / @@ -619,17 +603,17 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * P / (2 * k - 2 * m + 1)) := by rw [hpow]; ring rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt, hpow_mul] - exact pIntegral_mul _ _ _ (pIntegral_ofInt p p) hcmp + exact pIntegral_mul _ _ _ (Int.padicValuation_le_one p p) hcmp · unfold vonStaudtIndicator; split_ifs · simp only [one_mul]; rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt]; exact hcmp - · simp only [zero_mul, zero_div, pIntegral, map_zero]; exact bot_le + · simp only [zero_mul, zero_div, map_zero]; exact bot_le /-- The full remainder sum in Faulhaber's formula is `p`-integral. -/ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by - apply pIntegral_sum + apply (Rat.padicValuation p).map_sum_le intro i hi rw [Finset.mem_range] at hi rcases i with _ | _ | i @@ -646,7 +630,7 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] simp only [hi_eq] exact pIntegral_bernoulli_even_term k m p hm_lt (ih m hm_pos hm_lt) · simp only [bernoulli_eq_zero_of_odd hodd (by lia), - zero_mul, zero_div, pIntegral, map_zero]; exact bot_le + zero_mul, zero_div, map_zero]; exact bot_le private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + @@ -715,13 +699,13 @@ private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact | _ k ih => obtain ⟨T, hT⟩ := bernoulli_add_indicator_eq_sub k p hk rw [hT] - have hT_int : pIntegral p (T : ℚ) := pIntegral_ofInt p T + have hT_int : pIntegral p (T : ℚ) := Int.padicValuation_le_one p T have hR : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by apply pIntegral_faulhaber_sum k p hk intro m hm_pos hm_lt - exact (pIntegral_iff_not_dvd p _).2 (ih m hm_lt hm_pos) - exact (pIntegral_iff_not_dvd p _).1 (pIntegral_sub p T _ hT_int hR) + exact Rat.padicValuation_le_one_iff.2 (ih m hm_lt hm_pos) + exact Rat.padicValuation_le_one_iff.1 ((Rat.padicValuation p).map_sub_le hT_int hR) /-- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : From c3491494f4e4bfb1a7567a0879949e7f136bb177 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Tue, 21 Apr 2026 15:19:21 -0700 Subject: [PATCH 53/70] abbrev vonStaudtPrimes --- Mathlib/NumberTheory/Bernoulli.lean | 40 +++++++++++++++++------------ 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 234cad7410d148..2ad1407af66db3 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -415,6 +415,11 @@ namespace bernoulli private noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := if (p - 1) ∣ k then 1 else 0 +/- The primes `q < 2k + 2` with `(q - 1) ∣ 2k` — the primes appearing in the +von Staudt-Clausen correction sum. -/ +private abbrev vonStaudtPrimes (k : ℕ) : Finset ℕ := + (Finset.range (2 * k + 2)).filter fun q => q.Prime ∧ (q - 1) ∣ 2 * k + /-- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + @@ -453,36 +458,38 @@ private lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) /-- Denominators of the "other primes" part of the indicator sum stay coprime to a fixed prime `p`. -/ private lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : - (∏ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, - ((1 : ℚ) / q).den).Coprime p := by + (∏ q ∈ vonStaudtPrimes k with q ≠ p, ((1 : ℚ) / q).den).Coprime p := by apply Nat.Coprime.prod_left intro q hq - have h1 : q.Prime := (Finset.mem_filter.mp hq).2.1 + simp only [Finset.mem_filter, Finset.mem_range] at hq + have h1 : q.Prime := hq.1.2.1 have h2 : ((1 : ℚ) / q).den = q := by simp [h1.ne_zero] rw [h2] - exact (Nat.coprime_primes h1 Fact.out).mpr (Finset.mem_filter.mp hq).2.2.2 + exact (Nat.coprime_primes h1 Fact.out).mpr hq.2 /-- Splits the prime-indexed correction sum into the `p`-term (`vonStaudtIndicator / p`) plus the rest. -/ private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [Fact p.Prime] : - (∑ q ∈ Finset.range (2 * k + 2) with q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q) = - vonStaudtIndicator (2 * k) p / p + ∑ q ∈ Finset.range (2 * k + 2) with - q.Prime ∧ (q - 1) ∣ 2 * k ∧ q ≠ p, (1 : ℚ) / q := by + (∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q) = + vonStaudtIndicator (2 * k) p / p + ∑ q ∈ vonStaudtPrimes k with q ≠ p, (1 : ℚ) / q := by by_cases hdvd : (p - 1) ∣ 2 * k · -- p is in the filtered set; extract its term - have hp_mem : p ∈ (Finset.range (2 * k + 2)).filter (fun q ↦ q.Prime ∧ (q - 1) ∣ 2 * k) := by - simp only [Finset.mem_filter, Finset.mem_range] + have hp_mem : p ∈ vonStaudtPrimes k := by + simp only [vonStaudtPrimes, Finset.mem_filter, Finset.mem_range] exact ⟨by have := Nat.le_of_dvd (by lia) hdvd; lia, Fact.out, hdvd⟩ rw [← Finset.add_sum_erase _ _ hp_mem] simp only [vonStaudtIndicator, if_pos hdvd] congr 1 - apply Finset.sum_congr _ (fun _ _ ↦ rfl) - grind - · -- p is not in the filtered set; indicator is 0, filter sets are equal + exact Finset.sum_congr (Finset.filter_ne' _ _).symm fun _ _ ↦ rfl + · -- p is not in the filtered set; filter is redundant since p ∉ vonStaudtPrimes k simp only [vonStaudtIndicator, if_neg hdvd, zero_div, zero_add] - exact Finset.sum_congr (Finset.filter_congr fun q _ ↦ - ⟨fun ⟨hpr, hd⟩ ↦ ⟨hpr, hd, fun h ↦ hdvd (h ▸ hd)⟩, - fun ⟨hpr, hd, _⟩ ↦ ⟨hpr, hd⟩⟩) fun _ _ ↦ rfl + refine Finset.sum_congr ?_ fun _ _ ↦ rfl + symm + apply Finset.filter_true_of_mem + intro q hq + simp only [vonStaudtPrimes, Finset.mem_filter] at hq + rintro rfl + exact hdvd hq.2.2 /-- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) @@ -709,8 +716,7 @@ private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact /-- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : - ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ Finset.range (2 * k + 2) with - q.Prime ∧ (q - 1) ∣ 2 * k, (1 : ℚ) / q).den := by + ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q).den := by rw [sum_one_div_prime_eq_indicator_div_add k p hk, ← add_assoc] have hcop_ind := ((Nat.Prime.coprime_iff_not_dvd Fact.out).2 (bernoulli_add_indicator_den_not_dvd k p hk)).symm From 8bd31e5104dcf1adc81179322af553fda2f445bf Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Tue, 21 Apr 2026 15:21:17 -0700 Subject: [PATCH 54/70] change to regular comments --- Mathlib/NumberTheory/Bernoulli.lean | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 2ad1407af66db3..a014125332d1fd 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -420,7 +420,7 @@ von Staudt-Clausen correction sum. -/ private abbrev vonStaudtPrimes (k : ℕ) : Finset ℕ := (Finset.range (2 * k + 2)).filter fun q => q.Prime ∧ (q - 1) ∣ 2 * k -/-- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ +/- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + (if (p - 1) ∣ l then (1 : ZMod p) else 0) = 0 := by @@ -439,7 +439,7 @@ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : rw [hbij, FiniteField.sum_pow_units, ZMod.card] grind -/-- A rational number `x` is `p`-integral if `p` does not divide its denominator. -/ +/- A rational number `x` is `p`-integral if `p` does not divide its denominator. -/ private abbrev pIntegral (p : ℕ) (x : ℚ) [Fact p.Prime] : Prop := Rat.padicValuation p x ≤ 1 private lemma den_sum_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : @@ -455,7 +455,7 @@ private lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := ((Rat.padicValuation p).map_mul x y).trans_le (mul_le_one' hx hy) -/-- Denominators of the "other primes" part of the indicator sum +/- Denominators of the "other primes" part of the indicator sum stay coprime to a fixed prime `p`. -/ private lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : (∏ q ∈ vonStaudtPrimes k with q ≠ p, ((1 : ℚ) / q).den).Coprime p := by @@ -467,7 +467,7 @@ private lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : rw [h2] exact (Nat.coprime_primes h1 Fact.out).mpr hq.2 -/-- Splits the prime-indexed correction sum into the `p`-term (`vonStaudtIndicator / p`) +/- Splits the prime-indexed correction sum into the `p`-term (`vonStaudtIndicator / p`) plus the rest. -/ private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [Fact p.Prime] : (∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q) = @@ -491,7 +491,7 @@ private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [F rintro rfl exact hdvd hq.2.2 -/-- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ +/- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ) ^ N / M) := by set e := M.factorization p @@ -513,7 +513,7 @@ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) (hM'_cop.coprime_dvd_left (by rw [hM'_eq]; exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _))).symm) -/-- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ +/- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by rw [bernoulli_one] @@ -534,7 +534,7 @@ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prim have := Nat.le_of_dvd two_pos h; have := (Fact.out : p.Prime).two_le; lia)] exact Nat.zero_le _)) -/-- Main valuation estimate behind the contradiction step for even-index summands. -/ +/- Main valuation estimate behind the contradiction step for even-index summands. -/ private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by -- Special case: p = 2, d = 2 (since 3 is not divisible by 2) @@ -556,7 +556,7 @@ private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d _ ≤ p ^ (m - 1) * p := by nlinarith [Nat.one_le_pow (m - 1) p (by lia)] _ = p ^ m := by rw [hm_eq]; exact pow_succ .. -/-- Multiplicative variant of the binomial coefficient denominator rewrite +/- Multiplicative variant of the binomial coefficient denominator rewrite as in Rado's summand. -/ private lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) * x / (2 * k + 1) = @@ -570,7 +570,7 @@ private lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] -/-- `p`-integrality of the core even-index summand after denominator normalization. -/ +/- `p`-integrality of the core even-index summand after denominator normalization. -/ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (hd : 2 * k - 2 * m ≥ 2) : pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / @@ -584,7 +584,7 @@ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p exact pIntegral_mul p _ _ (by exact_mod_cast Int.padicValuation_le_one p ((2 * k).choose (2 * m))) (pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero (factorization_succ_le_sub_one p d hd)) -/-- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` +/- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` to prove `p`-integrality of the even term. -/ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : @@ -615,7 +615,7 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact · simp only [one_mul]; rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt]; exact hcmp · simp only [zero_mul, zero_div, map_zero]; exact bot_le -/-- The full remainder sum in Faulhaber's formula is `p`-integral. -/ +/- The full remainder sum in Faulhaber's formula is `p`-integral. -/ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ Finset.range (2 * k), @@ -684,7 +684,7 @@ private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : rw [hsub, pow_succ] field_simp [hp_ne] -/-- Rearranges the Faulhaber identity and power-sum congruence to isolate +/- Rearranges the Faulhaber identity and power-sum congruence to isolate `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = @@ -699,7 +699,7 @@ private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Pr field_simp [hp_ne]; linarith [hT, sum_pow_filter_eq_faulhaber k p hk] rw [hAlg]; congr 1; simpa using faulhaber_sum_div_prime_eq k p -/-- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ +/- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := by induction k using Nat.strong_induction_on with @@ -714,7 +714,7 @@ private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact exact Rat.padicValuation_le_one_iff.2 (ih m hm_lt hm_pos) exact Rat.padicValuation_le_one_iff.1 ((Rat.padicValuation p).map_sub_le hT_int hR) -/-- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ +/- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q).den := by rw [sum_one_div_prime_eq_indicator_div_add k p hk, ← add_assoc] From 2182d33dcb7ba77e4b7bd2c08c2b63ac00e1ee17 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Tue, 21 Apr 2026 15:40:19 -0700 Subject: [PATCH 55/70] golf von Staudt-Clausen proofs Co-Authored-By: Claude Opus 4.7 --- Mathlib/NumberTheory/Bernoulli.lean | 99 +++++++++++------------------ 1 file changed, 38 insertions(+), 61 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index a014125332d1fd..3d01fdfd632603 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -447,9 +447,9 @@ private lemma den_sum_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) classical induction s using Finset.induction_on with | empty => simp - | @insert a s has ih => + | insert _ _ has ih => rw [Finset.sum_insert has, Finset.prod_insert has] - exact dvd_trans (Rat.add_den_dvd (f a) (∑ x ∈ s, f x)) (mul_dvd_mul_left _ ih) + exact (Rat.add_den_dvd _ _).trans (mul_dvd_mul_left _ ih) private lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := @@ -459,37 +459,25 @@ private lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) stay coprime to a fixed prime `p`. -/ private lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : (∏ q ∈ vonStaudtPrimes k with q ≠ p, ((1 : ℚ) / q).den).Coprime p := by - apply Nat.Coprime.prod_left - intro q hq + refine Nat.Coprime.prod_left fun q hq ↦ ?_ simp only [Finset.mem_filter, Finset.mem_range] at hq - have h1 : q.Prime := hq.1.2.1 - have h2 : ((1 : ℚ) / q).den = q := by simp [h1.ne_zero] - rw [h2] - exact (Nat.coprime_primes h1 Fact.out).mpr hq.2 + obtain ⟨⟨_, hq_prime, _⟩, hne⟩ := hq + rw [show ((1 : ℚ) / q).den = q by simp [hq_prime.ne_zero]] + exact (Nat.coprime_primes hq_prime Fact.out).mpr hne /- Splits the prime-indexed correction sum into the `p`-term (`vonStaudtIndicator / p`) plus the rest. -/ private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [Fact p.Prime] : (∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q) = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ vonStaudtPrimes k with q ≠ p, (1 : ℚ) / q := by + rw [Finset.sum_congr (Finset.filter_ne' (vonStaudtPrimes k) p) fun _ _ ↦ rfl] by_cases hdvd : (p - 1) ∣ 2 * k - · -- p is in the filtered set; extract its term - have hp_mem : p ∈ vonStaudtPrimes k := by - simp only [vonStaudtPrimes, Finset.mem_filter, Finset.mem_range] - exact ⟨by have := Nat.le_of_dvd (by lia) hdvd; lia, Fact.out, hdvd⟩ + · have hp_mem : p ∈ vonStaudtPrimes k := Finset.mem_filter.mpr + ⟨Finset.mem_range.mpr (by have := Nat.le_of_dvd (by lia) hdvd; lia), Fact.out, hdvd⟩ rw [← Finset.add_sum_erase _ _ hp_mem] - simp only [vonStaudtIndicator, if_pos hdvd] - congr 1 - exact Finset.sum_congr (Finset.filter_ne' _ _).symm fun _ _ ↦ rfl - · -- p is not in the filtered set; filter is redundant since p ∉ vonStaudtPrimes k - simp only [vonStaudtIndicator, if_neg hdvd, zero_div, zero_add] - refine Finset.sum_congr ?_ fun _ _ ↦ rfl - symm - apply Finset.filter_true_of_mem - intro q hq - simp only [vonStaudtPrimes, Finset.mem_filter] at hq - rintro rfl - exact hdvd hq.2.2 + simp [vonStaudtIndicator, hdvd] + · rw [Finset.erase_eq_of_notMem fun h ↦ hdvd (Finset.mem_filter.mp h).2.2] + simp [vonStaudtIndicator, hdvd] /- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) @@ -518,10 +506,9 @@ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prim pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by rw [bernoulli_one] obtain rfl | hp2 := eq_or_ne p 2 - · have hsub : 2 * k - 1 = (2 * k - 2) + 1 := by lia - have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = + · have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = -(2 : ℤ) ^ (2 * k - 2) := by - rw [hsub, pow_succ]; push_cast; field_simp + rw [(by lia : 2 * k - 1 = (2 * k - 2) + 1), pow_succ]; push_cast; field_simp simpa [h] using Int.padicValuation_le_one _ (-(2 : ℤ) ^ (2 * k - 2)) · have hk_ne : (2 * k : ℚ) ≠ 0 := by positivity have hrw : (-1 / 2 : ℚ) * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = @@ -537,24 +524,21 @@ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prim /- Main valuation estimate behind the contradiction step for even-index summands. -/ private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by - -- Special case: p = 2, d = 2 (since 3 is not divisible by 2) - obtain ⟨rfl, rfl⟩ | hne : (p = 2 ∧ d = 2) ∨ ¬(p = 2 ∧ d = 2) := by tauto - · simp [Nat.factorization_eq_zero_of_not_dvd (by decide : ¬(2 ∣ 3))] - · -- For all other prime p and d ≥ 2, we have d + 1 ≤ p^(d-1) - apply Nat.factorization_le_of_le_pow + by_cases hcase : p = 2 ∧ d = 2 + · obtain ⟨rfl, rfl⟩ := hcase + simp [Nat.factorization_eq_zero_of_not_dvd (by decide : ¬(2 ∣ 3))] + · apply Nat.factorization_le_of_le_pow have hp2 := (Fact.out : p.Prime).two_le - suffices ∀ n : ℕ, n ≥ 2 → ¬(p = 2 ∧ n = 2) → n + 1 ≤ p ^ (n - 1) from this d hd hne + suffices ∀ n : ℕ, n ≥ 2 → ¬(p = 2 ∧ n = 2) → n + 1 ≤ p ^ (n - 1) from this d hd hcase intro n hn hne' induction hn with | refl => norm_num at hne' ⊢; lia | @step m hm IH => by_cases hm2 : p = 2 ∧ m = 2 - · obtain ⟨rfl, rfl⟩ := hm2 - norm_num - · have hm_eq : m = m - 1 + 1 := by lia - calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by linarith [IH hm2] + · obtain ⟨rfl, rfl⟩ := hm2; norm_num + · calc m + 1 + 1 ≤ p ^ (m - 1) + 1 := by linarith [IH hm2] _ ≤ p ^ (m - 1) * p := by nlinarith [Nat.one_le_pow (m - 1) p (by lia)] - _ = p ^ m := by rw [hm_eq]; exact pow_succ .. + _ = p ^ m := by rw [show m = m - 1 + 1 by lia]; exact pow_succ .. /- Multiplicative variant of the binomial coefficient denominator rewrite as in Rado's summand. -/ @@ -576,8 +560,8 @@ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def - have ⟨hd_ne_zero, hd_plus_one_ne_zero, h_exp, hkm⟩ : - d ≠ 0 ∧ d + 1 ≠ 0 ∧ 2 * k - 2 * m - 1 = d - 1 ∧ 2 * m ≤ 2 * k := by lia + have ⟨hd_plus_one_ne_zero, h_exp, hkm⟩ : + d + 1 ≠ 0 ∧ 2 * k - 2 * m - 1 = d - 1 ∧ 2 * m ≤ 2 * k := by lia have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat, mul_div_assoc] @@ -642,33 +626,27 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = p * T := by - -- Get divisibility in ℤ from the ZMod result - have ⟨T, hT⟩ : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + - (if (p - 1) ∣ 2 * k then 1 else 0) = p * T := by - have : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + - (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := by - push_cast; exact sum_pow_add_indicator_eq_zero p (2 * k) - exact (ZMod.intCast_zmod_eq_zero_iff_dvd _ _).mp this + have hcast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + + (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := by + push_cast; exact sum_pow_add_indicator_eq_zero p (2 * k) + obtain ⟨T, hT⟩ := (ZMod.intCast_zmod_eq_zero_iff_dvd _ _).mp hcast refine ⟨T, ?_⟩ - have : vonStaudtIndicator (2 * k) p = - ((if (p - 1) ∣ 2 * k then (1 : ℤ) else 0) : ℚ) := by - unfold vonStaudtIndicator; split_ifs <;> simp - rw [this]; exact_mod_cast hT + rw [show vonStaudtIndicator (2 * k) p = ((if (p - 1) ∣ 2 * k then (1 : ℤ) else 0) : ℚ) by + unfold vonStaudtIndicator; split_ifs <;> simp] + exact_mod_cast hT private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by have hfilter : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) := by - rw [Finset.sum_filter]; exact Finset.sum_congr rfl fun v _ ↦ by - by_cases hv : v = 0 <;> simp [hv, (by lia : 2 * k ≠ 0)] - have hsub : 2 * k + 1 - 2 * k = 1 := by lia + ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) := + Finset.sum_filter_of_ne fun v _ hne ↦ by rintro rfl; exact hne (by simp [(by lia : 2 * k ≠ 0)]) have hne : (2 * k + 1 : ℚ) ≠ 0 := by positivity rw [hfilter, sum_range_pow, Finset.sum_range_succ] push_cast congr 1 - rw [Nat.choose_succ_self_right, hsub, pow_one] + rw [Nat.choose_succ_self_right, show 2 * k + 1 - 2 * k = 1 by lia, pow_one] push_cast; field_simp [hne] private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : @@ -678,11 +656,10 @@ private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero rw [Finset.sum_div] - exact Finset.sum_congr rfl fun i hi ↦ by - have hi_lt := Finset.mem_range.mp hi - have hsub : 2 * k + 1 - i = (2 * k - i) + 1 := by lia - rw [hsub, pow_succ] - field_simp [hp_ne] + refine Finset.sum_congr rfl fun i hi ↦ ?_ + have := Finset.mem_range.mp hi + rw [show 2 * k + 1 - i = (2 * k - i) + 1 by lia, pow_succ] + field_simp [hp_ne] /- Rearranges the Faulhaber identity and power-sum congruence to isolate `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ From adb1cc919bfa406d5dfd555e671f4057d689a429 Mon Sep 17 00:00:00 2001 From: Seewoo Lee <49933279+seewoo5@users.noreply.github.com> Date: Sat, 25 Apr 2026 10:44:20 -0700 Subject: [PATCH 56/70] Apply suggestions from code review Co-authored-by: Michael Stoll <99838730+MichaelStollBayreuth@users.noreply.github.com> --- Mathlib/NumberTheory/Bernoulli.lean | 72 ++++++++++++----------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 3d01fdfd632603..8530913fc59c8d 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -409,7 +409,7 @@ $$B_{2k} + \sum_{p \text{ prime}, (p - 1) \mid 2k} \frac{1}{p} \in \mathbb{Z}.$$ Rado's proof is based on Faulhaber's theorem and induction on $k$. -/ -namespace bernoulli +namespace Bernoulli /- Indicator function that is `1` if `(p - 1) ∣ k` and `0` otherwise. -/ private noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := @@ -451,7 +451,7 @@ private lemma den_sum_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) rw [Finset.sum_insert has, Finset.prod_insert has] exact (Rat.add_den_dvd _ _).trans (mul_dvd_mul_left _ ih) -private lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) +private lemma pIntegral_mul {p : ℕ} [Fact p.Prime] {x y : ℚ} (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := ((Rat.padicValuation p).map_mul x y).trans_le (mul_le_one' hx hy) @@ -545,14 +545,10 @@ as in Rado's summand. -/ private lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) * x / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) * x / (2 * k - 2 * m + 1) := by - have h : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = - ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by - have hm_le : 2 * m ≤ 2 * k + 1 := by lia - rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia)] - conv_rhs => norm_cast; rw [Nat.choose_mul_succ_eq] - push_cast [Nat.cast_sub hm_le]; ring - rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, - mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] + rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia), mul_right_comm _ x, mul_right_comm _ x] + refine congrArg (· * x) ?_ + rw [show (2 * (k : ℚ) - 2 * (m : ℚ) + 1) = (↑(2 * k + 1 - 2 * m) : ℚ) by norm_cast; lia] + exact_mod_cast Nat.choose_mul_succ_eq (2 * k) (2 * m) |>.symm /- `p`-integrality of the core even-index summand after denominator normalization. -/ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] @@ -565,7 +561,7 @@ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat, mul_div_assoc] - exact pIntegral_mul p _ _ (by exact_mod_cast Int.padicValuation_le_one p ((2 * k).choose (2 * m))) + exact pIntegral_mul p _ _ (mod_cast Int.padicValuation_le_one p ((2 * k).choose (2 * m))) (pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero (factorization_succ_le_sub_one p d hd)) /- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` @@ -574,7 +570,7 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by - have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero Fact.out) + have hp_ne : (p : ℚ) ≠ 0 := mod_cast (Nat.Prime.ne_zero Fact.out) set P := (p : ℚ) ^ (2 * k - 2 * m - 1) have hpow : (p : ℚ) ^ (2 * k - 2 * m) = P * p := by rw [(by lia : 2 * k - 2 * m = (2 * k - 2 * m - 1) + 1), pow_succ] @@ -586,6 +582,7 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact P / (2 * k + 1) := by rw [hpow]; field_simp [hp_ne]; ring rw [hdecomp] have hcmp := pIntegral_choose_mul_pow_div k m p hm_lt (by lia) + have H x := choose_two_mul_succ_mul_div_eq k m x hm_lt apply (Rat.padicValuation p).map_sub_le · rw [mul_assoc, mul_div_assoc] apply pIntegral_mul _ _ _ ih @@ -593,26 +590,24 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact (2 * k - 2 * m + 1) = (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * P / (2 * k - 2 * m + 1)) := by rw [hpow]; ring - rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt, hpow_mul] + rw [H, hpow_mul] exact pIntegral_mul _ _ _ (Int.padicValuation_le_one p p) hcmp - · unfold vonStaudtIndicator; split_ifs - · simp only [one_mul]; rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt]; exact hcmp - · simp only [zero_mul, zero_div, map_zero]; exact bot_le + · unfold vonStaudtIndicator + split_ifs + · grind + · simp /- The full remainder sum in Faulhaber's formula is `p`-integral. -/ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by - apply (Rat.padicValuation p).map_sum_le - intro i hi + refine (Rat.padicValuation p).map_sum_le fun i hi ↦ ? rw [Finset.mem_range] at hi rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] exact_mod_cast pIntegral_pow_div p (2 * k + 1) (2 * k) (by lia) - (Nat.factorization_le_of_le_pow <| calc 2 * k + 1 = (2 * k + 1).choose 1 := by simp - _ ≤ 2 ^ (2 * k) := Nat.choose_succ_le_two_pow _ 1 - _ ≤ p ^ (2 * k) := Nat.pow_le_pow_left (Fact.out : p.Prime).two_le _) + (factorization_succ_le_sub_one p (2 * k) (by lia) |>.trans tsub_le_self) · simp only [zero_add, Nat.choose_one_right] convert pIntegral_bernoulli_one_term k p hk using 1 push_cast; field_simp @@ -620,19 +615,17 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] · have ⟨hm_pos, hm_lt, hi_eq⟩ : 0 < m ∧ m < k ∧ i + 2 = 2 * m := by lia simp only [hi_eq] exact pIntegral_bernoulli_even_term k m p hm_lt (ih m hm_pos hm_lt) - · simp only [bernoulli_eq_zero_of_odd hodd (by lia), - zero_mul, zero_div, map_zero]; exact bot_le + · simp [bernoulli_eq_zero_of_odd hodd (by lia)] private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = p * T := by have hcast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + - (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := by - push_cast; exact sum_pow_add_indicator_eq_zero p (2 * k) + (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := + mod_cast sum_pow_add_indicator_eq_zero p (2 * k) obtain ⟨T, hT⟩ := (ZMod.intCast_zmod_eq_zero_iff_dvd _ _).mp hcast refine ⟨T, ?_⟩ - rw [show vonStaudtIndicator (2 * k) p = ((if (p - 1) ∣ 2 * k then (1 : ℤ) else 0) : ℚ) by - unfold vonStaudtIndicator; split_ifs <;> simp] + unfold vonStaudtIndicator exact_mod_cast hT private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : @@ -641,20 +634,18 @@ private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by have hfilter : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) := - Finset.sum_filter_of_ne fun v _ hne ↦ by rintro rfl; exact hne (by simp [(by lia : 2 * k ≠ 0)]) - have hne : (2 * k + 1 : ℚ) ≠ 0 := by positivity - rw [hfilter, sum_range_pow, Finset.sum_range_succ] + Finset.sum_filter_of_ne fun v _ hne ↦ ne_zero_pow (by lia) (mod_cast hne) + rw [hfilter, sum_range_pow, Finset.sum_range_succ, Nat.choose_succ_self_right, + show 2 * k + 1 - 2 * k = 1 by lia] push_cast - congr 1 - rw [Nat.choose_succ_self_right, show 2 * k + 1 - 2 * k = 1 by lia, pow_one] - push_cast; field_simp [hne] + field_simp private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = ∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by - have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero + have hp_ne : (p : ℚ) ≠ 0 := mod_cast (Fact.out : p.Prime).ne_zero rw [Finset.sum_div] refine Finset.sum_congr rfl fun i hi ↦ ?_ have := Finset.mem_range.mp hi @@ -683,13 +674,10 @@ private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact | _ k ih => obtain ⟨T, hT⟩ := bernoulli_add_indicator_eq_sub k p hk rw [hT] - have hT_int : pIntegral p (T : ℚ) := Int.padicValuation_le_one p T - have hR : pIntegral p (∑ i ∈ Finset.range (2 * k), - bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by - apply pIntegral_faulhaber_sum k p hk - intro m hm_pos hm_lt - exact Rat.padicValuation_le_one_iff.2 (ih m hm_lt hm_pos) - exact Rat.padicValuation_le_one_iff.1 ((Rat.padicValuation p).map_sub_le hT_int hR) + have hT_int : pIntegral p T := Int.padicValuation_le_one p T + have hR := pIntegral_faulhaber_sum k p hk fun m hm_pos hm_lt ↦ + Rat.padicValuation_le_one_iff.mpr (ih m hm_lt hm_pos) + exact Rat.padicValuation_le_one_iff.mp ((Rat.padicValuation p).map_sub_le hT_int hR) /- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : @@ -714,7 +702,7 @@ theorem vonStaudt_clausen (k : ℕ) : refine ⟨_, Rat.coe_int_num_of_den_eq_one ?_⟩ by_contra h obtain ⟨p, hp, hdvd⟩ := ne_one_iff_exists_prime_dvd.mp h - exact absurd hdvd (by let : Fact p.Prime := ⟨hp⟩; exact vonStaudt_sum_den_not_dvd k p hk) + exact (let : Fact p.Prime := ⟨hp⟩; vonStaudt_sum_den_not_dvd k p hk) hdvd end bernoulli From e61ad45ec7054530f4b6361288c2f1a444533e91 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 25 Apr 2026 10:58:10 -0700 Subject: [PATCH 57/70] update with suggested proofs & signatures --- Mathlib/NumberTheory/Bernoulli.lean | 37 +++++++++++++---------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 8530913fc59c8d..029ca2083c074f 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -12,6 +12,7 @@ public import Mathlib.RingTheory.PowerSeries.Exp public import Mathlib.FieldTheory.Finite.Basic public import Mathlib.RingTheory.ZMod.UnitsCyclic public import Mathlib.NumberTheory.Padics.PadicNumbers +import Mathlib.Tactic.NormNum.GCD /-! # Bernoulli numbers @@ -504,22 +505,16 @@ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) /- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by + field_simp rw [bernoulli_one] obtain rfl | hp2 := eq_or_ne p 2 - · have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = - -(2 : ℤ) ^ (2 * k - 2) := by + · have h : ((-1 / 2 : ℚ) * (2 : ℚ) ^ (2 * k - 1)) = -(2 : ℤ) ^ (2 * k - 2) := by rw [(by lia : 2 * k - 1 = (2 * k - 2) + 1), pow_succ]; push_cast; field_simp simpa [h] using Int.padicValuation_le_one _ (-(2 : ℤ) ^ (2 * k - 2)) - · have hk_ne : (2 * k : ℚ) ≠ 0 := by positivity - have hrw : (-1 / 2 : ℚ) * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = - (-1 : ℤ) * ((p : ℚ) ^ (2 * k - 1) / 2) := by - field_simp [hk_ne]; push_cast; ring - rw [hrw] - exact pIntegral_mul p _ _ (by exact_mod_cast Int.padicValuation_le_one p (-1)) - (pIntegral_pow_div p 2 (2 * k - 1) two_ne_zero (by - rw [Nat.factorization_eq_zero_of_not_dvd (fun h ↦ by - have := Nat.le_of_dvd two_pos h; have := (Fact.out : p.Prime).two_le; lia)] - exact Nat.zero_le _)) + · refine pIntegral_mul ?_ ?_ <;> rw [pIntegral, Rat.padicValuation_le_one_iff] + · norm_num + simpa [Nat.prime_dvd_prime_iff_eq Fact.out Nat.prime_two] + · simp [show p ≠ 1 from Nat.Prime.ne_one Fact.out] /- Main valuation estimate behind the contradiction step for even-index summands. -/ private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : @@ -561,7 +556,7 @@ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat, mul_div_assoc] - exact pIntegral_mul p _ _ (mod_cast Int.padicValuation_le_one p ((2 * k).choose (2 * m))) + exact pIntegral_mul (mod_cast Int.padicValuation_le_one p ((2 * k).choose (2 * m))) (pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero (factorization_succ_le_sub_one p d hd)) /- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` @@ -585,13 +580,13 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact have H x := choose_two_mul_succ_mul_div_eq k m x hm_lt apply (Rat.padicValuation p).map_sub_le · rw [mul_assoc, mul_div_assoc] - apply pIntegral_mul _ _ _ ih + apply pIntegral_mul ih have hpow_mul : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k - 2 * m + 1) = (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * P / (2 * k - 2 * m + 1)) := by rw [hpow]; ring rw [H, hpow_mul] - exact pIntegral_mul _ _ _ (Int.padicValuation_le_one p p) hcmp + exact pIntegral_mul (Int.padicValuation_le_one p p) hcmp · unfold vonStaudtIndicator split_ifs · grind @@ -602,7 +597,7 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by - refine (Rat.padicValuation p).map_sum_le fun i hi ↦ ? + refine (Rat.padicValuation p).map_sum_le fun i hi ↦ ?_ rw [Finset.mem_range] at hi rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] @@ -668,7 +663,7 @@ private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Pr rw [hAlg]; congr 1; simpa using faulhaber_sum_div_prime_eq k p /- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ -private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma not_dvd_den_bernoulli_add_indicator (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := by induction k using Nat.strong_induction_on with | _ k ih => @@ -680,11 +675,11 @@ private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact exact Rat.padicValuation_le_one_iff.mp ((Rat.padicValuation p).map_sub_le hT_int hR) /- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ -private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma not_dvd_den_vonStaudt_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q).den := by rw [sum_one_div_prime_eq_indicator_div_add k p hk, ← add_assoc] have hcop_ind := ((Nat.Prime.coprime_iff_not_dvd Fact.out).2 - (bernoulli_add_indicator_den_not_dvd k p hk)).symm + (not_dvd_den_bernoulli_add_indicator k p hk)).symm have hcop_rest := Nat.Coprime.of_dvd_left (den_sum_dvd_prod_den _ _) (prod_one_div_prime_den_coprime k p) have hcop := (Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) (hcop_ind.mul_left hcop_rest)).symm @@ -702,8 +697,8 @@ theorem vonStaudt_clausen (k : ℕ) : refine ⟨_, Rat.coe_int_num_of_den_eq_one ?_⟩ by_contra h obtain ⟨p, hp, hdvd⟩ := ne_one_iff_exists_prime_dvd.mp h - exact (let : Fact p.Prime := ⟨hp⟩; vonStaudt_sum_den_not_dvd k p hk) hdvd + exact (let : Fact p.Prime := ⟨hp⟩; not_dvd_den_vonStaudt_sum k p hk) hdvd -end bernoulli +end Bernoulli end vonStaudtClausen From 0a0a6ce263e9eab0b01d35164189b8ff4a1633d6 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 25 Apr 2026 11:10:01 -0700 Subject: [PATCH 58/70] Change to Ico 1 p --- Mathlib/NumberTheory/Bernoulli.lean | 33 ++++++++++++++++------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 029ca2083c074f..01a601aa329d17 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -423,18 +423,18 @@ private abbrev vonStaudtPrimes (k : ℕ) : Finset ℕ := /- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : - (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + - (if (p - 1) ∣ l then (1 : ZMod p) else 0) = 0 := by - have hbij : (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) = - ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := + (∑ v ∈ Ico 1 p, (v : ZMod p) ^ l) + (if (p - 1) ∣ l then (1 : ZMod p) else 0) = 0 := by + have hbij : (∑ v ∈ Ico 1 p, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := Finset.sum_bij' (fun v hv ↦ Units.mk0 (v : ZMod p) (mt (ZMod.natCast_eq_zero_iff v p).mp (by - obtain ⟨hlt, hne⟩ := Finset.mem_filter.mp hv - exact Nat.not_dvd_of_pos_of_lt (Nat.pos_of_ne_zero hne) (Finset.mem_range.mp hlt)))) + obtain ⟨hvpos, hvlt⟩ := Finset.mem_Ico.mp hv + exact Nat.not_dvd_of_pos_of_lt (by omega) hvlt))) (fun u _ ↦ (u : ZMod p).val) (fun _ _ ↦ Finset.mem_univ _) - (fun u _ ↦ by simp [ZMod.val_lt, u.ne_zero]) - (fun v hv ↦ by simp [ZMod.val_cast_of_lt (Finset.mem_range.mp (Finset.mem_filter.mp hv).1)]) + (fun u _ ↦ by + refine Finset.mem_Ico.mpr ⟨?_, ZMod.val_lt _⟩ + exact Nat.succ_le_of_lt <| Nat.pos_of_ne_zero <| (ZMod.val_ne_zero _).2 u.ne_zero) + (fun v hv ↦ by simp [ZMod.val_cast_of_lt (Finset.mem_Ico.mp hv).2]) (fun u _ ↦ Units.ext (ZMod.natCast_zmod_val _)) (fun _ _ ↦ rfl) rw [hbij, FiniteField.sum_pow_units, ZMod.card] @@ -613,9 +613,8 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] · simp [bernoulli_eq_zero_of_odd hodd (by lia)] private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : - ∃ T : ℤ, (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) + - vonStaudtIndicator (2 * k) p = p * T := by - have hcast : (↑((∑ v ∈ Finset.range p with v ≠ 0, (v : ℤ) ^ (2 * k)) + + ∃ T : ℤ, (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = p * T := by + have hcast : (↑((∑ v ∈ Ico 1 p, (v : ℤ) ^ (2 * k)) + (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := mod_cast sum_pow_add_indicator_eq_zero p (2 * k) obtain ⟨T, hT⟩ := (ZMod.intCast_zmod_eq_zero_iff_dvd _ _).mp hcast @@ -624,12 +623,16 @@ private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : exact_mod_cast hT private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : - (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = + (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by - have hfilter : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = - ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) := - Finset.sum_filter_of_ne fun v _ hne ↦ ne_zero_pow (by lia) (mod_cast hne) + have hfilter : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) := + by + by_cases hp : 0 < p + · rw [Finset.sum_range_eq_add_Ico _ hp] + simp [show 2 * k ≠ 0 by omega] + · have hp0 : p = 0 := by omega + simp [hp0] rw [hfilter, sum_range_pow, Finset.sum_range_succ, Nat.choose_succ_self_right, show 2 * k + 1 - 2 * k = 1 by lia] push_cast From 6e31f5b05fc48e66faa42d180f29d875fb3b0428 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 25 Apr 2026 11:18:55 -0700 Subject: [PATCH 59/70] inline exists_int_sum_pow_add_indicator_eq --- Mathlib/NumberTheory/Bernoulli.lean | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 01a601aa329d17..c460a75c879f32 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -612,16 +612,6 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] exact pIntegral_bernoulli_even_term k m p hm_lt (ih m hm_pos hm_lt) · simp [bernoulli_eq_zero_of_odd hodd (by lia)] -private lemma exists_int_sum_pow_add_indicator_eq (k p : ℕ) [Fact p.Prime] : - ∃ T : ℤ, (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = p * T := by - have hcast : (↑((∑ v ∈ Ico 1 p, (v : ℤ) ^ (2 * k)) + - (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := - mod_cast sum_pow_add_indicator_eq_zero p (2 * k) - obtain ⟨T, hT⟩ := (ZMod.intCast_zmod_eq_zero_iff_dvd _ _).mp hcast - refine ⟨T, ?_⟩ - unfold vonStaudtIndicator - exact_mod_cast hT - private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * @@ -656,8 +646,13 @@ private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Pr ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by - obtain ⟨T, hT⟩ := exists_int_sum_pow_add_indicator_eq k p + have hcast : (↑((∑ v ∈ Ico 1 p, (v : ℤ) ^ (2 * k)) + + (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := + mod_cast sum_pow_add_indicator_eq_zero p _ + obtain ⟨T, hT_int⟩ := (ZMod.intCast_zmod_eq_zero_iff_dvd _ _).mp hcast use T + have hT : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = + p * T := by unfold vonStaudtIndicator; exact_mod_cast hT_int have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero have hAlg : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * @@ -681,7 +676,7 @@ private lemma not_dvd_den_bernoulli_add_indicator (k p : ℕ) (hk : k > 0) [Fact private lemma not_dvd_den_vonStaudt_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q).den := by rw [sum_one_div_prime_eq_indicator_div_add k p hk, ← add_assoc] - have hcop_ind := ((Nat.Prime.coprime_iff_not_dvd Fact.out).2 + have hcop_ind := ((Nat.Prime.coprime_iff_not_dvd Fact.out).mpr (not_dvd_den_bernoulli_add_indicator k p hk)).symm have hcop_rest := Nat.Coprime.of_dvd_left (den_sum_dvd_prod_den _ _) (prod_one_div_prime_den_coprime k p) From 67c7772baaf1734cc4b98ee952bcda067bf056a2 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 25 Apr 2026 11:22:37 -0700 Subject: [PATCH 60/70] simplify hfilter --- Mathlib/NumberTheory/Bernoulli.lean | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index c460a75c879f32..6d541880a23b56 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -616,13 +616,8 @@ private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by - have hfilter : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) := - by - by_cases hp : 0 < p - · rw [Finset.sum_range_eq_add_Ico _ hp] - simp [show 2 * k ≠ 0 by omega] - · have hp0 : p = 0 := by omega - simp [hp0] + have hfilter : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) := by + cases p <;> simp [Finset.sum_range_eq_add_Ico, show 2 * k ≠ 0 by omega] rw [hfilter, sum_range_pow, Finset.sum_range_succ, Nat.choose_succ_self_right, show 2 * k + 1 - 2 * k = 1 by lia] push_cast From 8f3d1bf3300be61ad23216005aa741b58ece9670 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 25 Apr 2026 11:38:25 -0700 Subject: [PATCH 61/70] Finset is opened --- Mathlib/NumberTheory/Bernoulli.lean | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 6d541880a23b56..6b2db642ffe75b 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -56,9 +56,9 @@ The proof of von Staudt-Clausen's theorem follows Rado's JLMS 1934 paper ## Main theorems -* `sum_bernoulli : ∑ k ∈ Finset.range n, (n.choose k : ℚ) * bernoulli k = +* `sum_bernoulli : ∑ k ∈ range n, (n.choose k : ℚ) * bernoulli k = if n = 1 then 1 else 0` -* `bernoulli.vonStaudt_clausen : bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) +* `bernoulli.vonStaudt_clausen : bernoulli (2 * k) + ∑ p ∈ range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast` ## References @@ -419,7 +419,7 @@ private noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := /- The primes `q < 2k + 2` with `(q - 1) ∣ 2k` — the primes appearing in the von Staudt-Clausen correction sum. -/ private abbrev vonStaudtPrimes (k : ℕ) : Finset ℕ := - (Finset.range (2 * k + 2)).filter fun q => q.Prime ∧ (q - 1) ∣ 2 * k + (range (2 * k + 2)).filter fun q => q.Prime ∧ (q - 1) ∣ 2 * k /- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : @@ -595,7 +595,7 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact /- The full remainder sum in Faulhaber's formula is `p`-integral. -/ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : - pIntegral p (∑ i ∈ Finset.range (2 * k), + pIntegral p (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by refine (Rat.padicValuation p).map_sum_le fun i hi ↦ ?_ rw [Finset.mem_range] at hi @@ -614,9 +614,9 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * + (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by - have hfilter : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) := by + have hfilter : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = ∑ v ∈ range p, (v : ℚ) ^ (2 * k) := by cases p <;> simp [Finset.sum_range_eq_add_Ico, show 2 * k ≠ 0 by omega] rw [hfilter, sum_range_pow, Finset.sum_range_succ, Nat.choose_succ_self_right, show 2 * k + 1 - 2 * k = 1 by lia] @@ -624,9 +624,9 @@ private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : field_simp private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * + (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = - ∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * + ∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by have hp_ne : (p : ℚ) ≠ 0 := mod_cast (Fact.out : p.Prime).ne_zero rw [Finset.sum_div] @@ -639,7 +639,7 @@ private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Prime] : ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = - T - (∑ i ∈ Finset.range (2 * k), + T - (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by have hcast : (↑((∑ v ∈ Ico 1 p, (v : ℤ) ^ (2 * k)) + (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := @@ -650,7 +650,7 @@ private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Pr p * T := by unfold vonStaudtIndicator; exact_mod_cast hT_int have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero have hAlg : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = - T - (∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i) * + T - (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by field_simp [hp_ne]; linarith [hT, sum_pow_filter_eq_faulhaber k p hk] rw [hAlg]; congr 1; simpa using faulhaber_sum_div_prime_eq k p @@ -682,7 +682,7 @@ private lemma not_dvd_den_vonStaudt_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] $$B_{2k} + \sum_{p - 1 \mid 2k} \frac{1}{p}$$ is an integer. -/ theorem vonStaudt_clausen (k : ℕ) : - bernoulli (2 * k) + ∑ p ∈ Finset.range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, + bernoulli (2 * k) + ∑ p ∈ range (2 * k + 2) with p.Prime ∧ (p - 1) ∣ 2 * k, (1 : ℚ) / p ∈ Set.range Int.cast := by rcases Nat.eq_zero_or_pos k with rfl | hk · exact ⟨1, by decide +kernel⟩ From 66eeda2fa0cc3a15c14f0af54105cb517a2bf6b0 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 25 Apr 2026 11:44:36 -0700 Subject: [PATCH 62/70] minor --- Mathlib/NumberTheory/Bernoulli.lean | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 6b2db642ffe75b..a60968a7116a4a 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -433,7 +433,7 @@ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : (fun _ _ ↦ Finset.mem_univ _) (fun u _ ↦ by refine Finset.mem_Ico.mpr ⟨?_, ZMod.val_lt _⟩ - exact Nat.succ_le_of_lt <| Nat.pos_of_ne_zero <| (ZMod.val_ne_zero _).2 u.ne_zero) + exact Nat.succ_le_of_lt <| Nat.pos_of_ne_zero <| (ZMod.val_ne_zero _).mpr u.ne_zero) (fun v hv ↦ by simp [ZMod.val_cast_of_lt (Finset.mem_Ico.mp hv).2]) (fun u _ ↦ Units.ext (ZMod.natCast_zmod_val _)) (fun _ _ ↦ rfl) @@ -548,8 +548,7 @@ private lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < /- `p`-integrality of the core even-index summand after denominator normalization. -/ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] (hd : 2 * k - 2 * m ≥ 2) : - pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / - (2 * k - 2 * m + 1)) := by + pIntegral p (((2 * k).choose (2 * m) : ℚ) * p ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def have ⟨hd_plus_one_ne_zero, h_exp, hkm⟩ : d + 1 ≠ 0 ∧ 2 * k - 2 * m - 1 = d - 1 ∧ 2 * m ≤ 2 * k := by lia @@ -568,7 +567,7 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact have hp_ne : (p : ℚ) ≠ 0 := mod_cast (Nat.Prime.ne_zero Fact.out) set P := (p : ℚ) ^ (2 * k - 2 * m - 1) have hpow : (p : ℚ) ^ (2 * k - 2 * m) = P * p := by - rw [(by lia : 2 * k - 2 * m = (2 * k - 2 * m - 1) + 1), pow_succ] + rw [show 2 * k - 2 * m = (2 * k - 2 * m - 1) + 1 by lia, pow_succ] have hdecomp : bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1) = (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p) * From 54b812641dab60716a5bf341c91190d5606dfd0e Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 25 Apr 2026 13:51:09 -0700 Subject: [PATCH 63/70] grind --- Mathlib/NumberTheory/Bernoulli.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index a60968a7116a4a..ea494d6646b148 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -427,8 +427,7 @@ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : have hbij : (∑ v ∈ Ico 1 p, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := Finset.sum_bij' (fun v hv ↦ Units.mk0 (v : ZMod p) (mt (ZMod.natCast_eq_zero_iff v p).mp (by - obtain ⟨hvpos, hvlt⟩ := Finset.mem_Ico.mp hv - exact Nat.not_dvd_of_pos_of_lt (by omega) hvlt))) + grind [not_dvd_of_pos_of_lt]))) (fun u _ ↦ (u : ZMod p).val) (fun _ _ ↦ Finset.mem_univ _) (fun u _ ↦ by From f76a91b00a268ff906d16e4c61e608a902409052 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 25 Apr 2026 14:31:05 -0700 Subject: [PATCH 64/70] inline pIntegral_bernoulli_one_term --- Mathlib/NumberTheory/Bernoulli.lean | 32 ++++++++++++----------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index ea494d6646b148..0f9041b1e2d21d 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -501,20 +501,6 @@ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) (hM'_cop.coprime_dvd_left (by rw [hM'_eq]; exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _))).symm) -/- The `i = 1` Faulhaber term is `p`-integral (handled separately for `p = 2` and odd `p`). -/ -private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : - pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by - field_simp - rw [bernoulli_one] - obtain rfl | hp2 := eq_or_ne p 2 - · have h : ((-1 / 2 : ℚ) * (2 : ℚ) ^ (2 * k - 1)) = -(2 : ℤ) ^ (2 * k - 2) := by - rw [(by lia : 2 * k - 1 = (2 * k - 2) + 1), pow_succ]; push_cast; field_simp - simpa [h] using Int.padicValuation_le_one _ (-(2 : ℤ) ^ (2 * k - 2)) - · refine pIntegral_mul ?_ ?_ <;> rw [pIntegral, Rat.padicValuation_le_one_iff] - · norm_num - simpa [Nat.prime_dvd_prime_iff_eq Fact.out Nat.prime_two] - · simp [show p ≠ 1 from Nat.Prime.ne_one Fact.out] - /- Main valuation estimate behind the contradiction step for even-index summands. -/ private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by @@ -594,16 +580,24 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ range (2 * k), - bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by + bernoulli i * ((2 * k + 1).choose i) * p ^ (2 * k - i) / (2 * k + 1)) := by refine (Rat.padicValuation p).map_sum_le fun i hi ↦ ?_ rw [Finset.mem_range] at hi rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] exact_mod_cast pIntegral_pow_div p (2 * k + 1) (2 * k) (by lia) (factorization_succ_le_sub_one p (2 * k) (by lia) |>.trans tsub_le_self) - · simp only [zero_add, Nat.choose_one_right] - convert pIntegral_bernoulli_one_term k p hk using 1 - push_cast; field_simp + · rw [zero_add, Nat.choose_one_right, bernoulli_one] + have : (-1 / 2 : ℚ) * ((2 * k + 1 : ℕ) : ℚ) * p ^ (2 * k - 1) / (2 * k + 1) = + (-1 / 2 : ℚ) * p ^ (2 * k - 1) := by field_simp; push_cast; ring + rw [this] + obtain rfl | hp2 := eq_or_ne p 2 + · have h : ((-1 / 2 : ℚ) * (2 : ℚ) ^ (2 * k - 1)) = -(2 : ℤ) ^ (2 * k - 2) := by + rw [show 2 * k - 1 = (2 * k - 2) + 1 by lia, pow_succ]; push_cast; field_simp + simpa [h] using Int.padicValuation_le_one 2 (-(2 : ℤ) ^ (2 * k - 2)) + · refine pIntegral_mul ?_ ?_ <;> rw [pIntegral, Rat.padicValuation_le_one_iff] + · norm_num [Nat.prime_dvd_prime_iff_eq Fact.out Nat.prime_two, hp2] + · simp [show p ≠ 1 from Nat.Prime.ne_one Fact.out] · rcases Nat.even_or_odd (i + 2) with ⟨m, hm⟩ | hodd · have ⟨hm_pos, hm_lt, hi_eq⟩ : 0 < m ∧ m < k ∧ i + 2 = 2 * m := by lia simp only [hi_eq] @@ -615,7 +609,7 @@ private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by have hfilter : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = ∑ v ∈ range p, (v : ℚ) ^ (2 * k) := by - cases p <;> simp [Finset.sum_range_eq_add_Ico, show 2 * k ≠ 0 by omega] + cases p <;> simp [Finset.sum_range_eq_add_Ico, show 2 * k ≠ 0 by lia] rw [hfilter, sum_range_pow, Finset.sum_range_succ, Nat.choose_succ_self_right, show 2 * k + 1 - 2 * k = 1 by lia] push_cast From 360f943211c48cdccbe8b0706230917930e7365b Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sat, 25 Apr 2026 14:34:05 -0700 Subject: [PATCH 65/70] one more grind suggestion --- Mathlib/NumberTheory/Bernoulli.lean | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 0f9041b1e2d21d..e91dfb95c3a794 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -430,9 +430,7 @@ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : grind [not_dvd_of_pos_of_lt]))) (fun u _ ↦ (u : ZMod p).val) (fun _ _ ↦ Finset.mem_univ _) - (fun u _ ↦ by - refine Finset.mem_Ico.mpr ⟨?_, ZMod.val_lt _⟩ - exact Nat.succ_le_of_lt <| Nat.pos_of_ne_zero <| (ZMod.val_ne_zero _).mpr u.ne_zero) + (fun u _ ↦ by grind [u.ne_zero, ZMod.val_ne_zero, ZMod.val_lt]) (fun v hv ↦ by simp [ZMod.val_cast_of_lt (Finset.mem_Ico.mp hv).2]) (fun u _ ↦ Units.ext (ZMod.natCast_zmod_val _)) (fun _ _ ↦ rfl) From f6719f2eb6908bcd356e7689a604861b8e867930 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sun, 26 Apr 2026 15:20:32 -0700 Subject: [PATCH 66/70] move den_sum_dvd_prod_den and make some variables implicit --- .../BigOperators/Group/Finset/Rat.lean | 24 ++++++++ Mathlib/NumberTheory/Bernoulli.lean | 56 ++++++++----------- 2 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 Mathlib/Algebra/BigOperators/Group/Finset/Rat.lean diff --git a/Mathlib/Algebra/BigOperators/Group/Finset/Rat.lean b/Mathlib/Algebra/BigOperators/Group/Finset/Rat.lean new file mode 100644 index 00000000000000..017c45cbff4ed7 --- /dev/null +++ b/Mathlib/Algebra/BigOperators/Group/Finset/Rat.lean @@ -0,0 +1,24 @@ +/- +Copyright (c) 2026 Seewoo Lee. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Seewoo Lee +-/ +module + +public import Mathlib.Algebra.GCDMonoid.FinsetLemmas + + +@[expose] public section + +theorem den_sum_dvd_lcm_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : + (∑ i ∈ s, f i).den ∣ s.lcm (fun i ↦ (f i).den) := by + classical + induction s using Finset.induction_on with + | empty => simp + | insert _ _ has ih => + rw [Finset.sum_insert has, Finset.lcm_insert] + exact (Rat.add_den_dvd_lcm _ _).trans (lcm_dvd_lcm dvd_rfl ih) + +theorem den_sum_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : + (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := + dvd_trans (den_sum_dvd_lcm_den s f) (s.lcm_dvd_prod (fun i ↦ (f i).den)) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index e91dfb95c3a794..e9b4ede343d123 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -6,6 +6,7 @@ Authors: Johan Commelin, Kevin Buzzard, Seewoo Lee module public import Mathlib.Algebra.BigOperators.Field +public import Mathlib.Algebra.BigOperators.Group.Finset.Rat public import Mathlib.Algebra.Field.GeomSum public import Mathlib.Data.Nat.Choose.Bounds public import Mathlib.RingTheory.PowerSeries.Exp @@ -440,15 +441,6 @@ private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : /- A rational number `x` is `p`-integral if `p` does not divide its denominator. -/ private abbrev pIntegral (p : ℕ) (x : ℚ) [Fact p.Prime] : Prop := Rat.padicValuation p x ≤ 1 -private lemma den_sum_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : - (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by - classical - induction s using Finset.induction_on with - | empty => simp - | insert _ _ has ih => - rw [Finset.sum_insert has, Finset.prod_insert has] - exact (Rat.add_den_dvd _ _).trans (mul_dvd_mul_left _ ih) - private lemma pIntegral_mul {p : ℕ} [Fact p.Prime] {x y : ℚ} (hx : pIntegral p x) (hy : pIntegral p y) : pIntegral p (x * y) := ((Rat.padicValuation p).map_mul x y).trans_le (mul_le_one' hx hy) @@ -465,7 +457,7 @@ private lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : /- Splits the prime-indexed correction sum into the `p`-term (`vonStaudtIndicator / p`) plus the rest. -/ -private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma sum_one_div_prime_eq_indicator_div_add {k : ℕ} (p : ℕ) (hk : k > 0) [Fact p.Prime] : (∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q) = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ vonStaudtPrimes k with q ≠ p, (1 : ℚ) / q := by rw [Finset.sum_congr (Finset.filter_ne' (vonStaudtPrimes k) p) fun _ _ ↦ rfl] @@ -478,7 +470,7 @@ private lemma sum_one_div_prime_eq_indicator_div_add (k p : ℕ) (hk : k > 0) [F simp [vonStaudtIndicator, hdvd] /- If the `p`-adic valuation of `M` is at most `N`, then `p^N / M` is `p`-integral. -/ -private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) +private lemma pIntegral_pow_div {p M N : ℕ} [Fact p.Prime] (hM : M ≠ 0) (hv : M.factorization p ≤ N) : pIntegral p ((p : ℚ) ^ N / M) := by set e := M.factorization p set M' := M / p ^ e @@ -500,7 +492,7 @@ private lemma pIntegral_pow_div (p M N : ℕ) [Fact p.Prime] (hM : M ≠ 0) rw [hM'_eq]; exact Int.natCast_dvd_natCast.mp (Rat.den_dvd _ _))).symm) /- Main valuation estimate behind the contradiction step for even-index summands. -/ -private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d ≥ 2) : +private lemma factorization_succ_le_sub_one {p d : ℕ} [Fact p.Prime] (hd : d ≥ 2) : (d + 1).factorization p ≤ d - 1 := by by_cases hcase : p = 2 ∧ d = 2 · obtain ⟨rfl, rfl⟩ := hcase @@ -520,7 +512,7 @@ private lemma factorization_succ_le_sub_one (p d : ℕ) [Fact p.Prime] (hd : d /- Multiplicative variant of the binomial coefficient denominator rewrite as in Rado's summand. -/ -private lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < k) : +private lemma choose_two_mul_succ_mul_div_eq {k m : ℕ} (x : ℚ) (hm_lt : m < k) : ((2 * k + 1).choose (2 * m) : ℚ) * x / (2 * k + 1) = ((2 * k).choose (2 * m) : ℚ) * x / (2 * k - 2 * m + 1) := by rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia), mul_right_comm _ x, mul_right_comm _ x] @@ -529,7 +521,7 @@ private lemma choose_two_mul_succ_mul_div_eq (k m : ℕ) (x : ℚ) (hm_lt : m < exact_mod_cast Nat.choose_mul_succ_eq (2 * k) (2 * m) |>.symm /- `p`-integrality of the core even-index summand after denominator normalization. -/ -private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] +private lemma pIntegral_choose_mul_pow_div {k m : ℕ} (p : ℕ) (hm_lt : m < k) [Fact p.Prime] (hd : 2 * k - 2 * m ≥ 2) : pIntegral p (((2 * k).choose (2 * m) : ℚ) * p ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def @@ -539,11 +531,11 @@ private lemma pIntegral_choose_mul_pow_div (k m p : ℕ) (hm_lt : m < k) [Fact p simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring rw [h_exp, h_denom_rat, mul_div_assoc] exact pIntegral_mul (mod_cast Int.padicValuation_le_one p ((2 * k).choose (2 * m))) - (pIntegral_pow_div p (d + 1) (d - 1) hd_plus_one_ne_zero (factorization_succ_le_sub_one p d hd)) + (pIntegral_pow_div hd_plus_one_ne_zero (factorization_succ_le_sub_one hd)) /- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` to prove `p`-integrality of the even term. -/ -private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact p.Prime] +private lemma pIntegral_bernoulli_even_term {k m : ℕ} (p : ℕ) (hm_lt : m < k) [Fact p.Prime] (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by @@ -558,8 +550,8 @@ private lemma pIntegral_bernoulli_even_term (k m p : ℕ) (hm_lt : m < k) [Fact vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * P / (2 * k + 1) := by rw [hpow]; field_simp [hp_ne]; ring rw [hdecomp] - have hcmp := pIntegral_choose_mul_pow_div k m p hm_lt (by lia) - have H x := choose_two_mul_succ_mul_div_eq k m x hm_lt + have hcmp := pIntegral_choose_mul_pow_div p hm_lt (by lia) + have H x := choose_two_mul_succ_mul_div_eq x hm_lt apply (Rat.padicValuation p).map_sub_le · rw [mul_assoc, mul_div_assoc] apply pIntegral_mul ih @@ -583,8 +575,8 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] rw [Finset.mem_range] at hi rcases i with _ | _ | i · simp only [bernoulli_zero, one_mul, Nat.choose_zero_right, Nat.cast_one, Nat.sub_zero] - exact_mod_cast pIntegral_pow_div p (2 * k + 1) (2 * k) (by lia) - (factorization_succ_le_sub_one p (2 * k) (by lia) |>.trans tsub_le_self) + exact_mod_cast pIntegral_pow_div (by lia) + (factorization_succ_le_sub_one (by lia) |>.trans tsub_le_self) · rw [zero_add, Nat.choose_one_right, bernoulli_one] have : (-1 / 2 : ℚ) * ((2 * k + 1 : ℕ) : ℚ) * p ^ (2 * k - 1) / (2 * k + 1) = (-1 / 2 : ℚ) * p ^ (2 * k - 1) := by field_simp; push_cast; ring @@ -599,10 +591,10 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] · rcases Nat.even_or_odd (i + 2) with ⟨m, hm⟩ | hodd · have ⟨hm_pos, hm_lt, hi_eq⟩ : 0 < m ∧ m < k ∧ i + 2 = 2 * m := by lia simp only [hi_eq] - exact pIntegral_bernoulli_even_term k m p hm_lt (ih m hm_pos hm_lt) + exact pIntegral_bernoulli_even_term p hm_lt (ih m hm_pos hm_lt) · simp [bernoulli_eq_zero_of_odd hodd (by lia)] -private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : +private lemma sum_pow_filter_eq_faulhaber {k : ℕ} (p : ℕ) (hk : 0 < k) : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) = (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by @@ -613,7 +605,7 @@ private lemma sum_pow_filter_eq_faulhaber (k p : ℕ) (hk : 0 < k) : push_cast field_simp -private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : +private lemma faulhaber_sum_div_prime_eq {k : ℕ} (p : ℕ) [Fact p.Prime] : (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = ∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * @@ -627,7 +619,7 @@ private lemma faulhaber_sum_div_prime_eq (k p : ℕ) [Fact p.Prime] : /- Rearranges the Faulhaber identity and power-sum congruence to isolate `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ -private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma bernoulli_add_indicator_eq_sub {k : ℕ} (p : ℕ) (hk : k > 0) [Fact p.Prime] : ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by @@ -642,15 +634,15 @@ private lemma bernoulli_add_indicator_eq_sub (k p : ℕ) (hk : k > 0) [Fact p.Pr have hAlg : bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by - field_simp [hp_ne]; linarith [hT, sum_pow_filter_eq_faulhaber k p hk] - rw [hAlg]; congr 1; simpa using faulhaber_sum_div_prime_eq k p + field_simp [hp_ne]; linarith [hT, sum_pow_filter_eq_faulhaber p hk] + rw [hAlg]; congr 1; simpa using faulhaber_sum_div_prime_eq p /- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ -private lemma not_dvd_den_bernoulli_add_indicator (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma not_dvd_den_bernoulli_add_indicator {k : ℕ} (p : ℕ) (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := by induction k using Nat.strong_induction_on with | _ k ih => - obtain ⟨T, hT⟩ := bernoulli_add_indicator_eq_sub k p hk + obtain ⟨T, hT⟩ := bernoulli_add_indicator_eq_sub p hk rw [hT] have hT_int : pIntegral p T := Int.padicValuation_le_one p T have hR := pIntegral_faulhaber_sum k p hk fun m hm_pos hm_lt ↦ @@ -658,11 +650,11 @@ private lemma not_dvd_den_bernoulli_add_indicator (k p : ℕ) (hk : k > 0) [Fact exact Rat.padicValuation_le_one_iff.mp ((Rat.padicValuation p).map_sub_le hT_int hR) /- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ -private lemma not_dvd_den_vonStaudt_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma not_dvd_den_vonStaudt_sum {k p : ℕ} (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q).den := by - rw [sum_one_div_prime_eq_indicator_div_add k p hk, ← add_assoc] + rw [sum_one_div_prime_eq_indicator_div_add p hk, ← add_assoc] have hcop_ind := ((Nat.Prime.coprime_iff_not_dvd Fact.out).mpr - (not_dvd_den_bernoulli_add_indicator k p hk)).symm + (not_dvd_den_bernoulli_add_indicator p hk)).symm have hcop_rest := Nat.Coprime.of_dvd_left (den_sum_dvd_prod_den _ _) (prod_one_div_prime_den_coprime k p) have hcop := (Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) (hcop_ind.mul_left hcop_rest)).symm @@ -680,7 +672,7 @@ theorem vonStaudt_clausen (k : ℕ) : refine ⟨_, Rat.coe_int_num_of_den_eq_one ?_⟩ by_contra h obtain ⟨p, hp, hdvd⟩ := ne_one_iff_exists_prime_dvd.mp h - exact (let : Fact p.Prime := ⟨hp⟩; not_dvd_den_vonStaudt_sum k p hk) hdvd + exact (let : Fact p.Prime := ⟨hp⟩; not_dvd_den_vonStaudt_sum hk) hdvd end Bernoulli From d77b828047ed9a156c46d4e8e5edb193c8552508 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sun, 26 Apr 2026 15:30:09 -0700 Subject: [PATCH 67/70] more implicit --- Mathlib/NumberTheory/Bernoulli.lean | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index e9b4ede343d123..c9cbc58f7c4c95 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -420,10 +420,10 @@ private noncomputable def vonStaudtIndicator (k p : ℕ) : ℚ := /- The primes `q < 2k + 2` with `(q - 1) ∣ 2k` — the primes appearing in the von Staudt-Clausen correction sum. -/ private abbrev vonStaudtPrimes (k : ℕ) : Finset ℕ := - (range (2 * k + 2)).filter fun q => q.Prime ∧ (q - 1) ∣ 2 * k + (range (2 * k + 2)).filter fun q ↦ q.Prime ∧ (q - 1) ∣ 2 * k /- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ -private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : +private lemma sum_pow_add_indicator_eq_zero {p : ℕ} (l : ℕ) [Fact p.Prime] : (∑ v ∈ Ico 1 p, (v : ZMod p) ^ l) + (if (p - 1) ∣ l then (1 : ZMod p) else 0) = 0 := by have hbij : (∑ v ∈ Ico 1 p, (v : ZMod p) ^ l) = ∑ u : (ZMod p)ˣ, (u : ZMod p) ^ l := Finset.sum_bij' @@ -447,7 +447,7 @@ private lemma pIntegral_mul {p : ℕ} [Fact p.Prime] {x y : ℚ} /- Denominators of the "other primes" part of the indicator sum stay coprime to a fixed prime `p`. -/ -private lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : +private lemma prod_one_div_prime_den_coprime (k : ℕ) {p : ℕ} [Fact p.Prime] : (∏ q ∈ vonStaudtPrimes k with q ≠ p, ((1 : ℚ) / q).den).Coprime p := by refine Nat.Coprime.prod_left fun q hq ↦ ?_ simp only [Finset.mem_filter, Finset.mem_range] at hq @@ -457,7 +457,7 @@ private lemma prod_one_div_prime_den_coprime (k p : ℕ) [Fact p.Prime] : /- Splits the prime-indexed correction sum into the `p`-term (`vonStaudtIndicator / p`) plus the rest. -/ -private lemma sum_one_div_prime_eq_indicator_div_add {k : ℕ} (p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma sum_one_div_prime_eq_indicator_div_add {k p : ℕ} (hk : k > 0) [Fact p.Prime] : (∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q) = vonStaudtIndicator (2 * k) p / p + ∑ q ∈ vonStaudtPrimes k with q ≠ p, (1 : ℚ) / q := by rw [Finset.sum_congr (Finset.filter_ne' (vonStaudtPrimes k) p) fun _ _ ↦ rfl] @@ -521,7 +521,7 @@ private lemma choose_two_mul_succ_mul_div_eq {k m : ℕ} (x : ℚ) (hm_lt : m < exact_mod_cast Nat.choose_mul_succ_eq (2 * k) (2 * m) |>.symm /- `p`-integrality of the core even-index summand after denominator normalization. -/ -private lemma pIntegral_choose_mul_pow_div {k m : ℕ} (p : ℕ) (hm_lt : m < k) [Fact p.Prime] +private lemma pIntegral_choose_mul_pow_div {k m p : ℕ} (hm_lt : m < k) [Fact p.Prime] (hd : 2 * k - 2 * m ≥ 2) : pIntegral p (((2 * k).choose (2 * m) : ℚ) * p ^ (2 * k - 2 * m - 1) / (2 * k - 2 * m + 1)) := by set d := 2 * k - 2 * m with hd_def @@ -535,7 +535,7 @@ private lemma pIntegral_choose_mul_pow_div {k m : ℕ} (p : ℕ) (hm_lt : m < k) /- Uses the induction hypothesis on `B_{2m} + e_{2m}(p)/p` to prove `p`-integrality of the even term. -/ -private lemma pIntegral_bernoulli_even_term {k m : ℕ} (p : ℕ) (hm_lt : m < k) [Fact p.Prime] +private lemma pIntegral_bernoulli_even_term {k m p : ℕ} (hm_lt : m < k) [Fact p.Prime] (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by @@ -550,7 +550,7 @@ private lemma pIntegral_bernoulli_even_term {k m : ℕ} (p : ℕ) (hm_lt : m < k vonStaudtIndicator (2 * m) p * ((2 * k + 1).choose (2 * m)) * P / (2 * k + 1) := by rw [hpow]; field_simp [hp_ne]; ring rw [hdecomp] - have hcmp := pIntegral_choose_mul_pow_div p hm_lt (by lia) + have hcmp := pIntegral_choose_mul_pow_div (p := p) hm_lt (by lia) have H x := choose_two_mul_succ_mul_div_eq x hm_lt apply (Rat.padicValuation p).map_sub_le · rw [mul_assoc, mul_div_assoc] @@ -567,7 +567,7 @@ private lemma pIntegral_bernoulli_even_term {k m : ℕ} (p : ℕ) (hm_lt : m < k · simp /- The full remainder sum in Faulhaber's formula is `p`-integral. -/ -private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] +private lemma pIntegral_faulhaber_sum {k p : ℕ} (hk : k > 0) [Fact p.Prime] (ih : ∀ m, 0 < m → m < k → pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : pIntegral p (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * p ^ (2 * k - i) / (2 * k + 1)) := by @@ -591,7 +591,7 @@ private lemma pIntegral_faulhaber_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] · rcases Nat.even_or_odd (i + 2) with ⟨m, hm⟩ | hodd · have ⟨hm_pos, hm_lt, hi_eq⟩ : 0 < m ∧ m < k ∧ i + 2 = 2 * m := by lia simp only [hi_eq] - exact pIntegral_bernoulli_even_term p hm_lt (ih m hm_pos hm_lt) + exact pIntegral_bernoulli_even_term hm_lt (ih m hm_pos hm_lt) · simp [bernoulli_eq_zero_of_odd hodd (by lia)] private lemma sum_pow_filter_eq_faulhaber {k : ℕ} (p : ℕ) (hk : 0 < k) : @@ -605,7 +605,7 @@ private lemma sum_pow_filter_eq_faulhaber {k : ℕ} (p : ℕ) (hk : 0 < k) : push_cast field_simp -private lemma faulhaber_sum_div_prime_eq {k : ℕ} (p : ℕ) [Fact p.Prime] : +private lemma faulhaber_sum_div_prime_eq {k p : ℕ} [Fact p.Prime] : (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = ∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * @@ -619,13 +619,13 @@ private lemma faulhaber_sum_div_prime_eq {k : ℕ} (p : ℕ) [Fact p.Prime] : /- Rearranges the Faulhaber identity and power-sum congruence to isolate `bernoulli (2*k) + vonStaudtIndicator (2*k) p / p`. -/ -private lemma bernoulli_add_indicator_eq_sub {k : ℕ} (p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma bernoulli_add_indicator_eq_sub {k p : ℕ} (hk : k > 0) [Fact p.Prime] : ∃ T : ℤ, bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p = T - (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by have hcast : (↑((∑ v ∈ Ico 1 p, (v : ℤ) ^ (2 * k)) + (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := - mod_cast sum_pow_add_indicator_eq_zero p _ + mod_cast sum_pow_add_indicator_eq_zero (p := p) _ obtain ⟨T, hT_int⟩ := (ZMod.intCast_zmod_eq_zero_iff_dvd _ _).mp hcast use T have hT : (∑ v ∈ Ico 1 p, (v : ℚ) ^ (2 * k)) + vonStaudtIndicator (2 * k) p = @@ -635,28 +635,28 @@ private lemma bernoulli_add_indicator_eq_sub {k : ℕ} (p : ℕ) (hk : k > 0) [F T - (∑ i ∈ range (2 * k), bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) / p := by field_simp [hp_ne]; linarith [hT, sum_pow_filter_eq_faulhaber p hk] - rw [hAlg]; congr 1; simpa using faulhaber_sum_div_prime_eq p + rw [hAlg]; congr 1; simpa using faulhaber_sum_div_prime_eq /- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ -private lemma not_dvd_den_bernoulli_add_indicator {k : ℕ} (p : ℕ) (hk : k > 0) [Fact p.Prime] : +private lemma not_dvd_den_bernoulli_add_indicator {k p : ℕ} (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + vonStaudtIndicator (2 * k) p / p).den := by induction k using Nat.strong_induction_on with | _ k ih => - obtain ⟨T, hT⟩ := bernoulli_add_indicator_eq_sub p hk + obtain ⟨T, hT⟩ := bernoulli_add_indicator_eq_sub (p := p) hk rw [hT] have hT_int : pIntegral p T := Int.padicValuation_le_one p T - have hR := pIntegral_faulhaber_sum k p hk fun m hm_pos hm_lt ↦ + have hR := pIntegral_faulhaber_sum hk fun m hm_pos hm_lt ↦ Rat.padicValuation_le_one_iff.mpr (ih m hm_lt hm_pos) exact Rat.padicValuation_le_one_iff.mp ((Rat.padicValuation p).map_sub_le hT_int hR) /- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ private lemma not_dvd_den_vonStaudt_sum {k p : ℕ} (hk : k > 0) [Fact p.Prime] : ¬ p ∣ (bernoulli (2 * k) + ∑ q ∈ vonStaudtPrimes k, (1 : ℚ) / q).den := by - rw [sum_one_div_prime_eq_indicator_div_add p hk, ← add_assoc] + rw [sum_one_div_prime_eq_indicator_div_add (p := p) hk, ← add_assoc] have hcop_ind := ((Nat.Prime.coprime_iff_not_dvd Fact.out).mpr - (not_dvd_den_bernoulli_add_indicator p hk)).symm + (not_dvd_den_bernoulli_add_indicator (p := p) hk)).symm have hcop_rest := Nat.Coprime.of_dvd_left (den_sum_dvd_prod_den _ _) - (prod_one_div_prime_den_coprime k p) + (prod_one_div_prime_den_coprime k (p := p)) have hcop := (Nat.Coprime.of_dvd_left (Rat.add_den_dvd _ _) (hcop_ind.mul_left hcop_rest)).symm exact (Nat.Prime.coprime_iff_not_dvd Fact.out).1 hcop From 6e079d416b4c3f0d6d28245ff486f531c6742696 Mon Sep 17 00:00:00 2001 From: Seewoo Lee <49933279+seewoo5@users.noreply.github.com> Date: Sun, 26 Apr 2026 15:33:29 -0700 Subject: [PATCH 68/70] Update Mathlib/NumberTheory/Bernoulli.lean Co-authored-by: Michael Stoll <99838730+MichaelStollBayreuth@users.noreply.github.com> --- Mathlib/NumberTheory/Bernoulli.lean | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index c9cbc58f7c4c95..6c0978910a1d36 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -578,16 +578,16 @@ private lemma pIntegral_faulhaber_sum {k p : ℕ} (hk : k > 0) [Fact p.Prime] exact_mod_cast pIntegral_pow_div (by lia) (factorization_succ_le_sub_one (by lia) |>.trans tsub_le_self) · rw [zero_add, Nat.choose_one_right, bernoulli_one] - have : (-1 / 2 : ℚ) * ((2 * k + 1 : ℕ) : ℚ) * p ^ (2 * k - 1) / (2 * k + 1) = - (-1 / 2 : ℚ) * p ^ (2 * k - 1) := by field_simp; push_cast; ring - rw [this] + push_cast + field_simp obtain rfl | hp2 := eq_or_ne p 2 - · have h : ((-1 / 2 : ℚ) * (2 : ℚ) ^ (2 * k - 1)) = -(2 : ℤ) ^ (2 * k - 2) := by - rw [show 2 * k - 1 = (2 * k - 2) + 1 by lia, pow_succ]; push_cast; field_simp - simpa [h] using Int.padicValuation_le_one 2 (-(2 : ℤ) ^ (2 * k - 2)) - · refine pIntegral_mul ?_ ?_ <;> rw [pIntegral, Rat.padicValuation_le_one_iff] - · norm_num [Nat.prime_dvd_prime_iff_eq Fact.out Nat.prime_two, hp2] - · simp [show p ≠ 1 from Nat.Prime.ne_one Fact.out] + · push_cast + rw [show 2 * k - 1 = (2 * k - 2) + 1 by lia, pow_succ, mul_div_cancel_right₀ _ two_ne_zero] + exact_mod_cast Int.padicValuation_le_one .. + · rw [Valuation.map_neg] + refine pIntegral_pow_div _ _ _ two_ne_zero <| + (factorization_eq_zero_of_lt ?_).trans_le (by lia) + exact (Prime.odd_iff Fact.out).mp <| Prime.odd_of_ne_two Fact.out hp2 · rcases Nat.even_or_odd (i + 2) with ⟨m, hm⟩ | hodd · have ⟨hm_pos, hm_lt, hi_eq⟩ : 0 < m ∧ m < k ∧ i + 2 = 2 * m := by lia simp only [hi_eq] From 0a9afa3806e58f6061afad3687a86df0a3ef3ef5 Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sun, 26 Apr 2026 15:34:16 -0700 Subject: [PATCH 69/70] fix implicit --- Mathlib/NumberTheory/Bernoulli.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index 6c0978910a1d36..db19db6922d4c5 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -585,7 +585,7 @@ private lemma pIntegral_faulhaber_sum {k p : ℕ} (hk : k > 0) [Fact p.Prime] rw [show 2 * k - 1 = (2 * k - 2) + 1 by lia, pow_succ, mul_div_cancel_right₀ _ two_ne_zero] exact_mod_cast Int.padicValuation_le_one .. · rw [Valuation.map_neg] - refine pIntegral_pow_div _ _ _ two_ne_zero <| + refine pIntegral_pow_div two_ne_zero <| (factorization_eq_zero_of_lt ?_).trans_le (by lia) exact (Prime.odd_iff Fact.out).mp <| Prime.odd_of_ne_two Fact.out hp2 · rcases Nat.even_or_odd (i + 2) with ⟨m, hm⟩ | hodd From a0bf527be49f39c261975676082068b3dbabce2e Mon Sep 17 00:00:00 2001 From: Seewoo Lee Date: Sun, 26 Apr 2026 15:45:30 -0700 Subject: [PATCH 70/70] lake mk_all --- Mathlib.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib.lean b/Mathlib.lean index 4c2d2eba135003..d320e9e71e3e89 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -73,6 +73,7 @@ public import Mathlib.Algebra.BigOperators.Group.Finset.Pi public import Mathlib.Algebra.BigOperators.Group.Finset.Piecewise public import Mathlib.Algebra.BigOperators.Group.Finset.Powerset public import Mathlib.Algebra.BigOperators.Group.Finset.Preimage +public import Mathlib.Algebra.BigOperators.Group.Finset.Rat public import Mathlib.Algebra.BigOperators.Group.Finset.Sigma public import Mathlib.Algebra.BigOperators.Group.List.Basic public import Mathlib.Algebra.BigOperators.Group.List.Defs