Gauss: complete formalization of E₈ optimality in ℝ⁸#341
Gauss: complete formalization of E₈ optimality in ℝ⁸#341augustepoiroux wants to merge 18 commits into
Conversation
| let A : SchwartzMap.dualLattice (d := d) P.lattice → ℂ := | ||
| SpherePacking.CohnElkies.expSum P D | ||
| let r : SchwartzMap.dualLattice (d := d) P.lattice → ℝ := fun m => | ||
| (𝓕 ⇑f (m : EuclideanSpace ℝ (Fin d))).re * (‖A m‖ ^ 2) | ||
| have hFourier : | ||
| ∀ m : SchwartzMap.dualLattice (d := d) P.lattice, | ||
| 𝓕 f (m : EuclideanSpace ℝ (Fin d)) = (𝓕 ⇑f) (m : EuclideanSpace ℝ (Fin d)) := by | ||
| intro m | ||
| simpa using congrArg (fun g : EuclideanSpace ℝ (Fin d) → ℂ => | ||
| g (m : EuclideanSpace ℝ (Fin d))) (SchwartzMap.fourier_coe (f := f)) | ||
| have hterm : | ||
| ∀ m : SchwartzMap.dualLattice (d := d) P.lattice, | ||
| ((𝓕 f m).re : ℂ) * A m * conj (A m) = (r m : ℂ) := by | ||
| intro m | ||
| have hFourierRe : | ||
| (𝓕 f m).re = (𝓕 ⇑f (m : EuclideanSpace ℝ (Fin d))).re := by | ||
| simpa using congrArg Complex.re (hFourier m) | ||
| calc | ||
| ((𝓕 f m).re : ℂ) * A m * conj (A m) | ||
| = ((𝓕 f m).re : ℂ) * (A m * conj (A m)) := by | ||
| simp [mul_assoc] | ||
| _ = ((𝓕 f m).re : ℂ) * (‖A m‖ ^ 2) := by | ||
| simp [Complex.mul_conj'] | ||
| _ = ((𝓕 ⇑f (m : EuclideanSpace ℝ (Fin d))).re : ℂ) * (‖A m‖ ^ 2) := by | ||
| simp [hFourierRe] | ||
| _ = (r m : ℂ) := by | ||
| simp [r] | ||
| have hsum : | ||
| (∑' m : SchwartzMap.dualLattice (d := d) P.lattice, | ||
| ((𝓕 f m).re : ℂ) * A m * conj (A m)) | ||
| = | ||
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, (r m : ℂ) := by | ||
| exact tsum_congr fun m => hterm m | ||
| have hsum' : | ||
| (∑' m : SchwartzMap.dualLattice (d := d) P.lattice, (r m : ℂ)) | ||
| = | ||
| ((∑' m : SchwartzMap.dualLattice (d := d) P.lattice, r m : ℝ) : ℂ) := by | ||
| exact | ||
| (Complex.ofReal_tsum (L := .unconditional _) | ||
| (fun m : SchwartzMap.dualLattice (d := d) P.lattice => r m)).symm | ||
| -- Turn the complex series into an `ofReal` series, then take real parts. | ||
| have hcalc : | ||
| ((1 / ZLattice.covolume P.lattice volume) * | ||
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, | ||
| ((𝓕 f m).re : ℂ) * A m * conj (A m)).re | ||
| = | ||
| (1 / ZLattice.covolume P.lattice volume) * | ||
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, | ||
| (𝓕 ⇑f (m : EuclideanSpace ℝ (Fin d))).re * (‖A m‖ ^ 2) := by | ||
| calc | ||
| ((1 / ZLattice.covolume P.lattice volume) * | ||
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, | ||
| ((𝓕 f m).re : ℂ) * A m * conj (A m)).re | ||
| = | ||
| ((1 / ZLattice.covolume P.lattice volume : ℂ) * | ||
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, (r m : ℂ)).re := by | ||
| simp [hsum] | ||
| _ = (1 / ZLattice.covolume P.lattice volume) * | ||
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, r m := by | ||
| rw [hsum'] | ||
| simp | ||
| _ = (1 / ZLattice.covolume P.lattice volume) * | ||
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, | ||
| (𝓕 ⇑f (m : EuclideanSpace ℝ (Fin d))).re * (‖A m‖ ^ 2) := by | ||
| rfl | ||
| -- Unfold `A` and rewrite `‖A m‖` as `norm (∑' x, ...)` (definitional). | ||
| simpa [A, r] using hcalc |
There was a problem hiding this comment.
In #302 I added a shorter proof of this section:
| let A : SchwartzMap.dualLattice (d := d) P.lattice → ℂ := | |
| SpherePacking.CohnElkies.expSum P D | |
| let r : SchwartzMap.dualLattice (d := d) P.lattice → ℝ := fun m => | |
| (𝓕 ⇑f (m : EuclideanSpace ℝ (Fin d))).re * (‖A m‖ ^ 2) | |
| have hFourier : | |
| ∀ m : SchwartzMap.dualLattice (d := d) P.lattice, | |
| 𝓕 f (m : EuclideanSpace ℝ (Fin d)) = (𝓕 ⇑f) (m : EuclideanSpace ℝ (Fin d)) := by | |
| intro m | |
| simpa using congrArg (fun g : EuclideanSpace ℝ (Fin d) → ℂ => | |
| g (m : EuclideanSpace ℝ (Fin d))) (SchwartzMap.fourier_coe (f := f)) | |
| have hterm : | |
| ∀ m : SchwartzMap.dualLattice (d := d) P.lattice, | |
| ((𝓕 f m).re : ℂ) * A m * conj (A m) = (r m : ℂ) := by | |
| intro m | |
| have hFourierRe : | |
| (𝓕 f m).re = (𝓕 ⇑f (m : EuclideanSpace ℝ (Fin d))).re := by | |
| simpa using congrArg Complex.re (hFourier m) | |
| calc | |
| ((𝓕 f m).re : ℂ) * A m * conj (A m) | |
| = ((𝓕 f m).re : ℂ) * (A m * conj (A m)) := by | |
| simp [mul_assoc] | |
| _ = ((𝓕 f m).re : ℂ) * (‖A m‖ ^ 2) := by | |
| simp [Complex.mul_conj'] | |
| _ = ((𝓕 ⇑f (m : EuclideanSpace ℝ (Fin d))).re : ℂ) * (‖A m‖ ^ 2) := by | |
| simp [hFourierRe] | |
| _ = (r m : ℂ) := by | |
| simp [r] | |
| have hsum : | |
| (∑' m : SchwartzMap.dualLattice (d := d) P.lattice, | |
| ((𝓕 f m).re : ℂ) * A m * conj (A m)) | |
| = | |
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, (r m : ℂ) := by | |
| exact tsum_congr fun m => hterm m | |
| have hsum' : | |
| (∑' m : SchwartzMap.dualLattice (d := d) P.lattice, (r m : ℂ)) | |
| = | |
| ((∑' m : SchwartzMap.dualLattice (d := d) P.lattice, r m : ℝ) : ℂ) := by | |
| exact | |
| (Complex.ofReal_tsum (L := .unconditional _) | |
| (fun m : SchwartzMap.dualLattice (d := d) P.lattice => r m)).symm | |
| -- Turn the complex series into an `ofReal` series, then take real parts. | |
| have hcalc : | |
| ((1 / ZLattice.covolume P.lattice volume) * | |
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, | |
| ((𝓕 f m).re : ℂ) * A m * conj (A m)).re | |
| = | |
| (1 / ZLattice.covolume P.lattice volume) * | |
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, | |
| (𝓕 ⇑f (m : EuclideanSpace ℝ (Fin d))).re * (‖A m‖ ^ 2) := by | |
| calc | |
| ((1 / ZLattice.covolume P.lattice volume) * | |
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, | |
| ((𝓕 f m).re : ℂ) * A m * conj (A m)).re | |
| = | |
| ((1 / ZLattice.covolume P.lattice volume : ℂ) * | |
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, (r m : ℂ)).re := by | |
| simp [hsum] | |
| _ = (1 / ZLattice.covolume P.lattice volume) * | |
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, r m := by | |
| rw [hsum'] | |
| simp | |
| _ = (1 / ZLattice.covolume P.lattice volume) * | |
| ∑' m : SchwartzMap.dualLattice (d := d) P.lattice, | |
| (𝓕 ⇑f (m : EuclideanSpace ℝ (Fin d))).re * (‖A m‖ ^ 2) := by | |
| rfl | |
| -- Unfold `A` and rewrite `‖A m‖` as `norm (∑' x, ...)` (definitional). | |
| simpa [A, r] using hcalc | |
| rw [← ofReal_re (1 / ZLattice.covolume P.lattice volume * | |
| ∑' (m : ↥(LinearMap.BilinForm.dualSubmodule (innerₗ _) P.lattice)), | |
| (𝓕 ⇑f ↑m).re * norm (∑' (x : ↑(P.centers ∩ D)), | |
| cexp (2 * ↑π * I * ↑⟪(x : EuclideanSpace ℝ (Fin d)), ↑m⟫_[ℝ])) ^ 2)] | |
| congr 1 | |
| push_cast | |
| congr! 3 with m | |
| rw [mul_assoc] | |
| apply congrArg _ _ | |
| rw [mul_conj, Complex.normSq_eq_norm_sq] | |
| norm_cast |
There was a problem hiding this comment.
Added back your proof in a new commit: 38876bc#diff-ebf1c68f284079a6364607bb7113a4b517ffb358424f42f02a128c225340f25d
| rw [← ofReal_re (1 / ZLattice.covolume P.lattice volume * | ||
| ∑' (m : ↥(LinearMap.BilinForm.dualSubmodule (innerₗ _) P.lattice)), | ||
| (𝓕 ⇑f ↑m).re * norm (∑' (x : ↑(P.centers ∩ D)), | ||
| cexp (2 * ↑π * I * ↑⟪(x : EuclideanSpace ℝ (Fin d)), ↑m⟫_[ℝ])) ^ 2)] | ||
| congr 1 | ||
| push_cast | ||
| congr! 3 with m | ||
| rw [mul_assoc] | ||
| apply congrArg _ _ | ||
| rw [mul_conj, Complex.normSq_eq_norm_sq] | ||
| norm_cast |
There was a problem hiding this comment.
See my comment below. You deleted this proof and added a much longer proof of the same thing.
There was a problem hiding this comment.
Thank you, sorry about that. We tried our best to incorporate recent changes, but failed in some places. Feel free to push more changes where needed.
There was a problem hiding this comment.
Added back your proof in a new commit: 38876bc#diff-ebf1c68f284079a6364607bb7113a4b517ffb358424f42f02a128c225340f25d
| toEquiv := | ||
| { toFun := fun p => Fin.cons p.1 p.2 | ||
| invFun := fun f => (f 0, fun i => f (Fin.succ i)) | ||
| left_inv := by | ||
| rintro ⟨a, f⟩ | ||
| ext <;> simp | ||
| right_inv := by | ||
| intro f | ||
| ext i | ||
| cases i using Fin.cases with | ||
| | zero => simp | ||
| | succ i => simp } | ||
| continuous_toFun := by | ||
| -- `Fin.cons` is continuous coordinatewise. | ||
| refine continuous_pi ?_ | ||
| intro i | ||
| cases i using Fin.cases with | ||
| | zero => | ||
| simpa using continuous_fst | ||
| | succ i => | ||
| simpa using (continuous_apply i |>.comp continuous_snd) | ||
| continuous_invFun := by | ||
| refine (continuous_apply (0 : Fin n.succ)).prodMk ?_ | ||
| refine continuous_pi ?_ | ||
| intro i | ||
| simpa using (continuous_apply (Fin.succ i)) |
There was a problem hiding this comment.
| toEquiv := | |
| { toFun := fun p => Fin.cons p.1 p.2 | |
| invFun := fun f => (f 0, fun i => f (Fin.succ i)) | |
| left_inv := by | |
| rintro ⟨a, f⟩ | |
| ext <;> simp | |
| right_inv := by | |
| intro f | |
| ext i | |
| cases i using Fin.cases with | |
| | zero => simp | |
| | succ i => simp } | |
| continuous_toFun := by | |
| -- `Fin.cons` is continuous coordinatewise. | |
| refine continuous_pi ?_ | |
| intro i | |
| cases i using Fin.cases with | |
| | zero => | |
| simpa using continuous_fst | |
| | succ i => | |
| simpa using (continuous_apply i |>.comp continuous_snd) | |
| continuous_invFun := by | |
| refine (continuous_apply (0 : Fin n.succ)).prodMk ?_ | |
| refine continuous_pi ?_ | |
| intro i | |
| simpa using (continuous_apply (Fin.succ i)) | |
| toEquiv := Fin.consEquiv (fun _ ↦ α) | |
| continuous_toFun := by | |
| simp only [Fin.consEquiv] | |
| refine Continuous.finCons (by fun_prop) (by fun_prop) | |
| continuous_invFun := by fun_prop |
There was a problem hiding this comment.
Added your change in 38876bc#diff-ebf1c68f284079a6364607bb7113a4b517ffb358424f42f02a128c225340f25d
There was a problem hiding this comment.
Quite amazed by this golf by the way. I didn't check properly yesterday and thought it was a change that got overwritten by the merge. Next time I will use the "Commit suggestion" option instead.
|
Some improvements that |
|
It seems many of diffs include changing to the new module system - should we separate it as a new PR |
|
|
||
| /-- | ||
| If `F : ℍ → ℂ` is `O(exp(-c * im τ))` at `atImInfty` for some `c > 0`, then | ||
| the restriction to the imaginary axis `t ↦ F(it)` is `O(exp(-c * t))` at `atTop`. | ||
| -/ | ||
| lemma isBigO_resToImagAxis_of_isBigO_atImInfty {F : ℍ → ℂ} {c : ℝ} (_hc : 0 < c) | ||
| lemma isBigO_resToImagAxis_of_isBigO_atImInfty {F : ℍ → ℂ} {c : ℝ} |
There was a problem hiding this comment.
We can make this (and other theorems use this) as a separate PR; it upgrades theorem by removing unnecessary assumption.
improvements found by tryAtEachStep
…ngly discarded during merge
|
Second round of improvements from |
more improvements found by tryAtEachStep
|
Some golfs with |
positivity improvements suggested by tryAtEachStep
seewoo5
left a comment
There was a problem hiding this comment.
For the part related to the modular form inequality (FG.lean, where Gauss splitted it into multiple files), it is essentially done once some open PRs are merged #248 #331 #307, so it is likely that the corresponding parts won't be needed (although there's a chance where Gauss's proof is better than current proofs). But something hasn't been formalized before is to connect the inequality FG_ineq_1 and FG_ineq_2 with the actual linear constraints of a and b that we definitely need - which I saw somewhere but cannot find it now (it was something like A_ineq or B_ienq).
| ResToImagAxis.Real.sub (ResToImagAxis.Real.mul hDFreal hGreal) | ||
| (ResToImagAxis.Real.mul hFreal hDGreal) | ||
|
|
||
| private lemma L₁₀_over_tendsto_atImInfty : |
There was a problem hiding this comment.
Just as a note, this lemma (or whole file) won't be needed. This follows argument in v1 or v2 of my paper (2024 July), where the revised v3 (2025 August) uses new argument that avoids computation of D_F_div_F_tendsto in #270 and D_G_div_G_tendsto in #239.
| @@ -1,74 +1,86 @@ | |||
| import Mathlib.Analysis.Normed.Group.Tannery | |||
There was a problem hiding this comment.
Large amount of this file are upstreamed and probably removed after bump #332
|
Even more from |
more improvements found by tryAtEachStep
Add improvements found by autoGolf
Auto golf 2
…343) `im_pnat_div_pos` was added upstream in leanprover-community/mathlib4@f160a5e. This change reduces the diff in #341. Gauss made the same change: https://github.com/math-inc/Sphere-Packing-Lean/blob/a6042330f897685ee6cd6d7a01e36e2460d60b18/SpherePacking/ModularForms/upperhalfplane.lean#L9
…print (#359) #239 proved `FmodG_strictAntiOn` in `FG.lean` and updated the blueprint to refer to it instead of `FmodG_antitone`. Concurrently, the gauss PR #341 split `FG.lean` into `FG/Basic.lean`, `FG/Inequalities.lean`, etc. That change was rebased in the `gauss2` branch, clobbering some of the work from #239. See [this bit of zulip discussion](https://leanprover.zulipchat.com/#narrow/channel/509682-Sphere-packing-in-8-dimensions/topic/Gauss.20Rebase.20effort/near/578655616). One of the things that was clobbered was `FmodG_strictAntiOn`, which in the Gauss version is proved somewhat differently and has a different name `FmodG_strictAnti`. The present PR is a minimal change to get `leanblueprint all` working again. It renames gauss's `FmodG_strictAnti` to `FmodG_strictAntiOn`, to match the version from #239. It's possible that we might want to pull in other clobbered code from #239, but that can happen in a later PR.
Summary
This PR completes the Lean formalization of the theorem that the optimal sphere packing in
ℝ⁸is theE₈lattice packing.The branch contains the final theorem together with all remaining dependencies, and is checked by the Lean kernel (sorry-free).
Context
The code in this branch was generated by Gauss (Math Inc’s autoformalization agent) starting from the existing Sphere Packing blueprint and Lean codebase, and then packaged into this PR for review.
Notable changes
E₈optimality inℝ⁸b(t)), with the downstream definition ofgin Thm. 4 updated accordinglyv4.28.0Review notes
main. As such, some results may be duplicated.The following blueprint-linked Lean statements were commented out in this branch:-> they have been added back in 38876bc#diff-ebf1c68f284079a6364607bb7113a4b517ffb358424f42f02a128c225340f25dModularForm.dimension_level_one,dim_gen_cong_levels, D_qexp_tsum_pnat,serre_D_two_H₃`