From 23cbc1d8f1a50299ce32056633f263ef7e8c5838 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Sat, 4 Apr 2026 00:31:36 +0100 Subject: [PATCH 01/49] save --- Mathlib.lean | 2 + Mathlib/NumberTheory/ModularForms/Basic.lean | 24 +++++ .../ModularForms/CongruenceSubgroups.lean | 4 + .../ModularForms/Discriminant.lean | 87 ++++++++++++++++++- .../ModularForms/EisensteinSeries/Basic.lean | 7 +- .../EisensteinSeries/QExpansion.lean | 7 +- .../NumberTheory/ModularForms/LevelOne.lean | 8 +- 7 files changed, 131 insertions(+), 8 deletions(-) diff --git a/Mathlib.lean b/Mathlib.lean index 293afedbdf27b2..c8637a2c3d8cc8 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5578,6 +5578,7 @@ public import Mathlib.NumberTheory.ModularForms.Basic public import Mathlib.NumberTheory.ModularForms.BoundedAtCusp public import Mathlib.NumberTheory.ModularForms.Bounds public import Mathlib.NumberTheory.ModularForms.CongruenceSubgroups +public import Mathlib.NumberTheory.ModularForms.CuspFormSubmodule public import Mathlib.NumberTheory.ModularForms.Cusps public import Mathlib.NumberTheory.ModularForms.DedekindEta public import Mathlib.NumberTheory.ModularForms.Delta @@ -5600,6 +5601,7 @@ public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Manifold public import Mathlib.NumberTheory.ModularForms.JacobiTheta.OneVariable public import Mathlib.NumberTheory.ModularForms.JacobiTheta.TwoVariable public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.LevelOne public import Mathlib.NumberTheory.ModularForms.NormTrace public import Mathlib.NumberTheory.ModularForms.Petersson public import Mathlib.NumberTheory.ModularForms.QExpansion diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index daff18550bed69..3100c9f841d33d 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -370,6 +370,18 @@ lemma coe_intCast [Γ.HasDetPlusMinusOne] (z : ℤ) : lemma toSlashInvariantForm_intCast [Γ.HasDetPlusMinusOne] (z : ℤ) : (z : ModularForm Γ 0).toSlashInvariantForm = z := rfl +/-- Transport a modular form along an equality of subgroups. -/ +def ofSubgroupEq {Γ' : Subgroup (GL (Fin 2) ℝ)} (h : Γ = Γ') (f : ModularForm Γ k) : + ModularForm Γ' k where + toFun := f + slash_action_eq' A hA := f.slash_action_eq' A (h ▸ hA) + holo' := f.holo' + bdd_at_cusps' hc := f.bdd_at_cusps' (h ▸ hc) + +@[simp] +lemma ofSubgroupEq_apply {Γ' : Subgroup (GL (Fin 2) ℝ)} (h : Γ = Γ') (f : ModularForm Γ k) + (z : ℍ) : (f.ofSubgroupEq h) z = f z := rfl + end ModularForm namespace CuspForm @@ -504,6 +516,18 @@ instance (priority := 99) [FunLike F ℍ ℂ] [CuspFormClass F Γ k] : ModularFo holo := CuspFormClass.holo bdd_at_cusps f _ hc g hg := (CuspFormClass.zero_at_cusps f hc g hg).boundedAtFilter +/-- Transport a cusp form along an equality of subgroups. -/ +def ofSubgroupEq {Γ' : Subgroup (GL (Fin 2) ℝ)} (h : Γ = Γ') (f : CuspForm Γ k) : + CuspForm Γ' k where + toFun := f + slash_action_eq' A hA := f.slash_action_eq' A (h ▸ hA) + holo' := f.holo' + zero_at_cusps' hc := f.zero_at_cusps' (h ▸ hc) + +@[simp] +lemma ofSubgroupEq_apply {Γ' : Subgroup (GL (Fin 2) ℝ)} (h : Γ = Γ') (f : CuspForm Γ k) + (z : ℍ) : (f.ofSubgroupEq h) z = f z := rfl + end CuspForm namespace ModularForm diff --git a/Mathlib/NumberTheory/ModularForms/CongruenceSubgroups.lean b/Mathlib/NumberTheory/ModularForms/CongruenceSubgroups.lean index c2e8ed6841c1f1..bda2a576528cb1 100644 --- a/Mathlib/NumberTheory/ModularForms/CongruenceSubgroups.lean +++ b/Mathlib/NumberTheory/ModularForms/CongruenceSubgroups.lean @@ -69,6 +69,10 @@ theorem Gamma_one_top : Gamma 1 = ⊤ := by lemma mem_Gamma_one (γ : SL(2, ℤ)) : γ ∈ Γ(1) := by simp only [Gamma_one_top, Subgroup.mem_top] +/-- The GL-image of `Γ(1)` equals `𝒮ℒ` (the image of `SL(2, ℤ)` in `GL(2, ℝ)`). -/ +theorem Gamma_one_coe_eq_SL : (↑(Gamma 1) : Subgroup (GL (Fin 2) ℝ)) = 𝒮ℒ := by + change (Gamma 1).map (mapGL ℝ) = (mapGL ℝ).range; rw [Gamma_one_top, MonoidHom.range_eq_map] + theorem Gamma_zero_bot : Gamma 0 = ⊥ := rfl lemma ModularGroup_T_pow_mem_Gamma (N M : ℤ) (hNM : N ∣ M) : diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index 6861c50bb5bb92..fbca87f567f656 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -11,6 +11,7 @@ public import Mathlib.NumberTheory.ModularForms.DedekindEta public import Mathlib.NumberTheory.ModularForms.Basic public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.E2.Transform public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.QExpansion /-! # The modular discriminant Δ @@ -35,7 +36,8 @@ be expressed as `q * ∏' (1 - q ^ (n + 1)) ^ 24` where `q = e ^ (2πiz)`. * [F. Diamond and J. Shurman, *A First Course in Modular Forms*][diamondshurman2005], section 1.2 -/ -open Function Complex Topology Filter SlashInvariantForm CongruenceSubgroup MatrixGroups +open Function Complex Topology Filter SlashInvariantForm SlashInvariantFormClass + CongruenceSubgroup MatrixGroups ModularFormClass open UpperHalfPlane hiding I @@ -192,6 +194,89 @@ def discriminantCuspForm : CuspForm 𝒮ℒ 12 where rw [slash_action_generators_SL2Z discriminant_S_invariant discriminant_T_invariant] exact discriminant_isZeroAtImInfty +/-- The infinite product `∏ (1 - q^(n+1))` is multipliable for `‖q‖ < 1`. -/ +private lemma multipliable_one_sub_pow {q : ℂ} (hq : ‖q‖ < 1) : + Multipliable fun i ↦ 1 - q ^ (i + 1) := by + rw [show (fun i ↦ 1 - q ^ (i + 1)) = (fun i ↦ 1 + (-q ^ (i + 1))) from by ext; ring] + apply multipliable_one_add_of_summable + simp only [norm_neg, norm_pow] + exact (summable_nat_add_iff 1).mpr (summable_geometric_of_lt_one (norm_nonneg _) hq) + +/-- The cusp function of the discriminant equals `q * ∏' n, (1 - q^(n+1))^24` +on `ball 0 (1/2)`. -/ +private lemma discriminant_cuspFunction_eqOn : + Set.EqOn (cuspFunction 1 (Δ : ℍ → ℂ)) + (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) := by + intro q hq + by_cases hq0 : q = 0 + · simp only [hq0, zero_mul] + exact Periodic.cuspFunction_zero_of_zero_at_inf one_pos + discriminant_isZeroAtImInfty.zero_at_infty_comp_ofComplex + · have hqn : ‖q‖ < 1 := lt_trans (by simpa [dist_zero_right] using hq) (by norm_num) + have him := Periodic.im_invQParam_pos_of_norm_lt_one one_pos hqn hq0 + rw [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, + comp_apply, ofComplex_apply_of_im_pos him, discriminant_eq_q_prod ⟨_, him⟩] + -- eta_q n z = (qParam 1 z)^(n+1), and qParam(invQParam(q)) = q + have hqr := Periodic.qParam_right_inv one_ne_zero hq0 + have heta : ∀ n : ℕ, eta_q n (Periodic.invQParam 1 q) = q ^ (n + 1) := fun n ↦ by + simp [eta_q, hqr] + simp only [hqr, heta] + +/-- The partial products `∏_{i simp [differentiableOn_const] + | succ n ih => + simp_rw [Finset.prod_range_succ]; exact ih.mul (by fun_prop)) + Metric.isOpen_ball + have hmem := Metric.mem_ball_self (x := (0 : ℂ)) (by norm_num : (0 : ℝ) < 1 / 2) + -- (∏(1-q^(n+1)))^24 is differentiable as a power of a differentiable function + have h24 := (hdiff 0 hmem).pow (n := 24) + -- ∏(1-q^(n+1))^24 = (∏(1-q^(n+1)))^24 by tprod_pow, so congr gives differentiability + refine h24.congr (fun q hq ↦ ?_) (by simp) + exact (multipliable_one_sub_pow (lt_trans (by simpa [dist_zero_right] using hq) + (by norm_num : (1 : ℝ) / 2 < 1))).tprod_pow 24 + +/-- The first q-expansion coefficient of the modular discriminant is 1. -/ +lemma discriminant_qExpansion_coeff_one : + (qExpansion 1 (discriminantCuspForm : ℍ → ℂ)).coeff 1 = 1 := by + rw [qExpansion_coeff] + simp only [Nat.factorial_one, Nat.cast_one, inv_one, one_mul, iteratedDeriv_succ, + iteratedDeriv_zero] + have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) (1 / 2 : ℝ) := Metric.mem_ball_self (by norm_num) + change deriv (cuspFunction 1 Δ) 0 = 1 + rw [← derivWithin_of_isOpen Metric.isOpen_ball hmem] + rw [derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem)] + have : derivWithin (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) 0 = + derivWithin id (Metric.ball 0 (1 / 2)) 0 * (∏' i, (1 - (0 : ℂ) ^ (i + 1)) ^ 24) + + id 0 * derivWithin (fun q ↦ ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) 0 := + derivWithin_mul differentiableWithinAt_id' differentiableWithinAt_eta_prod_pow + rw [this, derivWithin_id _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] + simp + end end ModularForm diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Basic.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Basic.lean index 386d86e4de8bbf..e6e4c33ee3bf95 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Basic.lean @@ -26,7 +26,7 @@ noncomputable section namespace ModularForm -open EisensteinSeries CongruenceSubgroup Matrix.SpecialLinearGroup +open EisensteinSeries CongruenceSubgroup Matrix.SpecialLinearGroup MatrixGroups /-- This defines Eisenstein series as modular forms of weight `k`, level `Γ(N)` and congruence condition given by `a : Fin 2 → ZMod N`. -/ @@ -44,7 +44,8 @@ def eisensteinSeriesMF {k : ℤ} {N : ℕ} [NeZero N] (hk : 3 ≤ k) (a : Fin 2 /-- Normalised Eisenstein series of level 1 and weight `k`, here they have been scaled by `1/2` since we sum over coprime pairs. -/ -noncomputable def E {k : ℕ} (hk : 3 ≤ k) : ModularForm Γ(1) k := - (1 / 2 : ℂ) • eisensteinSeriesMF (mod_cast hk) 0 +noncomputable def E {k : ℕ} (hk : 3 ≤ k) : ModularForm 𝒮ℒ k := + ((1 / 2 : ℂ) • eisensteinSeriesMF (mod_cast hk) 0).ofSubgroupEq + CongruenceSubgroup.Gamma_one_coe_eq_SL end ModularForm diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean index 96dab6415c09b5..158f8c89164524 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean @@ -43,7 +43,7 @@ public section open Set Metric TopologicalSpace Function Filter Complex ArithmeticFunction ModularForm EisensteinSeries -open scoped Topology Real Nat Complex Pointwise ArithmeticFunction.sigma +open scoped Topology Real Nat Complex Pointwise ArithmeticFunction.sigma MatrixGroups open _root_.UpperHalfPlane hiding I @@ -277,7 +277,8 @@ lemma EisensteinSeries.q_expansion_riemannZeta {k : ℕ} (hk : 3 ≤ k) (hk2 : E E hk z = 1 + (riemannZeta k)⁻¹ * (-2 * π * I) ^ k / (k - 1)! * ∑' n : ℕ+, σ (k - 1) n * cexp (2 * π * I * z) ^ (n : ℤ) := by have : eisensteinSeriesMF (Int.toNat_le.mp hk) 0 z = eisensteinSeriesSIF (N := 1) 0 k z := rfl - rw [E, ModularForm.IsGLPos.smul_apply, this, eisensteinSeriesSIF_apply 0 k z, eisensteinSeries] + rw [E, ModularForm.ofSubgroupEq_apply, ModularForm.IsGLPos.smul_apply, this, + eisensteinSeriesSIF_apply 0 k z, eisensteinSeries] have HE1 := tsum_eisSummand_eq_tsum_sigma_mul_cexp_pow hk hk2 z have HE2 := tsum_eisSummand_eq_riemannZeta_mul_eisensteinSeries hk z have z2 : riemannZeta k ≠ 0 := riemannZeta_ne_zero_of_one_lt_re <| by norm_cast; grind @@ -326,6 +327,8 @@ lemma EisensteinSeries.E_qExpansion_coeff {k : ℕ} (hk : 3 ≤ k) (hk2 : Even k if m = 0 then 1 else -(2 * k / bernoulli k : ℂ) * (σ (k - 1) m) := by set β : ℂ := -(2 * k / bernoulli k : ℂ) set c : ℕ → ℂ := fun m ↦ if m = 0 then 1 else β * ↑(σ (k - 1) m) + haveI : ModularFormClass (ModularForm 𝒮ℒ k) (CongruenceSubgroup.Gamma 1) k := + CongruenceSubgroup.Gamma_one_coe_eq_SL ▸ inferInstance suffices ∀ τ : ℍ, HasSum (fun m ↦ c m • 𝕢 (1 : ℝ) τ ^ m) (E hk τ) from (qExpansion_coeff_unique one_pos one_mem_strictPeriods_SL2Z this m).symm intro τ diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne.lean index f62bd3810ea1c2..30c515d4933a0b 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne.lean @@ -104,12 +104,16 @@ lemma levelOne_weight_zero_const [ModularFormClass F Γ(1) 0] (f : F) : end ModularFormClass -lemma ModularForm.levelOne_weight_zero_rank_one : Module.rank ℂ (ModularForm Γ(1) 0) = 1 := by +lemma ModularForm.levelOne_weight_zero_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ 0) = 1 := by + haveI : ModularFormClass (ModularForm 𝒮ℒ 0) Γ(1) 0 := + Gamma_one_coe_eq_SL ▸ inferInstance refine rank_eq_one (const 1) (by simp [DFunLike.ne_iff]) fun g ↦ ?_ obtain ⟨c', hc'⟩ := levelOne_weight_zero_const g aesop lemma ModularForm.levelOne_neg_weight_rank_zero (hk : k < 0) : - Module.rank ℂ (ModularForm Γ(1) k) = 0 := by + Module.rank ℂ (ModularForm 𝒮ℒ k) = 0 := by + haveI : ModularFormClass (ModularForm 𝒮ℒ k) Γ(1) k := + Gamma_one_coe_eq_SL ▸ inferInstance refine rank_eq_zero_iff.mpr fun f ↦ ⟨_, one_ne_zero, ?_⟩ simpa [← coe_eq_zero_iff] using levelOne_neg_weight_eq_zero hk f From 1548cacc125e261f1d66152aae1d53ef3005ba13 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 08:22:54 +0100 Subject: [PATCH 02/49] feat(NumberTheory/ModularForms): add cusp form submodule and level one dimension formula Adds `CuspFormSubmodule.lean` providing the cusp form submodule of modular forms together with API, and `DimensionFormulas/LevelOne.lean` proving the classical dimension formula for spaces of level one modular forms. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ModularForms/CuspFormSubmodule.lean | 143 ++++++ .../DimensionFormulas/LevelOne.lean | 463 ++++++++++++++++++ 2 files changed, 606 insertions(+) create mode 100644 Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean create mode 100644 Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean diff --git a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean new file mode 100644 index 00000000000000..b75d24bcfa9c34 --- /dev/null +++ b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean @@ -0,0 +1,143 @@ +/- +Copyright (c) 2026 Chris Birkbeck. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Birkbeck +-/ +import Mathlib.NumberTheory.ModularForms.QExpansion +import Mathlib.NumberTheory.ModularForms.LevelOne +import Mathlib.NumberTheory.ModularForms.EisensteinSeries.QExpansion + +/-! +# Cusp form submodule and IsCuspForm predicate + +This file defines the inclusion of cusp forms into modular forms as a linear map, the cusp form +submodule of modular forms, and the `IsCuspForm` predicate. It also provides a direct constructor +`ModularForm.toCuspForm` for building cusp forms from modular forms with vanishing constant +q-expansion coefficient (for `𝒮ℒ`). + +## Main definitions + +* `CuspForm.toModularFormₗ`: the inclusion `CuspForm Γ k →ₗ[ℂ] ModularForm Γ k`. +* `ModularForm.cuspFormSubmodule`: the submodule of `ModularForm Γ k` consisting of cusp forms. +* `ModularForm.IsCuspForm`: predicate that a modular form lies in the cusp form submodule. +* `ModularForm.toCuspForm`: builds a `CuspForm 𝒮ℒ k` from a `ModularForm` whose q-expansion + has vanishing constant term. + +## Main results + +* `CuspForm.toModularFormₗ_injective`: the inclusion is injective. +* `CuspForm.equivCuspFormSubmodule`: `CuspForm Γ k ≃ₗ[ℂ] cuspFormSubmodule Γ k`. +* `ModularForm.isCuspForm_iff_coeffZero_eq_zero`: for `𝒮ℒ`, `IsCuspForm` is equivalent to the + q-expansion having vanishing constant term. +-/ + +open UpperHalfPlane ModularForm Complex SlashInvariantForm SlashInvariantFormClass + ModularFormClass MatrixGroups OnePoint Filter Topology + +noncomputable section + +variable {Γ : Subgroup (GL (Fin 2) ℝ)} {k : ℤ} + +namespace CuspForm + +/-- The inclusion of cusp forms into modular forms, as a ℂ-linear map. -/ +def toModularFormₗ [Γ.HasDetOne] : CuspForm Γ k →ₗ[ℂ] ModularForm Γ k where + toFun f := + { toSlashInvariantForm := f.toSlashInvariantForm + holo' := f.holo' + bdd_at_cusps' := fun hc g hg ↦ (f.zero_at_cusps' hc g hg).boundedAtFilter } + map_add' _ _ := by ext; rfl + map_smul' _ _ := by ext; rfl + +@[simp] +lemma toModularFormₗ_apply [Γ.HasDetOne] (f : CuspForm Γ k) (z : ℍ) : + (toModularFormₗ f) z = f z := rfl + +lemma toModularFormₗ_injective [Γ.HasDetOne] : + Function.Injective (toModularFormₗ : CuspForm Γ k → ModularForm Γ k) := + fun _ _ h ↦ DFunLike.ext _ _ fun z ↦ congr_fun (congr_arg DFunLike.coe h) z + +end CuspForm + +namespace ModularForm + +/-- The submodule of `ModularForm Γ k` consisting of cusp forms, defined as the range of +the inclusion `CuspForm.toModularFormₗ`. -/ +def cuspFormSubmodule [Γ.HasDetOne] : Submodule ℂ (ModularForm Γ k) := + LinearMap.range (CuspForm.toModularFormₗ) + +/-- A modular form is a cusp form if it lies in the cusp form submodule. -/ +def IsCuspForm [Γ.HasDetOne] (f : ModularForm Γ k) : Prop := + f ∈ cuspFormSubmodule (Γ := Γ) (k := k) + +/-- The cusp form submodule is linearly equivalent to the type of cusp forms. -/ +def CuspForm.equivCuspFormSubmodule [Γ.HasDetOne] : + CuspForm Γ k ≃ₗ[ℂ] cuspFormSubmodule (Γ := Γ) (k := k) := + LinearEquiv.ofInjective CuspForm.toModularFormₗ CuspForm.toModularFormₗ_injective + +/-- A modular form is a cusp form if and only if it vanishes at every cusp. This is the +general characterization valid for any subgroup. -/ +lemma isCuspForm_iff [Γ.HasDetOne] (f : ModularForm Γ k) : + IsCuspForm f ↔ ∀ {c : OnePoint ℝ}, IsCusp c Γ → c.IsZeroAt f k := by + constructor + · rintro ⟨g, hg⟩ c hc + have : (f : ℍ → ℂ) = (g : ℍ → ℂ) := congr_arg DFunLike.coe hg.symm + simpa [this] using g.zero_at_cusps' hc + · intro h + exact ⟨⟨f.toSlashInvariantForm, f.holo', h⟩, by ext; rfl⟩ + +section SL2Z + +open EisensteinSeries + +variable {k : ℤ} + +lemma one_mem_strictPeriods_SL : (1 : ℝ) ∈ (𝒮ℒ : Subgroup (GL (Fin 2) ℝ)).strictPeriods := + CongruenceSubgroup.Gamma_one_coe_eq_SL ▸ one_mem_strictPeriods_SL2Z + +/-- If an `𝒮ℒ` modular form has `valueAtInfty f = 0`, then it is zero at infinity. -/ +lemma isZeroAtImInfty_of_valueAtInfty_eq_zero + (f : ModularForm 𝒮ℒ k) (h : valueAtInfty f = 0) : IsZeroAtImInfty f := by + change Filter.Tendsto f atImInfty (𝓝 0) + rw [show (0 : ℂ) = cuspFunction 1 f 0 from by + rw [cuspFunction_apply_zero f one_pos one_mem_strictPeriods_SL]; exact h.symm] + exact ((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt.tendsto.comp + (qParam_tendsto_atImInfty one_pos)).congr + (fun τ ↦ eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero) + +/-- An `𝒮ℒ` modular form with vanishing q-expansion constant term vanishes at every cusp. -/ +private lemma isZeroAt_of_coeffZero_eq_zero (f : ModularForm 𝒮ℒ k) + (h : (qExpansion 1 f).coeff 0 = 0) {c : OnePoint ℝ} (hc : IsCusp c 𝒮ℒ) : + c.IsZeroAt f k := by + rw [Subgroup.IsArithmetic.isCusp_iff_isCusp_SL2Z] at hc + rw [isZeroAt_iff_forall_SL2Z hc] + intro γ _ + rw [show (⇑f ∣[k] γ) = ⇑f from f.slash_action_eq' _ (MonoidHom.mem_range.mpr ⟨γ, rfl⟩)] + exact isZeroAtImInfty_of_valueAtInfty_eq_zero f <| by + rwa [← qExpansion_coeff_zero f one_pos one_mem_strictPeriods_SL] + +/-- Build a `CuspForm 𝒮ℒ k` from a `ModularForm 𝒮ℒ k` whose q-expansion has vanishing +constant term. The resulting cusp form has the same underlying function. -/ +def toCuspForm (f : ModularForm 𝒮ℒ k) (h : (qExpansion 1 f).coeff 0 = 0) : CuspForm 𝒮ℒ k where + toSlashInvariantForm := f.toSlashInvariantForm + holo' := f.holo' + zero_at_cusps' := isZeroAt_of_coeffZero_eq_zero f h + +@[simp] +lemma toCuspForm_apply (f : ModularForm 𝒮ℒ k) (h : (qExpansion 1 f).coeff 0 = 0) + (z : ℍ) : (toCuspForm f h) z = f z := rfl + +/-- For `𝒮ℒ` modular forms, `IsCuspForm` is equivalent to the q-expansion having vanishing +constant term. -/ +lemma isCuspForm_iff_coeffZero_eq_zero (f : ModularForm 𝒮ℒ k) : + IsCuspForm f ↔ (qExpansion 1 f).coeff 0 = 0 := by + constructor + · intro ⟨g, hg⟩ + rw [qExpansion_coeff_zero f one_pos one_mem_strictPeriods_SL] + exact congr_arg valueAtInfty (congr_arg DFunLike.coe hg.symm) ▸ + (CuspFormClass.zero_at_infty g).valueAtInfty_eq_zero + · exact fun h ↦ (isCuspForm_iff f).mpr (isZeroAt_of_coeffZero_eq_zero f h) + +end SL2Z + +end ModularForm diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean new file mode 100644 index 00000000000000..aff3fb037ce6be --- /dev/null +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -0,0 +1,463 @@ +/- +Copyright (c) 2026 Chris Birkbeck. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Birkbeck +-/ +import Mathlib.NumberTheory.ModularForms.CuspFormSubmodule +import Mathlib.NumberTheory.ModularForms.Discriminant +import Mathlib.Data.Rat.Star +import Mathlib.LinearAlgebra.Dimension.Localization + +/-! +# Dimension formula for level 1 modular forms + +This file proves the dimension formula for the space of modular forms for `𝒮ℒ` (= `SL(2, ℤ)`) +of even weight `k ≥ 3`. + +## Main results + +* `CuspForm.discriminantEquiv`: `CuspForm 𝒮ℒ k ≃ₗ[ℂ] ModularForm 𝒮ℒ (k - 12)`. +* `ModularForm.rank_eq_one_add_rank_cuspForm`: `rank M_k = 1 + rank S_k` for even `k ≥ 3`. +* `ModularForm.dimension_level_one`: the full dimension formula. +-/ + +open UpperHalfPlane ModularForm Complex SlashInvariantForm SlashInvariantFormClass + ModularFormClass CongruenceSubgroup MatrixGroups OnePoint Filter Topology EisensteinSeries + +noncomputable section + +/-! ### Delta isomorphism: `CuspForm 𝒮ℒ k ≃ₗ[ℂ] ModularForm 𝒮ℒ (k - 12)` -/ + +section DeltaIsomorphism + +variable {k : ℤ} + +local notation "Δ" => ModularForm.discriminant + +namespace CuspForm + +/-- Multiply a modular form of weight `k - 12` by the discriminant to get a cusp form of +weight `k`. Built directly as a CuspForm (no `IsCuspForm` intermediary). -/ +def ofMulDiscriminant (f : ModularForm 𝒮ℒ (k - 12)) : CuspForm 𝒮ℒ k := + let Δ' := CuspForm.toModularFormₗ discriminantCuspForm + ModularForm.toCuspForm (ModularForm.mcast (by ring) (f.mul Δ')) (by + have : (qExpansion 1 (Δ' : ℍ → ℂ)).coeff 0 = 0 := by + rw [qExpansion_coeff_zero Δ' one_pos one_mem_strictPeriods_SL] + exact (CuspFormClass.zero_at_infty discriminantCuspForm).valueAtInfty_eq_zero + rw [show (ModularForm.mcast _ (f.mul Δ') : ℍ → ℂ) = (f : ℍ → ℂ) * Δ' from rfl, + qExpansion_mul_coeff_zero + (analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt + (analyticAt_cuspFunction_zero Δ' one_pos one_mem_strictPeriods_SL).continuousAt, + this, mul_zero]) + +@[simp] +lemma ofMulDiscriminant_apply (f : ModularForm 𝒮ℒ (k - 12)) (z : ℍ) : + (ofMulDiscriminant f) z = f z * Δ z := rfl + +private lemma divByDiscriminant_slash_eq (f : CuspForm 𝒮ℒ k) (γ : SL(2, ℤ)) : + (fun z ↦ f z / Δ z) ∣[k - 12] γ = fun z ↦ f z / Δ z := by + haveI : SlashInvariantFormClass (CuspForm 𝒮ℒ k) (CongruenceSubgroup.Gamma 1) k := + CongruenceSubgroup.Gamma_one_coe_eq_SL ▸ inferInstance + haveI : SlashInvariantFormClass (CuspForm 𝒮ℒ 12) (CongruenceSubgroup.Gamma 1) 12 := + CongruenceSubgroup.Gamma_one_coe_eq_SL ▸ inferInstance + have hf := slash_action_eqn_SL'' f (mem_Gamma_one γ) + have hΔ := slash_action_eqn_SL'' discriminantCuspForm (mem_Gamma_one γ) + ext z + rw [SL_slash_apply, hf, show Δ (γ • z) = denom γ z ^ (12 : ℤ) * Δ z from by + exact_mod_cast hΔ z] + have hd : (denom γ z : ℂ) ≠ 0 := denom_ne_zero γ z + rw [div_mul_eq_mul_div, mul_right_comm, ← zpow_add₀ hd, + show k + -(k - 12) = (12 : ℤ) from by ring] + exact mul_div_mul_left (f z) (Δ z) (zpow_ne_zero _ hd) + +private lemma exp_decay_isBigO_discriminant (f : CuspForm 𝒮ℒ k) : + (f : ℍ → ℂ) =O[atImInfty] Δ := by + have hf_decay := CuspFormClass.exp_decay_atImInfty (h := 1) f one_pos one_mem_strictPeriods_SL + have hΔ_lower : ∀ᶠ τ : ℍ in atImInfty, + ‖(fun τ : ℍ ↦ Real.exp (-2 * Real.pi * τ.im / 1)) τ‖ ≤ 2 * ‖Δ τ‖ := by + have hprod := discriminant_bounded_factor.eventually + (Metric.ball_mem_nhds (1 : ℂ) (by norm_num : (0 : ℝ) < 1/2)) + filter_upwards [hprod] with τ hτ + simp only [div_one] + rw [discriminant_eq_q_prod, norm_mul, Real.norm_of_nonneg (Real.exp_pos _).le] + have hq_norm : ‖Function.Periodic.qParam 1 (τ : ℂ)‖ = + Real.exp (-2 * Real.pi * τ.im) := by + simp [Function.Periodic.qParam, Complex.norm_exp, Complex.mul_re, div_one] + rw [← hq_norm] + have hprod_bound : 1 / 2 ≤ ‖∏' (n : ℕ), (1 - eta_q n τ) ^ 24‖ := by + have hsub : ‖∏' (n : ℕ), (1 - eta_q n τ) ^ 24 - 1‖ < 1 / 2 := by + rwa [Complex.dist_eq] at hτ + have h1 := norm_sub_norm_le (1 : ℂ) (∏' (n : ℕ), (1 - eta_q n τ) ^ 24) + simp only [norm_one] at h1 + linarith [norm_sub_rev (1 : ℂ) (∏' (n : ℕ), (1 - eta_q n τ) ^ 24)] + linarith [norm_nonneg (Function.Periodic.qParam 1 (τ : ℂ)), + mul_le_mul_of_nonneg_left hprod_bound + (norm_nonneg (Function.Periodic.qParam 1 (τ : ℂ)))] + exact hf_decay.trans (Asymptotics.IsBigO.of_bound 2 hΔ_lower) + +/-- Divide a cusp form by the discriminant to get a modular form of weight `k - 12`. -/ +def divDiscriminant (f : CuspForm 𝒮ℒ k) : ModularForm 𝒮ℒ (k - 12) where + toFun z := f z / Δ z + slash_action_eq' A hA := by + obtain ⟨γ, rfl⟩ := hA + exact divByDiscriminant_slash_eq f γ + holo' := by + rw [UpperHalfPlane.mdifferentiable_iff] + apply DifferentiableOn.div + · exact UpperHalfPlane.mdifferentiable_iff.mp f.holo' + · exact UpperHalfPlane.mdifferentiable_iff.mp discriminantCuspForm.holo' + · intro z hz + simp only [ofComplex_apply_of_im_pos hz] + exact discriminant_ne_zero ⟨z, hz⟩ + bdd_at_cusps' {c} hc := by + rw [Subgroup.IsArithmetic.isCusp_iff_isCusp_SL2Z] at hc + rw [isBoundedAt_iff_forall_SL2Z hc] + intro γ _ + rw [divByDiscriminant_slash_eq f γ, IsBoundedAtImInfty, BoundedAtFilter] + exact (Asymptotics.div_isBoundedUnder_of_isBigO + (exp_decay_isBigO_discriminant f)).isBigO_one ℝ + +@[simp] +lemma divDiscriminant_apply (f : CuspForm 𝒮ℒ k) (z : ℍ) : + (divDiscriminant f) z = f z / Δ z := rfl + +/-- The linear equivalence between cusp forms of weight `k` and modular forms of weight `k - 12`, +given by division by the discriminant. -/ +def discriminantEquiv : CuspForm 𝒮ℒ k ≃ₗ[ℂ] ModularForm 𝒮ℒ (k - 12) where + toFun := divDiscriminant + map_add' a b := by ext z; simp [add_div] + map_smul' c a := by ext z; simp [mul_div_assoc] + invFun := ofMulDiscriminant + left_inv f := by + ext z + simp only [divDiscriminant_apply, ofMulDiscriminant_apply] + exact div_mul_cancel₀ (f z) (discriminant_ne_zero z) + right_inv f := by + ext z + simp only [ofMulDiscriminant_apply, divDiscriminant_apply] + exact mul_div_cancel_right₀ (f z) (discriminant_ne_zero z) + +end CuspForm + +end DeltaIsomorphism + +/-! ### Rank identities -/ + +section RankIdentity + +variable {k : ℤ} + +/-- Cusp forms of weight `k < 12` for `𝒮ℒ` are zero-dimensional. -/ +lemma cuspForm_rank_lt_twelve (hk : k < 12) : + Module.rank ℂ (CuspForm 𝒮ℒ k) = 0 := by + rw [LinearEquiv.rank_eq CuspForm.discriminantEquiv] + exact levelOne_neg_weight_rank_zero (by omega) + +/-- The space of weight 12 cusp forms for `𝒮ℒ` has rank 1. -/ +lemma cuspForm_rank_twelve : Module.rank ℂ (CuspForm 𝒮ℒ 12) = 1 := by + rw [LinearEquiv.rank_eq CuspForm.discriminantEquiv, + show (12 : ℤ) - 12 = 0 from by norm_num] + exact levelOne_weight_zero_rank_one + +/-- Every weight 12 cusp form for `𝒮ℒ` is a scalar multiple of the discriminant. -/ +lemma cuspForm_twelve_smul_discriminant (f : CuspForm 𝒮ℒ 12) : + ∃ c : ℂ, c • discriminantCuspForm = f := by + have hne : discriminantCuspForm ≠ 0 := fun h ↦ + discriminant_ne_zero UpperHalfPlane.I (congr_fun (congr_arg DFunLike.coe h) _) + exact (finrank_eq_one_iff_of_nonzero' discriminantCuspForm hne).mp + (Module.rank_eq_one_iff_finrank_eq_one.mp cuspForm_rank_twelve) f + +/-- For even `k ≥ 3`, the rank of `𝒮ℒ` modular forms is one more than the rank of +cusp forms. -/ +lemma ModularForm.rank_eq_one_add_rank_cuspForm {k : ℕ} (hk : 3 ≤ (k : ℤ)) (hk2 : Even k) : + Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ)) = 1 + Module.rank ℂ (CuspForm 𝒮ℒ (k : ℤ)) := by + have h_add := Submodule.rank_quotient_add_rank + (cuspFormSubmodule (Γ := 𝒮ℒ) (k := (k : ℤ))) + rw [show Module.rank ℂ ↥(cuspFormSubmodule (Γ := 𝒮ℒ) (k := (k : ℤ))) = + Module.rank ℂ (CuspForm 𝒮ℒ (k : ℤ)) from + (LinearEquiv.rank_eq CuspForm.equivCuspFormSubmodule).symm] at h_add + suffices h1 : Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ) ⧸ cuspFormSubmodule) = 1 by + rw [← h_add, h1] + have hk' : 3 ≤ k := by exact_mod_cast hk + have hE_coeff_zero := E_qExpansion_coeff_zero hk' hk2 + apply rank_eq_one (Submodule.Quotient.mk (p := cuspFormSubmodule) (E hk')) + · intro h + rw [Submodule.Quotient.mk_eq_zero] at h + exact one_ne_zero <| + hE_coeff_zero.symm.trans <| + (isCuspForm_iff_coeffZero_eq_zero _).mp h + · refine (Submodule.Quotient.mk_surjective _).forall.mpr fun f ↦ + ⟨(qExpansion 1 f).coeff 0, ?_⟩ + have h_mem : f - (qExpansion 1 ↑f).coeff 0 • E hk' ∈ + cuspFormSubmodule := + (isCuspForm_iff_coeffZero_eq_zero _).mpr (by + set c := (qExpansion 1 ↑f).coeff 0 with hc + have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (k : ℤ))).map_sub + f (c • E hk') + simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk] at hsub + rw [hsub] + have hcoe : ⇑(c • E hk') = c • (E hk' : ℍ → ℂ) := rfl + rw [hcoe, qExpansion_smul one_pos one_mem_strictPeriods_SL c (E hk')] + simp only [_root_.map_sub, _root_.map_smul, smul_eq_mul, hE_coeff_zero, mul_one, ← hc, + sub_self]) + have h0 : (cuspFormSubmodule.mkQ (f - (qExpansion 1 ↑f).coeff 0 • + E hk') : ModularForm 𝒮ℒ (k : ℤ) ⧸ cuspFormSubmodule) = 0 := + (Submodule.Quotient.mk_eq_zero _).mpr h_mem + rw [map_sub, LinearMap.map_smul, Submodule.mkQ_apply, Submodule.mkQ_apply, + sub_eq_zero] at h0 + exact h0.symm + +end RankIdentity + +/-! ### Dimension formula -/ + +section DimensionFormula + +/-! ### Helpers for weight 2 proof -/ + +/-- In a rank-1 module over ℂ, any element is a scalar multiple of any nonzero element. -/ +private lemma exists_smul_eq_of_rank_one {M : Type*} [AddCommGroup M] [Module ℂ M] + (hrank : Module.rank ℂ M = 1) {e : M} (he : e ≠ 0) (f : M) : ∃ c : ℂ, c • e = f := by + obtain ⟨v, _, hv⟩ := rank_eq_one_iff.mp hrank + obtain ⟨a, rfl⟩ := hv e; obtain ⟨b, rfl⟩ := hv f + exact ⟨b * a⁻¹, by rw [smul_smul, mul_assoc, inv_mul_cancel₀ (fun h ↦ he (by simp [h])), + mul_one]⟩ + +/-- Weight 4 modular forms for `𝒮ℒ` are 1-dimensional. -/ +private lemma weight_four_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ (4 : ℤ)) = 1 := + (rank_eq_one_add_rank_cuspForm (show (3 : ℤ) ≤ 4 by norm_num) ⟨2, rfl⟩).trans + ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (show (4 : ℤ) < 12 by norm_num))).trans + (by norm_cast)) + +/-- Weight 6 modular forms for `𝒮ℒ` are 1-dimensional. -/ +private lemma weight_six_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ (6 : ℤ)) = 1 := + (rank_eq_one_add_rank_cuspForm (show (3 : ℤ) ≤ 6 by norm_num) ⟨3, rfl⟩).trans + ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (show (6 : ℤ) < 12 by norm_num))).trans + (by norm_cast)) + +private lemma E_qExpansion_coeff_one_four : + (qExpansion 1 (E (show 3 ≤ 4 by norm_num))).coeff 1 = 240 := by + rw [E_qExpansion_coeff (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩] + simp only [show (1 : ℕ) ≠ 0 from one_ne_zero, ↓reduceIte] + rw [show bernoulli (4 : ℕ) = ((-1 : ℚ) / 30 : ℚ) from by + rw [bernoulli_eq_bernoulli'_of_ne_one (by norm_num)]; exact bernoulli'_four] + simp [ArithmeticFunction.sigma_one]; norm_num + +private lemma E_qExpansion_coeff_one_six : + (qExpansion 1 (E (show 3 ≤ 6 by norm_num))).coeff 1 = -504 := by + rw [E_qExpansion_coeff (show 3 ≤ 6 by norm_num) ⟨3, rfl⟩] + simp only [show (1 : ℕ) ≠ 0 from one_ne_zero, ↓reduceIte] + rw [show bernoulli (6 : ℕ) = ((1 : ℚ) / 42 : ℚ) from by + rw [bernoulli_eq_bernoulli'_of_ne_one (by norm_num), bernoulli'_def] + norm_num [Finset.sum_range_succ, Finset.sum_range_zero, + show Nat.choose 6 2 = 15 from by decide, show Nat.choose 6 4 = 15 from by decide, + bernoulli'_eq_zero_of_odd (show Odd 5 from ⟨2, rfl⟩) (by norm_num)]] + simp [ArithmeticFunction.sigma_one]; norm_num + +/-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ +theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : + 1728 * discriminant z = + E (show 3 ≤ 4 by norm_num) z ^ 3 - E (show 3 ≤ 6 by norm_num) z ^ 2 := by + set E4 := E (show 3 ≤ 4 by norm_num) + set E6 := E (show 3 ≤ 6 by norm_num) + set F : ModularForm 𝒮ℒ 12 := + ModularForm.mcast (show 4 + (4 + 4) = 12 by norm_num) + (E4.mul (ModularForm.mcast (show 4 + 4 = 4 + 4 from rfl) (E4.mul E4))) - + ModularForm.mcast (show 6 + 6 = 12 by norm_num) (E6.mul E6) + have hF : ∀ w, F w = E4 w ^ 3 - E6 w ^ 2 := fun w ↦ by + change E4 w * (E4 w * E4 w) - E6 w * E6 w = E4 w ^ 3 - E6 w ^ 2; ring + have h0_4 := E_qExpansion_coeff_zero (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩ + have h0_6 := E_qExpansion_coeff_zero (show 3 ≤ 6 by norm_num) ⟨3, rfl⟩ + -- q-expansion of F splits as products minus products + -- F is a cusp form (coeff 0 = valueAtInfty F = 1³-1² = 0) + have hF_cusp : IsCuspForm F := (isCuspForm_iff_coeffZero_eq_zero F).mpr (by + rw [qExpansion_coeff_zero F one_pos one_mem_strictPeriods_SL] + -- valueAtInfty F = valueAtInfty (E₄*E₄*E₄ - E₆*E₆) = 1*1*1 - 1*1 = 0 + have hv4 : valueAtInfty (E4 : ℍ → ℂ) = 1 := by + rwa [← qExpansion_coeff_zero E4 one_pos one_mem_strictPeriods_SL] + have hv6 : valueAtInfty (E6 : ℍ → ℂ) = 1 := by + rwa [← qExpansion_coeff_zero E6 one_pos one_mem_strictPeriods_SL] + change limUnder atImInfty (fun w ↦ E4 w * (E4 w * E4 w) - E6 w * E6 w) = 0 + have htend : ∀ (k' : ℤ) (f : ModularForm 𝒮ℒ k') (c' : ℂ) (_ : valueAtInfty f = c'), + Filter.Tendsto f atImInfty (𝓝 c') := fun _ f c' hv ↦ by + rw [← hv, ← cuspFunction_apply_zero f one_pos one_mem_strictPeriods_SL] + exact ((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL + ).continuousAt.tendsto.comp (qParam_tendsto_atImInfty one_pos)).congr + (fun τ ↦ eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero) + have h4 := htend _ E4 _ hv4 + have h6 := htend _ E6 _ hv6 + convert ((h4.mul (h4.mul h4)).sub (h6.mul h6)).limUnder_eq using 1 + norm_num) + obtain ⟨g, hg⟩ := hF_cusp + obtain ⟨c, hc⟩ := cuspForm_twelve_smul_discriminant g + -- c = 1728 by comparing q-expansion coeff 1 + have hc_eq : c = 1728 := by + -- coeff 1 of g = coeff 1 of F (since g = F as modular forms) + -- coeff 1 of g = c * coeff 1 of Δ = c * 1 = c (since c•Δ = g) + have hgF : qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (F : ℍ → ℂ) := by + congr 1; exact congr_arg DFunLike.coe hg + have hgΔ : qExpansion 1 (g : ℍ → ℂ) = + c • qExpansion 1 (discriminantCuspForm : ℍ → ℂ) := by + conv_lhs => rw [show (g : ℍ → ℂ) = ((c • discriminantCuspForm : CuspForm 𝒮ℒ 12) : ℍ → ℂ) + from congr_arg DFunLike.coe hc.symm] + exact qExpansion_smul one_pos one_mem_strictPeriods_SL c discriminantCuspForm + -- coeff 1 of F = c (from hgF, hgΔ, and discriminant_qExpansion_coeff_one) + have h := congr_arg (·.coeff 1) (hgF.symm.trans hgΔ) + simp only [PowerSeries.coeff_smul, smul_eq_mul, discriminant_qExpansion_coeff_one, + mul_one] at h + -- (qExpansion 1 F).coeff 1 = 3*240 - 2*(-504) = 1728 + -- Use ModularForm.qExpansion_mul which works on ModularForm, not raw functions + have hq44 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E4 E4 + have hq444 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E4 + (ModularForm.mcast rfl (E4.mul E4)) + have hq66 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E6 E6 + have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (12 : ℤ))).map_sub + (ModularForm.mcast (by norm_num) (E4.mul (ModularForm.mcast rfl (E4.mul E4)))) + (ModularForm.mcast (by norm_num) (E6.mul E6)) + simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk] at hsub + -- mcast doesn't change coercions, so qExpansion is unaffected + have hmcast : ∀ (a b : ℤ) (h : a = b) (f : ModularForm 𝒮ℒ a), + qExpansion 1 (ModularForm.mcast h f : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) := + fun _ _ _ _ ↦ rfl + simp only [hmcast] at hsub + rw [hsub, hq444] at h; simp only [hmcast] at h; rw [hq44, hq66] at h + -- h now has: coeff 1 of (p4 * (p4 * p4) - p6 * p6) = c + -- Build the numeric value via calc, avoiding simp-at-h which consumes h + have h1_4 : (PowerSeries.coeff 1) (qExpansion 1 E4) = 240 := E_qExpansion_coeff_one_four + have h1_6 : (PowerSeries.coeff 1) (qExpansion 1 E6) = -504 := E_qExpansion_coeff_one_six + have hc0_4 : PowerSeries.constantCoeff (qExpansion 1 (E4 : ℍ → ℂ)) = 1 := by + rw [← PowerSeries.coeff_zero_eq_constantCoeff]; exact h0_4 + have hc0_6 : PowerSeries.constantCoeff (qExpansion 1 (E6 : ℍ → ℂ)) = 1 := by + rw [← PowerSeries.coeff_zero_eq_constantCoeff]; exact h0_6 + -- Use native_decide or norm_num on the coefficient computation + simp only [map_sub, PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, + Finset.Nat.antidiagonal_zero, Finset.sum_cons, Finset.sum_singleton, + Finset.map_singleton, Function.Embedding.prodMap, Prod.map, + Function.Embedding.coeFn_mk, Nat.succ_eq_add_one, Nat.zero_add, + Function.Embedding.refl_apply, h1_4, h1_6] at h + exact h.symm.trans (by norm_num [show (PowerSeries.coeff 0) (qExpansion 1 (E4 : ℍ → ℂ)) = 1 + from h0_4, show (PowerSeries.coeff 0) (qExpansion 1 (E6 : ℍ → ℂ)) = 1 from h0_6]) + calc 1728 * discriminant z = c * discriminant z := by rw [hc_eq] + _ = (c • discriminantCuspForm) z := rfl + _ = g z := by rw [← hc] + _ = (CuspForm.toModularFormₗ g) z := rfl + _ = F z := by rw [hg] + _ = E4 z ^ 3 - E6 z ^ 2 := hF z + +private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : ℤ)) + (hf : ¬IsCuspForm f) : f = 0 := by + exfalso + have hc0 : (qExpansion 1 f).coeff 0 ≠ 0 := + fun h ↦ hf ((isCuspForm_iff_coeffZero_eq_zero f).mpr h) + obtain ⟨c4, hc4⟩ := exists_smul_eq_of_rank_one weight_four_rank_one + (E_ne_zero (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩) (f.mul f) + obtain ⟨c6, hc6⟩ := exists_smul_eq_of_rank_one weight_six_rank_one + (E_ne_zero (show 3 ≤ 6 by norm_num) ⟨3, rfl⟩) ((f.mul f).mul f) + set p := qExpansion 1 f + set p4 := qExpansion 1 (E (show 3 ≤ 4 by norm_num)) + set p6 := qExpansion 1 (E (show 3 ≤ 6 by norm_num)) + have hqc4 : c4 • p4 = p * p := by + have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c4 + (E (show 3 ≤ 4 by norm_num)) + rw [show (c4 • E (show 3 ≤ 4 by norm_num) : ℍ → ℂ) = + (f.mul f : ℍ → ℂ) from congrArg DFunLike.coe hc4] at hsmul + rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] + exact hsmul.symm + have hqc6 : c6 • p6 = p * p * p := by + have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c6 + (E (show 3 ≤ 6 by norm_num)) + have hmul1 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (f.mul f) f + rw [show (c6 • E (show 3 ≤ 6 by norm_num) : ℍ → ℂ) = + ((f.mul f).mul f : ℍ → ℂ) from congrArg DFunLike.coe hc6] at hsmul + rw [ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] at hmul1 + rw [← hmul1]; exact hsmul.symm + have hp4_0 : p4.coeff 0 = 1 := + E_qExpansion_coeff_zero (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩ + have hp6_0 : p6.coeff 0 = 1 := + E_qExpansion_coeff_zero (show 3 ≤ 6 by norm_num) ⟨3, rfl⟩ + have hc4_eq : c4 = p.coeff 0 ^ 2 := by + have h := congr_arg (·.coeff 0) hqc4 + simp only [PowerSeries.coeff_smul, smul_eq_mul, PowerSeries.coeff_mul, + Finset.Nat.antidiagonal_zero, Finset.sum_singleton, hp4_0, mul_one] at h + rw [sq]; exact h + have hc6_eq : c6 = p.coeff 0 ^ 3 := by + have h := congr_arg (·.coeff 0) hqc6 + simp only [PowerSeries.coeff_smul, smul_eq_mul, PowerSeries.coeff_mul, + Finset.Nat.antidiagonal_zero, Finset.sum_singleton, hp6_0, mul_one] at h + rw [show p.coeff 0 ^ 3 = p.coeff 0 * p.coeff 0 * p.coeff 0 by ring]; exact h + have hp4_1 : p4.coeff 1 = 240 := E_qExpansion_coeff_one_four + have hp6_1 : p6.coeff 1 = -504 := E_qExpansion_coeff_one_six + have heq4 : c4 * 240 = 2 * p.coeff 0 * p.coeff 1 := by + have h := congr_arg (·.coeff 1) hqc4 + simp only [PowerSeries.coeff_smul, smul_eq_mul, hp4_1] at h + rw [show (p * p).coeff 1 = 2 * p.coeff 0 * p.coeff 1 from by + simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring] at h + exact h + have heq6 : c6 * (-504) = 3 * p.coeff 0 ^ 2 * p.coeff 1 := by + have h := congr_arg (·.coeff 1) hqc6 + simp only [PowerSeries.coeff_smul, smul_eq_mul, hp6_1] at h + rw [show (p * p * p).coeff 1 = 3 * p.coeff 0 ^ 2 * p.coeff 1 from by + simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring] at h + exact h + rw [hc4_eq] at heq4; rw [hc6_eq] at heq6 + have h1728 : 1728 * p.coeff 0 ^ 3 = 0 := by + linear_combination 3 * p.coeff 0 * heq4 - 2 * heq6 + exact hc0 (by + by_contra h + exact absurd h1728 (mul_ne_zero (by norm_num : (1728 : ℂ) ≠ 0) (pow_ne_zero 3 h))) + +/-- Modular forms of weight 2 for `𝒮ℒ` are zero. -/ +theorem ModularForm.levelOne_weight_two_rank_zero : + Module.rank ℂ (ModularForm 𝒮ℒ (2 : ℤ)) = 0 := by + rw [rank_zero_iff_forall_zero] + intro f + by_cases hf : IsCuspForm f + · obtain ⟨g, hg⟩ := hf + rw [← hg] + simp [rank_zero_iff_forall_zero.mp + (cuspForm_rank_lt_twelve (show (2 : ℤ) < 12 by norm_num)) g] + · exact weight_two_eq_zero_of_not_cuspForm f hf + +private lemma floor_lem1 (k a : ℚ) (ha : 0 < a) (hak : a ≤ k) : + 1 + Nat.floor ((k - a) / a) = Nat.floor (k / a) := by + rw [div_sub_same (Ne.symm (ne_of_lt ha))] + have := Nat.floor_sub_one (k / a) + push_cast at * + rw [this] + refine Nat.add_sub_cancel' ?_ + exact Nat.le_floor ((le_div_iff₀ ha).mpr (by simpa using hak)) + +/-- The dimension formula for `𝒮ℒ` modular forms of even weight `k ≥ 3`. -/ +theorem ModularForm.dimension_level_one (k : ℕ) (hk : 3 ≤ (k : ℤ)) (hk2 : Even k) : + Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ)) = + if 12 ∣ ((k : ℤ) - 2) then Nat.floor ((k : ℚ) / 12) + else Nat.floor ((k : ℚ) / 12) + 1 := by + induction k using Nat.strong_induction_on with | h k ihn => + rw [rank_eq_one_add_rank_cuspForm (by omega) hk2, + LinearEquiv.rank_eq CuspForm.discriminantEquiv] + by_cases HK : (3 : ℤ) ≤ ((k : ℤ) - 12) + · have iH := ihn (k - 12) (by omega) (by omega) + ((Nat.even_sub (by omega)).mpr (by simp only [hk2, true_iff]; decide)) + have hk12 : (((k - 12) : ℕ) : ℤ) = k - 12 := by + norm_cast; exact Eq.symm (Int.subNatNat_of_le (by omega)) + rw [hk12] at iH + rw [iH, show ((k - 12 : ℕ) : ℚ) = (k : ℚ) - 12 from by norm_cast] + have hfl := floor_lem1 k 12 (by norm_num) + by_cases h12 : 12 ∣ ((k) : ℤ) - 2 + · simp only [show 12 ∣ (k : ℤ) - 12 - 2 from by omega, ↓reduceIte, h12] + norm_cast at *; apply hfl; omega + · simp only [show ¬ 12 ∣ (k : ℤ) - 12 - 2 from by omega, ↓reduceIte, h12, + Nat.cast_add, Nat.cast_one] + norm_cast at *; rw [← add_assoc, hfl]; omega + · simp only [not_le] at HK + have hkop : k ∈ Finset.filter Even (Finset.Icc 3 14) := by + simp only [Finset.mem_filter, Finset.mem_Icc, hk2, and_true]; omega + rw [show Finset.filter Even (Finset.Icc 3 14) = ({4, 6, 8, 10, 12, 14} : Finset ℕ) + from by decide] at hkop + fin_cases hkop <;> simp only [Nat.cast_ofNat, Int.reduceSub, Int.reduceNeg] at * + all_goals first + | exact (congrArg (1 + ·) (levelOne_neg_weight_rank_zero (by omega))).trans (by norm_cast) + | exact (congrArg (1 + ·) levelOne_weight_zero_rank_one).trans (by norm_cast) + | exact (congrArg (1 + ·) levelOne_weight_two_rank_zero).trans (by norm_cast) + +end DimensionFormula From 40cd50a3921bf7e79a9b68b789fa9e055531fb04 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 10:03:27 +0100 Subject: [PATCH 03/49] chore(NumberTheory/ModularForms): address PR review comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Targeted fixes from PR #37789 review: - `cuspFormSubmodule` and `equivCuspFormSubmodule`: make `Γ`/`k` explicit - `isCuspForm_iff`: shorter proof - `ofMulDiscriminant`: simplify cusp-form coeff zero argument - `divDiscriminant.holo'`: golf by inlining the differentiability subgoals - `rank_eq_one_add_rank_cuspForm`: take `hk : 3 ≤ k` over `ℕ` - `discriminant_eq_E4_cube_sub_E6_sq`: restate as `Δ = (E₄³ - E₆²)/1728`, drop inline proof comments, fold redundant `have`s - `exists_smul_eq_of_rank_one`: use `finrank_eq_one_iff_of_nonzero'` from mathlib - Move `one_mem_strictPeriods_SL` to `LevelOne.lean` so the haveI workaround in `EisensteinSeries.E_qExpansion_coeff` can be dropped Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ModularForms/CuspFormSubmodule.lean | 22 ++-- .../DimensionFormulas/LevelOne.lean | 123 +++++++----------- .../EisensteinSeries/QExpansion.lean | 4 +- .../NumberTheory/ModularForms/LevelOne.lean | 3 + 4 files changed, 62 insertions(+), 90 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean index b75d24bcfa9c34..42f695b0886447 100644 --- a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean +++ b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean @@ -63,28 +63,25 @@ namespace ModularForm /-- The submodule of `ModularForm Γ k` consisting of cusp forms, defined as the range of the inclusion `CuspForm.toModularFormₗ`. -/ -def cuspFormSubmodule [Γ.HasDetOne] : Submodule ℂ (ModularForm Γ k) := - LinearMap.range (CuspForm.toModularFormₗ) +def cuspFormSubmodule (Γ : Subgroup (GL (Fin 2) ℝ)) (k : ℤ) [Γ.HasDetOne] : + Submodule ℂ (ModularForm Γ k) := + LinearMap.range CuspForm.toModularFormₗ /-- A modular form is a cusp form if it lies in the cusp form submodule. -/ def IsCuspForm [Γ.HasDetOne] (f : ModularForm Γ k) : Prop := - f ∈ cuspFormSubmodule (Γ := Γ) (k := k) + f ∈ cuspFormSubmodule Γ k /-- The cusp form submodule is linearly equivalent to the type of cusp forms. -/ -def CuspForm.equivCuspFormSubmodule [Γ.HasDetOne] : - CuspForm Γ k ≃ₗ[ℂ] cuspFormSubmodule (Γ := Γ) (k := k) := +def CuspForm.equivCuspFormSubmodule (Γ : Subgroup (GL (Fin 2) ℝ)) (k : ℤ) [Γ.HasDetOne] : + CuspForm Γ k ≃ₗ[ℂ] cuspFormSubmodule Γ k := LinearEquiv.ofInjective CuspForm.toModularFormₗ CuspForm.toModularFormₗ_injective /-- A modular form is a cusp form if and only if it vanishes at every cusp. This is the general characterization valid for any subgroup. -/ lemma isCuspForm_iff [Γ.HasDetOne] (f : ModularForm Γ k) : IsCuspForm f ↔ ∀ {c : OnePoint ℝ}, IsCusp c Γ → c.IsZeroAt f k := by - constructor - · rintro ⟨g, hg⟩ c hc - have : (f : ℍ → ℂ) = (g : ℍ → ℂ) := congr_arg DFunLike.coe hg.symm - simpa [this] using g.zero_at_cusps' hc - · intro h - exact ⟨⟨f.toSlashInvariantForm, f.holo', h⟩, by ext; rfl⟩ + refine ⟨fun ⟨g, hg⟩ c hc ↦ hg ▸ g.zero_at_cusps' hc, fun h ↦ + ⟨⟨f.toSlashInvariantForm, f.holo', h⟩, rfl⟩⟩ section SL2Z @@ -92,9 +89,6 @@ open EisensteinSeries variable {k : ℤ} -lemma one_mem_strictPeriods_SL : (1 : ℝ) ∈ (𝒮ℒ : Subgroup (GL (Fin 2) ℝ)).strictPeriods := - CongruenceSubgroup.Gamma_one_coe_eq_SL ▸ one_mem_strictPeriods_SL2Z - /-- If an `𝒮ℒ` modular form has `valueAtInfty f = 0`, then it is zero at infinity. -/ lemma isZeroAtImInfty_of_valueAtInfty_eq_zero (f : ModularForm 𝒮ℒ k) (h : valueAtInfty f = 0) : IsZeroAtImInfty f := by diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index aff3fb037ce6be..7ddac2e6cffd59 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -41,14 +41,14 @@ weight `k`. Built directly as a CuspForm (no `IsCuspForm` intermediary). -/ def ofMulDiscriminant (f : ModularForm 𝒮ℒ (k - 12)) : CuspForm 𝒮ℒ k := let Δ' := CuspForm.toModularFormₗ discriminantCuspForm ModularForm.toCuspForm (ModularForm.mcast (by ring) (f.mul Δ')) (by - have : (qExpansion 1 (Δ' : ℍ → ℂ)).coeff 0 = 0 := by - rw [qExpansion_coeff_zero Δ' one_pos one_mem_strictPeriods_SL] - exact (CuspFormClass.zero_at_infty discriminantCuspForm).valueAtInfty_eq_zero + have hΔ' : (qExpansion 1 (Δ' : ℍ → ℂ)).coeff 0 = 0 := + (qExpansion_coeff_zero Δ' one_pos one_mem_strictPeriods_SL).trans + (CuspFormClass.zero_at_infty discriminantCuspForm).valueAtInfty_eq_zero rw [show (ModularForm.mcast _ (f.mul Δ') : ℍ → ℂ) = (f : ℍ → ℂ) * Δ' from rfl, qExpansion_mul_coeff_zero (analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt (analyticAt_cuspFunction_zero Δ' one_pos one_mem_strictPeriods_SL).continuousAt, - this, mul_zero]) + hΔ', mul_zero]) @[simp] lemma ofMulDiscriminant_apply (f : ModularForm 𝒮ℒ (k - 12)) (z : ℍ) : @@ -103,12 +103,9 @@ def divDiscriminant (f : CuspForm 𝒮ℒ k) : ModularForm 𝒮ℒ (k - 12) wher exact divByDiscriminant_slash_eq f γ holo' := by rw [UpperHalfPlane.mdifferentiable_iff] - apply DifferentiableOn.div - · exact UpperHalfPlane.mdifferentiable_iff.mp f.holo' - · exact UpperHalfPlane.mdifferentiable_iff.mp discriminantCuspForm.holo' - · intro z hz - simp only [ofComplex_apply_of_im_pos hz] - exact discriminant_ne_zero ⟨z, hz⟩ + refine (UpperHalfPlane.mdifferentiable_iff.mp f.holo').div + (UpperHalfPlane.mdifferentiable_iff.mp discriminantCuspForm.holo') fun z hz ↦ ?_ + simpa [ofComplex_apply_of_im_pos hz] using discriminant_ne_zero ⟨z, hz⟩ bdd_at_cusps' {c} hc := by rw [Subgroup.IsArithmetic.isCusp_iff_isCusp_SL2Z] at hc rw [isBoundedAt_iff_forall_SL2Z hc] @@ -169,18 +166,16 @@ lemma cuspForm_twelve_smul_discriminant (f : CuspForm 𝒮ℒ 12) : /-- For even `k ≥ 3`, the rank of `𝒮ℒ` modular forms is one more than the rank of cusp forms. -/ -lemma ModularForm.rank_eq_one_add_rank_cuspForm {k : ℕ} (hk : 3 ≤ (k : ℤ)) (hk2 : Even k) : +lemma ModularForm.rank_eq_one_add_rank_cuspForm {k : ℕ} (hk : 3 ≤ k) (hk2 : Even k) : Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ)) = 1 + Module.rank ℂ (CuspForm 𝒮ℒ (k : ℤ)) := by - have h_add := Submodule.rank_quotient_add_rank - (cuspFormSubmodule (Γ := 𝒮ℒ) (k := (k : ℤ))) - rw [show Module.rank ℂ ↥(cuspFormSubmodule (Γ := 𝒮ℒ) (k := (k : ℤ))) = + have h_add := Submodule.rank_quotient_add_rank (cuspFormSubmodule 𝒮ℒ (k : ℤ)) + rw [show Module.rank ℂ ↥(cuspFormSubmodule 𝒮ℒ (k : ℤ)) = Module.rank ℂ (CuspForm 𝒮ℒ (k : ℤ)) from - (LinearEquiv.rank_eq CuspForm.equivCuspFormSubmodule).symm] at h_add - suffices h1 : Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ) ⧸ cuspFormSubmodule) = 1 by + (LinearEquiv.rank_eq (CuspForm.equivCuspFormSubmodule 𝒮ℒ (k : ℤ))).symm] at h_add + suffices h1 : Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ) ⧸ cuspFormSubmodule 𝒮ℒ (k : ℤ)) = 1 by rw [← h_add, h1] - have hk' : 3 ≤ k := by exact_mod_cast hk - have hE_coeff_zero := E_qExpansion_coeff_zero hk' hk2 - apply rank_eq_one (Submodule.Quotient.mk (p := cuspFormSubmodule) (E hk')) + have hE_coeff_zero := E_qExpansion_coeff_zero hk hk2 + apply rank_eq_one (Submodule.Quotient.mk (p := cuspFormSubmodule 𝒮ℒ (k : ℤ)) (E hk)) · intro h rw [Submodule.Quotient.mk_eq_zero] at h exact one_ne_zero <| @@ -188,20 +183,20 @@ lemma ModularForm.rank_eq_one_add_rank_cuspForm {k : ℕ} (hk : 3 ≤ (k : ℤ)) (isCuspForm_iff_coeffZero_eq_zero _).mp h · refine (Submodule.Quotient.mk_surjective _).forall.mpr fun f ↦ ⟨(qExpansion 1 f).coeff 0, ?_⟩ - have h_mem : f - (qExpansion 1 ↑f).coeff 0 • E hk' ∈ - cuspFormSubmodule := + have h_mem : f - (qExpansion 1 ↑f).coeff 0 • E hk ∈ + cuspFormSubmodule 𝒮ℒ (k : ℤ) := (isCuspForm_iff_coeffZero_eq_zero _).mpr (by set c := (qExpansion 1 ↑f).coeff 0 with hc have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (k : ℤ))).map_sub - f (c • E hk') + f (c • E hk) simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk] at hsub rw [hsub] - have hcoe : ⇑(c • E hk') = c • (E hk' : ℍ → ℂ) := rfl - rw [hcoe, qExpansion_smul one_pos one_mem_strictPeriods_SL c (E hk')] + have hcoe : ⇑(c • E hk) = c • (E hk : ℍ → ℂ) := rfl + rw [hcoe, qExpansion_smul one_pos one_mem_strictPeriods_SL c (E hk)] simp only [_root_.map_sub, _root_.map_smul, smul_eq_mul, hE_coeff_zero, mul_one, ← hc, sub_self]) - have h0 : (cuspFormSubmodule.mkQ (f - (qExpansion 1 ↑f).coeff 0 • - E hk') : ModularForm 𝒮ℒ (k : ℤ) ⧸ cuspFormSubmodule) = 0 := + have h0 : ((cuspFormSubmodule 𝒮ℒ (k : ℤ)).mkQ (f - (qExpansion 1 ↑f).coeff 0 • + E hk) : ModularForm 𝒮ℒ (k : ℤ) ⧸ cuspFormSubmodule 𝒮ℒ (k : ℤ)) = 0 := (Submodule.Quotient.mk_eq_zero _).mpr h_mem rw [map_sub, LinearMap.map_smul, Submodule.mkQ_apply, Submodule.mkQ_apply, sub_eq_zero] at h0 @@ -215,25 +210,22 @@ section DimensionFormula /-! ### Helpers for weight 2 proof -/ -/-- In a rank-1 module over ℂ, any element is a scalar multiple of any nonzero element. -/ +/-- In a rank-one ℂ-module, every element is a scalar multiple of any nonzero element. +This is a thin wrapper around `finrank_eq_one_iff_of_nonzero'` adapted to `Module.rank`. -/ private lemma exists_smul_eq_of_rank_one {M : Type*} [AddCommGroup M] [Module ℂ M] - (hrank : Module.rank ℂ M = 1) {e : M} (he : e ≠ 0) (f : M) : ∃ c : ℂ, c • e = f := by - obtain ⟨v, _, hv⟩ := rank_eq_one_iff.mp hrank - obtain ⟨a, rfl⟩ := hv e; obtain ⟨b, rfl⟩ := hv f - exact ⟨b * a⁻¹, by rw [smul_smul, mul_assoc, inv_mul_cancel₀ (fun h ↦ he (by simp [h])), - mul_one]⟩ + (hrank : Module.rank ℂ M = 1) {e : M} (he : e ≠ 0) (f : M) : ∃ c : ℂ, c • e = f := + (finrank_eq_one_iff_of_nonzero' e he).mp + (Module.rank_eq_one_iff_finrank_eq_one.mp hrank) f /-- Weight 4 modular forms for `𝒮ℒ` are 1-dimensional. -/ private lemma weight_four_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ (4 : ℤ)) = 1 := - (rank_eq_one_add_rank_cuspForm (show (3 : ℤ) ≤ 4 by norm_num) ⟨2, rfl⟩).trans - ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (show (4 : ℤ) < 12 by norm_num))).trans - (by norm_cast)) + (rank_eq_one_add_rank_cuspForm (by norm_num) ⟨2, rfl⟩).trans + ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (by norm_num))).trans (by norm_cast)) /-- Weight 6 modular forms for `𝒮ℒ` are 1-dimensional. -/ private lemma weight_six_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ (6 : ℤ)) = 1 := - (rank_eq_one_add_rank_cuspForm (show (3 : ℤ) ≤ 6 by norm_num) ⟨3, rfl⟩).trans - ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (show (6 : ℤ) < 12 by norm_num))).trans - (by norm_cast)) + (rank_eq_one_add_rank_cuspForm (by norm_num) ⟨3, rfl⟩).trans + ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (by norm_num))).trans (by norm_cast)) private lemma E_qExpansion_coeff_one_four : (qExpansion 1 (E (show 3 ≤ 4 by norm_num))).coeff 1 = 240 := by @@ -256,8 +248,8 @@ private lemma E_qExpansion_coeff_one_six : /-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : - 1728 * discriminant z = - E (show 3 ≤ 4 by norm_num) z ^ 3 - E (show 3 ≤ 6 by norm_num) z ^ 2 := by + discriminant z = (1 / 1728) * + (E (show 3 ≤ 4 by norm_num) z ^ 3 - E (show 3 ≤ 6 by norm_num) z ^ 2) := by set E4 := E (show 3 ≤ 4 by norm_num) set E6 := E (show 3 ≤ 6 by norm_num) set F : ModularForm 𝒮ℒ 12 := @@ -268,11 +260,8 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : change E4 w * (E4 w * E4 w) - E6 w * E6 w = E4 w ^ 3 - E6 w ^ 2; ring have h0_4 := E_qExpansion_coeff_zero (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩ have h0_6 := E_qExpansion_coeff_zero (show 3 ≤ 6 by norm_num) ⟨3, rfl⟩ - -- q-expansion of F splits as products minus products - -- F is a cusp form (coeff 0 = valueAtInfty F = 1³-1² = 0) have hF_cusp : IsCuspForm F := (isCuspForm_iff_coeffZero_eq_zero F).mpr (by rw [qExpansion_coeff_zero F one_pos one_mem_strictPeriods_SL] - -- valueAtInfty F = valueAtInfty (E₄*E₄*E₄ - E₆*E₆) = 1*1*1 - 1*1 = 0 have hv4 : valueAtInfty (E4 : ℍ → ℂ) = 1 := by rwa [← qExpansion_coeff_zero E4 one_pos one_mem_strictPeriods_SL] have hv6 : valueAtInfty (E6 : ℍ → ℂ) = 1 := by @@ -290,10 +279,7 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : norm_num) obtain ⟨g, hg⟩ := hF_cusp obtain ⟨c, hc⟩ := cuspForm_twelve_smul_discriminant g - -- c = 1728 by comparing q-expansion coeff 1 have hc_eq : c = 1728 := by - -- coeff 1 of g = coeff 1 of F (since g = F as modular forms) - -- coeff 1 of g = c * coeff 1 of Δ = c * 1 = c (since c•Δ = g) have hgF : qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (F : ℍ → ℂ) := by congr 1; exact congr_arg DFunLike.coe hg have hgΔ : qExpansion 1 (g : ℍ → ℂ) = @@ -301,35 +287,23 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : conv_lhs => rw [show (g : ℍ → ℂ) = ((c • discriminantCuspForm : CuspForm 𝒮ℒ 12) : ℍ → ℂ) from congr_arg DFunLike.coe hc.symm] exact qExpansion_smul one_pos one_mem_strictPeriods_SL c discriminantCuspForm - -- coeff 1 of F = c (from hgF, hgΔ, and discriminant_qExpansion_coeff_one) have h := congr_arg (·.coeff 1) (hgF.symm.trans hgΔ) simp only [PowerSeries.coeff_smul, smul_eq_mul, discriminant_qExpansion_coeff_one, mul_one] at h - -- (qExpansion 1 F).coeff 1 = 3*240 - 2*(-504) = 1728 - -- Use ModularForm.qExpansion_mul which works on ModularForm, not raw functions - have hq44 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E4 E4 - have hq444 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E4 - (ModularForm.mcast rfl (E4.mul E4)) - have hq66 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E6 E6 - have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (12 : ℤ))).map_sub - (ModularForm.mcast (by norm_num) (E4.mul (ModularForm.mcast rfl (E4.mul E4)))) - (ModularForm.mcast (by norm_num) (E6.mul E6)) - simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk] at hsub - -- mcast doesn't change coercions, so qExpansion is unaffected have hmcast : ∀ (a b : ℤ) (h : a = b) (f : ModularForm 𝒮ℒ a), qExpansion 1 (ModularForm.mcast h f : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) := fun _ _ _ _ ↦ rfl - simp only [hmcast] at hsub - rw [hsub, hq444] at h; simp only [hmcast] at h; rw [hq44, hq66] at h - -- h now has: coeff 1 of (p4 * (p4 * p4) - p6 * p6) = c - -- Build the numeric value via calc, avoiding simp-at-h which consumes h + have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (12 : ℤ))).map_sub + (ModularForm.mcast (by norm_num) (E4.mul (ModularForm.mcast rfl (E4.mul E4)))) + (ModularForm.mcast (by norm_num) (E6.mul E6)) + simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk, hmcast] at hsub + rw [hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E4 + (ModularForm.mcast rfl (E4.mul E4))] at h + simp only [hmcast] at h + rw [ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E4 E4, + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E6 E6] at h have h1_4 : (PowerSeries.coeff 1) (qExpansion 1 E4) = 240 := E_qExpansion_coeff_one_four have h1_6 : (PowerSeries.coeff 1) (qExpansion 1 E6) = -504 := E_qExpansion_coeff_one_six - have hc0_4 : PowerSeries.constantCoeff (qExpansion 1 (E4 : ℍ → ℂ)) = 1 := by - rw [← PowerSeries.coeff_zero_eq_constantCoeff]; exact h0_4 - have hc0_6 : PowerSeries.constantCoeff (qExpansion 1 (E6 : ℍ → ℂ)) = 1 := by - rw [← PowerSeries.coeff_zero_eq_constantCoeff]; exact h0_6 - -- Use native_decide or norm_num on the coefficient computation simp only [map_sub, PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, Finset.Nat.antidiagonal_zero, Finset.sum_cons, Finset.sum_singleton, Finset.map_singleton, Function.Embedding.prodMap, Prod.map, @@ -337,12 +311,15 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : Function.Embedding.refl_apply, h1_4, h1_6] at h exact h.symm.trans (by norm_num [show (PowerSeries.coeff 0) (qExpansion 1 (E4 : ℍ → ℂ)) = 1 from h0_4, show (PowerSeries.coeff 0) (qExpansion 1 (E6 : ℍ → ℂ)) = 1 from h0_6]) - calc 1728 * discriminant z = c * discriminant z := by rw [hc_eq] - _ = (c • discriminantCuspForm) z := rfl - _ = g z := by rw [← hc] - _ = (CuspForm.toModularFormₗ g) z := rfl - _ = F z := by rw [hg] - _ = E4 z ^ 3 - E6 z ^ 2 := hF z + have h1728 : (1728 : ℂ) * discriminant z = E4 z ^ 3 - E6 z ^ 2 := by + calc (1728 : ℂ) * discriminant z + = c * discriminant z := by rw [hc_eq] + _ = (c • discriminantCuspForm) z := rfl + _ = g z := by rw [← hc] + _ = (CuspForm.toModularFormₗ g) z := rfl + _ = F z := by rw [hg] + _ = E4 z ^ 3 - E6 z ^ 2 := hF z + linear_combination (norm := ring_nf) (1 / 1728 : ℂ) * h1728 private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : ℤ)) (hf : ¬IsCuspForm f) : f = 0 := by diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean index 158f8c89164524..8de94c3361db09 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean @@ -327,10 +327,8 @@ lemma EisensteinSeries.E_qExpansion_coeff {k : ℕ} (hk : 3 ≤ k) (hk2 : Even k if m = 0 then 1 else -(2 * k / bernoulli k : ℂ) * (σ (k - 1) m) := by set β : ℂ := -(2 * k / bernoulli k : ℂ) set c : ℕ → ℂ := fun m ↦ if m = 0 then 1 else β * ↑(σ (k - 1) m) - haveI : ModularFormClass (ModularForm 𝒮ℒ k) (CongruenceSubgroup.Gamma 1) k := - CongruenceSubgroup.Gamma_one_coe_eq_SL ▸ inferInstance suffices ∀ τ : ℍ, HasSum (fun m ↦ c m • 𝕢 (1 : ℝ) τ ^ m) (E hk τ) from - (qExpansion_coeff_unique one_pos one_mem_strictPeriods_SL2Z this m).symm + (qExpansion_coeff_unique one_pos one_mem_strictPeriods_SL this m).symm intro τ have hS : Summable fun n : ℕ ↦ (σ (k - 1) (n + 1) : ℂ) * cexp (2 * π * I * τ) ^ (n + 1) := (summable_nat_add_iff 1).mpr (summable_sigma_mul_cexp_pow (by omega) τ) diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne.lean index 30c515d4933a0b..15fb58c051e639 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne.lean @@ -69,6 +69,9 @@ variable [ModularFormClass F Γ(1) k] lemma one_mem_strictPeriods_SL2Z : (1 : ℝ) ∈ Γ(1).strictPeriods := by simp +lemma one_mem_strictPeriods_SL : (1 : ℝ) ∈ (𝒮ℒ : Subgroup (GL (Fin 2) ℝ)).strictPeriods := + Gamma_one_coe_eq_SL ▸ one_mem_strictPeriods_SL2Z + private theorem cuspFunction_eqOn_const_of_nonpos_wt (hk : k ≤ 0) (f : F) : Set.EqOn (cuspFunction 1 f) (const ℂ (cuspFunction 1 f 0)) (Metric.ball 0 1) := by refine eq_const_of_exists_le (fun q hq ↦ ?_) (exp_nonneg (-π)) ?_ (fun q hq ↦ ?_) From fda7c119519fa3cb4172fb7054126d5ced7eab9f Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 10:24:16 +0100 Subject: [PATCH 04/49] chore(NumberTheory/ModularForms): inline more haves in dimension formula proofs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `discriminant_eq_E4_cube_sub_E6_sq`: hoist `hmcast` (used 3x) above its use, drop redundant calc step `_ = (CuspForm.toModularFormₗ g) z := rfl` - `weight_two_eq_zero_of_not_cuspForm`: drop `hc0`, fold the c4/c6 substitutions directly into `heq4`/`heq6` rather than via separate `hc4_eq`/`hc6_eq` + `rw`, replace the by_contra finale with `pow_eq_zero_iff`/`mul_eq_zero` Co-Authored-By: Claude Opus 4.6 (1M context) --- .../DimensionFormulas/LevelOne.lean | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 7ddac2e6cffd59..578278f6f050de 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -280,6 +280,9 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : obtain ⟨g, hg⟩ := hF_cusp obtain ⟨c, hc⟩ := cuspForm_twelve_smul_discriminant g have hc_eq : c = 1728 := by + have hmcast : ∀ {a b : ℤ} (h : a = b) (f : ModularForm 𝒮ℒ a), + qExpansion 1 (ModularForm.mcast h f : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) := + fun _ _ ↦ rfl have hgF : qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (F : ℍ → ℂ) := by congr 1; exact congr_arg DFunLike.coe hg have hgΔ : qExpansion 1 (g : ℍ → ℂ) = @@ -290,9 +293,6 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : have h := congr_arg (·.coeff 1) (hgF.symm.trans hgΔ) simp only [PowerSeries.coeff_smul, smul_eq_mul, discriminant_qExpansion_coeff_one, mul_one] at h - have hmcast : ∀ (a b : ℤ) (h : a = b) (f : ModularForm 𝒮ℒ a), - qExpansion 1 (ModularForm.mcast h f : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) := - fun _ _ _ _ ↦ rfl have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (12 : ℤ))).map_sub (ModularForm.mcast (by norm_num) (E4.mul (ModularForm.mcast rfl (E4.mul E4)))) (ModularForm.mcast (by norm_num) (E6.mul E6)) @@ -311,21 +311,18 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : Function.Embedding.refl_apply, h1_4, h1_6] at h exact h.symm.trans (by norm_num [show (PowerSeries.coeff 0) (qExpansion 1 (E4 : ℍ → ℂ)) = 1 from h0_4, show (PowerSeries.coeff 0) (qExpansion 1 (E6 : ℍ → ℂ)) = 1 from h0_6]) - have h1728 : (1728 : ℂ) * discriminant z = E4 z ^ 3 - E6 z ^ 2 := by + have h1728 : (1728 : ℂ) * discriminant z = E4 z ^ 3 - E6 z ^ 2 := calc (1728 : ℂ) * discriminant z = c * discriminant z := by rw [hc_eq] _ = (c • discriminantCuspForm) z := rfl _ = g z := by rw [← hc] - _ = (CuspForm.toModularFormₗ g) z := rfl - _ = F z := by rw [hg] + _ = F z := congr_fun (congr_arg DFunLike.coe hg) z _ = E4 z ^ 3 - E6 z ^ 2 := hF z linear_combination (norm := ring_nf) (1 / 1728 : ℂ) * h1728 private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : ℤ)) (hf : ¬IsCuspForm f) : f = 0 := by exfalso - have hc0 : (qExpansion 1 f).coeff 0 ≠ 0 := - fun h ↦ hf ((isCuspForm_iff_coeffZero_eq_zero f).mpr h) obtain ⟨c4, hc4⟩ := exists_smul_eq_of_rank_one weight_four_rank_one (E_ne_zero (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩) (f.mul f) obtain ⟨c6, hc6⟩ := exists_smul_eq_of_rank_one weight_six_rank_one @@ -338,8 +335,7 @@ private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : (E (show 3 ≤ 4 by norm_num)) rw [show (c4 • E (show 3 ≤ 4 by norm_num) : ℍ → ℂ) = (f.mul f : ℍ → ℂ) from congrArg DFunLike.coe hc4] at hsmul - rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] - exact hsmul.symm + rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f]; exact hsmul.symm have hqc6 : c6 • p6 = p * p * p := by have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c6 (E (show 3 ≤ 6 by norm_num)) @@ -352,36 +348,35 @@ private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : E_qExpansion_coeff_zero (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩ have hp6_0 : p6.coeff 0 = 1 := E_qExpansion_coeff_zero (show 3 ≤ 6 by norm_num) ⟨3, rfl⟩ - have hc4_eq : c4 = p.coeff 0 ^ 2 := by + have h0_4 : c4 = p.coeff 0 ^ 2 := by have h := congr_arg (·.coeff 0) hqc4 simp only [PowerSeries.coeff_smul, smul_eq_mul, PowerSeries.coeff_mul, Finset.Nat.antidiagonal_zero, Finset.sum_singleton, hp4_0, mul_one] at h rw [sq]; exact h - have hc6_eq : c6 = p.coeff 0 ^ 3 := by + have h0_6 : c6 = p.coeff 0 ^ 3 := by have h := congr_arg (·.coeff 0) hqc6 simp only [PowerSeries.coeff_smul, smul_eq_mul, PowerSeries.coeff_mul, Finset.Nat.antidiagonal_zero, Finset.sum_singleton, hp6_0, mul_one] at h rw [show p.coeff 0 ^ 3 = p.coeff 0 * p.coeff 0 * p.coeff 0 by ring]; exact h have hp4_1 : p4.coeff 1 = 240 := E_qExpansion_coeff_one_four have hp6_1 : p6.coeff 1 = -504 := E_qExpansion_coeff_one_six - have heq4 : c4 * 240 = 2 * p.coeff 0 * p.coeff 1 := by + have heq4 : p.coeff 0 ^ 2 * 240 = 2 * p.coeff 0 * p.coeff 1 := by have h := congr_arg (·.coeff 1) hqc4 simp only [PowerSeries.coeff_smul, smul_eq_mul, hp4_1] at h rw [show (p * p).coeff 1 = 2 * p.coeff 0 * p.coeff 1 from by - simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring] at h + simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring, h0_4] at h exact h - have heq6 : c6 * (-504) = 3 * p.coeff 0 ^ 2 * p.coeff 1 := by + have heq6 : p.coeff 0 ^ 3 * (-504) = 3 * p.coeff 0 ^ 2 * p.coeff 1 := by have h := congr_arg (·.coeff 1) hqc6 simp only [PowerSeries.coeff_smul, smul_eq_mul, hp6_1] at h rw [show (p * p * p).coeff 1 = 3 * p.coeff 0 ^ 2 * p.coeff 1 from by - simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring] at h + simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring, h0_6] at h exact h - rw [hc4_eq] at heq4; rw [hc6_eq] at heq6 - have h1728 : 1728 * p.coeff 0 ^ 3 = 0 := by + refine hf ((isCuspForm_iff_coeffZero_eq_zero f).mpr <| + pow_eq_zero_iff (n := 3) three_ne_zero |>.mp ?_) + have h0 : (1728 : ℂ) * p.coeff 0 ^ 3 = 0 := by linear_combination 3 * p.coeff 0 * heq4 - 2 * heq6 - exact hc0 (by - by_contra h - exact absurd h1728 (mul_ne_zero (by norm_num : (1728 : ℂ) ≠ 0) (pow_ne_zero 3 h))) + exact (mul_eq_zero.mp h0).resolve_left (by norm_num) /-- Modular forms of weight 2 for `𝒮ℒ` are zero. -/ theorem ModularForm.levelOne_weight_two_rank_zero : From 563616ad36a66fab91253078f0c0eeb41b7b78b7 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 10:31:48 +0100 Subject: [PATCH 05/49] =?UTF-8?q?feat(NumberTheory/ModularForms):=20add=20?= =?UTF-8?q?E=E2=82=84=20and=20E=E2=82=86=20abbreviations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add public `noncomputable abbrev`s `ModularForm.E₄ : ModularForm 𝒮ℒ 4` and `ModularForm.E₆ : ModularForm 𝒮ℒ 6` for the normalised level 1 Eisenstein series of weights 4 and 6. Use them throughout `DimensionFormulas/LevelOne.lean` to drop the awkward `E (show 3 ≤ 4 by norm_num)` and `set E4 := …` patterns. The `abbrev` (rather than `def` or notation) is required so all uses share a single underlying proof of `3 ≤ 4` / `3 ≤ 6`, which lets simp lemmas about their q-expansions match consistently. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../DimensionFormulas/LevelOne.lean | 114 ++++++++---------- .../ModularForms/EisensteinSeries/Basic.lean | 6 + 2 files changed, 58 insertions(+), 62 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 578278f6f050de..51ba125cbfbe19 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -227,18 +227,18 @@ private lemma weight_six_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ (6 : (rank_eq_one_add_rank_cuspForm (by norm_num) ⟨3, rfl⟩).trans ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (by norm_num))).trans (by norm_cast)) -private lemma E_qExpansion_coeff_one_four : - (qExpansion 1 (E (show 3 ≤ 4 by norm_num))).coeff 1 = 240 := by - rw [E_qExpansion_coeff (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩] - simp only [show (1 : ℕ) ≠ 0 from one_ne_zero, ↓reduceIte] +private lemma E₄_qExpansion_coeff_one : (qExpansion 1 E₄).coeff 1 = 240 := by + rw [show (E₄ : ModularForm 𝒮ℒ 4) = E (by norm_num : (3 : ℕ) ≤ 4) from rfl, + E_qExpansion_coeff _ ⟨2, rfl⟩] + simp only [one_ne_zero, ↓reduceIte] rw [show bernoulli (4 : ℕ) = ((-1 : ℚ) / 30 : ℚ) from by rw [bernoulli_eq_bernoulli'_of_ne_one (by norm_num)]; exact bernoulli'_four] simp [ArithmeticFunction.sigma_one]; norm_num -private lemma E_qExpansion_coeff_one_six : - (qExpansion 1 (E (show 3 ≤ 6 by norm_num))).coeff 1 = -504 := by - rw [E_qExpansion_coeff (show 3 ≤ 6 by norm_num) ⟨3, rfl⟩] - simp only [show (1 : ℕ) ≠ 0 from one_ne_zero, ↓reduceIte] +private lemma E₆_qExpansion_coeff_one : (qExpansion 1 E₆).coeff 1 = -504 := by + rw [show (E₆ : ModularForm 𝒮ℒ 6) = E (by norm_num : (3 : ℕ) ≤ 6) from rfl, + E_qExpansion_coeff _ ⟨3, rfl⟩] + simp only [one_ne_zero, ↓reduceIte] rw [show bernoulli (6 : ℕ) = ((1 : ℚ) / 42 : ℚ) from by rw [bernoulli_eq_bernoulli'_of_ne_one (by norm_num), bernoulli'_def] norm_num [Finset.sum_range_succ, Finset.sum_range_zero, @@ -248,33 +248,32 @@ private lemma E_qExpansion_coeff_one_six : /-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : - discriminant z = (1 / 1728) * - (E (show 3 ≤ 4 by norm_num) z ^ 3 - E (show 3 ≤ 6 by norm_num) z ^ 2) := by - set E4 := E (show 3 ≤ 4 by norm_num) - set E6 := E (show 3 ≤ 6 by norm_num) + discriminant z = (1 / 1728) * (E₄ z ^ 3 - E₆ z ^ 2) := by set F : ModularForm 𝒮ℒ 12 := ModularForm.mcast (show 4 + (4 + 4) = 12 by norm_num) - (E4.mul (ModularForm.mcast (show 4 + 4 = 4 + 4 from rfl) (E4.mul E4))) - - ModularForm.mcast (show 6 + 6 = 12 by norm_num) (E6.mul E6) - have hF : ∀ w, F w = E4 w ^ 3 - E6 w ^ 2 := fun w ↦ by - change E4 w * (E4 w * E4 w) - E6 w * E6 w = E4 w ^ 3 - E6 w ^ 2; ring - have h0_4 := E_qExpansion_coeff_zero (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩ - have h0_6 := E_qExpansion_coeff_zero (show 3 ≤ 6 by norm_num) ⟨3, rfl⟩ + (E₄.mul (ModularForm.mcast (show 4 + 4 = 4 + 4 from rfl) (E₄.mul E₄))) - + ModularForm.mcast (show 6 + 6 = 12 by norm_num) (E₆.mul E₆) + have hF : ∀ w, F w = E₄ w ^ 3 - E₆ w ^ 2 := fun w ↦ by + change E₄ w * (E₄ w * E₄ w) - E₆ w * E₆ w = E₄ w ^ 3 - E₆ w ^ 2; ring + have h0_4 : (qExpansion 1 (E₄ : ℍ → ℂ)).coeff 0 = 1 := + E_qExpansion_coeff_zero _ ⟨2, rfl⟩ + have h0_6 : (qExpansion 1 (E₆ : ℍ → ℂ)).coeff 0 = 1 := + E_qExpansion_coeff_zero _ ⟨3, rfl⟩ have hF_cusp : IsCuspForm F := (isCuspForm_iff_coeffZero_eq_zero F).mpr (by rw [qExpansion_coeff_zero F one_pos one_mem_strictPeriods_SL] - have hv4 : valueAtInfty (E4 : ℍ → ℂ) = 1 := by - rwa [← qExpansion_coeff_zero E4 one_pos one_mem_strictPeriods_SL] - have hv6 : valueAtInfty (E6 : ℍ → ℂ) = 1 := by - rwa [← qExpansion_coeff_zero E6 one_pos one_mem_strictPeriods_SL] - change limUnder atImInfty (fun w ↦ E4 w * (E4 w * E4 w) - E6 w * E6 w) = 0 - have htend : ∀ (k' : ℤ) (f : ModularForm 𝒮ℒ k') (c' : ℂ) (_ : valueAtInfty f = c'), - Filter.Tendsto f atImInfty (𝓝 c') := fun _ f c' hv ↦ by + have hv4 : valueAtInfty (E₄ : ℍ → ℂ) = 1 := by + rwa [← qExpansion_coeff_zero E₄ one_pos one_mem_strictPeriods_SL] + have hv6 : valueAtInfty (E₆ : ℍ → ℂ) = 1 := by + rwa [← qExpansion_coeff_zero E₆ one_pos one_mem_strictPeriods_SL] + change limUnder atImInfty (fun w ↦ E₄ w * (E₄ w * E₄ w) - E₆ w * E₆ w) = 0 + have htend : ∀ {k' : ℤ} (f : ModularForm 𝒮ℒ k') {c' : ℂ}, valueAtInfty (f : ℍ → ℂ) = c' → + Filter.Tendsto f atImInfty (𝓝 c') := fun {_} f {_} hv ↦ by rw [← hv, ← cuspFunction_apply_zero f one_pos one_mem_strictPeriods_SL] exact ((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL ).continuousAt.tendsto.comp (qParam_tendsto_atImInfty one_pos)).congr (fun τ ↦ eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero) - have h4 := htend _ E4 _ hv4 - have h6 := htend _ E6 _ hv6 + have h4 := htend E₄ hv4 + have h6 := htend E₆ hv6 convert ((h4.mul (h4.mul h4)).sub (h6.mul h6)).limUnder_eq using 1 norm_num) obtain ⟨g, hg⟩ := hF_cusp @@ -294,60 +293,53 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : simp only [PowerSeries.coeff_smul, smul_eq_mul, discriminant_qExpansion_coeff_one, mul_one] at h have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (12 : ℤ))).map_sub - (ModularForm.mcast (by norm_num) (E4.mul (ModularForm.mcast rfl (E4.mul E4)))) - (ModularForm.mcast (by norm_num) (E6.mul E6)) + (ModularForm.mcast (by norm_num) (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄)))) + (ModularForm.mcast (by norm_num) (E₆.mul E₆)) simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk, hmcast] at hsub - rw [hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E4 - (ModularForm.mcast rfl (E4.mul E4))] at h + rw [hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ + (ModularForm.mcast rfl (E₄.mul E₄))] at h simp only [hmcast] at h - rw [ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E4 E4, - ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E6 E6] at h - have h1_4 : (PowerSeries.coeff 1) (qExpansion 1 E4) = 240 := E_qExpansion_coeff_one_four - have h1_6 : (PowerSeries.coeff 1) (qExpansion 1 E6) = -504 := E_qExpansion_coeff_one_six + rw [ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] at h simp only [map_sub, PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, Finset.Nat.antidiagonal_zero, Finset.sum_cons, Finset.sum_singleton, Finset.map_singleton, Function.Embedding.prodMap, Prod.map, Function.Embedding.coeFn_mk, Nat.succ_eq_add_one, Nat.zero_add, - Function.Embedding.refl_apply, h1_4, h1_6] at h - exact h.symm.trans (by norm_num [show (PowerSeries.coeff 0) (qExpansion 1 (E4 : ℍ → ℂ)) = 1 - from h0_4, show (PowerSeries.coeff 0) (qExpansion 1 (E6 : ℍ → ℂ)) = 1 from h0_6]) - have h1728 : (1728 : ℂ) * discriminant z = E4 z ^ 3 - E6 z ^ 2 := + Function.Embedding.refl_apply, E₄_qExpansion_coeff_one, + E₆_qExpansion_coeff_one] at h + exact h.symm.trans (by norm_num [h0_4, h0_6]) + have h1728 : (1728 : ℂ) * discriminant z = E₄ z ^ 3 - E₆ z ^ 2 := calc (1728 : ℂ) * discriminant z = c * discriminant z := by rw [hc_eq] _ = (c • discriminantCuspForm) z := rfl _ = g z := by rw [← hc] _ = F z := congr_fun (congr_arg DFunLike.coe hg) z - _ = E4 z ^ 3 - E6 z ^ 2 := hF z + _ = E₄ z ^ 3 - E₆ z ^ 2 := hF z linear_combination (norm := ring_nf) (1 / 1728 : ℂ) * h1728 private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : ℤ)) (hf : ¬IsCuspForm f) : f = 0 := by exfalso obtain ⟨c4, hc4⟩ := exists_smul_eq_of_rank_one weight_four_rank_one - (E_ne_zero (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩) (f.mul f) + (E_ne_zero _ ⟨2, rfl⟩ : (E₄ : ModularForm 𝒮ℒ 4) ≠ 0) (f.mul f) obtain ⟨c6, hc6⟩ := exists_smul_eq_of_rank_one weight_six_rank_one - (E_ne_zero (show 3 ≤ 6 by norm_num) ⟨3, rfl⟩) ((f.mul f).mul f) + (E_ne_zero _ ⟨3, rfl⟩ : (E₆ : ModularForm 𝒮ℒ 6) ≠ 0) ((f.mul f).mul f) set p := qExpansion 1 f - set p4 := qExpansion 1 (E (show 3 ≤ 4 by norm_num)) - set p6 := qExpansion 1 (E (show 3 ≤ 6 by norm_num)) - have hqc4 : c4 • p4 = p * p := by - have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c4 - (E (show 3 ≤ 4 by norm_num)) - rw [show (c4 • E (show 3 ≤ 4 by norm_num) : ℍ → ℂ) = - (f.mul f : ℍ → ℂ) from congrArg DFunLike.coe hc4] at hsmul + have hqc4 : c4 • qExpansion 1 (E₄ : ℍ → ℂ) = p * p := by + have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄ + rw [show (c4 • E₄ : ℍ → ℂ) = (f.mul f : ℍ → ℂ) from congrArg DFunLike.coe hc4] at hsmul rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f]; exact hsmul.symm - have hqc6 : c6 • p6 = p * p * p := by - have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c6 - (E (show 3 ≤ 6 by norm_num)) + have hqc6 : c6 • qExpansion 1 (E₆ : ℍ → ℂ) = p * p * p := by + have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆ have hmul1 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (f.mul f) f - rw [show (c6 • E (show 3 ≤ 6 by norm_num) : ℍ → ℂ) = - ((f.mul f).mul f : ℍ → ℂ) from congrArg DFunLike.coe hc6] at hsmul + rw [show (c6 • E₆ : ℍ → ℂ) = ((f.mul f).mul f : ℍ → ℂ) from + congrArg DFunLike.coe hc6] at hsmul rw [ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] at hmul1 rw [← hmul1]; exact hsmul.symm - have hp4_0 : p4.coeff 0 = 1 := - E_qExpansion_coeff_zero (show 3 ≤ 4 by norm_num) ⟨2, rfl⟩ - have hp6_0 : p6.coeff 0 = 1 := - E_qExpansion_coeff_zero (show 3 ≤ 6 by norm_num) ⟨3, rfl⟩ + have hp4_0 : (qExpansion 1 (E₄ : ℍ → ℂ)).coeff 0 = 1 := + E_qExpansion_coeff_zero _ ⟨2, rfl⟩ + have hp6_0 : (qExpansion 1 (E₆ : ℍ → ℂ)).coeff 0 = 1 := + E_qExpansion_coeff_zero _ ⟨3, rfl⟩ have h0_4 : c4 = p.coeff 0 ^ 2 := by have h := congr_arg (·.coeff 0) hqc4 simp only [PowerSeries.coeff_smul, smul_eq_mul, PowerSeries.coeff_mul, @@ -358,17 +350,15 @@ private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : simp only [PowerSeries.coeff_smul, smul_eq_mul, PowerSeries.coeff_mul, Finset.Nat.antidiagonal_zero, Finset.sum_singleton, hp6_0, mul_one] at h rw [show p.coeff 0 ^ 3 = p.coeff 0 * p.coeff 0 * p.coeff 0 by ring]; exact h - have hp4_1 : p4.coeff 1 = 240 := E_qExpansion_coeff_one_four - have hp6_1 : p6.coeff 1 = -504 := E_qExpansion_coeff_one_six have heq4 : p.coeff 0 ^ 2 * 240 = 2 * p.coeff 0 * p.coeff 1 := by have h := congr_arg (·.coeff 1) hqc4 - simp only [PowerSeries.coeff_smul, smul_eq_mul, hp4_1] at h + simp only [PowerSeries.coeff_smul, smul_eq_mul, E₄_qExpansion_coeff_one] at h rw [show (p * p).coeff 1 = 2 * p.coeff 0 * p.coeff 1 from by simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring, h0_4] at h exact h have heq6 : p.coeff 0 ^ 3 * (-504) = 3 * p.coeff 0 ^ 2 * p.coeff 1 := by have h := congr_arg (·.coeff 1) hqc6 - simp only [PowerSeries.coeff_smul, smul_eq_mul, hp6_1] at h + simp only [PowerSeries.coeff_smul, smul_eq_mul, E₆_qExpansion_coeff_one] at h rw [show (p * p * p).coeff 1 = 3 * p.coeff 0 ^ 2 * p.coeff 1 from by simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring, h0_6] at h exact h diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Basic.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Basic.lean index e6e4c33ee3bf95..62b0a89b7fadf2 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Basic.lean @@ -48,4 +48,10 @@ noncomputable def E {k : ℕ} (hk : 3 ≤ k) : ModularForm 𝒮ℒ k := ((1 / 2 : ℂ) • eisensteinSeriesMF (mod_cast hk) 0).ofSubgroupEq CongruenceSubgroup.Gamma_one_coe_eq_SL +/-- The normalised level 1 Eisenstein series of weight 4. -/ +noncomputable abbrev E₄ : ModularForm 𝒮ℒ 4 := E (by norm_num : (3 : ℕ) ≤ 4) + +/-- The normalised level 1 Eisenstein series of weight 6. -/ +noncomputable abbrev E₆ : ModularForm 𝒮ℒ 6 := E (by norm_num : (3 : ℕ) ≤ 6) + end ModularForm From ba215366fc3bb3271ef290a0e5cd7e54cd7e9829 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 10:38:59 +0100 Subject: [PATCH 06/49] golf --- Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean index 42f695b0886447..a9b6378449a2f0 100644 --- a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean +++ b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean @@ -46,8 +46,8 @@ def toModularFormₗ [Γ.HasDetOne] : CuspForm Γ k →ₗ[ℂ] ModularForm Γ k { toSlashInvariantForm := f.toSlashInvariantForm holo' := f.holo' bdd_at_cusps' := fun hc g hg ↦ (f.zero_at_cusps' hc g hg).boundedAtFilter } - map_add' _ _ := by ext; rfl - map_smul' _ _ := by ext; rfl + map_add' _ _ := rfl + map_smul' _ _ := rfl @[simp] lemma toModularFormₗ_apply [Γ.HasDetOne] (f : CuspForm Γ k) (z : ℍ) : From 58ce4e1e1504910e36bd45bdf75b0abe9735779e Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 12:56:10 +0100 Subject: [PATCH 07/49] feat(Algebra/Order/Floor/Semifield): add `Nat.floor_div_eq_one_add_floor_sub_div` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the lemma `⌊k / a⌋₊ = 1 + ⌊(k - a) / a⌋₊` for `0 < a ≤ k` over a linear ordered field, generalising the local `floor_lem1` helper that was buried in `DimensionFormulas/LevelOne.lean`. Inline the helper at its single use site in `dimension_level_one`. Co-Authored-By: Claude Opus 4.6 (1M context) --- Mathlib/Algebra/Order/Floor/Semifield.lean | 5 +++++ .../DimensionFormulas/LevelOne.lean | 19 +++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Mathlib/Algebra/Order/Floor/Semifield.lean b/Mathlib/Algebra/Order/Floor/Semifield.lean index 4690b6da5f5b2d..5a78c62a053682 100644 --- a/Mathlib/Algebra/Order/Floor/Semifield.lean +++ b/Mathlib/Algebra/Order/Floor/Semifield.lean @@ -53,6 +53,11 @@ end LinearOrderedSemifield section LinearOrderedField variable [Field K] [LinearOrder K] [IsStrictOrderedRing K] [FloorSemiring K] {a b : K} +theorem floor_div_eq_one_add_floor_sub_div (k a : K) (ha : 0 < a) (hak : a ≤ k) : + ⌊k / a⌋₊ = 1 + ⌊(k - a) / a⌋₊ := by + rw [sub_div, div_self ha.ne', Nat.floor_sub_one] + exact (Nat.add_sub_cancel' (Nat.le_floor (mod_cast (one_le_div₀ ha).mpr hak))).symm + lemma mul_lt_floor (hb₀ : 0 < b) (hb : b < 1) (hba : ⌈b / (1 - b)⌉₊ ≤ a) : b * a < ⌊a⌋₊ := by calc b * a < b * (⌊a⌋₊ + 1) := by gcongr; apply lt_floor_add_one diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 51ba125cbfbe19..f137c1580b49f3 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -3,6 +3,7 @@ Copyright (c) 2026 Chris Birkbeck. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Birkbeck -/ +import Mathlib.Algebra.Order.Floor.Semifield import Mathlib.NumberTheory.ModularForms.CuspFormSubmodule import Mathlib.NumberTheory.ModularForms.Discriminant import Mathlib.Data.Rat.Star @@ -380,15 +381,6 @@ theorem ModularForm.levelOne_weight_two_rank_zero : (cuspForm_rank_lt_twelve (show (2 : ℤ) < 12 by norm_num)) g] · exact weight_two_eq_zero_of_not_cuspForm f hf -private lemma floor_lem1 (k a : ℚ) (ha : 0 < a) (hak : a ≤ k) : - 1 + Nat.floor ((k - a) / a) = Nat.floor (k / a) := by - rw [div_sub_same (Ne.symm (ne_of_lt ha))] - have := Nat.floor_sub_one (k / a) - push_cast at * - rw [this] - refine Nat.add_sub_cancel' ?_ - exact Nat.le_floor ((le_div_iff₀ ha).mpr (by simpa using hak)) - /-- The dimension formula for `𝒮ℒ` modular forms of even weight `k ≥ 3`. -/ theorem ModularForm.dimension_level_one (k : ℕ) (hk : 3 ≤ (k : ℤ)) (hk2 : Even k) : Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ)) = @@ -404,13 +396,16 @@ theorem ModularForm.dimension_level_one (k : ℕ) (hk : 3 ≤ (k : ℤ)) (hk2 : norm_cast; exact Eq.symm (Int.subNatNat_of_le (by omega)) rw [hk12] at iH rw [iH, show ((k - 12 : ℕ) : ℚ) = (k : ℚ) - 12 from by norm_cast] - have hfl := floor_lem1 k 12 (by norm_num) + have hfl (hk' : (12 : ℚ) ≤ k) : + ⌊(k : ℚ) / 12⌋₊ = 1 + ⌊((k : ℚ) - 12) / 12⌋₊ := + Nat.floor_div_eq_one_add_floor_sub_div (k : ℚ) 12 (by norm_num) hk' by_cases h12 : 12 ∣ ((k) : ℤ) - 2 · simp only [show 12 ∣ (k : ℤ) - 12 - 2 from by omega, ↓reduceIte, h12] - norm_cast at *; apply hfl; omega + norm_cast at *; rw [hfl (by exact_mod_cast (by omega : (12 : ℤ) ≤ k))] · simp only [show ¬ 12 ∣ (k : ℤ) - 12 - 2 from by omega, ↓reduceIte, h12, Nat.cast_add, Nat.cast_one] - norm_cast at *; rw [← add_assoc, hfl]; omega + norm_cast at * + rw [← add_assoc, ← hfl (by exact_mod_cast (by omega : (12 : ℤ) ≤ k))] · simp only [not_le] at HK have hkop : k ∈ Finset.filter Even (Finset.Icc 3 14) := by simp only [Finset.mem_filter, Finset.mem_Icc, hk2, and_true]; omega From c9064312d2e432a6421e3ae841b4fed249148d36 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 13:22:51 +0100 Subject: [PATCH 08/49] refactor(NumberTheory/ModularForms): pull q-coordinate eta-product helpers up to DedekindEta MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds three q-coordinate lemmas to `DedekindEta.lean`: - `multipliable_one_sub_pow {q : ℂ} (hq : ‖q‖ < 1)`: pointwise multipliability - `multipliableLocallyUniformlyOn_one_sub_pow`: local uniform convergence on the open unit disc - `differentiableOn_tprod_one_sub_pow_pow (k : ℕ)`: differentiability of the k-th power of the product on the open unit disc These cover the case `q = 0` (the cusp at infinity), which the existing eta-side lemmas (`multipliableLocallyUniformlyOn_eta` etc., stated on `ℍₒ`) cannot. In `Discriminant.lean`, deletes the three private helpers `multipliable_one_sub_pow`, `tendstoLocallyUniformlyOn_eta_prod`, `differentiableWithinAt_eta_prod_pow`, and rewrites `discriminant_cuspFunction_eqOn` and `discriminant_qExpansion_coeff_one` to work on the full open unit disc `Metric.ball 0 1` (instead of the arbitrary `Metric.ball 0 (1/2)`) and to call the new helpers from `DedekindEta.lean`. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ModularForms/DedekindEta.lean | 54 +++++++++++++++ .../ModularForms/Discriminant.lean | 69 +++---------------- 2 files changed, 65 insertions(+), 58 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DedekindEta.lean b/Mathlib/NumberTheory/ModularForms/DedekindEta.lean index b2905265b4ee9b..3ecd57ab784478 100644 --- a/Mathlib/NumberTheory/ModularForms/DedekindEta.lean +++ b/Mathlib/NumberTheory/ModularForms/DedekindEta.lean @@ -65,6 +65,60 @@ noncomputable def eta (z : ℂ) := 𝕢 24 z * ∏' n, (1 - eta_q n z) /-- Notation for the Dedekind eta function. -/ scoped[ModularForm] notation "η" => eta +/-! ### q-coordinate facts about `∏ (1 - q^(n+1))` + +The following lemmas describe the analytic behaviour of the infinite product +`∏' n, (1 - q^(n+1))` viewed as a function of `q` on the open unit disc, including the +behaviour at `q = 0` (the cusp at infinity). The eta-side lemmas below derive from these +by pulling back along `qParam 1 : ℍₒ → 𝔻 \ {0}`. +-/ + +/-- For `‖q‖ < 1`, the infinite product `∏ (1 - q^(n+1))` is multipliable. -/ +lemma multipliable_one_sub_pow {q : ℂ} (hq : ‖q‖ < 1) : + Multipliable fun n : ℕ ↦ 1 - q ^ (n + 1) := by + rw [show (fun n : ℕ ↦ 1 - q ^ (n + 1)) = (fun n ↦ 1 + (-q ^ (n + 1))) from by ext; ring] + apply multipliable_one_add_of_summable + simp only [norm_neg, norm_pow] + exact (summable_nat_add_iff 1).mpr (summable_geometric_of_lt_one (norm_nonneg _) hq) + +/-- The infinite product `∏ (1 - q^(n+1))` converges locally uniformly on the open unit disc, +with limit `q ↦ ∏' n, (1 - q^(n+1))`. -/ +lemma multipliableLocallyUniformlyOn_one_sub_pow : + MultipliableLocallyUniformlyOn (fun n q ↦ 1 - q ^ (n + 1)) (Metric.ball (0 : ℂ) 1) := by + use fun q ↦ ∏' n, (1 - q ^ (n + 1)) + simp_rw [sub_eq_add_neg] + apply hasProdLocallyUniformlyOn_of_forall_compact Metric.isOpen_ball + intro K hK hcK + by_cases hN : K.Nonempty + · have hc : ContinuousOn (fun q : ℂ ↦ ‖q‖) K := by fun_prop + obtain ⟨q₀, hq₀, _, HB⟩ := hcK.exists_sSup_image_eq_and_ge hN hc + have hq₀_lt : ‖q₀‖ < 1 := by simpa [Metric.mem_ball, dist_zero_right] using hK hq₀ + have hsum : Summable fun n : ℕ ↦ ‖q₀‖ ^ (n + 1) := + (summable_nat_add_iff 1).mpr (summable_geometric_of_lt_one (norm_nonneg _) hq₀_lt) + refine hsum.hasProdUniformlyOn_nat_one_add hcK (.of_forall fun n x hx ↦ ?_) + (fun _ ↦ by fun_prop) + simpa [norm_pow] using pow_le_pow_left₀ (norm_nonneg _) (HB x hx) (n + 1) + · rw [hasProdUniformlyOn_iff_tendstoUniformlyOn] + simpa [not_nonempty_iff_eq_empty.mp hN] using tendstoUniformlyOn_empty + +/-- The infinite product `q ↦ ∏' n, (1 - q^(n+1))` is differentiable on the open unit disc. -/ +lemma differentiableOn_tprod_one_sub_pow : + DifferentiableOn ℂ (fun q ↦ ∏' n, (1 - q ^ (n + 1))) (Metric.ball (0 : ℂ) 1) := by + apply multipliableLocallyUniformlyOn_one_sub_pow.hasProdLocallyUniformlyOn.differentiableOn + ?_ Metric.isOpen_ball + filter_upwards with n + simpa [Finset.prod_fn] using DifferentiableOn.finset_prod (fun _ _ ↦ by fun_prop) + +/-- For any `k`, the function `q ↦ ∏' n, (1 - q^(n+1))^k` is differentiable on the +open unit disc. -/ +lemma differentiableOn_tprod_one_sub_pow_pow (k : ℕ) : + DifferentiableOn ℂ (fun q ↦ ∏' n, (1 - q ^ (n + 1)) ^ k) (Metric.ball (0 : ℂ) 1) := by + refine (differentiableOn_tprod_one_sub_pow.fun_pow k).congr fun q hq ↦ ?_ + have hq_lt : ‖q‖ < 1 := by simpa [Metric.mem_ball, dist_zero_right] using hq + exact (multipliable_one_sub_pow hq_lt).tprod_pow k + +/-! ### z-coordinate eta product facts (derived from q-coordinate versions) -/ + theorem summable_eta_q (z : ℍ) : Summable fun n ↦ ‖-eta_q n z‖ := by simp [eta_q, eta_q_eq_pow, summable_nat_add_iff 1, norm_exp_two_pi_I_lt_one z] diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index fbca87f567f656..4fb13197343168 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -194,87 +194,40 @@ def discriminantCuspForm : CuspForm 𝒮ℒ 12 where rw [slash_action_generators_SL2Z discriminant_S_invariant discriminant_T_invariant] exact discriminant_isZeroAtImInfty -/-- The infinite product `∏ (1 - q^(n+1))` is multipliable for `‖q‖ < 1`. -/ -private lemma multipliable_one_sub_pow {q : ℂ} (hq : ‖q‖ < 1) : - Multipliable fun i ↦ 1 - q ^ (i + 1) := by - rw [show (fun i ↦ 1 - q ^ (i + 1)) = (fun i ↦ 1 + (-q ^ (i + 1))) from by ext; ring] - apply multipliable_one_add_of_summable - simp only [norm_neg, norm_pow] - exact (summable_nat_add_iff 1).mpr (summable_geometric_of_lt_one (norm_nonneg _) hq) - /-- The cusp function of the discriminant equals `q * ∏' n, (1 - q^(n+1))^24` -on `ball 0 (1/2)`. -/ +on the open unit disc. -/ private lemma discriminant_cuspFunction_eqOn : Set.EqOn (cuspFunction 1 (Δ : ℍ → ℂ)) - (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) := by + (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 1) := by intro q hq by_cases hq0 : q = 0 · simp only [hq0, zero_mul] exact Periodic.cuspFunction_zero_of_zero_at_inf one_pos discriminant_isZeroAtImInfty.zero_at_infty_comp_ofComplex - · have hqn : ‖q‖ < 1 := lt_trans (by simpa [dist_zero_right] using hq) (by norm_num) + · have hqn : ‖q‖ < 1 := by simpa [dist_zero_right] using hq have him := Periodic.im_invQParam_pos_of_norm_lt_one one_pos hqn hq0 rw [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, comp_apply, ofComplex_apply_of_im_pos him, discriminant_eq_q_prod ⟨_, him⟩] - -- eta_q n z = (qParam 1 z)^(n+1), and qParam(invQParam(q)) = q have hqr := Periodic.qParam_right_inv one_ne_zero hq0 have heta : ∀ n : ℕ, eta_q n (Periodic.invQParam 1 q) = q ^ (n + 1) := fun n ↦ by simp [eta_q, hqr] simp only [hqr, heta] -/-- The partial products `∏_{i simp [differentiableOn_const] - | succ n ih => - simp_rw [Finset.prod_range_succ]; exact ih.mul (by fun_prop)) - Metric.isOpen_ball - have hmem := Metric.mem_ball_self (x := (0 : ℂ)) (by norm_num : (0 : ℝ) < 1 / 2) - -- (∏(1-q^(n+1)))^24 is differentiable as a power of a differentiable function - have h24 := (hdiff 0 hmem).pow (n := 24) - -- ∏(1-q^(n+1))^24 = (∏(1-q^(n+1)))^24 by tprod_pow, so congr gives differentiability - refine h24.congr (fun q hq ↦ ?_) (by simp) - exact (multipliable_one_sub_pow (lt_trans (by simpa [dist_zero_right] using hq) - (by norm_num : (1 : ℝ) / 2 < 1))).tprod_pow 24 - /-- The first q-expansion coefficient of the modular discriminant is 1. -/ lemma discriminant_qExpansion_coeff_one : (qExpansion 1 (discriminantCuspForm : ℍ → ℂ)).coeff 1 = 1 := by rw [qExpansion_coeff] simp only [Nat.factorial_one, Nat.cast_one, inv_one, one_mul, iteratedDeriv_succ, iteratedDeriv_zero] - have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) (1 / 2 : ℝ) := Metric.mem_ball_self (by norm_num) + have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) 1 := Metric.mem_ball_self one_pos change deriv (cuspFunction 1 Δ) 0 = 1 - rw [← derivWithin_of_isOpen Metric.isOpen_ball hmem] - rw [derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem)] - have : derivWithin (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) 0 = - derivWithin id (Metric.ball 0 (1 / 2)) 0 * (∏' i, (1 - (0 : ℂ) ^ (i + 1)) ^ 24) + - id 0 * derivWithin (fun q ↦ ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) 0 := - derivWithin_mul differentiableWithinAt_id' differentiableWithinAt_eta_prod_pow - rw [this, derivWithin_id _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] + rw [← derivWithin_of_isOpen Metric.isOpen_ball hmem, + derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem), + show (fun q : ℂ ↦ q * ∏' n, (1 - q ^ (n + 1)) ^ 24) = + (fun q ↦ id q * ∏' n, (1 - q ^ (n + 1)) ^ 24) from rfl, + derivWithin_fun_mul differentiableWithinAt_id + (differentiableOn_tprod_one_sub_pow_pow 24 0 hmem), + derivWithin_id _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] simp end From 4870bfc8b33fdf25a1bfecba326d9bd281bc51da Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 13:53:27 +0100 Subject: [PATCH 09/49] refactor(NumberTheory/ModularForms): derive z-coord eta lemmas from q-coord base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than having parallel q-coord and z-coord proofs of the same convergence facts about the eta product, derive the z-coord versions from the q-coord ones by composing with `Periodic.qParam 1 : ℍₒ → Metric.ball 0 1`. - `multipliableLocallyUniformlyOn_eta` is now derived from `multipliableLocallyUniformlyOn_one_sub_pow` via `TendstoLocallyUniformlyOn.comp`, shrinking the proof from ~14 lines to ~7. - `differentiableAt_eta_tprod` now derives from `differentiableOn_tprod_one_sub_pow` by chain rule (instead of going through the eta-side multipliable lemma). - `summable_eta_q` switched to `norm_qParam_lt_one` (which the q-coord material already uses) for consistency. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ModularForms/DedekindEta.lean | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DedekindEta.lean b/Mathlib/NumberTheory/ModularForms/DedekindEta.lean index 3ecd57ab784478..55411f1649cb51 100644 --- a/Mathlib/NumberTheory/ModularForms/DedekindEta.lean +++ b/Mathlib/NumberTheory/ModularForms/DedekindEta.lean @@ -120,24 +120,21 @@ lemma differentiableOn_tprod_one_sub_pow_pow (k : ℕ) : /-! ### z-coordinate eta product facts (derived from q-coordinate versions) -/ theorem summable_eta_q (z : ℍ) : Summable fun n ↦ ‖-eta_q n z‖ := by - simp [eta_q, eta_q_eq_pow, summable_nat_add_iff 1, norm_exp_two_pi_I_lt_one z] + have hq : ‖(𝕢 (1 : ℝ) ↑z : ℂ)‖ < 1 := by exact_mod_cast norm_qParam_lt_one 1 z + simpa only [norm_neg, eta_q, norm_pow] using + (summable_nat_add_iff 1).mpr (summable_geometric_of_lt_one (norm_nonneg _) hq) lemma multipliableLocallyUniformlyOn_eta : MultipliableLocallyUniformlyOn (fun n a ↦ 1 - eta_q n a) ℍₒ := by - use fun z ↦ ∏' n, (1 - eta_q n z) - simp_rw [sub_eq_add_neg] - apply hasProdLocallyUniformlyOn_of_forall_compact isOpen_upperHalfPlaneSet - intro K hK hcK - by_cases hN : K.Nonempty - · have hc : ContinuousOn (fun x ↦ ‖cexp (2 * π * I * x)‖) K := by fun_prop - obtain ⟨z, hz, hB, HB⟩ := hcK.exists_sSup_image_eq_and_ge hN hc - apply (summable_eta_q ⟨z, hK hz⟩).hasProdUniformlyOn_nat_one_add hcK - · filter_upwards with n x hx - simpa [eta_q, eta_q_eq_pow] using pow_le_pow_left₀ (by simp [norm_nonneg]) (HB x hx) _ - · simp_rw [eta_q, Periodic.qParam] - fun_prop - · rw [hasProdUniformlyOn_iff_tendstoUniformlyOn] - simpa [not_nonempty_iff_eq_empty.mp hN] using tendstoUniformlyOn_empty + refine ⟨fun z ↦ ∏' n, (1 - eta_q n z), ?_⟩ + rw [hasProdLocallyUniformlyOn_iff_tendstoLocallyUniformlyOn] + have h := multipliableLocallyUniformlyOn_one_sub_pow.hasProdLocallyUniformlyOn + rw [hasProdLocallyUniformlyOn_iff_tendstoLocallyUniformlyOn] at h + exact h.comp (Periodic.qParam 1) + (fun z hz ↦ by + simpa [Metric.mem_ball, dist_zero_right] using + (by exact_mod_cast norm_qParam_lt_one 1 ⟨z, hz⟩ : ‖(𝕢 (1 : ℝ) z : ℂ)‖ < 1)) + (by fun_prop) lemma eta_tprod_ne_zero {z : ℂ} (hz : z ∈ ℍₒ) : ∏' n, (1 - eta_q n z) ≠ 0 := by refine tprod_one_add_ne_zero_of_summable (f := fun n ↦ -eta_q n z) ?_ ?_ @@ -179,10 +176,11 @@ lemma tsum_logDeriv_eta_q (z : ℂ) : ∑' n, logDeriv (fun x ↦ 1 - eta_q n x) lemma differentiableAt_eta_tprod {z : ℂ} (hz : z ∈ ℍₒ) : DifferentiableAt ℂ (fun x ↦ ∏' n, (1 - eta_q n x)) z := by - apply (multipliableLocallyUniformlyOn_eta.hasProdLocallyUniformlyOn.differentiableOn ?_ - isOpen_upperHalfPlaneSet z hz).differentiableAt (isOpen_upperHalfPlaneSet.mem_nhds hz) - filter_upwards with b - simpa [Finset.prod_fn] using DifferentiableOn.finset_prod (by fun_prop) + have hq : (𝕢 (1 : ℝ) z : ℂ) ∈ Metric.ball (0 : ℂ) 1 := by + simpa [Metric.mem_ball, dist_zero_right] using + (by exact_mod_cast norm_qParam_lt_one 1 ⟨z, hz⟩ : ‖(𝕢 (1 : ℝ) z : ℂ)‖ < 1) + exact (((differentiableOn_tprod_one_sub_pow).differentiableAt + (Metric.isOpen_ball.mem_nhds hq)).comp z (by fun_prop : DifferentiableAt ℂ (𝕢 (1 : ℝ)) z)) theorem differentiableAt_eta_of_mem_upperHalfPlaneSet {z : ℂ} (hz : z ∈ ℍₒ) : DifferentiableAt ℂ eta z := From 53ec44010ea7c2c03c80ba923cd520e503ab0348 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 14:00:40 +0100 Subject: [PATCH 10/49] chore(NumberTheory/ModularForms): shorten `multipliableLocallyUniformlyOn_eta` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `hasProdLocallyUniformlyOn_iff_tendstoLocallyUniformlyOn` is `Iff.rfl`, so the two `rw` calls in the previous proof are unnecessary — a type ascription on the underlying `HasProdLocallyUniformlyOn` is enough to invoke `TendstoLocallyUniformlyOn.comp` via dot notation. Collapse the proof to a 6-line term-mode expression. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../NumberTheory/ModularForms/DedekindEta.lean | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DedekindEta.lean b/Mathlib/NumberTheory/ModularForms/DedekindEta.lean index 55411f1649cb51..1b5e52c6561510 100644 --- a/Mathlib/NumberTheory/ModularForms/DedekindEta.lean +++ b/Mathlib/NumberTheory/ModularForms/DedekindEta.lean @@ -125,16 +125,12 @@ theorem summable_eta_q (z : ℍ) : Summable fun n ↦ ‖-eta_q n z‖ := by (summable_nat_add_iff 1).mpr (summable_geometric_of_lt_one (norm_nonneg _) hq) lemma multipliableLocallyUniformlyOn_eta : - MultipliableLocallyUniformlyOn (fun n a ↦ 1 - eta_q n a) ℍₒ := by - refine ⟨fun z ↦ ∏' n, (1 - eta_q n z), ?_⟩ - rw [hasProdLocallyUniformlyOn_iff_tendstoLocallyUniformlyOn] - have h := multipliableLocallyUniformlyOn_one_sub_pow.hasProdLocallyUniformlyOn - rw [hasProdLocallyUniformlyOn_iff_tendstoLocallyUniformlyOn] at h - exact h.comp (Periodic.qParam 1) - (fun z hz ↦ by - simpa [Metric.mem_ball, dist_zero_right] using - (by exact_mod_cast norm_qParam_lt_one 1 ⟨z, hz⟩ : ‖(𝕢 (1 : ℝ) z : ℂ)‖ < 1)) - (by fun_prop) + MultipliableLocallyUniformlyOn (fun n a ↦ 1 - eta_q n a) ℍₒ := + ⟨_, (multipliableLocallyUniformlyOn_one_sub_pow.hasProdLocallyUniformlyOn : + TendstoLocallyUniformlyOn _ _ _ _).comp (Periodic.qParam 1) + (fun z hz ↦ by simpa [Metric.mem_ball, dist_zero_right] using + (by exact_mod_cast norm_qParam_lt_one 1 ⟨z, hz⟩ : ‖(𝕢 (1 : ℝ) z : ℂ)‖ < 1)) + (by fun_prop)⟩ lemma eta_tprod_ne_zero {z : ℂ} (hz : z ∈ ℍₒ) : ∏' n, (1 - eta_q n z) ≠ 0 := by refine tprod_one_add_ne_zero_of_summable (f := fun n ↦ -eta_q n z) ?_ ?_ From 1f1ec2dc04d69cce8c3bb9dfbba35589f7ebd7d5 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 14:10:52 +0100 Subject: [PATCH 11/49] refactor(NumberTheory/ModularForms): decompose dimension-formula proofs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extracts helper lemmas to shorten the two main proofs: - `tendsto_valueAtInfty`: a modular form whose `valueAtInfty` is `c` tends to `c` along `atImInfty`. Used in `E4_cube_sub_E6_sq_form_isCuspForm`. - `E4_cube_sub_E6_sq_form` (def): the explicit `ModularForm 𝒮ℒ 12` whose pointwise value is `E₄³ - E₆²`, with companion lemmas `_apply`, `_isCuspForm`, `_qExpansion_coeff_one`. The main theorem `discriminant_eq_E4_cube_sub_E6_sq` is now ~15 lines instead of ~70. - `coeffZero_eq_zero_of_pow_eq_smul`: the algebraic core of the weight-2 vanishing argument as a pure power-series fact (no modular forms). `weight_two_eq_zero_of_not_cuspForm` becomes a thin wrapper that transports the modular-form identities into the power-series form, shrinking from ~50 lines to ~25. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../DimensionFormulas/LevelOne.lean | 183 ++++++++++-------- 1 file changed, 101 insertions(+), 82 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index f137c1580b49f3..8a517d753cce2b 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -247,100 +247,95 @@ private lemma E₆_qExpansion_coeff_one : (qExpansion 1 E₆).coeff 1 = -504 := bernoulli'_eq_zero_of_odd (show Odd 5 from ⟨2, rfl⟩) (by norm_num)]] simp [ArithmeticFunction.sigma_one]; norm_num -/-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ -theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : - discriminant z = (1 / 1728) * (E₄ z ^ 3 - E₆ z ^ 2) := by - set F : ModularForm 𝒮ℒ 12 := - ModularForm.mcast (show 4 + (4 + 4) = 12 by norm_num) - (E₄.mul (ModularForm.mcast (show 4 + 4 = 4 + 4 from rfl) (E₄.mul E₄))) - +/-- A modular form whose `valueAtInfty` is `c` tends to `c` along `atImInfty`. -/ +private lemma tendsto_valueAtInfty {k : ℤ} (f : ModularForm 𝒮ℒ k) (c : ℂ) + (hv : valueAtInfty (f : ℍ → ℂ) = c) : Filter.Tendsto f atImInfty (𝓝 c) := by + rw [← hv, ← cuspFunction_apply_zero f one_pos one_mem_strictPeriods_SL] + exact ((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL + ).continuousAt.tendsto.comp (qParam_tendsto_atImInfty one_pos)).congr + (fun τ ↦ eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero) + +/-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ +private noncomputable def E4_cube_sub_E6_sq_form : ModularForm 𝒮ℒ 12 := + ModularForm.mcast (show 4 + (4 + 4) = 12 by norm_num) + (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄))) - ModularForm.mcast (show 6 + 6 = 12 by norm_num) (E₆.mul E₆) - have hF : ∀ w, F w = E₄ w ^ 3 - E₆ w ^ 2 := fun w ↦ by - change E₄ w * (E₄ w * E₄ w) - E₆ w * E₆ w = E₄ w ^ 3 - E₆ w ^ 2; ring + +private lemma E4_cube_sub_E6_sq_form_apply (z : ℍ) : + E4_cube_sub_E6_sq_form z = E₄ z ^ 3 - E₆ z ^ 2 := by + change E₄ z * (E₄ z * E₄ z) - E₆ z * E₆ z = _; ring + +private lemma E4_cube_sub_E6_sq_form_isCuspForm : IsCuspForm E4_cube_sub_E6_sq_form := by + refine (isCuspForm_iff_coeffZero_eq_zero _).mpr ?_ + rw [qExpansion_coeff_zero _ one_pos one_mem_strictPeriods_SL] + have h4 : Filter.Tendsto (E₄ : ℍ → ℂ) atImInfty (𝓝 1) := tendsto_valueAtInfty E₄ 1 (by + rw [← qExpansion_coeff_zero E₄ one_pos one_mem_strictPeriods_SL] + exact E_qExpansion_coeff_zero _ ⟨2, rfl⟩) + have h6 : Filter.Tendsto (E₆ : ℍ → ℂ) atImInfty (𝓝 1) := tendsto_valueAtInfty E₆ 1 (by + rw [← qExpansion_coeff_zero E₆ one_pos one_mem_strictPeriods_SL] + exact E_qExpansion_coeff_zero _ ⟨3, rfl⟩) + refine ((Filter.Tendsto.congr (fun w ↦ (E4_cube_sub_E6_sq_form_apply w).symm) ?_)).limUnder_eq + simpa using (h4.pow 3).sub (h6.pow 2) + +private lemma E4_cube_sub_E6_sq_form_qExpansion_coeff_one : + (qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ)).coeff 1 = 1728 := by + have hmcast : ∀ {a b : ℤ} (h : a = b) (f : ModularForm 𝒮ℒ a), + qExpansion 1 (ModularForm.mcast h f : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) := + fun _ _ ↦ rfl have h0_4 : (qExpansion 1 (E₄ : ℍ → ℂ)).coeff 0 = 1 := E_qExpansion_coeff_zero _ ⟨2, rfl⟩ have h0_6 : (qExpansion 1 (E₆ : ℍ → ℂ)).coeff 0 = 1 := E_qExpansion_coeff_zero _ ⟨3, rfl⟩ - have hF_cusp : IsCuspForm F := (isCuspForm_iff_coeffZero_eq_zero F).mpr (by - rw [qExpansion_coeff_zero F one_pos one_mem_strictPeriods_SL] - have hv4 : valueAtInfty (E₄ : ℍ → ℂ) = 1 := by - rwa [← qExpansion_coeff_zero E₄ one_pos one_mem_strictPeriods_SL] - have hv6 : valueAtInfty (E₆ : ℍ → ℂ) = 1 := by - rwa [← qExpansion_coeff_zero E₆ one_pos one_mem_strictPeriods_SL] - change limUnder atImInfty (fun w ↦ E₄ w * (E₄ w * E₄ w) - E₆ w * E₆ w) = 0 - have htend : ∀ {k' : ℤ} (f : ModularForm 𝒮ℒ k') {c' : ℂ}, valueAtInfty (f : ℍ → ℂ) = c' → - Filter.Tendsto f atImInfty (𝓝 c') := fun {_} f {_} hv ↦ by - rw [← hv, ← cuspFunction_apply_zero f one_pos one_mem_strictPeriods_SL] - exact ((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL - ).continuousAt.tendsto.comp (qParam_tendsto_atImInfty one_pos)).congr - (fun τ ↦ eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero) - have h4 := htend E₄ hv4 - have h6 := htend E₆ hv6 - convert ((h4.mul (h4.mul h4)).sub (h6.mul h6)).limUnder_eq using 1 - norm_num) - obtain ⟨g, hg⟩ := hF_cusp + have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (12 : ℤ))).map_sub + (ModularForm.mcast (by norm_num) (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄)))) + (ModularForm.mcast (by norm_num) (E₆.mul E₆)) + simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk, hmcast] at hsub + rw [show (E4_cube_sub_E6_sq_form : ℍ → ℂ) = + (((ModularForm.mcast (by norm_num) (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄))) - + ModularForm.mcast (by norm_num) (E₆.mul E₆) : ModularForm 𝒮ℒ 12)) : ℍ → ℂ) from rfl, + hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ + (ModularForm.mcast rfl (E₄.mul E₄)), hmcast, + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] + simp only [map_sub, PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, + Finset.Nat.antidiagonal_zero, Finset.sum_cons, Finset.sum_singleton, + Finset.map_singleton, Function.Embedding.prodMap, Prod.map, + Function.Embedding.coeFn_mk, Nat.succ_eq_add_one, Nat.zero_add, + Function.Embedding.refl_apply, E₄_qExpansion_coeff_one, E₆_qExpansion_coeff_one] + norm_num [h0_4, h0_6] + +/-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ +theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : + discriminant z = (1 / 1728) * (E₄ z ^ 3 - E₆ z ^ 2) := by + obtain ⟨g, hg⟩ := E4_cube_sub_E6_sq_form_isCuspForm obtain ⟨c, hc⟩ := cuspForm_twelve_smul_discriminant g + have hgF : qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) := by + congr 1; exact congr_arg DFunLike.coe hg + have hgΔ : qExpansion 1 (g : ℍ → ℂ) = c • qExpansion 1 (discriminantCuspForm : ℍ → ℂ) := by + conv_lhs => rw [show (g : ℍ → ℂ) = ((c • discriminantCuspForm : CuspForm 𝒮ℒ 12) : ℍ → ℂ) + from congr_arg DFunLike.coe hc.symm] + exact qExpansion_smul one_pos one_mem_strictPeriods_SL c discriminantCuspForm have hc_eq : c = 1728 := by - have hmcast : ∀ {a b : ℤ} (h : a = b) (f : ModularForm 𝒮ℒ a), - qExpansion 1 (ModularForm.mcast h f : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) := - fun _ _ ↦ rfl - have hgF : qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (F : ℍ → ℂ) := by - congr 1; exact congr_arg DFunLike.coe hg - have hgΔ : qExpansion 1 (g : ℍ → ℂ) = - c • qExpansion 1 (discriminantCuspForm : ℍ → ℂ) := by - conv_lhs => rw [show (g : ℍ → ℂ) = ((c • discriminantCuspForm : CuspForm 𝒮ℒ 12) : ℍ → ℂ) - from congr_arg DFunLike.coe hc.symm] - exact qExpansion_smul one_pos one_mem_strictPeriods_SL c discriminantCuspForm have h := congr_arg (·.coeff 1) (hgF.symm.trans hgΔ) simp only [PowerSeries.coeff_smul, smul_eq_mul, discriminant_qExpansion_coeff_one, - mul_one] at h - have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (12 : ℤ))).map_sub - (ModularForm.mcast (by norm_num) (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄)))) - (ModularForm.mcast (by norm_num) (E₆.mul E₆)) - simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk, hmcast] at hsub - rw [hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ - (ModularForm.mcast rfl (E₄.mul E₄))] at h - simp only [hmcast] at h - rw [ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, - ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] at h - simp only [map_sub, PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, - Finset.Nat.antidiagonal_zero, Finset.sum_cons, Finset.sum_singleton, - Finset.map_singleton, Function.Embedding.prodMap, Prod.map, - Function.Embedding.coeFn_mk, Nat.succ_eq_add_one, Nat.zero_add, - Function.Embedding.refl_apply, E₄_qExpansion_coeff_one, - E₆_qExpansion_coeff_one] at h - exact h.symm.trans (by norm_num [h0_4, h0_6]) + mul_one, E4_cube_sub_E6_sq_form_qExpansion_coeff_one] at h + exact h.symm have h1728 : (1728 : ℂ) * discriminant z = E₄ z ^ 3 - E₆ z ^ 2 := calc (1728 : ℂ) * discriminant z = c * discriminant z := by rw [hc_eq] _ = (c • discriminantCuspForm) z := rfl _ = g z := by rw [← hc] - _ = F z := congr_fun (congr_arg DFunLike.coe hg) z - _ = E₄ z ^ 3 - E₆ z ^ 2 := hF z + _ = E4_cube_sub_E6_sq_form z := congr_fun (congr_arg DFunLike.coe hg) z + _ = _ := E4_cube_sub_E6_sq_form_apply z linear_combination (norm := ring_nf) (1 / 1728 : ℂ) * h1728 -private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : ℤ)) - (hf : ¬IsCuspForm f) : f = 0 := by - exfalso - obtain ⟨c4, hc4⟩ := exists_smul_eq_of_rank_one weight_four_rank_one - (E_ne_zero _ ⟨2, rfl⟩ : (E₄ : ModularForm 𝒮ℒ 4) ≠ 0) (f.mul f) - obtain ⟨c6, hc6⟩ := exists_smul_eq_of_rank_one weight_six_rank_one - (E_ne_zero _ ⟨3, rfl⟩ : (E₆ : ModularForm 𝒮ℒ 6) ≠ 0) ((f.mul f).mul f) - set p := qExpansion 1 f - have hqc4 : c4 • qExpansion 1 (E₄ : ℍ → ℂ) = p * p := by - have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄ - rw [show (c4 • E₄ : ℍ → ℂ) = (f.mul f : ℍ → ℂ) from congrArg DFunLike.coe hc4] at hsmul - rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f]; exact hsmul.symm - have hqc6 : c6 • qExpansion 1 (E₆ : ℍ → ℂ) = p * p * p := by - have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆ - have hmul1 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (f.mul f) f - rw [show (c6 • E₆ : ℍ → ℂ) = ((f.mul f).mul f : ℍ → ℂ) from - congrArg DFunLike.coe hc6] at hsmul - rw [ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] at hmul1 - rw [← hmul1]; exact hsmul.symm - have hp4_0 : (qExpansion 1 (E₄ : ℍ → ℂ)).coeff 0 = 1 := - E_qExpansion_coeff_zero _ ⟨2, rfl⟩ - have hp6_0 : (qExpansion 1 (E₆ : ℍ → ℂ)).coeff 0 = 1 := - E_qExpansion_coeff_zero _ ⟨3, rfl⟩ +/-- Algebraic core of the weight-2 vanishing argument: if a complex power series `p` +satisfies `c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with constant +terms equal to `1` and first-order coefficients `240` and `-504`, then `p.coeff 0 = 0`. -/ +private lemma coeffZero_eq_zero_of_pow_eq_smul {p p4 p6 : PowerSeries ℂ} {c4 c6 : ℂ} + (hp4_0 : p4.coeff 0 = 1) (hp6_0 : p6.coeff 0 = 1) + (hp4_1 : p4.coeff 1 = 240) (hp6_1 : p6.coeff 1 = -504) + (hqc4 : c4 • p4 = p * p) (hqc6 : c6 • p6 = p * p * p) : p.coeff 0 = 0 := by have h0_4 : c4 = p.coeff 0 ^ 2 := by have h := congr_arg (·.coeff 0) hqc4 simp only [PowerSeries.coeff_smul, smul_eq_mul, PowerSeries.coeff_mul, @@ -353,22 +348,46 @@ private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : rw [show p.coeff 0 ^ 3 = p.coeff 0 * p.coeff 0 * p.coeff 0 by ring]; exact h have heq4 : p.coeff 0 ^ 2 * 240 = 2 * p.coeff 0 * p.coeff 1 := by have h := congr_arg (·.coeff 1) hqc4 - simp only [PowerSeries.coeff_smul, smul_eq_mul, E₄_qExpansion_coeff_one] at h + simp only [PowerSeries.coeff_smul, smul_eq_mul, hp4_1] at h rw [show (p * p).coeff 1 = 2 * p.coeff 0 * p.coeff 1 from by simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring, h0_4] at h exact h have heq6 : p.coeff 0 ^ 3 * (-504) = 3 * p.coeff 0 ^ 2 * p.coeff 1 := by have h := congr_arg (·.coeff 1) hqc6 - simp only [PowerSeries.coeff_smul, smul_eq_mul, E₆_qExpansion_coeff_one] at h + simp only [PowerSeries.coeff_smul, smul_eq_mul, hp6_1] at h rw [show (p * p * p).coeff 1 = 3 * p.coeff 0 ^ 2 * p.coeff 1 from by simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring, h0_6] at h exact h - refine hf ((isCuspForm_iff_coeffZero_eq_zero f).mpr <| - pow_eq_zero_iff (n := 3) three_ne_zero |>.mp ?_) + refine pow_eq_zero_iff (n := 3) three_ne_zero |>.mp ?_ have h0 : (1728 : ℂ) * p.coeff 0 ^ 3 = 0 := by linear_combination 3 * p.coeff 0 * heq4 - 2 * heq6 exact (mul_eq_zero.mp h0).resolve_left (by norm_num) +private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : ℤ)) + (hf : ¬IsCuspForm f) : f = 0 := by + exfalso + obtain ⟨c4, hc4⟩ := exists_smul_eq_of_rank_one weight_four_rank_one + (E_ne_zero _ ⟨2, rfl⟩ : (E₄ : ModularForm 𝒮ℒ 4) ≠ 0) (f.mul f) + obtain ⟨c6, hc6⟩ := exists_smul_eq_of_rank_one weight_six_rank_one + (E_ne_zero _ ⟨3, rfl⟩ : (E₆ : ModularForm 𝒮ℒ 6) ≠ 0) ((f.mul f).mul f) + have hqc4 : c4 • qExpansion 1 (E₄ : ℍ → ℂ) = + qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 (f : ℍ → ℂ) := by + have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄ + rw [show (c4 • E₄ : ℍ → ℂ) = (f.mul f : ℍ → ℂ) from congrArg DFunLike.coe hc4] at hsmul + rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f]; exact hsmul.symm + have hqc6 : c6 • qExpansion 1 (E₆ : ℍ → ℂ) = + qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 (f : ℍ → ℂ) := by + have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆ + have hmul1 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (f.mul f) f + rw [show (c6 • E₆ : ℍ → ℂ) = ((f.mul f).mul f : ℍ → ℂ) from + congrArg DFunLike.coe hc6] at hsmul + rw [ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] at hmul1 + rw [← hmul1]; exact hsmul.symm + exact hf <| (isCuspForm_iff_coeffZero_eq_zero f).mpr <| + coeffZero_eq_zero_of_pow_eq_smul (E_qExpansion_coeff_zero _ ⟨2, rfl⟩) + (E_qExpansion_coeff_zero _ ⟨3, rfl⟩) E₄_qExpansion_coeff_one E₆_qExpansion_coeff_one + hqc4 hqc6 + /-- Modular forms of weight 2 for `𝒮ℒ` are zero. -/ theorem ModularForm.levelOne_weight_two_rank_zero : Module.rank ℂ (ModularForm 𝒮ℒ (2 : ℤ)) = 0 := by From 9aee73773e5d6e237461aad506059c0360f8acc1 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 14:15:17 +0100 Subject: [PATCH 12/49] chore(NumberTheory/ModularForms): tighten dimension-formula proofs after decomposition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `discriminant_eq_E4_cube_sub_E6_sq`: move `hgΔ` back inside the local `hc_eq` block (it's only used there), inline `hgF`, and use `simpa` for the final step. - `E4_cube_sub_E6_sq_form_qExpansion_coeff_one`: minor simplification collapsing the chained `mcast`/`hmcast` rewrites. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../DimensionFormulas/LevelOne.lean | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 8a517d753cce2b..4e6c1ecc087c40 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -290,11 +290,10 @@ private lemma E4_cube_sub_E6_sq_form_qExpansion_coeff_one : (ModularForm.mcast (by norm_num) (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄)))) (ModularForm.mcast (by norm_num) (E₆.mul E₆)) simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk, hmcast] at hsub - rw [show (E4_cube_sub_E6_sq_form : ℍ → ℂ) = - (((ModularForm.mcast (by norm_num) (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄))) - - ModularForm.mcast (by norm_num) (E₆.mul E₆) : ModularForm 𝒮ℒ 12)) : ℍ → ℂ) from rfl, - hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ - (ModularForm.mcast rfl (E₄.mul E₄)), hmcast, + rw [show (E4_cube_sub_E6_sq_form : ℍ → ℂ) = ((ModularForm.mcast (by norm_num) + (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄))) - + ModularForm.mcast (by norm_num) (E₆.mul E₆) : ModularForm 𝒮ℒ 12) : ℍ → ℂ) from rfl, + hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ _, hmcast, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] simp only [map_sub, PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, @@ -309,17 +308,16 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : discriminant z = (1 / 1728) * (E₄ z ^ 3 - E₆ z ^ 2) := by obtain ⟨g, hg⟩ := E4_cube_sub_E6_sq_form_isCuspForm obtain ⟨c, hc⟩ := cuspForm_twelve_smul_discriminant g - have hgF : qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) := by - congr 1; exact congr_arg DFunLike.coe hg - have hgΔ : qExpansion 1 (g : ℍ → ℂ) = c • qExpansion 1 (discriminantCuspForm : ℍ → ℂ) := by - conv_lhs => rw [show (g : ℍ → ℂ) = ((c • discriminantCuspForm : CuspForm 𝒮ℒ 12) : ℍ → ℂ) - from congr_arg DFunLike.coe hc.symm] - exact qExpansion_smul one_pos one_mem_strictPeriods_SL c discriminantCuspForm have hc_eq : c = 1728 := by - have h := congr_arg (·.coeff 1) (hgF.symm.trans hgΔ) - simp only [PowerSeries.coeff_smul, smul_eq_mul, discriminant_qExpansion_coeff_one, - mul_one, E4_cube_sub_E6_sq_form_qExpansion_coeff_one] at h - exact h.symm + have hgΔ : qExpansion 1 (g : ℍ → ℂ) = c • qExpansion 1 (discriminantCuspForm : ℍ → ℂ) := by + conv_lhs => rw [show (g : ℍ → ℂ) = ((c • discriminantCuspForm : CuspForm 𝒮ℒ 12) : ℍ → ℂ) + from congr_arg DFunLike.coe hc.symm] + exact qExpansion_smul one_pos one_mem_strictPeriods_SL c discriminantCuspForm + have h := congr_arg (·.coeff 1) <| + (show qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) + from congr_arg _ (congr_arg DFunLike.coe hg)).symm.trans hgΔ + simpa [PowerSeries.coeff_smul, discriminant_qExpansion_coeff_one, + E4_cube_sub_E6_sq_form_qExpansion_coeff_one] using h.symm have h1728 : (1728 : ℂ) * discriminant z = E₄ z ^ 3 - E₆ z ^ 2 := calc (1728 : ℂ) * discriminant z = c * discriminant z := by rw [hc_eq] From b8144c96040403f80814561bc005ac180eb6e4ff Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 14:18:38 +0100 Subject: [PATCH 13/49] =?UTF-8?q?chore(NumberTheory/ModularForms):=20wrap?= =?UTF-8?q?=20long=20lines=20to=20=E2=89=A4=20100=20chars?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wraps several lines in the dimension-formula proofs to fit within mathlib's 100-character line length limit. No semantic changes. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../DimensionFormulas/LevelOne.lean | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 4e6c1ecc087c40..cbbedae2751b12 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -168,12 +168,14 @@ lemma cuspForm_twelve_smul_discriminant (f : CuspForm 𝒮ℒ 12) : /-- For even `k ≥ 3`, the rank of `𝒮ℒ` modular forms is one more than the rank of cusp forms. -/ lemma ModularForm.rank_eq_one_add_rank_cuspForm {k : ℕ} (hk : 3 ≤ k) (hk2 : Even k) : - Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ)) = 1 + Module.rank ℂ (CuspForm 𝒮ℒ (k : ℤ)) := by + Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ)) = + 1 + Module.rank ℂ (CuspForm 𝒮ℒ (k : ℤ)) := by have h_add := Submodule.rank_quotient_add_rank (cuspFormSubmodule 𝒮ℒ (k : ℤ)) rw [show Module.rank ℂ ↥(cuspFormSubmodule 𝒮ℒ (k : ℤ)) = Module.rank ℂ (CuspForm 𝒮ℒ (k : ℤ)) from (LinearEquiv.rank_eq (CuspForm.equivCuspFormSubmodule 𝒮ℒ (k : ℤ))).symm] at h_add - suffices h1 : Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ) ⧸ cuspFormSubmodule 𝒮ℒ (k : ℤ)) = 1 by + suffices h1 : Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ) ⧸ + cuspFormSubmodule 𝒮ℒ (k : ℤ)) = 1 by rw [← h_add, h1] have hE_coeff_zero := E_qExpansion_coeff_zero hk hk2 apply rank_eq_one (Submodule.Quotient.mk (p := cuspFormSubmodule 𝒮ℒ (k : ℤ)) (E hk)) @@ -268,12 +270,14 @@ private lemma E4_cube_sub_E6_sq_form_apply (z : ℍ) : private lemma E4_cube_sub_E6_sq_form_isCuspForm : IsCuspForm E4_cube_sub_E6_sq_form := by refine (isCuspForm_iff_coeffZero_eq_zero _).mpr ?_ rw [qExpansion_coeff_zero _ one_pos one_mem_strictPeriods_SL] - have h4 : Filter.Tendsto (E₄ : ℍ → ℂ) atImInfty (𝓝 1) := tendsto_valueAtInfty E₄ 1 (by - rw [← qExpansion_coeff_zero E₄ one_pos one_mem_strictPeriods_SL] - exact E_qExpansion_coeff_zero _ ⟨2, rfl⟩) - have h6 : Filter.Tendsto (E₆ : ℍ → ℂ) atImInfty (𝓝 1) := tendsto_valueAtInfty E₆ 1 (by - rw [← qExpansion_coeff_zero E₆ one_pos one_mem_strictPeriods_SL] - exact E_qExpansion_coeff_zero _ ⟨3, rfl⟩) + have h4 : Filter.Tendsto (E₄ : ℍ → ℂ) atImInfty (𝓝 1) := + tendsto_valueAtInfty E₄ 1 <| by + rw [← qExpansion_coeff_zero E₄ one_pos one_mem_strictPeriods_SL] + exact E_qExpansion_coeff_zero _ ⟨2, rfl⟩ + have h6 : Filter.Tendsto (E₆ : ℍ → ℂ) atImInfty (𝓝 1) := + tendsto_valueAtInfty E₆ 1 <| by + rw [← qExpansion_coeff_zero E₆ one_pos one_mem_strictPeriods_SL] + exact E_qExpansion_coeff_zero _ ⟨3, rfl⟩ refine ((Filter.Tendsto.congr (fun w ↦ (E4_cube_sub_E6_sq_form_apply w).symm) ?_)).limUnder_eq simpa using (h4.pow 3).sub (h6.pow 2) @@ -292,7 +296,8 @@ private lemma E4_cube_sub_E6_sq_form_qExpansion_coeff_one : simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk, hmcast] at hsub rw [show (E4_cube_sub_E6_sq_form : ℍ → ℂ) = ((ModularForm.mcast (by norm_num) (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄))) - - ModularForm.mcast (by norm_num) (E₆.mul E₆) : ModularForm 𝒮ℒ 12) : ℍ → ℂ) from rfl, + ModularForm.mcast (by norm_num) (E₆.mul E₆) : + ModularForm 𝒮ℒ 12) : ℍ → ℂ) from rfl, hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ _, hmcast, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] @@ -309,9 +314,11 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : obtain ⟨g, hg⟩ := E4_cube_sub_E6_sq_form_isCuspForm obtain ⟨c, hc⟩ := cuspForm_twelve_smul_discriminant g have hc_eq : c = 1728 := by - have hgΔ : qExpansion 1 (g : ℍ → ℂ) = c • qExpansion 1 (discriminantCuspForm : ℍ → ℂ) := by - conv_lhs => rw [show (g : ℍ → ℂ) = ((c • discriminantCuspForm : CuspForm 𝒮ℒ 12) : ℍ → ℂ) - from congr_arg DFunLike.coe hc.symm] + have hgΔ : qExpansion 1 (g : ℍ → ℂ) = + c • qExpansion 1 (discriminantCuspForm : ℍ → ℂ) := by + conv_lhs => rw [show (g : ℍ → ℂ) = + ((c • discriminantCuspForm : CuspForm 𝒮ℒ 12) : ℍ → ℂ) from + congr_arg DFunLike.coe hc.symm] exact qExpansion_smul one_pos one_mem_strictPeriods_SL c discriminantCuspForm have h := congr_arg (·.coeff 1) <| (show qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) @@ -327,9 +334,9 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : _ = _ := E4_cube_sub_E6_sq_form_apply z linear_combination (norm := ring_nf) (1 / 1728 : ℂ) * h1728 -/-- Algebraic core of the weight-2 vanishing argument: if a complex power series `p` -satisfies `c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with constant -terms equal to `1` and first-order coefficients `240` and `-504`, then `p.coeff 0 = 0`. -/ +/-- Algebraic core of the weight-2 vanishing argument: if `p : PowerSeries ℂ` satisfies +`c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with constant term `1` +and first-order coefficients `240` and `-504`, then `p.coeff 0 = 0`. -/ private lemma coeffZero_eq_zero_of_pow_eq_smul {p p4 p6 : PowerSeries ℂ} {c4 c6 : ℂ} (hp4_0 : p4.coeff 0 = 1) (hp6_0 : p6.coeff 0 = 1) (hp4_1 : p4.coeff 1 = 240) (hp6_1 : p6.coeff 1 = -504) @@ -371,10 +378,13 @@ private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : have hqc4 : c4 • qExpansion 1 (E₄ : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 (f : ℍ → ℂ) := by have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄ - rw [show (c4 • E₄ : ℍ → ℂ) = (f.mul f : ℍ → ℂ) from congrArg DFunLike.coe hc4] at hsmul - rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f]; exact hsmul.symm + rw [show (c4 • E₄ : ℍ → ℂ) = (f.mul f : ℍ → ℂ) from + congrArg DFunLike.coe hc4] at hsmul + rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] + exact hsmul.symm have hqc6 : c6 • qExpansion 1 (E₆ : ℍ → ℂ) = - qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 (f : ℍ → ℂ) := by + qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 (f : ℍ → ℂ) * + qExpansion 1 (f : ℍ → ℂ) := by have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆ have hmul1 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (f.mul f) f rw [show (c6 • E₆ : ℍ → ℂ) = ((f.mul f).mul f : ℍ → ℂ) from From 3ab18d1e84974910ed9bed4f10eec525be5b10aa Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 15:03:59 +0100 Subject: [PATCH 14/49] =?UTF-8?q?chore(NumberTheory/ModularForms):=20drop?= =?UTF-8?q?=20redundant=20show=20in=20E=E2=82=84/E=E2=82=86=20qExpansion?= =?UTF-8?q?=20lemmas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `E₄` and `E₆` are `noncomputable abbrev`s, so they reduce automatically and the explicit `show E₄ = E (...) from rfl` step in `E₄_qExpansion_coeff_one` and `E₆_qExpansion_coeff_one` was unnecessary. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ModularForms/DimensionFormulas/LevelOne.lean | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index cbbedae2751b12..0c5c61cd10b273 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -231,16 +231,14 @@ private lemma weight_six_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ (6 : ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (by norm_num))).trans (by norm_cast)) private lemma E₄_qExpansion_coeff_one : (qExpansion 1 E₄).coeff 1 = 240 := by - rw [show (E₄ : ModularForm 𝒮ℒ 4) = E (by norm_num : (3 : ℕ) ≤ 4) from rfl, - E_qExpansion_coeff _ ⟨2, rfl⟩] + rw [E_qExpansion_coeff _ ⟨2, rfl⟩] simp only [one_ne_zero, ↓reduceIte] rw [show bernoulli (4 : ℕ) = ((-1 : ℚ) / 30 : ℚ) from by rw [bernoulli_eq_bernoulli'_of_ne_one (by norm_num)]; exact bernoulli'_four] simp [ArithmeticFunction.sigma_one]; norm_num private lemma E₆_qExpansion_coeff_one : (qExpansion 1 E₆).coeff 1 = -504 := by - rw [show (E₆ : ModularForm 𝒮ℒ 6) = E (by norm_num : (3 : ℕ) ≤ 6) from rfl, - E_qExpansion_coeff _ ⟨3, rfl⟩] + rw [E_qExpansion_coeff _ ⟨3, rfl⟩] simp only [one_ne_zero, ↓reduceIte] rw [show bernoulli (6 : ℕ) = ((1 : ℚ) / 42 : ℚ) from by rw [bernoulli_eq_bernoulli'_of_ne_one (by norm_num), bernoulli'_def] From 1722006fd8c4487224519f0e8e2fc3bd7134d429 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 16:35:43 +0100 Subject: [PATCH 15/49] some golfs --- .../ModularForms/DedekindEta.lean | 4 +- .../DimensionFormulas/LevelOne.lean | 124 +++++++----------- .../ModularForms/Discriminant.lean | 11 +- 3 files changed, 53 insertions(+), 86 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DedekindEta.lean b/Mathlib/NumberTheory/ModularForms/DedekindEta.lean index 1b5e52c6561510..c2abe6a5a5d7d0 100644 --- a/Mathlib/NumberTheory/ModularForms/DedekindEta.lean +++ b/Mathlib/NumberTheory/ModularForms/DedekindEta.lean @@ -117,8 +117,6 @@ lemma differentiableOn_tprod_one_sub_pow_pow (k : ℕ) : have hq_lt : ‖q‖ < 1 := by simpa [Metric.mem_ball, dist_zero_right] using hq exact (multipliable_one_sub_pow hq_lt).tprod_pow k -/-! ### z-coordinate eta product facts (derived from q-coordinate versions) -/ - theorem summable_eta_q (z : ℍ) : Summable fun n ↦ ‖-eta_q n z‖ := by have hq : ‖(𝕢 (1 : ℝ) ↑z : ℂ)‖ < 1 := by exact_mod_cast norm_qParam_lt_one 1 z simpa only [norm_neg, eta_q, norm_pow] using @@ -130,7 +128,7 @@ lemma multipliableLocallyUniformlyOn_eta : TendstoLocallyUniformlyOn _ _ _ _).comp (Periodic.qParam 1) (fun z hz ↦ by simpa [Metric.mem_ball, dist_zero_right] using (by exact_mod_cast norm_qParam_lt_one 1 ⟨z, hz⟩ : ‖(𝕢 (1 : ℝ) z : ℂ)‖ < 1)) - (by fun_prop)⟩ + (by fun_prop)⟩ lemma eta_tprod_ne_zero {z : ℂ} (hz : z ∈ ℍₒ) : ∏' n, (1 - eta_q n z) ≠ 0 := by refine tprod_one_add_ne_zero_of_summable (f := fun n ↦ -eta_q n z) ?_ ?_ diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 0c5c61cd10b273..0db6b772cb4a76 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -39,17 +39,16 @@ namespace CuspForm /-- Multiply a modular form of weight `k - 12` by the discriminant to get a cusp form of weight `k`. Built directly as a CuspForm (no `IsCuspForm` intermediary). -/ -def ofMulDiscriminant (f : ModularForm 𝒮ℒ (k - 12)) : CuspForm 𝒮ℒ k := +def ofMulDiscriminant (f : ModularForm 𝒮ℒ (k - 12)) : CuspForm 𝒮ℒ k := by let Δ' := CuspForm.toModularFormₗ discriminantCuspForm - ModularForm.toCuspForm (ModularForm.mcast (by ring) (f.mul Δ')) (by - have hΔ' : (qExpansion 1 (Δ' : ℍ → ℂ)).coeff 0 = 0 := - (qExpansion_coeff_zero Δ' one_pos one_mem_strictPeriods_SL).trans - (CuspFormClass.zero_at_infty discriminantCuspForm).valueAtInfty_eq_zero - rw [show (ModularForm.mcast _ (f.mul Δ') : ℍ → ℂ) = (f : ℍ → ℂ) * Δ' from rfl, - qExpansion_mul_coeff_zero - (analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt - (analyticAt_cuspFunction_zero Δ' one_pos one_mem_strictPeriods_SL).continuousAt, - hΔ', mul_zero]) + apply ModularForm.toCuspForm (ModularForm.mcast (by ring) (f.mul Δ')) + have hΔ' : (qExpansion 1 (Δ' : ℍ → ℂ)).coeff 0 = 0 := + (qExpansion_coeff_zero Δ' one_pos one_mem_strictPeriods_SL).trans + (CuspFormClass.zero_at_infty discriminantCuspForm).valueAtInfty_eq_zero + rw [show (ModularForm.mcast _ (f.mul Δ')) = (f : ℍ → ℂ) * Δ' from rfl, + qExpansion_mul_coeff_zero + (analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt + (analyticAt_cuspFunction_zero Δ' one_pos one_mem_strictPeriods_SL).continuousAt,hΔ', mul_zero] @[simp] lemma ofMulDiscriminant_apply (f : ModularForm 𝒮ℒ (k - 12)) (z : ℍ) : @@ -57,9 +56,9 @@ lemma ofMulDiscriminant_apply (f : ModularForm 𝒮ℒ (k - 12)) (z : ℍ) : private lemma divByDiscriminant_slash_eq (f : CuspForm 𝒮ℒ k) (γ : SL(2, ℤ)) : (fun z ↦ f z / Δ z) ∣[k - 12] γ = fun z ↦ f z / Δ z := by - haveI : SlashInvariantFormClass (CuspForm 𝒮ℒ k) (CongruenceSubgroup.Gamma 1) k := + have : SlashInvariantFormClass (CuspForm 𝒮ℒ k) (CongruenceSubgroup.Gamma 1) k := CongruenceSubgroup.Gamma_one_coe_eq_SL ▸ inferInstance - haveI : SlashInvariantFormClass (CuspForm 𝒮ℒ 12) (CongruenceSubgroup.Gamma 1) 12 := + have : SlashInvariantFormClass (CuspForm 𝒮ℒ 12) (CongruenceSubgroup.Gamma 1) 12 := CongruenceSubgroup.Gamma_one_coe_eq_SL ▸ inferInstance have hf := slash_action_eqn_SL'' f (mem_Gamma_one γ) have hΔ := slash_action_eqn_SL'' discriminantCuspForm (mem_Gamma_one γ) @@ -153,8 +152,7 @@ lemma cuspForm_rank_lt_twelve (hk : k < 12) : /-- The space of weight 12 cusp forms for `𝒮ℒ` has rank 1. -/ lemma cuspForm_rank_twelve : Module.rank ℂ (CuspForm 𝒮ℒ 12) = 1 := by - rw [LinearEquiv.rank_eq CuspForm.discriminantEquiv, - show (12 : ℤ) - 12 = 0 from by norm_num] + rw [LinearEquiv.rank_eq CuspForm.discriminantEquiv, show (12 : ℤ) - 12 = 0 from by norm_num] exact levelOne_weight_zero_rank_one /-- Every weight 12 cusp form for `𝒮ℒ` is a scalar multiple of the discriminant. -/ @@ -186,18 +184,14 @@ lemma ModularForm.rank_eq_one_add_rank_cuspForm {k : ℕ} (hk : 3 ≤ k) (hk2 : (isCuspForm_iff_coeffZero_eq_zero _).mp h · refine (Submodule.Quotient.mk_surjective _).forall.mpr fun f ↦ ⟨(qExpansion 1 f).coeff 0, ?_⟩ - have h_mem : f - (qExpansion 1 ↑f).coeff 0 • E hk ∈ - cuspFormSubmodule 𝒮ℒ (k : ℤ) := - (isCuspForm_iff_coeffZero_eq_zero _).mpr (by - set c := (qExpansion 1 ↑f).coeff 0 with hc - have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (k : ℤ))).map_sub - f (c • E hk) - simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk] at hsub - rw [hsub] - have hcoe : ⇑(c • E hk) = c • (E hk : ℍ → ℂ) := rfl - rw [hcoe, qExpansion_smul one_pos one_mem_strictPeriods_SL c (E hk)] - simp only [_root_.map_sub, _root_.map_smul, smul_eq_mul, hE_coeff_zero, mul_one, ← hc, - sub_self]) + have h_mem : f - (qExpansion 1 ↑f).coeff 0 • E hk ∈ cuspFormSubmodule 𝒮ℒ (k : ℤ) := by + apply (isCuspForm_iff_coeffZero_eq_zero _).mpr + set c := (qExpansion 1 ↑f).coeff 0 with hc + have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := k)).map_sub f (c • E hk) + simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk] at hsub + rw [hsub] + simp [qExpansion_smul one_pos one_mem_strictPeriods_SL c (E hk), + _root_.map_sub, _root_.map_smul, hE_coeff_zero, mul_one, ← hc] have h0 : ((cuspFormSubmodule 𝒮ℒ (k : ℤ)).mkQ (f - (qExpansion 1 ↑f).coeff 0 • E hk) : ModularForm 𝒮ℒ (k : ℤ) ⧸ cuspFormSubmodule 𝒮ℒ (k : ℤ)) = 0 := (Submodule.Quotient.mk_eq_zero _).mpr h_mem @@ -211,15 +205,6 @@ end RankIdentity section DimensionFormula -/-! ### Helpers for weight 2 proof -/ - -/-- In a rank-one ℂ-module, every element is a scalar multiple of any nonzero element. -This is a thin wrapper around `finrank_eq_one_iff_of_nonzero'` adapted to `Module.rank`. -/ -private lemma exists_smul_eq_of_rank_one {M : Type*} [AddCommGroup M] [Module ℂ M] - (hrank : Module.rank ℂ M = 1) {e : M} (he : e ≠ 0) (f : M) : ∃ c : ℂ, c • e = f := - (finrank_eq_one_iff_of_nonzero' e he).mp - (Module.rank_eq_one_iff_finrank_eq_one.mp hrank) f - /-- Weight 4 modular forms for `𝒮ℒ` are 1-dimensional. -/ private lemma weight_four_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ (4 : ℤ)) = 1 := (rank_eq_one_add_rank_cuspForm (by norm_num) ⟨2, rfl⟩).trans @@ -249,10 +234,10 @@ private lemma E₆_qExpansion_coeff_one : (qExpansion 1 E₆).coeff 1 = -504 := /-- A modular form whose `valueAtInfty` is `c` tends to `c` along `atImInfty`. -/ private lemma tendsto_valueAtInfty {k : ℤ} (f : ModularForm 𝒮ℒ k) (c : ℂ) - (hv : valueAtInfty (f : ℍ → ℂ) = c) : Filter.Tendsto f atImInfty (𝓝 c) := by + (hv : valueAtInfty f = c) : Filter.Tendsto f atImInfty (𝓝 c) := by rw [← hv, ← cuspFunction_apply_zero f one_pos one_mem_strictPeriods_SL] - exact ((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL - ).continuousAt.tendsto.comp (qParam_tendsto_atImInfty one_pos)).congr + exact ((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt.tendsto.comp + (qParam_tendsto_atImInfty one_pos)).congr (fun τ ↦ eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero) /-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ @@ -282,20 +267,13 @@ private lemma E4_cube_sub_E6_sq_form_isCuspForm : IsCuspForm E4_cube_sub_E6_sq_f private lemma E4_cube_sub_E6_sq_form_qExpansion_coeff_one : (qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ)).coeff 1 = 1728 := by have hmcast : ∀ {a b : ℤ} (h : a = b) (f : ModularForm 𝒮ℒ a), - qExpansion 1 (ModularForm.mcast h f : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) := - fun _ _ ↦ rfl - have h0_4 : (qExpansion 1 (E₄ : ℍ → ℂ)).coeff 0 = 1 := - E_qExpansion_coeff_zero _ ⟨2, rfl⟩ - have h0_6 : (qExpansion 1 (E₆ : ℍ → ℂ)).coeff 0 = 1 := - E_qExpansion_coeff_zero _ ⟨3, rfl⟩ + qExpansion 1 (mcast h f) = qExpansion 1 (f : ℍ → ℂ) := fun _ _ ↦ rfl have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (12 : ℤ))).map_sub - (ModularForm.mcast (by norm_num) (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄)))) - (ModularForm.mcast (by norm_num) (E₆.mul E₆)) + (mcast (by norm_num) (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄)))) + (mcast (by norm_num) (E₆.mul E₆)) simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk, hmcast] at hsub - rw [show (E4_cube_sub_E6_sq_form : ℍ → ℂ) = ((ModularForm.mcast (by norm_num) - (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄))) - - ModularForm.mcast (by norm_num) (E₆.mul E₆) : - ModularForm 𝒮ℒ 12) : ℍ → ℂ) from rfl, + rw [show (E4_cube_sub_E6_sq_form) = ((mcast (by norm_num) + (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄))) - mcast (by norm_num) (E₆.mul E₆))) from rfl, hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ _, hmcast, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] @@ -304,7 +282,7 @@ private lemma E4_cube_sub_E6_sq_form_qExpansion_coeff_one : Finset.map_singleton, Function.Embedding.prodMap, Prod.map, Function.Embedding.coeFn_mk, Nat.succ_eq_add_one, Nat.zero_add, Function.Embedding.refl_apply, E₄_qExpansion_coeff_one, E₆_qExpansion_coeff_one] - norm_num [h0_4, h0_6] + norm_num [E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] /-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : @@ -312,14 +290,13 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : obtain ⟨g, hg⟩ := E4_cube_sub_E6_sq_form_isCuspForm obtain ⟨c, hc⟩ := cuspForm_twelve_smul_discriminant g have hc_eq : c = 1728 := by - have hgΔ : qExpansion 1 (g : ℍ → ℂ) = - c • qExpansion 1 (discriminantCuspForm : ℍ → ℂ) := by + have hgΔ : qExpansion 1 (g : ℍ → ℂ) = c • qExpansion 1 (discriminantCuspForm) := by conv_lhs => rw [show (g : ℍ → ℂ) = ((c • discriminantCuspForm : CuspForm 𝒮ℒ 12) : ℍ → ℂ) from congr_arg DFunLike.coe hc.symm] exact qExpansion_smul one_pos one_mem_strictPeriods_SL c discriminantCuspForm have h := congr_arg (·.coeff 1) <| - (show qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) + (show qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (E4_cube_sub_E6_sq_form) from congr_arg _ (congr_arg DFunLike.coe hg)).symm.trans hgΔ simpa [PowerSeries.coeff_smul, discriminant_qExpansion_coeff_one, E4_cube_sub_E6_sq_form_qExpansion_coeff_one] using h.symm @@ -330,7 +307,7 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : _ = g z := by rw [← hc] _ = E4_cube_sub_E6_sq_form z := congr_fun (congr_arg DFunLike.coe hg) z _ = _ := E4_cube_sub_E6_sq_form_apply z - linear_combination (norm := ring_nf) (1 / 1728 : ℂ) * h1728 + linear_combination (1 / 1728 : ℂ) * h1728 /-- Algebraic core of the weight-2 vanishing argument: if `p : PowerSeries ℂ` satisfies `c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with constant term `1` @@ -366,33 +343,31 @@ private lemma coeffZero_eq_zero_of_pow_eq_smul {p p4 p6 : PowerSeries ℂ} {c4 c linear_combination 3 * p.coeff 0 * heq4 - 2 * heq6 exact (mul_eq_zero.mp h0).resolve_left (by norm_num) -private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ (2 : ℤ)) +private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ 2) (hf : ¬IsCuspForm f) : f = 0 := by exfalso - obtain ⟨c4, hc4⟩ := exists_smul_eq_of_rank_one weight_four_rank_one - (E_ne_zero _ ⟨2, rfl⟩ : (E₄ : ModularForm 𝒮ℒ 4) ≠ 0) (f.mul f) - obtain ⟨c6, hc6⟩ := exists_smul_eq_of_rank_one weight_six_rank_one - (E_ne_zero _ ⟨3, rfl⟩ : (E₆ : ModularForm 𝒮ℒ 6) ≠ 0) ((f.mul f).mul f) + have h0 := Module.rank_eq_one_iff_finrank_eq_one.mp weight_four_rank_one + rw [(finrank_eq_one_iff_of_nonzero' E₄ (E_ne_zero _ ⟨2, rfl⟩ : E₄ ≠ 0))] at h0 + have h1 := Module.rank_eq_one_iff_finrank_eq_one.mp weight_six_rank_one + rw [(finrank_eq_one_iff_of_nonzero' E₆ (E_ne_zero _ ⟨3, rfl⟩ : E₆ ≠ 0))] at h1 + obtain ⟨c4, hc4⟩ := h0 (f.mul f) + obtain ⟨c6, hc6⟩ := h1 ((f.mul f).mul f) have hqc4 : c4 • qExpansion 1 (E₄ : ℍ → ℂ) = - qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 (f : ℍ → ℂ) := by + qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 f := by have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄ - rw [show (c4 • E₄ : ℍ → ℂ) = (f.mul f : ℍ → ℂ) from + rw [show (c4 • E₄ : ℍ → ℂ) = (f.mul f) from congrArg DFunLike.coe hc4] at hsmul rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] exact hsmul.symm - have hqc6 : c6 • qExpansion 1 (E₆ : ℍ → ℂ) = - qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 (f : ℍ → ℂ) * - qExpansion 1 (f : ℍ → ℂ) := by + have hqc6 : c6 • qExpansion 1 E₆ = qExpansion 1 f * qExpansion 1 f * qExpansion 1 f := by have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆ have hmul1 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (f.mul f) f - rw [show (c6 • E₆ : ℍ → ℂ) = ((f.mul f).mul f : ℍ → ℂ) from - congrArg DFunLike.coe hc6] at hsmul + rw [show (c6 • E₆ : ℍ → ℂ) = (f.mul f).mul f from congrArg DFunLike.coe hc6] at hsmul rw [ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] at hmul1 - rw [← hmul1]; exact hsmul.symm + simp [← hmul1, hsmul.symm] exact hf <| (isCuspForm_iff_coeffZero_eq_zero f).mpr <| coeffZero_eq_zero_of_pow_eq_smul (E_qExpansion_coeff_zero _ ⟨2, rfl⟩) - (E_qExpansion_coeff_zero _ ⟨3, rfl⟩) E₄_qExpansion_coeff_one E₆_qExpansion_coeff_one - hqc4 hqc6 + (E_qExpansion_coeff_zero _ ⟨3, rfl⟩) E₄_qExpansion_coeff_one E₆_qExpansion_coeff_one hqc4 hqc6 /-- Modular forms of weight 2 for `𝒮ℒ` are zero. -/ theorem ModularForm.levelOne_weight_two_rank_zero : @@ -402,8 +377,7 @@ theorem ModularForm.levelOne_weight_two_rank_zero : by_cases hf : IsCuspForm f · obtain ⟨g, hg⟩ := hf rw [← hg] - simp [rank_zero_iff_forall_zero.mp - (cuspForm_rank_lt_twelve (show (2 : ℤ) < 12 by norm_num)) g] + simp [rank_zero_iff_forall_zero.mp (cuspForm_rank_lt_twelve (show (2 : ℤ) < 12 by norm_num)) g] · exact weight_two_eq_zero_of_not_cuspForm f hf /-- The dimension formula for `𝒮ℒ` modular forms of even weight `k ≥ 3`. -/ @@ -412,8 +386,7 @@ theorem ModularForm.dimension_level_one (k : ℕ) (hk : 3 ≤ (k : ℤ)) (hk2 : if 12 ∣ ((k : ℤ) - 2) then Nat.floor ((k : ℚ) / 12) else Nat.floor ((k : ℚ) / 12) + 1 := by induction k using Nat.strong_induction_on with | h k ihn => - rw [rank_eq_one_add_rank_cuspForm (by omega) hk2, - LinearEquiv.rank_eq CuspForm.discriminantEquiv] + rw [rank_eq_one_add_rank_cuspForm (by omega) hk2, LinearEquiv.rank_eq CuspForm.discriminantEquiv] by_cases HK : (3 : ℤ) ≤ ((k : ℤ) - 12) · have iH := ihn (k - 12) (by omega) (by omega) ((Nat.even_sub (by omega)).mpr (by simp only [hk2, true_iff]; decide)) @@ -426,7 +399,8 @@ theorem ModularForm.dimension_level_one (k : ℕ) (hk : 3 ≤ (k : ℤ)) (hk2 : Nat.floor_div_eq_one_add_floor_sub_div (k : ℚ) 12 (by norm_num) hk' by_cases h12 : 12 ∣ ((k) : ℤ) - 2 · simp only [show 12 ∣ (k : ℤ) - 12 - 2 from by omega, ↓reduceIte, h12] - norm_cast at *; rw [hfl (by exact_mod_cast (by omega : (12 : ℤ) ≤ k))] + norm_cast at * + rw [hfl (by exact_mod_cast (by omega : (12 : ℤ) ≤ k))] · simp only [show ¬ 12 ∣ (k : ℤ) - 12 - 2 from by omega, ↓reduceIte, h12, Nat.cast_add, Nat.cast_one] norm_cast at * diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index 4fb13197343168..a6a118d9fd92fd 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -197,8 +197,7 @@ def discriminantCuspForm : CuspForm 𝒮ℒ 12 where /-- The cusp function of the discriminant equals `q * ∏' n, (1 - q^(n+1))^24` on the open unit disc. -/ private lemma discriminant_cuspFunction_eqOn : - Set.EqOn (cuspFunction 1 (Δ : ℍ → ℂ)) - (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 1) := by + Set.EqOn (cuspFunction 1 Δ) (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 1) := by intro q hq by_cases hq0 : q = 0 · simp only [hq0, zero_mul] @@ -208,14 +207,10 @@ private lemma discriminant_cuspFunction_eqOn : have him := Periodic.im_invQParam_pos_of_norm_lt_one one_pos hqn hq0 rw [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, comp_apply, ofComplex_apply_of_im_pos him, discriminant_eq_q_prod ⟨_, him⟩] - have hqr := Periodic.qParam_right_inv one_ne_zero hq0 - have heta : ∀ n : ℕ, eta_q n (Periodic.invQParam 1 q) = q ^ (n + 1) := fun n ↦ by - simp [eta_q, hqr] - simp only [hqr, heta] + simp [eta_q, Periodic.qParam_right_inv one_ne_zero hq0] /-- The first q-expansion coefficient of the modular discriminant is 1. -/ -lemma discriminant_qExpansion_coeff_one : - (qExpansion 1 (discriminantCuspForm : ℍ → ℂ)).coeff 1 = 1 := by +lemma discriminant_qExpansion_coeff_one : (qExpansion 1 discriminantCuspForm).coeff 1 = 1 := by rw [qExpansion_coeff] simp only [Nat.factorial_one, Nat.cast_one, inv_one, one_mul, iteratedDeriv_succ, iteratedDeriv_zero] From 8d4689c385bc5d5355fec6252ca8f523dc794495 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 8 Apr 2026 16:51:52 +0100 Subject: [PATCH 16/49] more golfs --- .../DimensionFormulas/LevelOne.lean | 19 ++++++------------- .../ModularForms/Discriminant.lean | 3 +-- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 0db6b772cb4a76..1f6b388aaa7ca6 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -45,8 +45,7 @@ def ofMulDiscriminant (f : ModularForm 𝒮ℒ (k - 12)) : CuspForm 𝒮ℒ k := have hΔ' : (qExpansion 1 (Δ' : ℍ → ℂ)).coeff 0 = 0 := (qExpansion_coeff_zero Δ' one_pos one_mem_strictPeriods_SL).trans (CuspFormClass.zero_at_infty discriminantCuspForm).valueAtInfty_eq_zero - rw [show (ModularForm.mcast _ (f.mul Δ')) = (f : ℍ → ℂ) * Δ' from rfl, - qExpansion_mul_coeff_zero + rw [show (ModularForm.mcast _ (f.mul Δ')) = (f : ℍ → ℂ) * Δ' from rfl, qExpansion_mul_coeff_zero (analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt (analyticAt_cuspFunction_zero Δ' one_pos one_mem_strictPeriods_SL).continuousAt,hΔ', mul_zero] @@ -70,8 +69,7 @@ private lemma divByDiscriminant_slash_eq (f : CuspForm 𝒮ℒ k) (γ : SL(2, show k + -(k - 12) = (12 : ℤ) from by ring] exact mul_div_mul_left (f z) (Δ z) (zpow_ne_zero _ hd) -private lemma exp_decay_isBigO_discriminant (f : CuspForm 𝒮ℒ k) : - (f : ℍ → ℂ) =O[atImInfty] Δ := by +private lemma exp_decay_isBigO_discriminant (f : CuspForm 𝒮ℒ k) : f =O[atImInfty] Δ := by have hf_decay := CuspFormClass.exp_decay_atImInfty (h := 1) f one_pos one_mem_strictPeriods_SL have hΔ_lower : ∀ᶠ τ : ℍ in atImInfty, ‖(fun τ : ℍ ↦ Real.exp (-2 * Real.pi * τ.im / 1)) τ‖ ≤ 2 * ‖Δ τ‖ := by @@ -216,16 +214,12 @@ private lemma weight_six_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ (6 : ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (by norm_num))).trans (by norm_cast)) private lemma E₄_qExpansion_coeff_one : (qExpansion 1 E₄).coeff 1 = 240 := by - rw [E_qExpansion_coeff _ ⟨2, rfl⟩] - simp only [one_ne_zero, ↓reduceIte] - rw [show bernoulli (4 : ℕ) = ((-1 : ℚ) / 30 : ℚ) from by + rw [E_qExpansion_coeff _ ⟨2, rfl⟩, show bernoulli (4 : ℕ) = ((-1 : ℚ) / 30 : ℚ) from by rw [bernoulli_eq_bernoulli'_of_ne_one (by norm_num)]; exact bernoulli'_four] simp [ArithmeticFunction.sigma_one]; norm_num private lemma E₆_qExpansion_coeff_one : (qExpansion 1 E₆).coeff 1 = -504 := by - rw [E_qExpansion_coeff _ ⟨3, rfl⟩] - simp only [one_ne_zero, ↓reduceIte] - rw [show bernoulli (6 : ℕ) = ((1 : ℚ) / 42 : ℚ) from by + rw [E_qExpansion_coeff _ ⟨3, rfl⟩, show bernoulli (6 : ℕ) = ((1 : ℚ) / 42 : ℚ) from by rw [bernoulli_eq_bernoulli'_of_ne_one (by norm_num), bernoulli'_def] norm_num [Finset.sum_range_succ, Finset.sum_range_zero, show Nat.choose 6 2 = 15 from by decide, show Nat.choose 6 4 = 15 from by decide, @@ -242,9 +236,8 @@ private lemma tendsto_valueAtInfty {k : ℤ} (f : ModularForm 𝒮ℒ k) (c : /-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ private noncomputable def E4_cube_sub_E6_sq_form : ModularForm 𝒮ℒ 12 := - ModularForm.mcast (show 4 + (4 + 4) = 12 by norm_num) - (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄))) - - ModularForm.mcast (show 6 + 6 = 12 by norm_num) (E₆.mul E₆) + mcast (show 4 + (4 + 4) = 12 by norm_num) (E₄.mul (mcast rfl (E₄.mul E₄))) - + mcast (show 6 + 6 = 12 by norm_num) (E₆.mul E₆) private lemma E4_cube_sub_E6_sq_form_apply (z : ℍ) : E4_cube_sub_E6_sq_form z = E₄ z ^ 3 - E₆ z ^ 2 := by diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index a6a118d9fd92fd..4705397a850a06 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -216,14 +216,13 @@ lemma discriminant_qExpansion_coeff_one : (qExpansion 1 discriminantCuspForm).co iteratedDeriv_zero] have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) 1 := Metric.mem_ball_self one_pos change deriv (cuspFunction 1 Δ) 0 = 1 - rw [← derivWithin_of_isOpen Metric.isOpen_ball hmem, + simp [← derivWithin_of_isOpen Metric.isOpen_ball hmem, derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem), show (fun q : ℂ ↦ q * ∏' n, (1 - q ^ (n + 1)) ^ 24) = (fun q ↦ id q * ∏' n, (1 - q ^ (n + 1)) ^ 24) from rfl, derivWithin_fun_mul differentiableWithinAt_id (differentiableOn_tprod_one_sub_pow_pow 24 0 hmem), derivWithin_id _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] - simp end From 97c057c64ba3231e956cc931aa971340d7604396 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 10 Apr 2026 17:37:14 +0100 Subject: [PATCH 17/49] cleanup --- .../ModularForms/CuspFormSubmodule.lean | 14 +- .../DimensionFormulas/LevelOne.lean | 178 ++++++++---------- .../ModularForms/Discriminant.lean | 2 +- 3 files changed, 85 insertions(+), 109 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean index a9b6378449a2f0..f717c96303b259 100644 --- a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean +++ b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean @@ -3,9 +3,11 @@ Copyright (c) 2026 Chris Birkbeck. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Birkbeck -/ -import Mathlib.NumberTheory.ModularForms.QExpansion -import Mathlib.NumberTheory.ModularForms.LevelOne -import Mathlib.NumberTheory.ModularForms.EisensteinSeries.QExpansion +module + +public import Mathlib.NumberTheory.ModularForms.QExpansion +public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.QExpansion /-! # Cusp form submodule and IsCuspForm predicate @@ -31,11 +33,11 @@ q-expansion coefficient (for `𝒮ℒ`). q-expansion having vanishing constant term. -/ +@[expose] public noncomputable section + open UpperHalfPlane ModularForm Complex SlashInvariantForm SlashInvariantFormClass ModularFormClass MatrixGroups OnePoint Filter Topology -noncomputable section - variable {Γ : Subgroup (GL (Fin 2) ℝ)} {k : ℤ} namespace CuspForm @@ -100,7 +102,7 @@ lemma isZeroAtImInfty_of_valueAtInfty_eq_zero (fun τ ↦ eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero) /-- An `𝒮ℒ` modular form with vanishing q-expansion constant term vanishes at every cusp. -/ -private lemma isZeroAt_of_coeffZero_eq_zero (f : ModularForm 𝒮ℒ k) +lemma isZeroAt_of_coeffZero_eq_zero (f : ModularForm 𝒮ℒ k) (h : (qExpansion 1 f).coeff 0 = 0) {c : OnePoint ℝ} (hc : IsCusp c 𝒮ℒ) : c.IsZeroAt f k := by rw [Subgroup.IsArithmetic.isCusp_iff_isCusp_SL2Z] at hc diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 1f6b388aaa7ca6..30e85a8f7b3e8a 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -3,11 +3,13 @@ Copyright (c) 2026 Chris Birkbeck. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Birkbeck -/ -import Mathlib.Algebra.Order.Floor.Semifield -import Mathlib.NumberTheory.ModularForms.CuspFormSubmodule -import Mathlib.NumberTheory.ModularForms.Discriminant -import Mathlib.Data.Rat.Star -import Mathlib.LinearAlgebra.Dimension.Localization +module + +public import Mathlib.Algebra.Order.Floor.Semifield +public import Mathlib.NumberTheory.ModularForms.CuspFormSubmodule +public import Mathlib.NumberTheory.ModularForms.Discriminant +public import Mathlib.Data.Rat.Star +public import Mathlib.LinearAlgebra.Dimension.Localization /-! # Dimension formula for level 1 modular forms @@ -22,11 +24,11 @@ of even weight `k ≥ 3`. * `ModularForm.dimension_level_one`: the full dimension formula. -/ +@[expose] public noncomputable section + open UpperHalfPlane ModularForm Complex SlashInvariantForm SlashInvariantFormClass ModularFormClass CongruenceSubgroup MatrixGroups OnePoint Filter Topology EisensteinSeries -noncomputable section - /-! ### Delta isomorphism: `CuspForm 𝒮ℒ k ≃ₗ[ℂ] ModularForm 𝒮ℒ (k - 12)` -/ section DeltaIsomorphism @@ -45,9 +47,11 @@ def ofMulDiscriminant (f : ModularForm 𝒮ℒ (k - 12)) : CuspForm 𝒮ℒ k := have hΔ' : (qExpansion 1 (Δ' : ℍ → ℂ)).coeff 0 = 0 := (qExpansion_coeff_zero Δ' one_pos one_mem_strictPeriods_SL).trans (CuspFormClass.zero_at_infty discriminantCuspForm).valueAtInfty_eq_zero - rw [show (ModularForm.mcast _ (f.mul Δ')) = (f : ℍ → ℂ) * Δ' from rfl, qExpansion_mul_coeff_zero + rw [show (ModularForm.mcast _ (f.mul Δ')) = (f : ℍ → ℂ) * Δ' from rfl, + qExpansion_mul_coeff_zero (analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt - (analyticAt_cuspFunction_zero Δ' one_pos one_mem_strictPeriods_SL).continuousAt,hΔ', mul_zero] + (analyticAt_cuspFunction_zero Δ' one_pos one_mem_strictPeriods_SL).continuousAt, + hΔ', mul_zero] @[simp] lemma ofMulDiscriminant_apply (f : ModularForm 𝒮ℒ (k - 12)) (z : ℍ) : @@ -182,10 +186,12 @@ lemma ModularForm.rank_eq_one_add_rank_cuspForm {k : ℕ} (hk : 3 ≤ k) (hk2 : (isCuspForm_iff_coeffZero_eq_zero _).mp h · refine (Submodule.Quotient.mk_surjective _).forall.mpr fun f ↦ ⟨(qExpansion 1 f).coeff 0, ?_⟩ - have h_mem : f - (qExpansion 1 ↑f).coeff 0 • E hk ∈ cuspFormSubmodule 𝒮ℒ (k : ℤ) := by + have h_mem : f - (qExpansion 1 ↑f).coeff 0 • E hk ∈ + cuspFormSubmodule 𝒮ℒ (k : ℤ) := by apply (isCuspForm_iff_coeffZero_eq_zero _).mpr set c := (qExpansion 1 ↑f).coeff 0 with hc - have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := k)).map_sub f (c • E hk) + have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := k)).map_sub f + (c • E hk) simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk] at hsub rw [hsub] simp [qExpansion_smul one_pos one_mem_strictPeriods_SL c (E hk), @@ -228,139 +234,106 @@ private lemma E₆_qExpansion_coeff_one : (qExpansion 1 E₆).coeff 1 = -504 := /-- A modular form whose `valueAtInfty` is `c` tends to `c` along `atImInfty`. -/ private lemma tendsto_valueAtInfty {k : ℤ} (f : ModularForm 𝒮ℒ k) (c : ℂ) - (hv : valueAtInfty f = c) : Filter.Tendsto f atImInfty (𝓝 c) := by + (hv : valueAtInfty f = c) : Tendsto f atImInfty (𝓝 c) := by rw [← hv, ← cuspFunction_apply_zero f one_pos one_mem_strictPeriods_SL] - exact ((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt.tendsto.comp - (qParam_tendsto_atImInfty one_pos)).congr - (fun τ ↦ eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero) + refine (((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt + |>.tendsto.comp (qParam_tendsto_atImInfty one_pos))).congr fun τ ↦ ?_ + exact eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero /-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ private noncomputable def E4_cube_sub_E6_sq_form : ModularForm 𝒮ℒ 12 := - mcast (show 4 + (4 + 4) = 12 by norm_num) (E₄.mul (mcast rfl (E₄.mul E₄))) - - mcast (show 6 + 6 = 12 by norm_num) (E₆.mul E₆) + mcast (by norm_num) ((E₄.mul E₄).mul E₄) - mcast (by norm_num) (E₆.mul E₆) private lemma E4_cube_sub_E6_sq_form_apply (z : ℍ) : E4_cube_sub_E6_sq_form z = E₄ z ^ 3 - E₆ z ^ 2 := by - change E₄ z * (E₄ z * E₄ z) - E₆ z * E₆ z = _; ring + change E₄ z * E₄ z * E₄ z - E₆ z * E₆ z = _; ring private lemma E4_cube_sub_E6_sq_form_isCuspForm : IsCuspForm E4_cube_sub_E6_sq_form := by refine (isCuspForm_iff_coeffZero_eq_zero _).mpr ?_ rw [qExpansion_coeff_zero _ one_pos one_mem_strictPeriods_SL] - have h4 : Filter.Tendsto (E₄ : ℍ → ℂ) atImInfty (𝓝 1) := - tendsto_valueAtInfty E₄ 1 <| by - rw [← qExpansion_coeff_zero E₄ one_pos one_mem_strictPeriods_SL] - exact E_qExpansion_coeff_zero _ ⟨2, rfl⟩ - have h6 : Filter.Tendsto (E₆ : ℍ → ℂ) atImInfty (𝓝 1) := - tendsto_valueAtInfty E₆ 1 <| by - rw [← qExpansion_coeff_zero E₆ one_pos one_mem_strictPeriods_SL] - exact E_qExpansion_coeff_zero _ ⟨3, rfl⟩ - refine ((Filter.Tendsto.congr (fun w ↦ (E4_cube_sub_E6_sq_form_apply w).symm) ?_)).limUnder_eq - simpa using (h4.pow 3).sub (h6.pow 2) + have hE : ∀ {k : ℕ} (hk : 3 ≤ k) (hk2 : Even k), + Tendsto ((E hk : ModularForm 𝒮ℒ k) : ℍ → ℂ) atImInfty (𝓝 1) := fun hk hk2 ↦ + tendsto_valueAtInfty _ 1 <| by + rw [← qExpansion_coeff_zero _ one_pos one_mem_strictPeriods_SL] + exact E_qExpansion_coeff_zero hk hk2 + refine ((Tendsto.congr (fun w ↦ (E4_cube_sub_E6_sq_form_apply w).symm) ?_)).limUnder_eq + simpa using ((hE _ ⟨2, rfl⟩).pow 3).sub ((hE _ ⟨3, rfl⟩).pow 2) private lemma E4_cube_sub_E6_sq_form_qExpansion_coeff_one : (qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ)).coeff 1 = 1728 := by - have hmcast : ∀ {a b : ℤ} (h : a = b) (f : ModularForm 𝒮ℒ a), - qExpansion 1 (mcast h f) = qExpansion 1 (f : ℍ → ℂ) := fun _ _ ↦ rfl - have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := (12 : ℤ))).map_sub - (mcast (by norm_num) (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄)))) - (mcast (by norm_num) (E₆.mul E₆)) - simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk, hmcast] at hsub - rw [show (E4_cube_sub_E6_sq_form) = ((mcast (by norm_num) - (E₄.mul (ModularForm.mcast rfl (E₄.mul E₄))) - mcast (by norm_num) (E₆.mul E₆))) from rfl, - hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ _, hmcast, + have hsub : qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) = + qExpansion 1 ((E₄.mul E₄).mul E₄ : ℍ → ℂ) - + qExpansion 1 (E₆.mul E₆ : ℍ → ℂ) := + qExpansion_sub one_pos one_mem_strictPeriods_SL + (mcast (by norm_num) ((E₄.mul E₄).mul E₄)) (mcast (by norm_num) (E₆.mul E₆)) + rw [hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (E₄.mul E₄) E₄, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] - simp only [map_sub, PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, - Finset.Nat.antidiagonal_zero, Finset.sum_cons, Finset.sum_singleton, - Finset.map_singleton, Function.Embedding.prodMap, Prod.map, - Function.Embedding.coeFn_mk, Nat.succ_eq_add_one, Nat.zero_add, - Function.Embedding.refl_apply, E₄_qExpansion_coeff_one, E₆_qExpansion_coeff_one] - norm_num [E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] + simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, + E₄_qExpansion_coeff_one, E₆_qExpansion_coeff_one, + E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] + ring /-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : discriminant z = (1 / 1728) * (E₄ z ^ 3 - E₆ z ^ 2) := by obtain ⟨g, hg⟩ := E4_cube_sub_E6_sq_form_isCuspForm obtain ⟨c, hc⟩ := cuspForm_twelve_smul_discriminant g + have hgE : (g : ℍ → ℂ) = E4_cube_sub_E6_sq_form := congrArg DFunLike.coe hg have hc_eq : c = 1728 := by - have hgΔ : qExpansion 1 (g : ℍ → ℂ) = c • qExpansion 1 (discriminantCuspForm) := by - conv_lhs => rw [show (g : ℍ → ℂ) = - ((c • discriminantCuspForm : CuspForm 𝒮ℒ 12) : ℍ → ℂ) from - congr_arg DFunLike.coe hc.symm] - exact qExpansion_smul one_pos one_mem_strictPeriods_SL c discriminantCuspForm - have h := congr_arg (·.coeff 1) <| - (show qExpansion 1 (g : ℍ → ℂ) = qExpansion 1 (E4_cube_sub_E6_sq_form) - from congr_arg _ (congr_arg DFunLike.coe hg)).symm.trans hgΔ + have hcΔ : (c • discriminantCuspForm : ℍ → ℂ) = g := congrArg DFunLike.coe hc + have hgΔ := qExpansion_smul one_pos one_mem_strictPeriods_SL c discriminantCuspForm + rw [hcΔ, hgE] at hgΔ + have h := congr_arg (·.coeff 1) hgΔ simpa [PowerSeries.coeff_smul, discriminant_qExpansion_coeff_one, E4_cube_sub_E6_sq_form_qExpansion_coeff_one] using h.symm - have h1728 : (1728 : ℂ) * discriminant z = E₄ z ^ 3 - E₆ z ^ 2 := - calc (1728 : ℂ) * discriminant z - = c * discriminant z := by rw [hc_eq] - _ = (c • discriminantCuspForm) z := rfl - _ = g z := by rw [← hc] - _ = E4_cube_sub_E6_sq_form z := congr_fun (congr_arg DFunLike.coe hg) z - _ = _ := E4_cube_sub_E6_sq_form_apply z + have h1728 : (1728 : ℂ) * discriminant z = E₄ z ^ 3 - E₆ z ^ 2 := by + rw [← hc_eq, show c * discriminant z = (c • discriminantCuspForm) z from rfl, hc, + congr_fun hgE z, E4_cube_sub_E6_sq_form_apply] linear_combination (1 / 1728 : ℂ) * h1728 -/-- Algebraic core of the weight-2 vanishing argument: if `p : PowerSeries ℂ` satisfies -`c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with constant term `1` -and first-order coefficients `240` and `-504`, then `p.coeff 0 = 0`. -/ +/-- Algebraic core of the weight-2 vanishing argument: if `p : PowerSeries ℂ` +satisfies `c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with +constant term `1` and first-order coefficients `240` and `-504`, then `p.coeff 0 = 0`. -/ private lemma coeffZero_eq_zero_of_pow_eq_smul {p p4 p6 : PowerSeries ℂ} {c4 c6 : ℂ} (hp4_0 : p4.coeff 0 = 1) (hp6_0 : p6.coeff 0 = 1) (hp4_1 : p4.coeff 1 = 240) (hp6_1 : p6.coeff 1 = -504) (hqc4 : c4 • p4 = p * p) (hqc6 : c6 • p6 = p * p * p) : p.coeff 0 = 0 := by - have h0_4 : c4 = p.coeff 0 ^ 2 := by - have h := congr_arg (·.coeff 0) hqc4 - simp only [PowerSeries.coeff_smul, smul_eq_mul, PowerSeries.coeff_mul, - Finset.Nat.antidiagonal_zero, Finset.sum_singleton, hp4_0, mul_one] at h - rw [sq]; exact h - have h0_6 : c6 = p.coeff 0 ^ 3 := by - have h := congr_arg (·.coeff 0) hqc6 - simp only [PowerSeries.coeff_smul, smul_eq_mul, PowerSeries.coeff_mul, - Finset.Nat.antidiagonal_zero, Finset.sum_singleton, hp6_0, mul_one] at h - rw [show p.coeff 0 ^ 3 = p.coeff 0 * p.coeff 0 * p.coeff 0 by ring]; exact h - have heq4 : p.coeff 0 ^ 2 * 240 = 2 * p.coeff 0 * p.coeff 1 := by - have h := congr_arg (·.coeff 1) hqc4 - simp only [PowerSeries.coeff_smul, smul_eq_mul, hp4_1] at h - rw [show (p * p).coeff 1 = 2 * p.coeff 0 * p.coeff 1 from by - simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring, h0_4] at h - exact h - have heq6 : p.coeff 0 ^ 3 * (-504) = 3 * p.coeff 0 ^ 2 * p.coeff 1 := by - have h := congr_arg (·.coeff 1) hqc6 - simp only [PowerSeries.coeff_smul, smul_eq_mul, hp6_1] at h - rw [show (p * p * p).coeff 1 = 3 * p.coeff 0 ^ 2 * p.coeff 1 from by - simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ]; ring, h0_6] at h - exact h + have h40 := congr_arg (·.coeff 0) hqc4 + have h41 := congr_arg (·.coeff 1) hqc4 + have h60 := congr_arg (·.coeff 0) hqc6 + have h61 := congr_arg (·.coeff 1) hqc6 + simp only [PowerSeries.coeff_smul, smul_eq_mul, PowerSeries.coeff_mul, + Finset.Nat.antidiagonal_zero, Finset.Nat.antidiagonal_succ, Finset.sum_singleton, + Finset.sum_cons, Finset.map_singleton, Function.Embedding.prodMap, Prod.map, + Function.Embedding.coeFn_mk, Function.Embedding.refl_apply, hp4_0, hp4_1, hp6_0, hp6_1, + mul_one] at h40 h41 h60 h61 refine pow_eq_zero_iff (n := 3) three_ne_zero |>.mp ?_ have h0 : (1728 : ℂ) * p.coeff 0 ^ 3 = 0 := by - linear_combination 3 * p.coeff 0 * heq4 - 2 * heq6 + linear_combination 3 * p.coeff 0 * h41 - 2 * h61 - 720 * p.coeff 0 * h40 - 1008 * h60 exact (mul_eq_zero.mp h0).resolve_left (by norm_num) private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ 2) (hf : ¬IsCuspForm f) : f = 0 := by exfalso - have h0 := Module.rank_eq_one_iff_finrank_eq_one.mp weight_four_rank_one - rw [(finrank_eq_one_iff_of_nonzero' E₄ (E_ne_zero _ ⟨2, rfl⟩ : E₄ ≠ 0))] at h0 - have h1 := Module.rank_eq_one_iff_finrank_eq_one.mp weight_six_rank_one - rw [(finrank_eq_one_iff_of_nonzero' E₆ (E_ne_zero _ ⟨3, rfl⟩ : E₆ ≠ 0))] at h1 - obtain ⟨c4, hc4⟩ := h0 (f.mul f) - obtain ⟨c6, hc6⟩ := h1 ((f.mul f).mul f) + obtain ⟨c4, hc4⟩ := (finrank_eq_one_iff_of_nonzero' E₄ (E_ne_zero _ ⟨2, rfl⟩)).mp + (Module.rank_eq_one_iff_finrank_eq_one.mp weight_four_rank_one) (f.mul f) + obtain ⟨c6, hc6⟩ := (finrank_eq_one_iff_of_nonzero' E₆ (E_ne_zero _ ⟨3, rfl⟩)).mp + (Module.rank_eq_one_iff_finrank_eq_one.mp weight_six_rank_one) ((f.mul f).mul f) have hqc4 : c4 • qExpansion 1 (E₄ : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 f := by - have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄ - rw [show (c4 • E₄ : ℍ → ℂ) = (f.mul f) from - congrArg DFunLike.coe hc4] at hsmul - rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] - exact hsmul.symm + rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f, + ← qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄, + show (c4 • E₄ : ℍ → ℂ) = (f.mul f) from congrArg DFunLike.coe hc4] have hqc6 : c6 • qExpansion 1 E₆ = qExpansion 1 f * qExpansion 1 f * qExpansion 1 f := by - have hsmul := qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆ - have hmul1 := ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (f.mul f) f - rw [show (c6 • E₆ : ℍ → ℂ) = (f.mul f).mul f from congrArg DFunLike.coe hc6] at hsmul - rw [ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f] at hmul1 - simp [← hmul1, hsmul.symm] + rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f, + ← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (f.mul f) f, + ← qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆, + show (c6 • E₆ : ℍ → ℂ) = (f.mul f).mul f from congrArg DFunLike.coe hc6] exact hf <| (isCuspForm_iff_coeffZero_eq_zero f).mpr <| coeffZero_eq_zero_of_pow_eq_smul (E_qExpansion_coeff_zero _ ⟨2, rfl⟩) - (E_qExpansion_coeff_zero _ ⟨3, rfl⟩) E₄_qExpansion_coeff_one E₆_qExpansion_coeff_one hqc4 hqc6 + (E_qExpansion_coeff_zero _ ⟨3, rfl⟩) E₄_qExpansion_coeff_one E₆_qExpansion_coeff_one + hqc4 hqc6 /-- Modular forms of weight 2 for `𝒮ℒ` are zero. -/ theorem ModularForm.levelOne_weight_two_rank_zero : @@ -370,7 +343,8 @@ theorem ModularForm.levelOne_weight_two_rank_zero : by_cases hf : IsCuspForm f · obtain ⟨g, hg⟩ := hf rw [← hg] - simp [rank_zero_iff_forall_zero.mp (cuspForm_rank_lt_twelve (show (2 : ℤ) < 12 by norm_num)) g] + simp [rank_zero_iff_forall_zero.mp + (cuspForm_rank_lt_twelve (show (2 : ℤ) < 12 by norm_num)) g] · exact weight_two_eq_zero_of_not_cuspForm f hf /-- The dimension formula for `𝒮ℒ` modular forms of even weight `k ≥ 3`. -/ diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index ff85b397cc0b17..a570ab86c2b05e 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -177,7 +177,7 @@ lemma discriminant_isZeroAtImInfty : IsZeroAtImInfty Δ := by (discriminant_bounded_factor.congr fun z ↦ by congr 1) /-- The modular discriminant `Δ` as a cusp form of weight 12 and level 1. -/ -def discriminantCuspForm : CuspForm 𝒮ℒ 12 where +@[expose] def discriminantCuspForm : CuspForm 𝒮ℒ 12 where toFun := Δ slash_action_eq' A hA := by obtain ⟨A, rfl⟩ := hA From 8d9031061f15578f43bc70154db2d2b28e1cbe4a Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Mon, 13 Apr 2026 10:24:33 +0100 Subject: [PATCH 18/49] feat(NumberTheory/ModularForms): Coe from CuspForm to ModularForm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `CuspForm.toModularForm` and a `Coe (CuspForm Γ k) (ModularForm Γ k)` instance so cusp forms can be viewed as modular forms automatically. Refactors `CuspForm.toModularFormₗ` to delegate to this plain function and updates call sites. Co-Authored-By: Claude Opus 4.6 (1M context) --- Mathlib/NumberTheory/ModularForms/Basic.lean | 15 ++ .../ModularForms/CuspFormSubmodule.lean | 8 +- .../DimensionFormulas/LevelOne.lean | 191 ++++++++---------- 3 files changed, 104 insertions(+), 110 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index 3100c9f841d33d..9a356680b7c080 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -516,6 +516,21 @@ instance (priority := 99) [FunLike F ℍ ℂ] [CuspFormClass F Γ k] : ModularFo holo := CuspFormClass.holo bdd_at_cusps f _ hc g hg := (CuspFormClass.zero_at_cusps f hc g hg).boundedAtFilter +/-- The underlying modular form of a cusp form. -/ +def toModularForm (f : CuspForm Γ k) : ModularForm Γ k where + toSlashInvariantForm := f.toSlashInvariantForm + holo' := f.holo' + bdd_at_cusps' hc g hg := (f.zero_at_cusps' hc g hg).boundedAtFilter + +@[simp] +lemma toModularForm_apply (f : CuspForm Γ k) (z : ℍ) : (toModularForm f) z = f z := rfl + +/-- A cusp form can be viewed as a modular form. -/ +instance : Coe (CuspForm Γ k) (ModularForm Γ k) := ⟨toModularForm⟩ + +@[simp] +lemma coe_toModularForm (f : CuspForm Γ k) (z : ℍ) : ((f : ModularForm Γ k) : ℍ → ℂ) z = f z := rfl + /-- Transport a cusp form along an equality of subgroups. -/ def ofSubgroupEq {Γ' : Subgroup (GL (Fin 2) ℝ)} (h : Γ = Γ') (f : CuspForm Γ k) : CuspForm Γ' k where diff --git a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean index f717c96303b259..5b7dbde9c17d3f 100644 --- a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean +++ b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean @@ -44,10 +44,7 @@ namespace CuspForm /-- The inclusion of cusp forms into modular forms, as a ℂ-linear map. -/ def toModularFormₗ [Γ.HasDetOne] : CuspForm Γ k →ₗ[ℂ] ModularForm Γ k where - toFun f := - { toSlashInvariantForm := f.toSlashInvariantForm - holo' := f.holo' - bdd_at_cusps' := fun hc g hg ↦ (f.zero_at_cusps' hc g hg).boundedAtFilter } + toFun := toModularForm map_add' _ _ := rfl map_smul' _ _ := rfl @@ -55,6 +52,9 @@ def toModularFormₗ [Γ.HasDetOne] : CuspForm Γ k →ₗ[ℂ] ModularForm Γ k lemma toModularFormₗ_apply [Γ.HasDetOne] (f : CuspForm Γ k) (z : ℍ) : (toModularFormₗ f) z = f z := rfl +lemma toModularFormₗ_eq_coe [Γ.HasDetOne] (f : CuspForm Γ k) : + toModularFormₗ f = (f : ModularForm Γ k) := rfl + lemma toModularFormₗ_injective [Γ.HasDetOne] : Function.Injective (toModularFormₗ : CuspForm Γ k → ModularForm Γ k) := fun _ _ h ↦ DFunLike.ext _ _ fun z ↦ congr_fun (congr_arg DFunLike.coe h) z diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 30e85a8f7b3e8a..fcfd2bb195e0b0 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -42,7 +42,7 @@ namespace CuspForm /-- Multiply a modular form of weight `k - 12` by the discriminant to get a cusp form of weight `k`. Built directly as a CuspForm (no `IsCuspForm` intermediary). -/ def ofMulDiscriminant (f : ModularForm 𝒮ℒ (k - 12)) : CuspForm 𝒮ℒ k := by - let Δ' := CuspForm.toModularFormₗ discriminantCuspForm + let Δ' : ModularForm 𝒮ℒ 12 := discriminantCuspForm apply ModularForm.toCuspForm (ModularForm.mcast (by ring) (f.mul Δ')) have hΔ' : (qExpansion 1 (Δ' : ℍ → ℂ)).coeff 0 = 0 := (qExpansion_coeff_zero Δ' one_pos one_mem_strictPeriods_SL).trans @@ -65,15 +65,12 @@ private lemma divByDiscriminant_slash_eq (f : CuspForm 𝒮ℒ k) (γ : SL(2, CongruenceSubgroup.Gamma_one_coe_eq_SL ▸ inferInstance have hf := slash_action_eqn_SL'' f (mem_Gamma_one γ) have hΔ := slash_action_eqn_SL'' discriminantCuspForm (mem_Gamma_one γ) - ext z - rw [SL_slash_apply, hf, show Δ (γ • z) = denom γ z ^ (12 : ℤ) * Δ z from by - exact_mod_cast hΔ z] - have hd : (denom γ z : ℂ) ≠ 0 := denom_ne_zero γ z - rw [div_mul_eq_mul_div, mul_right_comm, ← zpow_add₀ hd, - show k + -(k - 12) = (12 : ℤ) from by ring] - exact mul_div_mul_left (f z) (Δ z) (zpow_ne_zero _ hd) - -private lemma exp_decay_isBigO_discriminant (f : CuspForm 𝒮ℒ k) : f =O[atImInfty] Δ := by + ext z; rw [SL_slash_apply, hf, show Δ (γ • z) = denom γ z ^ (12 : ℤ) * Δ z from by + exact_mod_cast hΔ z, div_mul_eq_mul_div, mul_right_comm, + ← zpow_add₀ (denom_ne_zero γ z), show k + -(k - 12) = (12 : ℤ) from by ring] + exact mul_div_mul_left (f z) (Δ z) (zpow_ne_zero _ (denom_ne_zero γ z)) + +lemma exp_decay_isBigO_discriminant (f : CuspForm 𝒮ℒ k) : f =O[atImInfty] Δ := by have hf_decay := CuspFormClass.exp_decay_atImInfty (h := 1) f one_pos one_mem_strictPeriods_SL have hΔ_lower : ∀ᶠ τ : ℍ in atImInfty, ‖(fun τ : ℍ ↦ Real.exp (-2 * Real.pi * τ.im / 1)) τ‖ ≤ 2 * ‖Δ τ‖ := by @@ -82,37 +79,30 @@ private lemma exp_decay_isBigO_discriminant (f : CuspForm 𝒮ℒ k) : f =O[atIm filter_upwards [hprod] with τ hτ simp only [div_one] rw [discriminant_eq_q_prod, norm_mul, Real.norm_of_nonneg (Real.exp_pos _).le] - have hq_norm : ‖Function.Periodic.qParam 1 (τ : ℂ)‖ = - Real.exp (-2 * Real.pi * τ.im) := by + have hq_norm : ‖Function.Periodic.qParam 1 (τ : ℂ)‖ = Real.exp (-2 * Real.pi * τ.im) := by simp [Function.Periodic.qParam, Complex.norm_exp, Complex.mul_re, div_one] rw [← hq_norm] have hprod_bound : 1 / 2 ≤ ‖∏' (n : ℕ), (1 - eta_q n τ) ^ 24‖ := by - have hsub : ‖∏' (n : ℕ), (1 - eta_q n τ) ^ 24 - 1‖ < 1 / 2 := by - rwa [Complex.dist_eq] at hτ + have hsub : ‖∏' (n : ℕ), (1 - eta_q n τ) ^ 24 - 1‖ < 1 / 2 := by rwa [Complex.dist_eq] at hτ have h1 := norm_sub_norm_le (1 : ℂ) (∏' (n : ℕ), (1 - eta_q n τ) ^ 24) simp only [norm_one] at h1 linarith [norm_sub_rev (1 : ℂ) (∏' (n : ℕ), (1 - eta_q n τ) ^ 24)] - linarith [norm_nonneg (Function.Periodic.qParam 1 (τ : ℂ)), - mul_le_mul_of_nonneg_left hprod_bound - (norm_nonneg (Function.Periodic.qParam 1 (τ : ℂ)))] + linarith [norm_nonneg (Function.Periodic.qParam 1 (τ : ℂ)), mul_le_mul_of_nonneg_left + hprod_bound (norm_nonneg (Function.Periodic.qParam 1 (τ : ℂ)))] exact hf_decay.trans (Asymptotics.IsBigO.of_bound 2 hΔ_lower) /-- Divide a cusp form by the discriminant to get a modular form of weight `k - 12`. -/ def divDiscriminant (f : CuspForm 𝒮ℒ k) : ModularForm 𝒮ℒ (k - 12) where toFun z := f z / Δ z - slash_action_eq' A hA := by - obtain ⟨γ, rfl⟩ := hA - exact divByDiscriminant_slash_eq f γ + slash_action_eq' _ hA := by obtain ⟨γ, rfl⟩ := hA; exact divByDiscriminant_slash_eq f γ holo' := by rw [UpperHalfPlane.mdifferentiable_iff] - refine (UpperHalfPlane.mdifferentiable_iff.mp f.holo').div - (UpperHalfPlane.mdifferentiable_iff.mp discriminantCuspForm.holo') fun z hz ↦ ?_ - simpa [ofComplex_apply_of_im_pos hz] using discriminant_ne_zero ⟨z, hz⟩ + exact (UpperHalfPlane.mdifferentiable_iff.mp f.holo').div + (UpperHalfPlane.mdifferentiable_iff.mp discriminantCuspForm.holo') fun z hz ↦ by + simpa [ofComplex_apply_of_im_pos hz] using discriminant_ne_zero ⟨z, hz⟩ bdd_at_cusps' {c} hc := by - rw [Subgroup.IsArithmetic.isCusp_iff_isCusp_SL2Z] at hc - rw [isBoundedAt_iff_forall_SL2Z hc] - intro γ _ - rw [divByDiscriminant_slash_eq f γ, IsBoundedAtImInfty, BoundedAtFilter] + rw [Subgroup.IsArithmetic.isCusp_iff_isCusp_SL2Z] at hc; rw [isBoundedAt_iff_forall_SL2Z hc] + intro γ _; rw [divByDiscriminant_slash_eq f γ, IsBoundedAtImInfty, BoundedAtFilter] exact (Asymptotics.div_isBoundedUnder_of_isBigO (exp_decay_isBigO_discriminant f)).isBigO_one ℝ @@ -127,14 +117,8 @@ def discriminantEquiv : CuspForm 𝒮ℒ k ≃ₗ[ℂ] ModularForm 𝒮ℒ (k - map_add' a b := by ext z; simp [add_div] map_smul' c a := by ext z; simp [mul_div_assoc] invFun := ofMulDiscriminant - left_inv f := by - ext z - simp only [divDiscriminant_apply, ofMulDiscriminant_apply] - exact div_mul_cancel₀ (f z) (discriminant_ne_zero z) - right_inv f := by - ext z - simp only [ofMulDiscriminant_apply, divDiscriminant_apply] - exact mul_div_cancel_right₀ (f z) (discriminant_ne_zero z) + left_inv f := by ext z; simpa using div_mul_cancel₀ (f z) (discriminant_ne_zero z) + right_inv f := by ext z; simpa using mul_div_cancel_right₀ (f z) (discriminant_ne_zero z) end CuspForm @@ -159,49 +143,38 @@ lemma cuspForm_rank_twelve : Module.rank ℂ (CuspForm 𝒮ℒ 12) = 1 := by /-- Every weight 12 cusp form for `𝒮ℒ` is a scalar multiple of the discriminant. -/ lemma cuspForm_twelve_smul_discriminant (f : CuspForm 𝒮ℒ 12) : - ∃ c : ℂ, c • discriminantCuspForm = f := by - have hne : discriminantCuspForm ≠ 0 := fun h ↦ - discriminant_ne_zero UpperHalfPlane.I (congr_fun (congr_arg DFunLike.coe h) _) - exact (finrank_eq_one_iff_of_nonzero' discriminantCuspForm hne).mp + ∃ c : ℂ, c • discriminantCuspForm = f := + (finrank_eq_one_iff_of_nonzero' discriminantCuspForm (fun h ↦ + discriminant_ne_zero UpperHalfPlane.I (congr_fun (congr_arg DFunLike.coe h) _))).mp (Module.rank_eq_one_iff_finrank_eq_one.mp cuspForm_rank_twelve) f /-- For even `k ≥ 3`, the rank of `𝒮ℒ` modular forms is one more than the rank of cusp forms. -/ lemma ModularForm.rank_eq_one_add_rank_cuspForm {k : ℕ} (hk : 3 ≤ k) (hk2 : Even k) : - Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ)) = - 1 + Module.rank ℂ (CuspForm 𝒮ℒ (k : ℤ)) := by - have h_add := Submodule.rank_quotient_add_rank (cuspFormSubmodule 𝒮ℒ (k : ℤ)) - rw [show Module.rank ℂ ↥(cuspFormSubmodule 𝒮ℒ (k : ℤ)) = - Module.rank ℂ (CuspForm 𝒮ℒ (k : ℤ)) from - (LinearEquiv.rank_eq (CuspForm.equivCuspFormSubmodule 𝒮ℒ (k : ℤ))).symm] at h_add - suffices h1 : Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ) ⧸ - cuspFormSubmodule 𝒮ℒ (k : ℤ)) = 1 by + Module.rank ℂ (ModularForm 𝒮ℒ k) = 1 + Module.rank ℂ (CuspForm 𝒮ℒ k) := by + have h_add := Submodule.rank_quotient_add_rank (cuspFormSubmodule 𝒮ℒ k) + rw [show Module.rank ℂ ↥(cuspFormSubmodule 𝒮ℒ k) = Module.rank ℂ (CuspForm 𝒮ℒ k) from + (LinearEquiv.rank_eq (CuspForm.equivCuspFormSubmodule 𝒮ℒ k)).symm] at h_add + suffices h1 : Module.rank ℂ (ModularForm 𝒮ℒ k ⧸ cuspFormSubmodule 𝒮ℒ k) = 1 by rw [← h_add, h1] - have hE_coeff_zero := E_qExpansion_coeff_zero hk hk2 - apply rank_eq_one (Submodule.Quotient.mk (p := cuspFormSubmodule 𝒮ℒ (k : ℤ)) (E hk)) + have hE := E_qExpansion_coeff_zero hk hk2 + apply rank_eq_one (Submodule.Quotient.mk (p := cuspFormSubmodule 𝒮ℒ k) (E hk)) · intro h rw [Submodule.Quotient.mk_eq_zero] at h - exact one_ne_zero <| - hE_coeff_zero.symm.trans <| - (isCuspForm_iff_coeffZero_eq_zero _).mp h + exact one_ne_zero <| hE.symm.trans <| (isCuspForm_iff_coeffZero_eq_zero _).mp h · refine (Submodule.Quotient.mk_surjective _).forall.mpr fun f ↦ ⟨(qExpansion 1 f).coeff 0, ?_⟩ - have h_mem : f - (qExpansion 1 ↑f).coeff 0 • E hk ∈ - cuspFormSubmodule 𝒮ℒ (k : ℤ) := by + have h_mem : f - (qExpansion 1 ↑f).coeff 0 • E hk ∈ cuspFormSubmodule 𝒮ℒ k := by apply (isCuspForm_iff_coeffZero_eq_zero _).mpr set c := (qExpansion 1 ↑f).coeff 0 with hc - have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := k)).map_sub f - (c • E hk) + have hsub := (qExpansionAddHom one_pos one_mem_strictPeriods_SL (k := k)).map_sub f (c • E hk) simp only [qExpansionAddHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk] at hsub - rw [hsub] - simp [qExpansion_smul one_pos one_mem_strictPeriods_SL c (E hk), - _root_.map_sub, _root_.map_smul, hE_coeff_zero, mul_one, ← hc] - have h0 : ((cuspFormSubmodule 𝒮ℒ (k : ℤ)).mkQ (f - (qExpansion 1 ↑f).coeff 0 • - E hk) : ModularForm 𝒮ℒ (k : ℤ) ⧸ cuspFormSubmodule 𝒮ℒ (k : ℤ)) = 0 := + rw [hsub]; simp [qExpansion_smul one_pos one_mem_strictPeriods_SL c (E hk), + _root_.map_sub, _root_.map_smul, hE, mul_one, ← hc] + have h0 : (cuspFormSubmodule 𝒮ℒ k).mkQ (f - (qExpansion 1 ↑f).coeff 0 • E hk) = 0 := (Submodule.Quotient.mk_eq_zero _).mpr h_mem - rw [map_sub, LinearMap.map_smul, Submodule.mkQ_apply, Submodule.mkQ_apply, - sub_eq_zero] at h0 - exact h0.symm + rwa [map_sub, LinearMap.map_smul, Submodule.mkQ_apply, Submodule.mkQ_apply, + sub_eq_zero, eq_comm] at h0 end RankIdentity @@ -210,12 +183,12 @@ end RankIdentity section DimensionFormula /-- Weight 4 modular forms for `𝒮ℒ` are 1-dimensional. -/ -private lemma weight_four_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ (4 : ℤ)) = 1 := +private lemma weight_four_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ 4) = 1 := (rank_eq_one_add_rank_cuspForm (by norm_num) ⟨2, rfl⟩).trans ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (by norm_num))).trans (by norm_cast)) /-- Weight 6 modular forms for `𝒮ℒ` are 1-dimensional. -/ -private lemma weight_six_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ (6 : ℤ)) = 1 := +private lemma weight_six_rank_one : Module.rank ℂ (ModularForm 𝒮ℒ 6) = 1 := (rank_eq_one_add_rank_cuspForm (by norm_num) ⟨3, rfl⟩).trans ((congrArg (1 + ·) (cuspForm_rank_lt_twelve (by norm_num))).trans (by norm_cast)) @@ -236,9 +209,9 @@ private lemma E₆_qExpansion_coeff_one : (qExpansion 1 E₆).coeff 1 = -504 := private lemma tendsto_valueAtInfty {k : ℤ} (f : ModularForm 𝒮ℒ k) (c : ℂ) (hv : valueAtInfty f = c) : Tendsto f atImInfty (𝓝 c) := by rw [← hv, ← cuspFunction_apply_zero f one_pos one_mem_strictPeriods_SL] - refine (((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt - |>.tendsto.comp (qParam_tendsto_atImInfty one_pos))).congr fun τ ↦ ?_ - exact eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero + exact ((analyticAt_cuspFunction_zero f one_pos one_mem_strictPeriods_SL).continuousAt + |>.tendsto.comp (qParam_tendsto_atImInfty one_pos)).congr + fun τ ↦ eq_cuspFunction f τ one_mem_strictPeriods_SL one_ne_zero /-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ private noncomputable def E4_cube_sub_E6_sq_form : ModularForm 𝒮ℒ 12 := @@ -256,22 +229,20 @@ private lemma E4_cube_sub_E6_sq_form_isCuspForm : IsCuspForm E4_cube_sub_E6_sq_f tendsto_valueAtInfty _ 1 <| by rw [← qExpansion_coeff_zero _ one_pos one_mem_strictPeriods_SL] exact E_qExpansion_coeff_zero hk hk2 - refine ((Tendsto.congr (fun w ↦ (E4_cube_sub_E6_sq_form_apply w).symm) ?_)).limUnder_eq - simpa using ((hE _ ⟨2, rfl⟩).pow 3).sub ((hE _ ⟨3, rfl⟩).pow 2) + exact (Tendsto.congr (fun w ↦ (E4_cube_sub_E6_sq_form_apply w).symm) + (by simpa using ((hE _ ⟨2, rfl⟩).pow 3).sub ((hE _ ⟨3, rfl⟩).pow 2))).limUnder_eq private lemma E4_cube_sub_E6_sq_form_qExpansion_coeff_one : (qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ)).coeff 1 = 1728 := by have hsub : qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) = - qExpansion 1 ((E₄.mul E₄).mul E₄ : ℍ → ℂ) - - qExpansion 1 (E₆.mul E₆ : ℍ → ℂ) := - qExpansion_sub one_pos one_mem_strictPeriods_SL - (mcast (by norm_num) ((E₄.mul E₄).mul E₄)) (mcast (by norm_num) (E₆.mul E₆)) + qExpansion 1 ((E₄.mul E₄).mul E₄ : ℍ → ℂ) - qExpansion 1 (E₆.mul E₆ : ℍ → ℂ) := + qExpansion_sub one_pos one_mem_strictPeriods_SL (mcast (by norm_num) ((E₄.mul E₄).mul E₄)) + (mcast (by norm_num) (E₆.mul E₆)) rw [hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (E₄.mul E₄) E₄, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] - simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, - E₄_qExpansion_coeff_one, E₆_qExpansion_coeff_one, - E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] + simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, E₄_qExpansion_coeff_one, + E₆_qExpansion_coeff_one, E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] ring /-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ @@ -292,13 +263,30 @@ theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : congr_fun hgE z, E4_cube_sub_E6_sq_form_apply] linear_combination (1 / 1728 : ℂ) * h1728 +/-- The modular discriminant equals `(E₄³ - E₆²) / 1728` in the graded ring +`⨁ k, ModularForm 𝒮ℒ k`. -/ +theorem ModularForm.discriminant_eq_E4_cube_sub_E6_sq_in_graded_ring : + DirectSum.of (ModularForm 𝒮ℒ) 12 (discriminantCuspForm : ModularForm 𝒮ℒ 12) = + (1 / 1728 : ℂ) • (DirectSum.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 - + DirectSum.of (ModularForm 𝒮ℒ) 6 E₆ ^ 2) := by + have hE4 : DirectSum.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 = + DirectSum.of (ModularForm 𝒮ℒ) 12 (mcast (by norm_num) ((E₄.mul E₄).mul E₄)) := by + rw [pow_succ (n := 2), pow_two, DirectSum.of_mul_of, DirectSum.of_mul_of]; rfl + have hE6 : DirectSum.of (ModularForm 𝒮ℒ) 6 E₆ ^ 2 = + DirectSum.of (ModularForm 𝒮ℒ) 12 (mcast (by norm_num) (E₆.mul E₆)) := by + rw [pow_two, DirectSum.of_mul_of]; rfl + rw [hE4, hE6, ← map_sub (DirectSum.of (ModularForm 𝒮ℒ) 12), ← DirectSum.of_smul] + congr 1; ext z + change discriminant z = (1 / 1728 : ℂ) * (E₄ z * E₄ z * E₄ z - E₆ z * E₆ z) + rw [discriminant_eq_E4_cube_sub_E6_sq z]; ring + /-- Algebraic core of the weight-2 vanishing argument: if `p : PowerSeries ℂ` satisfies `c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with constant term `1` and first-order coefficients `240` and `-504`, then `p.coeff 0 = 0`. -/ private lemma coeffZero_eq_zero_of_pow_eq_smul {p p4 p6 : PowerSeries ℂ} {c4 c6 : ℂ} - (hp4_0 : p4.coeff 0 = 1) (hp6_0 : p6.coeff 0 = 1) - (hp4_1 : p4.coeff 1 = 240) (hp6_1 : p6.coeff 1 = -504) - (hqc4 : c4 • p4 = p * p) (hqc6 : c6 • p6 = p * p * p) : p.coeff 0 = 0 := by + (hp4_0 : p4.coeff 0 = 1) (hp6_0 : p6.coeff 0 = 1) (hp4_1 : p4.coeff 1 = 240) + (hp6_1 : p6.coeff 1 = -504) (hqc4 : c4 • p4 = p * p) + (hqc6 : c6 • p6 = p * p * p) : p.coeff 0 = 0 := by have h40 := congr_arg (·.coeff 0) hqc4 have h41 := congr_arg (·.coeff 1) hqc4 have h60 := congr_arg (·.coeff 0) hqc6 @@ -313,15 +301,14 @@ private lemma coeffZero_eq_zero_of_pow_eq_smul {p p4 p6 : PowerSeries ℂ} {c4 c linear_combination 3 * p.coeff 0 * h41 - 2 * h61 - 720 * p.coeff 0 * h40 - 1008 * h60 exact (mul_eq_zero.mp h0).resolve_left (by norm_num) -private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ 2) - (hf : ¬IsCuspForm f) : f = 0 := by +private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ 2) (hf : ¬IsCuspForm f) : + f = 0 := by exfalso obtain ⟨c4, hc4⟩ := (finrank_eq_one_iff_of_nonzero' E₄ (E_ne_zero _ ⟨2, rfl⟩)).mp (Module.rank_eq_one_iff_finrank_eq_one.mp weight_four_rank_one) (f.mul f) obtain ⟨c6, hc6⟩ := (finrank_eq_one_iff_of_nonzero' E₆ (E_ne_zero _ ⟨3, rfl⟩)).mp (Module.rank_eq_one_iff_finrank_eq_one.mp weight_six_rank_one) ((f.mul f).mul f) - have hqc4 : c4 • qExpansion 1 (E₄ : ℍ → ℂ) = - qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 f := by + have hqc4 : c4 • qExpansion 1 (E₄ : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) * qExpansion 1 f := by rw [← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f, ← qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄, show (c4 • E₄ : ℍ → ℂ) = (f.mul f) from congrArg DFunLike.coe hc4] @@ -337,46 +324,38 @@ private lemma weight_two_eq_zero_of_not_cuspForm (f : ModularForm 𝒮ℒ 2) /-- Modular forms of weight 2 for `𝒮ℒ` are zero. -/ theorem ModularForm.levelOne_weight_two_rank_zero : - Module.rank ℂ (ModularForm 𝒮ℒ (2 : ℤ)) = 0 := by - rw [rank_zero_iff_forall_zero] - intro f + Module.rank ℂ (ModularForm 𝒮ℒ 2) = 0 := by + rw [rank_zero_iff_forall_zero]; intro f by_cases hf : IsCuspForm f - · obtain ⟨g, hg⟩ := hf - rw [← hg] - simp [rank_zero_iff_forall_zero.mp - (cuspForm_rank_lt_twelve (show (2 : ℤ) < 12 by norm_num)) g] + · obtain ⟨g, hg⟩ := hf; rw [← hg] + simp [rank_zero_iff_forall_zero.mp (cuspForm_rank_lt_twelve (by norm_num)) g] · exact weight_two_eq_zero_of_not_cuspForm f hf /-- The dimension formula for `𝒮ℒ` modular forms of even weight `k ≥ 3`. -/ theorem ModularForm.dimension_level_one (k : ℕ) (hk : 3 ≤ (k : ℤ)) (hk2 : Even k) : - Module.rank ℂ (ModularForm 𝒮ℒ (k : ℤ)) = - if 12 ∣ ((k : ℤ) - 2) then Nat.floor ((k : ℚ) / 12) + Module.rank ℂ (ModularForm 𝒮ℒ k) = if 12 ∣ ((k : ℤ) - 2) then Nat.floor ((k : ℚ) / 12) else Nat.floor ((k : ℚ) / 12) + 1 := by induction k using Nat.strong_induction_on with | h k ihn => rw [rank_eq_one_add_rank_cuspForm (by omega) hk2, LinearEquiv.rank_eq CuspForm.discriminantEquiv] - by_cases HK : (3 : ℤ) ≤ ((k : ℤ) - 12) + by_cases HK : (3 : ℤ) ≤ (k : ℤ) - 12 · have iH := ihn (k - 12) (by omega) (by omega) ((Nat.even_sub (by omega)).mpr (by simp only [hk2, true_iff]; decide)) - have hk12 : (((k - 12) : ℕ) : ℤ) = k - 12 := by - norm_cast; exact Eq.symm (Int.subNatNat_of_le (by omega)) + have hk12 : (((k - 12) : ℕ) : ℤ) = k - 12 := by grind rw [hk12] at iH rw [iH, show ((k - 12 : ℕ) : ℚ) = (k : ℚ) - 12 from by norm_cast] - have hfl (hk' : (12 : ℚ) ≤ k) : - ⌊(k : ℚ) / 12⌋₊ = 1 + ⌊((k : ℚ) - 12) / 12⌋₊ := + have hfl (hk' : (12 : ℚ) ≤ k) : ⌊(k : ℚ) / 12⌋₊ = 1 + ⌊((k : ℚ) - 12) / 12⌋₊ := Nat.floor_div_eq_one_add_floor_sub_div (k : ℚ) 12 (by norm_num) hk' - by_cases h12 : 12 ∣ ((k) : ℤ) - 2 - · simp only [show 12 ∣ (k : ℤ) - 12 - 2 from by omega, ↓reduceIte, h12] - norm_cast at * + by_cases h12 : 12 ∣ (k : ℤ) - 2 + · simp only [show 12 ∣ (k : ℤ) - 12 - 2 from by omega, ↓reduceIte, h12]; norm_cast at * rw [hfl (by exact_mod_cast (by omega : (12 : ℤ) ≤ k))] · simp only [show ¬ 12 ∣ (k : ℤ) - 12 - 2 from by omega, ↓reduceIte, h12, - Nat.cast_add, Nat.cast_one] - norm_cast at * + Nat.cast_add, Nat.cast_one]; norm_cast at * rw [← add_assoc, ← hfl (by exact_mod_cast (by omega : (12 : ℤ) ≤ k))] · simp only [not_le] at HK have hkop : k ∈ Finset.filter Even (Finset.Icc 3 14) := by simp only [Finset.mem_filter, Finset.mem_Icc, hk2, and_true]; omega - rw [show Finset.filter Even (Finset.Icc 3 14) = ({4, 6, 8, 10, 12, 14} : Finset ℕ) - from by decide] at hkop + rw [show Finset.filter Even (Finset.Icc 3 14) = ({4, 6, 8, 10, 12, 14} : Finset ℕ) from by + decide] at hkop fin_cases hkop <;> simp only [Nat.cast_ofNat, Int.reduceSub, Int.reduceNeg] at * all_goals first | exact (congrArg (1 + ·) (levelOne_neg_weight_rank_zero (by omega))).trans (by norm_cast) From 43c4faed12cd741a4c5dbee9f2952271aa4f0e43 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Mon, 13 Apr 2026 10:58:47 +0100 Subject: [PATCH 19/49] chore: run mk_all to fix Mathlib.lean import order Co-Authored-By: Claude Opus 4.6 (1M context) --- Mathlib.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib.lean b/Mathlib.lean index 2c55ac3de481c2..99802f82937a45 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5589,6 +5589,7 @@ public import Mathlib.NumberTheory.ModularForms.Cusps public import Mathlib.NumberTheory.ModularForms.DedekindEta public import Mathlib.NumberTheory.ModularForms.Delta public import Mathlib.NumberTheory.ModularForms.Derivative +public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.LevelOne public import Mathlib.NumberTheory.ModularForms.Discriminant public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Basic public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Defs @@ -5607,7 +5608,6 @@ public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Manifold public import Mathlib.NumberTheory.ModularForms.JacobiTheta.OneVariable public import Mathlib.NumberTheory.ModularForms.JacobiTheta.TwoVariable public import Mathlib.NumberTheory.ModularForms.LevelOne -public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.LevelOne public import Mathlib.NumberTheory.ModularForms.NormTrace public import Mathlib.NumberTheory.ModularForms.Petersson public import Mathlib.NumberTheory.ModularForms.QExpansion From f91e8daf2061d88d325ff4fe721f15baea3d921b Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Mon, 13 Apr 2026 11:26:41 +0100 Subject: [PATCH 20/49] feat(NumberTheory/ModularForms): CuspFormClass instance for cuspFormSubmodule Co-Authored-By: Claude Opus 4.6 (1M context) --- Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean index 5b7dbde9c17d3f..86faed2b8a72fa 100644 --- a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean +++ b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean @@ -85,6 +85,15 @@ lemma isCuspForm_iff [Γ.HasDetOne] (f : ModularForm Γ k) : refine ⟨fun ⟨g, hg⟩ c hc ↦ hg ▸ g.zero_at_cusps' hc, fun h ↦ ⟨⟨f.toSlashInvariantForm, f.holo', h⟩, rfl⟩⟩ +instance [Γ.HasDetOne] : FunLike (cuspFormSubmodule Γ k) ℍ ℂ where + coe f := (f : ModularForm Γ k) + coe_injective' _ _ h := Subtype.ext (DFunLike.ext _ _ (congr_fun h)) + +instance [Γ.HasDetOne] : CuspFormClass (cuspFormSubmodule Γ k) Γ k where + slash_action_eq f := (f : ModularForm Γ k).slash_action_eq' + holo f := (f : ModularForm Γ k).holo' + zero_at_cusps f := (isCuspForm_iff f.1).mp f.2 + section SL2Z open EisensteinSeries From b5f280eba93b610f8e2cb370d44e4b1f1a0941af Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 1 May 2026 11:30:10 +0100 Subject: [PATCH 21/49] =?UTF-8?q?feat(NumberTheory/ModularForms):=20restor?= =?UTF-8?q?e=20=CE=94=20=3D=20(E=E2=82=84=C2=B3=20-=20E=E2=82=86=C2=B2)=20?= =?UTF-8?q?/=201728?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restores ModularForm.discriminant_eq_E4_cube_sub_E6_sq, ported from earlier work (commit 8d9031061f1) and updated to current master's API: - discriminantCuspForm → CuspForm.discriminant - cuspForm_twelve_smul_discriminant → CuspForm.exists_smul_discriminant_of_weight_eq_twelve - qExpansion_sub/qExpansion_smul → ModularFormClass.qExpansion_sub/qExpansion_smul - The `IsCuspForm` proof uses an algebraic q-expansion split rather than the no-longer-available tendsto_valueAtInfty. Adds supporting lemmas in Discriminant.lean: - discriminant_cuspFunction_eqOn (private) - differentiableWithinAt_eta_prod_pow (private; shorter than original since differentiableOn_tprod_one_sub_pow_pow is now in mathlib) - discriminant_qExpansion_coeff_one Also drops merge-induced duplicates of master lemmas (summable_eta_q, multipliableLocallyUniformlyOn_eta, differentiableOn_tprod_one_sub_pow, differentiableOn_tprod_one_sub_pow_pow, one_mem_strictPeriods_SL) and removes two unused/duplicating helpers (floor_div_eq_one_add_floor_sub_div, which is too specific for a top-level file and unused, and ModularForm.ofSubgroupEq, which duplicates mcast). --- Mathlib/Algebra/Order/Floor/Semifield.lean | 5 -- Mathlib/NumberTheory/ModularForms/Basic.lean | 12 ---- .../ModularForms/DedekindEta.lean | 29 --------- .../DimensionFormulas/LevelOne.lean | 59 +++++++++++++++++++ .../ModularForms/Discriminant.lean | 44 ++++++++++++++ .../NumberTheory/ModularForms/LevelOne.lean | 3 - 6 files changed, 103 insertions(+), 49 deletions(-) diff --git a/Mathlib/Algebra/Order/Floor/Semifield.lean b/Mathlib/Algebra/Order/Floor/Semifield.lean index 43af3f6b88c848..e3bdf9a4329851 100644 --- a/Mathlib/Algebra/Order/Floor/Semifield.lean +++ b/Mathlib/Algebra/Order/Floor/Semifield.lean @@ -53,11 +53,6 @@ end LinearOrderedSemifield section LinearOrderedField variable [Field K] [LinearOrder K] [IsOrderedRing K] [FloorSemiring K] {a b : K} -theorem floor_div_eq_one_add_floor_sub_div (k a : K) (ha : 0 < a) (hak : a ≤ k) : - ⌊k / a⌋₊ = 1 + ⌊(k - a) / a⌋₊ := by - rw [sub_div, div_self ha.ne', Nat.floor_sub_one] - exact (Nat.add_sub_cancel' (Nat.le_floor (mod_cast (one_le_div₀ ha).mpr hak))).symm - lemma mul_lt_floor (hb₀ : 0 < b) (hb : b < 1) (hba : ⌈b / (1 - b)⌉₊ ≤ a) : b * a < ⌊a⌋₊ := by calc b * a < b * (⌊a⌋₊ + 1) := by gcongr; apply lt_floor_add_one diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index 9ef354b962b0d6..cfb4abba9ed314 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -395,18 +395,6 @@ lemma coe_intCast [Γ.HasDetPlusMinusOne] (z : ℤ) : lemma toSlashInvariantForm_intCast [Γ.HasDetPlusMinusOne] (z : ℤ) : (z : ModularForm Γ 0).toSlashInvariantForm = z := rfl -/-- Transport a modular form along an equality of subgroups. -/ -def ofSubgroupEq {Γ' : Subgroup (GL (Fin 2) ℝ)} (h : Γ = Γ') (f : ModularForm Γ k) : - ModularForm Γ' k where - toFun := f - slash_action_eq' A hA := f.slash_action_eq' A (h ▸ hA) - holo' := f.holo' - bdd_at_cusps' hc := f.bdd_at_cusps' (h ▸ hc) - -@[simp] -lemma ofSubgroupEq_apply {Γ' : Subgroup (GL (Fin 2) ℝ)} (h : Γ = Γ') (f : ModularForm Γ k) - (z : ℍ) : (f.ofSubgroupEq h) z = f z := rfl - end ModularForm namespace CuspForm diff --git a/Mathlib/NumberTheory/ModularForms/DedekindEta.lean b/Mathlib/NumberTheory/ModularForms/DedekindEta.lean index 0a0107a7debfb9..b8b69cf7e4c144 100644 --- a/Mathlib/NumberTheory/ModularForms/DedekindEta.lean +++ b/Mathlib/NumberTheory/ModularForms/DedekindEta.lean @@ -108,35 +108,6 @@ lemma multipliableLocallyUniformlyOn_eta : multipliableLocallyUniformlyOn_one_sub_pow.comp (𝕢 1) (fun z hz ↦ by simpa using norm_qParam_lt_one 1 ⟨z, hz⟩) (by fun_prop) -/-- The infinite product `q ↦ ∏' n, (1 - q^(n+1))` is differentiable on the open unit disc. -/ -lemma differentiableOn_tprod_one_sub_pow : - DifferentiableOn ℂ (fun q ↦ ∏' n, (1 - q ^ (n + 1))) (Metric.ball (0 : ℂ) 1) := by - apply multipliableLocallyUniformlyOn_one_sub_pow.hasProdLocallyUniformlyOn.differentiableOn - ?_ Metric.isOpen_ball - filter_upwards with n - simpa [Finset.prod_fn] using DifferentiableOn.finset_prod (fun _ _ ↦ by fun_prop) - -/-- For any `k`, the function `q ↦ ∏' n, (1 - q^(n+1))^k` is differentiable on the -open unit disc. -/ -lemma differentiableOn_tprod_one_sub_pow_pow (k : ℕ) : - DifferentiableOn ℂ (fun q ↦ ∏' n, (1 - q ^ (n + 1)) ^ k) (Metric.ball (0 : ℂ) 1) := by - refine (differentiableOn_tprod_one_sub_pow.fun_pow k).congr fun q hq ↦ ?_ - have hq_lt : ‖q‖ < 1 := by simpa [Metric.mem_ball, dist_zero_right] using hq - exact (multipliable_one_sub_pow hq_lt).tprod_pow k - -theorem summable_eta_q (z : ℍ) : Summable fun n ↦ ‖-eta_q n z‖ := by - have hq : ‖(𝕢 (1 : ℝ) ↑z : ℂ)‖ < 1 := by exact_mod_cast norm_qParam_lt_one 1 z - simpa only [norm_neg, eta_q, norm_pow] using - (summable_nat_add_iff 1).mpr (summable_geometric_of_lt_one (norm_nonneg _) hq) - -lemma multipliableLocallyUniformlyOn_eta : - MultipliableLocallyUniformlyOn (fun n a ↦ 1 - eta_q n a) ℍₒ := - ⟨_, (multipliableLocallyUniformlyOn_one_sub_pow.hasProdLocallyUniformlyOn : - TendstoLocallyUniformlyOn _ _ _ _).comp (Periodic.qParam 1) - (fun z hz ↦ by simpa [Metric.mem_ball, dist_zero_right] using - (by exact_mod_cast norm_qParam_lt_one 1 ⟨z, hz⟩ : ‖(𝕢 (1 : ℝ) z : ℂ)‖ < 1)) - (by fun_prop)⟩ - lemma eta_tprod_ne_zero {z : ℂ} (hz : z ∈ ℍₒ) : ∏' n, (1 - eta_q n z) ≠ 0 := by refine tprod_one_add_ne_zero_of_summable (f := fun n ↦ -eta_q n z) ?_ ?_ · exact fun i ↦ by simpa using one_sub_eta_q_ne_zero i hz diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 0ddf7a000f7e55..83083c0afe4ccb 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -163,6 +163,65 @@ lemma E₄_qExpansion_coeff_one : (qExpansion 1 E₄).coeff 1 = 240 := by lemma E₆_qExpansion_coeff_one : (qExpansion 1 E₆).coeff 1 = -504 := by norm_num [E_qExpansion_coeff _ ⟨3, rfl⟩, show bernoulli 6 = 1 / 42 by decide +kernel] +/-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ +private noncomputable def E4_cube_sub_E6_sq_form : ModularForm 𝒮ℒ 12 := + ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄) - + ModularForm.mcast (by norm_num) (E₆.mul E₆) + +private lemma E4_cube_sub_E6_sq_form_apply (z : ℍ) : + E4_cube_sub_E6_sq_form z = E₄ z ^ 3 - E₆ z ^ 2 := by + change E₄ z * E₄ z * E₄ z - E₆ z * E₆ z = _ + ring + +private lemma E4_cube_sub_E6_sq_form_isCuspForm : IsCuspForm E4_cube_sub_E6_sq_form := by + refine (isCuspForm_iff_coeffZero_eq_zero _).mpr ?_ + have hsub : qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) = + qExpansion 1 ((E₄.mul E₄).mul E₄ : ℍ → ℂ) - qExpansion 1 (E₆.mul E₆ : ℍ → ℂ) := + ModularFormClass.qExpansion_sub one_pos one_mem_strictPeriods_SL + (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) + (ModularForm.mcast (by norm_num) (E₆.mul E₆)) + rw [hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (E₄.mul E₄) E₄, + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] + have h4 := E_qExpansion_coeff_zero (show (3 : ℕ) ≤ 4 by norm_num) ⟨2, rfl⟩ + have h6 := E_qExpansion_coeff_zero (show (3 : ℕ) ≤ 6 by norm_num) ⟨3, rfl⟩ + rw [PowerSeries.coeff_zero_eq_constantCoeff] at h4 h6 ⊢ + simp [h4, h6] + +private lemma E4_cube_sub_E6_sq_form_qExpansion_coeff_one : + (qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ)).coeff 1 = 1728 := by + have hsub : qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) = + qExpansion 1 ((E₄.mul E₄).mul E₄ : ℍ → ℂ) - qExpansion 1 (E₆.mul E₆ : ℍ → ℂ) := + ModularFormClass.qExpansion_sub one_pos one_mem_strictPeriods_SL + (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) + (ModularForm.mcast (by norm_num) (E₆.mul E₆)) + rw [hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (E₄.mul E₄) E₄, + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] + simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, E₄_qExpansion_coeff_one, + E₆_qExpansion_coeff_one, E_qExpansion_coeff_zero _ ⟨2, rfl⟩, + E_qExpansion_coeff_zero _ ⟨3, rfl⟩] + ring + +/-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ +theorem discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : + discriminant z = (1 / 1728) * (E₄ z ^ 3 - E₆ z ^ 2) := by + obtain ⟨g, hg⟩ := E4_cube_sub_E6_sq_form_isCuspForm + obtain ⟨c, hc⟩ := CuspForm.exists_smul_discriminant_of_weight_eq_twelve g + have hgE : (g : ℍ → ℂ) = E4_cube_sub_E6_sq_form := congrArg DFunLike.coe hg + have hc_eq : c = 1728 := by + have hcΔ : (c • CuspForm.discriminant : ℍ → ℂ) = g := congrArg DFunLike.coe hc + have hgΔ := ModularFormClass.qExpansion_smul one_pos one_mem_strictPeriods_SL c + CuspForm.discriminant + rw [hcΔ, hgE] at hgΔ + have h := congr_arg (·.coeff 1) hgΔ + simpa [PowerSeries.coeff_smul, discriminant_qExpansion_coeff_one, + E4_cube_sub_E6_sq_form_qExpansion_coeff_one] using h.symm + have h1728 : (1728 : ℂ) * discriminant z = E₄ z ^ 3 - E₆ z ^ 2 := by + rw [← hc_eq, show c * discriminant z = (c • CuspForm.discriminant) z from rfl, hc, + congr_fun hgE z, E4_cube_sub_E6_sq_form_apply] + linear_combination (1 / 1728 : ℂ) * h1728 + /- Algebraic core of the weight-2 vanishing argument: if `p : PowerSeries ℂ` satisfies `c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with constant term `1` and first-order coefficients `240` and `-504`, then `p = 0`. -/ diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index 582d40a8fefd1d..d22a368066fde1 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -192,6 +192,50 @@ lemma exp_isBigO_discriminant : (fun τ ↦ Real.exp (-2 * π * τ.im)) =O[atImI grind [norm_one, norm_sub_rev] linarith [norm_nonneg (𝕢 1 τ), mul_le_mul_of_nonneg_left hprod_bound (norm_nonneg (𝕢 1 τ))] +/-- The cusp function of the discriminant equals `q * ∏' n, (1 - q^(n+1))^24` +on `ball 0 (1/2)`. -/ +private lemma discriminant_cuspFunction_eqOn : + Set.EqOn (cuspFunction 1 (Δ : ℍ → ℂ)) + (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) := by + intro q hq + by_cases hq0 : q = 0 + · simp only [hq0, zero_mul] + exact Periodic.cuspFunction_zero_of_zero_at_inf one_pos + discriminant_isZeroAtImInfty.zero_at_infty_comp_ofComplex + · have hqn : ‖q‖ < 1 := lt_trans (by simpa [dist_zero_right] using hq) (by norm_num) + have him := Periodic.im_invQParam_pos_of_norm_lt_one one_pos hqn hq0 + rw [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, + comp_apply, ofComplex_apply_of_im_pos him, discriminant_eq_q_prod ⟨_, him⟩] + have hqr := Periodic.qParam_right_inv one_ne_zero hq0 + have heta : ∀ n : ℕ, eta_q n (Periodic.invQParam 1 q) = q ^ (n + 1) := fun n ↦ by + simp [eta_q, hqr] + simp only [hqr, heta] + +/-- The product `∏' i, (1 - q^(i+1))^24` is differentiable within `ball 0 (1/2)` at 0. -/ +private lemma differentiableWithinAt_eta_prod_pow : + DifferentiableWithinAt ℂ (fun q : ℂ ↦ ∏' i, (1 - q ^ (i + 1)) ^ 24) + (Metric.ball 0 (1 / 2)) 0 := + (differentiableOn_tprod_one_sub_pow_pow 24 0 + (by simp [Metric.mem_ball] : (0 : ℂ) ∈ Metric.ball 0 1)).mono + (Metric.ball_subset_ball (by norm_num)) + +/-- The first q-expansion coefficient of the modular discriminant is 1. -/ +lemma discriminant_qExpansion_coeff_one : + (qExpansion 1 (Δ : ℍ → ℂ)).coeff 1 = 1 := by + rw [qExpansion_coeff] + simp only [Nat.factorial_one, Nat.cast_one, inv_one, one_mul, iteratedDeriv_succ, + iteratedDeriv_zero] + have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) (1 / 2 : ℝ) := Metric.mem_ball_self (by norm_num) + change deriv (cuspFunction 1 Δ) 0 = 1 + rw [← derivWithin_of_isOpen Metric.isOpen_ball hmem] + rw [derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem)] + have : derivWithin (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) 0 = + derivWithin id (Metric.ball 0 (1 / 2)) 0 * (∏' i, (1 - (0 : ℂ) ^ (i + 1)) ^ 24) + + id 0 * derivWithin (fun q ↦ ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) 0 := + derivWithin_mul differentiableWithinAt_id' differentiableWithinAt_eta_prod_pow + rw [this, derivWithin_id _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] + simp + end end ModularForm diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne.lean index 90e84f176c71fc..18b54c2095a625 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne.lean @@ -72,9 +72,6 @@ namespace ModularFormClass variable [ModularFormClass F 𝒮ℒ k] -lemma one_mem_strictPeriods_SL : (1 : ℝ) ∈ (𝒮ℒ : Subgroup (GL (Fin 2) ℝ)).strictPeriods := - Gamma_one_coe_eq_SL ▸ one_mem_strictPeriods_SL2Z - private theorem cuspFunction_eqOn_const_of_nonpos_wt (hk : k ≤ 0) (f : F) : Set.EqOn (cuspFunction 1 f) (const ℂ (cuspFunction 1 f 0)) (Metric.ball 0 1) := by refine eq_const_of_exists_le (fun q hq ↦ ?_) (exp_nonneg (-π)) ?_ (fun q hq ↦ ?_) From 5ebde02548a1ed952501090401a0f46abd55e265 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 1 May 2026 12:53:34 +0100 Subject: [PATCH 22/49] =?UTF-8?q?chore(NumberTheory/ModularForms):=20clean?= =?UTF-8?q?=20up=20=CE=94=20=3D=20(E=E2=82=84=C2=B3=20-=20E=E2=82=86=C2=B2?= =?UTF-8?q?)=20/=201728=20proof?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applies findings from /simplify code review: - Extract the duplicated `qExpansion_sub` rewrite chain into a shared `E₄CubeSubE₆SqForm_qExpansion_eq` helper. Both `_isCuspForm` and `_qExpansion_coeff_one` now reduce to a one-line `rw` of this helper (~16 lines saved). - `linear_combination (1 / 1728 : ℂ) * h1728` → `linear_combination h1728 / 1728`. - Rename `E4_cube_sub_E6_sq_form` → `E₄CubeSubE₆SqForm` (camelCase + subscripts per mathlib def naming convention) and `discriminant_eq_E4_cube_sub_E6_sq` → `discriminant_eq_E₄_cube_sub_E₆_sq`. - Use `ball 0 1` instead of `ball 0 (1/2)` in `discriminant_cuspFunction_eqOn` and `discriminant_qExpansion_coeff_one` (the actual constraint is `‖q‖ < 1`), which lets `differentiableOn_tprod_one_sub_pow_pow` apply directly and removes the now-unnecessary `differentiableWithinAt_eta_prod_pow` helper. --- .../DimensionFormulas/LevelOne.lean | 65 +++++++++---------- .../ModularForms/Discriminant.lean | 48 +++++--------- 2 files changed, 45 insertions(+), 68 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 83083c0afe4ccb..f32cf75aa63e3d 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -164,63 +164,58 @@ lemma E₆_qExpansion_coeff_one : (qExpansion 1 E₆).coeff 1 = -504 := by norm_num [E_qExpansion_coeff _ ⟨3, rfl⟩, show bernoulli 6 = 1 / 42 by decide +kernel] /-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ -private noncomputable def E4_cube_sub_E6_sq_form : ModularForm 𝒮ℒ 12 := +private noncomputable def E₄CubeSubE₆SqForm : ModularForm 𝒮ℒ 12 := ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄) - ModularForm.mcast (by norm_num) (E₆.mul E₆) -private lemma E4_cube_sub_E6_sq_form_apply (z : ℍ) : - E4_cube_sub_E6_sq_form z = E₄ z ^ 3 - E₆ z ^ 2 := by +private lemma E₄CubeSubE₆SqForm_apply (z : ℍ) : + E₄CubeSubE₆SqForm z = E₄ z ^ 3 - E₆ z ^ 2 := by change E₄ z * E₄ z * E₄ z - E₆ z * E₆ z = _ ring -private lemma E4_cube_sub_E6_sq_form_isCuspForm : IsCuspForm E4_cube_sub_E6_sq_form := by - refine (isCuspForm_iff_coeffZero_eq_zero _).mpr ?_ - have hsub : qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) = - qExpansion 1 ((E₄.mul E₄).mul E₄ : ℍ → ℂ) - qExpansion 1 (E₆.mul E₆ : ℍ → ℂ) := - ModularFormClass.qExpansion_sub one_pos one_mem_strictPeriods_SL - (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) - (ModularForm.mcast (by norm_num) (E₆.mul E₆)) - rw [hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (E₄.mul E₄) E₄, - ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, - ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] - have h4 := E_qExpansion_coeff_zero (show (3 : ℕ) ≤ 4 by norm_num) ⟨2, rfl⟩ - have h6 := E_qExpansion_coeff_zero (show (3 : ℕ) ≤ 6 by norm_num) ⟨3, rfl⟩ - rw [PowerSeries.coeff_zero_eq_constantCoeff] at h4 h6 ⊢ - simp [h4, h6] - -private lemma E4_cube_sub_E6_sq_form_qExpansion_coeff_one : - (qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ)).coeff 1 = 1728 := by - have hsub : qExpansion 1 (E4_cube_sub_E6_sq_form : ℍ → ℂ) = - qExpansion 1 ((E₄.mul E₄).mul E₄ : ℍ → ℂ) - qExpansion 1 (E₆.mul E₆ : ℍ → ℂ) := - ModularFormClass.qExpansion_sub one_pos one_mem_strictPeriods_SL - (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) - (ModularForm.mcast (by norm_num) (E₆.mul E₆)) - rw [hsub, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (E₄.mul E₄) E₄, +private lemma E₄CubeSubE₆SqForm_qExpansion_eq : + qExpansion 1 (E₄CubeSubE₆SqForm : ℍ → ℂ) = + qExpansion 1 (E₄ : ℍ → ℂ) * qExpansion 1 E₄ * qExpansion 1 E₄ - + qExpansion 1 (E₆ : ℍ → ℂ) * qExpansion 1 E₆ := by + rw [show qExpansion 1 (E₄CubeSubE₆SqForm : ℍ → ℂ) = + qExpansion 1 ((E₄.mul E₄).mul E₄ : ℍ → ℂ) - qExpansion 1 (E₆.mul E₆ : ℍ → ℂ) from + ModularFormClass.qExpansion_sub one_pos one_mem_strictPeriods_SL + (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) + (ModularForm.mcast (by norm_num) (E₆.mul E₆)), + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (E₄.mul E₄) E₄, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] - simp [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, E₄_qExpansion_coeff_one, + +private lemma E₄CubeSubE₆SqForm_isCuspForm : IsCuspForm E₄CubeSubE₆SqForm := by + refine (isCuspForm_iff_coeffZero_eq_zero _).mpr ?_ + rw [E₄CubeSubE₆SqForm_qExpansion_eq] + simp [PowerSeries.coeff_mul, -PowerSeries.coeff_zero_eq_constantCoeff, + E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] + +private lemma E₄CubeSubE₆SqForm_qExpansion_coeff_one : + (qExpansion 1 (E₄CubeSubE₆SqForm : ℍ → ℂ)).coeff 1 = 1728 := by + rw [E₄CubeSubE₆SqForm_qExpansion_eq] + norm_num [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, E₄_qExpansion_coeff_one, E₆_qExpansion_coeff_one, E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] - ring /-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ -theorem discriminant_eq_E4_cube_sub_E6_sq (z : ℍ) : +theorem discriminant_eq_E₄_cube_sub_E₆_sq (z : ℍ) : discriminant z = (1 / 1728) * (E₄ z ^ 3 - E₆ z ^ 2) := by - obtain ⟨g, hg⟩ := E4_cube_sub_E6_sq_form_isCuspForm + obtain ⟨g, hg⟩ := E₄CubeSubE₆SqForm_isCuspForm obtain ⟨c, hc⟩ := CuspForm.exists_smul_discriminant_of_weight_eq_twelve g - have hgE : (g : ℍ → ℂ) = E4_cube_sub_E6_sq_form := congrArg DFunLike.coe hg + have hgE : (g : ℍ → ℂ) = E₄CubeSubE₆SqForm := congrArg DFunLike.coe hg have hc_eq : c = 1728 := by have hcΔ : (c • CuspForm.discriminant : ℍ → ℂ) = g := congrArg DFunLike.coe hc have hgΔ := ModularFormClass.qExpansion_smul one_pos one_mem_strictPeriods_SL c CuspForm.discriminant rw [hcΔ, hgE] at hgΔ - have h := congr_arg (·.coeff 1) hgΔ simpa [PowerSeries.coeff_smul, discriminant_qExpansion_coeff_one, - E4_cube_sub_E6_sq_form_qExpansion_coeff_one] using h.symm + E₄CubeSubE₆SqForm_qExpansion_coeff_one] using (congr_arg (·.coeff 1) hgΔ).symm have h1728 : (1728 : ℂ) * discriminant z = E₄ z ^ 3 - E₆ z ^ 2 := by rw [← hc_eq, show c * discriminant z = (c • CuspForm.discriminant) z from rfl, hc, - congr_fun hgE z, E4_cube_sub_E6_sq_form_apply] - linear_combination (1 / 1728 : ℂ) * h1728 + congr_fun hgE z, E₄CubeSubE₆SqForm_apply] + linear_combination h1728 / 1728 /- Algebraic core of the weight-2 vanishing argument: if `p : PowerSeries ℂ` satisfies `c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index d22a368066fde1..9798ae883c45f5 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -193,48 +193,30 @@ lemma exp_isBigO_discriminant : (fun τ ↦ Real.exp (-2 * π * τ.im)) =O[atImI linarith [norm_nonneg (𝕢 1 τ), mul_le_mul_of_nonneg_left hprod_bound (norm_nonneg (𝕢 1 τ))] /-- The cusp function of the discriminant equals `q * ∏' n, (1 - q^(n+1))^24` -on `ball 0 (1/2)`. -/ +on the open unit disc. -/ private lemma discriminant_cuspFunction_eqOn : Set.EqOn (cuspFunction 1 (Δ : ℍ → ℂ)) - (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) := by + (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 1) := by intro q hq by_cases hq0 : q = 0 - · simp only [hq0, zero_mul] - exact Periodic.cuspFunction_zero_of_zero_at_inf one_pos + · simpa [hq0] using Periodic.cuspFunction_zero_of_zero_at_inf one_pos discriminant_isZeroAtImInfty.zero_at_infty_comp_ofComplex - · have hqn : ‖q‖ < 1 := lt_trans (by simpa [dist_zero_right] using hq) (by norm_num) - have him := Periodic.im_invQParam_pos_of_norm_lt_one one_pos hqn hq0 - rw [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, - comp_apply, ofComplex_apply_of_im_pos him, discriminant_eq_q_prod ⟨_, him⟩] - have hqr := Periodic.qParam_right_inv one_ne_zero hq0 - have heta : ∀ n : ℕ, eta_q n (Periodic.invQParam 1 q) = q ^ (n + 1) := fun n ↦ by - simp [eta_q, hqr] - simp only [hqr, heta] - -/-- The product `∏' i, (1 - q^(i+1))^24` is differentiable within `ball 0 (1/2)` at 0. -/ -private lemma differentiableWithinAt_eta_prod_pow : - DifferentiableWithinAt ℂ (fun q : ℂ ↦ ∏' i, (1 - q ^ (i + 1)) ^ 24) - (Metric.ball 0 (1 / 2)) 0 := - (differentiableOn_tprod_one_sub_pow_pow 24 0 - (by simp [Metric.mem_ball] : (0 : ℂ) ∈ Metric.ball 0 1)).mono - (Metric.ball_subset_ball (by norm_num)) + · have him := Periodic.im_invQParam_pos_of_norm_lt_one one_pos + (by simpa [dist_zero_right] using hq) hq0 + simp [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, + comp_apply, ofComplex_apply_of_im_pos him, discriminant_eq_q_prod ⟨_, him⟩, + Periodic.qParam_right_inv one_ne_zero hq0, eta_q] /-- The first q-expansion coefficient of the modular discriminant is 1. -/ lemma discriminant_qExpansion_coeff_one : (qExpansion 1 (Δ : ℍ → ℂ)).coeff 1 = 1 := by - rw [qExpansion_coeff] - simp only [Nat.factorial_one, Nat.cast_one, inv_one, one_mul, iteratedDeriv_succ, - iteratedDeriv_zero] - have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) (1 / 2 : ℝ) := Metric.mem_ball_self (by norm_num) - change deriv (cuspFunction 1 Δ) 0 = 1 - rw [← derivWithin_of_isOpen Metric.isOpen_ball hmem] - rw [derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem)] - have : derivWithin (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) 0 = - derivWithin id (Metric.ball 0 (1 / 2)) 0 * (∏' i, (1 - (0 : ℂ) ^ (i + 1)) ^ 24) + - id 0 * derivWithin (fun q ↦ ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 (1 / 2)) 0 := - derivWithin_mul differentiableWithinAt_id' differentiableWithinAt_eta_prod_pow - rw [this, derivWithin_id _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] - simp + have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) 1 := Metric.mem_ball_self one_pos + simp [qExpansion_coeff, iteratedDeriv_succ, iteratedDeriv_zero, + ← derivWithin_of_isOpen Metric.isOpen_ball hmem, + derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem), + derivWithin_fun_mul (s := Metric.ball 0 1) differentiableWithinAt_id' + (differentiableOn_tprod_one_sub_pow_pow 24 _ hmem), + derivWithin_id' _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] end From 82028aa9cc1036b5c52b431e04d28bd58c51729b Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 1 May 2026 13:02:40 +0100 Subject: [PATCH 23/49] =?UTF-8?q?chore(NumberTheory/ModularForms):=20drop?= =?UTF-8?q?=20redundant=20=E2=84=8D=20=E2=86=92=20=E2=84=82=20ascriptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops `(... : ℍ → ℂ)` type ascriptions where the surrounding term already forces the coercion (`qExpansion 1 E₄`, `cuspFunction 1 Δ`, `qExpansion 1 E₄CubeSubE₆SqForm`, etc.). Also reflows the affected declarations to fit the 100-character line limit. --- .../ModularForms/DimensionFormulas/LevelOne.lean | 11 +++++------ Mathlib/NumberTheory/ModularForms/Discriminant.lean | 12 +++++------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index f32cf75aa63e3d..ad1db030e3eba2 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -174,11 +174,10 @@ private lemma E₄CubeSubE₆SqForm_apply (z : ℍ) : ring private lemma E₄CubeSubE₆SqForm_qExpansion_eq : - qExpansion 1 (E₄CubeSubE₆SqForm : ℍ → ℂ) = - qExpansion 1 (E₄ : ℍ → ℂ) * qExpansion 1 E₄ * qExpansion 1 E₄ - - qExpansion 1 (E₆ : ℍ → ℂ) * qExpansion 1 E₆ := by - rw [show qExpansion 1 (E₄CubeSubE₆SqForm : ℍ → ℂ) = - qExpansion 1 ((E₄.mul E₄).mul E₄ : ℍ → ℂ) - qExpansion 1 (E₆.mul E₆ : ℍ → ℂ) from + qExpansion 1 E₄CubeSubE₆SqForm = qExpansion 1 E₄ * qExpansion 1 E₄ * qExpansion 1 E₄ - + qExpansion 1 E₆ * qExpansion 1 E₆ := by + rw [show qExpansion 1 E₄CubeSubE₆SqForm = + qExpansion 1 ((E₄.mul E₄).mul E₄) - qExpansion 1 (E₆.mul E₆) from ModularFormClass.qExpansion_sub one_pos one_mem_strictPeriods_SL (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) (ModularForm.mcast (by norm_num) (E₆.mul E₆)), @@ -193,7 +192,7 @@ private lemma E₄CubeSubE₆SqForm_isCuspForm : IsCuspForm E₄CubeSubE₆SqFor E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] private lemma E₄CubeSubE₆SqForm_qExpansion_coeff_one : - (qExpansion 1 (E₄CubeSubE₆SqForm : ℍ → ℂ)).coeff 1 = 1728 := by + (qExpansion 1 E₄CubeSubE₆SqForm).coeff 1 = 1728 := by rw [E₄CubeSubE₆SqForm_qExpansion_eq] norm_num [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, E₄_qExpansion_coeff_one, E₆_qExpansion_coeff_one, E_qExpansion_coeff_zero _ ⟨2, rfl⟩, diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index 9798ae883c45f5..08efb060e5203e 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -194,22 +194,20 @@ lemma exp_isBigO_discriminant : (fun τ ↦ Real.exp (-2 * π * τ.im)) =O[atImI /-- The cusp function of the discriminant equals `q * ∏' n, (1 - q^(n+1))^24` on the open unit disc. -/ -private lemma discriminant_cuspFunction_eqOn : - Set.EqOn (cuspFunction 1 (Δ : ℍ → ℂ)) - (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 1) := by +private lemma discriminant_cuspFunction_eqOn : Set.EqOn (cuspFunction 1 Δ) + (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 1) := by intro q hq by_cases hq0 : q = 0 · simpa [hq0] using Periodic.cuspFunction_zero_of_zero_at_inf one_pos discriminant_isZeroAtImInfty.zero_at_infty_comp_ofComplex · have him := Periodic.im_invQParam_pos_of_norm_lt_one one_pos (by simpa [dist_zero_right] using hq) hq0 - simp [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, - comp_apply, ofComplex_apply_of_im_pos him, discriminant_eq_q_prod ⟨_, him⟩, + simp [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, comp_apply, + ofComplex_apply_of_im_pos him, discriminant_eq_q_prod ⟨_, him⟩, Periodic.qParam_right_inv one_ne_zero hq0, eta_q] /-- The first q-expansion coefficient of the modular discriminant is 1. -/ -lemma discriminant_qExpansion_coeff_one : - (qExpansion 1 (Δ : ℍ → ℂ)).coeff 1 = 1 := by +lemma discriminant_qExpansion_coeff_one : (qExpansion 1 Δ).coeff 1 = 1 := by have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) 1 := Metric.mem_ball_self one_pos simp [qExpansion_coeff, iteratedDeriv_succ, iteratedDeriv_zero, ← derivWithin_of_isOpen Metric.isOpen_ball hmem, From d2b5d0e8dfeb17ee675d8b4fdd4cf3e9b8c35b7b Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 1 May 2026 15:46:36 +0100 Subject: [PATCH 24/49] =?UTF-8?q?feat(NumberTheory/ModularForms):=20graded?= =?UTF-8?q?-ring=20version=20of=20=CE=94=20=3D=20(E=E2=82=84=C2=B3=20-=20E?= =?UTF-8?q?=E2=82=86=C2=B2)=20/=201728?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `ModularForm.discriminant_eq_E₄_cube_sub_E₆_sq_graded`, the analogue of `discriminant_eq_E₄_cube_sub_E₆_sq` in the graded ring `⨁ k, ModularForm 𝒮ℒ k`: DirectSum.of (ModularForm 𝒮ℒ) 12 (CuspForm.discriminant : ModularForm 𝒮ℒ 12) = (1 / 1728 : ℂ) • (DirectSum.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 - DirectSum.of (ModularForm 𝒮ℒ) 6 E₆ ^ 2) The proof reduces to the pointwise identity via `DirectSum.of_mul_of`, `congr 1`, and `ext`, then closes by `discriminant_eq_E₄_cube_sub_E₆_sq` and `ring`. --- .../DimensionFormulas/LevelOne.lean | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index ad1db030e3eba2..d65412a50ecf90 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -23,6 +23,8 @@ of even weight. * `ModularForm.rank_eq_one_add_rank_cuspForm`: `rank M_k = 1 + rank S_k` for even `k ≥ 3`. * `ModularForm.dimension_level_one`: the full dimension formula for all even `k : ℕ`. * `ModularForm.levelOne_odd_weight_rank_zero`: modular forms of odd weight are zero. +* `ModularForm.discriminant_eq_E₄_cube_sub_E₆_sq`: the identity `Δ = (E₄³ - E₆²) / 1728`, + with a graded-ring version `ModularForm.discriminant_eq_E₄_cube_sub_E₆_sq_graded`. * A `FiniteDimensional ℂ (ModularForm 𝒮ℒ k)` instance for every `k : ℤ`. -/ @@ -216,6 +218,28 @@ theorem discriminant_eq_E₄_cube_sub_E₆_sq (z : ℍ) : congr_fun hgE z, E₄CubeSubE₆SqForm_apply] linear_combination h1728 / 1728 +/-- The modular discriminant equals `(E₄³ - E₆²) / 1728` in the graded ring +`⨁ k, ModularForm 𝒮ℒ k`. -/ +theorem discriminant_eq_E₄_cube_sub_E₆_sq_graded : + DirectSum.of (ModularForm 𝒮ℒ) 12 (CuspForm.discriminant : ModularForm 𝒮ℒ 12) = + (1 / 1728 : ℂ) • (DirectSum.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 - + DirectSum.of (ModularForm 𝒮ℒ) 6 E₆ ^ 2) := by + have hE4 : DirectSum.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 = DirectSum.of (ModularForm 𝒮ℒ) 12 + (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) := by + rw [pow_succ (n := 2), pow_two, DirectSum.of_mul_of, DirectSum.of_mul_of] + rfl + have hE6 : DirectSum.of (ModularForm 𝒮ℒ) 6 E₆ ^ 2 = + DirectSum.of (ModularForm 𝒮ℒ) 12 (ModularForm.mcast (by norm_num) (E₆.mul E₆)) := by + rw [pow_two, DirectSum.of_mul_of] + rfl + rw [hE4, hE6, ← map_sub (DirectSum.of (ModularForm 𝒮ℒ) 12), ← DirectSum.of_smul] + congr 1 + ext z + change ModularForm.discriminant z = + (1 / 1728 : ℂ) * (E₄ z * E₄ z * E₄ z - E₆ z * E₆ z) + rw [discriminant_eq_E₄_cube_sub_E₆_sq z] + ring + /- Algebraic core of the weight-2 vanishing argument: if `p : PowerSeries ℂ` satisfies `c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with constant term `1` and first-order coefficients `240` and `-504`, then `p = 0`. -/ From 4b367badbfe4266a158531426cd15117b040dd3f Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 1 May 2026 15:54:08 +0100 Subject: [PATCH 25/49] chore(NumberTheory/ModularForms): use decide for nat equalities in mcast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In `discriminant_eq_E₄_cube_sub_E₆_sq_graded`, replace `(by norm_num)` proofs of `4 + 4 + 4 = 12` and `6 + 6 = 12` with `(by decide)` (kernel reduction). --- .../ModularForms/DimensionFormulas/LevelOne.lean | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index d65412a50ecf90..ab4f264c03b330 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -221,24 +221,21 @@ theorem discriminant_eq_E₄_cube_sub_E₆_sq (z : ℍ) : /-- The modular discriminant equals `(E₄³ - E₆²) / 1728` in the graded ring `⨁ k, ModularForm 𝒮ℒ k`. -/ theorem discriminant_eq_E₄_cube_sub_E₆_sq_graded : - DirectSum.of (ModularForm 𝒮ℒ) 12 (CuspForm.discriminant : ModularForm 𝒮ℒ 12) = - (1 / 1728 : ℂ) • (DirectSum.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 - - DirectSum.of (ModularForm 𝒮ℒ) 6 E₆ ^ 2) := by + DirectSum.of (ModularForm 𝒮ℒ) 12 CuspForm.discriminant = + (1 / 1728 : ℂ) • (.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 - .of (ModularForm 𝒮ℒ) 6 E₆ ^ 2) := by have hE4 : DirectSum.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 = DirectSum.of (ModularForm 𝒮ℒ) 12 - (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) := by + (ModularForm.mcast (by decide) ((E₄.mul E₄).mul E₄)) := by rw [pow_succ (n := 2), pow_two, DirectSum.of_mul_of, DirectSum.of_mul_of] rfl have hE6 : DirectSum.of (ModularForm 𝒮ℒ) 6 E₆ ^ 2 = - DirectSum.of (ModularForm 𝒮ℒ) 12 (ModularForm.mcast (by norm_num) (E₆.mul E₆)) := by + DirectSum.of (ModularForm 𝒮ℒ) 12 (ModularForm.mcast (by decide) (E₆.mul E₆)) := by rw [pow_two, DirectSum.of_mul_of] rfl rw [hE4, hE6, ← map_sub (DirectSum.of (ModularForm 𝒮ℒ) 12), ← DirectSum.of_smul] congr 1 ext z - change ModularForm.discriminant z = - (1 / 1728 : ℂ) * (E₄ z * E₄ z * E₄ z - E₆ z * E₆ z) - rw [discriminant_eq_E₄_cube_sub_E₆_sq z] - ring + change ModularForm.discriminant z = (1 / 1728 : ℂ) * (E₄ z * E₄ z * E₄ z - E₆ z * E₆ z) + grind [discriminant_eq_E₄_cube_sub_E₆_sq z] /- Algebraic core of the weight-2 vanishing argument: if `p : PowerSeries ℂ` satisfies `c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with From 8de2aff96a1c5443840512d551fc0d7a9cc82110 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 1 May 2026 16:01:05 +0100 Subject: [PATCH 26/49] feat(NumberTheory/ModularForms): mcast_apply simp lemmas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `@[simp]` lemmas `ModularForm.mcast_apply` and `CuspForm.mcast_apply` saying `mcast h f hΓ z = f z` (true by `rfl`). These let `simp` automatically unfold `mcast` in pointwise reasoning, and are useful API for any future proofs that mix `ModularForm.mcast`/`CuspForm.mcast` with `simp`-based function-level rewriting. --- Mathlib/NumberTheory/ModularForms/Basic.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index cfb4abba9ed314..6a3070e0e34275 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -549,6 +549,10 @@ def mcast {a b : ℤ} {Γ Γ' : Subgroup (GL (Fin 2) ℝ)} (h : a = b) (f : Cusp holo' := f.holo' zero_at_cusps' hc := h ▸ f.zero_at_cusps' (hΓ ▸ hc) +@[simp] +lemma mcast_apply {a b : ℤ} {Γ Γ' : Subgroup (GL (Fin 2) ℝ)} (h : a = b) (f : CuspForm Γ a) + (hΓ : Γ' = Γ := by rfl) (z : ℍ) : mcast h f hΓ z = f z := rfl + end CuspForm namespace ModularForm @@ -564,6 +568,10 @@ def mcast {a b : ℤ} {Γ Γ' : Subgroup (GL (Fin 2) ℝ)} (h : a = b) (f : Modu holo' := f.holo' bdd_at_cusps' hc := h ▸ f.bdd_at_cusps' (hΓ ▸ hc) +@[simp] +lemma mcast_apply {a b : ℤ} {Γ Γ' : Subgroup (GL (Fin 2) ℝ)} (h : a = b) (f : ModularForm Γ a) + (hΓ : Γ' = Γ := by rfl) (z : ℍ) : mcast h f hΓ z = f z := rfl + @[ext (iff := false)] theorem gradedMonoid_eq_of_cast {Γ : Subgroup (GL (Fin 2) ℝ)} {a b : GradedMonoid (ModularForm Γ)} (h : a.fst = b.fst) (h2 : mcast h a.snd = b.snd) : a = b := by From 0ce59fdc426ca49ac3781248fc681f910c0f531c Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 1 May 2026 16:35:31 +0100 Subject: [PATCH 27/49] Revert "feat(NumberTheory/ModularForms): mcast_apply simp lemmas" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The simp lemmas were unused — `change` in `discriminant_eq_E₄_cube_sub_E₆_sq_graded` goes through defeq directly, and the `simp only`-based alternatives I tried didn't close the goal. Removing per "no unused API" guideline; can be re-added later when there's a proof that benefits. This reverts commit 8de2aff96a1. --- Mathlib/NumberTheory/ModularForms/Basic.lean | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index 6a3070e0e34275..cfb4abba9ed314 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -549,10 +549,6 @@ def mcast {a b : ℤ} {Γ Γ' : Subgroup (GL (Fin 2) ℝ)} (h : a = b) (f : Cusp holo' := f.holo' zero_at_cusps' hc := h ▸ f.zero_at_cusps' (hΓ ▸ hc) -@[simp] -lemma mcast_apply {a b : ℤ} {Γ Γ' : Subgroup (GL (Fin 2) ℝ)} (h : a = b) (f : CuspForm Γ a) - (hΓ : Γ' = Γ := by rfl) (z : ℍ) : mcast h f hΓ z = f z := rfl - end CuspForm namespace ModularForm @@ -568,10 +564,6 @@ def mcast {a b : ℤ} {Γ Γ' : Subgroup (GL (Fin 2) ℝ)} (h : a = b) (f : Modu holo' := f.holo' bdd_at_cusps' hc := h ▸ f.bdd_at_cusps' (hΓ ▸ hc) -@[simp] -lemma mcast_apply {a b : ℤ} {Γ Γ' : Subgroup (GL (Fin 2) ℝ)} (h : a = b) (f : ModularForm Γ a) - (hΓ : Γ' = Γ := by rfl) (z : ℍ) : mcast h f hΓ z = f z := rfl - @[ext (iff := false)] theorem gradedMonoid_eq_of_cast {Γ : Subgroup (GL (Fin 2) ℝ)} {a b : GradedMonoid (ModularForm Γ)} (h : a.fst = b.fst) (h2 : mcast h a.snd = b.snd) : a = b := by From 9f3dadc6b2e1f24100a399a7a5db99f045338376 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 1 May 2026 16:46:48 +0100 Subject: [PATCH 28/49] refactor(NumberTheory/ModularForms): move discriminant identity to GradedRing.lean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Splits the `Δ = (E₄³ - E₆²) / 1728` results out of `DimensionFormulas/LevelOne.lean` into a new file `DimensionFormulas/GradedRing.lean`. This new file is intended to collect structural results about the graded ring `⨁ k, ModularForm 𝒮ℒ k` of level-1 modular forms (e.g. that `E₄, E₆` generate the full graded ring, to come). Moved declarations: - `E₄CubeSubE₆SqForm` (private) - `E₄CubeSubE₆SqForm_apply` (private) - `E₄CubeSubE₆SqForm_qExpansion_eq` (private) - `E₄CubeSubE₆SqForm_isCuspForm` (private) - `E₄CubeSubE₆SqForm_qExpansion_coeff_one` (private) - `discriminant_eq_E₄_cube_sub_E₆_sq` - `discriminant_eq_E₄_cube_sub_E₆_sq_graded` --- Mathlib.lean | 1 + .../DimensionFormulas/GradedRing.lean | 104 ++++++++++++++++++ .../DimensionFormulas/LevelOne.lean | 74 ------------- .../ModularForms/Discriminant.lean | 2 +- 4 files changed, 106 insertions(+), 75 deletions(-) create mode 100644 Mathlib/NumberTheory/ModularForms/DimensionFormulas/GradedRing.lean diff --git a/Mathlib.lean b/Mathlib.lean index 06e253281cc1da..4735ad3e08a74e 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5655,6 +5655,7 @@ public import Mathlib.NumberTheory.ModularForms.Cusps public import Mathlib.NumberTheory.ModularForms.DedekindEta public import Mathlib.NumberTheory.ModularForms.Delta public import Mathlib.NumberTheory.ModularForms.Derivative +public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.GradedRing public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.LevelOne public import Mathlib.NumberTheory.ModularForms.Discriminant public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Basic diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/GradedRing.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/GradedRing.lean new file mode 100644 index 00000000000000..f3c55e20f78f1b --- /dev/null +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/GradedRing.lean @@ -0,0 +1,104 @@ +/- +Copyright (c) 2026 Chris Birkbeck. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Birkbeck +-/ +module + +public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.LevelOne + +/-! +# The graded ring of level-1 modular forms + +This file collects structural results about the graded ring `⨁ k, ModularForm 𝒮ℒ k` of +level-1 modular forms, beyond those that fall out of the dimension formula directly. + +## Main results + +* `ModularForm.discriminant_eq_E₄_cube_sub_E₆_sq`: the pointwise identity + `Δ = (E₄³ - E₆²) / 1728`. +* `ModularForm.discriminant_eq_E₄_cube_sub_E₆_sq_graded`: the same identity in the graded + ring `⨁ k, ModularForm 𝒮ℒ k`. +-/ + +@[expose] public noncomputable section + +open UpperHalfPlane ModularForm ModularFormClass MatrixGroups EisensteinSeries + +namespace ModularForm + +/-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ +private noncomputable def E₄CubeSubE₆SqForm : ModularForm 𝒮ℒ 12 := + ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄) - + ModularForm.mcast (by norm_num) (E₆.mul E₆) + +private lemma E₄CubeSubE₆SqForm_apply (z : ℍ) : + E₄CubeSubE₆SqForm z = E₄ z ^ 3 - E₆ z ^ 2 := by + change E₄ z * E₄ z * E₄ z - E₆ z * E₆ z = _ + ring + +private lemma E₄CubeSubE₆SqForm_qExpansion_eq : + qExpansion 1 E₄CubeSubE₆SqForm = qExpansion 1 E₄ * qExpansion 1 E₄ * qExpansion 1 E₄ - + qExpansion 1 E₆ * qExpansion 1 E₆ := by + rw [show qExpansion 1 E₄CubeSubE₆SqForm = + qExpansion 1 ((E₄.mul E₄).mul E₄) - qExpansion 1 (E₆.mul E₆) from + ModularFormClass.qExpansion_sub one_pos one_mem_strictPeriods_SL + (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) + (ModularForm.mcast (by norm_num) (E₆.mul E₆)), + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (E₄.mul E₄) E₄, + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, + ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] + +private lemma E₄CubeSubE₆SqForm_isCuspForm : IsCuspForm E₄CubeSubE₆SqForm := by + refine (isCuspForm_iff_coeffZero_eq_zero _).mpr ?_ + rw [E₄CubeSubE₆SqForm_qExpansion_eq] + simp [PowerSeries.coeff_mul, -PowerSeries.coeff_zero_eq_constantCoeff, + E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] + +private lemma E₄CubeSubE₆SqForm_qExpansion_coeff_one : + (qExpansion 1 E₄CubeSubE₆SqForm).coeff 1 = 1728 := by + rw [E₄CubeSubE₆SqForm_qExpansion_eq] + norm_num [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, E₄_qExpansion_coeff_one, + E₆_qExpansion_coeff_one, E_qExpansion_coeff_zero _ ⟨2, rfl⟩, + E_qExpansion_coeff_zero _ ⟨3, rfl⟩] + +/-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ +theorem discriminant_eq_E₄_cube_sub_E₆_sq (z : ℍ) : + discriminant z = (1 / 1728) * (E₄ z ^ 3 - E₆ z ^ 2) := by + obtain ⟨g, hg⟩ := E₄CubeSubE₆SqForm_isCuspForm + obtain ⟨c, hc⟩ := CuspForm.exists_smul_discriminant_of_weight_eq_twelve g + have hgE : (g : ℍ → ℂ) = E₄CubeSubE₆SqForm := congrArg DFunLike.coe hg + have hc_eq : c = 1728 := by + have hcΔ : (c • CuspForm.discriminant : ℍ → ℂ) = g := congrArg DFunLike.coe hc + have hgΔ := ModularFormClass.qExpansion_smul one_pos one_mem_strictPeriods_SL c + CuspForm.discriminant + rw [hcΔ, hgE] at hgΔ + simpa [PowerSeries.coeff_smul, discriminant_qExpansion_coeff_one, + E₄CubeSubE₆SqForm_qExpansion_coeff_one] using (congr_arg (·.coeff 1) hgΔ).symm + have h1728 : (1728 : ℂ) * discriminant z = E₄ z ^ 3 - E₆ z ^ 2 := by + rw [← hc_eq, show c * discriminant z = (c • CuspForm.discriminant) z from rfl, hc, + congr_fun hgE z, E₄CubeSubE₆SqForm_apply] + linear_combination h1728 / 1728 + +/-- The modular discriminant equals `(E₄³ - E₆²) / 1728` in the graded ring +`⨁ k, ModularForm 𝒮ℒ k`. -/ +theorem discriminant_eq_E₄_cube_sub_E₆_sq_graded : + DirectSum.of (ModularForm 𝒮ℒ) 12 CuspForm.discriminant = + (1 / 1728 : ℂ) • (.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 - .of (ModularForm 𝒮ℒ) 6 E₆ ^ 2) := by + have hE4 : DirectSum.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 = DirectSum.of (ModularForm 𝒮ℒ) 12 + (ModularForm.mcast (by decide) ((E₄.mul E₄).mul E₄)) := by + rw [pow_succ (n := 2), pow_two, DirectSum.of_mul_of, DirectSum.of_mul_of] + rfl + have hE6 : DirectSum.of (ModularForm 𝒮ℒ) 6 E₆ ^ 2 = + DirectSum.of (ModularForm 𝒮ℒ) 12 (ModularForm.mcast (by decide) (E₆.mul E₆)) := by + rw [pow_two, DirectSum.of_mul_of] + rfl + rw [hE4, hE6, ← map_sub (DirectSum.of (ModularForm 𝒮ℒ) 12), ← DirectSum.of_smul] + congr 1 + ext z + change ModularForm.discriminant z = (1 / 1728 : ℂ) * (E₄ z * E₄ z * E₄ z - E₆ z * E₆ z) + grind [discriminant_eq_E₄_cube_sub_E₆_sq z] + +end ModularForm + +end diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index ab4f264c03b330..0ddf7a000f7e55 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -23,8 +23,6 @@ of even weight. * `ModularForm.rank_eq_one_add_rank_cuspForm`: `rank M_k = 1 + rank S_k` for even `k ≥ 3`. * `ModularForm.dimension_level_one`: the full dimension formula for all even `k : ℕ`. * `ModularForm.levelOne_odd_weight_rank_zero`: modular forms of odd weight are zero. -* `ModularForm.discriminant_eq_E₄_cube_sub_E₆_sq`: the identity `Δ = (E₄³ - E₆²) / 1728`, - with a graded-ring version `ModularForm.discriminant_eq_E₄_cube_sub_E₆_sq_graded`. * A `FiniteDimensional ℂ (ModularForm 𝒮ℒ k)` instance for every `k : ℤ`. -/ @@ -165,78 +163,6 @@ lemma E₄_qExpansion_coeff_one : (qExpansion 1 E₄).coeff 1 = 240 := by lemma E₆_qExpansion_coeff_one : (qExpansion 1 E₆).coeff 1 = -504 := by norm_num [E_qExpansion_coeff _ ⟨3, rfl⟩, show bernoulli 6 = 1 / 42 by decide +kernel] -/-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ -private noncomputable def E₄CubeSubE₆SqForm : ModularForm 𝒮ℒ 12 := - ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄) - - ModularForm.mcast (by norm_num) (E₆.mul E₆) - -private lemma E₄CubeSubE₆SqForm_apply (z : ℍ) : - E₄CubeSubE₆SqForm z = E₄ z ^ 3 - E₆ z ^ 2 := by - change E₄ z * E₄ z * E₄ z - E₆ z * E₆ z = _ - ring - -private lemma E₄CubeSubE₆SqForm_qExpansion_eq : - qExpansion 1 E₄CubeSubE₆SqForm = qExpansion 1 E₄ * qExpansion 1 E₄ * qExpansion 1 E₄ - - qExpansion 1 E₆ * qExpansion 1 E₆ := by - rw [show qExpansion 1 E₄CubeSubE₆SqForm = - qExpansion 1 ((E₄.mul E₄).mul E₄) - qExpansion 1 (E₆.mul E₆) from - ModularFormClass.qExpansion_sub one_pos one_mem_strictPeriods_SL - (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) - (ModularForm.mcast (by norm_num) (E₆.mul E₆)), - ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (E₄.mul E₄) E₄, - ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, - ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] - -private lemma E₄CubeSubE₆SqForm_isCuspForm : IsCuspForm E₄CubeSubE₆SqForm := by - refine (isCuspForm_iff_coeffZero_eq_zero _).mpr ?_ - rw [E₄CubeSubE₆SqForm_qExpansion_eq] - simp [PowerSeries.coeff_mul, -PowerSeries.coeff_zero_eq_constantCoeff, - E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] - -private lemma E₄CubeSubE₆SqForm_qExpansion_coeff_one : - (qExpansion 1 E₄CubeSubE₆SqForm).coeff 1 = 1728 := by - rw [E₄CubeSubE₆SqForm_qExpansion_eq] - norm_num [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, E₄_qExpansion_coeff_one, - E₆_qExpansion_coeff_one, E_qExpansion_coeff_zero _ ⟨2, rfl⟩, - E_qExpansion_coeff_zero _ ⟨3, rfl⟩] - -/-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ -theorem discriminant_eq_E₄_cube_sub_E₆_sq (z : ℍ) : - discriminant z = (1 / 1728) * (E₄ z ^ 3 - E₆ z ^ 2) := by - obtain ⟨g, hg⟩ := E₄CubeSubE₆SqForm_isCuspForm - obtain ⟨c, hc⟩ := CuspForm.exists_smul_discriminant_of_weight_eq_twelve g - have hgE : (g : ℍ → ℂ) = E₄CubeSubE₆SqForm := congrArg DFunLike.coe hg - have hc_eq : c = 1728 := by - have hcΔ : (c • CuspForm.discriminant : ℍ → ℂ) = g := congrArg DFunLike.coe hc - have hgΔ := ModularFormClass.qExpansion_smul one_pos one_mem_strictPeriods_SL c - CuspForm.discriminant - rw [hcΔ, hgE] at hgΔ - simpa [PowerSeries.coeff_smul, discriminant_qExpansion_coeff_one, - E₄CubeSubE₆SqForm_qExpansion_coeff_one] using (congr_arg (·.coeff 1) hgΔ).symm - have h1728 : (1728 : ℂ) * discriminant z = E₄ z ^ 3 - E₆ z ^ 2 := by - rw [← hc_eq, show c * discriminant z = (c • CuspForm.discriminant) z from rfl, hc, - congr_fun hgE z, E₄CubeSubE₆SqForm_apply] - linear_combination h1728 / 1728 - -/-- The modular discriminant equals `(E₄³ - E₆²) / 1728` in the graded ring -`⨁ k, ModularForm 𝒮ℒ k`. -/ -theorem discriminant_eq_E₄_cube_sub_E₆_sq_graded : - DirectSum.of (ModularForm 𝒮ℒ) 12 CuspForm.discriminant = - (1 / 1728 : ℂ) • (.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 - .of (ModularForm 𝒮ℒ) 6 E₆ ^ 2) := by - have hE4 : DirectSum.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 = DirectSum.of (ModularForm 𝒮ℒ) 12 - (ModularForm.mcast (by decide) ((E₄.mul E₄).mul E₄)) := by - rw [pow_succ (n := 2), pow_two, DirectSum.of_mul_of, DirectSum.of_mul_of] - rfl - have hE6 : DirectSum.of (ModularForm 𝒮ℒ) 6 E₆ ^ 2 = - DirectSum.of (ModularForm 𝒮ℒ) 12 (ModularForm.mcast (by decide) (E₆.mul E₆)) := by - rw [pow_two, DirectSum.of_mul_of] - rfl - rw [hE4, hE6, ← map_sub (DirectSum.of (ModularForm 𝒮ℒ) 12), ← DirectSum.of_smul] - congr 1 - ext z - change ModularForm.discriminant z = (1 / 1728 : ℂ) * (E₄ z * E₄ z * E₄ z - E₆ z * E₆ z) - grind [discriminant_eq_E₄_cube_sub_E₆_sq z] - /- Algebraic core of the weight-2 vanishing argument: if `p : PowerSeries ℂ` satisfies `c₄ • p₄ = p²` and `c₆ • p₆ = p³` for power series `p₄`, `p₆` with constant term `1` and first-order coefficients `240` and `-504`, then `p = 0`. -/ diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index 08efb060e5203e..627a7139ddaa04 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -202,7 +202,7 @@ private lemma discriminant_cuspFunction_eqOn : Set.EqOn (cuspFunction 1 Δ) discriminant_isZeroAtImInfty.zero_at_infty_comp_ofComplex · have him := Periodic.im_invQParam_pos_of_norm_lt_one one_pos (by simpa [dist_zero_right] using hq) hq0 - simp [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, comp_apply, + simp [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, ofComplex_apply_of_im_pos him, discriminant_eq_q_prod ⟨_, him⟩, Periodic.qParam_right_inv one_ne_zero hq0, eta_q] From a4125e642e648e05bef5674067fc47cfea30f9b9 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 1 May 2026 16:54:24 +0100 Subject: [PATCH 29/49] chore(NumberTheory/ModularForms): move GradedRing.lean to ModularForms/ root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move `DimensionFormulas/GradedRing.lean` → `GradedRing.lean`. The graded-ring results aren't specifically about dimension formulas, so they belong at the top of the `ModularForms/` directory. --- Mathlib.lean | 2 +- .../ModularForms/{DimensionFormulas => }/GradedRing.lean | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Mathlib/NumberTheory/ModularForms/{DimensionFormulas => }/GradedRing.lean (100%) diff --git a/Mathlib.lean b/Mathlib.lean index 4735ad3e08a74e..094ddc76d96bb5 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5655,7 +5655,6 @@ public import Mathlib.NumberTheory.ModularForms.Cusps public import Mathlib.NumberTheory.ModularForms.DedekindEta public import Mathlib.NumberTheory.ModularForms.Delta public import Mathlib.NumberTheory.ModularForms.Derivative -public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.GradedRing public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.LevelOne public import Mathlib.NumberTheory.ModularForms.Discriminant public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Basic @@ -5669,6 +5668,7 @@ public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.MDifferentiable public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.QExpansion public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Summable public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.UniformConvergence +public import Mathlib.NumberTheory.ModularForms.GradedRing public import Mathlib.NumberTheory.ModularForms.Identities public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Bounds public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Manifold diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/GradedRing.lean b/Mathlib/NumberTheory/ModularForms/GradedRing.lean similarity index 100% rename from Mathlib/NumberTheory/ModularForms/DimensionFormulas/GradedRing.lean rename to Mathlib/NumberTheory/ModularForms/GradedRing.lean From e05f5e31d04f8b991998ddbe65c1a012ecd8f04e Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Sun, 3 May 2026 10:39:54 +0100 Subject: [PATCH 30/49] review: address loefflerd's review comments on PR #38806 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Discriminant.lean: convert single `simp` for `discriminant_qExpansion_coeff_one` to a 3-step `calc` proof for robustness. - Basic.lean: add `ModularForm.pow` (with `coe_pow` simp lemma). - QExpansion.lean: add `ModularForm.qExpansion_pow`. - GradedRing.lean: use `pow` and `qExpansion_pow` in the `E₄³ - E₆²` def. - QExpansion.lean: move `cuspFunction_smul/neg/add/sub` and `qExpansion_smul/neg/add/sub` from `ModularFormClass` to `ModularForm` namespace, per the convention that lemmas about `Foo` go in the `Foo` namespace even when their input is class-generic. Co-Authored-By: Claude Opus 4.7 (1M context) --- Mathlib/NumberTheory/ModularForms/Basic.lean | 17 ++++++++++ .../DimensionFormulas/LevelOne.lean | 8 ++--- .../ModularForms/Discriminant.lean | 17 ++++++---- .../NumberTheory/ModularForms/GradedRing.lean | 24 +++++++------- .../NumberTheory/ModularForms/QExpansion.lean | 31 ++++++++++++------- 5 files changed, 63 insertions(+), 34 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index cfb4abba9ed314..e687391fa631f6 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -571,6 +571,23 @@ theorem gradedMonoid_eq_of_cast {Γ : Subgroup (GL (Fin 2) ℝ)} {a b : GradedMo cases h exact congr_arg _ h2 +/-- The `n`-th power of a modular form, as a modular form of weight `n * k`. -/ +def pow {Γ : Subgroup (GL (Fin 2) ℝ)} [Γ.HasDetPlusMinusOne] {k : ℤ} (f : ModularForm Γ k) : + ∀ (n : ℕ), ModularForm Γ ((n : ℤ) * k) + | 0 => mcast (by simp) (1 : ModularForm Γ 0) + | n + 1 => mcast (by push_cast; ring) ((f.pow n).mul f) + +@[simp] +lemma coe_pow {Γ : Subgroup (GL (Fin 2) ℝ)} [Γ.HasDetPlusMinusOne] {k : ℤ} + (f : ModularForm Γ k) (n : ℕ) : ⇑(f.pow n) = (⇑f) ^ n := by + induction n with + | zero => + change (1 : ℍ → ℂ) = _ + rw [pow_zero] + | succ n ih => + change ((f.pow n).mul f : ℍ → ℂ) = _ + rw [coe_mul, ih, pow_succ] + instance (Γ : Subgroup (GL (Fin 2) ℝ)) [Γ.HasDetPlusMinusOne] : GradedMonoid.GOne (ModularForm Γ) where one := 1 diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean index 0ddf7a000f7e55..dd37aa7f69b6b1 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -136,8 +136,8 @@ lemma ModularForm.rank_eq_one_add_rank_cuspForm {k : ℕ} (hk : 3 ≤ k) (hk2 : exact one_ne_zero <| hE.symm.trans <| (isCuspForm_iff_coeffZero_eq_zero _).mp h · refine (Submodule.Quotient.forall _).mpr fun f ↦ ⟨(qExpansion 1 f).coeff 0, ?_⟩ rw [← Submodule.Quotient.mk_smul, Submodule.Quotient.eq, mem_cuspFormSubmodule_iff, - isCuspForm_iff_coeffZero_eq_zero, ModularForm.coe_sub, ModularFormClass.qExpansion_sub, - IsGLPos.coe_smul, ModularFormClass.qExpansion_smul, map_sub, + isCuspForm_iff_coeffZero_eq_zero, ModularForm.coe_sub, ModularForm.qExpansion_sub, + IsGLPos.coe_smul, ModularForm.qExpansion_smul, map_sub, PowerSeries.coeff_smul, E_qExpansion_coeff_zero hk hk2, smul_eq_mul, mul_one, sub_self] all_goals simp @@ -187,12 +187,12 @@ private lemma weight_two_qExpansion_eq_zero (f : ModularForm 𝒮ℒ 2) : qExpan (Module.rank_eq_one_iff_finrank_eq_one.mp levelOne_weight_six_rank_one) _ have hqc4 : c4 • qExpansion 1 (E₄ : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) ^ 2 := by rw [pow_two, ← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f, - ← ModularFormClass.qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄, + ← ModularForm.qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄, show (c4 • E₄ : ℍ → ℂ) = (f.mul f) from congrArg DFunLike.coe hc4] have hqc6 : c6 • qExpansion 1 E₆ = qExpansion 1 (f : ℍ → ℂ) ^ 3 := by rw [pow_succ, pow_two, ← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f, ← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (f.mul f) f, - ← ModularFormClass.qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆, + ← ModularForm.qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆, show (c6 • E₆ : ℍ → ℂ) = (f.mul f).mul f from congrArg DFunLike.coe hc6] exact eq_zero_of_pow_eq_smul (E_qExpansion_coeff_zero _ ⟨2, rfl⟩) (E_qExpansion_coeff_zero _ ⟨3, rfl⟩) E₄_qExpansion_coeff_one E₆_qExpansion_coeff_one hqc4 hqc6 diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index 627a7139ddaa04..5bec8502b02a13 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -209,12 +209,17 @@ private lemma discriminant_cuspFunction_eqOn : Set.EqOn (cuspFunction 1 Δ) /-- The first q-expansion coefficient of the modular discriminant is 1. -/ lemma discriminant_qExpansion_coeff_one : (qExpansion 1 Δ).coeff 1 = 1 := by have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) 1 := Metric.mem_ball_self one_pos - simp [qExpansion_coeff, iteratedDeriv_succ, iteratedDeriv_zero, - ← derivWithin_of_isOpen Metric.isOpen_ball hmem, - derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem), - derivWithin_fun_mul (s := Metric.ball 0 1) differentiableWithinAt_id' - (differentiableOn_tprod_one_sub_pow_pow 24 _ hmem), - derivWithin_id' _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] + calc (qExpansion 1 Δ).coeff 1 + = derivWithin (cuspFunction 1 Δ) (Metric.ball 0 1) 0 := by + simp [qExpansion_coeff, iteratedDeriv_succ, iteratedDeriv_zero, + ← derivWithin_of_isOpen Metric.isOpen_ball hmem] + _ = derivWithin (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 1) 0 := + derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem) + _ = 1 := by + rw [derivWithin_fun_mul (s := Metric.ball 0 1) differentiableWithinAt_id' + (differentiableOn_tprod_one_sub_pow_pow 24 _ hmem), + derivWithin_id' _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] + simp end diff --git a/Mathlib/NumberTheory/ModularForms/GradedRing.lean b/Mathlib/NumberTheory/ModularForms/GradedRing.lean index f3c55e20f78f1b..8c4e365a615dee 100644 --- a/Mathlib/NumberTheory/ModularForms/GradedRing.lean +++ b/Mathlib/NumberTheory/ModularForms/GradedRing.lean @@ -29,25 +29,25 @@ namespace ModularForm /-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ private noncomputable def E₄CubeSubE₆SqForm : ModularForm 𝒮ℒ 12 := - ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄) - - ModularForm.mcast (by norm_num) (E₆.mul E₆) + ModularForm.mcast (by decide) (E₄.pow 3) - ModularForm.mcast (by decide) (E₆.pow 2) private lemma E₄CubeSubE₆SqForm_apply (z : ℍ) : E₄CubeSubE₆SqForm z = E₄ z ^ 3 - E₆ z ^ 2 := by - change E₄ z * E₄ z * E₄ z - E₆ z * E₆ z = _ - ring + change ⇑(E₄.pow 3) z - ⇑(E₆.pow 2) z = _ + rw [coe_pow, coe_pow] + rfl private lemma E₄CubeSubE₆SqForm_qExpansion_eq : qExpansion 1 E₄CubeSubE₆SqForm = qExpansion 1 E₄ * qExpansion 1 E₄ * qExpansion 1 E₄ - qExpansion 1 E₆ * qExpansion 1 E₆ := by rw [show qExpansion 1 E₄CubeSubE₆SqForm = - qExpansion 1 ((E₄.mul E₄).mul E₄) - qExpansion 1 (E₆.mul E₆) from - ModularFormClass.qExpansion_sub one_pos one_mem_strictPeriods_SL - (ModularForm.mcast (by norm_num) ((E₄.mul E₄).mul E₄)) - (ModularForm.mcast (by norm_num) (E₆.mul E₆)), - ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (E₄.mul E₄) E₄, - ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₄ E₄, - ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL E₆ E₆] + qExpansion 1 (E₄.pow 3) - qExpansion 1 (E₆.pow 2) from + ModularForm.qExpansion_sub one_pos one_mem_strictPeriods_SL + (ModularForm.mcast (by decide) (E₄.pow 3)) + (ModularForm.mcast (by decide) (E₆.pow 2)), + ModularForm.qExpansion_pow one_pos one_mem_strictPeriods_SL E₄ 3, + ModularForm.qExpansion_pow one_pos one_mem_strictPeriods_SL E₆ 2] + ring private lemma E₄CubeSubE₆SqForm_isCuspForm : IsCuspForm E₄CubeSubE₆SqForm := by refine (isCuspForm_iff_coeffZero_eq_zero _).mpr ?_ @@ -70,7 +70,7 @@ theorem discriminant_eq_E₄_cube_sub_E₆_sq (z : ℍ) : have hgE : (g : ℍ → ℂ) = E₄CubeSubE₆SqForm := congrArg DFunLike.coe hg have hc_eq : c = 1728 := by have hcΔ : (c • CuspForm.discriminant : ℍ → ℂ) = g := congrArg DFunLike.coe hc - have hgΔ := ModularFormClass.qExpansion_smul one_pos one_mem_strictPeriods_SL c + have hgΔ := ModularForm.qExpansion_smul one_pos one_mem_strictPeriods_SL c CuspForm.discriminant rw [hcΔ, hgE] at hgΔ simpa [PowerSeries.coeff_smul, discriminant_qExpansion_coeff_one, diff --git a/Mathlib/NumberTheory/ModularForms/QExpansion.lean b/Mathlib/NumberTheory/ModularForms/QExpansion.lean index 06ff2fd364d9a0..0dec76a41cf843 100644 --- a/Mathlib/NumberTheory/ModularForms/QExpansion.lean +++ b/Mathlib/NumberTheory/ModularForms/QExpansion.lean @@ -522,7 +522,7 @@ lemma qExpansion_one (h) : qExpansion h (1 : ℍ → ℂ) = 1 := by end UpperHalfPlane -namespace ModularFormClass +namespace ModularForm protected lemma cuspFunction_smul (hh : 0 < h) (hΓ : h ∈ Γ.strictPeriods) (a : ℂ) (f : F) [ModularFormClass F Γ k] : cuspFunction h (a • f) = a • cuspFunction h f := @@ -544,6 +544,12 @@ protected lemma cuspFunction_sub {G : Type*} [FunLike G ℍ ℂ] (hh : 0 < h) cuspFunction_sub (ModularFormClass.analyticAt_cuspFunction_zero f hh hΓ).continuousAt (ModularFormClass.analyticAt_cuspFunction_zero g hh hΓ).continuousAt +protected lemma cuspFunction_mul [Γ.HasDetPlusMinusOne] (hh : 0 < h) + (hΓ : h ∈ Γ.strictPeriods) {a b : ℤ} (f : ModularForm Γ a) (g : ModularForm Γ b) : + cuspFunction h (f.mul g) = cuspFunction h f * cuspFunction h g := + cuspFunction_mul (ModularFormClass.analyticAt_cuspFunction_zero f hh hΓ).continuousAt + (ModularFormClass.analyticAt_cuspFunction_zero g hh hΓ).continuousAt + protected lemma qExpansion_smul (hh : 0 < h) (hΓ : h ∈ Γ.strictPeriods) (a : ℂ) (f : F) [ModularFormClass F Γ k] : qExpansion h (a • f) = a • qExpansion h f := qExpansion_smul (ModularFormClass.analyticAt_cuspFunction_zero f hh hΓ) a @@ -564,16 +570,6 @@ protected lemma qExpansion_sub {G : Type*} [FunLike G ℍ ℂ] (hh : 0 < h) qExpansion_sub (ModularFormClass.analyticAt_cuspFunction_zero f hh hΓ) (ModularFormClass.analyticAt_cuspFunction_zero g hh hΓ) -end ModularFormClass - -namespace ModularForm - -protected lemma cuspFunction_mul [Γ.HasDetPlusMinusOne] (hh : 0 < h) - (hΓ : h ∈ Γ.strictPeriods) {a b : ℤ} (f : ModularForm Γ a) (g : ModularForm Γ b) : - cuspFunction h (f.mul g) = cuspFunction h f * cuspFunction h g := - cuspFunction_mul (ModularFormClass.analyticAt_cuspFunction_zero f hh hΓ).continuousAt - (ModularFormClass.analyticAt_cuspFunction_zero g hh hΓ).continuousAt - protected lemma qExpansion_mul [Γ.HasDetPlusMinusOne] (hh : 0 < h) (hΓ : h ∈ Γ.strictPeriods) {a b : ℤ} (f : ModularForm Γ a) (g : ModularForm Γ b) : qExpansion h (f.mul g) = qExpansion h f * qExpansion h g := @@ -589,12 +585,23 @@ protected lemma qExpansion_one [Γ.HasDetPlusMinusOne] : qExpansion h (1 : ModularForm Γ 0) = 1 := by simp [qExpansion_one] +protected lemma qExpansion_pow [Γ.HasDetPlusMinusOne] (hh : 0 < h) + (hΓ : h ∈ Γ.strictPeriods) (f : ModularForm Γ k) (n : ℕ) : + qExpansion h (f.pow n) = (qExpansion h f) ^ n := by + induction n with + | zero => + change qExpansion h (1 : ModularForm Γ 0) = _ + rw [pow_zero, ModularForm.qExpansion_one] + | succ n ih => + change qExpansion h ((f.pow n).mul f) = _ + rw [ModularForm.qExpansion_mul hh hΓ, ih, pow_succ] + /-- The qExpansion map as an additive group hom. to power series over `ℂ`. -/ def qExpansionAddHom (hh : 0 < h) (hΓ : h ∈ Γ.strictPeriods) (k : ℤ) : ModularForm Γ k →+ PowerSeries ℂ where toFun f := qExpansion h f map_zero' := qExpansion_zero h - map_add' f g := ModularFormClass.qExpansion_add hh hΓ f g + map_add' f g := ModularForm.qExpansion_add hh hΓ f g open scoped DirectSum in /-- The qExpansion map as a map from the graded ring of modular forms to power series over `ℂ`. -/ From a12e6ac15f6539803aa433a62b5a7b641f862e0f Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 08:30:00 +0100 Subject: [PATCH 31/49] rev updates --- Mathlib.lean | 3 ++ Mathlib/NumberTheory/ModularForms/Basic.lean | 16 ++++------- .../ModularForms/CuspFormSubmodule.lean | 2 +- .../ModularForms/Discriminant.lean | 8 ++---- .../EisensteinSeries/QExpansion.lean | 2 +- .../{LevelOne.lean => LevelOne/Basic.lean} | 0 .../DimensionFormula.lean} | 0 .../{ => LevelOne}/GradedRing.lean | 25 ++++++----------- .../NumberTheory/ModularForms/NormTrace.lean | 2 +- .../NumberTheory/ModularForms/QExpansion.lean | 28 +++++++++++++++++++ 10 files changed, 52 insertions(+), 34 deletions(-) rename Mathlib/NumberTheory/ModularForms/{LevelOne.lean => LevelOne/Basic.lean} (100%) rename Mathlib/NumberTheory/ModularForms/{DimensionFormulas/LevelOne.lean => LevelOne/DimensionFormula.lean} (100%) rename Mathlib/NumberTheory/ModularForms/{ => LevelOne}/GradedRing.lean (82%) diff --git a/Mathlib.lean b/Mathlib.lean index 094ddc76d96bb5..7bd94308067813 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5675,6 +5675,9 @@ public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Manifold public import Mathlib.NumberTheory.ModularForms.JacobiTheta.OneVariable public import Mathlib.NumberTheory.ModularForms.JacobiTheta.TwoVariable public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic +public import Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula +public import Mathlib.NumberTheory.ModularForms.LevelOne.GradedRing public import Mathlib.NumberTheory.ModularForms.NormTrace public import Mathlib.NumberTheory.ModularForms.Petersson public import Mathlib.NumberTheory.ModularForms.ProperlyDiscontinuous diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index e687391fa631f6..8fe5991ef0b962 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -557,6 +557,7 @@ section GradedRing /-- Cast for modular forms, which is useful for avoiding `Heq`s. Optionally transports along an equality of subgroups. -/ +@[simps -fullyApplied coe] def mcast {a b : ℤ} {Γ Γ' : Subgroup (GL (Fin 2) ℝ)} (h : a = b) (f : ModularForm Γ a) (hΓ : Γ' = Γ := by rfl) : ModularForm Γ' b where toFun := (f : ℍ → ℂ) @@ -572,21 +573,16 @@ theorem gradedMonoid_eq_of_cast {Γ : Subgroup (GL (Fin 2) ℝ)} {a b : GradedMo exact congr_arg _ h2 /-- The `n`-th power of a modular form, as a modular form of weight `n * k`. -/ -def pow {Γ : Subgroup (GL (Fin 2) ℝ)} [Γ.HasDetPlusMinusOne] {k : ℤ} (f : ModularForm Γ k) : - ∀ (n : ℕ), ModularForm Γ ((n : ℤ) * k) - | 0 => mcast (by simp) (1 : ModularForm Γ 0) - | n + 1 => mcast (by push_cast; ring) ((f.pow n).mul f) +def pow {Γ : Subgroup (GL (Fin 2) ℝ)} [Γ.HasDetPlusMinusOne] {k : ℤ} (f : ModularForm Γ k) + (n : ℕ) : ModularForm Γ (n * k) := + n.rec (mcast (by simp) (1 : ModularForm Γ 0)) (fun n g ↦ (g.mul f).mcast (by grind)) @[simp] lemma coe_pow {Γ : Subgroup (GL (Fin 2) ℝ)} [Γ.HasDetPlusMinusOne] {k : ℤ} (f : ModularForm Γ k) (n : ℕ) : ⇑(f.pow n) = (⇑f) ^ n := by induction n with - | zero => - change (1 : ℍ → ℂ) = _ - rw [pow_zero] - | succ n ih => - change ((f.pow n).mul f : ℍ → ℂ) = _ - rw [coe_mul, ih, pow_succ] + | zero => simp [pow] + | succ n ih => simp_all only [pow, coe_mcast, coe_mul, pow_succ] instance (Γ : Subgroup (GL (Fin 2) ℝ)) [Γ.HasDetPlusMinusOne] : GradedMonoid.GOne (ModularForm Γ) where diff --git a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean index 5d38f28dbec919..dcd9a8cd6975d3 100644 --- a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean +++ b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean @@ -6,7 +6,7 @@ Authors: Chris Birkbeck module public import Mathlib.NumberTheory.ModularForms.QExpansion -public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.QExpansion /-! diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index 5bec8502b02a13..c283e2a4742ba4 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -10,7 +10,7 @@ public import Mathlib.Analysis.Normed.Ring.InfiniteProd public import Mathlib.NumberTheory.ModularForms.DedekindEta public import Mathlib.NumberTheory.ModularForms.Basic public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.E2.Transform -public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic public import Mathlib.NumberTheory.ModularForms.QExpansion /-! @@ -211,15 +211,13 @@ lemma discriminant_qExpansion_coeff_one : (qExpansion 1 Δ).coeff 1 = 1 := by have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) 1 := Metric.mem_ball_self one_pos calc (qExpansion 1 Δ).coeff 1 = derivWithin (cuspFunction 1 Δ) (Metric.ball 0 1) 0 := by - simp [qExpansion_coeff, iteratedDeriv_succ, iteratedDeriv_zero, - ← derivWithin_of_isOpen Metric.isOpen_ball hmem] + simp [qExpansion_coeff, ← derivWithin_of_isOpen Metric.isOpen_ball hmem] _ = derivWithin (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 1) 0 := derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem) _ = 1 := by - rw [derivWithin_fun_mul (s := Metric.ball 0 1) differentiableWithinAt_id' + simp [derivWithin_fun_mul differentiableWithinAt_id' (differentiableOn_tprod_one_sub_pow_pow 24 _ hmem), derivWithin_id' _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] - simp end diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean index 4c02bb54420f53..300dfb9bd5b2e7 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean @@ -10,7 +10,7 @@ public import Mathlib.Analysis.SpecialFunctions.Trigonometric.Cotangent public import Mathlib.NumberTheory.LSeries.Dirichlet public import Mathlib.NumberTheory.LSeries.HurwitzZetaValues public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Basic -public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic public import Mathlib.NumberTheory.TsumDivisorsAntidiagonal import Mathlib.Topology.EMetricSpace.Paracompact diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/Basic.lean similarity index 100% rename from Mathlib/NumberTheory/ModularForms/LevelOne.lean rename to Mathlib/NumberTheory/ModularForms/LevelOne/Basic.lean diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/DimensionFormula.lean similarity index 100% rename from Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean rename to Mathlib/NumberTheory/ModularForms/LevelOne/DimensionFormula.lean diff --git a/Mathlib/NumberTheory/ModularForms/GradedRing.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/GradedRing.lean similarity index 82% rename from Mathlib/NumberTheory/ModularForms/GradedRing.lean rename to Mathlib/NumberTheory/ModularForms/LevelOne/GradedRing.lean index 8c4e365a615dee..628e02aedd3126 100644 --- a/Mathlib/NumberTheory/ModularForms/GradedRing.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/GradedRing.lean @@ -5,7 +5,7 @@ Authors: Chris Birkbeck -/ module -public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula /-! # The graded ring of level-1 modular forms @@ -21,7 +21,7 @@ level-1 modular forms, beyond those that fall out of the dimension formula direc ring `⨁ k, ModularForm 𝒮ℒ k`. -/ -@[expose] public noncomputable section +public noncomputable section open UpperHalfPlane ModularForm ModularFormClass MatrixGroups EisensteinSeries @@ -33,26 +33,19 @@ private noncomputable def E₄CubeSubE₆SqForm : ModularForm 𝒮ℒ 12 := private lemma E₄CubeSubE₆SqForm_apply (z : ℍ) : E₄CubeSubE₆SqForm z = E₄ z ^ 3 - E₆ z ^ 2 := by - change ⇑(E₄.pow 3) z - ⇑(E₆.pow 2) z = _ - rw [coe_pow, coe_pow] - rfl + simp only [E₄CubeSubE₆SqForm, coe_mcast, coe_pow, sub_apply, Pi.pow_apply] private lemma E₄CubeSubE₆SqForm_qExpansion_eq : qExpansion 1 E₄CubeSubE₆SqForm = qExpansion 1 E₄ * qExpansion 1 E₄ * qExpansion 1 E₄ - qExpansion 1 E₆ * qExpansion 1 E₆ := by - rw [show qExpansion 1 E₄CubeSubE₆SqForm = - qExpansion 1 (E₄.pow 3) - qExpansion 1 (E₆.pow 2) from - ModularForm.qExpansion_sub one_pos one_mem_strictPeriods_SL - (ModularForm.mcast (by decide) (E₄.pow 3)) - (ModularForm.mcast (by decide) (E₆.pow 2)), - ModularForm.qExpansion_pow one_pos one_mem_strictPeriods_SL E₄ 3, - ModularForm.qExpansion_pow one_pos one_mem_strictPeriods_SL E₆ 2] + simp only [E₄CubeSubE₆SqForm, coe_sub, coe_mcast, + ModularForm.qExpansion_sub one_pos one_mem_strictPeriods_SL, + ModularForm.qExpansion_pow one_pos one_mem_strictPeriods_SL] ring private lemma E₄CubeSubE₆SqForm_isCuspForm : IsCuspForm E₄CubeSubE₆SqForm := by - refine (isCuspForm_iff_coeffZero_eq_zero _).mpr ?_ - rw [E₄CubeSubE₆SqForm_qExpansion_eq] - simp [PowerSeries.coeff_mul, -PowerSeries.coeff_zero_eq_constantCoeff, + simp [isCuspForm_iff_coeffZero_eq_zero, E₄CubeSubE₆SqForm_qExpansion_eq, + PowerSeries.coeff_mul, -PowerSeries.coeff_zero_eq_constantCoeff, E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] private lemma E₄CubeSubE₆SqForm_qExpansion_coeff_one : @@ -64,7 +57,7 @@ private lemma E₄CubeSubE₆SqForm_qExpansion_coeff_one : /-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ theorem discriminant_eq_E₄_cube_sub_E₆_sq (z : ℍ) : - discriminant z = (1 / 1728) * (E₄ z ^ 3 - E₆ z ^ 2) := by + discriminant z = (E₄ z ^ 3 - E₆ z ^ 2) / 1728 := by obtain ⟨g, hg⟩ := E₄CubeSubE₆SqForm_isCuspForm obtain ⟨c, hc⟩ := CuspForm.exists_smul_discriminant_of_weight_eq_twelve g have hgE : (g : ℍ → ℂ) = E₄CubeSubE₆SqForm := congrArg DFunLike.coe hg diff --git a/Mathlib/NumberTheory/ModularForms/NormTrace.lean b/Mathlib/NumberTheory/ModularForms/NormTrace.lean index 4b4b9fe043873c..f09510a9db3449 100644 --- a/Mathlib/NumberTheory/ModularForms/NormTrace.lean +++ b/Mathlib/NumberTheory/ModularForms/NormTrace.lean @@ -5,7 +5,7 @@ Authors: David Loeffler -/ module -public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic /-! # Norm and trace maps diff --git a/Mathlib/NumberTheory/ModularForms/QExpansion.lean b/Mathlib/NumberTheory/ModularForms/QExpansion.lean index 0dec76a41cf843..8e37b6c2d42aee 100644 --- a/Mathlib/NumberTheory/ModularForms/QExpansion.lean +++ b/Mathlib/NumberTheory/ModularForms/QExpansion.lean @@ -630,6 +630,34 @@ lemma qExpansion_of_pow [Γ.HasDetPlusMinusOne] (hh : 0 < h) end ModularForm +namespace ModularFormClass + +@[deprecated (since := "2026-05-05")] +protected alias cuspFunction_smul := ModularForm.cuspFunction_smul + +@[deprecated (since := "2026-05-05")] +protected alias cuspFunction_neg := ModularForm.cuspFunction_neg + +@[deprecated (since := "2026-05-05")] +protected alias cuspFunction_add := ModularForm.cuspFunction_add + +@[deprecated (since := "2026-05-05")] +protected alias cuspFunction_sub := ModularForm.cuspFunction_sub + +@[deprecated (since := "2026-05-05")] +protected alias qExpansion_smul := ModularForm.qExpansion_smul + +@[deprecated (since := "2026-05-05")] +protected alias qExpansion_neg := ModularForm.qExpansion_neg + +@[deprecated (since := "2026-05-05")] +protected alias qExpansion_add := ModularForm.qExpansion_add + +@[deprecated (since := "2026-05-05")] +protected alias qExpansion_sub := ModularForm.qExpansion_sub + +end ModularFormClass + end ring section uniqueness From c64e68598f5f6373ce20c1ee50427d09c064948f Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 08:39:14 +0100 Subject: [PATCH 32/49] fix --- Mathlib.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Mathlib.lean b/Mathlib.lean index 7bd94308067813..849907fae954c3 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5668,7 +5668,6 @@ public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.MDifferentiable public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.QExpansion public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Summable public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.UniformConvergence -public import Mathlib.NumberTheory.ModularForms.GradedRing public import Mathlib.NumberTheory.ModularForms.Identities public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Bounds public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Manifold From 344eb2101db1d07a40d1ff914cdd83612bc9016d Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 08:46:12 +0100 Subject: [PATCH 33/49] fix: restore deprecation shims for files moved into LevelOne/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `LevelOne.lean` and `DimensionFormulas/LevelOne.lean` existed on master, so moving their content into `LevelOne/Basic.lean` and `LevelOne/DimensionFormula.lean` must leave deprecation shims at the old paths — otherwise `Mathlib.lean`'s existing imports of those paths point at missing files and CI fails with `bad import`. Each shim is a `module -- shake: keep-all` stub that `public import`s the new location plus `deprecated_module ... (since := "2026-05-05")`. Note: `GradedRing.lean` was added in this PR (no master version), so no shim is needed for it. --- .../ModularForms/DimensionFormulas/LevelOne.lean | 12 ++++++++++++ Mathlib/NumberTheory/ModularForms/LevelOne.lean | 12 ++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean create mode 100644 Mathlib/NumberTheory/ModularForms/LevelOne.lean diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean new file mode 100644 index 00000000000000..f8c47807bd1cdf --- /dev/null +++ b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean @@ -0,0 +1,12 @@ +/- +Copyright (c) 2026 Chris Birkbeck. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Birkbeck +-/ +module -- shake: keep-all + +public import Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula +public import Mathlib.Tactic.Linter.DeprecatedModule + +deprecated_module "Use `Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula` instead." + (since := "2026-05-05") diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne.lean new file mode 100644 index 00000000000000..3e348cc516da4a --- /dev/null +++ b/Mathlib/NumberTheory/ModularForms/LevelOne.lean @@ -0,0 +1,12 @@ +/- +Copyright (c) 2024 Chris Birkbeck. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Birkbeck +-/ +module -- shake: keep-all + +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic +public import Mathlib.Tactic.Linter.DeprecatedModule + +deprecated_module "Use `Mathlib.NumberTheory.ModularForms.LevelOne.Basic` instead." + (since := "2026-05-05") From ce615cc0e5da65d10846699739b49d576e23761c Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 09:05:20 +0100 Subject: [PATCH 34/49] ci: trigger rebuild From 79af9eb99403c2215388cd5ec0038575d82c8d7b Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 10:19:07 +0100 Subject: [PATCH 35/49] fix: drop in-PR deprecation shims so git rename-detection preserves history Per loefflerd's followup on this PR: > If the old file doesn't vanish entirely, but gets reduced to a one-line > deprecation stub, then Git treats the newly-relocated file as if it were > freshly created. So `LevelOne.lean` and `DimensionFormulas/LevelOne.lean` are simply removed here (the move into `LevelOne/Basic.lean` and `LevelOne/DimensionFormula.lean` preserves git history). A separate follow-up PR will reintroduce deprecation shims at those old paths for downstream users. `Mathlib.lean` updated via `lake exe mk_all`. --- Mathlib.lean | 2 -- .../ModularForms/DimensionFormulas/LevelOne.lean | 12 ------------ Mathlib/NumberTheory/ModularForms/LevelOne.lean | 12 ------------ 3 files changed, 26 deletions(-) delete mode 100644 Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean delete mode 100644 Mathlib/NumberTheory/ModularForms/LevelOne.lean diff --git a/Mathlib.lean b/Mathlib.lean index f2fdcbc5d97c5a..30c41021072211 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5665,7 +5665,6 @@ public import Mathlib.NumberTheory.ModularForms.Cusps public import Mathlib.NumberTheory.ModularForms.DedekindEta public import Mathlib.NumberTheory.ModularForms.Delta public import Mathlib.NumberTheory.ModularForms.Derivative -public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.LevelOne public import Mathlib.NumberTheory.ModularForms.Discriminant public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Basic public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Defs @@ -5683,7 +5682,6 @@ public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Bounds public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Manifold public import Mathlib.NumberTheory.ModularForms.JacobiTheta.OneVariable public import Mathlib.NumberTheory.ModularForms.JacobiTheta.TwoVariable -public import Mathlib.NumberTheory.ModularForms.LevelOne public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic public import Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula public import Mathlib.NumberTheory.ModularForms.LevelOne.GradedRing diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean deleted file mode 100644 index f8c47807bd1cdf..00000000000000 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ /dev/null @@ -1,12 +0,0 @@ -/- -Copyright (c) 2026 Chris Birkbeck. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Chris Birkbeck --/ -module -- shake: keep-all - -public import Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula -public import Mathlib.Tactic.Linter.DeprecatedModule - -deprecated_module "Use `Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula` instead." - (since := "2026-05-05") diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne.lean deleted file mode 100644 index 3e348cc516da4a..00000000000000 --- a/Mathlib/NumberTheory/ModularForms/LevelOne.lean +++ /dev/null @@ -1,12 +0,0 @@ -/- -Copyright (c) 2024 Chris Birkbeck. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Chris Birkbeck --/ -module -- shake: keep-all - -public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic -public import Mathlib.Tactic.Linter.DeprecatedModule - -deprecated_module "Use `Mathlib.NumberTheory.ModularForms.LevelOne.Basic` instead." - (since := "2026-05-05") From 94cdc0c783d5ac9aa9b54f70c0c3e0799ac698ce Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 11:13:08 +0100 Subject: [PATCH 36/49] feat(NumberTheory/ModularForms): Sturm bound for level-1 modular forms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A modular form `f` of weight `k` for `SL(2, ℤ)` whose first `⌊k/12⌋ + 1` q-expansion coefficients all vanish must be identically zero. The proof iterates `CuspForm.discriminantEquiv` (cusp forms ≃ modular forms of weight `k - 12` via division by `Δ`): a sufficiently-vanishing form is divisible by a power of `Δ`, eventually landing in negative weight where `ModularFormClass.levelOne_neg_weight_eq_zero` finishes. * `ModularForm.eq_zero_of_qExpansion_coeff_zero_lt` (private auxiliary form) * `ModularForm.sturm_bound_levelOne` (the main theorem) --- Mathlib.lean | 1 + .../ModularForms/LevelOne/SturmBound.lean | 128 ++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean diff --git a/Mathlib.lean b/Mathlib.lean index 30c41021072211..02eb53bf377624 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5685,6 +5685,7 @@ public import Mathlib.NumberTheory.ModularForms.JacobiTheta.TwoVariable public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic public import Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula public import Mathlib.NumberTheory.ModularForms.LevelOne.GradedRing +public import Mathlib.NumberTheory.ModularForms.LevelOne.SturmBound public import Mathlib.NumberTheory.ModularForms.NormTrace public import Mathlib.NumberTheory.ModularForms.Petersson public import Mathlib.NumberTheory.ModularForms.ProperlyDiscontinuous diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean new file mode 100644 index 00000000000000..78c6549ea770d9 --- /dev/null +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean @@ -0,0 +1,128 @@ +/- +Copyright (c) 2026 Chris Birkbeck. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Birkbeck +-/ +module + +public import Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula + +/-! +# The Sturm bound for level-1 modular forms + +This file proves the *Sturm bound* for level-1 modular forms: a modular form of weight `k` for +`SL(2, ℤ)` whose first `⌊k/12⌋ + 1` q-expansion coefficients all vanish must be identically zero. + +The proof iterates the isomorphism +`CuspForm.discriminantEquiv : CuspForm 𝒮ℒ k ≃ₗ[ℂ] ModularForm 𝒮ℒ (k - 12)` +(division by the modular discriminant `Δ`): a sufficiently-vanishing form is divisible by a power +of `Δ`, landing eventually in negative weight where everything is zero. + +## Main results + +* `ModularForm.eq_zero_of_qExpansion_coeff_zero_lt`: the auxiliary form of the Sturm bound, stated + in terms of an integer bound `n` with `k < 12 * n`. +* `ModularForm.sturm_bound_levelOne`: the Sturm bound stated in the standard form: if every + coefficient of `q^i` in `qExpansion 1 f` with `12 * i ≤ k` is zero, then `f = 0`. +-/ + +@[expose] public noncomputable section + +open UpperHalfPlane ModularForm CuspForm MatrixGroups + +namespace ModularForm + +private lemma analyticAt_cuspFunction_discriminant : + AnalyticAt ℂ (cuspFunction 1 ModularForm.discriminant) 0 := by + have h := ModularFormClass.analyticAt_cuspFunction_zero + (CuspForm.discriminant : CuspForm 𝒮ℒ 12) one_pos one_mem_strictPeriods_SL + rwa [CuspForm.coe_discriminant] at h + +private lemma qExpansion_eq_qExpansion_discriminant_mul {k : ℤ} (f : ModularForm 𝒮ℒ k) + (hcusp : (qExpansion 1 f).coeff 0 = 0) : + qExpansion 1 f = qExpansion 1 ModularForm.discriminant * + qExpansion 1 (CuspForm.discriminantEquiv (toCuspForm f hcusp)) := by + set g := CuspForm.discriminantEquiv (toCuspForm f hcusp) with hg_def + have hsymm : CuspForm.discriminantEquiv.symm g = toCuspForm f hcusp := by simp [hg_def] + have hfun_z : ∀ z, (f : ℍ → ℂ) z = ModularForm.discriminant z * g z := by + intro z + have hCD : CuspForm.ofMulDiscriminant g = toCuspForm f hcusp := hsymm + have h1 := CuspForm.ofMulDiscriminant_apply g z + rw [hCD, toCuspForm_apply] at h1 + exact h1 + have hfun : (f : ℍ → ℂ) = ModularForm.discriminant * (g : ℍ → ℂ) := by + funext z; rw [Pi.mul_apply]; exact hfun_z z + rw [hfun] + exact UpperHalfPlane.qExpansion_mul analyticAt_cuspFunction_discriminant + (ModularFormClass.analyticAt_cuspFunction_zero g one_pos one_mem_strictPeriods_SL) + +private lemma orderOf_qExpansion_discriminant : + (qExpansion 1 ModularForm.discriminant).order = 1 := by + refine PowerSeries.order_eq_nat.mpr ⟨?_, ?_⟩ + · rw [ModularForm.discriminant_qExpansion_coeff_one] + exact one_ne_zero + · intro i hi + interval_cases i + have hcusp : IsCuspForm ((CuspForm.discriminant : ModularForm 𝒮ℒ 12)) := + ⟨CuspForm.discriminant, rfl⟩ + have h0 := (isCuspForm_iff_coeffZero_eq_zero + ((CuspForm.discriminant : ModularForm 𝒮ℒ 12))).mp hcusp + rwa [show ((CuspForm.discriminant : ModularForm 𝒮ℒ 12) : ℍ → ℂ) = + ModularForm.discriminant from CuspForm.coe_discriminant] at h0 + +private lemma eq_zero_of_qExpansion_coeff_zero_lt : + ∀ (n : ℕ) {k : ℤ} (f : ModularForm 𝒮ℒ k), + k < 12 * n → (∀ i < n, (qExpansion 1 f).coeff i = 0) → f = 0 := by + intro n + induction n with + | zero => + intro k f hk _ + push_cast at hk + rw [← coe_eq_zero_iff] + exact ModularFormClass.levelOne_neg_weight_eq_zero (by omega) f + | succ n ih => + intro k f hk hcoeff + have h0 : (qExpansion 1 f).coeff 0 = 0 := hcoeff 0 (Nat.zero_lt_succ n) + set g := CuspForm.discriminantEquiv (toCuspForm f h0) with hg_def + have hqE : qExpansion 1 f = + qExpansion 1 ModularForm.discriminant * qExpansion 1 g := + qExpansion_eq_qExpansion_discriminant_mul f h0 + have hf_order : ↑(n + 1 : ℕ) ≤ (qExpansion 1 f).order := + PowerSeries.nat_le_order _ _ hcoeff + have hg_order : ↑(n : ℕ) ≤ (qExpansion 1 g).order := by + have hmul : (qExpansion 1 f).order = 1 + (qExpansion 1 g).order := by + rw [hqE, PowerSeries.order_mul, orderOf_qExpansion_discriminant] + rw [hmul] at hf_order + have h1 : (1 : ℕ∞) + ↑n ≤ 1 + (qExpansion 1 g).order := by + have heq : ((n + 1 : ℕ) : ℕ∞) = 1 + ↑n := by push_cast; ring + rw [← heq]; exact hf_order + exact (WithTop.add_le_add_iff_left (by simp : (1 : ℕ∞) ≠ ⊤)).mp h1 + have hgcoeff : ∀ i < n, (qExpansion 1 g).coeff i = 0 := fun i hi => + PowerSeries.coeff_of_lt_order _ (lt_of_lt_of_le (by exact_mod_cast hi) hg_order) + have hk' : k - 12 < 12 * (n : ℤ) := by push_cast at hk; linarith + have hg_zero : g = 0 := ih g hk' hgcoeff + have hf' : toCuspForm f h0 = 0 := by + apply CuspForm.discriminantEquiv.injective + simpa [← hg_def] using hg_zero + ext z + have hz := DFunLike.congr_fun hf' z + simpa [toCuspForm_apply] using hz + +/-- **Sturm bound for level-1 modular forms.** If a modular form `f` of weight `k` for `SL(2, ℤ)` +has zero coefficient on `q^i` in its q-expansion for every `i ≥ 0` with `12 * i ≤ k`, then +`f` is identically zero. -/ +theorem sturm_bound_levelOne {k : ℤ} (f : ModularForm 𝒮ℒ k) + (h : ∀ i : ℕ, 12 * (i : ℤ) ≤ k → (qExpansion 1 f).coeff i = 0) : f = 0 := by + by_cases hk_neg : k < 0 + · rw [← coe_eq_zero_iff] + exact ModularFormClass.levelOne_neg_weight_eq_zero hk_neg f + push Not at hk_neg + refine eq_zero_of_qExpansion_coeff_zero_lt (k.toNat / 12 + 1) f ?_ fun i hi => h i ?_ + · have hkn : (k : ℤ) = k.toNat := (Int.toNat_of_nonneg hk_neg).symm + omega + · have hkn : (k : ℤ) = k.toNat := (Int.toNat_of_nonneg hk_neg).symm + omega + +end ModularForm + +end From acf000cb6c116b63a8f40de9279becf6b51af54b Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 11:23:35 +0100 Subject: [PATCH 37/49] =?UTF-8?q?chore:=20cleanup=20Sturm=20bound=20?= =?UTF-8?q?=E2=80=94=20inline=20single-use=20haves,=20drop=20unused=20have?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup pass via /cleanup: * `analyticAt_cuspFunction_discriminant`: term-mode via `▸`. * `qExpansion_eq_qExpansion_discriminant_mul`: drop `hfun_z` intermediate, inline `h1`. * `eq_zero_of_qExpansion_coeff_zero_lt`: inline `hqE`/`hf_order`/`hgcoeff`/`hz`, collapse the ℕ∞ arithmetic, term-mode `hf'`. * `sturm_bound_levelOne`: drop two unused `hkn` haves — `omega` handles `Int.toNat` directly given the nonneg hypothesis. 128 → 113 lines. --- .../ModularForms/LevelOne/SturmBound.lean | 51 +++++++------------ 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean index 78c6549ea770d9..0a17b624a9e230 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean @@ -20,8 +20,6 @@ of `Δ`, landing eventually in negative weight where everything is zero. ## Main results -* `ModularForm.eq_zero_of_qExpansion_coeff_zero_lt`: the auxiliary form of the Sturm bound, stated - in terms of an integer bound `n` with `k < 12 * n`. * `ModularForm.sturm_bound_levelOne`: the Sturm bound stated in the standard form: if every coefficient of `q^i` in `qExpansion 1 f` with `12 * i ≤ k` is zero, then `f = 0`. -/ @@ -33,10 +31,9 @@ open UpperHalfPlane ModularForm CuspForm MatrixGroups namespace ModularForm private lemma analyticAt_cuspFunction_discriminant : - AnalyticAt ℂ (cuspFunction 1 ModularForm.discriminant) 0 := by - have h := ModularFormClass.analyticAt_cuspFunction_zero + AnalyticAt ℂ (cuspFunction 1 ModularForm.discriminant) 0 := + CuspForm.coe_discriminant ▸ ModularFormClass.analyticAt_cuspFunction_zero (CuspForm.discriminant : CuspForm 𝒮ℒ 12) one_pos one_mem_strictPeriods_SL - rwa [CuspForm.coe_discriminant] at h private lemma qExpansion_eq_qExpansion_discriminant_mul {k : ℤ} (f : ModularForm 𝒮ℒ k) (hcusp : (qExpansion 1 f).coeff 0 = 0) : @@ -44,14 +41,12 @@ private lemma qExpansion_eq_qExpansion_discriminant_mul {k : ℤ} (f : ModularFo qExpansion 1 (CuspForm.discriminantEquiv (toCuspForm f hcusp)) := by set g := CuspForm.discriminantEquiv (toCuspForm f hcusp) with hg_def have hsymm : CuspForm.discriminantEquiv.symm g = toCuspForm f hcusp := by simp [hg_def] - have hfun_z : ∀ z, (f : ℍ → ℂ) z = ModularForm.discriminant z * g z := by - intro z - have hCD : CuspForm.ofMulDiscriminant g = toCuspForm f hcusp := hsymm + have hfun : (f : ℍ → ℂ) = ModularForm.discriminant * (g : ℍ → ℂ) := by + funext z have h1 := CuspForm.ofMulDiscriminant_apply g z - rw [hCD, toCuspForm_apply] at h1 + rw [show CuspForm.ofMulDiscriminant g = toCuspForm f hcusp from hsymm, + toCuspForm_apply] at h1 exact h1 - have hfun : (f : ℍ → ℂ) = ModularForm.discriminant * (g : ℍ → ℂ) := by - funext z; rw [Pi.mul_apply]; exact hfun_z z rw [hfun] exact UpperHalfPlane.qExpansion_mul analyticAt_cuspFunction_discriminant (ModularFormClass.analyticAt_cuspFunction_zero g one_pos one_mem_strictPeriods_SL) @@ -84,29 +79,21 @@ private lemma eq_zero_of_qExpansion_coeff_zero_lt : intro k f hk hcoeff have h0 : (qExpansion 1 f).coeff 0 = 0 := hcoeff 0 (Nat.zero_lt_succ n) set g := CuspForm.discriminantEquiv (toCuspForm f h0) with hg_def - have hqE : qExpansion 1 f = - qExpansion 1 ModularForm.discriminant * qExpansion 1 g := - qExpansion_eq_qExpansion_discriminant_mul f h0 - have hf_order : ↑(n + 1 : ℕ) ≤ (qExpansion 1 f).order := - PowerSeries.nat_le_order _ _ hcoeff have hg_order : ↑(n : ℕ) ≤ (qExpansion 1 g).order := by have hmul : (qExpansion 1 f).order = 1 + (qExpansion 1 g).order := by - rw [hqE, PowerSeries.order_mul, orderOf_qExpansion_discriminant] - rw [hmul] at hf_order - have h1 : (1 : ℕ∞) + ↑n ≤ 1 + (qExpansion 1 g).order := by + rw [qExpansion_eq_qExpansion_discriminant_mul f h0, PowerSeries.order_mul, + orderOf_qExpansion_discriminant] + have hf_order : (1 : ℕ∞) + ↑n ≤ 1 + (qExpansion 1 g).order := by have heq : ((n + 1 : ℕ) : ℕ∞) = 1 + ↑n := by push_cast; ring - rw [← heq]; exact hf_order - exact (WithTop.add_le_add_iff_left (by simp : (1 : ℕ∞) ≠ ⊤)).mp h1 - have hgcoeff : ∀ i < n, (qExpansion 1 g).coeff i = 0 := fun i hi => + rw [← heq, ← hmul] + exact PowerSeries.nat_le_order _ _ hcoeff + exact (WithTop.add_le_add_iff_left (by simp : (1 : ℕ∞) ≠ ⊤)).mp hf_order + have hg_zero : g = 0 := ih g (by push_cast at hk; linarith) fun i hi => PowerSeries.coeff_of_lt_order _ (lt_of_lt_of_le (by exact_mod_cast hi) hg_order) - have hk' : k - 12 < 12 * (n : ℤ) := by push_cast at hk; linarith - have hg_zero : g = 0 := ih g hk' hgcoeff - have hf' : toCuspForm f h0 = 0 := by - apply CuspForm.discriminantEquiv.injective - simpa [← hg_def] using hg_zero + have hf' : toCuspForm f h0 = 0 := + CuspForm.discriminantEquiv.injective (by simpa [← hg_def] using hg_zero) ext z - have hz := DFunLike.congr_fun hf' z - simpa [toCuspForm_apply] using hz + simpa [toCuspForm_apply] using DFunLike.congr_fun hf' z /-- **Sturm bound for level-1 modular forms.** If a modular form `f` of weight `k` for `SL(2, ℤ)` has zero coefficient on `q^i` in its q-expansion for every `i ≥ 0` with `12 * i ≤ k`, then @@ -118,10 +105,8 @@ theorem sturm_bound_levelOne {k : ℤ} (f : ModularForm 𝒮ℒ k) exact ModularFormClass.levelOne_neg_weight_eq_zero hk_neg f push Not at hk_neg refine eq_zero_of_qExpansion_coeff_zero_lt (k.toNat / 12 + 1) f ?_ fun i hi => h i ?_ - · have hkn : (k : ℤ) = k.toNat := (Int.toNat_of_nonneg hk_neg).symm - omega - · have hkn : (k : ℤ) = k.toNat := (Int.toNat_of_nonneg hk_neg).symm - omega + · omega + · omega end ModularForm From a15bb98f9d5abe8843d7270b87072a954ab4c791 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 11:28:17 +0100 Subject: [PATCH 38/49] =?UTF-8?q?chore:=20simplify=20Sturm=20bound=20?= =?UTF-8?q?=E2=80=94=20extract=20`eq=5Fzero=5Fof=5Fneg=5Fweight`,=20drop?= =?UTF-8?q?=20`interval=5Fcases`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /simplify pass: * Extract `eq_zero_of_neg_weight` private helper to dedupe the `coe_eq_zero_iff` + `levelOne_neg_weight_eq_zero` pattern (used 2×). * `WithTop.add_le_add_iff_left` → `ENat.add_le_add_iff_left` (more idiomatic for the ℕ∞ type). * `interval_cases i` (with `i < 1`) → `obtain rfl : i = 0 := by omega` (lighter machinery for a single value). * Inline single-use `hcusp` in `orderOf_qExpansion_discriminant`. --- .../ModularForms/LevelOne/SturmBound.lean | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean index 0a17b624a9e230..c6e245b794acf8 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean @@ -35,6 +35,9 @@ private lemma analyticAt_cuspFunction_discriminant : CuspForm.coe_discriminant ▸ ModularFormClass.analyticAt_cuspFunction_zero (CuspForm.discriminant : CuspForm 𝒮ℒ 12) one_pos one_mem_strictPeriods_SL +private lemma eq_zero_of_neg_weight {k : ℤ} (hk : k < 0) (f : ModularForm 𝒮ℒ k) : f = 0 := + coe_eq_zero_iff f |>.mp <| ModularFormClass.levelOne_neg_weight_eq_zero hk f + private lemma qExpansion_eq_qExpansion_discriminant_mul {k : ℤ} (f : ModularForm 𝒮ℒ k) (hcusp : (qExpansion 1 f).coeff 0 = 0) : qExpansion 1 f = qExpansion 1 ModularForm.discriminant * @@ -57,11 +60,9 @@ private lemma orderOf_qExpansion_discriminant : · rw [ModularForm.discriminant_qExpansion_coeff_one] exact one_ne_zero · intro i hi - interval_cases i - have hcusp : IsCuspForm ((CuspForm.discriminant : ModularForm 𝒮ℒ 12)) := - ⟨CuspForm.discriminant, rfl⟩ + obtain rfl : i = 0 := by omega have h0 := (isCuspForm_iff_coeffZero_eq_zero - ((CuspForm.discriminant : ModularForm 𝒮ℒ 12))).mp hcusp + ((CuspForm.discriminant : ModularForm 𝒮ℒ 12))).mp ⟨CuspForm.discriminant, rfl⟩ rwa [show ((CuspForm.discriminant : ModularForm 𝒮ℒ 12) : ℍ → ℂ) = ModularForm.discriminant from CuspForm.coe_discriminant] at h0 @@ -73,8 +74,7 @@ private lemma eq_zero_of_qExpansion_coeff_zero_lt : | zero => intro k f hk _ push_cast at hk - rw [← coe_eq_zero_iff] - exact ModularFormClass.levelOne_neg_weight_eq_zero (by omega) f + exact eq_zero_of_neg_weight (by omega) f | succ n ih => intro k f hk hcoeff have h0 : (qExpansion 1 f).coeff 0 = 0 := hcoeff 0 (Nat.zero_lt_succ n) @@ -87,7 +87,7 @@ private lemma eq_zero_of_qExpansion_coeff_zero_lt : have heq : ((n + 1 : ℕ) : ℕ∞) = 1 + ↑n := by push_cast; ring rw [← heq, ← hmul] exact PowerSeries.nat_le_order _ _ hcoeff - exact (WithTop.add_le_add_iff_left (by simp : (1 : ℕ∞) ≠ ⊤)).mp hf_order + exact (ENat.add_le_add_iff_left (by simp : (1 : ℕ∞) ≠ ⊤)).mp hf_order have hg_zero : g = 0 := ih g (by push_cast at hk; linarith) fun i hi => PowerSeries.coeff_of_lt_order _ (lt_of_lt_of_le (by exact_mod_cast hi) hg_order) have hf' : toCuspForm f h0 = 0 := @@ -101,8 +101,7 @@ has zero coefficient on `q^i` in its q-expansion for every `i ≥ 0` with `12 * theorem sturm_bound_levelOne {k : ℤ} (f : ModularForm 𝒮ℒ k) (h : ∀ i : ℕ, 12 * (i : ℤ) ≤ k → (qExpansion 1 f).coeff i = 0) : f = 0 := by by_cases hk_neg : k < 0 - · rw [← coe_eq_zero_iff] - exact ModularFormClass.levelOne_neg_weight_eq_zero hk_neg f + · exact eq_zero_of_neg_weight hk_neg f push Not at hk_neg refine eq_zero_of_qExpansion_coeff_zero_lt (k.toNat / 12 + 1) f ?_ fun i hi => h i ?_ · omega From b98bf904d53cc51fd79cd969d08c7f615a8b8d2f Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 11:33:20 +0100 Subject: [PATCH 39/49] =?UTF-8?q?chore:=20drop=20redundant=20wrappers=20?= =?UTF-8?q?=E2=80=94=20use=20existing=20mathlib=20API=20directly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both `analyticAt_cuspFunction_discriminant` and `eq_zero_of_neg_weight` were thin wrappers around existing mathlib API: * `analyticAt_cuspFunction_discriminant` was a one-use specialization of `ModularFormClass.analyticAt_cuspFunction_zero` for `Δ`. Inlined. * `eq_zero_of_neg_weight` (`f = 0` for negative weight) follows from `ModularForm.levelOne_neg_weight_rank_zero` plus `rank_zero_iff_forall_zero`. --- .../ModularForms/LevelOne/SturmBound.lean | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean index c6e245b794acf8..5a38b105c2d3c3 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean @@ -30,14 +30,6 @@ open UpperHalfPlane ModularForm CuspForm MatrixGroups namespace ModularForm -private lemma analyticAt_cuspFunction_discriminant : - AnalyticAt ℂ (cuspFunction 1 ModularForm.discriminant) 0 := - CuspForm.coe_discriminant ▸ ModularFormClass.analyticAt_cuspFunction_zero - (CuspForm.discriminant : CuspForm 𝒮ℒ 12) one_pos one_mem_strictPeriods_SL - -private lemma eq_zero_of_neg_weight {k : ℤ} (hk : k < 0) (f : ModularForm 𝒮ℒ k) : f = 0 := - coe_eq_zero_iff f |>.mp <| ModularFormClass.levelOne_neg_weight_eq_zero hk f - private lemma qExpansion_eq_qExpansion_discriminant_mul {k : ℤ} (f : ModularForm 𝒮ℒ k) (hcusp : (qExpansion 1 f).coeff 0 = 0) : qExpansion 1 f = qExpansion 1 ModularForm.discriminant * @@ -51,7 +43,9 @@ private lemma qExpansion_eq_qExpansion_discriminant_mul {k : ℤ} (f : ModularFo toCuspForm_apply] at h1 exact h1 rw [hfun] - exact UpperHalfPlane.qExpansion_mul analyticAt_cuspFunction_discriminant + exact UpperHalfPlane.qExpansion_mul + (CuspForm.coe_discriminant ▸ ModularFormClass.analyticAt_cuspFunction_zero + (CuspForm.discriminant : CuspForm 𝒮ℒ 12) one_pos one_mem_strictPeriods_SL) (ModularFormClass.analyticAt_cuspFunction_zero g one_pos one_mem_strictPeriods_SL) private lemma orderOf_qExpansion_discriminant : @@ -74,7 +68,8 @@ private lemma eq_zero_of_qExpansion_coeff_zero_lt : | zero => intro k f hk _ push_cast at hk - exact eq_zero_of_neg_weight (by omega) f + exact rank_zero_iff_forall_zero.mp + (ModularForm.levelOne_neg_weight_rank_zero (by omega)) f | succ n ih => intro k f hk hcoeff have h0 : (qExpansion 1 f).coeff 0 = 0 := hcoeff 0 (Nat.zero_lt_succ n) @@ -101,7 +96,7 @@ has zero coefficient on `q^i` in its q-expansion for every `i ≥ 0` with `12 * theorem sturm_bound_levelOne {k : ℤ} (f : ModularForm 𝒮ℒ k) (h : ∀ i : ℕ, 12 * (i : ℤ) ≤ k → (qExpansion 1 f).coeff i = 0) : f = 0 := by by_cases hk_neg : k < 0 - · exact eq_zero_of_neg_weight hk_neg f + · exact rank_zero_iff_forall_zero.mp (ModularForm.levelOne_neg_weight_rank_zero hk_neg) f push Not at hk_neg refine eq_zero_of_qExpansion_coeff_zero_lt (k.toNat / 12 + 1) f ?_ fun i hi => h i ?_ · omega From 5ff012d3f5b169f7379209d2e2724ea8247093dc Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 12:43:34 +0100 Subject: [PATCH 40/49] chore: deeper /cleanup pass on Sturm bound proofs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per-declaration deep golf: * `qExpansion_eq_qExpansion_discriminant_mul`: drop `set g`/`have hsymm` scaffolding; use `funext fun z ↦ simp [CuspForm.discriminantEquiv, mul_div_cancel₀ _ (discriminant_ne_zero z)]` directly. (17 → 11 lines) * `orderOf_qExpansion_discriminant`: collapse first bullet via `▸`, replace `rwa [show … from coe_discriminant]` with `simpa using h0` (since `coe_discriminant` is `@[simp]`). (11 → 8 lines) * `eq_zero_of_qExpansion_coeff_zero_lt`: restructure the ℕ∞-arithmetic block — invert the chain so `ENat.add_le_add_iff_left` runs once at the start, then a single `rw` sequence reaches `nat_le_order`. (29 → 26 lines) 107 → 95 lines. --- .../ModularForms/LevelOne/SturmBound.lean | 42 +++++++------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean index 5a38b105c2d3c3..c79b7f53e230dd 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean @@ -34,31 +34,22 @@ private lemma qExpansion_eq_qExpansion_discriminant_mul {k : ℤ} (f : ModularFo (hcusp : (qExpansion 1 f).coeff 0 = 0) : qExpansion 1 f = qExpansion 1 ModularForm.discriminant * qExpansion 1 (CuspForm.discriminantEquiv (toCuspForm f hcusp)) := by - set g := CuspForm.discriminantEquiv (toCuspForm f hcusp) with hg_def - have hsymm : CuspForm.discriminantEquiv.symm g = toCuspForm f hcusp := by simp [hg_def] - have hfun : (f : ℍ → ℂ) = ModularForm.discriminant * (g : ℍ → ℂ) := by - funext z - have h1 := CuspForm.ofMulDiscriminant_apply g z - rw [show CuspForm.ofMulDiscriminant g = toCuspForm f hcusp from hsymm, - toCuspForm_apply] at h1 - exact h1 - rw [hfun] + rw [show (f : ℍ → ℂ) = ModularForm.discriminant * + (CuspForm.discriminantEquiv (toCuspForm f hcusp) : ℍ → ℂ) from funext fun z ↦ by + simp [CuspForm.discriminantEquiv, mul_div_cancel₀ _ (discriminant_ne_zero z)]] exact UpperHalfPlane.qExpansion_mul (CuspForm.coe_discriminant ▸ ModularFormClass.analyticAt_cuspFunction_zero (CuspForm.discriminant : CuspForm 𝒮ℒ 12) one_pos one_mem_strictPeriods_SL) - (ModularFormClass.analyticAt_cuspFunction_zero g one_pos one_mem_strictPeriods_SL) + (ModularFormClass.analyticAt_cuspFunction_zero _ one_pos one_mem_strictPeriods_SL) private lemma orderOf_qExpansion_discriminant : (qExpansion 1 ModularForm.discriminant).order = 1 := by - refine PowerSeries.order_eq_nat.mpr ⟨?_, ?_⟩ - · rw [ModularForm.discriminant_qExpansion_coeff_one] - exact one_ne_zero - · intro i hi - obtain rfl : i = 0 := by omega - have h0 := (isCuspForm_iff_coeffZero_eq_zero - ((CuspForm.discriminant : ModularForm 𝒮ℒ 12))).mp ⟨CuspForm.discriminant, rfl⟩ - rwa [show ((CuspForm.discriminant : ModularForm 𝒮ℒ 12) : ℍ → ℂ) = - ModularForm.discriminant from CuspForm.coe_discriminant] at h0 + refine PowerSeries.order_eq_nat.mpr + ⟨ModularForm.discriminant_qExpansion_coeff_one ▸ one_ne_zero, fun i hi => ?_⟩ + obtain rfl : i = 0 := by omega + have h0 := (isCuspForm_iff_coeffZero_eq_zero + ((CuspForm.discriminant : ModularForm 𝒮ℒ 12))).mp ⟨CuspForm.discriminant, rfl⟩ + simpa using h0 private lemma eq_zero_of_qExpansion_coeff_zero_lt : ∀ (n : ℕ) {k : ℤ} (f : ModularForm 𝒮ℒ k), @@ -75,14 +66,11 @@ private lemma eq_zero_of_qExpansion_coeff_zero_lt : have h0 : (qExpansion 1 f).coeff 0 = 0 := hcoeff 0 (Nat.zero_lt_succ n) set g := CuspForm.discriminantEquiv (toCuspForm f h0) with hg_def have hg_order : ↑(n : ℕ) ≤ (qExpansion 1 g).order := by - have hmul : (qExpansion 1 f).order = 1 + (qExpansion 1 g).order := by - rw [qExpansion_eq_qExpansion_discriminant_mul f h0, PowerSeries.order_mul, - orderOf_qExpansion_discriminant] - have hf_order : (1 : ℕ∞) + ↑n ≤ 1 + (qExpansion 1 g).order := by - have heq : ((n + 1 : ℕ) : ℕ∞) = 1 + ↑n := by push_cast; ring - rw [← heq, ← hmul] - exact PowerSeries.nat_le_order _ _ hcoeff - exact (ENat.add_le_add_iff_left (by simp : (1 : ℕ∞) ≠ ⊤)).mp hf_order + refine (ENat.add_le_add_iff_left ENat.one_ne_top (k := 1)).mp ?_ + rw [show (1 : ℕ∞) + ↑n = ((n + 1 : ℕ) : ℕ∞) by push_cast; ring, + ← orderOf_qExpansion_discriminant, ← PowerSeries.order_mul, + ← qExpansion_eq_qExpansion_discriminant_mul f h0] + exact PowerSeries.nat_le_order _ _ hcoeff have hg_zero : g = 0 := ih g (by push_cast at hk; linarith) fun i hi => PowerSeries.coeff_of_lt_order _ (lt_of_lt_of_le (by exact_mod_cast hi) hg_order) have hf' : toCuspForm f h0 = 0 := From c1065e0a8d8249cedb23ddac71b166d92e9ce937 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 13:15:49 +0100 Subject: [PATCH 41/49] chore: hoist `k` to a section variable, take `n` as a direct argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two minor cleanups suggested in review: * `variable {k : ℤ}` after `namespace ModularForm`, removing the per-lemma `{k : ℤ}` binders. * `eq_zero_of_qExpansion_coeff_zero_lt` now takes `n` as a parameter and uses `induction n generalizing k f` instead of stating `∀ n, ...` and manually `intro`-ing each case. --- .../ModularForms/LevelOne/SturmBound.lean | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean index c79b7f53e230dd..541dc2b7cabb31 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean @@ -30,11 +30,13 @@ open UpperHalfPlane ModularForm CuspForm MatrixGroups namespace ModularForm -private lemma qExpansion_eq_qExpansion_discriminant_mul {k : ℤ} (f : ModularForm 𝒮ℒ k) +variable {k : ℤ} + +private lemma qExpansion_eq_qExpansion_discriminant_mul (f : ModularForm 𝒮ℒ k) (hcusp : (qExpansion 1 f).coeff 0 = 0) : - qExpansion 1 f = qExpansion 1 ModularForm.discriminant * - qExpansion 1 (CuspForm.discriminantEquiv (toCuspForm f hcusp)) := by - rw [show (f : ℍ → ℂ) = ModularForm.discriminant * + qExpansion 1 f = qExpansion 1 discriminant * + qExpansion 1 (discriminantEquiv (toCuspForm f hcusp)) := by + rw [show (f : ℍ → ℂ) = discriminant * (CuspForm.discriminantEquiv (toCuspForm f hcusp) : ℍ → ℂ) from funext fun z ↦ by simp [CuspForm.discriminantEquiv, mul_div_cancel₀ _ (discriminant_ne_zero z)]] exact UpperHalfPlane.qExpansion_mul @@ -51,18 +53,14 @@ private lemma orderOf_qExpansion_discriminant : ((CuspForm.discriminant : ModularForm 𝒮ℒ 12))).mp ⟨CuspForm.discriminant, rfl⟩ simpa using h0 -private lemma eq_zero_of_qExpansion_coeff_zero_lt : - ∀ (n : ℕ) {k : ℤ} (f : ModularForm 𝒮ℒ k), - k < 12 * n → (∀ i < n, (qExpansion 1 f).coeff i = 0) → f = 0 := by - intro n - induction n with +private lemma eq_zero_of_qExpansion_coeff_zero_lt (n : ℕ) (f : ModularForm 𝒮ℒ k) + (hk : k < 12 * n) (hcoeff : ∀ i < n, (qExpansion 1 f).coeff i = 0) : f = 0 := by + induction n generalizing k f with | zero => - intro k f hk _ push_cast at hk exact rank_zero_iff_forall_zero.mp (ModularForm.levelOne_neg_weight_rank_zero (by omega)) f | succ n ih => - intro k f hk hcoeff have h0 : (qExpansion 1 f).coeff 0 = 0 := hcoeff 0 (Nat.zero_lt_succ n) set g := CuspForm.discriminantEquiv (toCuspForm f h0) with hg_def have hg_order : ↑(n : ℕ) ≤ (qExpansion 1 g).order := by @@ -81,7 +79,7 @@ private lemma eq_zero_of_qExpansion_coeff_zero_lt : /-- **Sturm bound for level-1 modular forms.** If a modular form `f` of weight `k` for `SL(2, ℤ)` has zero coefficient on `q^i` in its q-expansion for every `i ≥ 0` with `12 * i ≤ k`, then `f` is identically zero. -/ -theorem sturm_bound_levelOne {k : ℤ} (f : ModularForm 𝒮ℒ k) +theorem sturm_bound_levelOne (f : ModularForm 𝒮ℒ k) (h : ∀ i : ℕ, 12 * (i : ℤ) ≤ k → (qExpansion 1 f).coeff i = 0) : f = 0 := by by_cases hk_neg : k < 0 · exact rank_zero_iff_forall_zero.mp (ModularForm.levelOne_neg_weight_rank_zero hk_neg) f From c0df70562e5ff7fcb6f01482ac1b1ed2db0f642a Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 13:22:18 +0100 Subject: [PATCH 42/49] chore: hoist `f` to a section variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `variable (f : ModularForm 𝒮ℒ k)` after the namespace; per-lemma `f` binders dropped from `qExpansion_eq_qExpansion_discriminant_mul`, `eq_zero_of_qExpansion_coeff_zero_lt`, and `sturm_bound_levelOne`. The `f`-first argument order at the `eq_zero_of_qExpansion_coeff_zero_lt` call site is updated accordingly. --- .../NumberTheory/ModularForms/LevelOne/SturmBound.lean | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean index 541dc2b7cabb31..3ce24f5560c121 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean @@ -30,9 +30,9 @@ open UpperHalfPlane ModularForm CuspForm MatrixGroups namespace ModularForm -variable {k : ℤ} +variable {k : ℤ} (f : ModularForm 𝒮ℒ k) -private lemma qExpansion_eq_qExpansion_discriminant_mul (f : ModularForm 𝒮ℒ k) +private lemma qExpansion_eq_qExpansion_discriminant_mul (hcusp : (qExpansion 1 f).coeff 0 = 0) : qExpansion 1 f = qExpansion 1 discriminant * qExpansion 1 (discriminantEquiv (toCuspForm f hcusp)) := by @@ -53,7 +53,7 @@ private lemma orderOf_qExpansion_discriminant : ((CuspForm.discriminant : ModularForm 𝒮ℒ 12))).mp ⟨CuspForm.discriminant, rfl⟩ simpa using h0 -private lemma eq_zero_of_qExpansion_coeff_zero_lt (n : ℕ) (f : ModularForm 𝒮ℒ k) +private lemma eq_zero_of_qExpansion_coeff_zero_lt (n : ℕ) (hk : k < 12 * n) (hcoeff : ∀ i < n, (qExpansion 1 f).coeff i = 0) : f = 0 := by induction n generalizing k f with | zero => @@ -79,12 +79,12 @@ private lemma eq_zero_of_qExpansion_coeff_zero_lt (n : ℕ) (f : ModularForm /-- **Sturm bound for level-1 modular forms.** If a modular form `f` of weight `k` for `SL(2, ℤ)` has zero coefficient on `q^i` in its q-expansion for every `i ≥ 0` with `12 * i ≤ k`, then `f` is identically zero. -/ -theorem sturm_bound_levelOne (f : ModularForm 𝒮ℒ k) +theorem sturm_bound_levelOne (h : ∀ i : ℕ, 12 * (i : ℤ) ≤ k → (qExpansion 1 f).coeff i = 0) : f = 0 := by by_cases hk_neg : k < 0 · exact rank_zero_iff_forall_zero.mp (ModularForm.levelOne_neg_weight_rank_zero hk_neg) f push Not at hk_neg - refine eq_zero_of_qExpansion_coeff_zero_lt (k.toNat / 12 + 1) f ?_ fun i hi => h i ?_ + refine eq_zero_of_qExpansion_coeff_zero_lt f (k.toNat / 12 + 1) ?_ fun i hi => h i ?_ · omega · omega From 7ca8e7e67cd20ccaa9e38bb29ff7ec0f6d2d6071 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 13:23:02 +0100 Subject: [PATCH 43/49] =?UTF-8?q?chore:=20extract=20`f=20=3D=20=CE=94=20*?= =?UTF-8?q?=20g`=20step=20to=20a=20separate=20`have=20hfun`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoids a `simp` nested inside a `rw [show ... from ...]`. The statement of `hfun` is also self-documenting now. --- .../NumberTheory/ModularForms/LevelOne/SturmBound.lean | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean index 3ce24f5560c121..a88a8675edf8e8 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/SturmBound.lean @@ -36,9 +36,11 @@ private lemma qExpansion_eq_qExpansion_discriminant_mul (hcusp : (qExpansion 1 f).coeff 0 = 0) : qExpansion 1 f = qExpansion 1 discriminant * qExpansion 1 (discriminantEquiv (toCuspForm f hcusp)) := by - rw [show (f : ℍ → ℂ) = discriminant * - (CuspForm.discriminantEquiv (toCuspForm f hcusp) : ℍ → ℂ) from funext fun z ↦ by - simp [CuspForm.discriminantEquiv, mul_div_cancel₀ _ (discriminant_ne_zero z)]] + have hfun : (f : ℍ → ℂ) = discriminant * + (CuspForm.discriminantEquiv (toCuspForm f hcusp) : ℍ → ℂ) := by + funext z + simp [CuspForm.discriminantEquiv, mul_div_cancel₀ _ (discriminant_ne_zero z)] + rw [hfun] exact UpperHalfPlane.qExpansion_mul (CuspForm.coe_discriminant ▸ ModularFormClass.analyticAt_cuspFunction_zero (CuspForm.discriminant : CuspForm 𝒮ℒ 12) one_pos one_mem_strictPeriods_SL) From 7fcd5a0a29811c392d74097ab694018b3bbcbf7d Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 13:56:34 +0100 Subject: [PATCH 44/49] feat(NumberTheory/ModularForms): Sturm bound for finite-index subgroups (skeleton) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a skeleton PR for the Sturm bound for finite-index subgroups `𝒢 ⊆ SL(2, ℤ)`, lifting the level-one Sturm bound (#38993) via the norm map `ModularForm.norm 𝒮ℒ`. The main theorem `sturm_bound_finiteIndex` is fully proved, modulo one key q-expansion lemma `qExpansion_norm_order_ge_qExpansion_order` left as `sorry` for now: > The order of vanishing of `qExpansion 1 (norm 𝒮ℒ f)` at 0 is at least > the order of vanishing of `qExpansion 1 f`, when `1 ∈ 𝒢.strictPeriods`. To prove the lemma, decompose `N(f) = f * rest` where `rest := ∏_{q ≠ ⟦1⟧} quotientFunc f q`, show `rest` is `1`-periodic (using `T ∈ 𝒢`) and bounded at `∞` (using `f` bounded at every cusp of `𝒢`), then apply `UpperHalfPlane.qExpansion_mul` and `PowerSeries.order_mul`. - [ ] depends on: #38993 --- Mathlib.lean | 1 + .../NumberTheory/ModularForms/SturmBound.lean | 88 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 Mathlib/NumberTheory/ModularForms/SturmBound.lean diff --git a/Mathlib.lean b/Mathlib.lean index 02eb53bf377624..be2866f8e408bd 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5692,6 +5692,7 @@ public import Mathlib.NumberTheory.ModularForms.ProperlyDiscontinuous public import Mathlib.NumberTheory.ModularForms.QExpansion public import Mathlib.NumberTheory.ModularForms.SlashActions public import Mathlib.NumberTheory.ModularForms.SlashInvariantForms +public import Mathlib.NumberTheory.ModularForms.SturmBound public import Mathlib.NumberTheory.MulChar.Basic public import Mathlib.NumberTheory.MulChar.Duality public import Mathlib.NumberTheory.MulChar.Lemmas diff --git a/Mathlib/NumberTheory/ModularForms/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/SturmBound.lean new file mode 100644 index 00000000000000..51963e9ee0a5a8 --- /dev/null +++ b/Mathlib/NumberTheory/ModularForms/SturmBound.lean @@ -0,0 +1,88 @@ +/- +Copyright (c) 2026 Chris Birkbeck. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Birkbeck +-/ +module + +public import Mathlib.NumberTheory.ModularForms.LevelOne.SturmBound +public import Mathlib.NumberTheory.ModularForms.NormTrace + +/-! +# The Sturm bound for finite-index subgroups of `SL(2, ℤ)` + +This file lifts the level-one Sturm bound (`sturm_bound_levelOne`) to arbitrary finite-index +subgroups `𝒢 ⊆ SL(2, ℤ)` via the norm map +`ModularForm.norm 𝒮ℒ : ModularForm 𝒢 k → ModularForm 𝒮ℒ (k * m)` +where `m = [SL(2,ℤ) : 𝒢]`. + +## Strategy + +For `f : ModularForm 𝒢 k`, the norm `N(f) := ModularForm.norm 𝒮ℒ f` is a product over coset +representatives `γ ∈ 𝒮ℒ ⧸ 𝒢` of the slash-translates `f ∣ γ⁻¹`. By +`ModularForm.norm_eq_zero_iff`, `N(f) = 0 ↔ f = 0` as functions, so `f = 0` reduces to +`N(f) = 0`. The level-one Sturm bound applied to `N(f)` (which is a level-one form of +weight `k * m`) reduces this further to a vanishing condition on the q-expansion of +`N(f)` at `∞`. + +The bridge is the key q-expansion lemma: + +`qExpansion_norm_order_ge_qExpansion_order` : + the order of `qExpansion 1 (N f)` at `0` is at least the order of `qExpansion h_𝒢 f`, + where `h_𝒢` is the cusp width of `𝒢` at `∞`. + +## Main results + +* `ModularForm.sturm_bound_finiteIndex` : if `f : ModularForm 𝒢 k` for finite-index + `𝒢 ⊆ 𝒮ℒ` with `1 ∈ 𝒢.strictPeriods`, and the q-expansion of `f` vanishes for the first + `⌊k * [𝒮ℒ : 𝒢] / 12⌋ + 1` coefficients, then `f = 0`. + +## TODO + +* The current statement assumes `1 ∈ 𝒢.strictPeriods` (covers `Γ₀(N)`, `Γ₁(N)`, …). The + fully general version with arbitrary cusp width `h_𝒢` requires extending the proof of + `qExpansion_norm_order_ge_qExpansion_order` to interact correctly with the change-of-period + structure, which is left as future work. +-/ + +@[expose] public noncomputable section + +open UpperHalfPlane ModularForm CuspForm MatrixGroups + +namespace ModularForm + +variable {𝒢 : Subgroup (GL (Fin 2) ℝ)} [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] +variable {k : ℤ} (f : ModularForm 𝒢 k) + +/-- **Key bridge lemma.** The order of vanishing of `qExpansion 1 (N(f))` at `0` is at least +the order of vanishing of `qExpansion 1 f`, when `1 ∈ 𝒢.strictPeriods`. + +Mathematical content: write `N(f) = ∏_{γ ∈ 𝒮ℒ ⧸ 𝒢} f ∣ γ⁻¹`. The factor for the trivial coset +is `f` itself, and the remaining factors are bounded at the cusp `∞` (since `f` is bounded +at every cusp of `𝒢`). The product of bounded analytic functions, with one factor of order +`N`, has order at least `N` at `0`. -/ +private lemma qExpansion_norm_order_ge_qExpansion_order + (h𝒢 : 1 ∈ 𝒢.strictPeriods) : + (qExpansion 1 f).order ≤ (qExpansion 1 (ModularForm.norm 𝒮ℒ f)).order := by + -- TODO: prove via decomposition + -- N(f)(τ) = f(τ) * ∏_{q ∈ 𝒬, q ≠ ⟦1⟧} quotientFunc f q (τ) + -- and the rest factor's analytic cusp function being bounded at 0. + sorry + +/-- **Sturm bound for finite-index subgroups of `SL(2, ℤ)` with `T ∈ 𝒢`.** +If `f : ModularForm 𝒢 k` has zero coefficient on `q^i` in its q-expansion (at period `1`) +for every `i ≥ 0` with `12 * i ≤ k * [𝒮ℒ : 𝒢]`, then `f = 0`. -/ +theorem sturm_bound_finiteIndex (h𝒢 : 1 ∈ 𝒢.strictPeriods) + (h : ∀ i : ℕ, 12 * (i : ℤ) ≤ k * Nat.card (𝒮ℒ ⧸ 𝒢.subgroupOf 𝒮ℒ) → + (qExpansion 1 f).coeff i = 0) : f = 0 := by + rw [← coe_eq_zero_iff, ← ModularForm.norm_eq_zero_iff (ℋ := 𝒮ℒ)] + refine sturm_bound_levelOne (ModularForm.norm 𝒮ℒ f) fun i hi => ?_ + have h_le : ↑(i + 1) ≤ (qExpansion 1 f).order := + PowerSeries.nat_le_order _ _ fun j hj => h j (by omega) + exact PowerSeries.coeff_of_lt_order _ <| + lt_of_lt_of_le (by exact_mod_cast Nat.lt_succ_self i) + (h_le.trans (qExpansion_norm_order_ge_qExpansion_order f h𝒢)) + +end ModularForm + +end From 90c83486d24c6733945003a7ea2fc5edfcf9b64f Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Wed, 6 May 2026 14:08:20 +0100 Subject: [PATCH 45/49] generalize Sturm bound statement to arbitrary cusp width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use `𝒢.strictWidthInfty` (the smallest period at the cusp `∞`) in place of the previous `1 ∈ 𝒢.strictPeriods` assumption, which restricted to subgroups containing `T = [[1,1],[0,1]]`. --- .../NumberTheory/ModularForms/SturmBound.lean | 72 +++++++------------ 1 file changed, 26 insertions(+), 46 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/SturmBound.lean index 51963e9ee0a5a8..27647ed9c0e2da 100644 --- a/Mathlib/NumberTheory/ModularForms/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/SturmBound.lean @@ -11,38 +11,18 @@ public import Mathlib.NumberTheory.ModularForms.NormTrace /-! # The Sturm bound for finite-index subgroups of `SL(2, ℤ)` -This file lifts the level-one Sturm bound (`sturm_bound_levelOne`) to arbitrary finite-index -subgroups `𝒢 ⊆ SL(2, ℤ)` via the norm map -`ModularForm.norm 𝒮ℒ : ModularForm 𝒢 k → ModularForm 𝒮ℒ (k * m)` -where `m = [SL(2,ℤ) : 𝒢]`. +For any finite-index subgroup `𝒢 ⊆ SL(2, ℤ)` and `f : ModularForm 𝒢 k`, if the q-expansion of +`f` at the cusp `∞` (with cusp width `𝒢.strictWidthInfty`) vanishes for the first +`⌊k * [SL(2, ℤ) : 𝒢] / 12⌋ + 1` coefficients, then `f = 0`. -## Strategy - -For `f : ModularForm 𝒢 k`, the norm `N(f) := ModularForm.norm 𝒮ℒ f` is a product over coset -representatives `γ ∈ 𝒮ℒ ⧸ 𝒢` of the slash-translates `f ∣ γ⁻¹`. By -`ModularForm.norm_eq_zero_iff`, `N(f) = 0 ↔ f = 0` as functions, so `f = 0` reduces to -`N(f) = 0`. The level-one Sturm bound applied to `N(f)` (which is a level-one form of -weight `k * m`) reduces this further to a vanishing condition on the q-expansion of -`N(f)` at `∞`. - -The bridge is the key q-expansion lemma: - -`qExpansion_norm_order_ge_qExpansion_order` : - the order of `qExpansion 1 (N f)` at `0` is at least the order of `qExpansion h_𝒢 f`, - where `h_𝒢` is the cusp width of `𝒢` at `∞`. +The proof lifts the level-one bound (`sturm_bound_levelOne`) via the norm map +`ModularForm.norm 𝒮ℒ : ModularForm 𝒢 k → ModularForm 𝒮ℒ (k * m)` (where `m = [SL(2,ℤ) : 𝒢]`): +the norm is identically zero precisely when `f` is, by `ModularForm.norm_eq_zero_iff`, and +sufficient vanishing of `f` at `∞` propagates to sufficient vanishing of `N(f)` at `∞`. ## Main results -* `ModularForm.sturm_bound_finiteIndex` : if `f : ModularForm 𝒢 k` for finite-index - `𝒢 ⊆ 𝒮ℒ` with `1 ∈ 𝒢.strictPeriods`, and the q-expansion of `f` vanishes for the first - `⌊k * [𝒮ℒ : 𝒢] / 12⌋ + 1` coefficients, then `f = 0`. - -## TODO - -* The current statement assumes `1 ∈ 𝒢.strictPeriods` (covers `Γ₀(N)`, `Γ₁(N)`, …). The - fully general version with arbitrary cusp width `h_𝒢` requires extending the proof of - `qExpansion_norm_order_ge_qExpansion_order` to interact correctly with the change-of-period - structure, which is left as future work. +* `ModularForm.sturm_bound_finiteIndex`: the Sturm bound for arbitrary finite-index `𝒢 ⊆ 𝒮ℒ`. -/ @[expose] public noncomputable section @@ -54,34 +34,34 @@ namespace ModularForm variable {𝒢 : Subgroup (GL (Fin 2) ℝ)} [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] variable {k : ℤ} (f : ModularForm 𝒢 k) -/-- **Key bridge lemma.** The order of vanishing of `qExpansion 1 (N(f))` at `0` is at least -the order of vanishing of `qExpansion 1 f`, when `1 ∈ 𝒢.strictPeriods`. +/-- **Key bridge lemma.** The order of vanishing of `qExpansion 1 (norm 𝒮ℒ f)` at the cusp `∞` +is at least the order of vanishing of `qExpansion 𝒢.strictWidthInfty f` at the cusp `∞`. -Mathematical content: write `N(f) = ∏_{γ ∈ 𝒮ℒ ⧸ 𝒢} f ∣ γ⁻¹`. The factor for the trivial coset -is `f` itself, and the remaining factors are bounded at the cusp `∞` (since `f` is bounded -at every cusp of `𝒢`). The product of bounded analytic functions, with one factor of order -`N`, has order at least `N` at `0`. -/ +The proof writes `N(f) = ∏_q quotientFunc f q` and isolates the `𝒮ℒ_∞`-related factors (one +factor per element of `𝒮ℒ_∞ ⧸ 𝒢_∞`, i.e. `𝒢.strictWidthInfty` factors), whose product is +`1`-periodic and contributes order `(qExpansion 𝒢.strictWidthInfty f).order` in `q`. The +remaining factors are bounded at `∞` (since `f` is bounded at every cusp of `𝒢`), so they +contribute order `≥ 0`. -/ private lemma qExpansion_norm_order_ge_qExpansion_order - (h𝒢 : 1 ∈ 𝒢.strictPeriods) : - (qExpansion 1 f).order ≤ (qExpansion 1 (ModularForm.norm 𝒮ℒ f)).order := by - -- TODO: prove via decomposition - -- N(f)(τ) = f(τ) * ∏_{q ∈ 𝒬, q ≠ ⟦1⟧} quotientFunc f q (τ) - -- and the rest factor's analytic cusp function being bounded at 0. + [DiscreteTopology 𝒢.strictPeriods] : + (qExpansion 𝒢.strictWidthInfty f).order ≤ + (qExpansion 1 (ModularForm.norm 𝒮ℒ f)).order := by sorry -/-- **Sturm bound for finite-index subgroups of `SL(2, ℤ)` with `T ∈ 𝒢`.** -If `f : ModularForm 𝒢 k` has zero coefficient on `q^i` in its q-expansion (at period `1`) -for every `i ≥ 0` with `12 * i ≤ k * [𝒮ℒ : 𝒢]`, then `f = 0`. -/ -theorem sturm_bound_finiteIndex (h𝒢 : 1 ∈ 𝒢.strictPeriods) +/-- **Sturm bound for finite-index subgroups of `SL(2, ℤ)`.** +If `f : ModularForm 𝒢 k` has zero coefficient on `q^i` in its q-expansion at the cusp `∞` +(at the natural period `𝒢.strictWidthInfty`) for every `i ≥ 0` with `12 * i ≤ k * [𝒮ℒ : 𝒢]`, +then `f = 0`. -/ +theorem sturm_bound_finiteIndex [DiscreteTopology 𝒢.strictPeriods] (h : ∀ i : ℕ, 12 * (i : ℤ) ≤ k * Nat.card (𝒮ℒ ⧸ 𝒢.subgroupOf 𝒮ℒ) → - (qExpansion 1 f).coeff i = 0) : f = 0 := by + (qExpansion 𝒢.strictWidthInfty f).coeff i = 0) : f = 0 := by rw [← coe_eq_zero_iff, ← ModularForm.norm_eq_zero_iff (ℋ := 𝒮ℒ)] refine sturm_bound_levelOne (ModularForm.norm 𝒮ℒ f) fun i hi => ?_ - have h_le : ↑(i + 1) ≤ (qExpansion 1 f).order := + have h_le : ↑(i + 1) ≤ (qExpansion 𝒢.strictWidthInfty f).order := PowerSeries.nat_le_order _ _ fun j hj => h j (by omega) exact PowerSeries.coeff_of_lt_order _ <| lt_of_lt_of_le (by exact_mod_cast Nat.lt_succ_self i) - (h_le.trans (qExpansion_norm_order_ge_qExpansion_order f h𝒢)) + (h_le.trans (qExpansion_norm_order_ge_qExpansion_order f)) end ModularForm From 84bf6d7034ed5dca7aa875d98c45250aa4949c39 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 8 May 2026 08:16:39 +0100 Subject: [PATCH 46/49] feat(NumberTheory/ModularForms): complete Sturm bound for finite-index subgroups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fills the sorry on `qExpansion_norm_order_ge_qExpansion_order` and adds an SL(2, ℤ)-specialised corollary `sturm_bound_finiteIndex_SL2Z`. The proof goes via the modular norm map and a Galois-product decomposition. It uses `integerCuspWidth 𝒢` (smallest positive integer in `𝒢.strictPeriods`) for the parabolic-coset enumeration; `⌊𝒢.strictWidthInfty⌋₊` would be wrong when the strict width is non-integer. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../NumberTheory/ModularForms/SturmBound.lean | 894 +++++++++++++++++- 1 file changed, 892 insertions(+), 2 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/SturmBound.lean index 27647ed9c0e2da..51a11cbe455ae2 100644 --- a/Mathlib/NumberTheory/ModularForms/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/SturmBound.lean @@ -27,13 +27,818 @@ sufficient vanishing of `f` at `∞` propagates to sufficient vanishing of `N(f) @[expose] public noncomputable section -open UpperHalfPlane ModularForm CuspForm MatrixGroups +open UpperHalfPlane ModularForm CuspForm MatrixGroups Function + +open scoped Manifold Topology namespace ModularForm +section GaloisProd + +-- For an `(N : ℝ)`-periodic function `f : ℍ → ℂ`, the Galois product +-- `A(τ) := ∏_{j=0}^{N-1} f(τ - j)` is `1`-periodic and its q-expansion at period `1` has +-- the same order as the q-expansion of `f` at period `(N : ℝ)`. + +variable (N : ℕ) (f : ℍ → ℂ) + +/-- The Galois product of translates: `∏_{j=0}^{N-1} f(τ - j)`. -/ +private noncomputable def galoisProd (τ : ℍ) : ℂ := + ∏ j ∈ Finset.range N, f (ofComplex ((τ : ℂ) - j)) + +variable {N f} + +private lemma galoisProd_periodic_one (hN : 0 < N) + (hf_per : Function.Periodic (f ∘ ofComplex) (N : ℝ)) : + Function.Periodic (galoisProd N f ∘ ofComplex) 1 := by + intro w + simp only [Function.comp_apply] + unfold galoisProd + obtain ⟨n, rfl⟩ : ∃ n, N = n + 1 := ⟨N - 1, by omega⟩ + by_cases hw : 0 < w.im + · have hw1 : 0 < (w + 1).im := by simpa using hw + rw [ofComplex_apply_of_im_pos hw1, ofComplex_apply_of_im_pos hw, + Finset.prod_range_succ' (fun j => f (ofComplex (w + 1 - ↑j))), + Finset.prod_range_succ (fun j => f (ofComplex (w - ↑j)))] + have hinner : ∏ j ∈ Finset.range n, f (ofComplex (w + 1 - ↑(j + 1))) = + ∏ j ∈ Finset.range n, f (ofComplex (w - ↑j)) := + Finset.prod_congr rfl fun j _ => by + congr 2 + push_cast + ring + have hbdry : f (ofComplex (w + 1 - ↑(0 : ℕ))) = f (ofComplex (w - ↑n)) := by + rw [show w + 1 - ↑(0 : ℕ) = (w - ↑n) + ↑(n + 1 : ℕ) by push_cast; ring] + exact hf_per (w - ↑n) + rw [hinner, hbdry] + · have hw0 : w.im ≤ 0 := not_lt.mp hw + have hw1 : (w + 1).im ≤ 0 := by simpa using hw0 + rw [ofComplex_apply_of_im_nonpos hw1, ofComplex_apply_of_im_nonpos hw0] + +private lemma galoisProd_mdiff (hf_mdiff : MDiff f) : MDiff (galoisProd N f) := by + unfold galoisProd + have hfo : DifferentiableOn ℂ (f ∘ ofComplex) {z | 0 < z.im} := + mdifferentiable_iff.mp hf_mdiff + intro τ + rw [mdifferentiableAt_iff] + have hτj : ∀ j : ℕ, 0 < ((τ : ℂ) - ↑j).im := fun j => by + simp [Complex.sub_im, Complex.natCast_im, τ.im_pos] + refine DifferentiableAt.fun_finsetProd fun j _ => + DifferentiableAt.congr_of_eventuallyEq + (((hfo ((τ : ℂ) - j) (hτj j)).differentiableAt + (isOpen_upperHalfPlaneSet.mem_nhds (hτj j))).comp (τ : ℂ) + ((differentiableAt_id (𝕜 := ℂ)).sub (differentiableAt_const (c := (j : ℂ))))) ?_ + filter_upwards [eventuallyEq_coe_comp_ofComplex τ.im_pos] with z hz + simp_all [Function.comp_apply, id_eq, Pi.sub_apply] + +private lemma galoisProd_isBoundedAtImInfty (hf_bdd : IsBoundedAtImInfty f) : + IsBoundedAtImInfty (galoisProd N f) := by + unfold galoisProd IsBoundedAtImInfty Filter.BoundedAtFilter + rw [← Finset.prod_fn] + refine Filter.BoundedAtFilter.prod _ fun j _ => hf_bdd.comp_tendsto ?_ + simp only [atImInfty, Filter.tendsto_comap_iff, Function.comp_def] + refine Filter.tendsto_comap.congr' (.of_forall fun τ => ?_) + have him : 0 < ((τ : ℂ) - ↑j).im := by + simp [Complex.sub_im, Complex.natCast_im, τ.im_pos] + simp [ofComplex_apply_of_im_pos him] + +/-- For `q` in a neighborhood of `0`, the `cuspFunction` at period `1` of the Galois product +`A(τ) = ∏_{j=0}^{N-1} f(τ - j)` evaluated at `q^N` equals the explicit product of cuspFunctions +at period `(N : ℝ)` of `f`, evaluated at the points `q · exp(-2πi j / N)`. -/ +private lemma cuspFunction_one_galoisProd_pow_eq (hN : 0 < N) + (hf_per : Function.Periodic (f ∘ ofComplex) (N : ℝ)) + (hf_bdd : IsBoundedAtImInfty f) (hf_mdiff : MDiff f) : + (fun q : ℂ => cuspFunction 1 (galoisProd N f) (q ^ N)) + =ᶠ[𝓝 0] + (fun q : ℂ => ∏ j ∈ Finset.range N, + cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) := by + have hNR : (0 : ℝ) < N := by exact_mod_cast hN + have hNR_ne : (N : ℝ) ≠ 0 := hNR.ne' + have hNC_ne : (N : ℂ) ≠ 0 := mod_cast hN.ne' + have hLHS_cts : ContinuousAt + (fun q : ℂ => cuspFunction 1 (galoisProd N f) (q ^ N)) 0 := by + have h1 : AnalyticAt ℂ (cuspFunction 1 (galoisProd N f)) 0 := + analyticAt_cuspFunction_zero one_pos + (galoisProd_periodic_one hN hf_per) (galoisProd_mdiff hf_mdiff) + (galoisProd_isBoundedAtImInfty hf_bdd) + have h2 : ContinuousAt (fun q : ℂ => q ^ N) 0 := by fun_prop + have h3 : (fun q : ℂ => q ^ N) 0 = 0 := by simp [zero_pow hN.ne'] + exact h1.continuousAt.comp_of_eq h2 h3 + have h_factor_cts : ∀ j ∈ Finset.range N, ContinuousAt + (fun q : ℂ => cuspFunction (N : ℝ) f + (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 := by + intro j _ + have h1 : AnalyticAt ℂ (cuspFunction (N : ℝ) f) 0 := + analyticAt_cuspFunction_zero hNR hf_per hf_mdiff hf_bdd + have h2 : ContinuousAt + (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 := by fun_prop + have h3 : (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 = 0 := by + simp + exact h1.continuousAt.comp_of_eq h2 h3 + have hRHS_cts : ContinuousAt + (fun q : ℂ => ∏ j ∈ Finset.range N, + cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 := + tendsto_finsetProd _ fun j hj => (h_factor_cts j hj).tendsto + -- It suffices to show the equality on the punctured neighborhood, where q ≠ 0. + rw [← hLHS_cts.eventuallyEq_nhds_iff_eventuallyEq_nhdsNE hRHS_cts] + have hball : Metric.ball (0 : ℂ) 1 ∈ 𝓝 (0 : ℂ) := + Metric.ball_mem_nhds 0 zero_lt_one + rw [eventuallyEq_nhdsWithin_iff] + filter_upwards [hball] with q hq_lt hq_ne + rw [mem_ball_zero_iff] at hq_lt + -- For q ≠ 0 with ‖q‖ < 1, define τ as the inverse via `invQParam`. + set τ : ℍ := ⟨Function.Periodic.invQParam (N : ℝ) q, + Function.Periodic.im_invQParam_pos_of_norm_lt_one hNR hq_lt hq_ne⟩ + have hτq : Function.Periodic.qParam (N : ℝ) τ = q := + Function.Periodic.qParam_right_inv hNR_ne hq_ne + have hqN : q ^ N = Function.Periodic.qParam 1 (τ : ℂ) := by + rw [← hτq] + simp only [Function.Periodic.qParam, ← Complex.exp_nat_mul, Complex.ofReal_one, div_one, + Complex.ofReal_natCast] + congr 1 + field_simp + have hLHS_eq : cuspFunction 1 (galoisProd N f) (q ^ N) = galoisProd N f τ := by + rw [hqN] + exact eq_cuspFunction τ one_ne_zero (galoisProd_periodic_one hN hf_per) + have h_factor_eq : ∀ j ∈ Finset.range N, + cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) = + f (ofComplex ((τ : ℂ) - j)) := by + intro j _ + -- Show q · exp(-2πi j/N) = qParam N (τ - j), then apply `eq_cuspFunction`. + have hqj : q * Complex.exp (-2 * Real.pi * Complex.I * j / N) = + Function.Periodic.qParam (N : ℝ) ((τ : ℂ) - j) := by + rw [← hτq] + simp only [Function.Periodic.qParam, ← Complex.exp_add, Complex.ofReal_natCast] + congr 1 + field_simp + ring + rw [hqj] + have him : 0 < ((τ : ℂ) - ↑j).im := by + simp [Complex.sub_im, Complex.natCast_im, τ.im_pos] + have h_eq : cuspFunction (N : ℝ) f + (Function.Periodic.qParam (N : ℝ) ((⟨(τ : ℂ) - j, him⟩ : ℍ) : ℂ)) = + f ⟨(τ : ℂ) - j, him⟩ := + eq_cuspFunction ⟨(τ : ℂ) - j, him⟩ hNR_ne hf_per + rw [show ((τ : ℂ) - j : ℂ) = ((⟨(τ : ℂ) - j, him⟩ : ℍ) : ℂ) from rfl, h_eq, + ofComplex_apply_of_im_pos him] + rw [hLHS_eq] + unfold galoisProd + exact Finset.prod_congr rfl fun j hj => (h_factor_eq j hj).symm + +/-- The order of the q-expansion of `f` at period `h` equals the analytic order of vanishing of +its `cuspFunction` at `q = 0`, when the latter is analytic. -/ +private lemma qExpansion_order_eq_analyticOrderAt_cuspFunction {h : ℝ} {f : ℍ → ℂ} + (hf : AnalyticAt ℂ (cuspFunction h f) 0) : + (qExpansion h f).order = analyticOrderAt (cuspFunction h f) 0 := by + refine ENat.eq_of_forall_natCast_le_iff fun n => ?_ + rw [natCast_le_analyticOrderAt_iff_iteratedDeriv_eq_zero hf] + refine ⟨fun H i hi => ?_, fun H => PowerSeries.nat_le_order _ _ fun i hi => ?_⟩ + · have hcoeff : (qExpansion h f).coeff i = 0 := + PowerSeries.coeff_of_lt_order _ (lt_of_lt_of_le (by exact_mod_cast hi) H) + rw [qExpansion_coeff] at hcoeff + have hfact : ((i.factorial : ℂ))⁻¹ ≠ 0 := + inv_ne_zero (mod_cast Nat.factorial_ne_zero i) + exact (mul_eq_zero.mp hcoeff).resolve_left hfact + · rw [qExpansion_coeff, H i hi, mul_zero] + +/-- The analytic order of a finite product of analytic functions equals the sum of the +analytic orders. -/ +private lemma analyticOrderAt_prod {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {ι : Type*} (s : Finset ι) (f : ι → 𝕜 → 𝕜) {z₀ : 𝕜} + (h : ∀ i ∈ s, AnalyticAt 𝕜 (f i) z₀) : + analyticOrderAt (∏ i ∈ s, f i) z₀ = ∑ i ∈ s, analyticOrderAt (f i) z₀ := by + induction s using Finset.cons_induction with + | empty => simp [analyticOrderAt_eq_zero] + | cons a s ha ih => + rw [Finset.prod_cons, Finset.sum_cons, + analyticOrderAt_mul (h a (Finset.mem_cons.mpr (.inl rfl))) + (Finset.analyticAt_prod _ fun i hi => h i (Finset.mem_cons.mpr (.inr hi))), + ih fun i hi => h i (Finset.mem_cons.mpr (.inr hi))] + +/-- For `f : ℂ → ℂ` analytic at `0` and `N : ℕ` positive, the analytic order at `0` of +`q ↦ f (q ^ N)` equals `analyticOrderAt f 0 * N`. -/ +private lemma analyticOrderAt_comp_pow_zero {f : ℂ → ℂ} (hf : AnalyticAt ℂ f 0) + {N : ℕ} (hN : 0 < N) : + analyticOrderAt (fun q : ℂ => f (q ^ N)) 0 = analyticOrderAt f 0 * N := by + have h_pow_an : AnalyticAt ℂ (fun q : ℂ => q ^ N) 0 := by fun_prop + have hzero : (0 : ℂ) ^ N = 0 := zero_pow hN.ne' + have hf' : AnalyticAt ℂ f ((fun q : ℂ => q ^ N) (0 : ℂ)) := by + change AnalyticAt ℂ f ((0 : ℂ) ^ N) + rwa [hzero] + change analyticOrderAt (f ∘ (npowRec N : ℂ → ℂ)) 0 = analyticOrderAt f 0 * N + rw [hf'.analyticOrderAt_comp h_pow_an] + change analyticOrderAt f ((0 : ℂ) ^ N) * + analyticOrderAt (fun x : ℂ => x ^ N - (0 : ℂ) ^ N) 0 = analyticOrderAt f 0 * N + rw [hzero, show (fun x : ℂ => x ^ N - (0 : ℂ)) = (id : ℂ → ℂ) ^ N by ext; simp, + analyticOrderAt_pow analyticAt_id, analyticOrderAt_id] + simp + +/-- For an `N`-periodic function `f` whose q-expansion at period `N` has order `M`, the +Galois product has q-expansion at period `1` whose order equals `M`. -/ +private lemma qExpansion_one_galoisProd_order_eq_qExpansion_self_order (hN : 0 < N) + (hf_per : Function.Periodic (f ∘ ofComplex) (N : ℝ)) + (hf_bdd : IsBoundedAtImInfty f) (hf_mdiff : MDiff f) : + (qExpansion 1 (galoisProd N f)).order = (qExpansion (N : ℝ) f).order := by + have hNR : (0 : ℝ) < N := by exact_mod_cast hN + have hLHS_an : AnalyticAt ℂ (cuspFunction 1 (galoisProd N f)) 0 := + analyticAt_cuspFunction_zero one_pos + (galoisProd_periodic_one hN hf_per) (galoisProd_mdiff hf_mdiff) + (galoisProd_isBoundedAtImInfty hf_bdd) + have hRHS_an : AnalyticAt ℂ (cuspFunction (N : ℝ) f) 0 := + analyticAt_cuspFunction_zero hNR hf_per hf_mdiff hf_bdd + rw [qExpansion_order_eq_analyticOrderAt_cuspFunction hLHS_an, + qExpansion_order_eq_analyticOrderAt_cuspFunction hRHS_an] + set ML := analyticOrderAt (cuspFunction 1 (galoisProd N f)) 0 + set MR := analyticOrderAt (cuspFunction (N : ℝ) f) 0 with hMR_def + -- The order of LHS (in lambda form) equals ML * N (compute via composition). + have h_comp_left : analyticOrderAt + (fun q : ℂ => cuspFunction 1 (galoisProd N f) (q ^ N)) 0 = ML * N := + analyticOrderAt_comp_pow_zero hLHS_an hN + have h_left_eq_prod : analyticOrderAt + (fun q : ℂ => cuspFunction 1 (galoisProd N f) (q ^ N)) 0 = + analyticOrderAt (fun q : ℂ => ∏ j ∈ Finset.range N, + cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 := + analyticOrderAt_congr (cuspFunction_one_galoisProd_pow_eq hN hf_per hf_bdd hf_mdiff) + have h_factor_an : ∀ j ∈ Finset.range N, + AnalyticAt ℂ (fun q : ℂ => cuspFunction (N : ℝ) f + (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 := by + intro j _ + have hg_an : AnalyticAt ℂ + (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 := by fun_prop + have hg_zero : (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) + (0 : ℂ) = 0 := by simp + change AnalyticAt ℂ (cuspFunction (N : ℝ) f ∘ + fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 + exact hRHS_an.comp_of_eq hg_an hg_zero + have h_factor_order : ∀ j ∈ Finset.range N, + analyticOrderAt (fun q : ℂ => cuspFunction (N : ℝ) f + (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 = MR := by + intro j _ + have hg_an : AnalyticAt ℂ + (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 := by fun_prop + have hg_deriv : deriv + (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 ≠ 0 := by + simp [Complex.exp_ne_zero] + change analyticOrderAt (cuspFunction (N : ℝ) f ∘ + fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 = MR + rw [analyticOrderAt_comp_of_deriv_ne_zero (f := cuspFunction (N : ℝ) f) hg_an hg_deriv, + zero_mul, ← hMR_def] + have h_prod_order : analyticOrderAt + (fun q : ℂ => ∏ j ∈ Finset.range N, + cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 = + N * MR := by + rw [show (fun q : ℂ => ∏ j ∈ Finset.range N, + cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) = + ∏ j ∈ Finset.range N, fun q : ℂ => + cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) by + ext q; simp, + analyticOrderAt_prod _ _ h_factor_an, Finset.sum_congr rfl h_factor_order, + Finset.sum_const, Finset.card_range, nsmul_eq_mul] + have h_combine : ML * (N : ℕ∞) = (N : ℕ∞) * MR := by + rw [← h_comp_left, h_left_eq_prod, h_prod_order] + have hN_ne : (N : ℕ∞) ≠ 0 := by exact_mod_cast hN.ne' + by_cases hL : ML = ⊤ + · rw [hL, ENat.top_mul hN_ne] at h_combine + have hMR_top : MR = ⊤ := by + by_contra hMR_fin + rcases ENat.ne_top_iff_exists.mp hMR_fin with ⟨r, hr⟩ + rw [← hr] at h_combine + exact absurd h_combine.symm (ENat.coe_ne_top _) + rw [hL, hMR_top] + by_cases hR : MR = ⊤ + · rw [hR, ENat.mul_top hN_ne] at h_combine + rcases ENat.ne_top_iff_exists.mp hL with ⟨a, ha⟩ + rw [← ha] at h_combine + exact absurd h_combine (ENat.coe_ne_top _) + -- Both finite: convert to nats and cancel + rcases ENat.ne_top_iff_exists.mp hL with ⟨a, ha⟩ + rcases ENat.ne_top_iff_exists.mp hR with ⟨b, hb⟩ + rw [← ha, ← hb] at h_combine + rw [← ha, ← hb] + rw [show (a : ℕ∞) * (N : ℕ∞) = ((a * N : ℕ) : ℕ∞) by push_cast; ring, + show (N : ℕ∞) * (b : ℕ∞) = ((N * b : ℕ) : ℕ∞) by push_cast; ring, + Nat.cast_inj] at h_combine + rw [Nat.cast_inj] + -- a * N = N * b, hence a = b (using N > 0) + have hN_eq : a * N = b * N := by linarith [h_combine] + exact Nat.mul_right_cancel hN hN_eq + +end GaloisProd + variable {𝒢 : Subgroup (GL (Fin 2) ℝ)} [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] variable {k : ℤ} (f : ModularForm 𝒢 k) +omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in +/-- The image of `T^n` (for `T = ![![1,1],![0,1]]`) in `GL(2, ℝ)` is `upperRightHom n`. -/ +private lemma mapGL_T_zpow_eq_upperRightHom (n : ℤ) : + Matrix.SpecialLinearGroup.mapGL ℝ ((ModularGroup.T : SL(2, ℤ))^n) = + Matrix.GeneralLinearGroup.upperRightHom ((n : ℝ)) := by + have hT : Matrix.SpecialLinearGroup.mapGL ℝ (ModularGroup.T : SL(2, ℤ)) = + Matrix.GeneralLinearGroup.upperRightHom (1 : ℝ) := by + ext i j + fin_cases i <;> fin_cases j <;> + simp [Matrix.SpecialLinearGroup.mapGL_coe_matrix, ModularGroup.coe_T] + rw [map_zpow, hT, ← AddChar.map_zsmul_eq_zpow, zsmul_one] + +/-- The smallest positive integer `n` such that `T^n ∈ 𝒢`. Equivalently, the smallest +positive integer in `𝒢.strictPeriods`. Under `[𝒢.IsFiniteRelIndex 𝒮ℒ]` this is well-defined +and positive. -/ +private noncomputable def integerCuspWidth (𝒢 : Subgroup (GL (Fin 2) ℝ)) + [𝒢.IsFiniteRelIndex 𝒮ℒ] : ℕ := + open Classical in + Nat.find (p := fun n => 0 < n ∧ (n : ℝ) ∈ 𝒢.strictPeriods) (by + -- Apply the pigeonhole lemma to find `n > 0` with `T_𝒮ℒ^n ∈ 𝒢.subgroupOf 𝒮ℒ`, then translate + -- back to `𝒢` membership in `GL(2, ℝ)` via `upperRightHom`. + set T_SL : 𝒮ℒ := (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict ModularGroup.T with hT_SL + have hidx : ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ).index ≠ 0 := + Subgroup.FiniteIndex.index_ne_zero + obtain ⟨n, hn_pos, _, hn_mem⟩ := + Subgroup.exists_pow_mem_of_index_ne_zero hidx T_SL + refine ⟨n, hn_pos, ?_⟩ + rw [Subgroup.mem_subgroupOf] at hn_mem + have hcoe : ((T_SL ^ n : 𝒮ℒ) : GL (Fin 2) ℝ) = + Matrix.SpecialLinearGroup.mapGL ℝ ((ModularGroup.T : SL(2, ℤ))^n) := by + rw [Subgroup.coe_pow, hT_SL, MonoidHom.coe_rangeRestrict, ← map_pow] + rw [hcoe, show ((ModularGroup.T : SL(2, ℤ))^n) = ((ModularGroup.T : SL(2, ℤ))^((n : ℤ))) from + (zpow_natCast _ n).symm, + mapGL_T_zpow_eq_upperRightHom] at hn_mem + rw [Subgroup.mem_strictPeriods_iff] + exact_mod_cast hn_mem) + +omit [𝒢.HasDetPlusMinusOne] in +/-- The integer cusp width is positive. -/ +private lemma integerCuspWidth_pos : 0 < integerCuspWidth 𝒢 := by + classical + exact (Nat.find_spec (p := fun n => 0 < n ∧ (n : ℝ) ∈ 𝒢.strictPeriods) _).1 + +omit [𝒢.HasDetPlusMinusOne] in +/-- The integer cusp width belongs to `𝒢.strictPeriods` (as a real). -/ +private lemma integerCuspWidth_mem_strictPeriods : + (integerCuspWidth 𝒢 : ℝ) ∈ 𝒢.strictPeriods := by + classical + exact (Nat.find_spec (p := fun n => 0 < n ∧ (n : ℝ) ∈ 𝒢.strictPeriods) _).2 + +omit [𝒢.HasDetPlusMinusOne] in +/-- Equivalently: `T^(integerCuspWidth 𝒢)` is in `𝒢` (viewed in `GL(2, ℝ)`). -/ +private lemma T_zpow_integerCuspWidth_mem : + ((ModularGroup.T : SL(2, ℤ))^(integerCuspWidth 𝒢 : ℕ) : GL (Fin 2) ℝ) ∈ 𝒢 := by + have h := integerCuspWidth_mem_strictPeriods (𝒢 := 𝒢) + rw [Subgroup.mem_strictPeriods_iff] at h + have hgl : ((ModularGroup.T : SL(2, ℤ))^(integerCuspWidth 𝒢 : ℕ) : GL (Fin 2) ℝ) = + Matrix.SpecialLinearGroup.mapGL ℝ + ((ModularGroup.T : SL(2, ℤ))^((integerCuspWidth 𝒢 : ℕ) : ℤ)) := by + change (Matrix.SpecialLinearGroup.mapGL ℝ ModularGroup.T)^(integerCuspWidth 𝒢 : ℕ) = _ + rw [← map_pow, ← zpow_natCast] + rw [hgl, mapGL_T_zpow_eq_upperRightHom] + push_cast + exact h + +omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in +/-- General version: the slash action of `T^j` translates the argument by `j`, for any function +`g : ℍ → ℂ`. -/ +private lemma slash_T_zpow_apply_general (j : ℤ) (g : ℍ → ℂ) (τ : ℍ) : + (g ∣[k] ((ModularGroup.T : SL(2, ℤ))^j : GL (Fin 2) ℝ)) τ = + g ((j : ℝ) +ᵥ τ) := by + have hgl : ((ModularGroup.T : SL(2, ℤ))^j : GL (Fin 2) ℝ) = + Matrix.SpecialLinearGroup.mapGL ℝ ((ModularGroup.T)^j : SL(2, ℤ)) := by + change (Matrix.SpecialLinearGroup.mapGL ℝ ModularGroup.T)^j = _ + rw [← map_zpow] + rw [hgl] + change (g ∣[k] ((ModularGroup.T)^j : SL(2, ℤ))) τ = _ + rw [SL_slash_apply, modular_T_zpow_smul] + have hdenom : denom (((ModularGroup.T)^j : SL(2, ℤ)) : GL (Fin 2) ℝ) (τ : ℂ) = 1 := by + have hcoe : (((((ModularGroup.T)^j : SL(2, ℤ)) : GL (Fin 2) ℝ)) : + Matrix (Fin 2) (Fin 2) ℝ) = + ((((ModularGroup.T)^j : SL(2, ℤ)) : Matrix (Fin 2) (Fin 2) ℤ)).map (Int.castRingHom ℝ) := + rfl + change ((((((ModularGroup.T)^j : SL(2, ℤ)) : GL (Fin 2) ℝ)) : + Matrix (Fin 2) (Fin 2) ℝ) 1 0 : ℂ) * τ + + ((((((ModularGroup.T)^j : SL(2, ℤ)) : GL (Fin 2) ℝ)) : + Matrix (Fin 2) (Fin 2) ℝ) 1 1 : ℂ) = 1 + rw [hcoe, ModularGroup.coe_T_zpow] + simp + rw [hdenom, one_zpow, mul_one] + +omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in +/-- The slash action of `T^j` (for `T = ![![1,1],![0,1]]`) translates the argument by `j`. -/ +private lemma slash_T_zpow_apply (j : ℤ) (τ : ℍ) : + ((f : ℍ → ℂ) ∣[k] ((ModularGroup.T : SL(2, ℤ))^j : GL (Fin 2) ℝ)) τ = + (f : ℍ → ℂ) ((j : ℝ) +ᵥ τ) := + slash_T_zpow_apply_general j _ τ + +omit [𝒢.HasDetPlusMinusOne] in +/-- The map `j ↦ ⟦T^j⟧` from `Fin (integerCuspWidth 𝒢)` into the quotient +`𝒮ℒ ⧸ 𝒢.subgroupOf 𝒮ℒ` is injective. -/ +private lemma quotient_T_pow_injective_integerCuspWidth + [DiscreteTopology 𝒢.strictPeriods] : + Function.Injective (fun j : Fin (integerCuspWidth 𝒢) => + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))) := by + classical + intro j₁ j₂ hj + rw [QuotientGroup.eq, Subgroup.mem_subgroupOf] at hj + -- The underlying GL element `((T^j₁)⁻¹ * T^j₂)` maps to `T^(j₂ - j₁) = upperRightHom (j₂ - j₁)`. + have hSub : (((((Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j₁ : ℕ)))⁻¹ * + (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j₂ : ℕ))) : 𝒮ℒ) : GL (Fin 2) ℝ) = + Matrix.SpecialLinearGroup.mapGL ℝ + ((ModularGroup.T : SL(2, ℤ))^((j₂ : ℤ) - (j₁ : ℤ))) := by + rw [Subgroup.coe_mul, Subgroup.coe_inv, + MonoidHom.coe_rangeRestrict, MonoidHom.coe_rangeRestrict, + ← map_inv, ← map_mul, zpow_sub, zpow_natCast, zpow_natCast] + congr 1 + -- Powers of T commute, so (T^j₁)⁻¹ * T^j₂ = T^j₂ * (T^j₁)⁻¹. + exact ((Commute.pow_pow_self ModularGroup.T (j₂ : ℕ) (j₁ : ℕ)).inv_right).eq.symm + rw [hSub, mapGL_T_zpow_eq_upperRightHom] at hj + rw [show (((j₂ : ℤ) - (j₁ : ℤ) : ℤ) : ℝ) = ((j₂ : ℝ) - (j₁ : ℝ)) by push_cast; ring, + ← Subgroup.mem_strictPeriods_iff] at hj + -- A natural number `d` in `𝒢.strictPeriods` with `d < integerCuspWidth 𝒢` must be `0`, + -- by minimality of `integerCuspWidth`. + have h_min_zero : ∀ d : ℕ, d < integerCuspWidth 𝒢 → (d : ℝ) ∈ 𝒢.strictPeriods → d = 0 := by + intro d hd_lt hd_mem + by_contra hd_ne + have : integerCuspWidth 𝒢 ≤ d := + Nat.find_min' (p := fun n => 0 < n ∧ (n : ℝ) ∈ 𝒢.strictPeriods) _ + ⟨Nat.pos_of_ne_zero hd_ne, hd_mem⟩ + omega + -- WLOG split on `j₁ ≤ j₂` to handle the natural-number subtraction. + rcases le_total (j₁ : ℕ) (j₂ : ℕ) with hle | hle + · have hd_real : (((j₂ : ℕ) - (j₁ : ℕ) : ℕ) : ℝ) = (j₂ : ℝ) - (j₁ : ℝ) := + Nat.cast_sub hle + have hd_zero : (j₂ : ℕ) - (j₁ : ℕ) = 0 := + h_min_zero _ (by have := j₂.isLt; omega) (hd_real ▸ hj) + exact Fin.ext (by omega) + · have hd_real : (((j₁ : ℕ) - (j₂ : ℕ) : ℕ) : ℝ) = (j₁ : ℝ) - (j₂ : ℝ) := + Nat.cast_sub hle + have hd_mem : (((j₁ : ℕ) - (j₂ : ℕ) : ℕ) : ℝ) ∈ 𝒢.strictPeriods := by + rw [hd_real] + convert neg_mem hj using 1 + ring + have hd_zero : (j₁ : ℕ) - (j₂ : ℕ) = 0 := + h_min_zero _ (by have := j₁.isLt; omega) hd_mem + exact Fin.ext (by omega) + +omit [𝒢.HasDetPlusMinusOne] in +/-- For `j : Fin (integerCuspWidth 𝒢)`, the function-level value of `quotientFunc f` at the +coset `⟦T^j⟧` is `τ ↦ f (ofComplex (τ - j))`. -/ +private lemma quotientFunc_T_pow_apply + (j : Fin (integerCuspWidth 𝒢)) (τ : ℍ) : + SlashInvariantForm.quotientFunc f + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) τ = + f (ofComplex ((τ : ℂ) - j)) := by + rw [SlashInvariantForm.quotientFunc_mk] + have h_val : ((Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ)) : 𝒮ℒ).val = + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ) : GL (Fin 2) ℝ) := by + rw [MonoidHom.coe_rangeRestrict, map_pow] + rfl + rw [h_val, + show (((ModularGroup.T : SL(2, ℤ))^(j : ℕ) : GL (Fin 2) ℝ))⁻¹ = + ((ModularGroup.T : SL(2, ℤ))^(-(j : ℕ) : ℤ) : GL (Fin 2) ℝ) by + rw [zpow_neg, zpow_natCast], + slash_T_zpow_apply] + have him : 0 < ((τ : ℂ) - (j : ℂ)).im := by + simp [Complex.sub_im, Complex.natCast_im, τ.im_pos] + have h_eq : ((-(j : ℕ) : ℝ) +ᵥ τ : ℍ) = ofComplex ((τ : ℂ) - (j : ℂ)) := by + apply UpperHalfPlane.ext + rw [coe_vadd, ofComplex_apply_of_im_pos him] + push_cast + ring + rw [show ((-((j : ℕ) : ℤ) : ℤ) : ℝ) = (-(j : ℕ) : ℝ) by push_cast; ring, h_eq] + +omit [𝒢.HasDetPlusMinusOne] in +/-- The image set of `j ↦ ⟦T^j⟧` (for `j ∈ Fin (integerCuspWidth 𝒢)`) in +`𝒮ℒ ⧸ 𝒢.subgroupOf 𝒮ℒ` is invariant under left multiplication by `T_𝒮ℒ`: if +`⟦x⟧ ∈ image`, then `⟦T_𝒮ℒ * x⟧ ∈ image`. -/ +private lemma image_T_pow_invariant_under_T_mul + [DiscreteTopology 𝒢.strictPeriods] + [DecidableEq (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))] {x : 𝒮ℒ} + (hx : (⟦x⟧ : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) ∈ + Finset.univ.image (fun j : Fin (integerCuspWidth 𝒢) => + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)))) : + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict (ModularGroup.T : SL(2, ℤ)) * x⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) ∈ + Finset.univ.image (fun j : Fin (integerCuspWidth 𝒢) => + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))) := by + classical + set T_𝒮ℒ : 𝒮ℒ := (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + (ModularGroup.T : SL(2, ℤ)) with hT_𝒮ℒ_def + set h_𝒢 := integerCuspWidth 𝒢 + rw [Finset.mem_image] at hx + obtain ⟨j, _, hj⟩ := hx + -- ⟦x⟧ = ⟦T^j⟧ ⇒ ⟦T_𝒮ℒ * x⟧ = ⟦T^(j+1)⟧. + have h_eq_quot : (⟦T_𝒮ℒ * x⟧ : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) = + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^((j : ℕ) + 1))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) := by + have h_eq_quot' : (⟦T_𝒮ℒ * x⟧ : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) = + (⟦T_𝒮ℒ * (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) := by + rw [QuotientGroup.eq] at hj ⊢ + have hj' : x⁻¹ * (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ)) ∈ + (𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ := by + simpa [mul_inv_rev, inv_inv] using inv_mem hj + convert hj' using 1 + group + rw [h_eq_quot'] + congr 1 + rw [hT_𝒮ℒ_def, ← MonoidHom.map_mul, ← pow_succ'] + rw [h_eq_quot, Finset.mem_image] + by_cases hj1 : (j : ℕ) + 1 < h_𝒢 + · exact ⟨⟨(j : ℕ) + 1, hj1⟩, Finset.mem_univ _, rfl⟩ + -- Wrap-around case: j+1 = h_𝒢, so ⟦T^h_𝒢⟧ = ⟦1⟧ = imgFn 0 (using T^h_𝒢 ∈ 𝒢). + · have hj_eq : (j : ℕ) + 1 = h_𝒢 := by + have := j.isLt + omega + have h_𝒢_pos : 0 < h_𝒢 := integerCuspWidth_pos + refine ⟨⟨0, h_𝒢_pos⟩, Finset.mem_univ _, ?_⟩ + rw [hj_eq, QuotientGroup.eq, Subgroup.mem_subgroupOf] + have h_simp : (((Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(((⟨0, h_𝒢_pos⟩ : Fin h_𝒢) : ℕ))))⁻¹ * + (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^h_𝒢) : 𝒮ℒ).val = + ((ModularGroup.T : SL(2, ℤ))^h_𝒢 : GL (Fin 2) ℝ) := by + change (((Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(0 : ℕ)))⁻¹ * + (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^h_𝒢) : 𝒮ℒ).val = _ + rw [Subgroup.coe_mul, Subgroup.coe_inv, + MonoidHom.coe_rangeRestrict, MonoidHom.coe_rangeRestrict, pow_zero, map_one, + inv_one, one_mul, map_pow] + rfl + rw [h_simp] + exact T_zpow_integerCuspWidth_mem + +omit [𝒢.HasDetPlusMinusOne] in +/-- SMul-version of `image_T_pow_invariant_under_T_mul` via `Quotient.inductionOn`. -/ +private lemma image_T_pow_invariant_under_T_smul + [DiscreteTopology 𝒢.strictPeriods] + [DecidableEq (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))] + {q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)} + (hq : q ∈ Finset.univ.image (fun j : Fin (integerCuspWidth 𝒢) => + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)))) : + ((Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict (ModularGroup.T : SL(2, ℤ)) • q : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) ∈ + Finset.univ.image (fun j : Fin (integerCuspWidth 𝒢) => + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))) := by + induction q using Quotient.inductionOn with + | h x => exact image_T_pow_invariant_under_T_mul (𝒢 := 𝒢) hq + +omit [𝒢.HasDetPlusMinusOne] in +/-- The image set is closed under `T_𝒮ℒ⁻¹ • _`: since `T_𝒮ℒ • _` is a permutation on a +finite set, `T_𝒮ℒ • image = image` and hence the iff version. -/ +private lemma image_T_pow_smul_inv_iff + [DiscreteTopology 𝒢.strictPeriods] + [DecidableEq (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))] + (q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) : + ((Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict (ModularGroup.T : SL(2, ℤ)))⁻¹ • q ∈ + Finset.univ.image (fun j : Fin (integerCuspWidth 𝒢) => + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))) ↔ + q ∈ Finset.univ.image (fun j : Fin (integerCuspWidth 𝒢) => + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))) := by + letI : Fintype (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) := Fintype.ofFinite _ + set T_𝒮ℒ : 𝒮ℒ := (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + (ModularGroup.T : SL(2, ℤ)) + set image : Finset (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) := + Finset.univ.image (fun j : Fin (integerCuspWidth 𝒢) => + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))) with himage_def + refine ⟨fun hq => ?_, fun hq => ?_⟩ + · have h := image_T_pow_invariant_under_T_smul (𝒢 := 𝒢) hq + rwa [smul_inv_smul] at h + · have h_inj : Function.Injective + (fun q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ) => T_𝒮ℒ • q) := + MulAction.injective T_𝒮ℒ + have h_smul_image : image.image (fun q => T_𝒮ℒ • q) = image := by + refine Finset.eq_of_subset_of_card_le (fun q hq' => ?_) ?_ + · obtain ⟨q', hq'', rfl⟩ := Finset.mem_image.mp hq' + exact image_T_pow_invariant_under_T_smul (𝒢 := 𝒢) hq'' + · rw [Finset.card_image_of_injective _ h_inj] + have h_target : T_𝒮ℒ • (T_𝒮ℒ⁻¹ • q) ∈ image := by + rwa [smul_inv_smul] + obtain ⟨q', hq'_mem, hq'_eq⟩ := Finset.mem_image.mp (h_smul_image ▸ h_target) + exact h_inj hq'_eq ▸ hq'_mem + +omit [𝒢.HasDetPlusMinusOne] in +/-- The "rest factor" `∏_{q ∉ image} quotientFunc f q` is invariant under `τ ↦ 1 +ᵥ τ`: +each factor is shifted to `quotientFunc f (T_𝒮ℒ⁻¹ • q) τ`, and `T_𝒮ℒ⁻¹ • _` permutes the +non-image cosets (since `image` is `T_𝒮ℒ`-invariant). -/ +private lemma prod_quotientFunc_filter_image_one_vadd + [DiscreteTopology 𝒢.strictPeriods] + [DecidableEq (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))] + [Fintype (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))] + (τ : ℍ) : + (∏ q ∈ Finset.univ.filter (· ∉ Finset.univ.image + (fun j : Fin (integerCuspWidth 𝒢) => + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)))), + SlashInvariantForm.quotientFunc f q ((1 : ℝ) +ᵥ τ)) = + ∏ q ∈ Finset.univ.filter (· ∉ Finset.univ.image + (fun j : Fin (integerCuspWidth 𝒢) => + (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : + 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)))), + SlashInvariantForm.quotientFunc f q τ := by + set T_𝒮ℒ : 𝒮ℒ := (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + (ModularGroup.T : SL(2, ℤ)) with hT_𝒮ℒ_def + have hT_𝒮ℒ_val : (T_𝒮ℒ : GL (Fin 2) ℝ) = + Matrix.SpecialLinearGroup.mapGL ℝ (ModularGroup.T : SL(2, ℤ)) := by + rw [hT_𝒮ℒ_def] + rfl + have h_step1 : ∀ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), + SlashInvariantForm.quotientFunc f q ((1 : ℝ) +ᵥ τ) = + SlashInvariantForm.quotientFunc f (T_𝒮ℒ⁻¹ • q) τ := by + intro q + have h_slash_eq : (SlashInvariantForm.quotientFunc f q) ((1 : ℝ) +ᵥ τ) = + ((SlashInvariantForm.quotientFunc f q) ∣[k] T_𝒮ℒ.val) τ := by + rw [hT_𝒮ℒ_val] + have h := slash_T_zpow_apply_general (k := k) + (1 : ℤ) (SlashInvariantForm.quotientFunc f q) τ + simpa [zpow_one] using h.symm + rw [h_slash_eq, SlashInvariantForm.quotientFunc_smul f T_𝒮ℒ.2] + refine (Finset.prod_congr rfl (fun q _ => h_step1 q)).trans ?_ + -- Re-index using the bijection MulAction.toPerm T_𝒮ℒ⁻¹. + refine Finset.prod_equiv (MulAction.toPerm T_𝒮ℒ⁻¹) ?_ ?_ + · intro q + simp only [Finset.mem_filter, Finset.mem_univ, true_and] + exact (image_T_pow_smul_inv_iff (𝒢 := 𝒢) q).symm.not + · intro q _ + rfl + +omit [𝒢.HasDetPlusMinusOne] in +/-- The "rest factor" decomposition of the modular norm `N(f)` at period `1`. The norm splits as +a product over the `integerCuspWidth 𝒢` cosets corresponding to the powers of `T` (which give the +factors `f(τ - j)` for `j = 0, ..., integerCuspWidth 𝒢 - 1`) times a "rest" function `rest` that +is `1`-periodic and whose period-`1` cusp function is analytic at `0`. -/ +private lemma analyticAt_cuspFunction_one_norm_rest + [DiscreteTopology 𝒢.strictPeriods] : + ∃ rest : ℍ → ℂ, + Function.Periodic (rest ∘ ofComplex) 1 ∧ + AnalyticAt ℂ (cuspFunction 1 rest) 0 ∧ + ∀ τ : ℍ, (ModularForm.norm 𝒮ℒ f : ℍ → ℂ) τ = + (∏ j ∈ Finset.range (integerCuspWidth 𝒢), f (ofComplex ((τ : ℂ) - j))) * rest τ := by + classical + set h_𝒢 := integerCuspWidth 𝒢 + letI : Fintype (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) := Fintype.ofFinite _ + -- The injective map `j ↦ ⟦T^j⟧ : Fin h_𝒢 → 𝒮ℒ ⧸ 𝒢.subgroupOf 𝒮ℒ` and its `Finset` image. + set imgFn : Fin h_𝒢 → 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ) := fun j => + ⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ + set image : Finset (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) := + Finset.univ.image imgFn with himage_def + have h_imgFn_inj : Function.Injective imgFn := + quotient_T_pow_injective_integerCuspWidth (𝒢 := 𝒢) + -- Define rest as the product over non-image cosets. + let rest : ℍ → ℂ := fun τ => + ∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q τ + -- The key formula: each `quotientFunc f (imgFn j)` equals `f(ofComplex(τ - j))`. + have h_quotientFunc_imgFn : ∀ (j : Fin h_𝒢) (τ : ℍ), + SlashInvariantForm.quotientFunc f (imgFn j) τ = f (ofComplex ((τ : ℂ) - j)) := + fun j τ => quotientFunc_T_pow_apply f j τ + -- `rest` is invariant under `τ ↦ 1 +ᵥ τ` since `T_𝒮ℒ⁻¹ • _` re-indexes the product. + have h_rest_periodic_vAdd : ∀ τ : ℍ, rest ((1 : ℝ) +ᵥ τ) = rest τ := + prod_quotientFunc_filter_image_one_vadd f + have h_rest_periodic : Function.Periodic (rest ∘ ofComplex) 1 := by + intro w + simp only [Function.comp_apply] + by_cases hw : 0 < w.im + · have hw1 : 0 < (w + 1).im := by simpa using hw + rw [ofComplex_apply_of_im_pos hw1, ofComplex_apply_of_im_pos hw] + have h_eq : ((1 : ℝ) +ᵥ (⟨w, hw⟩ : ℍ) : ℍ) = (⟨w + 1, hw1⟩ : ℍ) := + UpperHalfPlane.ext (by simp [coe_vadd, add_comm]) + exact h_eq ▸ h_rest_periodic_vAdd ⟨w, hw⟩ + · have hw0 : w.im ≤ 0 := not_lt.mp hw + have hw1 : (w + 1).im ≤ 0 := by simpa using hw0 + rw [ofComplex_apply_of_im_nonpos hw1, ofComplex_apply_of_im_nonpos hw0] + -- `IsCusp ∞ 𝒮ℒ` is needed to invoke `bdd_at_cusps'` on `translate f r⁻¹`. + have h_isCusp_𝒮ℒ : IsCusp (OnePoint.infty : OnePoint ℝ) (𝒮ℒ : Subgroup (GL (Fin 2) ℝ)) := + Subgroup.isCusp_of_mem_strictPeriods (𝒢 := 𝒮ℒ) zero_lt_one (by simp) + have h_quotientFunc_mdiff : + ∀ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), + MDiff (SlashInvariantForm.quotientFunc f q) := by + refine Quotient.forall.mpr fun r => ?_ + exact (ModularForm.translate f r.val⁻¹).holo' + have h_quotientFunc_bdd : + ∀ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), + IsBoundedAtImInfty (SlashInvariantForm.quotientFunc f q) := by + refine Quotient.forall.mpr fun ⟨r, hr⟩ => ?_ + exact OnePoint.isBoundedAt_infty_iff.mp + ((ModularForm.translate f _).bdd_at_cusps' (h_isCusp_𝒮ℒ.of_isFiniteRelIndex_conj hr)) + have h_rest_eq : rest = + ∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q := by + ext τ + simp [rest, Finset.prod_apply] + have h_rest_mdiff : MDiff rest := by + rw [h_rest_eq] + exact MDifferentiable.prod fun q _ => h_quotientFunc_mdiff q + have h_rest_bdd : IsBoundedAtImInfty rest := by + rw [h_rest_eq] + unfold IsBoundedAtImInfty + rw [show ((∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q : + ℍ → ℂ)) = + ∏ q ∈ Finset.univ.filter (· ∉ image), (SlashInvariantForm.quotientFunc f q : ℍ → ℂ) from + rfl] + exact Filter.BoundedAtFilter.prod _ fun q _ => h_quotientFunc_bdd q + refine ⟨rest, ?_, ?_, ?_⟩ + · exact h_rest_periodic + · -- Analyticity of cuspFunction 1 rest at 0. + exact analyticAt_cuspFunction_zero one_pos h_rest_periodic h_rest_mdiff h_rest_bdd + · -- Decomposition formula. + intro τ + have h_unfold_norm : (ModularForm.norm 𝒮ℒ f : ℍ → ℂ) τ = + ∏ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), + SlashInvariantForm.quotientFunc f q τ := by + rw [ModularForm.coe_norm, Finset.prod_apply] + rw [h_unfold_norm] + -- Split the universal product into image vs non-image cosets. + rw [show (∏ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), + SlashInvariantForm.quotientFunc f q τ) = + (∏ q ∈ Finset.univ.filter (· ∈ image), SlashInvariantForm.quotientFunc f q τ) * + (∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q τ) from + (Finset.prod_filter_mul_prod_filter_not _ _ _).symm] + -- The non-image factor is `rest τ` by definition. + -- The image factor we relate to ∏ j ∈ range h_𝒢, f(ofComplex(τ - j)). + rw [Finset.filter_univ_mem] + -- Now: (∏ q ∈ image, quotientFunc f q τ) * rest τ = (∏ j ∈ range h_𝒢, ...) * rest τ + congr 1 + -- (∏ q ∈ image, quotientFunc f q τ) = ∏ j ∈ range h_𝒢, f(ofComplex(τ - j)) + rw [himage_def, Finset.prod_image h_imgFn_inj.injOn, + Finset.prod_congr rfl (fun j _ => h_quotientFunc_imgFn j τ)] + exact Fin.prod_univ_eq_prod_range (fun n => f (ofComplex ((τ : ℂ) - (n : ℕ)))) h_𝒢 + +omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in +/-- For an `h`-periodic function `f`, the order of `qExpansion (m * h) f` is at least the order +of `qExpansion h f`. (In fact it equals `m` times the order of `qExpansion h f`.) -/ +private lemma qExpansion_order_le_qExpansion_nat_mul_order + {h : ℝ} {g : ℍ → ℂ} {m : ℕ} (hh : 0 < h) (hm : 0 < m) + (hg_per : Function.Periodic (g ∘ ofComplex) h) + (hg_bdd : IsBoundedAtImInfty g) (hg_mdiff : MDiff g) : + (qExpansion h g).order ≤ (qExpansion ((m * h : ℝ)) g).order := by + have hmh : (0 : ℝ) < (m : ℝ) * h := mul_pos (by exact_mod_cast hm) hh + have hg_per_mh : Function.Periodic (g ∘ ofComplex) (((m : ℝ) * h : ℝ)) := by + convert hg_per.nat_mul m using 1 + push_cast + ring + have hLHS_an : AnalyticAt ℂ (cuspFunction h g) 0 := + analyticAt_cuspFunction_zero hh hg_per hg_mdiff hg_bdd + have hRHS_an : AnalyticAt ℂ (cuspFunction ((m : ℝ) * h) g) 0 := + analyticAt_cuspFunction_zero hmh hg_per_mh hg_mdiff hg_bdd + rw [qExpansion_order_eq_analyticOrderAt_cuspFunction hLHS_an, + qExpansion_order_eq_analyticOrderAt_cuspFunction hRHS_an] + -- Show cuspFunction (m * h) g =ᶠ[𝓝 0] cuspFunction h g ∘ (·^m). + have hzero : (0 : ℂ) ^ m = 0 := zero_pow hm.ne' + have h_RHS_lift_cts : ContinuousAt (fun q : ℂ => cuspFunction h g (q ^ m)) 0 := by + have h1 : ContinuousAt (fun q : ℂ => q ^ m) 0 := by fun_prop + exact hLHS_an.continuousAt.comp_of_eq h1 hzero + have h_eqOn : + (fun q : ℂ => cuspFunction ((m : ℝ) * h) g q) =ᶠ[𝓝 0] + (fun q : ℂ => cuspFunction h g (q ^ m)) := by + rw [← hRHS_an.continuousAt.eventuallyEq_nhds_iff_eventuallyEq_nhdsNE h_RHS_lift_cts] + have hball : Metric.ball (0 : ℂ) 1 ∈ 𝓝 (0 : ℂ) := + Metric.ball_mem_nhds 0 zero_lt_one + rw [eventuallyEq_nhdsWithin_iff] + filter_upwards [hball] with q hq_lt hq_ne + rw [mem_ball_zero_iff] at hq_lt + set τ : ℍ := ⟨Function.Periodic.invQParam ((m : ℝ) * h) q, + Function.Periodic.im_invQParam_pos_of_norm_lt_one hmh hq_lt hq_ne⟩ + have hτq : Function.Periodic.qParam ((m : ℝ) * h) τ = q := + Function.Periodic.qParam_right_inv hmh.ne' hq_ne + have hqm : q ^ m = Function.Periodic.qParam h (τ : ℂ) := by + rw [← hτq] + simp only [Function.Periodic.qParam, ← Complex.exp_nat_mul, + Complex.ofReal_mul, Complex.ofReal_natCast] + congr 1 + have : (m : ℂ) ≠ 0 := mod_cast hm.ne' + field_simp + have hLHS_eq : cuspFunction ((m : ℝ) * h) g q = g τ := by + rw [← hτq] + exact eq_cuspFunction τ hmh.ne' hg_per_mh + have hRHS_eq : cuspFunction h g (q ^ m) = g τ := by + rw [hqm] + exact eq_cuspFunction τ hh.ne' hg_per + rw [hLHS_eq, hRHS_eq] + rw [analyticOrderAt_congr h_eqOn, analyticOrderAt_comp_pow_zero hLHS_an hm] + exact ENat.self_le_mul_right _ (by exact_mod_cast hm.ne') + +omit [𝒢.HasDetPlusMinusOne] in /-- **Key bridge lemma.** The order of vanishing of `qExpansion 1 (norm 𝒮ℒ f)` at the cusp `∞` is at least the order of vanishing of `qExpansion 𝒢.strictWidthInfty f` at the cusp `∞`. @@ -46,8 +851,73 @@ private lemma qExpansion_norm_order_ge_qExpansion_order [DiscreteTopology 𝒢.strictPeriods] : (qExpansion 𝒢.strictWidthInfty f).order ≤ (qExpansion 1 (ModularForm.norm 𝒮ℒ f)).order := by - sorry + -- Express `(integerCuspWidth 𝒢 : ℝ)` as `m' * 𝒢.strictWidthInfty` for some positive `m' : ℕ`, + -- using `strictPeriods = AddSubgroup.zmultiples 𝒢.strictWidthInfty`. + have hn_pos : 0 < integerCuspWidth 𝒢 := integerCuspWidth_pos + have hnR_pos : (0 : ℝ) < integerCuspWidth 𝒢 := by exact_mod_cast hn_pos + have hw_nn : (0 : ℝ) ≤ 𝒢.strictWidthInfty := 𝒢.strictWidthInfty_nonneg + have hn_mem : (integerCuspWidth 𝒢 : ℝ) ∈ 𝒢.strictPeriods := + integerCuspWidth_mem_strictPeriods + rw [Subgroup.strictPeriods_eq_zmultiples_strictWidthInfty, + AddSubgroup.mem_zmultiples_iff] at hn_mem + obtain ⟨m, hm⟩ := hn_mem + rw [zsmul_eq_mul] at hm + have hw_pos : (0 : ℝ) < 𝒢.strictWidthInfty := by + refine hw_nn.lt_of_ne fun heq => ?_ + rw [← heq, mul_zero] at hm + exact (Nat.cast_pos.mpr hn_pos).ne' hm.symm + have hm_pos : (0 : ℤ) < m := by + by_contra hle + have hm_nn : (m : ℝ) ≤ 0 := by exact_mod_cast not_lt.mp hle + have : (m : ℝ) * 𝒢.strictWidthInfty ≤ 0 := + mul_nonpos_of_nonpos_of_nonneg hm_nn hw_nn + rw [hm] at this + linarith + obtain ⟨m', rfl⟩ : ∃ m' : ℕ, m = (m' : ℤ) := ⟨m.toNat, (Int.toNat_of_nonneg hm_pos.le).symm⟩ + have hm'_pos : 0 < m' := by exact_mod_cast hm_pos + have hnRw : (integerCuspWidth 𝒢 : ℝ) = (m' : ℝ) * 𝒢.strictWidthInfty := by + rw [← hm] + push_cast + ring + -- `f` is `𝒢.strictWidthInfty`-periodic, bounded at `∞`, holomorphic; hence also `n`-periodic. + have hCusp : IsCusp (OnePoint.infty : OnePoint ℝ) 𝒢 := + Subgroup.isCusp_of_mem_strictPeriods hnR_pos integerCuspWidth_mem_strictPeriods + have hf_w_per : Function.Periodic ((f : ℍ → ℂ) ∘ ofComplex) 𝒢.strictWidthInfty := + SlashInvariantFormClass.periodic_comp_ofComplex f 𝒢.strictWidthInfty_mem_strictPeriods + have hf_bdd : IsBoundedAtImInfty (f : ℍ → ℂ) := + OnePoint.isBoundedAt_infty_iff.mp (f.bdd_at_cusps' hCusp) + have hf_mdiff : MDiff (f : ℍ → ℂ) := f.holo' + have hf_n_per : Function.Periodic ((f : ℍ → ℂ) ∘ ofComplex) + ((integerCuspWidth 𝒢 : ℕ) : ℝ) := by + rw [hnRw] + convert hf_w_per.nat_mul m' using 1 + push_cast + ring + have h_w_le_n : (qExpansion 𝒢.strictWidthInfty (f : ℍ → ℂ)).order ≤ + (qExpansion ((integerCuspWidth 𝒢 : ℕ) : ℝ) (f : ℍ → ℂ)).order := by + rw [hnRw] + exact qExpansion_order_le_qExpansion_nat_mul_order hw_pos hm'_pos + hf_w_per hf_bdd hf_mdiff + -- Decompose `(norm 𝒮ℒ f) = (galoisProd n f) * rest` and apply `qExpansion_mul`. + obtain ⟨rest, _, h_rest_an, h_decomp⟩ := analyticAt_cuspFunction_one_norm_rest f + have h_funeq : ((ModularForm.norm 𝒮ℒ f : ℍ → ℂ)) = + (galoisProd (integerCuspWidth 𝒢) (f : ℍ → ℂ)) * rest := + funext h_decomp + have h_galois_an : AnalyticAt ℂ + (cuspFunction 1 (galoisProd (integerCuspWidth 𝒢) (f : ℍ → ℂ))) 0 := + analyticAt_cuspFunction_zero one_pos + (galoisProd_periodic_one hn_pos hf_n_per) + (galoisProd_mdiff hf_mdiff) + (galoisProd_isBoundedAtImInfty hf_bdd) + have h_qexp_mul : qExpansion 1 (ModularForm.norm 𝒮ℒ f : ℍ → ℂ) = + qExpansion 1 (galoisProd (integerCuspWidth 𝒢) (f : ℍ → ℂ)) * qExpansion 1 rest := by + rw [h_funeq] + exact qExpansion_mul h_galois_an h_rest_an + rw [h_qexp_mul, PowerSeries.order_mul, + qExpansion_one_galoisProd_order_eq_qExpansion_self_order hn_pos hf_n_per hf_bdd hf_mdiff] + exact h_w_le_n.trans le_self_add +omit [𝒢.HasDetPlusMinusOne] in /-- **Sturm bound for finite-index subgroups of `SL(2, ℤ)`.** If `f : ModularForm 𝒢 k` has zero coefficient on `q^i` in its q-expansion at the cusp `∞` (at the natural period `𝒢.strictWidthInfty`) for every `i ≥ 0` with `12 * i ≤ k * [𝒮ℒ : 𝒢]`, @@ -63,6 +933,26 @@ theorem sturm_bound_finiteIndex [DiscreteTopology 𝒢.strictPeriods] lt_of_lt_of_le (by exact_mod_cast Nat.lt_succ_self i) (h_le.trans (qExpansion_norm_order_ge_qExpansion_order f)) +/-- **Sturm bound for finite-index subgroups of `SL(2, ℤ)`.** +For `Γ` a finite-index subgroup of `SL(2, ℤ)` and `f : ModularForm Γ k` (viewed in +`GL(2, ℝ)`), if the first `⌊k · [SL(2,ℤ) : Γ] / 12⌋ + 1` coefficients of `f`'s q-expansion +at the cusp `∞` vanish, then `f` is identically zero. + +This is the classical Sturm bound. The cusp width at `∞` is +`(Γ : Subgroup (GL (Fin 2) ℝ)).strictWidthInfty`, which is automatically a positive integer +for `Γ ⊆ SL(2, ℤ)`. The bound is tight. -/ +theorem sturm_bound_finiteIndex_SL2Z {Γ : Subgroup SL(2, ℤ)} [Γ.FiniteIndex] + {k : ℤ} (f : ModularForm (Γ : Subgroup (GL (Fin 2) ℝ)) k) + (h : ∀ i : ℕ, 12 * (i : ℤ) ≤ k * Γ.index → + (qExpansion (Γ : Subgroup (GL (Fin 2) ℝ)).strictWidthInfty f).coeff i = 0) : f = 0 := by + have h_index : Nat.card (𝒮ℒ ⧸ (Γ : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ) = Γ.index := by + change ((Γ.map (Matrix.SpecialLinearGroup.mapGL ℝ)).subgroupOf 𝒮ℒ).index = Γ.index + rw [← Subgroup.relIndex, MonoidHom.range_eq_map (Matrix.SpecialLinearGroup.mapGL ℝ), + ← Subgroup.relIndex_comap, + Subgroup.comap_map_eq_self_of_injective Matrix.SpecialLinearGroup.mapGL_injective, + Subgroup.relIndex_top_right] + exact sturm_bound_finiteIndex f fun i hi => h i (h_index ▸ hi) + end ModularForm end From 26aee0e7495c06fe660fe423eb7a76fcfadb6a17 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 8 May 2026 09:59:08 +0100 Subject: [PATCH 47/49] chore(NumberTheory/ModularForms): /cleanup pass on SturmBound MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strip docstrings from private helpers (mathlib style); golf 8 long lemmas via per-declaration audits. 957 → 694 lines (-27%). Public theorem signatures unchanged; build clean. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../NumberTheory/ModularForms/SturmBound.lean | 560 +++++------------- 1 file changed, 148 insertions(+), 412 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/SturmBound.lean index 51a11cbe455ae2..1dcca8d404fad7 100644 --- a/Mathlib/NumberTheory/ModularForms/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/SturmBound.lean @@ -41,7 +41,6 @@ section GaloisProd variable (N : ℕ) (f : ℍ → ℂ) -/-- The Galois product of translates: `∏_{j=0}^{N-1} f(τ - j)`. -/ private noncomputable def galoisProd (τ : ℍ) : ℂ := ∏ j ∈ Finset.range N, f (ofComplex ((τ : ℂ) - j)) @@ -100,9 +99,6 @@ private lemma galoisProd_isBoundedAtImInfty (hf_bdd : IsBoundedAtImInfty f) : simp [Complex.sub_im, Complex.natCast_im, τ.im_pos] simp [ofComplex_apply_of_im_pos him] -/-- For `q` in a neighborhood of `0`, the `cuspFunction` at period `1` of the Galois product -`A(τ) = ∏_{j=0}^{N-1} f(τ - j)` evaluated at `q^N` equals the explicit product of cuspFunctions -at period `(N : ℝ)` of `f`, evaluated at the points `q · exp(-2πi j / N)`. -/ private lemma cuspFunction_one_galoisProd_pow_eq (hN : 0 < N) (hf_per : Function.Periodic (f ∘ ofComplex) (N : ℝ)) (hf_bdd : IsBoundedAtImInfty f) (hf_mdiff : MDiff f) : @@ -113,38 +109,25 @@ private lemma cuspFunction_one_galoisProd_pow_eq (hN : 0 < N) have hNR : (0 : ℝ) < N := by exact_mod_cast hN have hNR_ne : (N : ℝ) ≠ 0 := hNR.ne' have hNC_ne : (N : ℂ) ≠ 0 := mod_cast hN.ne' + have hRHS_an : AnalyticAt ℂ (cuspFunction (N : ℝ) f) 0 := + analyticAt_cuspFunction_zero hNR hf_per hf_mdiff hf_bdd have hLHS_cts : ContinuousAt - (fun q : ℂ => cuspFunction 1 (galoisProd N f) (q ^ N)) 0 := by - have h1 : AnalyticAt ℂ (cuspFunction 1 (galoisProd N f)) 0 := - analyticAt_cuspFunction_zero one_pos - (galoisProd_periodic_one hN hf_per) (galoisProd_mdiff hf_mdiff) - (galoisProd_isBoundedAtImInfty hf_bdd) - have h2 : ContinuousAt (fun q : ℂ => q ^ N) 0 := by fun_prop - have h3 : (fun q : ℂ => q ^ N) 0 = 0 := by simp [zero_pow hN.ne'] - exact h1.continuousAt.comp_of_eq h2 h3 + (fun q : ℂ => cuspFunction 1 (galoisProd N f) (q ^ N)) 0 := + (analyticAt_cuspFunction_zero one_pos (galoisProd_periodic_one hN hf_per) + (galoisProd_mdiff hf_mdiff) (galoisProd_isBoundedAtImInfty hf_bdd)).continuousAt.comp_of_eq + (by fun_prop) (by simp [zero_pow hN.ne']) have h_factor_cts : ∀ j ∈ Finset.range N, ContinuousAt (fun q : ℂ => cuspFunction (N : ℝ) f - (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 := by - intro j _ - have h1 : AnalyticAt ℂ (cuspFunction (N : ℝ) f) 0 := - analyticAt_cuspFunction_zero hNR hf_per hf_mdiff hf_bdd - have h2 : ContinuousAt - (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 := by fun_prop - have h3 : (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 = 0 := by - simp - exact h1.continuousAt.comp_of_eq h2 h3 + (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 := fun _ _ => + hRHS_an.continuousAt.comp_of_eq (by fun_prop) (by simp) have hRHS_cts : ContinuousAt (fun q : ℂ => ∏ j ∈ Finset.range N, cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 := tendsto_finsetProd _ fun j hj => (h_factor_cts j hj).tendsto - -- It suffices to show the equality on the punctured neighborhood, where q ≠ 0. - rw [← hLHS_cts.eventuallyEq_nhds_iff_eventuallyEq_nhdsNE hRHS_cts] - have hball : Metric.ball (0 : ℂ) 1 ∈ 𝓝 (0 : ℂ) := - Metric.ball_mem_nhds 0 zero_lt_one - rw [eventuallyEq_nhdsWithin_iff] - filter_upwards [hball] with q hq_lt hq_ne + rw [← hLHS_cts.eventuallyEq_nhds_iff_eventuallyEq_nhdsNE hRHS_cts, + eventuallyEq_nhdsWithin_iff] + filter_upwards [Metric.ball_mem_nhds (0 : ℂ) zero_lt_one] with q hq_lt hq_ne rw [mem_ball_zero_iff] at hq_lt - -- For q ≠ 0 with ‖q‖ < 1, define τ as the inverse via `invQParam`. set τ : ℍ := ⟨Function.Periodic.invQParam (N : ℝ) q, Function.Periodic.im_invQParam_pos_of_norm_lt_one hNR hq_lt hq_ne⟩ have hτq : Function.Periodic.qParam (N : ℝ) τ = q := @@ -155,36 +138,20 @@ private lemma cuspFunction_one_galoisProd_pow_eq (hN : 0 < N) Complex.ofReal_natCast] congr 1 field_simp - have hLHS_eq : cuspFunction 1 (galoisProd N f) (q ^ N) = galoisProd N f τ := by - rw [hqN] - exact eq_cuspFunction τ one_ne_zero (galoisProd_periodic_one hN hf_per) - have h_factor_eq : ∀ j ∈ Finset.range N, - cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) = - f (ofComplex ((τ : ℂ) - j)) := by - intro j _ - -- Show q · exp(-2πi j/N) = qParam N (τ - j), then apply `eq_cuspFunction`. - have hqj : q * Complex.exp (-2 * Real.pi * Complex.I * j / N) = - Function.Periodic.qParam (N : ℝ) ((τ : ℂ) - j) := by - rw [← hτq] - simp only [Function.Periodic.qParam, ← Complex.exp_add, Complex.ofReal_natCast] - congr 1 - field_simp - ring - rw [hqj] - have him : 0 < ((τ : ℂ) - ↑j).im := by - simp [Complex.sub_im, Complex.natCast_im, τ.im_pos] - have h_eq : cuspFunction (N : ℝ) f - (Function.Periodic.qParam (N : ℝ) ((⟨(τ : ℂ) - j, him⟩ : ℍ) : ℂ)) = - f ⟨(τ : ℂ) - j, him⟩ := - eq_cuspFunction ⟨(τ : ℂ) - j, him⟩ hNR_ne hf_per - rw [show ((τ : ℂ) - j : ℂ) = ((⟨(τ : ℂ) - j, him⟩ : ℍ) : ℂ) from rfl, h_eq, - ofComplex_apply_of_im_pos him] - rw [hLHS_eq] + rw [hqN, eq_cuspFunction τ one_ne_zero (galoisProd_periodic_one hN hf_per)] unfold galoisProd - exact Finset.prod_congr rfl fun j hj => (h_factor_eq j hj).symm + refine Finset.prod_congr rfl fun j _ => ?_ + have him : 0 < ((τ : ℂ) - ↑j).im := by + simp [Complex.sub_im, Complex.natCast_im, τ.im_pos] + have hqj : q * Complex.exp (-2 * Real.pi * Complex.I * j / N) = + Function.Periodic.qParam (N : ℝ) ((⟨(τ : ℂ) - j, him⟩ : ℍ) : ℂ) := by + rw [← hτq] + simp only [Function.Periodic.qParam, ← Complex.exp_add, Complex.ofReal_natCast] + congr 1 + field_simp + ring + rw [hqj, eq_cuspFunction ⟨(τ : ℂ) - j, him⟩ hNR_ne hf_per, ofComplex_apply_of_im_pos him] -/-- The order of the q-expansion of `f` at period `h` equals the analytic order of vanishing of -its `cuspFunction` at `q = 0`, when the latter is analytic. -/ private lemma qExpansion_order_eq_analyticOrderAt_cuspFunction {h : ℝ} {f : ℍ → ℂ} (hf : AnalyticAt ℂ (cuspFunction h f) 0) : (qExpansion h f).order = analyticOrderAt (cuspFunction h f) 0 := by @@ -199,8 +166,6 @@ private lemma qExpansion_order_eq_analyticOrderAt_cuspFunction {h : ℝ} {f : exact (mul_eq_zero.mp hcoeff).resolve_left hfact · rw [qExpansion_coeff, H i hi, mul_zero] -/-- The analytic order of a finite product of analytic functions equals the sum of the -analytic orders. -/ private lemma analyticOrderAt_prod {𝕜 : Type*} [NontriviallyNormedField 𝕜] {ι : Type*} (s : Finset ι) (f : ι → 𝕜 → 𝕜) {z₀ : 𝕜} (h : ∀ i ∈ s, AnalyticAt 𝕜 (f i) z₀) : @@ -213,8 +178,6 @@ private lemma analyticOrderAt_prod {𝕜 : Type*} [NontriviallyNormedField 𝕜] (Finset.analyticAt_prod _ fun i hi => h i (Finset.mem_cons.mpr (.inr hi))), ih fun i hi => h i (Finset.mem_cons.mpr (.inr hi))] -/-- For `f : ℂ → ℂ` analytic at `0` and `N : ℕ` positive, the analytic order at `0` of -`q ↦ f (q ^ N)` equals `analyticOrderAt f 0 * N`. -/ private lemma analyticOrderAt_comp_pow_zero {f : ℂ → ℂ} (hf : AnalyticAt ℂ f 0) {N : ℕ} (hN : 0 < N) : analyticOrderAt (fun q : ℂ => f (q ^ N)) 0 = analyticOrderAt f 0 * N := by @@ -231,95 +194,47 @@ private lemma analyticOrderAt_comp_pow_zero {f : ℂ → ℂ} (hf : AnalyticAt analyticOrderAt_pow analyticAt_id, analyticOrderAt_id] simp -/-- For an `N`-periodic function `f` whose q-expansion at period `N` has order `M`, the -Galois product has q-expansion at period `1` whose order equals `M`. -/ private lemma qExpansion_one_galoisProd_order_eq_qExpansion_self_order (hN : 0 < N) (hf_per : Function.Periodic (f ∘ ofComplex) (N : ℝ)) (hf_bdd : IsBoundedAtImInfty f) (hf_mdiff : MDiff f) : (qExpansion 1 (galoisProd N f)).order = (qExpansion (N : ℝ) f).order := by - have hNR : (0 : ℝ) < N := by exact_mod_cast hN have hLHS_an : AnalyticAt ℂ (cuspFunction 1 (galoisProd N f)) 0 := - analyticAt_cuspFunction_zero one_pos - (galoisProd_periodic_one hN hf_per) (galoisProd_mdiff hf_mdiff) - (galoisProd_isBoundedAtImInfty hf_bdd) + analyticAt_cuspFunction_zero one_pos (galoisProd_periodic_one hN hf_per) + (galoisProd_mdiff hf_mdiff) (galoisProd_isBoundedAtImInfty hf_bdd) have hRHS_an : AnalyticAt ℂ (cuspFunction (N : ℝ) f) 0 := - analyticAt_cuspFunction_zero hNR hf_per hf_mdiff hf_bdd + analyticAt_cuspFunction_zero (mod_cast hN) hf_per hf_mdiff hf_bdd rw [qExpansion_order_eq_analyticOrderAt_cuspFunction hLHS_an, qExpansion_order_eq_analyticOrderAt_cuspFunction hRHS_an] set ML := analyticOrderAt (cuspFunction 1 (galoisProd N f)) 0 - set MR := analyticOrderAt (cuspFunction (N : ℝ) f) 0 with hMR_def - -- The order of LHS (in lambda form) equals ML * N (compute via composition). - have h_comp_left : analyticOrderAt - (fun q : ℂ => cuspFunction 1 (galoisProd N f) (q ^ N)) 0 = ML * N := - analyticOrderAt_comp_pow_zero hLHS_an hN - have h_left_eq_prod : analyticOrderAt - (fun q : ℂ => cuspFunction 1 (galoisProd N f) (q ^ N)) 0 = - analyticOrderAt (fun q : ℂ => ∏ j ∈ Finset.range N, - cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 := - analyticOrderAt_congr (cuspFunction_one_galoisProd_pow_eq hN hf_per hf_bdd hf_mdiff) + set MR := analyticOrderAt (cuspFunction (N : ℝ) f) 0 have h_factor_an : ∀ j ∈ Finset.range N, AnalyticAt ℂ (fun q : ℂ => cuspFunction (N : ℝ) f - (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 := by - intro j _ - have hg_an : AnalyticAt ℂ - (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 := by fun_prop - have hg_zero : (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) - (0 : ℂ) = 0 := by simp - change AnalyticAt ℂ (cuspFunction (N : ℝ) f ∘ - fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 - exact hRHS_an.comp_of_eq hg_an hg_zero + (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 := fun j _ => + hRHS_an.comp_of_eq (by fun_prop) (by simp) have h_factor_order : ∀ j ∈ Finset.range N, analyticOrderAt (fun q : ℂ => cuspFunction (N : ℝ) f - (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 = MR := by - intro j _ - have hg_an : AnalyticAt ℂ - (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 := by fun_prop - have hg_deriv : deriv - (fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 ≠ 0 := by - simp [Complex.exp_ne_zero] - change analyticOrderAt (cuspFunction (N : ℝ) f ∘ - fun q : ℂ => q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) 0 = MR - rw [analyticOrderAt_comp_of_deriv_ne_zero (f := cuspFunction (N : ℝ) f) hg_an hg_deriv, - zero_mul, ← hMR_def] - have h_prod_order : analyticOrderAt - (fun q : ℂ => ∏ j ∈ Finset.range N, - cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 = - N * MR := by - rw [show (fun q : ℂ => ∏ j ∈ Finset.range N, - cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) = - ∏ j ∈ Finset.range N, fun q : ℂ => - cuspFunction (N : ℝ) f (q * Complex.exp (-2 * Real.pi * Complex.I * j / N)) by - ext q; simp, - analyticOrderAt_prod _ _ h_factor_an, Finset.sum_congr rfl h_factor_order, - Finset.sum_const, Finset.card_range, nsmul_eq_mul] + (q * Complex.exp (-2 * Real.pi * Complex.I * j / N))) 0 = MR := fun j _ => by + rw [← Function.comp_def, analyticOrderAt_comp_of_deriv_ne_zero + (f := cuspFunction (N : ℝ) f) (by fun_prop) (by simp [Complex.exp_ne_zero]), zero_mul] have h_combine : ML * (N : ℕ∞) = (N : ℕ∞) * MR := by - rw [← h_comp_left, h_left_eq_prod, h_prod_order] - have hN_ne : (N : ℕ∞) ≠ 0 := by exact_mod_cast hN.ne' - by_cases hL : ML = ⊤ - · rw [hL, ENat.top_mul hN_ne] at h_combine - have hMR_top : MR = ⊤ := by - by_contra hMR_fin - rcases ENat.ne_top_iff_exists.mp hMR_fin with ⟨r, hr⟩ - rw [← hr] at h_combine - exact absurd h_combine.symm (ENat.coe_ne_top _) - rw [hL, hMR_top] - by_cases hR : MR = ⊤ - · rw [hR, ENat.mul_top hN_ne] at h_combine - rcases ENat.ne_top_iff_exists.mp hL with ⟨a, ha⟩ - rw [← ha] at h_combine + rw [← analyticOrderAt_comp_pow_zero hLHS_an hN, + analyticOrderAt_congr (cuspFunction_one_galoisProd_pow_eq hN hf_per hf_bdd hf_mdiff), + ← Finset.prod_fn, analyticOrderAt_prod _ _ h_factor_an, + Finset.sum_congr rfl h_factor_order, Finset.sum_const, Finset.card_range, nsmul_eq_mul] + have hN_ne : (N : ℕ∞) ≠ 0 := mod_cast hN.ne' + clear_value ML MR + rcases eq_or_ne ML ⊤ with hL | hL <;> rcases eq_or_ne MR ⊤ with hR | hR + · rw [hL, hR] + · lift MR to ℕ using hR + rw [hL, ENat.top_mul hN_ne] at h_combine + exact absurd h_combine.symm (ENat.coe_ne_top _) + · lift ML to ℕ using hL + rw [hR, ENat.mul_top hN_ne] at h_combine exact absurd h_combine (ENat.coe_ne_top _) - -- Both finite: convert to nats and cancel - rcases ENat.ne_top_iff_exists.mp hL with ⟨a, ha⟩ - rcases ENat.ne_top_iff_exists.mp hR with ⟨b, hb⟩ - rw [← ha, ← hb] at h_combine - rw [← ha, ← hb] - rw [show (a : ℕ∞) * (N : ℕ∞) = ((a * N : ℕ) : ℕ∞) by push_cast; ring, - show (N : ℕ∞) * (b : ℕ∞) = ((N * b : ℕ) : ℕ∞) by push_cast; ring, - Nat.cast_inj] at h_combine - rw [Nat.cast_inj] - -- a * N = N * b, hence a = b (using N > 0) - have hN_eq : a * N = b * N := by linarith [h_combine] - exact Nat.mul_right_cancel hN hN_eq + · lift ML to ℕ using hL + lift MR to ℕ using hR + rw [mul_comm (N : ℕ∞)] at h_combine + exact_mod_cast Nat.eq_of_mul_eq_mul_right hN (mod_cast h_combine) end GaloisProd @@ -327,7 +242,6 @@ variable {𝒢 : Subgroup (GL (Fin 2) ℝ)} [𝒢.HasDetPlusMinusOne] [𝒢.IsFi variable {k : ℤ} (f : ModularForm 𝒢 k) omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in -/-- The image of `T^n` (for `T = ![![1,1],![0,1]]`) in `GL(2, ℝ)` is `upperRightHom n`. -/ private lemma mapGL_T_zpow_eq_upperRightHom (n : ℤ) : Matrix.SpecialLinearGroup.mapGL ℝ ((ModularGroup.T : SL(2, ℤ))^n) = Matrix.GeneralLinearGroup.upperRightHom ((n : ℝ)) := by @@ -338,9 +252,6 @@ private lemma mapGL_T_zpow_eq_upperRightHom (n : ℤ) : simp [Matrix.SpecialLinearGroup.mapGL_coe_matrix, ModularGroup.coe_T] rw [map_zpow, hT, ← AddChar.map_zsmul_eq_zpow, zsmul_one] -/-- The smallest positive integer `n` such that `T^n ∈ 𝒢`. Equivalently, the smallest -positive integer in `𝒢.strictPeriods`. Under `[𝒢.IsFiniteRelIndex 𝒮ℒ]` this is well-defined -and positive. -/ private noncomputable def integerCuspWidth (𝒢 : Subgroup (GL (Fin 2) ℝ)) [𝒢.IsFiniteRelIndex 𝒮ℒ] : ℕ := open Classical in @@ -364,20 +275,17 @@ private noncomputable def integerCuspWidth (𝒢 : Subgroup (GL (Fin 2) ℝ)) exact_mod_cast hn_mem) omit [𝒢.HasDetPlusMinusOne] in -/-- The integer cusp width is positive. -/ private lemma integerCuspWidth_pos : 0 < integerCuspWidth 𝒢 := by classical exact (Nat.find_spec (p := fun n => 0 < n ∧ (n : ℝ) ∈ 𝒢.strictPeriods) _).1 omit [𝒢.HasDetPlusMinusOne] in -/-- The integer cusp width belongs to `𝒢.strictPeriods` (as a real). -/ private lemma integerCuspWidth_mem_strictPeriods : (integerCuspWidth 𝒢 : ℝ) ∈ 𝒢.strictPeriods := by classical exact (Nat.find_spec (p := fun n => 0 < n ∧ (n : ℝ) ∈ 𝒢.strictPeriods) _).2 omit [𝒢.HasDetPlusMinusOne] in -/-- Equivalently: `T^(integerCuspWidth 𝒢)` is in `𝒢` (viewed in `GL(2, ℝ)`). -/ private lemma T_zpow_integerCuspWidth_mem : ((ModularGroup.T : SL(2, ℤ))^(integerCuspWidth 𝒢 : ℕ) : GL (Fin 2) ℝ) ∈ 𝒢 := by have h := integerCuspWidth_mem_strictPeriods (𝒢 := 𝒢) @@ -392,8 +300,6 @@ private lemma T_zpow_integerCuspWidth_mem : exact h omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in -/-- General version: the slash action of `T^j` translates the argument by `j`, for any function -`g : ℍ → ℂ`. -/ private lemma slash_T_zpow_apply_general (j : ℤ) (g : ℍ → ℂ) (τ : ℍ) : (g ∣[k] ((ModularGroup.T : SL(2, ℤ))^j : GL (Fin 2) ℝ)) τ = g ((j : ℝ) +ᵥ τ) := by @@ -418,15 +324,12 @@ private lemma slash_T_zpow_apply_general (j : ℤ) (g : ℍ → ℂ) (τ : ℍ) rw [hdenom, one_zpow, mul_one] omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in -/-- The slash action of `T^j` (for `T = ![![1,1],![0,1]]`) translates the argument by `j`. -/ private lemma slash_T_zpow_apply (j : ℤ) (τ : ℍ) : ((f : ℍ → ℂ) ∣[k] ((ModularGroup.T : SL(2, ℤ))^j : GL (Fin 2) ℝ)) τ = (f : ℍ → ℂ) ((j : ℝ) +ᵥ τ) := slash_T_zpow_apply_general j _ τ omit [𝒢.HasDetPlusMinusOne] in -/-- The map `j ↦ ⟦T^j⟧` from `Fin (integerCuspWidth 𝒢)` into the quotient -`𝒮ℒ ⧸ 𝒢.subgroupOf 𝒮ℒ` is injective. -/ private lemma quotient_T_pow_injective_integerCuspWidth [DiscreteTopology 𝒢.strictPeriods] : Function.Injective (fun j : Fin (integerCuspWidth 𝒢) => @@ -436,7 +339,6 @@ private lemma quotient_T_pow_injective_integerCuspWidth classical intro j₁ j₂ hj rw [QuotientGroup.eq, Subgroup.mem_subgroupOf] at hj - -- The underlying GL element `((T^j₁)⁻¹ * T^j₂)` maps to `T^(j₂ - j₁) = upperRightHom (j₂ - j₁)`. have hSub : (((((Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict ((ModularGroup.T : SL(2, ℤ))^(j₁ : ℕ)))⁻¹ * (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict @@ -447,40 +349,26 @@ private lemma quotient_T_pow_injective_integerCuspWidth MonoidHom.coe_rangeRestrict, MonoidHom.coe_rangeRestrict, ← map_inv, ← map_mul, zpow_sub, zpow_natCast, zpow_natCast] congr 1 - -- Powers of T commute, so (T^j₁)⁻¹ * T^j₂ = T^j₂ * (T^j₁)⁻¹. exact ((Commute.pow_pow_self ModularGroup.T (j₂ : ℕ) (j₁ : ℕ)).inv_right).eq.symm rw [hSub, mapGL_T_zpow_eq_upperRightHom] at hj rw [show (((j₂ : ℤ) - (j₁ : ℤ) : ℤ) : ℝ) = ((j₂ : ℝ) - (j₁ : ℝ)) by push_cast; ring, ← Subgroup.mem_strictPeriods_iff] at hj - -- A natural number `d` in `𝒢.strictPeriods` with `d < integerCuspWidth 𝒢` must be `0`, - -- by minimality of `integerCuspWidth`. - have h_min_zero : ∀ d : ℕ, d < integerCuspWidth 𝒢 → (d : ℝ) ∈ 𝒢.strictPeriods → d = 0 := by - intro d hd_lt hd_mem - by_contra hd_ne - have : integerCuspWidth 𝒢 ≤ d := - Nat.find_min' (p := fun n => 0 < n ∧ (n : ℝ) ∈ 𝒢.strictPeriods) _ + have h_min_zero : ∀ d : ℕ, d < integerCuspWidth 𝒢 → (d : ℝ) ∈ 𝒢.strictPeriods → d = 0 := + fun d hd_lt hd_mem => by + by_contra hd_ne + exact Nat.find_min (p := fun n => 0 < n ∧ (n : ℝ) ∈ 𝒢.strictPeriods) _ hd_lt ⟨Nat.pos_of_ne_zero hd_ne, hd_mem⟩ - omega - -- WLOG split on `j₁ ≤ j₂` to handle the natural-number subtraction. rcases le_total (j₁ : ℕ) (j₂ : ℕ) with hle | hle - · have hd_real : (((j₂ : ℕ) - (j₁ : ℕ) : ℕ) : ℝ) = (j₂ : ℝ) - (j₁ : ℝ) := - Nat.cast_sub hle - have hd_zero : (j₂ : ℕ) - (j₁ : ℕ) = 0 := - h_min_zero _ (by have := j₂.isLt; omega) (hd_real ▸ hj) + · have : (j₂ : ℕ) - (j₁ : ℕ) = 0 := + h_min_zero _ (by have := j₂.isLt; omega) (by rw [Nat.cast_sub hle]; exact hj) exact Fin.ext (by omega) - · have hd_real : (((j₁ : ℕ) - (j₂ : ℕ) : ℕ) : ℝ) = (j₁ : ℝ) - (j₂ : ℝ) := - Nat.cast_sub hle - have hd_mem : (((j₁ : ℕ) - (j₂ : ℕ) : ℕ) : ℝ) ∈ 𝒢.strictPeriods := by - rw [hd_real] - convert neg_mem hj using 1 - ring - have hd_zero : (j₁ : ℕ) - (j₂ : ℕ) = 0 := - h_min_zero _ (by have := j₁.isLt; omega) hd_mem + · have : (j₁ : ℕ) - (j₂ : ℕ) = 0 := + h_min_zero _ (by have := j₁.isLt; omega) <| by + rw [Nat.cast_sub hle] + simpa [neg_sub] using neg_mem hj exact Fin.ext (by omega) omit [𝒢.HasDetPlusMinusOne] in -/-- For `j : Fin (integerCuspWidth 𝒢)`, the function-level value of `quotientFunc f` at the -coset `⟦T^j⟧` is `τ ↦ f (ofComplex (τ - j))`. -/ private lemma quotientFunc_T_pow_apply (j : Fin (integerCuspWidth 𝒢)) (τ : ℍ) : SlashInvariantForm.quotientFunc f @@ -509,9 +397,6 @@ private lemma quotientFunc_T_pow_apply rw [show ((-((j : ℕ) : ℤ) : ℤ) : ℝ) = (-(j : ℕ) : ℝ) by push_cast; ring, h_eq] omit [𝒢.HasDetPlusMinusOne] in -/-- The image set of `j ↦ ⟦T^j⟧` (for `j ∈ Fin (integerCuspWidth 𝒢)`) in -`𝒮ℒ ⧸ 𝒢.subgroupOf 𝒮ℒ` is invariant under left multiplication by `T_𝒮ℒ`: if -`⟦x⟧ ∈ image`, then `⟦T_𝒮ℒ * x⟧ ∈ image`. -/ private lemma image_T_pow_invariant_under_T_mul [DiscreteTopology 𝒢.strictPeriods] [DecidableEq (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))] {x : 𝒮ℒ} @@ -529,56 +414,23 @@ private lemma image_T_pow_invariant_under_T_mul classical set T_𝒮ℒ : 𝒮ℒ := (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict (ModularGroup.T : SL(2, ℤ)) with hT_𝒮ℒ_def - set h_𝒢 := integerCuspWidth 𝒢 - rw [Finset.mem_image] at hx - obtain ⟨j, _, hj⟩ := hx - -- ⟦x⟧ = ⟦T^j⟧ ⇒ ⟦T_𝒮ℒ * x⟧ = ⟦T^(j+1)⟧. - have h_eq_quot : (⟦T_𝒮ℒ * x⟧ : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) = - (⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict - ((ModularGroup.T : SL(2, ℤ))^((j : ℕ) + 1))⟧ : - 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) := by - have h_eq_quot' : (⟦T_𝒮ℒ * x⟧ : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) = - (⟦T_𝒮ℒ * (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict - ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ : - 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) := by - rw [QuotientGroup.eq] at hj ⊢ - have hj' : x⁻¹ * (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict - ((ModularGroup.T : SL(2, ℤ))^(j : ℕ)) ∈ - (𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ := by - simpa [mul_inv_rev, inv_inv] using inv_mem hj - convert hj' using 1 - group - rw [h_eq_quot'] - congr 1 - rw [hT_𝒮ℒ_def, ← MonoidHom.map_mul, ← pow_succ'] - rw [h_eq_quot, Finset.mem_image] - by_cases hj1 : (j : ℕ) + 1 < h_𝒢 + obtain ⟨j, _, hj⟩ := Finset.mem_image.mp hx + rw [Finset.mem_image, show (⟦T_𝒮ℒ * x⟧ : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) = + ⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict + ((ModularGroup.T : SL(2, ℤ))^((j : ℕ) + 1))⟧ by + rw [pow_succ', map_mul, hT_𝒮ℒ_def.symm, QuotientGroup.eq] + convert inv_mem (QuotientGroup.eq.mp hj) using 1 + group] + by_cases hj1 : (j : ℕ) + 1 < integerCuspWidth 𝒢 · exact ⟨⟨(j : ℕ) + 1, hj1⟩, Finset.mem_univ _, rfl⟩ - -- Wrap-around case: j+1 = h_𝒢, so ⟦T^h_𝒢⟧ = ⟦1⟧ = imgFn 0 (using T^h_𝒢 ∈ 𝒢). - · have hj_eq : (j : ℕ) + 1 = h_𝒢 := by + · have hj_eq : (j : ℕ) + 1 = integerCuspWidth 𝒢 := by have := j.isLt omega - have h_𝒢_pos : 0 < h_𝒢 := integerCuspWidth_pos - refine ⟨⟨0, h_𝒢_pos⟩, Finset.mem_univ _, ?_⟩ + refine ⟨⟨0, integerCuspWidth_pos⟩, Finset.mem_univ _, ?_⟩ rw [hj_eq, QuotientGroup.eq, Subgroup.mem_subgroupOf] - have h_simp : (((Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict - ((ModularGroup.T : SL(2, ℤ))^(((⟨0, h_𝒢_pos⟩ : Fin h_𝒢) : ℕ))))⁻¹ * - (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict - ((ModularGroup.T : SL(2, ℤ))^h_𝒢) : 𝒮ℒ).val = - ((ModularGroup.T : SL(2, ℤ))^h_𝒢 : GL (Fin 2) ℝ) := by - change (((Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict - ((ModularGroup.T : SL(2, ℤ))^(0 : ℕ)))⁻¹ * - (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict - ((ModularGroup.T : SL(2, ℤ))^h_𝒢) : 𝒮ℒ).val = _ - rw [Subgroup.coe_mul, Subgroup.coe_inv, - MonoidHom.coe_rangeRestrict, MonoidHom.coe_rangeRestrict, pow_zero, map_one, - inv_one, one_mul, map_pow] - rfl - rw [h_simp] - exact T_zpow_integerCuspWidth_mem + simpa using T_zpow_integerCuspWidth_mem (𝒢 := 𝒢) omit [𝒢.HasDetPlusMinusOne] in -/-- SMul-version of `image_T_pow_invariant_under_T_mul` via `Quotient.inductionOn`. -/ private lemma image_T_pow_invariant_under_T_smul [DiscreteTopology 𝒢.strictPeriods] [DecidableEq (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))] @@ -597,8 +449,6 @@ private lemma image_T_pow_invariant_under_T_smul | h x => exact image_T_pow_invariant_under_T_mul (𝒢 := 𝒢) hq omit [𝒢.HasDetPlusMinusOne] in -/-- The image set is closed under `T_𝒮ℒ⁻¹ • _`: since `T_𝒮ℒ • _` is a permutation on a -finite set, `T_𝒮ℒ • image = image` and hence the iff version. -/ private lemma image_T_pow_smul_inv_iff [DiscreteTopology 𝒢.strictPeriods] [DecidableEq (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))] @@ -637,9 +487,6 @@ private lemma image_T_pow_smul_inv_iff exact h_inj hq'_eq ▸ hq'_mem omit [𝒢.HasDetPlusMinusOne] in -/-- The "rest factor" `∏_{q ∉ image} quotientFunc f q` is invariant under `τ ↦ 1 +ᵥ τ`: -each factor is shifted to `quotientFunc f (T_𝒮ℒ⁻¹ • q) τ`, and `T_𝒮ℒ⁻¹ • _` permutes the -non-image cosets (since `image` is `T_𝒮ℒ`-invariant). -/ private lemma prod_quotientFunc_filter_image_one_vadd [DiscreteTopology 𝒢.strictPeriods] [DecidableEq (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ))] @@ -658,36 +505,21 @@ private lemma prod_quotientFunc_filter_image_one_vadd 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)))), SlashInvariantForm.quotientFunc f q τ := by set T_𝒮ℒ : 𝒮ℒ := (Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict - (ModularGroup.T : SL(2, ℤ)) with hT_𝒮ℒ_def - have hT_𝒮ℒ_val : (T_𝒮ℒ : GL (Fin 2) ℝ) = - Matrix.SpecialLinearGroup.mapGL ℝ (ModularGroup.T : SL(2, ℤ)) := by - rw [hT_𝒮ℒ_def] - rfl - have h_step1 : ∀ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), + (ModularGroup.T : SL(2, ℤ)) + have h_step1 (q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) : SlashInvariantForm.quotientFunc f q ((1 : ℝ) +ᵥ τ) = SlashInvariantForm.quotientFunc f (T_𝒮ℒ⁻¹ • q) τ := by - intro q - have h_slash_eq : (SlashInvariantForm.quotientFunc f q) ((1 : ℝ) +ᵥ τ) = - ((SlashInvariantForm.quotientFunc f q) ∣[k] T_𝒮ℒ.val) τ := by - rw [hT_𝒮ℒ_val] - have h := slash_T_zpow_apply_general (k := k) - (1 : ℤ) (SlashInvariantForm.quotientFunc f q) τ - simpa [zpow_one] using h.symm - rw [h_slash_eq, SlashInvariantForm.quotientFunc_smul f T_𝒮ℒ.2] - refine (Finset.prod_congr rfl (fun q _ => h_step1 q)).trans ?_ - -- Re-index using the bijection MulAction.toPerm T_𝒮ℒ⁻¹. - refine Finset.prod_equiv (MulAction.toPerm T_𝒮ℒ⁻¹) ?_ ?_ - · intro q - simp only [Finset.mem_filter, Finset.mem_univ, true_and] - exact (image_T_pow_smul_inv_iff (𝒢 := 𝒢) q).symm.not - · intro q _ - rfl + rw [show (SlashInvariantForm.quotientFunc f q) ((1 : ℝ) +ᵥ τ) = + ((SlashInvariantForm.quotientFunc f q) ∣[k] T_𝒮ℒ.val) τ by + simpa [zpow_one] using + (slash_T_zpow_apply_general (k := k) 1 (SlashInvariantForm.quotientFunc f q) τ).symm, + SlashInvariantForm.quotientFunc_smul f T_𝒮ℒ.2] + refine (Finset.prod_congr rfl fun q _ => h_step1 q).trans <| + Finset.prod_equiv (MulAction.toPerm T_𝒮ℒ⁻¹) + (fun q => by simpa using (image_T_pow_smul_inv_iff (𝒢 := 𝒢) q).symm.not) + (fun _ _ => rfl) omit [𝒢.HasDetPlusMinusOne] in -/-- The "rest factor" decomposition of the modular norm `N(f)` at period `1`. The norm splits as -a product over the `integerCuspWidth 𝒢` cosets corresponding to the powers of `T` (which give the -factors `f(τ - j)` for `j = 0, ..., integerCuspWidth 𝒢 - 1`) times a "rest" function `rest` that -is `1`-periodic and whose period-`1` cusp function is analytic at `0`. -/ private lemma analyticAt_cuspFunction_one_norm_rest [DiscreteTopology 𝒢.strictPeriods] : ∃ rest : ℍ → ℂ, @@ -698,7 +530,6 @@ private lemma analyticAt_cuspFunction_one_norm_rest classical set h_𝒢 := integerCuspWidth 𝒢 letI : Fintype (𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) := Fintype.ofFinite _ - -- The injective map `j ↦ ⟦T^j⟧ : Fin h_𝒢 → 𝒮ℒ ⧸ 𝒢.subgroupOf 𝒮ℒ` and its `Finset` image. set imgFn : Fin h_𝒢 → 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ) := fun j => ⟦(Matrix.SpecialLinearGroup.mapGL ℝ).rangeRestrict ((ModularGroup.T : SL(2, ℤ))^(j : ℕ))⟧ @@ -706,116 +537,66 @@ private lemma analyticAt_cuspFunction_one_norm_rest Finset.univ.image imgFn with himage_def have h_imgFn_inj : Function.Injective imgFn := quotient_T_pow_injective_integerCuspWidth (𝒢 := 𝒢) - -- Define rest as the product over non-image cosets. let rest : ℍ → ℂ := fun τ => ∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q τ - -- The key formula: each `quotientFunc f (imgFn j)` equals `f(ofComplex(τ - j))`. - have h_quotientFunc_imgFn : ∀ (j : Fin h_𝒢) (τ : ℍ), - SlashInvariantForm.quotientFunc f (imgFn j) τ = f (ofComplex ((τ : ℂ) - j)) := - fun j τ => quotientFunc_T_pow_apply f j τ - -- `rest` is invariant under `τ ↦ 1 +ᵥ τ` since `T_𝒮ℒ⁻¹ • _` re-indexes the product. - have h_rest_periodic_vAdd : ∀ τ : ℍ, rest ((1 : ℝ) +ᵥ τ) = rest τ := - prod_quotientFunc_filter_image_one_vadd f - have h_rest_periodic : Function.Periodic (rest ∘ ofComplex) 1 := by - intro w - simp only [Function.comp_apply] - by_cases hw : 0 < w.im - · have hw1 : 0 < (w + 1).im := by simpa using hw - rw [ofComplex_apply_of_im_pos hw1, ofComplex_apply_of_im_pos hw] - have h_eq : ((1 : ℝ) +ᵥ (⟨w, hw⟩ : ℍ) : ℍ) = (⟨w + 1, hw1⟩ : ℍ) := - UpperHalfPlane.ext (by simp [coe_vadd, add_comm]) - exact h_eq ▸ h_rest_periodic_vAdd ⟨w, hw⟩ - · have hw0 : w.im ≤ 0 := not_lt.mp hw - have hw1 : (w + 1).im ≤ 0 := by simpa using hw0 - rw [ofComplex_apply_of_im_nonpos hw1, ofComplex_apply_of_im_nonpos hw0] - -- `IsCusp ∞ 𝒮ℒ` is needed to invoke `bdd_at_cusps'` on `translate f r⁻¹`. - have h_isCusp_𝒮ℒ : IsCusp (OnePoint.infty : OnePoint ℝ) (𝒮ℒ : Subgroup (GL (Fin 2) ℝ)) := - Subgroup.isCusp_of_mem_strictPeriods (𝒢 := 𝒮ℒ) zero_lt_one (by simp) + have h_rest_eq : (rest : ℍ → ℂ) = + ∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q := + funext fun _ => (Finset.prod_apply ..).symm have h_quotientFunc_mdiff : ∀ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), - MDiff (SlashInvariantForm.quotientFunc f q) := by - refine Quotient.forall.mpr fun r => ?_ - exact (ModularForm.translate f r.val⁻¹).holo' + MDiff (SlashInvariantForm.quotientFunc f q) := + Quotient.forall.mpr fun r => (ModularForm.translate f r.val⁻¹).holo' have h_quotientFunc_bdd : ∀ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), - IsBoundedAtImInfty (SlashInvariantForm.quotientFunc f q) := by - refine Quotient.forall.mpr fun ⟨r, hr⟩ => ?_ - exact OnePoint.isBoundedAt_infty_iff.mp - ((ModularForm.translate f _).bdd_at_cusps' (h_isCusp_𝒮ℒ.of_isFiniteRelIndex_conj hr)) - have h_rest_eq : rest = - ∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q := by - ext τ - simp [rest, Finset.prod_apply] - have h_rest_mdiff : MDiff rest := by - rw [h_rest_eq] - exact MDifferentiable.prod fun q _ => h_quotientFunc_mdiff q - have h_rest_bdd : IsBoundedAtImInfty rest := by - rw [h_rest_eq] - unfold IsBoundedAtImInfty - rw [show ((∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q : - ℍ → ℂ)) = - ∏ q ∈ Finset.univ.filter (· ∉ image), (SlashInvariantForm.quotientFunc f q : ℍ → ℂ) from - rfl] - exact Filter.BoundedAtFilter.prod _ fun q _ => h_quotientFunc_bdd q - refine ⟨rest, ?_, ?_, ?_⟩ - · exact h_rest_periodic - · -- Analyticity of cuspFunction 1 rest at 0. - exact analyticAt_cuspFunction_zero one_pos h_rest_periodic h_rest_mdiff h_rest_bdd - · -- Decomposition formula. - intro τ - have h_unfold_norm : (ModularForm.norm 𝒮ℒ f : ℍ → ℂ) τ = - ∏ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), - SlashInvariantForm.quotientFunc f q τ := by - rw [ModularForm.coe_norm, Finset.prod_apply] - rw [h_unfold_norm] - -- Split the universal product into image vs non-image cosets. - rw [show (∏ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), - SlashInvariantForm.quotientFunc f q τ) = - (∏ q ∈ Finset.univ.filter (· ∈ image), SlashInvariantForm.quotientFunc f q τ) * - (∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q τ) from - (Finset.prod_filter_mul_prod_filter_not _ _ _).symm] - -- The non-image factor is `rest τ` by definition. - -- The image factor we relate to ∏ j ∈ range h_𝒢, f(ofComplex(τ - j)). - rw [Finset.filter_univ_mem] - -- Now: (∏ q ∈ image, quotientFunc f q τ) * rest τ = (∏ j ∈ range h_𝒢, ...) * rest τ - congr 1 - -- (∏ q ∈ image, quotientFunc f q τ) = ∏ j ∈ range h_𝒢, f(ofComplex(τ - j)) - rw [himage_def, Finset.prod_image h_imgFn_inj.injOn, - Finset.prod_congr rfl (fun j _ => h_quotientFunc_imgFn j τ)] - exact Fin.prod_univ_eq_prod_range (fun n => f (ofComplex ((τ : ℂ) - (n : ℕ)))) h_𝒢 + IsBoundedAtImInfty (SlashInvariantForm.quotientFunc f q) := + Quotient.forall.mpr fun ⟨r, hr⟩ => OnePoint.isBoundedAt_infty_iff.mp + ((ModularForm.translate f _).bdd_at_cusps' + ((Subgroup.isCusp_of_mem_strictPeriods (𝒢 := 𝒮ℒ) zero_lt_one + (by simp)).of_isFiniteRelIndex_conj hr)) + have h_rest_mdiff : MDiff rest := + h_rest_eq ▸ MDifferentiable.prod fun q _ => h_quotientFunc_mdiff q + have h_rest_bdd : IsBoundedAtImInfty rest := + h_rest_eq ▸ Filter.BoundedAtFilter.prod _ fun q _ => h_quotientFunc_bdd q + have h_rest_periodic : Function.Periodic (rest ∘ ofComplex) 1 := fun w => by + simp only [Function.comp_apply] + by_cases! hw : 0 < w.im + · have hw1 : 0 < (w + 1).im := by simpa using hw + rw [ofComplex_apply_of_im_pos hw1, ofComplex_apply_of_im_pos hw, + show (⟨w + 1, hw1⟩ : ℍ) = ((1 : ℝ) +ᵥ (⟨w, hw⟩ : ℍ) : ℍ) from + UpperHalfPlane.ext (by simp [add_comm])] + exact prod_quotientFunc_filter_image_one_vadd f ⟨w, hw⟩ + · rw [ofComplex_apply_eq_of_im_nonpos (by simpa using hw) hw] + refine ⟨rest, h_rest_periodic, + analyticAt_cuspFunction_zero one_pos h_rest_periodic h_rest_mdiff h_rest_bdd, fun τ => ?_⟩ + rw [ModularForm.coe_norm, Finset.prod_apply, + ← Finset.prod_filter_mul_prod_filter_not _ (· ∈ image), Finset.filter_univ_mem, + himage_def, Finset.prod_image h_imgFn_inj.injOn, + Finset.prod_congr rfl fun j _ => quotientFunc_T_pow_apply f j τ, + Fin.prod_univ_eq_prod_range (fun n => f (ofComplex ((τ : ℂ) - (n : ℕ)))) h_𝒢] omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in -/-- For an `h`-periodic function `f`, the order of `qExpansion (m * h) f` is at least the order -of `qExpansion h f`. (In fact it equals `m` times the order of `qExpansion h f`.) -/ private lemma qExpansion_order_le_qExpansion_nat_mul_order {h : ℝ} {g : ℍ → ℂ} {m : ℕ} (hh : 0 < h) (hm : 0 < m) (hg_per : Function.Periodic (g ∘ ofComplex) h) (hg_bdd : IsBoundedAtImInfty g) (hg_mdiff : MDiff g) : (qExpansion h g).order ≤ (qExpansion ((m * h : ℝ)) g).order := by - have hmh : (0 : ℝ) < (m : ℝ) * h := mul_pos (by exact_mod_cast hm) hh + have hmh : (0 : ℝ) < (m : ℝ) * h := by positivity have hg_per_mh : Function.Periodic (g ∘ ofComplex) (((m : ℝ) * h : ℝ)) := by - convert hg_per.nat_mul m using 1 - push_cast - ring + simpa using hg_per.nat_mul m have hLHS_an : AnalyticAt ℂ (cuspFunction h g) 0 := analyticAt_cuspFunction_zero hh hg_per hg_mdiff hg_bdd have hRHS_an : AnalyticAt ℂ (cuspFunction ((m : ℝ) * h) g) 0 := analyticAt_cuspFunction_zero hmh hg_per_mh hg_mdiff hg_bdd rw [qExpansion_order_eq_analyticOrderAt_cuspFunction hLHS_an, qExpansion_order_eq_analyticOrderAt_cuspFunction hRHS_an] - -- Show cuspFunction (m * h) g =ᶠ[𝓝 0] cuspFunction h g ∘ (·^m). - have hzero : (0 : ℂ) ^ m = 0 := zero_pow hm.ne' - have h_RHS_lift_cts : ContinuousAt (fun q : ℂ => cuspFunction h g (q ^ m)) 0 := by - have h1 : ContinuousAt (fun q : ℂ => q ^ m) 0 := by fun_prop - exact hLHS_an.continuousAt.comp_of_eq h1 hzero + have h_RHS_lift_cts : ContinuousAt (fun q : ℂ => cuspFunction h g (q ^ m)) 0 := + hLHS_an.continuousAt.comp_of_eq (by fun_prop) (zero_pow hm.ne') have h_eqOn : (fun q : ℂ => cuspFunction ((m : ℝ) * h) g q) =ᶠ[𝓝 0] (fun q : ℂ => cuspFunction h g (q ^ m)) := by - rw [← hRHS_an.continuousAt.eventuallyEq_nhds_iff_eventuallyEq_nhdsNE h_RHS_lift_cts] - have hball : Metric.ball (0 : ℂ) 1 ∈ 𝓝 (0 : ℂ) := - Metric.ball_mem_nhds 0 zero_lt_one - rw [eventuallyEq_nhdsWithin_iff] - filter_upwards [hball] with q hq_lt hq_ne + rw [← hRHS_an.continuousAt.eventuallyEq_nhds_iff_eventuallyEq_nhdsNE h_RHS_lift_cts, + eventuallyEq_nhdsWithin_iff] + filter_upwards [Metric.ball_mem_nhds (0 : ℂ) zero_lt_one] with q hq_lt hq_ne rw [mem_ball_zero_iff] at hq_lt set τ : ℍ := ⟨Function.Periodic.invQParam ((m : ℝ) * h) q, Function.Periodic.im_invQParam_pos_of_norm_lt_one hmh hq_lt hq_ne⟩ @@ -826,102 +607,64 @@ private lemma qExpansion_order_le_qExpansion_nat_mul_order simp only [Function.Periodic.qParam, ← Complex.exp_nat_mul, Complex.ofReal_mul, Complex.ofReal_natCast] congr 1 - have : (m : ℂ) ≠ 0 := mod_cast hm.ne' - field_simp - have hLHS_eq : cuspFunction ((m : ℝ) * h) g q = g τ := by - rw [← hτq] - exact eq_cuspFunction τ hmh.ne' hg_per_mh - have hRHS_eq : cuspFunction h g (q ^ m) = g τ := by - rw [hqm] - exact eq_cuspFunction τ hh.ne' hg_per - rw [hLHS_eq, hRHS_eq] + field_simp [show (m : ℂ) ≠ 0 from mod_cast hm.ne'] + rw [hqm, ← hτq, eq_cuspFunction τ hmh.ne' hg_per_mh, + eq_cuspFunction τ hh.ne' hg_per] rw [analyticOrderAt_congr h_eqOn, analyticOrderAt_comp_pow_zero hLHS_an hm] exact ENat.self_le_mul_right _ (by exact_mod_cast hm.ne') omit [𝒢.HasDetPlusMinusOne] in -/-- **Key bridge lemma.** The order of vanishing of `qExpansion 1 (norm 𝒮ℒ f)` at the cusp `∞` -is at least the order of vanishing of `qExpansion 𝒢.strictWidthInfty f` at the cusp `∞`. - -The proof writes `N(f) = ∏_q quotientFunc f q` and isolates the `𝒮ℒ_∞`-related factors (one -factor per element of `𝒮ℒ_∞ ⧸ 𝒢_∞`, i.e. `𝒢.strictWidthInfty` factors), whose product is -`1`-periodic and contributes order `(qExpansion 𝒢.strictWidthInfty f).order` in `q`. The -remaining factors are bounded at `∞` (since `f` is bounded at every cusp of `𝒢`), so they -contribute order `≥ 0`. -/ private lemma qExpansion_norm_order_ge_qExpansion_order [DiscreteTopology 𝒢.strictPeriods] : (qExpansion 𝒢.strictWidthInfty f).order ≤ (qExpansion 1 (ModularForm.norm 𝒮ℒ f)).order := by - -- Express `(integerCuspWidth 𝒢 : ℝ)` as `m' * 𝒢.strictWidthInfty` for some positive `m' : ℕ`, - -- using `strictPeriods = AddSubgroup.zmultiples 𝒢.strictWidthInfty`. have hn_pos : 0 < integerCuspWidth 𝒢 := integerCuspWidth_pos have hnR_pos : (0 : ℝ) < integerCuspWidth 𝒢 := by exact_mod_cast hn_pos - have hw_nn : (0 : ℝ) ≤ 𝒢.strictWidthInfty := 𝒢.strictWidthInfty_nonneg - have hn_mem : (integerCuspWidth 𝒢 : ℝ) ∈ 𝒢.strictPeriods := - integerCuspWidth_mem_strictPeriods - rw [Subgroup.strictPeriods_eq_zmultiples_strictWidthInfty, - AddSubgroup.mem_zmultiples_iff] at hn_mem - obtain ⟨m, hm⟩ := hn_mem - rw [zsmul_eq_mul] at hm - have hw_pos : (0 : ℝ) < 𝒢.strictWidthInfty := by - refine hw_nn.lt_of_ne fun heq => ?_ - rw [← heq, mul_zero] at hm - exact (Nat.cast_pos.mpr hn_pos).ne' hm.symm - have hm_pos : (0 : ℤ) < m := by + obtain ⟨m, hm⟩ : ∃ m : ℤ, (integerCuspWidth 𝒢 : ℝ) = m * 𝒢.strictWidthInfty := by + obtain ⟨m, hm⟩ := AddSubgroup.mem_zmultiples_iff.mp <| + Subgroup.strictPeriods_eq_zmultiples_strictWidthInfty (𝒢 := 𝒢) ▸ + integerCuspWidth_mem_strictPeriods + exact ⟨m, by rw [← hm, zsmul_eq_mul]⟩ + have hw_pos : (0 : ℝ) < 𝒢.strictWidthInfty := + 𝒢.strictWidthInfty_nonneg.lt_of_ne fun heq => by + rw [← heq, mul_zero] at hm; exact hnR_pos.ne' hm + have hm_pos : 0 < m := by by_contra hle - have hm_nn : (m : ℝ) ≤ 0 := by exact_mod_cast not_lt.mp hle - have : (m : ℝ) * 𝒢.strictWidthInfty ≤ 0 := - mul_nonpos_of_nonpos_of_nonneg hm_nn hw_nn - rw [hm] at this - linarith + nlinarith [(Int.cast_nonpos (R := ℝ)).mpr (not_lt.mp hle), hw_pos.le] obtain ⟨m', rfl⟩ : ∃ m' : ℕ, m = (m' : ℤ) := ⟨m.toNat, (Int.toNat_of_nonneg hm_pos.le).symm⟩ have hm'_pos : 0 < m' := by exact_mod_cast hm_pos have hnRw : (integerCuspWidth 𝒢 : ℝ) = (m' : ℝ) * 𝒢.strictWidthInfty := by - rw [← hm] - push_cast - ring - -- `f` is `𝒢.strictWidthInfty`-periodic, bounded at `∞`, holomorphic; hence also `n`-periodic. - have hCusp : IsCusp (OnePoint.infty : OnePoint ℝ) 𝒢 := - Subgroup.isCusp_of_mem_strictPeriods hnR_pos integerCuspWidth_mem_strictPeriods + rw [hm]; push_cast; ring have hf_w_per : Function.Periodic ((f : ℍ → ℂ) ∘ ofComplex) 𝒢.strictWidthInfty := SlashInvariantFormClass.periodic_comp_ofComplex f 𝒢.strictWidthInfty_mem_strictPeriods - have hf_bdd : IsBoundedAtImInfty (f : ℍ → ℂ) := - OnePoint.isBoundedAt_infty_iff.mp (f.bdd_at_cusps' hCusp) - have hf_mdiff : MDiff (f : ℍ → ℂ) := f.holo' + have hf_bdd : IsBoundedAtImInfty (f : ℍ → ℂ) := OnePoint.isBoundedAt_infty_iff.mp <| + f.bdd_at_cusps' <| + Subgroup.isCusp_of_mem_strictPeriods hnR_pos integerCuspWidth_mem_strictPeriods have hf_n_per : Function.Periodic ((f : ℍ → ℂ) ∘ ofComplex) ((integerCuspWidth 𝒢 : ℕ) : ℝ) := by rw [hnRw] convert hf_w_per.nat_mul m' using 1 - push_cast - ring + push_cast; ring have h_w_le_n : (qExpansion 𝒢.strictWidthInfty (f : ℍ → ℂ)).order ≤ (qExpansion ((integerCuspWidth 𝒢 : ℕ) : ℝ) (f : ℍ → ℂ)).order := by rw [hnRw] - exact qExpansion_order_le_qExpansion_nat_mul_order hw_pos hm'_pos - hf_w_per hf_bdd hf_mdiff - -- Decompose `(norm 𝒮ℒ f) = (galoisProd n f) * rest` and apply `qExpansion_mul`. + exact qExpansion_order_le_qExpansion_nat_mul_order hw_pos hm'_pos hf_w_per hf_bdd f.holo' obtain ⟨rest, _, h_rest_an, h_decomp⟩ := analyticAt_cuspFunction_one_norm_rest f - have h_funeq : ((ModularForm.norm 𝒮ℒ f : ℍ → ℂ)) = - (galoisProd (integerCuspWidth 𝒢) (f : ℍ → ℂ)) * rest := - funext h_decomp have h_galois_an : AnalyticAt ℂ (cuspFunction 1 (galoisProd (integerCuspWidth 𝒢) (f : ℍ → ℂ))) 0 := - analyticAt_cuspFunction_zero one_pos - (galoisProd_periodic_one hn_pos hf_n_per) - (galoisProd_mdiff hf_mdiff) - (galoisProd_isBoundedAtImInfty hf_bdd) - have h_qexp_mul : qExpansion 1 (ModularForm.norm 𝒮ℒ f : ℍ → ℂ) = - qExpansion 1 (galoisProd (integerCuspWidth 𝒢) (f : ℍ → ℂ)) * qExpansion 1 rest := by - rw [h_funeq] - exact qExpansion_mul h_galois_an h_rest_an - rw [h_qexp_mul, PowerSeries.order_mul, - qExpansion_one_galoisProd_order_eq_qExpansion_self_order hn_pos hf_n_per hf_bdd hf_mdiff] + analyticAt_cuspFunction_zero one_pos (galoisProd_periodic_one hn_pos hf_n_per) + (galoisProd_mdiff f.holo') (galoisProd_isBoundedAtImInfty hf_bdd) + rw [show qExpansion 1 (ModularForm.norm 𝒮ℒ f : ℍ → ℂ) = + qExpansion 1 (galoisProd (integerCuspWidth 𝒢) (f : ℍ → ℂ)) * qExpansion 1 rest by + rw [funext h_decomp]; exact qExpansion_mul h_galois_an h_rest_an, + PowerSeries.order_mul, + qExpansion_one_galoisProd_order_eq_qExpansion_self_order hn_pos hf_n_per hf_bdd f.holo'] exact h_w_le_n.trans le_self_add omit [𝒢.HasDetPlusMinusOne] in -/-- **Sturm bound for finite-index subgroups of `SL(2, ℤ)`.** -If `f : ModularForm 𝒢 k` has zero coefficient on `q^i` in its q-expansion at the cusp `∞` -(at the natural period `𝒢.strictWidthInfty`) for every `i ≥ 0` with `12 * i ≤ k * [𝒮ℒ : 𝒢]`, -then `f = 0`. -/ +/-- **Sturm bound for arithmetic subgroups of `GL(2, ℝ)` commensurable with `SL(2, ℤ)`.** A +modular form of weight `k` whose first `⌊k · [𝒮ℒ : 𝒢] / 12⌋ + 1` q-expansion coefficients at +the cusp `∞` vanish is identically zero. -/ theorem sturm_bound_finiteIndex [DiscreteTopology 𝒢.strictPeriods] (h : ∀ i : ℕ, 12 * (i : ℤ) ≤ k * Nat.card (𝒮ℒ ⧸ 𝒢.subgroupOf 𝒮ℒ) → (qExpansion 𝒢.strictWidthInfty f).coeff i = 0) : f = 0 := by @@ -933,14 +676,7 @@ theorem sturm_bound_finiteIndex [DiscreteTopology 𝒢.strictPeriods] lt_of_lt_of_le (by exact_mod_cast Nat.lt_succ_self i) (h_le.trans (qExpansion_norm_order_ge_qExpansion_order f)) -/-- **Sturm bound for finite-index subgroups of `SL(2, ℤ)`.** -For `Γ` a finite-index subgroup of `SL(2, ℤ)` and `f : ModularForm Γ k` (viewed in -`GL(2, ℝ)`), if the first `⌊k · [SL(2,ℤ) : Γ] / 12⌋ + 1` coefficients of `f`'s q-expansion -at the cusp `∞` vanish, then `f` is identically zero. - -This is the classical Sturm bound. The cusp width at `∞` is -`(Γ : Subgroup (GL (Fin 2) ℝ)).strictWidthInfty`, which is automatically a positive integer -for `Γ ⊆ SL(2, ℤ)`. The bound is tight. -/ +/-- **Classical Sturm bound for finite-index subgroups of `SL(2, ℤ)`.** -/ theorem sturm_bound_finiteIndex_SL2Z {Γ : Subgroup SL(2, ℤ)} [Γ.FiniteIndex] {k : ℤ} (f : ModularForm (Γ : Subgroup (GL (Fin 2) ℝ)) k) (h : ∀ i : ℕ, 12 * (i : ℤ) ≤ k * Γ.index → From a895288712444e33d56a232e5c2013c88c5d2789 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 8 May 2026 10:30:03 +0100 Subject: [PATCH 48/49] chore(NumberTheory/ModularForms): /decompose-proof on SturmBound long lemmas Extract 4 private helpers: - `quotientFunc_mdiff`, `quotientFunc_isBoundedAtImInfty`: generic regularity of `SlashInvariantForm.quotientFunc` factors. - `qParam_sub_eq_mul_exp`: algebraic `qParam` substitution identity. - `integerCuspWidth_eq_nat_mul_strictWidthInfty`: bridges integer and real cusp widths. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../NumberTheory/ModularForms/SturmBound.lean | 70 ++++++++++++------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/SturmBound.lean index 1dcca8d404fad7..e3c16868ec95b9 100644 --- a/Mathlib/NumberTheory/ModularForms/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/SturmBound.lean @@ -99,6 +99,13 @@ private lemma galoisProd_isBoundedAtImInfty (hf_bdd : IsBoundedAtImInfty f) : simp [Complex.sub_im, Complex.natCast_im, τ.im_pos] simp [ofComplex_apply_of_im_pos him] +private lemma qParam_sub_eq_mul_exp (h : ℝ) (z j : ℂ) : + Function.Periodic.qParam h (z - j) = + Function.Periodic.qParam h z * Complex.exp (-2 * Real.pi * Complex.I * j / h) := by + simp only [Function.Periodic.qParam, ← Complex.exp_add] + congr 1 + ring + private lemma cuspFunction_one_galoisProd_pow_eq (hN : 0 < N) (hf_per : Function.Periodic (f ∘ ofComplex) (N : ℝ)) (hf_bdd : IsBoundedAtImInfty f) (hf_mdiff : MDiff f) : @@ -145,11 +152,8 @@ private lemma cuspFunction_one_galoisProd_pow_eq (hN : 0 < N) simp [Complex.sub_im, Complex.natCast_im, τ.im_pos] have hqj : q * Complex.exp (-2 * Real.pi * Complex.I * j / N) = Function.Periodic.qParam (N : ℝ) ((⟨(τ : ℂ) - j, him⟩ : ℍ) : ℂ) := by - rw [← hτq] - simp only [Function.Periodic.qParam, ← Complex.exp_add, Complex.ofReal_natCast] - congr 1 - field_simp - ring + rw [show ((N : ℕ) : ℂ) = (((N : ℕ) : ℝ) : ℂ) by push_cast; rfl, ← hτq, + ← qParam_sub_eq_mul_exp (N : ℝ) τ j] rw [hqj, eq_cuspFunction ⟨(τ : ℂ) - j, him⟩ hNR_ne hf_per, ofComplex_apply_of_im_pos him] private lemma qExpansion_order_eq_analyticOrderAt_cuspFunction {h : ℝ} {f : ℍ → ℂ} @@ -519,6 +523,21 @@ private lemma prod_quotientFunc_filter_image_one_vadd (fun q => by simpa using (image_T_pow_smul_inv_iff (𝒢 := 𝒢) q).symm.not) (fun _ _ => rfl) +omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in +private lemma quotientFunc_mdiff + (q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) : + MDiff (SlashInvariantForm.quotientFunc f q) := + Quotient.inductionOn q fun r => (ModularForm.translate f r.val⁻¹).holo' + +omit [𝒢.HasDetPlusMinusOne] in +private lemma quotientFunc_isBoundedAtImInfty + (q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) : + IsBoundedAtImInfty (SlashInvariantForm.quotientFunc f q) := + Quotient.inductionOn q fun ⟨r, hr⟩ => OnePoint.isBoundedAt_infty_iff.mp + ((ModularForm.translate f _).bdd_at_cusps' + ((Subgroup.isCusp_of_mem_strictPeriods (𝒢 := 𝒮ℒ) zero_lt_one + (by simp)).of_isFiniteRelIndex_conj hr)) + omit [𝒢.HasDetPlusMinusOne] in private lemma analyticAt_cuspFunction_one_norm_rest [DiscreteTopology 𝒢.strictPeriods] : @@ -542,21 +561,10 @@ private lemma analyticAt_cuspFunction_one_norm_rest have h_rest_eq : (rest : ℍ → ℂ) = ∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q := funext fun _ => (Finset.prod_apply ..).symm - have h_quotientFunc_mdiff : - ∀ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), - MDiff (SlashInvariantForm.quotientFunc f q) := - Quotient.forall.mpr fun r => (ModularForm.translate f r.val⁻¹).holo' - have h_quotientFunc_bdd : - ∀ q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ), - IsBoundedAtImInfty (SlashInvariantForm.quotientFunc f q) := - Quotient.forall.mpr fun ⟨r, hr⟩ => OnePoint.isBoundedAt_infty_iff.mp - ((ModularForm.translate f _).bdd_at_cusps' - ((Subgroup.isCusp_of_mem_strictPeriods (𝒢 := 𝒮ℒ) zero_lt_one - (by simp)).of_isFiniteRelIndex_conj hr)) have h_rest_mdiff : MDiff rest := - h_rest_eq ▸ MDifferentiable.prod fun q _ => h_quotientFunc_mdiff q + h_rest_eq ▸ MDifferentiable.prod fun q _ => quotientFunc_mdiff f q have h_rest_bdd : IsBoundedAtImInfty rest := - h_rest_eq ▸ Filter.BoundedAtFilter.prod _ fun q _ => h_quotientFunc_bdd q + h_rest_eq ▸ Filter.BoundedAtFilter.prod _ fun q _ => quotientFunc_isBoundedAtImInfty f q have h_rest_periodic : Function.Periodic (rest ∘ ofComplex) 1 := fun w => by simp only [Function.comp_apply] by_cases! hw : 0 < w.im @@ -614,10 +622,10 @@ private lemma qExpansion_order_le_qExpansion_nat_mul_order exact ENat.self_le_mul_right _ (by exact_mod_cast hm.ne') omit [𝒢.HasDetPlusMinusOne] in -private lemma qExpansion_norm_order_ge_qExpansion_order +private lemma integerCuspWidth_eq_nat_mul_strictWidthInfty + (𝒢 : Subgroup (GL (Fin 2) ℝ)) [𝒢.IsFiniteRelIndex 𝒮ℒ] [DiscreteTopology 𝒢.strictPeriods] : - (qExpansion 𝒢.strictWidthInfty f).order ≤ - (qExpansion 1 (ModularForm.norm 𝒮ℒ f)).order := by + ∃ m : ℕ, 0 < m ∧ (integerCuspWidth 𝒢 : ℝ) = m * 𝒢.strictWidthInfty := by have hn_pos : 0 < integerCuspWidth 𝒢 := integerCuspWidth_pos have hnR_pos : (0 : ℝ) < integerCuspWidth 𝒢 := by exact_mod_cast hn_pos obtain ⟨m, hm⟩ : ∃ m : ℤ, (integerCuspWidth 𝒢 : ℝ) = m * 𝒢.strictWidthInfty := by @@ -631,10 +639,22 @@ private lemma qExpansion_norm_order_ge_qExpansion_order have hm_pos : 0 < m := by by_contra hle nlinarith [(Int.cast_nonpos (R := ℝ)).mpr (not_lt.mp hle), hw_pos.le] - obtain ⟨m', rfl⟩ : ∃ m' : ℕ, m = (m' : ℤ) := ⟨m.toNat, (Int.toNat_of_nonneg hm_pos.le).symm⟩ - have hm'_pos : 0 < m' := by exact_mod_cast hm_pos - have hnRw : (integerCuspWidth 𝒢 : ℝ) = (m' : ℝ) * 𝒢.strictWidthInfty := by - rw [hm]; push_cast; ring + refine ⟨m.toNat, by omega, ?_⟩ + rw [hm] + congr 1 + exact_mod_cast (Int.toNat_of_nonneg hm_pos.le).symm + +omit [𝒢.HasDetPlusMinusOne] in +private lemma qExpansion_norm_order_ge_qExpansion_order + [DiscreteTopology 𝒢.strictPeriods] : + (qExpansion 𝒢.strictWidthInfty f).order ≤ + (qExpansion 1 (ModularForm.norm 𝒮ℒ f)).order := by + obtain ⟨m', hm'_pos, hnRw⟩ := integerCuspWidth_eq_nat_mul_strictWidthInfty 𝒢 + have hn_pos : 0 < integerCuspWidth 𝒢 := integerCuspWidth_pos + have hnR_pos : (0 : ℝ) < integerCuspWidth 𝒢 := by exact_mod_cast hn_pos + have hw_pos : (0 : ℝ) < 𝒢.strictWidthInfty := + 𝒢.strictWidthInfty_nonneg.lt_of_ne fun heq => by + rw [← heq, mul_zero] at hnRw; exact hnR_pos.ne' hnRw have hf_w_per : Function.Periodic ((f : ℍ → ℂ) ∘ ofComplex) 𝒢.strictWidthInfty := SlashInvariantFormClass.periodic_comp_ofComplex f 𝒢.strictWidthInfty_mem_strictPeriods have hf_bdd : IsBoundedAtImInfty (f : ℍ → ℂ) := OnePoint.isBoundedAt_infty_iff.mp <| From 711101d0674d9ffe48b5ef07658a5f9c00628c9e Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Fri, 8 May 2026 10:56:29 +0100 Subject: [PATCH 49/49] chore(NumberTheory/ModularForms): promote 6 SturmBound helpers upstream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move private helpers to their proper mathlib files: - `analyticOrderAt_prod`, `analyticOrderAt_comp_pow_zero` → Analytic/Order.lean - `qExpansion_order_eq_analyticOrderAt_cuspFunction`, `qExpansion_order_le_qExpansion_nat_mul_order` → ModularForms/QExpansion.lean - `SlashInvariantForm.quotientFunc_mdiff`, `SlashInvariantForm.quotientFunc_isBoundedAtImInfty` → ModularForms/NormTrace.lean Each is now public with a docstring; signatures generalised where applicable (`comp_pow_zero` from `ℂ → ℂ` to `𝕜 → E`; `quotientFunc_*` from `f : ModularForm` to `f : F` with `[ModularFormClass F 𝒢 k]`). Co-Authored-By: Claude Opus 4.7 (1M context) --- Mathlib/Analysis/Analytic/Order.lean | 27 +++++ .../NumberTheory/ModularForms/NormTrace.lean | 13 +++ .../NumberTheory/ModularForms/QExpansion.lean | 56 +++++++++- .../NumberTheory/ModularForms/SturmBound.lean | 103 +----------------- 4 files changed, 99 insertions(+), 100 deletions(-) diff --git a/Mathlib/Analysis/Analytic/Order.lean b/Mathlib/Analysis/Analytic/Order.lean index a740430c245744..ad14438fe21157 100644 --- a/Mathlib/Analysis/Analytic/Order.lean +++ b/Mathlib/Analysis/Analytic/Order.lean @@ -451,6 +451,18 @@ theorem analyticOrderNatAt_mul (hf : AnalyticAt 𝕜 f z₀) (hg : AnalyticAt analyticOrderNatAt (f * g) z₀ = analyticOrderNatAt f z₀ + analyticOrderNatAt g z₀ := by simp [analyticOrderNatAt, analyticOrderAt_mul, ENat.toNat_add, *] +/-- The order is additive when taking a finite product of analytic functions. -/ +theorem analyticOrderAt_prod {ι : Type*} {s : Finset ι} {F : ι → 𝕜 → 𝕜} + (hF : ∀ i ∈ s, AnalyticAt 𝕜 (F i) z₀) : + analyticOrderAt (∏ i ∈ s, F i) z₀ = ∑ i ∈ s, analyticOrderAt (F i) z₀ := by + induction s using Finset.cons_induction with + | empty => simp [analyticOrderAt_eq_zero] + | cons a s ha ih => + rw [Finset.prod_cons, Finset.sum_cons, + analyticOrderAt_mul (hF a (Finset.mem_cons.mpr (.inl rfl))) + (Finset.analyticAt_prod _ fun i hi => hF i (Finset.mem_cons.mpr (.inr hi))), + ih fun i hi => hF i (Finset.mem_cons.mpr (.inr hi))] + /-- The order multiplies by `n` when taking an analytic function to its `n`th power. -/ theorem analyticOrderAt_pow (hf : AnalyticAt 𝕜 f z₀) : ∀ n, analyticOrderAt (f ^ n) z₀ = n • analyticOrderAt f z₀ @@ -513,6 +525,21 @@ lemma analyticOrderAt_comp_of_deriv_ne_zero (hg : AnalyticAt 𝕜 g z₀) (hg' : · rw [analyticOrderAt_of_not_analyticAt hf, analyticOrderAt_of_not_analyticAt] rwa [analyticAt_comp_iff_of_deriv_ne_zero hg hg'] +/-- The analytic order of `q ↦ f (q ^ N)` at `0` is `N` times the analytic order of `f` at `0`. -/ +lemma analyticOrderAt_comp_pow_zero (hf : AnalyticAt 𝕜 f 0) {N : ℕ} (hN : 0 < N) : + analyticOrderAt (fun q : 𝕜 => f (q ^ N)) 0 = analyticOrderAt f 0 * N := by + set g : 𝕜 → 𝕜 := fun q => q ^ N with hg_def + have h_pow_an : AnalyticAt 𝕜 g 0 := analyticAt_id.pow N + have hzero : g 0 = 0 := by simp [hg_def, zero_pow hN.ne'] + have hf' : AnalyticAt 𝕜 f (g 0) := by + rw [hzero] + exact hf + have h_sub_eq : (fun x : 𝕜 => g x - (0 : 𝕜)) = (id : 𝕜 → 𝕜) ^ N := + funext fun x => by simp [hg_def] + rw [show (fun q : 𝕜 => f (q ^ N)) = f ∘ g from rfl, hf'.analyticOrderAt_comp h_pow_an, + hzero, h_sub_eq, analyticOrderAt_pow analyticAt_id, analyticOrderAt_id] + simp + end comp /-! diff --git a/Mathlib/NumberTheory/ModularForms/NormTrace.lean b/Mathlib/NumberTheory/ModularForms/NormTrace.lean index b1e0731fd3fc8d..db8856577f6949 100644 --- a/Mathlib/NumberTheory/ModularForms/NormTrace.lean +++ b/Mathlib/NumberTheory/ModularForms/NormTrace.lean @@ -47,6 +47,19 @@ lemma quotientFunc_smul {h} (hh : h ∈ ℋ) (q : 𝒬) : induction q using Quotient.inductionOn with | h r => simp [SlashAction.slash_mul] +/-- Each `quotientFunc f q` is holomorphic on the upper half plane. -/ +lemma quotientFunc_mdiff [ModularFormClass F 𝒢 k] (q : 𝒬) : + MDiff (quotientFunc f q) := + Quotient.inductionOn q fun r => (ModularForm.translate f r.val⁻¹).holo' + +/-- Each `quotientFunc f q` is bounded at `∞`. -/ +lemma quotientFunc_isBoundedAtImInfty [ModularFormClass F 𝒢 k] [𝒢.IsFiniteRelIndex ℋ] + [Fact (IsCusp OnePoint.infty ℋ)] (q : 𝒬) : + IsBoundedAtImInfty (quotientFunc f q) := + Quotient.inductionOn q fun ⟨_, hr⟩ => OnePoint.isBoundedAt_infty_iff.mp <| + (ModularForm.translate f _).bdd_at_cusps' + ((Fact.out : IsCusp _ _).of_isFiniteRelIndex_conj hr) + variable (ℋ) [𝒢.IsFiniteRelIndex ℋ] /-- The trace of a slash-invariant form, as a slash-invariant form. -/ diff --git a/Mathlib/NumberTheory/ModularForms/QExpansion.lean b/Mathlib/NumberTheory/ModularForms/QExpansion.lean index c72a048c73539a..dd13e618ed2340 100644 --- a/Mathlib/NumberTheory/ModularForms/QExpansion.lean +++ b/Mathlib/NumberTheory/ModularForms/QExpansion.lean @@ -5,11 +5,12 @@ Authors: David Loeffler -/ module +public import Mathlib.Analysis.Analytic.Order public import Mathlib.Analysis.Complex.TaylorSeries public import Mathlib.Analysis.Complex.UpperHalfPlane.Exp public import Mathlib.NumberTheory.ModularForms.Basic public import Mathlib.NumberTheory.ModularForms.Identities -public import Mathlib.RingTheory.PowerSeries.Basic +public import Mathlib.RingTheory.PowerSeries.Order /-! # q-expansions of functions on the upper half plane @@ -176,6 +177,59 @@ lemma qExpansion_coeff_zero {f : ℍ → ℂ} (hh : 0 < h) (qExpansion h f).coeff 0 = valueAtInfty f := by simp [qExpansion_coeff, cuspFunction_apply_zero hh hfanalytic hfper] +/-- The order of the `q`-expansion equals the analytic order of the `cuspFunction` at `0`. -/ +lemma qExpansion_order_eq_analyticOrderAt_cuspFunction {f : ℍ → ℂ} + (hf : AnalyticAt ℂ (cuspFunction h f) 0) : + (qExpansion h f).order = analyticOrderAt (cuspFunction h f) 0 := by + refine ENat.eq_of_forall_natCast_le_iff fun n => ?_ + rw [natCast_le_analyticOrderAt_iff_iteratedDeriv_eq_zero hf] + refine ⟨fun H i hi => ?_, fun H => PowerSeries.nat_le_order _ _ fun i hi => ?_⟩ + · have hcoeff : (qExpansion h f).coeff i = 0 := + PowerSeries.coeff_of_lt_order _ (lt_of_lt_of_le (by exact_mod_cast hi) H) + rw [qExpansion_coeff] at hcoeff + have hfact : ((i.factorial : ℂ))⁻¹ ≠ 0 := + inv_ne_zero (mod_cast Nat.factorial_ne_zero i) + exact (mul_eq_zero.mp hcoeff).resolve_left hfact + · rw [qExpansion_coeff, H i hi, mul_zero] + +/-- The order of the `q`-expansion at period `h` is bounded above by the order of the `q`-expansion +at period `m * h`, for any positive natural number `m`. -/ +lemma qExpansion_order_le_qExpansion_nat_mul_order {g : ℍ → ℂ} {m : ℕ} (hh : 0 < h) (hm : 0 < m) + (hg_per : Periodic (g ∘ ofComplex) h) (hg_bdd : IsBoundedAtImInfty g) (hg_mdiff : MDiff g) : + (qExpansion h g).order ≤ (qExpansion ((m * h : ℝ)) g).order := by + have hmh : (0 : ℝ) < (m : ℝ) * h := by positivity + have hg_per_mh : Periodic (g ∘ ofComplex) (((m : ℝ) * h : ℝ)) := by + simpa using hg_per.nat_mul m + have hLHS_an : AnalyticAt ℂ (cuspFunction h g) 0 := + analyticAt_cuspFunction_zero hh hg_per hg_mdiff hg_bdd + have hRHS_an : AnalyticAt ℂ (cuspFunction ((m : ℝ) * h) g) 0 := + analyticAt_cuspFunction_zero hmh hg_per_mh hg_mdiff hg_bdd + rw [qExpansion_order_eq_analyticOrderAt_cuspFunction hLHS_an, + qExpansion_order_eq_analyticOrderAt_cuspFunction hRHS_an] + have h_RHS_lift_cts : ContinuousAt (fun q : ℂ => cuspFunction h g (q ^ m)) 0 := + hLHS_an.continuousAt.comp_of_eq (by fun_prop) (zero_pow hm.ne') + have h_eqOn : + (fun q : ℂ => cuspFunction ((m : ℝ) * h) g q) =ᶠ[𝓝 0] + (fun q : ℂ => cuspFunction h g (q ^ m)) := by + rw [← hRHS_an.continuousAt.eventuallyEq_nhds_iff_eventuallyEq_nhdsNE h_RHS_lift_cts, + eventuallyEq_nhdsWithin_iff] + filter_upwards [Metric.ball_mem_nhds (0 : ℂ) zero_lt_one] with q hq_lt hq_ne + rw [mem_ball_zero_iff] at hq_lt + set τ : ℍ := ⟨Periodic.invQParam ((m : ℝ) * h) q, + Periodic.im_invQParam_pos_of_norm_lt_one hmh hq_lt hq_ne⟩ + have hτq : Periodic.qParam ((m : ℝ) * h) τ = q := + Periodic.qParam_right_inv hmh.ne' hq_ne + have hqm : q ^ m = Periodic.qParam h (τ : ℂ) := by + rw [← hτq] + simp only [Periodic.qParam, ← Complex.exp_nat_mul, + Complex.ofReal_mul, Complex.ofReal_natCast] + congr 1 + field_simp [show (m : ℂ) ≠ 0 from mod_cast hm.ne'] + rw [hqm, ← hτq, eq_cuspFunction τ hmh.ne' hg_per_mh, + eq_cuspFunction τ hh.ne' hg_per] + rw [analyticOrderAt_congr h_eqOn, analyticOrderAt_comp_pow_zero hLHS_an hm] + exact ENat.self_le_mul_right _ (by exact_mod_cast hm.ne') + lemma hasSum_qExpansion_of_norm_lt {f : ℍ → ℂ} (hh : 0 < h) (hfper : Periodic (f ∘ ofComplex) h) (hfhol : MDiff f) (hfbdd : IsBoundedAtImInfty f) {q : ℂ} (hq : ‖q‖ < 1) : diff --git a/Mathlib/NumberTheory/ModularForms/SturmBound.lean b/Mathlib/NumberTheory/ModularForms/SturmBound.lean index e3c16868ec95b9..cdeec802fbfd11 100644 --- a/Mathlib/NumberTheory/ModularForms/SturmBound.lean +++ b/Mathlib/NumberTheory/ModularForms/SturmBound.lean @@ -156,48 +156,6 @@ private lemma cuspFunction_one_galoisProd_pow_eq (hN : 0 < N) ← qParam_sub_eq_mul_exp (N : ℝ) τ j] rw [hqj, eq_cuspFunction ⟨(τ : ℂ) - j, him⟩ hNR_ne hf_per, ofComplex_apply_of_im_pos him] -private lemma qExpansion_order_eq_analyticOrderAt_cuspFunction {h : ℝ} {f : ℍ → ℂ} - (hf : AnalyticAt ℂ (cuspFunction h f) 0) : - (qExpansion h f).order = analyticOrderAt (cuspFunction h f) 0 := by - refine ENat.eq_of_forall_natCast_le_iff fun n => ?_ - rw [natCast_le_analyticOrderAt_iff_iteratedDeriv_eq_zero hf] - refine ⟨fun H i hi => ?_, fun H => PowerSeries.nat_le_order _ _ fun i hi => ?_⟩ - · have hcoeff : (qExpansion h f).coeff i = 0 := - PowerSeries.coeff_of_lt_order _ (lt_of_lt_of_le (by exact_mod_cast hi) H) - rw [qExpansion_coeff] at hcoeff - have hfact : ((i.factorial : ℂ))⁻¹ ≠ 0 := - inv_ne_zero (mod_cast Nat.factorial_ne_zero i) - exact (mul_eq_zero.mp hcoeff).resolve_left hfact - · rw [qExpansion_coeff, H i hi, mul_zero] - -private lemma analyticOrderAt_prod {𝕜 : Type*} [NontriviallyNormedField 𝕜] - {ι : Type*} (s : Finset ι) (f : ι → 𝕜 → 𝕜) {z₀ : 𝕜} - (h : ∀ i ∈ s, AnalyticAt 𝕜 (f i) z₀) : - analyticOrderAt (∏ i ∈ s, f i) z₀ = ∑ i ∈ s, analyticOrderAt (f i) z₀ := by - induction s using Finset.cons_induction with - | empty => simp [analyticOrderAt_eq_zero] - | cons a s ha ih => - rw [Finset.prod_cons, Finset.sum_cons, - analyticOrderAt_mul (h a (Finset.mem_cons.mpr (.inl rfl))) - (Finset.analyticAt_prod _ fun i hi => h i (Finset.mem_cons.mpr (.inr hi))), - ih fun i hi => h i (Finset.mem_cons.mpr (.inr hi))] - -private lemma analyticOrderAt_comp_pow_zero {f : ℂ → ℂ} (hf : AnalyticAt ℂ f 0) - {N : ℕ} (hN : 0 < N) : - analyticOrderAt (fun q : ℂ => f (q ^ N)) 0 = analyticOrderAt f 0 * N := by - have h_pow_an : AnalyticAt ℂ (fun q : ℂ => q ^ N) 0 := by fun_prop - have hzero : (0 : ℂ) ^ N = 0 := zero_pow hN.ne' - have hf' : AnalyticAt ℂ f ((fun q : ℂ => q ^ N) (0 : ℂ)) := by - change AnalyticAt ℂ f ((0 : ℂ) ^ N) - rwa [hzero] - change analyticOrderAt (f ∘ (npowRec N : ℂ → ℂ)) 0 = analyticOrderAt f 0 * N - rw [hf'.analyticOrderAt_comp h_pow_an] - change analyticOrderAt f ((0 : ℂ) ^ N) * - analyticOrderAt (fun x : ℂ => x ^ N - (0 : ℂ) ^ N) 0 = analyticOrderAt f 0 * N - rw [hzero, show (fun x : ℂ => x ^ N - (0 : ℂ)) = (id : ℂ → ℂ) ^ N by ext; simp, - analyticOrderAt_pow analyticAt_id, analyticOrderAt_id] - simp - private lemma qExpansion_one_galoisProd_order_eq_qExpansion_self_order (hN : 0 < N) (hf_per : Function.Periodic (f ∘ ofComplex) (N : ℝ)) (hf_bdd : IsBoundedAtImInfty f) (hf_mdiff : MDiff f) : @@ -223,7 +181,7 @@ private lemma qExpansion_one_galoisProd_order_eq_qExpansion_self_order (hN : 0 < have h_combine : ML * (N : ℕ∞) = (N : ℕ∞) * MR := by rw [← analyticOrderAt_comp_pow_zero hLHS_an hN, analyticOrderAt_congr (cuspFunction_one_galoisProd_pow_eq hN hf_per hf_bdd hf_mdiff), - ← Finset.prod_fn, analyticOrderAt_prod _ _ h_factor_an, + ← Finset.prod_fn, analyticOrderAt_prod h_factor_an, Finset.sum_congr rfl h_factor_order, Finset.sum_const, Finset.card_range, nsmul_eq_mul] have hN_ne : (N : ℕ∞) ≠ 0 := mod_cast hN.ne' clear_value ML MR @@ -523,21 +481,6 @@ private lemma prod_quotientFunc_filter_image_one_vadd (fun q => by simpa using (image_T_pow_smul_inv_iff (𝒢 := 𝒢) q).symm.not) (fun _ _ => rfl) -omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in -private lemma quotientFunc_mdiff - (q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) : - MDiff (SlashInvariantForm.quotientFunc f q) := - Quotient.inductionOn q fun r => (ModularForm.translate f r.val⁻¹).holo' - -omit [𝒢.HasDetPlusMinusOne] in -private lemma quotientFunc_isBoundedAtImInfty - (q : 𝒮ℒ ⧸ ((𝒢 : Subgroup (GL (Fin 2) ℝ)).subgroupOf 𝒮ℒ)) : - IsBoundedAtImInfty (SlashInvariantForm.quotientFunc f q) := - Quotient.inductionOn q fun ⟨r, hr⟩ => OnePoint.isBoundedAt_infty_iff.mp - ((ModularForm.translate f _).bdd_at_cusps' - ((Subgroup.isCusp_of_mem_strictPeriods (𝒢 := 𝒮ℒ) zero_lt_one - (by simp)).of_isFiniteRelIndex_conj hr)) - omit [𝒢.HasDetPlusMinusOne] in private lemma analyticAt_cuspFunction_one_norm_rest [DiscreteTopology 𝒢.strictPeriods] : @@ -562,9 +505,10 @@ private lemma analyticAt_cuspFunction_one_norm_rest ∏ q ∈ Finset.univ.filter (· ∉ image), SlashInvariantForm.quotientFunc f q := funext fun _ => (Finset.prod_apply ..).symm have h_rest_mdiff : MDiff rest := - h_rest_eq ▸ MDifferentiable.prod fun q _ => quotientFunc_mdiff f q + h_rest_eq ▸ MDifferentiable.prod fun q _ => SlashInvariantForm.quotientFunc_mdiff f q have h_rest_bdd : IsBoundedAtImInfty rest := - h_rest_eq ▸ Filter.BoundedAtFilter.prod _ fun q _ => quotientFunc_isBoundedAtImInfty f q + h_rest_eq ▸ Filter.BoundedAtFilter.prod _ fun q _ => + SlashInvariantForm.quotientFunc_isBoundedAtImInfty f q have h_rest_periodic : Function.Periodic (rest ∘ ofComplex) 1 := fun w => by simp only [Function.comp_apply] by_cases! hw : 0 < w.im @@ -582,45 +526,6 @@ private lemma analyticAt_cuspFunction_one_norm_rest Finset.prod_congr rfl fun j _ => quotientFunc_T_pow_apply f j τ, Fin.prod_univ_eq_prod_range (fun n => f (ofComplex ((τ : ℂ) - (n : ℕ)))) h_𝒢] -omit [𝒢.HasDetPlusMinusOne] [𝒢.IsFiniteRelIndex 𝒮ℒ] in -private lemma qExpansion_order_le_qExpansion_nat_mul_order - {h : ℝ} {g : ℍ → ℂ} {m : ℕ} (hh : 0 < h) (hm : 0 < m) - (hg_per : Function.Periodic (g ∘ ofComplex) h) - (hg_bdd : IsBoundedAtImInfty g) (hg_mdiff : MDiff g) : - (qExpansion h g).order ≤ (qExpansion ((m * h : ℝ)) g).order := by - have hmh : (0 : ℝ) < (m : ℝ) * h := by positivity - have hg_per_mh : Function.Periodic (g ∘ ofComplex) (((m : ℝ) * h : ℝ)) := by - simpa using hg_per.nat_mul m - have hLHS_an : AnalyticAt ℂ (cuspFunction h g) 0 := - analyticAt_cuspFunction_zero hh hg_per hg_mdiff hg_bdd - have hRHS_an : AnalyticAt ℂ (cuspFunction ((m : ℝ) * h) g) 0 := - analyticAt_cuspFunction_zero hmh hg_per_mh hg_mdiff hg_bdd - rw [qExpansion_order_eq_analyticOrderAt_cuspFunction hLHS_an, - qExpansion_order_eq_analyticOrderAt_cuspFunction hRHS_an] - have h_RHS_lift_cts : ContinuousAt (fun q : ℂ => cuspFunction h g (q ^ m)) 0 := - hLHS_an.continuousAt.comp_of_eq (by fun_prop) (zero_pow hm.ne') - have h_eqOn : - (fun q : ℂ => cuspFunction ((m : ℝ) * h) g q) =ᶠ[𝓝 0] - (fun q : ℂ => cuspFunction h g (q ^ m)) := by - rw [← hRHS_an.continuousAt.eventuallyEq_nhds_iff_eventuallyEq_nhdsNE h_RHS_lift_cts, - eventuallyEq_nhdsWithin_iff] - filter_upwards [Metric.ball_mem_nhds (0 : ℂ) zero_lt_one] with q hq_lt hq_ne - rw [mem_ball_zero_iff] at hq_lt - set τ : ℍ := ⟨Function.Periodic.invQParam ((m : ℝ) * h) q, - Function.Periodic.im_invQParam_pos_of_norm_lt_one hmh hq_lt hq_ne⟩ - have hτq : Function.Periodic.qParam ((m : ℝ) * h) τ = q := - Function.Periodic.qParam_right_inv hmh.ne' hq_ne - have hqm : q ^ m = Function.Periodic.qParam h (τ : ℂ) := by - rw [← hτq] - simp only [Function.Periodic.qParam, ← Complex.exp_nat_mul, - Complex.ofReal_mul, Complex.ofReal_natCast] - congr 1 - field_simp [show (m : ℂ) ≠ 0 from mod_cast hm.ne'] - rw [hqm, ← hτq, eq_cuspFunction τ hmh.ne' hg_per_mh, - eq_cuspFunction τ hh.ne' hg_per] - rw [analyticOrderAt_congr h_eqOn, analyticOrderAt_comp_pow_zero hLHS_an hm] - exact ENat.self_le_mul_right _ (by exact_mod_cast hm.ne') - omit [𝒢.HasDetPlusMinusOne] in private lemma integerCuspWidth_eq_nat_mul_strictWidthInfty (𝒢 : Subgroup (GL (Fin 2) ℝ)) [𝒢.IsFiniteRelIndex 𝒮ℒ]