Mathematical formalization · Lean

Ginibre Poincaré

Theorem 1.9: project documentation, proof dependencies, and Lean source.

Scope: the explicit collision-free smooth compact symmetric core.

Ginibre Poincaré: concrete Lean development

This version adds a genuine normalized Gaussian probability measure on ℂⁿ. Each real coordinate is Mathlib's centered Gaussian law with variance 1 / (2n); two such laws form one complex coordinate, and a finite product forms the configuration law. Lean therefore proves directly that the reference Gaussian measure has total mass one.

The equality of this product law with the explicit density

(n / π)^n exp (-n |z|²) dz

is proved by complexGaussianDensityIdentification, using locally proved finite-product density and measure-preserving transport lemmas.

The project also defines the actual particle configuration space, collision set, Vandermonde determinant, Gaussian and Ginibre weights, Ginibre measure, normalized ground-state transform, real Fréchet gradient, coordinate Wirtinger derivatives, and the exact smooth-core theorem statement. The Vandermonde square is proved Gaussian-integrable and nonzero on a positive-measure open set, so the Ginibre normalizing mass is proved positive and finite and the normalized Ginibre measure has total mass one.

The public theorem concrete_theoremOneNine proves both exact sum-of-squares identities of Theorem 1.9 on the explicit collision-free smooth symmetric core. Its proof includes the complex Hermite Hilbert basis, lowering/creation identities, Parseval, the weighted mode-energy HasSum, the holomorphic zero-mode geometry, and the concrete generator square completion. transformedCenteredObservable_finiteMode_formCore supplies the associated finite-mode form-domain approximation.

Build

The source archive intentionally contains no .lake directory and no copy of Mathlib. From a fresh extraction, download the pinned Lean dependencies and their binary cache with:

make download

Then compile every local module and run the axiom audit with:

make check

make download runs lake update followed by lake exe cache get; the checked-in manifest pins Mathlib and its transitive dependencies. make check uses that single checkout at .lake/packages/mathlib, builds sequentially with one Lean worker, and does not create another dependency tree. The default make target is equivalent to make check. make setup remains an alias for make download.

A successful run ends with:

Lean validation of all completed modules succeeded.

Scope

The exact declarations and their scope are documented in STATUS.md. Theorem 1.9 is proved for IsTheoremOneNineCore; the project does not silently postulate an analytic certificate or claim an unspecified larger operator domain.

The status below reproduces the project's checked-in documentation. This HTML generation does not rerun the Lean build or axiom audit.

Formalization status

What is proved in Lean source

The project contains explicit proof terms for:

No theorem-valued certificate is defined.

Theorem 1.9 is unconditional on its stated collision-free smooth symmetric core. In particular, Lean proves the weighted mode-energy identity

HasSum (fun k => ((k + 1 : ℕ) : ℝ) *
  concretePositiveHermiteModeMass hn f hf k)
  (smoothGinibreEnergy n f / 4)

as concrete_weightedModeEnergy, and uses it in concrete_theoremOneNine. Convergence and evaluation are recorded together as HasSum, rather than merely asserting an equality with tsum.

Gaussian density identification

The reference Gaussian measure is now a genuine ProbabilityMeasure, hence its total mass is proved to be one. The equality between this product law and the explicit density measure

(n / π)^n exp (-n |z|²) dz

is expressed by

ComplexGaussianDensityIdentificationStatement

and is now proved unconditionally by complexGaussianDensityIdentification. Its proof identifies the two real coordinate densities, transports their product through the standard measurable equivalence with ℂ, and then forms the finite n-coordinate product.

Earlier exact statement interfaces

The following propositions use the literal configuration space, measures, Fréchet/Wirtinger derivatives, and holomorphic-distance infima:

SmoothGinibrePoincareStatement is derived from five explicit analytic hypotheses in GinibrePoincare.Concrete.MainProofReduction. The five analytic statements themselves are stated only as propositions and are not postulated as theorems.

Scope

The publication theorem is formalized on IsTheoremOneNineCore, the explicit collision-free smooth compact symmetric core used by the concrete generator. The accompanying HermiteWeightedDomain and finite-mode form-core theorem provide the domain/approximation statement used by the Hermite argument. No claim is made here about a larger, separately chosen self-adjoint realization unless it is explicitly defined in a future extension.

Proof dependencies

Major components of the formalization. The complete imports and declarations appear in the source browser below.

Lean dependency graph for Ginibre Poincaré Theorem 1.9 Major formalization components flowing into the unconditional theorem concrete_theoremOneNine. Theorem 1.9 — formal dependency graph Concrete Ginibre model → Hermite analysis → exact deficit identities Concrete probability model Gaussian product measure on ℂⁿ Ginibre density, mass, probability collision locus is null Complex Hermites normalized polynomials orthogonality + completeness Hilbert basis in Gaussian L² Vandermonde transform normalized L² isometry symmetric ↔ alternating ground-state energy identity Concrete generator Ginibre pregenerator integration by parts L² norm representatives Symmetries permutations conjugation global phase Gaussian ∂̄ integration by parts noncompact Gaussian identities configurationGaussianDbar… Parseval by anti-degree orthogonal mode projections gaussianHermiteMode Holomorphic zero mode Vandermonde lies in degree zero centering preserves positive modes Square completion generator and shifted generator ginibreGenerator_squareCompletion L² geometry h, star h, r orthogonal splitting Weighted Hermite energy creation/lowering coefficient identity Parseval + reindexing + convergence concrete_weightedModeEnergy Deficit geometry variance = 2‖h‖² + ‖r‖² zero mode = holomorphic projection centeredHolomorphicRemainderGeometry Exact infinite-series deficit assembly concrete_theoremOneNine_of_modeEnergy concrete_theoremOneNine Both exact sum-of-squares identities — unconditional on the stated core Domain and approximation HermiteWeightedDomain finite mode truncations converge in L² weighted energy tails tend to zero …finiteMode_formCore

Lean source browser

Expand a module to read its syntax-highlighted source. Colors distinguish analysis, concrete constructions, and endgame modules.

Analysis GinibrePoincare/Analysis/AngularMoments.lean #
import Mathlib.Analysis.SpecialFunctions.Integrals.Basic

/-! # Angular Fourier moments on a full circle -/

open MeasureTheory Set
open scoped Interval Real

namespace GinibrePoincare

noncomputable section

/-- The angular Fourier mode used in complex Gaussian polar coordinates. -/
def angularMode (a b : ℕ) (θ : ℝ) : ℂ :=
  Complex.exp ((((a : ℤ) - (b : ℤ) : ℤ) : ℂ) * θ * Complex.I)

/-- Angular modes are continuous, hence integrable on the bounded polar
angle interval. -/
theorem intervalIntegrable_angularMode (a b : ℕ) :
    IntervalIntegrable (angularMode a b) volume (-Real.pi) Real.pi := by
  apply Continuous.intervalIntegrable
  unfold angularMode
  fun_prop

/-- The exact Fourier orthogonality integral on the polar angle interval. -/
theorem integral_angularMode_Ioc (a b : ℕ) :
    ∫ θ in Ioc (-Real.pi) Real.pi, angularMode a b θ =
      if a = b then (2 * Real.pi : ℂ) else 0 := by
  rw [← intervalIntegral.integral_of_le
    (by linarith [Real.pi_pos] : -Real.pi ≤ Real.pi)]
  by_cases hab : a = b
  · subst b
    simp [angularMode]
    ring
  · rw [if_neg hab]
    let k : ℤ := (a : ℤ) - (b : ℤ)
    have hk : k ≠ 0 := by
      intro h
      apply hab
      exact_mod_cast sub_eq_zero.mp h
    let c : ℂ := (k : ℂ) * Complex.I
    have hc : c ≠ 0 := mul_ne_zero (Int.cast_ne_zero.mpr hk) Complex.I_ne_zero
    have hfun : angularMode a b = fun θ : ℝ ↦ Complex.exp (c * θ) := by
      funext θ
      simp only [angularMode, c, k]
      congr 1
      ring
    rw [hfun, integral_exp_mul_complex hc]
    have hplus : Complex.exp (c * Real.pi) = ((-1 : ℂ) ^ k) := by
      rw [show c * Real.pi = (k : ℂ) * ((Real.pi : ℂ) * Complex.I) by
        simp only [c]
        ring]
      rw [Complex.exp_int_mul, Complex.exp_pi_mul_I]
    have hminus : Complex.exp (c * ((-Real.pi : ℝ) : ℂ)) =
        ((-1 : ℂ) ^ k) := by
      rw [show c * ((-Real.pi : ℝ) : ℂ) =
          (k : ℂ) * (-((Real.pi : ℂ) * Complex.I)) by
        simp only [c]
        push_cast
        ring]
      rw [Complex.exp_int_mul, Complex.exp_neg, Complex.exp_pi_mul_I]
      simp
    rw [hplus, hminus, sub_self, zero_div]

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/CollisionNull.lean #
import GinibrePoincare.Analysis.GinibreMassPositivity
import Mathlib.Probability.Independence.Basic

/-! # The collision locus is Gaussian-null -/

open MeasureTheory ProbabilityTheory

namespace GinibrePoincare

noncomputable section

private theorem measure_prod_diagonal_eq_zero {α : Type*}
    [MeasurableSpace α] [MeasurableEq α] (μ : Measure α)
    [SFinite μ] [NullSingletonClass μ] :
    μ.prod μ (Set.diagonal α) = 0 := by
  rw [Measure.measure_prod_null measurableSet_diagonal]
  filter_upwards with x
  simpa [Set.diagonal] using (measure_singleton x : μ {x} = 0)

private theorem complexCoordinateGaussian_nullSingleton {n : ℕ} (hn : 0 < n) :
    NullSingletonClass
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  rw [complexCoordinateGaussianMeasure_eq_withDensity hn]
  infer_instance

private theorem coordinate_pair_map {n : ℕ} (i j : Fin n) (hij : i ≠ j) :
    Measure.map (fun z : Configuration n ↦ (z i, z j))
        (complexGaussianMeasure n) =
      (complexCoordinateGaussianProbability n : Measure ℂ).prod
        (complexCoordinateGaussianProbability n : Measure ℂ) := by
  let μ : Measure ℂ := complexCoordinateGaussianProbability n
  have hind : iIndepFun (fun k (z : Configuration n) ↦ z k)
      (complexGaussianMeasure n) := by
    rw [iIndepFun_iff_map_fun_eq_pi_map (fun k ↦
      (measurable_pi_apply k).aemeasurable)]
    unfold complexGaussianMeasure complexGaussianProbability
    simp only [ProbabilityMeasure.toMeasure_pi]
    change Measure.map id (Measure.pi fun _ : Fin n ↦ μ) =
      Measure.pi (fun k : Fin n ↦
        Measure.map (fun z : Configuration n ↦ z k)
          (Measure.pi fun _ : Fin n ↦ μ))
    rw [Measure.map_id]
    congr 1
    funext k
    exact (measurePreserving_eval (fun _ : Fin n ↦ μ) k).map_eq.symm
  have hp := (hind.indepFun hij).map_prod_eq_prod_map_map
    (measurable_pi_apply i).aemeasurable
    (measurable_pi_apply j).aemeasurable
  have hi : Measure.map (fun z : Configuration n ↦ z i)
      (complexGaussianMeasure n) = μ := by
    unfold complexGaussianMeasure complexGaussianProbability
    exact (measurePreserving_eval (fun _ : Fin n ↦ μ) i).map_eq
  have hj : Measure.map (fun z : Configuration n ↦ z j)
      (complexGaussianMeasure n) = μ := by
    unfold complexGaussianMeasure complexGaussianProbability
    exact (measurePreserving_eval (fun _ : Fin n ↦ μ) j).map_eq
  rw [hi, hj] at hp
  exact hp

private theorem coordinate_diagonal_null {n : ℕ} (hn : 0 < n)
    (i j : Fin n) (hij : i ≠ j) :
    complexGaussianMeasure n {z | z i = z j} = 0 := by
  let μ : Measure ℂ := complexCoordinateGaussianProbability n
  letI : NullSingletonClass μ := complexCoordinateGaussian_nullSingleton hn
  have hm : Measurable (fun z : Configuration n ↦ (z i, z j)) := by fun_prop
  have hd : MeasurableSet (Set.diagonal ℂ) := measurableSet_diagonal
  change complexGaussianMeasure n
    ((fun z : Configuration n ↦ (z i, z j)) ⁻¹' Set.diagonal ℂ) = 0
  rw [← Measure.map_apply hm hd, coordinate_pair_map i j hij]
  exact measure_prod_diagonal_eq_zero μ

/-- Under the product complex Gaussian law, particle collisions form a null
set. -/
theorem complexGaussianMeasure_collisionSet (n : ℕ) :
    complexGaussianMeasure n (collisionSet n) = 0 := by
  by_cases hn : 0 < n
  · apply measure_mono_null (show collisionSet n ⊆
        ⋃ i : Fin n, ⋃ j : Fin n, ⋃ (_h : i ≠ j), {z | z i = z j} by
      intro z hz
      rcases hz with ⟨i, j, heq, hij⟩
      exact Set.mem_iUnion_of_mem i <| Set.mem_iUnion_of_mem j <|
        Set.mem_iUnion_of_mem hij heq)
    apply measure_iUnion_null
    intro i
    apply measure_iUnion_null
    intro j
    apply measure_iUnion_null
    intro hij
    exact coordinate_diagonal_null hn i j hij
  · have hn0 : n = 0 := Nat.eq_zero_of_not_pos hn
    subst n
    simp [collisionSet]

/-- The Vandermonde density is nonzero almost everywhere for the complex
Gaussian law. -/
theorem vandermondeDensity_ne_zero_ae (n : ℕ) :
    ∀ᵐ z ∂complexGaussianMeasure n, vandermondeDensity z ≠ 0 := by
  rw [ae_iff]
  apply measure_mono_null _ (complexGaussianMeasure_collisionSet n)
  intro z hz
  simp only [Set.mem_ofPred_eq, not_not] at hz
  have hvle : vandermondeWeight z ≤ 0 := by
    exact ENNReal.ofReal_eq_zero.mp hz
  have hv : vandermondeWeight z = 0 :=
    le_antisymm hvle (vandermondeWeight_nonneg z)
  exact (vandermondeWeight_eq_zero_iff z).mp hv

/-- Once the normalizing scalar is positive, the Gaussian reference measure
is absolutely continuous with respect to the normalized Ginibre measure. -/
theorem complexGaussianMeasure_absolutelyContinuous_ginibreMeasure
    {n : ℕ} (hvalid : GinibreMassIsValid n) :
    complexGaussianMeasure n ≪ ginibreMeasure n := by
  unfold ginibreMeasure rawGinibreMeasure
  exact (withDensity_absolutelyContinuous'
      measurable_vandermondeDensity.aemeasurable
      (vandermondeDensity_ne_zero_ae n)).trans
    (Measure.absolutelyContinuous_smul
      (ENNReal.inv_ne_zero.mpr hvalid.2.ne))

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/ComplexGaussianDensity.lean #
import GinibrePoincare.Analysis.GaussianDensity
import GinibrePoincare.Analysis.FinitePiDensity
import GinibrePoincare.Analysis.MeasureTransport
import GinibrePoincare.Concrete.MeasureModel

/-! # Explicit density of the complex Gaussian product law -/

open Fintype MeasureTheory
open scoped ENNReal BigOperators

namespace GinibrePoincare

noncomputable section

/-- Density of one complex coordinate in the Ginibre normalization. -/
def complexCoordinateGaussianDensity (n : ℕ) (z : ℂ) : ℝ≥0∞ :=
  ENNReal.ofReal (((n : ℝ) / Real.pi) *
    Real.exp (-(n : ℝ) * Complex.normSq z))

theorem measurable_complexCoordinateGaussianDensity (n : ℕ) :
    Measurable (complexCoordinateGaussianDensity n) := by
  unfold complexCoordinateGaussianDensity
  fun_prop

private theorem real_density_product_formula {n : ℕ} (hn : 0 < n)
    (x : Fin 2 → ℝ) :
    ∏ i, ProbabilityTheory.gaussianPDF 0 (realCoordinateVariance n) (x i) =
      complexCoordinateGaussianDensity n
        (Complex.measurableEquivPi.symm x) := by
  simp_rw [realCoordinateGaussianPDF_formula hn]
  simp only [Fin.prod_univ_two, complexCoordinateGaussianDensity,
    Complex.measurableEquivPi_symm_apply, Complex.normSq_apply]
  rw [← ENNReal.ofReal_mul]
  · congr 1
    have hnR : (0 : ℝ) < n := by positivity
    have hsqrt : Real.sqrt (Real.pi / n) ^ 2 = Real.pi / n := by
      rw [Real.sq_sqrt]
      positivity
    calc
      _ = (Real.sqrt (Real.pi / n))⁻¹ ^ 2 *
          (Real.exp (-(n : ℝ) * x 0 ^ 2) *
            Real.exp (-(n : ℝ) * x 1 ^ 2)) := by ring
      _ = (Real.sqrt (Real.pi / n))⁻¹ ^ 2 *
          Real.exp (-(n : ℝ) * x 0 ^ 2 + -(n : ℝ) * x 1 ^ 2) := by
            rw [Real.exp_add]
      _ = _ := by
        simp only [Complex.add_re, Complex.ofReal_re, Complex.mul_re,
          Complex.ofReal_im, Complex.I_re, mul_zero, Complex.I_im, mul_one,
          sub_zero, add_zero, Complex.add_im, zero_add]
        have hc : (Real.sqrt (Real.pi / n))⁻¹ ^ 2 = (n : ℝ) / Real.pi := by
          rw [inv_pow, hsqrt]
          field_simp
        rw [hc]
        simp [hn.ne']
        ring
  · positivity

/-- One complex Gaussian coordinate has density
`(n / π) exp (-n |z|²)` with respect to complex Lebesgue measure. -/
theorem complexCoordinateGaussianMeasure_eq_withDensity {n : ℕ} (hn : 0 < n) :
    (complexCoordinateGaussianProbability n : Measure ℂ) =
      (volume : Measure ℂ).withDensity (complexCoordinateGaussianDensity n) := by
  unfold complexCoordinateGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_map, ProbabilityMeasure.toMeasure_pi]
  rw [show Measure.pi (fun _ : Fin 2 ↦
        (realCoordinateGaussianProbability n : Measure ℝ)) =
      Measure.pi (fun _ : Fin 2 ↦
        (volume : Measure ℝ).withDensity
          (ProbabilityTheory.gaussianPDF 0 (realCoordinateVariance n))) by
      congr 1
      funext i
      exact realCoordinateGaussianMeasure_eq_withDensity hn]
  have hsf : ∀ i : Fin 2, SigmaFinite
      ((volume : Measure ℝ).withDensity
        (ProbabilityTheory.gaussianPDF 0 (realCoordinateVariance n))) :=
    fun i ↦ by
      rw [← realCoordinateGaussianMeasure_eq_withDensity hn]
      infer_instance
  have hpi := @Measure.pi_withDensity _ _ _ _
    (fun _ : Fin 2 ↦ (volume : Measure ℝ)) (by intro i; infer_instance)
    (fun _ : Fin 2 ↦ ProbabilityTheory.gaussianPDF 0 (realCoordinateVariance n))
    (fun _ ↦ ProbabilityTheory.measurable_gaussianPDF _ _) hsf
  rw [hpi]
  rw [← volume_pi]
  have hdensity :
      (fun x : Fin 2 → ℝ ↦
        ∏ i, ProbabilityTheory.gaussianPDF 0
          (realCoordinateVariance n) (x i)) =
        complexCoordinateGaussianDensity n ∘
          Complex.measurableEquivPi.symm := by
    funext x
    exact real_density_product_formula hn x
  rw [hdensity]
  exact MeasureTheory.map_complexPi_withDensity
    (measurable_complexCoordinateGaussianDensity n)

private theorem coordinate_density_product_formula {n : ℕ} (hn : 0 < n)
    (z : Configuration n) :
    ∏ i, complexCoordinateGaussianDensity n (z i) =
      complexGaussianDensity n z := by
  simp only [complexCoordinateGaussianDensity, complexGaussianDensity]
  rw [← ENNReal.ofReal_prod_of_nonneg]
  · congr 1
    rw [Finset.prod_mul_distrib, Finset.prod_const, ← Real.exp_sum]
    simp only [configurationNormSq, gaussianWeight]
    rw [← Finset.mul_sum]
    simp
  · intro i hi
    positivity

/-- The product construction of the Gaussian reference law agrees with its
explicit Lebesgue density. -/
theorem complexGaussianDensityIdentification :
    ComplexGaussianDensityIdentificationStatement := by
  intro n hn
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  rw [show Measure.pi (fun _ : Fin n ↦
        (complexCoordinateGaussianProbability n : Measure ℂ)) =
      Measure.pi (fun _ : Fin n ↦
        (volume : Measure ℂ).withDensity
          (complexCoordinateGaussianDensity n)) by
      congr 1
      funext i
      exact complexCoordinateGaussianMeasure_eq_withDensity hn]
  have hsf : ∀ i : Fin n, SigmaFinite
      ((volume : Measure ℂ).withDensity
        (complexCoordinateGaussianDensity n)) :=
    fun i ↦ by
      rw [← complexCoordinateGaussianMeasure_eq_withDensity hn]
      infer_instance
  have hpi := @Measure.pi_withDensity _ _ _ _
    (fun _ : Fin n ↦ (volume : Measure ℂ)) (by intro i; infer_instance)
    (fun _ : Fin n ↦ complexCoordinateGaussianDensity n)
    (fun _ ↦ measurable_complexCoordinateGaussianDensity n) hsf
  rw [hpi]
  · rw [← volume_pi]
    unfold complexGaussianDensityMeasure configurationVolume
    congr 1
    funext z
    exact coordinate_density_product_formula hn z

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/ComplexGaussianIntegrationByParts.lean #
import GinibrePoincare.Analysis.RealGaussianIntegrationByParts
import GinibrePoincare.Concrete.Wirtinger

/-! # Sliced integration by parts for one complex Gaussian coordinate -/

open MeasureTheory

namespace GinibrePoincare

noncomputable section

def complexRealSlice (y : ℝ) (x : ℝ) : ℂ := (x : ℂ) + y * Complex.I

def complexImagSlice (x : ℝ) (y : ℝ) : ℂ := (x : ℂ) + y * Complex.I

def configurationCoordinateSlice {m : ℕ} (r : Configuration m) (j : Fin m)
    (w : ℂ) : Configuration m :=
  Function.update r j w

@[simp] theorem configurationCoordinateSlice_apply_self {m : ℕ}
    (r : Configuration m) (j : Fin m) (w : ℂ) :
    configurationCoordinateSlice r j w j = w := by
  simp [configurationCoordinateSlice]

theorem isometry_configurationCoordinateSlice {m : ℕ}
    (r : Configuration m) (j : Fin m) :
    Isometry (configurationCoordinateSlice r j) := by
  rw [isometry_iff_dist_eq]
  intro w w'
  apply le_antisymm
  · apply (dist_pi_le_iff dist_nonneg).2
    intro i
    by_cases hij : i = j
    · subst i
      simp
    · simp [configurationCoordinateSlice, hij]
  · have hj := (dist_pi_le_iff dist_nonneg).1
      (show dist (configurationCoordinateSlice r j w)
          (configurationCoordinateSlice r j w') ≤
        dist (configurationCoordinateSlice r j w)
          (configurationCoordinateSlice r j w') from le_rfl) j
    simpa using hj

theorem hasCompactSupport_comp_configurationCoordinateSlice {m : ℕ}
    {F : Configuration m → ℂ} (hF : HasCompactSupport F)
    (r : Configuration m) (j : Fin m) :
    HasCompactSupport (fun w ↦ F (configurationCoordinateSlice r j w)) := by
  apply HasCompactSupport.intro
    ((isometry_configurationCoordinateSlice r j).isClosedEmbedding.isCompact_preimage hF)
  intro w hw
  by_contra hne
  exact hw (subset_closure hne)

theorem contDiff_configurationCoordinateSlice {m : ℕ}
    (r : Configuration m) (j : Fin m) :
    ContDiff ℝ 1 (configurationCoordinateSlice r j) := by
  rw [contDiff_pi]
  intro i
  by_cases hij : i = j
  · subst i
    simp only [configurationCoordinateSlice, Function.update_self]
    fun_prop
  · simpa [configurationCoordinateSlice, hij] using
      (contDiff_const : ContDiff ℝ 1 (fun _ : ℂ ↦ r i))

theorem contDiff_comp_configurationCoordinateSlice {m : ℕ}
    {F : Configuration m → ℂ} (hF : ContDiff ℝ 1 F)
    (r : Configuration m) (j : Fin m) :
    ContDiff ℝ 1 (fun w ↦ F (configurationCoordinateSlice r j w)) := by
  exact hF.comp (contDiff_configurationCoordinateSlice r j)

theorem hasFDerivAt_configurationCoordinateSlice {m : ℕ}
    (r : Configuration m) (j : Fin m) (w : ℂ) :
    HasFDerivAt (configurationCoordinateSlice r j)
      (ContinuousLinearMap.single ℝ (fun _ : Fin m ↦ ℂ) j) w := by
  have hlin : HasFDerivAt
      (ContinuousLinearMap.single ℝ (fun _ : Fin m ↦ ℂ) j)
      (ContinuousLinearMap.single ℝ (fun _ : Fin m ↦ ℂ) j) w :=
    (ContinuousLinearMap.single ℝ (fun _ : Fin m ↦ ℂ) j).hasFDerivAt
  have h := hlin.const_add (configurationCoordinateSlice r j 0)
  rw [show configurationCoordinateSlice r j =
      fun u ↦ configurationCoordinateSlice r j 0 +
        (ContinuousLinearMap.single ℝ (fun _ : Fin m ↦ ℂ) j) u by
    funext u i
    by_cases hij : i = j
    · subst i
      simp [configurationCoordinateSlice, ContinuousLinearMap.single_apply]
    · simp [configurationCoordinateSlice, ContinuousLinearMap.single_apply, hij]]
  exact h

theorem fderiv_comp_configurationCoordinateSlice_apply {m : ℕ}
    {F : Configuration m → ℂ} (hF : ContDiff ℝ 1 F)
    (r : Configuration m) (j : Fin m) (w v : ℂ) :
    (fderiv ℝ (fun u ↦ F (configurationCoordinateSlice r j u)) w) v =
      (fderiv ℝ F (configurationCoordinateSlice r j w))
        (coordinateDirection j v) := by
  change (fderiv ℝ (F ∘ configurationCoordinateSlice r j) w) v = _
  have hout := (hF.differentiable (by norm_num)
    (configurationCoordinateSlice r j w)).hasFDerivAt
  have hcomp := HasFDerivAt.comp w hout
    (hasFDerivAt_configurationCoordinateSlice r j w)
  have hv := congrArg (fun L : ℂ →L[ℝ] ℂ ↦ L v) hcomp.fderiv
  rw [show coordinateDirection j v = Pi.single j v by
    funext i
    simp [coordinateDirection, Pi.single_apply]]
  simpa only [ContinuousLinearMap.comp_apply, ContinuousLinearMap.single_apply] using hv

theorem integrable_of_continuous_hasCompactSupport_isFiniteMeasure
    {α E : Type*} [TopologicalSpace α] [SecondCountableTopology α]
    [MeasurableSpace α] [BorelSpace α]
    [NormedAddCommGroup E] {μ : Measure α} [IsFiniteMeasure μ] {f : α → E}
    (hf : Continuous f) (hfc : HasCompactSupport f) : Integrable f μ := by
  obtain ⟨C, hC⟩ := hf.bounded_above_of_compact_support hfc
  exact Integrable.of_bound hf.aestronglyMeasurable C
    (Filter.Eventually.of_forall hC)

theorem integrable_complexGaussian_of_continuous_hasCompactSupport {n : ℕ}
    {F : ℂ → ℂ} (hF : Continuous F) (hFc : HasCompactSupport F) :
    Integrable F (complexCoordinateGaussianProbability n : Measure ℂ) :=
  integrable_of_continuous_hasCompactSupport_isFiniteMeasure hF hFc

theorem integrable_complexGaussian_fderiv_real {n : ℕ} {F : ℂ → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    Integrable (fun z ↦ (fderiv ℝ F z) (1 : ℂ))
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  apply integrable_complexGaussian_of_continuous_hasCompactSupport
  · exact (hF.continuous_fderiv (by norm_num)).clm_apply continuous_const
  · exact hFc.fderiv_apply ℝ (1 : ℂ)

theorem integrable_complexGaussian_fderiv_imag {n : ℕ} {F : ℂ → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    Integrable (fun z ↦ (fderiv ℝ F z) Complex.I)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  apply integrable_complexGaussian_of_continuous_hasCompactSupport
  · exact (hF.continuous_fderiv (by norm_num)).clm_apply continuous_const
  · exact hFc.fderiv_apply ℝ Complex.I

theorem integrable_complexGaussian_re_mul {n : ℕ} {F : ℂ → ℂ}
    (hF : Continuous F) (hFc : HasCompactSupport F) :
    Integrable (fun z ↦ (z.re : ℂ) * F z)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  apply integrable_complexGaussian_of_continuous_hasCompactSupport
  · fun_prop
  · exact hFc.mul_left

theorem integrable_complexGaussian_im_mul {n : ℕ} {F : ℂ → ℂ}
    (hF : Continuous F) (hFc : HasCompactSupport F) :
    Integrable (fun z ↦ (z.im : ℂ) * F z)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  apply integrable_complexGaussian_of_continuous_hasCompactSupport
  · fun_prop
  · exact hFc.mul_left

theorem integrable_piRealGaussian_comp_complexEquiv {n : ℕ} {F : ℂ → ℂ}
    (hF : Integrable F (complexCoordinateGaussianProbability n : Measure ℂ)) :
    Integrable (F ∘ Complex.measurableEquivPi.symm)
      (Measure.pi (fun _ : Fin 2 ↦
        (realCoordinateGaussianProbability n : Measure ℝ))) := by
  unfold complexCoordinateGaussianProbability at hF
  simpa only [ProbabilityMeasure.toMeasure_map, ProbabilityMeasure.toMeasure_pi] using
    (integrable_map_equiv Complex.measurableEquivPi.symm F).mp hF

theorem integrable_piRealGaussian_fderiv_real {n : ℕ} {F : ℂ → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    Integrable
      (fun x : Fin 2 → ℝ ↦
        (fderiv ℝ F (Complex.measurableEquivPi.symm x)) (1 : ℂ))
      (Measure.pi (fun _ : Fin 2 ↦
        (realCoordinateGaussianProbability n : Measure ℝ))) := by
  exact integrable_piRealGaussian_comp_complexEquiv
    (integrable_complexGaussian_fderiv_real hF hFc)

theorem integrable_piRealGaussian_fderiv_imag {n : ℕ} {F : ℂ → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    Integrable
      (fun x : Fin 2 → ℝ ↦
        (fderiv ℝ F (Complex.measurableEquivPi.symm x)) Complex.I)
      (Measure.pi (fun _ : Fin 2 ↦
        (realCoordinateGaussianProbability n : Measure ℝ))) := by
  exact integrable_piRealGaussian_comp_complexEquiv
    (integrable_complexGaussian_fderiv_imag hF hFc)

theorem integrable_piRealGaussian_re_mul {n : ℕ} {F : ℂ → ℂ}
    (hF : Continuous F) (hFc : HasCompactSupport F) :
    Integrable
      (fun x : Fin 2 → ℝ ↦
        ((Complex.measurableEquivPi.symm x).re : ℂ) *
          F (Complex.measurableEquivPi.symm x))
      (Measure.pi (fun _ : Fin 2 ↦
        (realCoordinateGaussianProbability n : Measure ℝ))) := by
  exact integrable_piRealGaussian_comp_complexEquiv
    (integrable_complexGaussian_re_mul hF hFc)

theorem integrable_piRealGaussian_im_mul {n : ℕ} {F : ℂ → ℂ}
    (hF : Continuous F) (hFc : HasCompactSupport F) :
    Integrable
      (fun x : Fin 2 → ℝ ↦
        ((Complex.measurableEquivPi.symm x).im : ℂ) *
          F (Complex.measurableEquivPi.symm x))
      (Measure.pi (fun _ : Fin 2 ↦
        (realCoordinateGaussianProbability n : Measure ℝ))) := by
  exact integrable_piRealGaussian_comp_complexEquiv
    (integrable_complexGaussian_im_mul hF hFc)

theorem integral_piFinTwo_eq_integral_prod {n : ℕ} {H : (Fin 2 → ℝ) → ℂ}
    (hH : Integrable H (Measure.pi (fun _ : Fin 2 ↦
      (realCoordinateGaussianProbability n : Measure ℝ)))) :
    (∫ x : Fin 2 → ℝ, H x
      ∂(Measure.pi (fun _ : Fin 2 ↦
        (realCoordinateGaussianProbability n : Measure ℝ)))) =
      ∫ x : ℝ, ∫ y : ℝ, H ![x, y]
        ∂(realCoordinateGaussianProbability n : Measure ℝ)
        ∂(realCoordinateGaussianProbability n : Measure ℝ) := by
  let μ : Fin 2 → Measure ℝ := fun _ ↦ realCoordinateGaussianProbability n
  let e := MeasurableEquiv.piFinTwo (fun _ : Fin 2 ↦ ℝ)
  have he : MeasurePreserving e (Measure.pi μ) ((μ 0).prod (μ 1)) :=
    measurePreserving_piFinTwo μ
  have hprod : Integrable (H ∘ e.symm) ((μ 0).prod (μ 1)) :=
    he.symm.integrable_comp_of_integrable hH
  calc
    _ = ∫ p : ℝ × ℝ, H (e.symm p) ∂((μ 0).prod (μ 1)) :=
      (he.symm.integral_comp' H).symm
    _ = ∫ x : ℝ, ∫ y : ℝ, H (e.symm (x, y)) ∂(μ 1) ∂(μ 0) :=
      integral_prod _ hprod
    _ = _ := by
      simp only [e, MeasurableEquiv.piFinTwo_symm_apply, μ]
      congr 2 with x

theorem integral_piFinTwo_eq_integral_prod_swap {n : ℕ} {H : (Fin 2 → ℝ) → ℂ}
    (hH : Integrable H (Measure.pi (fun _ : Fin 2 ↦
      (realCoordinateGaussianProbability n : Measure ℝ)))) :
    (∫ x : Fin 2 → ℝ, H x
      ∂(Measure.pi (fun _ : Fin 2 ↦
        (realCoordinateGaussianProbability n : Measure ℝ)))) =
      ∫ y : ℝ, ∫ x : ℝ, H ![x, y]
        ∂(realCoordinateGaussianProbability n : Measure ℝ)
        ∂(realCoordinateGaussianProbability n : Measure ℝ) := by
  let μ : Fin 2 → Measure ℝ := fun _ ↦ realCoordinateGaussianProbability n
  let e := MeasurableEquiv.piFinTwo (fun _ : Fin 2 ↦ ℝ)
  have he : MeasurePreserving e (Measure.pi μ) ((μ 0).prod (μ 1)) :=
    measurePreserving_piFinTwo μ
  have hprod : Integrable (H ∘ e.symm) ((μ 0).prod (μ 1)) :=
    he.symm.integrable_comp_of_integrable hH
  calc
    _ = ∫ p : ℝ × ℝ, H (e.symm p) ∂((μ 0).prod (μ 1)) :=
      (he.symm.integral_comp' H).symm
    _ = ∫ y : ℝ, ∫ x : ℝ, H (e.symm (x, y)) ∂(μ 0) ∂(μ 1) :=
      integral_prod_symm _ hprod
    _ = _ := by
      simp only [e, MeasurableEquiv.piFinTwo_symm_apply, μ]
      congr 2 with y

theorem integral_configuration_finSucc_split {k : ℕ} (j : Fin (k + 1))
    {H : Configuration (k + 1) → ℂ}
    (hH : Integrable H (complexGaussianMeasure (k + 1))) :
    (∫ z, H z ∂complexGaussianMeasure (k + 1)) =
      ∫ w : ℂ, ∫ r : Fin k → ℂ,
        H ((MeasurableEquiv.piFinSuccAbove (fun _ : Fin (k + 1) ↦ ℂ) j).symm
          (w, r))
        ∂(Measure.pi (fun _ : Fin k ↦
          (complexCoordinateGaussianProbability (k + 1) : Measure ℂ)))
        ∂(complexCoordinateGaussianProbability (k + 1) : Measure ℂ) := by
  let μ : Fin (k + 1) → Measure ℂ := fun _ ↦
    complexCoordinateGaussianProbability (k + 1)
  let e := MeasurableEquiv.piFinSuccAbove (fun _ : Fin (k + 1) ↦ ℂ) j
  have he : MeasurePreserving e (Measure.pi μ)
      ((μ j).prod (Measure.pi fun i : Fin k ↦ μ (j.succAbove i))) :=
    measurePreserving_piFinSuccAbove μ j
  unfold complexGaussianMeasure complexGaussianProbability at hH ⊢
  simp only [ProbabilityMeasure.toMeasure_pi] at hH ⊢
  have hprod : Integrable (H ∘ e.symm)
      ((μ j).prod (Measure.pi fun i : Fin k ↦ μ (j.succAbove i))) :=
    he.symm.integrable_comp_of_integrable hH
  calc
    _ = ∫ p : ℂ × (Fin k → ℂ), H (e.symm p)
        ∂((μ j).prod (Measure.pi fun i : Fin k ↦ μ (j.succAbove i))) :=
      (he.symm.integral_comp' H).symm
    _ = ∫ w : ℂ, ∫ r : Fin k → ℂ, H (e.symm (w, r))
        ∂(Measure.pi fun i : Fin k ↦ μ (j.succAbove i)) ∂(μ j) :=
      integral_prod _ hprod
    _ = _ := by simp only [μ, e]

theorem integral_configuration_finSucc_split_swap {k : ℕ} (j : Fin (k + 1))
    {H : Configuration (k + 1) → ℂ}
    (hH : Integrable H (complexGaussianMeasure (k + 1))) :
    (∫ z, H z ∂complexGaussianMeasure (k + 1)) =
      ∫ r : Fin k → ℂ, ∫ w : ℂ,
        H ((MeasurableEquiv.piFinSuccAbove (fun _ : Fin (k + 1) ↦ ℂ) j).symm
          (w, r))
        ∂(complexCoordinateGaussianProbability (k + 1) : Measure ℂ)
        ∂(Measure.pi (fun _ : Fin k ↦
          (complexCoordinateGaussianProbability (k + 1) : Measure ℂ))) := by
  let μ : Fin (k + 1) → Measure ℂ := fun _ ↦
    complexCoordinateGaussianProbability (k + 1)
  let e := MeasurableEquiv.piFinSuccAbove (fun _ : Fin (k + 1) ↦ ℂ) j
  have he : MeasurePreserving e (Measure.pi μ)
      ((μ j).prod (Measure.pi fun i : Fin k ↦ μ (j.succAbove i))) :=
    measurePreserving_piFinSuccAbove μ j
  unfold complexGaussianMeasure complexGaussianProbability at hH ⊢
  simp only [ProbabilityMeasure.toMeasure_pi] at hH ⊢
  have hprod : Integrable (H ∘ e.symm)
      ((μ j).prod (Measure.pi fun i : Fin k ↦ μ (j.succAbove i))) :=
    he.symm.integrable_comp_of_integrable hH
  calc
    _ = ∫ p : ℂ × (Fin k → ℂ), H (e.symm p)
        ∂((μ j).prod (Measure.pi fun i : Fin k ↦ μ (j.succAbove i))) :=
      (he.symm.integral_comp' H).symm
    _ = ∫ r : Fin k → ℂ, ∫ w : ℂ, H (e.symm (w, r))
        ∂(μ j) ∂(Measure.pi fun i : Fin k ↦ μ (j.succAbove i)) :=
      integral_prod_symm _ hprod
    _ = _ := by simp only [μ, e]

theorem integrable_configuration_fderiv_apply {m : ℕ}
    {F : Configuration m → ℂ} (hF : ContDiff ℝ 1 F)
    (hFc : HasCompactSupport F) (v : Configuration m) :
    Integrable (fun z ↦ (fderiv ℝ F z) v) (complexGaussianMeasure m) :=
  integrable_of_continuous_hasCompactSupport_isFiniteMeasure
    ((hF.continuous_fderiv (by norm_num)).clm_apply continuous_const)
    (hFc.fderiv_apply ℝ v)

theorem integrable_configuration_coordinate_re_mul {m : ℕ}
    {F : Configuration m → ℂ} (hF : Continuous F)
    (hFc : HasCompactSupport F) (j : Fin m) :
    Integrable (fun z ↦ ((z j).re : ℂ) * F z) (complexGaussianMeasure m) := by
  apply integrable_of_continuous_hasCompactSupport_isFiniteMeasure
  · fun_prop
  · exact hFc.mul_left

theorem integrable_configuration_coordinate_im_mul {m : ℕ}
    {F : Configuration m → ℂ} (hF : Continuous F)
    (hFc : HasCompactSupport F) (j : Fin m) :
    Integrable (fun z ↦ ((z j).im : ℂ) * F z) (complexGaussianMeasure m) := by
  apply integrable_of_continuous_hasCompactSupport_isFiniteMeasure
  · fun_prop
  · exact hFc.mul_left

theorem piFinSuccAbove_symm_eq_coordinateSlice {k : ℕ} (j : Fin (k + 1))
    (w : ℂ) (r : Fin k → ℂ) :
    (MeasurableEquiv.piFinSuccAbove (fun _ : Fin (k + 1) ↦ ℂ) j).symm (w, r) =
      configurationCoordinateSlice
        ((MeasurableEquiv.piFinSuccAbove (fun _ : Fin (k + 1) ↦ ℂ) j).symm
          (0, r)) j w := by
  funext i
  by_cases hij : i = j
  · subst i
    simp [configurationCoordinateSlice,
      MeasurableEquiv.piFinSuccAbove_symm_apply, Fin.insertNthEquiv]
  · simp [configurationCoordinateSlice,
      MeasurableEquiv.piFinSuccAbove_symm_apply, Fin.insertNthEquiv, hij]
    rcases lt_or_gt_of_ne hij with hlt | hgt
    · simp [Fin.insertNth_apply_below hlt]
    · simp [Fin.insertNth_apply_above hgt]

theorem isometry_complexRealSlice (y : ℝ) : Isometry (complexRealSlice y) := by
  rw [isometry_iff_dist_eq]
  intro x x'
  rw [dist_eq_norm, dist_eq_norm]
  unfold complexRealSlice
  ring_nf
  rw [← Complex.ofReal_sub, Complex.norm_real, Real.norm_eq_abs]

theorem isometry_complexImagSlice (x : ℝ) : Isometry (complexImagSlice x) := by
  rw [isometry_iff_dist_eq]
  intro y y'
  rw [dist_eq_norm, dist_eq_norm]
  unfold complexImagSlice
  ring_nf
  rw [show (y : ℂ) * Complex.I - Complex.I * (y' : ℂ) =
      ((y - y' : ℝ) : ℂ) * Complex.I by push_cast; ring]
  rw [norm_mul, Complex.norm_real, Real.norm_eq_abs]
  simp

theorem hasCompactSupport_comp_complexRealSlice {F : ℂ → ℂ}
    (hF : HasCompactSupport F) (y : ℝ) :
    HasCompactSupport (fun x ↦ F (complexRealSlice y x)) := by
  apply HasCompactSupport.intro
    ((isometry_complexRealSlice y).isClosedEmbedding.isCompact_preimage hF)
  intro x hx
  by_contra hne
  exact hx (subset_closure hne)

theorem hasCompactSupport_comp_complexImagSlice {F : ℂ → ℂ}
    (hF : HasCompactSupport F) (x : ℝ) :
    HasCompactSupport (fun y ↦ F (complexImagSlice x y)) := by
  apply HasCompactSupport.intro
    ((isometry_complexImagSlice x).isClosedEmbedding.isCompact_preimage hF)
  intro y hy
  by_contra hne
  exact hy (subset_closure hne)

theorem contDiff_comp_complexRealSlice {F : ℂ → ℂ}
    (hF : ContDiff ℝ 1 F) (y : ℝ) :
    ContDiff ℝ 1 (fun x ↦ F (complexRealSlice y x)) := by
  apply hF.comp
  unfold complexRealSlice
  exact Complex.ofRealCLM.contDiff.add contDiff_const

theorem contDiff_comp_complexImagSlice {F : ℂ → ℂ}
    (hF : ContDiff ℝ 1 F) (x : ℝ) :
    ContDiff ℝ 1 (fun y ↦ F (complexImagSlice x y)) := by
  apply hF.comp
  unfold complexImagSlice
  exact contDiff_const.add (Complex.ofRealCLM.contDiff.mul contDiff_const)

theorem deriv_comp_complexRealSlice {F : ℂ → ℂ} (hF : ContDiff ℝ 1 F)
    (y x : ℝ) :
    deriv (fun r ↦ F (complexRealSlice y r)) x =
      (fderiv ℝ F (complexRealSlice y x)) (1 : ℂ) := by
  change deriv (F ∘ complexRealSlice y) x = _
  apply HasDerivAt.deriv
  have hinner : HasDerivAt (complexRealSlice y) (1 : ℂ) x := by
    change HasDerivAt (fun r : ℝ ↦ (r : ℂ) + (y : ℂ) * Complex.I) (1 : ℂ) x
    simpa using
      (Complex.ofRealCLM.hasFDerivAt.hasDerivAt.add_const
        ((y : ℂ) * Complex.I))
  have houter := (hF.differentiable (by norm_num)
    (complexRealSlice y x)).hasFDerivAt
  simpa only [Function.comp_apply] using
    (HasFDerivAt.comp_hasDerivAt x houter hinner)

theorem deriv_comp_complexImagSlice {F : ℂ → ℂ} (hF : ContDiff ℝ 1 F)
    (x y : ℝ) :
    deriv (fun r ↦ F (complexImagSlice x r)) y =
      (fderiv ℝ F (complexImagSlice x y)) Complex.I := by
  change deriv (F ∘ complexImagSlice x) y = _
  apply HasDerivAt.deriv
  have hinner : HasDerivAt (complexImagSlice x) Complex.I y := by
    change HasDerivAt (fun r : ℝ ↦ (x : ℂ) + (r : ℂ) * Complex.I) Complex.I y
    simpa using
      ((Complex.ofRealCLM.hasFDerivAt.hasDerivAt.mul_const Complex.I).const_add
        (x : ℂ))
  have houter := (hF.differentiable (by norm_num)
    (complexImagSlice x y)).hasFDerivAt
  simpa only [Function.comp_apply] using
    (HasFDerivAt.comp_hasDerivAt y houter hinner)

theorem integral_complexGaussian_eq_integral_prod {n : ℕ} {F : ℂ → ℂ}
    (hF : Integrable F (complexCoordinateGaussianProbability n : Measure ℂ)) :
    (∫ z, F z ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      ∫ x : ℝ, ∫ y : ℝ, F ((x : ℂ) + (y : ℂ) * Complex.I)
        ∂(realCoordinateGaussianProbability n : Measure ℝ)
        ∂(realCoordinateGaussianProbability n : Measure ℝ) := by
  have hp := integrable_piRealGaussian_comp_complexEquiv hF
  unfold complexCoordinateGaussianProbability
  rw [ProbabilityMeasure.toMeasure_map, ProbabilityMeasure.toMeasure_pi,
    MeasureTheory.integral_map_equiv]
  simpa only [Function.comp_apply, Complex.measurableEquivPi_symm_apply,
    Matrix.cons_val_zero, Matrix.cons_val_one] using
    integral_piFinTwo_eq_integral_prod hp

theorem integral_complexGaussian_eq_integral_prod_swap {n : ℕ} {F : ℂ → ℂ}
    (hF : Integrable F (complexCoordinateGaussianProbability n : Measure ℂ)) :
    (∫ z, F z ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      ∫ y : ℝ, ∫ x : ℝ, F ((x : ℂ) + (y : ℂ) * Complex.I)
        ∂(realCoordinateGaussianProbability n : Measure ℝ)
        ∂(realCoordinateGaussianProbability n : Measure ℝ) := by
  have hp := integrable_piRealGaussian_comp_complexEquiv hF
  unfold complexCoordinateGaussianProbability
  rw [ProbabilityMeasure.toMeasure_map, ProbabilityMeasure.toMeasure_pi,
    MeasureTheory.integral_map_equiv]
  simpa only [Function.comp_apply, Complex.measurableEquivPi_symm_apply,
    Matrix.cons_val_zero, Matrix.cons_val_one] using
    integral_piFinTwo_eq_integral_prod_swap hp

theorem integrable_realProd_of_integrable_complexGaussian {n : ℕ}
    {F : ℂ → ℂ}
    (hF : Integrable F (complexCoordinateGaussianProbability n : Measure ℂ)) :
    Integrable (fun p : ℝ × ℝ ↦ F ((p.1 : ℂ) + (p.2 : ℂ) * Complex.I))
      ((realCoordinateGaussianProbability n : Measure ℝ).prod
        (realCoordinateGaussianProbability n : Measure ℝ)) := by
  have hp := integrable_piRealGaussian_comp_complexEquiv hF
  let μ : Fin 2 → Measure ℝ := fun _ ↦ realCoordinateGaussianProbability n
  let e := MeasurableEquiv.piFinTwo (fun _ : Fin 2 ↦ ℝ)
  have he : MeasurePreserving e (Measure.pi μ) ((μ 0).prod (μ 1)) :=
    measurePreserving_piFinTwo μ
  have hprod := he.symm.integrable_comp_of_integrable hp
  apply hprod.congr
  filter_upwards with p
  simp only [Function.comp_apply, e, μ,
    MeasurableEquiv.piFinTwo_symm_apply,
    Complex.measurableEquivPi_symm_apply,
    Matrix.cons_val_zero, Matrix.cons_val_one]
  congr 1

theorem complexGaussianIntegrationByParts_imag_of_integrable {n : ℕ}
    (hn : 0 < n) {F : ℂ → ℂ} (hF : ContDiff ℝ 1 F)
    (hFi : Integrable F (complexCoordinateGaussianProbability n : Measure ℂ))
    (hDi : Integrable (fun z ↦ (fderiv ℝ F z) Complex.I)
      (complexCoordinateGaussianProbability n : Measure ℂ))
    (hYi : Integrable (fun z ↦ (z.im : ℂ) * F z)
      (complexCoordinateGaussianProbability n : Measure ℂ)) :
    (∫ z, (fderiv ℝ F z) Complex.I
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (2 * n : ℝ) * ∫ z, (z.im : ℂ) * F z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
  have hFp := integrable_realProd_of_integrable_complexGaussian hFi
  have hDp := integrable_realProd_of_integrable_complexGaussian hDi
  have hYp := integrable_realProd_of_integrable_complexGaussian hYi
  have hFs := (integrable_prod_iff hFp.1).mp hFp |>.1
  have hDs := (integrable_prod_iff hDp.1).mp hDp |>.1
  have hYs := (integrable_prod_iff hYp.1).mp hYp |>.1
  rw [integral_complexGaussian_eq_integral_prod hDi,
    integral_complexGaussian_eq_integral_prod hYi, ← integral_const_mul]
  apply integral_congr_ae
  filter_upwards [hFs, hDs, hYs] with x hfx hdx hyx
  have hder : Integrable (deriv (fun y ↦ F (complexImagSlice x y)))
      (realCoordinateGaussianProbability n : Measure ℝ) := by
    apply hdx.congr
    filter_upwards with y
    rw [deriv_comp_complexImagSlice hF x]
    rfl
  have hy : Integrable (fun y : ℝ ↦ (y : ℂ) * F (complexImagSlice x y))
      (realCoordinateGaussianProbability n : Measure ℝ) := by
    apply hyx.congr
    filter_upwards with y
    simp [complexImagSlice]
  simp only [Complex.add_im, Complex.ofReal_im, Complex.mul_im,
    Complex.ofReal_re, Complex.I_re, Complex.I_im, zero_add, mul_one,
    zero_mul, add_zero]
  change (∫ y : ℝ, (fderiv ℝ F (complexImagSlice x y)) Complex.I
      ∂(realCoordinateGaussianProbability n : Measure ℝ)) =
    (2 * n : ℝ) * ∫ y : ℝ, (y : ℂ) * F (complexImagSlice x y)
      ∂(realCoordinateGaussianProbability n : Measure ℝ)
  rw [show (fun y : ℝ ↦ (fderiv ℝ F (complexImagSlice x y)) Complex.I) =
      deriv (fun y ↦ F (complexImagSlice x y)) by
    funext y
    exact (deriv_comp_complexImagSlice hF x y).symm]
  exact realGaussianIntegrationByParts_of_gaussian_integrable hn
    (contDiff_comp_complexImagSlice hF x) hfx hder hy

theorem complexGaussianIntegrationByParts_real_of_integrable {n : ℕ}
    (hn : 0 < n) {F : ℂ → ℂ} (hF : ContDiff ℝ 1 F)
    (hFi : Integrable F (complexCoordinateGaussianProbability n : Measure ℂ))
    (hDi : Integrable (fun z ↦ (fderiv ℝ F z) (1 : ℂ))
      (complexCoordinateGaussianProbability n : Measure ℂ))
    (hXi : Integrable (fun z ↦ (z.re : ℂ) * F z)
      (complexCoordinateGaussianProbability n : Measure ℂ)) :
    (∫ z, (fderiv ℝ F z) (1 : ℂ)
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (2 * n : ℝ) * ∫ z, (z.re : ℂ) * F z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
  have hFp := (integrable_realProd_of_integrable_complexGaussian hFi).swap
  have hDp := (integrable_realProd_of_integrable_complexGaussian hDi).swap
  have hXp := (integrable_realProd_of_integrable_complexGaussian hXi).swap
  have hFs := (integrable_prod_iff hFp.1).mp hFp |>.1
  have hDs := (integrable_prod_iff hDp.1).mp hDp |>.1
  have hXs := (integrable_prod_iff hXp.1).mp hXp |>.1
  rw [integral_complexGaussian_eq_integral_prod_swap hDi,
    integral_complexGaussian_eq_integral_prod_swap hXi, ← integral_const_mul]
  apply integral_congr_ae
  filter_upwards [hFs, hDs, hXs] with y hfy hdy hxy
  have hder : Integrable (deriv (fun x ↦ F (complexRealSlice y x)))
      (realCoordinateGaussianProbability n : Measure ℝ) := by
    apply hdy.congr
    filter_upwards with x
    rw [deriv_comp_complexRealSlice hF y]
    rfl
  have hx : Integrable (fun x : ℝ ↦ (x : ℂ) * F (complexRealSlice y x))
      (realCoordinateGaussianProbability n : Measure ℝ) := by
    apply hxy.congr
    filter_upwards with x
    simp [complexRealSlice]
  simp only [Complex.add_re, Complex.ofReal_re, Complex.mul_re,
    Complex.ofReal_im, Complex.I_re, Complex.I_im, mul_zero, zero_mul,
    mul_one, sub_zero, add_zero]
  change (∫ x : ℝ, (fderiv ℝ F (complexRealSlice y x)) (1 : ℂ)
      ∂(realCoordinateGaussianProbability n : Measure ℝ)) =
    (2 * n : ℝ) * ∫ x : ℝ, (x : ℂ) * F (complexRealSlice y x)
      ∂(realCoordinateGaussianProbability n : Measure ℝ)
  rw [show (fun x : ℝ ↦ (fderiv ℝ F (complexRealSlice y x)) (1 : ℂ)) =
      deriv (fun x ↦ F (complexRealSlice y x)) by
    funext x
    exact (deriv_comp_complexRealSlice hF y x).symm]
  exact realGaussianIntegrationByParts_of_gaussian_integrable hn
    (contDiff_comp_complexRealSlice hF y) hfy hder hx

theorem complexGaussianIntegrationByParts_real {n : ℕ} (hn : 0 < n)
    {F : ℂ → ℂ} (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    (∫ z, (fderiv ℝ F z) (1 : ℂ)
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (2 * n : ℝ) * ∫ z, (z.re : ℂ) * F z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
  rw [integral_complexGaussian_eq_integral_prod_swap
      (integrable_complexGaussian_fderiv_real hF hFc),
    integral_complexGaussian_eq_integral_prod_swap
      (integrable_complexGaussian_re_mul hF.continuous hFc)]
  simp only [Complex.add_re, Complex.ofReal_re, Complex.mul_re, Complex.I_re,
    Complex.I_im, mul_zero]
  rw [← MeasureTheory.integral_const_mul]
  congr 1
  funext y
  change (∫ x, (fderiv ℝ F (complexRealSlice y x)) (1 : ℂ)
      ∂(realCoordinateGaussianProbability n : Measure ℝ)) = _
  simp_rw [← deriv_comp_complexRealSlice hF y]
  simpa [complexRealSlice] using
    realGaussianIntegrationByParts hn (contDiff_comp_complexRealSlice hF y)
      (hasCompactSupport_comp_complexRealSlice hFc y)

theorem complexGaussianIntegrationByParts_imag {n : ℕ} (hn : 0 < n)
    {F : ℂ → ℂ} (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    (∫ z, (fderiv ℝ F z) Complex.I
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (2 * n : ℝ) * ∫ z, (z.im : ℂ) * F z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
  rw [integral_complexGaussian_eq_integral_prod
      (integrable_complexGaussian_fderiv_imag hF hFc),
    integral_complexGaussian_eq_integral_prod
      (integrable_complexGaussian_im_mul hF.continuous hFc)]
  simp only [Complex.add_im, Complex.ofReal_im, Complex.mul_im, Complex.I_re,
    Complex.I_im, zero_add, mul_one]
  rw [← MeasureTheory.integral_const_mul]
  congr 1
  funext x
  change (∫ y, (fderiv ℝ F (complexImagSlice x y)) Complex.I
      ∂(realCoordinateGaussianProbability n : Measure ℝ)) = _
  simp_rw [← deriv_comp_complexImagSlice hF x]
  simpa [complexImagSlice] using
    realGaussianIntegrationByParts hn (contDiff_comp_complexImagSlice hF x)
      (hasCompactSupport_comp_complexImagSlice hFc x)

theorem complexRealSlice_gaussianIntegrationByParts {n : ℕ} (hn : 0 < n)
    {F : ℂ → ℂ} (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F)
    (y : ℝ) :
    (∫ x, deriv (fun r ↦ F (complexRealSlice y r)) x
      ∂(realCoordinateGaussianProbability n : Measure ℝ)) =
      (2 * n : ℝ) * ∫ x, (x : ℂ) * F (complexRealSlice y x)
        ∂(realCoordinateGaussianProbability n : Measure ℝ) :=
  realGaussianIntegrationByParts hn (contDiff_comp_complexRealSlice hF y)
    (hasCompactSupport_comp_complexRealSlice hFc y)

theorem complexImagSlice_gaussianIntegrationByParts {n : ℕ} (hn : 0 < n)
    {F : ℂ → ℂ} (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F)
    (x : ℝ) :
    (∫ y, deriv (fun r ↦ F (complexImagSlice x r)) y
      ∂(realCoordinateGaussianProbability n : Measure ℝ)) =
      (2 * n : ℝ) * ∫ y, (y : ℂ) * F (complexImagSlice x y)
        ∂(realCoordinateGaussianProbability n : Measure ℝ) :=
  realGaussianIntegrationByParts hn (contDiff_comp_complexImagSlice hF x)
    (hasCompactSupport_comp_complexImagSlice hFc x)

theorem configurationCoordinateSlice_gaussianIntegrationByParts_real
    {m : ℕ} (hm : 0 < m) {F : Configuration m → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F)
    (r : Configuration m) (j : Fin m) :
    (∫ w, (fderiv ℝ (fun u ↦ F (configurationCoordinateSlice r j u)) w)
        (1 : ℂ) ∂(complexCoordinateGaussianProbability m : Measure ℂ)) =
      (2 * m : ℝ) * ∫ w, (w.re : ℂ) *
        F (configurationCoordinateSlice r j w)
        ∂(complexCoordinateGaussianProbability m : Measure ℂ) :=
  complexGaussianIntegrationByParts_real hm
    (contDiff_comp_configurationCoordinateSlice hF r j)
    (hasCompactSupport_comp_configurationCoordinateSlice hFc r j)

theorem configurationCoordinateSlice_gaussianIntegrationByParts_imag
    {m : ℕ} (hm : 0 < m) {F : Configuration m → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F)
    (r : Configuration m) (j : Fin m) :
    (∫ w, (fderiv ℝ (fun u ↦ F (configurationCoordinateSlice r j u)) w)
        Complex.I ∂(complexCoordinateGaussianProbability m : Measure ℂ)) =
      (2 * m : ℝ) * ∫ w, (w.im : ℂ) *
        F (configurationCoordinateSlice r j w)
        ∂(complexCoordinateGaussianProbability m : Measure ℂ) :=
  complexGaussianIntegrationByParts_imag hm
    (contDiff_comp_configurationCoordinateSlice hF r j)
    (hasCompactSupport_comp_configurationCoordinateSlice hFc r j)

theorem configurationGaussianIntegrationByParts_real_finSucc {k : ℕ}
    (j : Fin (k + 1)) {F : Configuration (k + 1) → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    (∫ z, (fderiv ℝ F z) (realCoordinateDirection j)
      ∂complexGaussianMeasure (k + 1)) =
      (2 * (k + 1) : ℝ) * ∫ z, ((z j).re : ℂ) * F z
        ∂complexGaussianMeasure (k + 1) := by
  rw [integral_configuration_finSucc_split_swap j
      (integrable_configuration_fderiv_apply hF hFc (realCoordinateDirection j)),
    integral_configuration_finSucc_split_swap j
      (integrable_configuration_coordinate_re_mul hF.continuous hFc j),
    ← MeasureTheory.integral_const_mul]
  congr 1
  funext r
  let z0 := (MeasurableEquiv.piFinSuccAbove
    (fun _ : Fin (k + 1) ↦ ℂ) j).symm (0, r)
  have hins : (fun w ↦ (MeasurableEquiv.piFinSuccAbove
      (fun _ : Fin (k + 1) ↦ ℂ) j).symm (w, r)) =
      configurationCoordinateSlice z0 j := by
    funext w
    exact piFinSuccAbove_symm_eq_coordinateSlice j w r
  have hins_apply (w : ℂ) : (MeasurableEquiv.piFinSuccAbove
      (fun _ : Fin (k + 1) ↦ ℂ) j).symm (w, r) =
      configurationCoordinateSlice z0 j w := congrFun hins w
  simp only [hins_apply]
  rw [show (fun w ↦ (fderiv ℝ F (configurationCoordinateSlice z0 j w))
      (realCoordinateDirection j)) =
      fun w ↦ (fderiv ℝ (fun u ↦ F (configurationCoordinateSlice z0 j u)) w)
        (1 : ℂ) by
    funext w
    rw [fderiv_comp_configurationCoordinateSlice_apply hF]
    rfl]
  simpa using configurationCoordinateSlice_gaussianIntegrationByParts_real
    (Nat.succ_pos k) hF hFc z0 j

theorem configurationGaussianIntegrationByParts_imag_finSucc {k : ℕ}
    (j : Fin (k + 1)) {F : Configuration (k + 1) → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    (∫ z, (fderiv ℝ F z) (imaginaryCoordinateDirection j)
      ∂complexGaussianMeasure (k + 1)) =
      (2 * (k + 1) : ℝ) * ∫ z, ((z j).im : ℂ) * F z
        ∂complexGaussianMeasure (k + 1) := by
  rw [integral_configuration_finSucc_split_swap j
      (integrable_configuration_fderiv_apply hF hFc (imaginaryCoordinateDirection j)),
    integral_configuration_finSucc_split_swap j
      (integrable_configuration_coordinate_im_mul hF.continuous hFc j),
    ← MeasureTheory.integral_const_mul]
  congr 1
  funext r
  let z0 := (MeasurableEquiv.piFinSuccAbove
    (fun _ : Fin (k + 1) ↦ ℂ) j).symm (0, r)
  have hins_apply (w : ℂ) : (MeasurableEquiv.piFinSuccAbove
      (fun _ : Fin (k + 1) ↦ ℂ) j).symm (w, r) =
      configurationCoordinateSlice z0 j w :=
    piFinSuccAbove_symm_eq_coordinateSlice j w r
  simp only [hins_apply]
  rw [show (fun w ↦ (fderiv ℝ F (configurationCoordinateSlice z0 j w))
      (imaginaryCoordinateDirection j)) =
      fun w ↦ (fderiv ℝ (fun u ↦ F (configurationCoordinateSlice z0 j u)) w)
        Complex.I by
    funext w
    rw [fderiv_comp_configurationCoordinateSlice_apply hF]
    rfl]
  simpa using configurationCoordinateSlice_gaussianIntegrationByParts_imag
    (Nat.succ_pos k) hF hFc z0 j

theorem integral_configuration_coordinate_mul_eq_re_add_im_finSucc {k : ℕ}
    (j : Fin (k + 1)) {F : Configuration (k + 1) → ℂ}
    (hF : Continuous F) (hFc : HasCompactSupport F) :
    (∫ z, z j * F z ∂complexGaussianMeasure (k + 1)) =
      (∫ z, ((z j).re : ℂ) * F z ∂complexGaussianMeasure (k + 1)) +
        Complex.I * ∫ z, ((z j).im : ℂ) * F z
          ∂complexGaussianMeasure (k + 1) := by
  rw [← MeasureTheory.integral_const_mul, ← MeasureTheory.integral_add
    (integrable_configuration_coordinate_re_mul hF hFc j)
    ((integrable_configuration_coordinate_im_mul hF hFc j).const_mul Complex.I)]
  apply integral_congr_ae
  filter_upwards [] with z
  apply Complex.ext <;> simp <;> ring

theorem configurationGaussianDbarIntegrationByParts_finSucc {k : ℕ}
    (j : Fin (k + 1)) {F : Configuration (k + 1) → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    (∫ z, dbarComponent F j z ∂complexGaussianMeasure (k + 1)) =
      ((k + 1 : ℕ) : ℂ) * ∫ z, z j * F z
        ∂complexGaussianMeasure (k + 1) := by
  have hr := integrable_configuration_fderiv_apply hF hFc
    (realCoordinateDirection j)
  have hi := integrable_configuration_fderiv_apply hF hFc
    (imaginaryCoordinateDirection j)
  unfold dbarComponent
  rw [MeasureTheory.integral_const_mul,
    MeasureTheory.integral_add hr (hi.const_mul Complex.I),
    MeasureTheory.integral_const_mul,
    configurationGaussianIntegrationByParts_real_finSucc j hF hFc,
    configurationGaussianIntegrationByParts_imag_finSucc j hF hFc,
    integral_configuration_coordinate_mul_eq_re_add_im_finSucc j hF.continuous hFc]
  push_cast
  ring

theorem configurationGaussianDbarIntegrationByParts {n : ℕ} (hn : 0 < n)
    (j : Fin n) {F : Configuration n → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    (∫ z, dbarComponent F j z ∂complexGaussianMeasure n) =
      (n : ℂ) * ∫ z, z j * F z ∂complexGaussianMeasure n := by
  obtain ⟨k, rfl⟩ := Nat.exists_eq_succ_of_ne_zero (Nat.ne_of_gt hn)
  exact configurationGaussianDbarIntegrationByParts_finSucc j hF hFc

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/ComplexGaussianMoments.lean #
import GinibrePoincare.Analysis.GaussianPolynomialIntegrability
import GinibrePoincare.Analysis.PolarGaussianMoments

/-! # Mixed moments of one complex Gaussian coordinate -/

open MeasureTheory Set
open scoped ComplexConjugate

namespace GinibrePoincare

noncomputable section

/-- Mixed complex monomials have the expected absolute value. -/
theorem norm_mixedComplexMonomial (a b : ℕ) (z : ℂ) :
    ‖z ^ a * (conj z) ^ b‖ = ‖z‖ ^ (a + b) := by
  simp [norm_pow, pow_add]

/-- Every mixed complex monomial is integrable under one complex Gaussian
coordinate law. -/
theorem integrable_mixedComplexMonomial (n a b : ℕ) :
    Integrable (fun z : ℂ ↦ z ^ a * (conj z) ^ b)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  apply Integrable.mono'
    (integrable_norm_pow_complexCoordinateGaussianProbability n (a + b))
  · fun_prop
  · filter_upwards with z
    exact le_of_eq (norm_mixedComplexMonomial a b z)

/-- The `(a,b)` mixed moment of one complex Gaussian coordinate. -/
noncomputable def complexGaussianMixedMoment (n a b : ℕ) : ℂ :=
  ∫ z : ℂ, z ^ a * (conj z) ^ b
    ∂(complexCoordinateGaussianProbability n : Measure ℂ)

/-- The zeroth mixed moment is one. -/
@[simp] theorem complexGaussianMixedMoment_zero_zero (n : ℕ) :
    complexGaussianMixedMoment n 0 0 = 1 := by
  simp [complexGaussianMixedMoment]

/-- Swapping the two exponents conjugates the mixed moment. -/
theorem complexGaussianMixedMoment_comm_conj (n a b : ℕ) :
    complexGaussianMixedMoment n b a =
      conj (complexGaussianMixedMoment n a b) := by
  unfold complexGaussianMixedMoment
  rw [← integral_conj]
  apply integral_congr_ae
  filter_upwards with z
  simp only [map_mul, map_pow]
  rw [show conj (conj z) = z by exact star_star z]
  ring

/-- The extended nonnegative density has the expected real value. -/
theorem complexCoordinateGaussianDensity_toReal (n : ℕ) (z : ℂ) :
    (complexCoordinateGaussianDensity n z).toReal =
      ((n : ℝ) / Real.pi) * Real.exp (-(n : ℝ) * Complex.normSq z) := by
  unfold complexCoordinateGaussianDensity
  rw [ENNReal.toReal_ofReal]
  positivity

/-- The mixed moment is the corresponding Jacobian-weighted polar integral. -/
theorem complexGaussianMixedMoment_eq_polar {n : ℕ} (hn : 0 < n) (a b : ℕ) :
    complexGaussianMixedMoment n a b =
      ∫ p : ℝ × ℝ in Set.Ioi 0 ×ˢ Set.Ioo (-Real.pi) Real.pi,
        ((((n : ℝ) : ℂ) / Real.pi) * (p.1 : ℂ) ^ (a + b + 1) *
          (Real.exp (-(n : ℝ) * p.1 ^ 2) : ℂ)) * angularMode a b p.2 := by
  unfold complexGaussianMixedMoment
  rw [complexCoordinateGaussianMeasure_eq_withDensity hn]
  rw [integral_withDensity_eq_integral_toReal_smul
    (measurable_complexCoordinateGaussianDensity n)
    (ae_of_all _ fun z ↦ ENNReal.ofReal_lt_top)]
  simp_rw [complexCoordinateGaussianDensity_toReal]
  rw [← Complex.integral_comp_polarCoord_symm]
  apply setIntegral_congr_fun Complex.polarCoord.open_target.measurableSet
  intro p hp
  change p.1 •
      (((n : ℝ) / Real.pi) *
        Real.exp (-(n : ℝ) * Complex.normSq (Complex.polarCoord.symm p))) •
        ((Complex.polarCoord.symm p) ^ a *
          conj (Complex.polarCoord.symm p) ^ b) = _
  rw [show Complex.normSq (Complex.polarCoord.symm p) = p.1 ^ 2 by
    rw [Complex.normSq_eq_norm_sq, Complex.norm_polarCoord_symm, sq_abs]]
  rw [gaussianMixedIntegrand_polar]
  push_cast
  rw [pow_succ]
  ring

/-- Exact mixed moments of the centered complex Gaussian coordinate law. -/
theorem complexGaussianMixedMoment_formula {n : ℕ} (hn : 0 < n) (a b : ℕ) :
    complexGaussianMixedMoment n a b =
      if a = b then (a.factorial : ℂ) / (n : ℂ) ^ a else 0 := by
  rw [complexGaussianMixedMoment_eq_polar hn]
  exact integral_gaussianMixedIntegrand_polar_eq n a b hn

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/ComplexGaussianProductIntegral.lean #
import GinibrePoincare.Concrete.GaussianProbability
import Mathlib.MeasureTheory.Integral.Pi

/-! # Factoring coordinatewise integrals under the complex Gaussian product -/

open MeasureTheory
open scoped BigOperators

namespace GinibrePoincare

noncomputable section

theorem integrable_prod_coordinateFunctions_complexGaussianMeasure
    (n : ℕ) (f : Fin n → ℂ → ℂ)
    (hf : ∀ i, Integrable (f i)
      (complexCoordinateGaussianProbability n : Measure ℂ)) :
    Integrable (fun z : Configuration n ↦ ∏ i, f i (z i))
      (complexGaussianMeasure n) := by
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  exact Integrable.fintype_prod hf

theorem integral_prod_coordinateFunctions_complexGaussianMeasure
    (n : ℕ) (f : Fin n → ℂ → ℂ) :
    (∫ z : Configuration n, ∏ i, f i (z i) ∂complexGaussianMeasure n) =
      ∏ i, ∫ w : ℂ, f i w
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  simpa using (integral_fintype_prod_eq_prod
    (𝕜 := ℂ) (E := fun _ : Fin n ↦ ℂ)
    (μ := fun _ : Fin n ↦
      (complexCoordinateGaussianProbability n : Measure ℂ)) f)

theorem integrable_and_integral_prod_coordinateFunctions_complexGaussianMeasure
    (n : ℕ) (f : Fin n → ℂ → ℂ)
    (hf : ∀ i, Integrable (f i)
      (complexCoordinateGaussianProbability n : Measure ℂ)) :
    Integrable (fun z : Configuration n ↦ ∏ i, f i (z i))
        (complexGaussianMeasure n) ∧
      (∫ z : Configuration n, ∏ i, f i (z i) ∂complexGaussianMeasure n) =
        ∏ i, ∫ w : ℂ, f i w
          ∂(complexCoordinateGaussianProbability n : Measure ℂ) :=
  ⟨integrable_prod_coordinateFunctions_complexGaussianMeasure n f hf,
    integral_prod_coordinateFunctions_complexGaussianMeasure n f⟩

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/ComplexHermite.lean #
import Mathlib.Algebra.MvPolynomial.PDeriv
import Mathlib.Data.Complex.Basic

/-!
# Univariate complex Hermite polynomials: algebraic layer

This file defines the two-variable polynomial underlying the complex Hermite
system.  The parameter `ρ` is the variance.  Thus the polynomial is

`J p q ρ = ∑ k, (-ρ)^k k! (p choose k) (q choose k) z^(p-k) w^(q-k)`.

Substitution `w = conj z` gives the usual univariate complex Hermite
polynomial.  Keeping the two formal variables separate makes the Wirtinger
operators honest partial derivatives.
-/

namespace GinibrePoincare

open scoped BigOperators ComplexConjugate

/-- The two formal coordinates `z` and `w` (later specialized to `z` and
`conj z`). -/
abbrev ComplexHermiteIndex := Fin 2

namespace ComplexHermite

abbrev Poly := MvPolynomial ComplexHermiteIndex ℂ

/-- Formal holomorphic coordinate. -/
noncomputable def Z : Poly := MvPolynomial.X 0

/-- Formal antiholomorphic coordinate. -/
noncomputable def W : Poly := MvPolynomial.X 1

/-- The unnormalized complex Hermite polynomial of bidegree `(p,q)` and
variance `ρ`. -/
noncomputable def raw (ρ : ℝ) (p q : ℕ) : Poly :=
  ∑ k ∈ Finset.range (min p q + 1),
    MvPolynomial.C (((-(ρ : ℂ)) ^ k) * (k.factorial : ℂ) *
      (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
      Z ^ (p - k) * W ^ (q - k)

/-- Evaluation of the formal polynomial on the complex diagonal
`(z, conj z)`. -/
noncomputable def eval (ρ : ℝ) (p q : ℕ) (z : ℂ) : ℂ :=
  MvPolynomial.eval ![z, conj z] (raw ρ p q)

@[simp] theorem raw_zero_right (ρ : ℝ) (p : ℕ) : raw ρ p 0 = Z ^ p := by
  simp [raw]

@[simp] theorem raw_zero_left (ρ : ℝ) (q : ℕ) : raw ρ 0 q = W ^ q := by
  simp [raw]

@[simp] theorem raw_zero_zero (ρ : ℝ) : raw ρ 0 0 = 1 := by
  simp

@[simp] theorem eval_zero_right (ρ : ℝ) (p : ℕ) (z : ℂ) :
    eval ρ p 0 z = z ^ p := by
  simp [eval, Z]

@[simp] theorem eval_zero_left (ρ : ℝ) (q : ℕ) (z : ℂ) :
    eval ρ 0 q z = (conj z) ^ q := by
  simp [eval, W]

@[simp] theorem eval_zero_zero (ρ : ℝ) (z : ℂ) : eval ρ 0 0 z = 1 := by
  simp

/-- The first mixed complex Hermite polynomial is `zw - ρ`. -/
theorem raw_one_one (ρ : ℝ) : raw ρ 1 1 = Z * W - MvPolynomial.C (ρ : ℂ) := by
  norm_num [raw, Z, W, Finset.sum_range_succ]
  ring

theorem eval_one_one (ρ : ℝ) (z : ℂ) :
    eval ρ 1 1 z = z * conj z - ρ := by
  rw [eval, raw_one_one]
  simp [Z, W]

/-- On the holomorphic axis the formal antiholomorphic derivative vanishes. -/
theorem pderiv_W_raw_zero_right (ρ : ℝ) (p : ℕ) :
    MvPolynomial.pderiv (1 : ComplexHermiteIndex) (raw ρ p 0) = 0 := by
  simp [raw_zero_right, Z]

/-- On the antiholomorphic axis the formal holomorphic derivative vanishes. -/
theorem pderiv_Z_raw_zero_left (ρ : ℝ) (q : ℕ) :
    MvPolynomial.pderiv (0 : ComplexHermiteIndex) (raw ρ 0 q) = 0 := by
  simp [raw_zero_left, W]

/-- Formal holomorphic differentiation on the holomorphic axis. -/
theorem pderiv_Z_raw_zero_right (ρ : ℝ) (p : ℕ) :
    MvPolynomial.pderiv (0 : ComplexHermiteIndex) (raw ρ p 0) =
      (p : Poly) * Z ^ (p - 1) := by
  simp [raw_zero_right, Z]

/-- Formal antiholomorphic differentiation on the antiholomorphic axis. -/
theorem pderiv_W_raw_zero_left (ρ : ℝ) (q : ℕ) :
    MvPolynomial.pderiv (1 : ComplexHermiteIndex) (raw ρ 0 q) =
      (q : Poly) * W ^ (q - 1) := by
  simp [raw_zero_left, W]

end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/ComplexHermiteLowering.lean #
import GinibrePoincare.Analysis.ComplexHermite

/-!
# Formal lowering identities for complex Hermite polynomials

The two formal partial derivatives lower the corresponding bidegree of the
raw complex Hermite polynomial, with coefficients `p` and `q`.  These are the
algebraic identities underlying the Wirtinger lowering relations after
specializing the two variables to `z` and `conj z`.
-/

namespace GinibrePoincare

open scoped BigOperators

namespace ComplexHermite

private theorem raw_eq_sum_range_right (ρ : ℝ) (p q : ℕ) :
    raw ρ p q =
      ∑ k ∈ Finset.range (q + 1),
        MvPolynomial.C (((-(ρ : ℂ)) ^ k) * (k.factorial : ℂ) *
          (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
          Z ^ (p - k) * W ^ (q - k) := by
  rw [raw]
  apply Finset.sum_subset
  · exact Finset.range_mono (Nat.succ_le_succ (min_le_right p q))
  · intro k hkq hkmin
    have hkq' : k ≤ q := Nat.lt_succ_iff.mp (Finset.mem_range.mp hkq)
    have hpk : p < k := by
      by_contra h
      have hkp : k ≤ p := Nat.le_of_not_gt h
      exact hkmin (Finset.mem_range.mpr (Nat.lt_succ_of_le (le_min hkp hkq')))
    simp [Nat.choose_eq_zero_of_lt hpk]

private theorem raw_eq_sum_range_left (ρ : ℝ) (p q : ℕ) :
    raw ρ p q =
      ∑ k ∈ Finset.range (p + 1),
        MvPolynomial.C (((-(ρ : ℂ)) ^ k) * (k.factorial : ℂ) *
          (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
          Z ^ (p - k) * W ^ (q - k) := by
  rw [raw]
  apply Finset.sum_subset
  · exact Finset.range_mono (Nat.succ_le_succ (min_le_left p q))
  · intro k hkp hkmin
    have hkp' : k ≤ p := Nat.lt_succ_iff.mp (Finset.mem_range.mp hkp)
    have hqk : q < k := by
      by_contra h
      have hkq : k ≤ q := Nat.le_of_not_gt h
      exact hkmin (Finset.mem_range.mpr (Nat.lt_succ_of_le (le_min hkp' hkq)))
    simp [Nat.choose_eq_zero_of_lt hqk]

/-- Formal differentiation in the holomorphic variable lowers the first
bidegree, with the exact unnormalized coefficient `p`. -/
theorem pderiv_Z_raw (ρ : ℝ) (p q : ℕ) :
    MvPolynomial.pderiv (0 : ComplexHermiteIndex) (raw ρ p q) =
      (p : Poly) * raw ρ (p - 1) q := by
  cases p with
  | zero => rw [pderiv_Z_raw_zero_left]; simp
  | succ p =>
      rw [raw_eq_sum_range_right, raw_eq_sum_range_right]
      simp only [map_sum, MvPolynomial.pderiv_C, MvPolynomial.pderiv_mul,
        MvPolynomial.pderiv_pow, Z, W, MvPolynomial.pderiv_X_self,
        MvPolynomial.pderiv_X_of_ne (by decide : (1 : ComplexHermiteIndex) ≠ 0),
        mul_zero, add_zero, mul_one, Nat.succ_sub_one, Finset.mul_sum]
      apply Finset.sum_congr rfl
      intro k hk
      have hnat : Nat.choose (p + 1) k * (p + 1 - k) =
          (p + 1) * Nat.choose p k := by
        simpa [Nat.mul_comm] using (Nat.choose_mul_succ_eq p k).symm
      have hcoef := congrArg (fun n : ℕ => (n : ℂ)) hnat
      simp only [Nat.cast_mul] at hcoef
      rw [show p + 1 - k - 1 = p - k by omega]
      push_cast at hcoef
      simp only [zero_mul, zero_add]
      have hc :
          MvPolynomial.C ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
              (Nat.choose (p + 1) k : ℂ) * (Nat.choose q k : ℂ)) *
              ((p + 1 - k : ℕ) : Poly) =
            ((p + 1 : ℕ) : Poly) *
              MvPolynomial.C ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
                (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) := by
        rw [show ((p + 1 - k : ℕ) : Poly) =
              MvPolynomial.C ((p + 1 - k : ℕ) : ℂ) by rfl,
          show ((p + 1 : ℕ) : Poly) = MvPolynomial.C ((p + 1 : ℕ) : ℂ) by rfl,
          ← MvPolynomial.C_mul, ← MvPolynomial.C_mul]
        congr 1
        calc
          _ = ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
                (Nat.choose q k : ℂ)) *
              ((Nat.choose (p + 1) k : ℂ) * (p + 1 - k : ℕ)) := by ring
          _ = ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
                (Nat.choose q k : ℂ)) *
              (((p : ℂ) + 1) * (Nat.choose p k : ℂ)) := by rw [hcoef]
          _ = _ := by
            simp only [Nat.cast_add, Nat.cast_one]
            ring
      calc
        _ = (MvPolynomial.C ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
              (Nat.choose (p + 1) k : ℂ) * (Nat.choose q k : ℂ)) *
              ((p + 1 - k : ℕ) : Poly)) *
              MvPolynomial.X 0 ^ (p - k) * MvPolynomial.X 1 ^ (q - k) := by ring
        _ = (((p + 1 : ℕ) : Poly) *
              MvPolynomial.C ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
                (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ))) *
              MvPolynomial.X 0 ^ (p - k) * MvPolynomial.X 1 ^ (q - k) := by rw [hc]
        _ = _ := by push_cast; ring

/-- Formal differentiation in the antiholomorphic variable lowers the second
bidegree, with the exact unnormalized coefficient `q`. -/
theorem pderiv_W_raw (ρ : ℝ) (p q : ℕ) :
    MvPolynomial.pderiv (1 : ComplexHermiteIndex) (raw ρ p q) =
      (q : Poly) * raw ρ p (q - 1) := by
  cases q with
  | zero => rw [pderiv_W_raw_zero_right]; simp
  | succ q =>
      rw [raw_eq_sum_range_left, raw_eq_sum_range_left]
      simp only [map_sum, MvPolynomial.pderiv_C, MvPolynomial.pderiv_mul,
        MvPolynomial.pderiv_pow, Z, W, MvPolynomial.pderiv_X_self,
        MvPolynomial.pderiv_X_of_ne (by decide : (0 : ComplexHermiteIndex) ≠ 1),
        mul_zero, zero_mul, add_zero, mul_one, Nat.succ_sub_one, Finset.mul_sum]
      apply Finset.sum_congr rfl
      intro k hk
      have hnat : Nat.choose (q + 1) k * (q + 1 - k) =
          (q + 1) * Nat.choose q k := by
        simpa [Nat.mul_comm] using (Nat.choose_mul_succ_eq q k).symm
      have hcoef := congrArg (fun n : ℕ => (n : ℂ)) hnat
      simp only [Nat.cast_mul] at hcoef
      rw [show q + 1 - k - 1 = q - k by omega]
      push_cast at hcoef
      simp only [zero_add]
      have hc :
          MvPolynomial.C ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
              (Nat.choose p k : ℂ) * (Nat.choose (q + 1) k : ℂ)) *
              ((q + 1 - k : ℕ) : Poly) =
            ((q + 1 : ℕ) : Poly) *
              MvPolynomial.C ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
                (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) := by
        rw [show ((q + 1 - k : ℕ) : Poly) =
              MvPolynomial.C ((q + 1 - k : ℕ) : ℂ) by rfl,
          show ((q + 1 : ℕ) : Poly) = MvPolynomial.C ((q + 1 : ℕ) : ℂ) by rfl,
          ← MvPolynomial.C_mul, ← MvPolynomial.C_mul]
        congr 1
        calc
          _ = ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
                (Nat.choose p k : ℂ)) *
              ((Nat.choose (q + 1) k : ℂ) * (q + 1 - k : ℕ)) := by ring
          _ = ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
                (Nat.choose p k : ℂ)) *
              (((q : ℂ) + 1) * (Nat.choose q k : ℂ)) := by rw [hcoef]
          _ = _ := by
            simp only [Nat.cast_add, Nat.cast_one]
            ring
      calc
        _ = (MvPolynomial.C ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
              (Nat.choose p k : ℂ) * (Nat.choose (q + 1) k : ℂ)) *
              ((q + 1 - k : ℕ) : Poly)) *
              MvPolynomial.X 0 ^ (p - k) * MvPolynomial.X 1 ^ (q - k) := by ring
        _ = (((q + 1 : ℕ) : Poly) *
              MvPolynomial.C ((-(ρ : ℂ)) ^ k * (k.factorial : ℂ) *
                (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ))) *
              MvPolynomial.X 0 ^ (p - k) * MvPolynomial.X 1 ^ (q - k) := by rw [hc]
        _ = _ := by push_cast; ring

end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/ComplexHermiteOrthogonality.lean #
import GinibrePoincare.Analysis.MultivariateComplexHermite
import GinibrePoincare.Analysis.GaussianPolynomialIntegrability

/-! # Analytic prerequisites for complex Hermite orthogonality -/

open MeasureTheory
open scoped BigOperators ComplexConjugate

namespace GinibrePoincare
namespace ComplexHermite

noncomputable section

/-- Explicit diagonal finite-sum formula for the normalized complex Hermite
polynomial. -/
theorem normalizedEval_eq_sum (n : ℕ) (hn : 0 < n) (p q : ℕ) (z : ℂ) :
    normalizedEval n hn p q z =
      ((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ) *
        ∑ k ∈ Finset.range (min p q + 1),
          (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
              (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
            z ^ (p - k) * (conj z) ^ (q - k) := by
  simp [normalizedEval, normalized, raw, Z, W, Finset.mul_sum]

/-- Every monomial occurring in the diagonal complex-Hermite expansion is
integrable under the matching complex Gaussian coordinate law. -/
theorem integrable_complex_monomial_complexCoordinateGaussianProbability
    (n a b : ℕ) :
    Integrable (fun z : ℂ ↦ z ^ a * (conj z) ^ b)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  apply Integrable.mono'
    (integrable_norm_pow_complexCoordinateGaussianProbability n (a + b))
  · fun_prop
  · filter_upwards with z
    simp only [norm_mul, norm_pow, Complex.norm_conj]
    rw [← pow_add]

/-- Each normalized complex Hermite polynomial is integrable under the
matching complex Gaussian coordinate law. -/
theorem integrable_normalizedEval (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    Integrable (normalizedEval n hn p q)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  rw [show normalizedEval n hn p q = fun z ↦
      ((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ) *
        ∑ k ∈ Finset.range (min p q + 1),
          (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
              (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
            z ^ (p - k) * (conj z) ^ (q - k) by
    funext z
    exact normalizedEval_eq_sum n hn p q z]
  apply Integrable.const_mul
  apply integrable_finsetSum
  intro k hk
  simpa only [mul_assoc] using
    (integrable_complex_monomial_complexCoordinateGaussianProbability
      n (p - k) (q - k)).const_mul
        (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
          (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ))

/-- The degree-zero normalized complex Hermite polynomial has unit norm. -/
theorem normalizedEval_zero_zero_inner (n : ℕ) (hn : 0 < n) :
    ∫ z : ℂ, conj (normalizedEval n hn 0 0 z) *
        normalizedEval n hn 0 0 z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ) = 1 := by
  simp

end
end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/FiniteHermiteDeficit.lean #
import GinibrePoincare.Analysis.HermiteEnergy

/-! # Finite Hermite deficit decomposition -/

open MeasureTheory
open scoped BigOperators

namespace GinibrePoincare
namespace ComplexHermite

noncomputable section

/-- The degree-zero part of a finite Hermite coefficient vector. -/
def zeroAntiCoefficients {n : ℕ} (c : HermiteMultiIndex n →₀ ℂ) :=
  coefficientsAtAntiDegree c 0

/-- The strictly positive antiholomorphic-degree part. -/
def positiveAntiCoefficients {n : ℕ} (c : HermiteMultiIndex n →₀ ℂ) :
    HermiteMultiIndex n →₀ ℂ :=
  c.filter fun pq => 0 < totalAntiDegree pq

theorem zero_add_positiveAntiCoefficients {n : ℕ}
    (c : HermiteMultiIndex n →₀ ℂ) :
    zeroAntiCoefficients c + positiveAntiCoefficients c = c := by
  ext pq
  by_cases h0 : totalAntiDegree pq = 0
  · simp [zeroAntiCoefficients, positiveAntiCoefficients,
      coefficientsAtAntiDegree, h0]
  · have hp : 0 < totalAntiDegree pq := Nat.pos_of_ne_zero h0
    simp [zeroAntiCoefficients, positiveAntiCoefficients,
      coefficientsAtAntiDegree, h0, hp]

/-- The finite Hermite vector splits into its degree-zero and positive
antiholomorphic-degree parts. -/
theorem finiteHermiteCombination_zero_add_positive (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    finiteHermiteCombination n hn c =
      finiteHermiteCombination n hn (zeroAntiCoefficients c) +
        finiteHermiteCombination n hn (positiveAntiCoefficients c) := by
  unfold finiteHermiteCombination
  rw [← map_add, zero_add_positiveAntiCoefficients]

/-- The two pieces in the zero/positive splitting are orthogonal. -/
theorem inner_zero_positiveAnti_eq_zero (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    inner ℂ (finiteHermiteCombination n hn (zeroAntiCoefficients c))
      (finiteHermiteCombination n hn (positiveAntiCoefficients c)) = 0 := by
  rw [inner_finiteHermiteCombination]
  unfold Finsupp.sum
  apply Finset.sum_eq_zero
  intro pq hpq
  have hz : totalAntiDegree pq = 0 := by
    have hnz := Finsupp.mem_support_iff.mp hpq
    by_contra hz
    apply hnz
    simp [zeroAntiCoefficients, coefficientsAtAntiDegree, hz]
  simp [positiveAntiCoefficients, hz]

/-- Exact Parseval/Pythagoras decomposition into degree zero and positive
degree. -/
theorem norm_sq_zero_add_positive (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    ‖finiteHermiteCombination n hn c‖ ^ 2 =
      ‖finiteHermiteCombination n hn (zeroAntiCoefficients c)‖ ^ 2 +
      ‖finiteHermiteCombination n hn (positiveAntiCoefficients c)‖ ^ 2 := by
  rw [finiteHermiteCombination_zero_add_positive]
  simp only [pow_two]
  apply norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero (𝕜 := ℂ)
  exact inner_zero_positiveAnti_eq_zero n hn c

/-- The finite deficit after subtracting the positive-mode mass from the
normalized `∂̄` energy. -/
def finiteHermiteDeficit {n : ℕ} (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) : ℝ :=
  (n : ℝ)⁻¹ * finiteDbarEnergy c -
    ‖finiteHermiteCombination n hn (positiveAntiCoefficients c)‖ ^ 2

/-- Exact coefficient form of the finite deficit: degree one cancels and
only degrees at least two remain. -/
theorem finiteHermiteDeficit_eq_sum (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    finiteHermiteDeficit hn c =
      c.sum fun pq a => (totalAntiDegree pq - 1 : ℕ) * Complex.normSq a := by
  unfold finiteHermiteDeficit finiteDbarEnergy
  rw [norm_sq_finiteHermiteCombination]
  rw [show (positiveAntiCoefficients c).sum
      (fun _ a => Complex.normSq a) =
      c.sum fun pq a => if 0 < totalAntiDegree pq then
        Complex.normSq a else 0 by
    classical
    unfold positiveAntiCoefficients Finsupp.sum
    have hsupp :
        (Finsupp.filter (fun pq => 0 < totalAntiDegree pq) c).support =
          c.support.filter (fun pq => 0 < totalAntiDegree pq) := by
      ext pq
      simp
    rw [hsupp, Finset.sum_filter]
    apply Finset.sum_congr rfl
    intro pq hpq
    by_cases h : 0 < totalAntiDegree pq <;> simp [h]]
  unfold Finsupp.sum
  rw [Finset.mul_sum, ← Finset.sum_sub_distrib]
  apply Finset.sum_congr rfl
  intro pq hpq
  by_cases h0 : totalAntiDegree pq = 0
  · simp [h0]
  · have hp : 0 < totalAntiDegree pq := Nat.pos_of_ne_zero h0
    simp [hp]
    have hn0 : (n : ℝ) ≠ 0 := by exact_mod_cast hn.ne'
    rw [Complex.sq_norm]
    field_simp

/-- Squared norm of the finite piece of exact antiholomorphic degree `m`. -/
def finiteAntiDegreeMass (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) (m : ℕ) : ℝ :=
  ‖finiteHermiteCombination n hn (coefficientsAtAntiDegree c m)‖ ^ 2

theorem finiteAntiDegreeMass_eq_sum (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) (m : ℕ) :
    finiteAntiDegreeMass n hn c m =
      c.sum fun pq a => if totalAntiDegree pq = m then
        Complex.normSq a else 0 := by
  unfold finiteAntiDegreeMass
  rw [norm_sq_finiteHermiteCombination]
  classical
  unfold coefficientsAtAntiDegree Finsupp.sum
  have hsupp :
      (Finsupp.filter (fun pq => totalAntiDegree pq = m) c).support =
        c.support.filter (fun pq => totalAntiDegree pq = m) := by
    ext pq
    simp
  rw [hsupp, Finset.sum_filter]
  apply Finset.sum_congr rfl
  intro pq hpq
  by_cases h : totalAntiDegree pq = m <;> simp [h]

/-- The finite set of antiholomorphic degrees occurring in the support. -/
def activeAntiDegrees {n : ℕ} (c : HermiteMultiIndex n →₀ ℂ) : Finset ℕ :=
  c.support.image totalAntiDegree

/-- Regrouping of the exact deficit as the finite sum of degree-piece norms
with weights `m - 1`; only degrees at least two occur. -/
theorem finiteHermiteDeficit_eq_sum_degreeMass (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    finiteHermiteDeficit hn c =
      ∑ m ∈ (activeAntiDegrees c).filter (fun m => 2 ≤ m),
        (m - 1 : ℕ) * finiteAntiDegreeMass n hn c m := by
  rw [finiteHermiteDeficit_eq_sum]
  simp_rw [finiteAntiDegreeMass_eq_sum]
  unfold activeAntiDegrees Finsupp.sum
  simp_rw [Finset.mul_sum]
  rw [Finset.sum_comm]
  apply Finset.sum_congr rfl
  intro pq hpq
  by_cases hp : 2 ≤ totalAntiDegree pq
  · have hmem : totalAntiDegree pq ∈
        (c.support.image totalAntiDegree).filter (fun m => 2 ≤ m) := by
      apply Finset.mem_filter.mpr
      exact ⟨Finset.mem_image.mpr ⟨pq, hpq, rfl⟩, hp⟩
    rw [Finset.sum_eq_single (totalAntiDegree pq)]
    · simp
    · intro m hm hne
      simp [hne.symm]
    · intro hnot
      exact (hnot hmem).elim
  · have hz : totalAntiDegree pq - 1 = 0 := by omega
    simp [hp, hz]

/-- The finite degree-zero component belongs to the closed degree-zero
Hermite span. -/
theorem finiteHermiteCombination_zero_mem_closedSpan (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    finiteHermiteCombination n hn (zeroAntiCoefficients c) ∈
      hermiteAntiDegreeClosedSpan n hn 0 := by
  unfold finiteHermiteCombination zeroAntiCoefficients
  rw [Finsupp.linearCombination_apply]
  apply Submodule.sum_mem
  intro pq hpq
  apply Submodule.smul_mem
  apply hermiteL2Family_mem_antiDegreeClosedSpan
  have hpq0 := Finsupp.mem_support_iff.mp hpq
  by_contra h
  apply hpq0
  simp [coefficientsAtAntiDegree, h]

private theorem finiteHermiteCombination_positive_mem_orthogonal (n : ℕ)
    (hn : 0 < n) (c : HermiteMultiIndex n →₀ ℂ) :
    finiteHermiteCombination n hn (positiveAntiCoefficients c) ∈
      (hermiteAntiDegreeClosedSpan n hn 0 :
        Submodule ℂ (Lp ℂ 2 (complexGaussianMeasure n)))ᗮ := by
  rw [show (hermiteAntiDegreeClosedSpan n hn 0 :
      Submodule ℂ (Lp ℂ 2 (complexGaussianMeasure n)))ᗮ =
      (hermiteAntiDegreeSpan n hn 0)ᗮ by
    exact Submodule.orthogonal_closure _]
  rw [Submodule.mem_orthogonal']
  intro y hy
  unfold hermiteAntiDegreeSpan at hy
  refine Submodule.span_induction ?_ ?_ ?_ ?_ hy
  · intro y hy
    obtain ⟨pq, hpq, rfl⟩ := hy
    unfold finiteHermiteCombination
    rw [(orthonormal_hermiteL2Family_gaussian n hn).inner_left_finsupp]
    have hz : ¬ 0 < totalAntiDegree pq := by
      have : totalAntiDegree pq = 0 := hpq
      omega
    simp [positiveAntiCoefficients, hz]
  · simp
  · intro x y hx hy hix hiy
    rw [inner_add_right, hix, hiy, add_zero]
  · intro a y hy hiy
    rw [inner_smul_right, hiy, mul_zero]

/-- The closed degree-zero projection of a finite Hermite combination is
exactly its degree-zero piece. -/
theorem starProjection_finiteHermiteCombination_eq_zeroPiece (n : ℕ)
    (hn : 0 < n) (c : HermiteMultiIndex n →₀ ℂ) :
    (hermiteAntiDegreeClosedSpan n hn 0).starProjection
        (finiteHermiteCombination n hn c) =
      finiteHermiteCombination n hn (zeroAntiCoefficients c) := by
  apply Submodule.eq_starProjection_of_mem_orthogonal
  · exact finiteHermiteCombination_zero_mem_closedSpan n hn c
  · rw [finiteHermiteCombination_zero_add_positive]
    simp only [add_sub_cancel_left]
    exact finiteHermiteCombination_positive_mem_orthogonal n hn c

/-- Distance from a finite Hermite combination to its degree-zero
orthogonal projection equals the norm of its positive-degree part. -/
theorem norm_sub_degreeZeroProjection_eq_positive (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    ‖finiteHermiteCombination n hn c -
        (hermiteAntiDegreeClosedSpan n hn 0).starProjection
          (finiteHermiteCombination n hn c)‖ =
      ‖finiteHermiteCombination n hn (positiveAntiCoefficients c)‖ := by
  rw [starProjection_finiteHermiteCombination_eq_zeroPiece,
    finiteHermiteCombination_zero_add_positive]
  simp

end
end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/FinitePiDensity.lean #
import Mathlib.MeasureTheory.Integral.Pi
import Mathlib.MeasureTheory.Measure.WithDensity

/-!
# Densities of finite product measures

This file proves that a finite product of measures with densities has density
the product of the coordinate densities.  Mathlib contains the binary version
(`Measure.prod_withDensity`); the theorem below packages its finite dependent
product analogue.
-/

open Fintype MeasureTheory

namespace GinibrePoincare

noncomputable section

set_option backward.isDefEq.respectTransparency false in
/-- Tonelli's product formula for a product of `ℝ≥0∞`-valued functions on a
finite dependent product. -/
theorem lintegral_fin_nat_prod_eq_prod {n : ℕ} {E : Fin n → Type*}
    {mE : ∀ i, MeasurableSpace (E i)} {μ : (i : Fin n) → Measure (E i)}
    [∀ i, SigmaFinite (μ i)] (f : ∀ i : Fin n, E i → ENNReal)
    (hf : ∀ i, Measurable (f i)) :
    ∫⁻ x : (i : Fin n) → E i, ∏ i, f i (x i) ∂(Measure.pi μ) =
      ∏ i, ∫⁻ x, f i x ∂(μ i) := by
  induction n with
  | zero => simp
  | succ n ih =>
      calc
        _ = ∫⁻ x : E 0 × ((i : Fin n) → E (Fin.succ i)),
            f 0 x.1 * ∏ i : Fin n, f (Fin.succ i) (x.2 i)
            ∂((μ 0).prod (Measure.pi (fun i ↦ μ i.succ))) := by
          rw [← ((measurePreserving_piFinSuccAbove μ 0).symm).lintegral_comp_emb
            (MeasurableEquiv.measurableEmbedding _)]
          simp_rw [MeasurableEquiv.piFinSuccAbove_symm_apply, Fin.insertNthEquiv,
            Fin.prod_univ_succ, Fin.insertNth_zero, Equiv.coe_fn_mk, Fin.cons_succ,
            Fin.zero_succAbove, cast_eq, Fin.cons_zero]
        _ = (∫⁻ x, f 0 x ∂μ 0) *
            ∫⁻ x : (i : Fin n) → E (Fin.succ i),
              ∏ i, f (Fin.succ i) (x i) ∂(Measure.pi (fun i ↦ μ i.succ)) := by
          have hg : AEMeasurable
              (fun x : (i : Fin n) → E (Fin.succ i) ↦
                ∏ i, f (Fin.succ i) (x i))
              (Measure.pi (fun i ↦ μ (Fin.succ i))) :=
            Finset.aemeasurable_fun_prod Finset.univ fun i _ ↦
              (hf (Fin.succ i)).aemeasurable.comp_quasiMeasurePreserving
                (Measure.quasiMeasurePreserving_eval _ i)
          exact lintegral_prod_mul (μ := μ 0)
            (ν := Measure.pi (fun i ↦ μ (Fin.succ i))) (hf 0).aemeasurable hg
        _ = (∫⁻ x, f 0 x ∂μ 0) *
            ∏ i : Fin n, ∫⁻ x, f (Fin.succ i) x ∂(μ i.succ) := by
          rw [ih (fun i ↦ f i.succ) (fun i ↦ hf i.succ)]
        _ = ∏ i, ∫⁻ x, f i x ∂(μ i) := by
          rw [Fin.prod_univ_succ]

set_option backward.isDefEq.respectTransparency false in
/-- Tonelli's product formula for a product of `ℝ≥0∞`-valued functions indexed
by an arbitrary finite type. -/
theorem lintegral_fintype_prod_eq_prod {ι : Type*} [Fintype ι]
    {E : ι → Type*} {mE : ∀ i, MeasurableSpace (E i)}
    {μ : (i : ι) → Measure (E i)} [∀ i, SigmaFinite (μ i)]
    (f : ∀ i : ι, E i → ENNReal) (hf : ∀ i, Measurable (f i)) :
    ∫⁻ x : (i : ι) → E i, ∏ i, f i (x i) ∂(Measure.pi μ) =
      ∏ i, ∫⁻ x, f i x ∂(μ i) := by
  let e := (equivFin ι).symm
  rw [← (measurePreserving_piCongrLeft _ e).lintegral_comp_emb
    (MeasurableEquiv.measurableEmbedding _)]
  simp_rw [← e.prod_comp, MeasurableEquiv.coe_piCongrLeft,
    Equiv.piCongrLeft_apply_apply]
  rw [lintegral_fin_nat_prod_eq_prod _ (fun i ↦ hf _)]

/-- A finite product of coordinate measures with measurable densities is the
product base measure with the product density. -/
theorem Measure.pi_withDensity {ι : Type*} [Fintype ι]
    {E : ι → Type*} {mE : ∀ i, MeasurableSpace (E i)}
    (μ : (i : ι) → Measure (E i)) [∀ i, SigmaFinite (μ i)]
    (f : ∀ i : ι, E i → ENNReal) (hf : ∀ i, Measurable (f i))
    [∀ i, SigmaFinite ((μ i).withDensity (f i))] :
    Measure.pi (fun i ↦ (μ i).withDensity (f i)) =
      (Measure.pi μ).withDensity (fun x ↦ ∏ i, f i (x i)) := by
  apply Measure.pi_eq
  intro s hs
  rw [withDensity_apply _ (MeasurableSet.univ_pi hs)]
  simp_rw [withDensity_apply _ (hs _)]
  rw [← lintegral_indicator (MeasurableSet.univ_pi hs)]
  simp_rw [← lintegral_indicator (hs _)]
  rw [← lintegral_fintype_prod_eq_prod
    (fun i x ↦ (s i).indicator (f i) x)
    (fun i ↦ (hf i).indicator (hs i))]
  apply lintegral_congr
  intro x
  simp only [Set.indicator]
  split_ifs with h
  · have hh : ∀ i, x i ∈ s i := by simpa [Set.mem_pi] using h
    simp_rw [if_pos (hh _)]
  · have hh : ¬ ∀ i, x i ∈ s i := by simpa [Set.mem_pi] using h
    push Not at hh
    obtain ⟨i, hi⟩ := hh
    symm
    apply Finset.prod_eq_zero (s := Finset.univ)
    · exact Finset.mem_univ i
    · exact if_neg hi

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/GaussianDbarParseval.lean #
import GinibrePoincare.Analysis.HermiteParsevalModes
import GinibrePoincare.Analysis.HermiteEnergy
import GinibrePoincare.Analysis.ComplexGaussianIntegrationByParts
import GinibrePoincare.Analysis.GroundStateDbar
import GinibrePoincare.Analysis.GaussianPolynomialIntegrability
import GinibrePoincare.Analysis.MultivariateHermiteIntegrability
import GinibrePoincare.Analysis.HermiteWirtinger
import GinibrePoincare.Analysis.ComplexGaussianProductIntegral

/-! # Gaussian `∂̄` energy and Hermite modes -/

open MeasureTheory
open scoped BigOperators ENNReal ComplexConjugate

namespace GinibrePoincare

noncomputable section

open ComplexHermite

theorem complexGaussianDbarIntegrationByParts_of_integrable
    {n : ℕ} (hn : 0 < n) {F : ℂ → ℂ} (hF : ContDiff ℝ 1 F)
    (hFi : Integrable F (complexCoordinateGaussianProbability n : Measure ℂ))
    (hDr : Integrable (fun z ↦ (fderiv ℝ F z) (1 : ℂ))
      (complexCoordinateGaussianProbability n : Measure ℂ))
    (hDi : Integrable (fun z ↦ (fderiv ℝ F z) Complex.I)
      (complexCoordinateGaussianProbability n : Measure ℂ))
    (hX : Integrable (fun z ↦ (z.re : ℂ) * F z)
      (complexCoordinateGaussianProbability n : Measure ℂ))
    (hY : Integrable (fun z ↦ (z.im : ℂ) * F z)
      (complexCoordinateGaussianProbability n : Measure ℂ)) :
    (∫ z, dbarOnePublic F z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (n : ℂ) * ∫ z, z * F z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
  unfold dbarOnePublic
  rw [integral_const_mul, integral_add hDr (hDi.const_mul Complex.I),
    integral_const_mul,
    complexGaussianIntegrationByParts_real_of_integrable hn hF hFi hDr hX,
    complexGaussianIntegrationByParts_imag_of_integrable hn hF hFi hDi hY]
  have hz : (fun z : ℂ ↦ (z.re : ℂ) * F z +
      Complex.I * ((z.im : ℂ) * F z)) = fun z ↦ z * F z := by
    funext z
    apply Complex.ext <;> simp <;> ring
  have hint : (∫ z, z * F z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (∫ z, (z.re : ℂ) * F z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ)) +
      Complex.I * ∫ z, (z.im : ℂ) * F z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
    rw [← integral_const_mul, ← integral_add hX (hY.const_mul Complex.I), hz]
  rw [hint]
  push_cast
  ring

theorem complexGaussianDbarIntegrationByParts_diagonalEval
    {n : ℕ} (hn : 0 < n) (P : Poly) :
    (∫ z, dbarOnePublic (diagonalEvalPublic P) z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (n : ℂ) * ∫ z, z * diagonalEvalPublic P z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
  obtain ⟨R, hR⟩ := exists_fderiv_diagonalEvalPublic_polynomial P 1
  obtain ⟨S, hS⟩ := exists_fderiv_diagonalEvalPublic_polynomial P Complex.I
  have hz := integrable_mul_mvPolynomial_diagonalEval n P
  have hcz := integrable_conj_mul_mvPolynomial_diagonalEval n P
  apply complexGaussianDbarIntegrationByParts_of_integrable hn
    (contDiff_diagonalEvalPublic P)
    (integrable_mvPolynomial_diagonalEval n P)
  · exact (integrable_mvPolynomial_diagonalEval n R).congr
      (Filter.Eventually.of_forall fun z ↦ (hR z).symm)
  · exact (integrable_mvPolynomial_diagonalEval n S).congr
      (Filter.Eventually.of_forall fun z ↦ (hS z).symm)
  · apply ((hz.add hcz).const_mul (1 / 2 : ℂ)).congr
    filter_upwards with z
    simp only [diagonalEvalPublic]
    apply Complex.ext <;> simp <;> ring
  · apply ((hz.sub hcz).const_mul (1 / (2 * Complex.I) : ℂ)).congr
    filter_upwards with z
    simp only [diagonalEvalPublic]
    apply Complex.ext <;> simp <;> ring

theorem integrable_normalizedEval_complexGaussian (n : ℕ) (hn : 0 < n)
    (p q : ℕ) :
    Integrable (normalizedEval n hn p q)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  unfold normalizedEval normalized raw
  simp only [map_mul, map_sum, map_pow, MvPolynomial.eval_C,
    Finset.sum_apply]
  apply Integrable.const_mul
  apply integrable_finset_sum
  intro k hk
  simp only [Z, W, MvPolynomial.eval_X, Matrix.cons_val_zero,
    Matrix.cons_val_one]
  have hb := integrable_pow_mul_conj_pow_complexCoordinateGaussianProbability
    n (p - k) (q - k)
  let C : ℂ := ((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
    (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)
  refine (hb.const_mul C).congr ?_
  filter_upwards with z
  dsimp [C]
  push_cast
  ring_nf

theorem integrable_normalizedEval_lowering_complexGaussian
    (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    Integrable (fun z ↦ (Real.sqrt (n * q : ℕ) : ℂ) *
      normalizedEval n hn p (q - 1) z)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  exact (integrable_normalizedEval_complexGaussian n hn p (q - 1)).const_mul _

theorem integrable_coordinate_mul_normalizedEval_complexGaussian
    (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    Integrable (fun z : ℂ ↦ z * normalizedEval n hn p q z)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  have hprod := ComplexHermite.integrable_normalizedEval_mul n hn 1 0 p q
  have hsqrt : Real.sqrt n ≠ 0 := Real.sqrt_ne_zero'.mpr (by exact_mod_cast hn)
  have hsqrtC : (Real.sqrt n : ℂ) ≠ 0 := by exact_mod_cast hsqrt
  have hscaled := hprod.const_mul ((Real.sqrt n : ℂ)⁻¹)
  apply hscaled.congr
  filter_upwards with z
  rw [normalizedEval_zero_right]
  rw [show oneDimNormalization n 1 = Real.sqrt n by
    simp [oneDimNormalization]]
  simp only [pow_one]
  field_simp [hsqrtC]

private theorem mixedMomentFormula_of_pos (n : ℕ) (hn : 0 < n) :
    MixedMomentFormula n := by
  intro a b
  rw [show (∫ z : ℂ, z ^ a * conj z ^ b
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      complexGaussianMixedMoment n a b by rfl]
  rw [complexGaussianMixedMoment_formula hn]
  simp [div_eq_mul_inv]

theorem integral_normalizedEval_complexGaussian (n : ℕ) (hn : 0 < n)
    (p q : ℕ) :
    (∫ z : ℂ, normalizedEval n hn p q z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      if p = 0 ∧ q = 0 then 1 else 0 := by
  have horth := normalizedEval_orthogonal_of_mixedMoments n hn
    (mixedMomentFormula_of_pos n hn) 0 0 p q
  simpa [eq_comm] using horth

theorem sqrt_mul_integral_coordinate_mul_normalizedEval
    (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    (Real.sqrt n : ℂ) *
        (∫ z : ℂ, z * normalizedEval n hn p q z
          ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      if p = 0 ∧ q = 1 then 1 else 0 := by
  rw [← integral_const_mul]
  have horth := normalizedEval_orthogonal_of_mixedMoments n hn
    (mixedMomentFormula_of_pos n hn) 0 1 p q
  have horth' : (∫ z : ℂ, conj (normalizedEval n hn 0 1 z) *
      normalizedEval n hn p q z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      if p = 0 ∧ q = 1 then 1 else 0 := by simpa [eq_comm] using horth
  rw [← horth']
  apply integral_congr_ae
  filter_upwards with z
  rw [normalizedEval_zero_left]
  rw [show oneDimNormalization n 1 = Real.sqrt n by
    simp [oneDimNormalization]]
  simp [RCLike.conj_ofReal, mul_assoc]

/-- Specialized noncompact complex Gaussian `∂̄` integration by parts
for every normalized one-coordinate Hermite polynomial. -/
theorem complexGaussianDbarIntegrationByParts_normalizedEval
    (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    (∫ z : ℂ, dbarOnePublic (normalizedEval n hn p q) z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (n : ℂ) * ∫ z : ℂ, z * normalizedEval n hn p q z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
  rw [integral_congr_ae (Filter.Eventually.of_forall
    (dbarOne_normalizedEval_public n hn p q))]
  rw [integral_const_mul, integral_normalizedEval_complexGaussian]
  have hs : (Real.sqrt n : ℂ) ≠ 0 := by
    exact_mod_cast Real.sqrt_ne_zero'.mpr (by exact_mod_cast hn)
  apply mul_left_cancel₀ hs
  rw [show (Real.sqrt n : ℂ) * ((n : ℂ) *
      ∫ z : ℂ, z * normalizedEval n hn p q z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (n : ℂ) * ((Real.sqrt n : ℂ) *
        ∫ z : ℂ, z * normalizedEval n hn p q z
          ∂(complexCoordinateGaussianProbability n : Measure ℂ)) by ring,
    sqrt_mul_integral_coordinate_mul_normalizedEval n hn p q]
  by_cases hp : p = 0
  · subst p
    cases q with
    | zero => simp
    | succ q =>
      cases q with
      | zero =>
        simp
        have hsq : Real.sqrt n * Real.sqrt n = n := by
          rw [Real.mul_self_sqrt (by positivity)]
        exact_mod_cast hsq
      | succ q => simp
  · simp [hp]

theorem conj_normalizedEval_swap (n : ℕ) (hn : 0 < n) (p q : ℕ) (z : ℂ) :
    conj (normalizedEval n hn p q z) = normalizedEval n hn q p z := by
  unfold normalizedEval normalized raw
  simp only [map_mul, map_sum, map_pow, map_natCast,
    MvPolynomial.eval_C]
  rw [min_comm]
  rw [Finset.mul_sum, Finset.mul_sum]
  apply Finset.sum_congr rfl
  intro k hk
  simp [Z, W, oneDimNormalization, mul_comm, mul_left_comm, mul_assoc]

theorem integrable_normalizedEval_mul_conj_normalizedEval
    (n : ℕ) (hn : 0 < n) (r s p q : ℕ) :
    Integrable (fun z : ℂ ↦ normalizedEval n hn r s z *
      conj (normalizedEval n hn p q z))
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  rw [show (fun z : ℂ ↦ normalizedEval n hn r s z *
      conj (normalizedEval n hn p q z)) =
      fun z ↦ normalizedEval n hn r s z * normalizedEval n hn q p z by
    funext z
    rw [conj_normalizedEval_swap]]
  exact ComplexHermite.integrable_normalizedEval_mul n hn r s q p

theorem integrable_coordinate_mul_normalizedEval_mul_conj_normalizedEval
    (n : ℕ) (hn : 0 < n) (r s p q : ℕ) :
    Integrable (fun z : ℂ ↦ z * (normalizedEval n hn r s z *
      conj (normalizedEval n hn p q z)))
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  let P : MvPolynomial (Fin 2) ℂ :=
    MvPolynomial.X 0 * normalized n hn r s * normalized n hn q p
  have hP := integrable_mvPolynomial_diagonalEval n P
  apply hP.congr
  filter_upwards with z
  simp only [P, MvPolynomial.eval_mul, MvPolynomial.eval_X,
    MvPolynomial.eval_C]
  simp only [Matrix.cons_val_zero]
  change (z * normalizedEval n hn r s z) * normalizedEval n hn q p z = _
  rw [conj_normalizedEval_swap]
  ring

theorem complexGaussianDbarIntegrationByParts_normalizedEval_mul_conj
    (n : ℕ) (hn : 0 < n) (r s p q : ℕ) :
    (∫ z : ℂ, dbarOnePublic (fun w ↦ normalizedEval n hn r s w *
      conj (normalizedEval n hn p q w)) z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (n : ℂ) * ∫ z : ℂ, z * (normalizedEval n hn r s z *
        conj (normalizedEval n hn p q z))
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
  let P : Poly := normalized n hn r s * normalized n hn q p
  have hfun : (fun z : ℂ ↦ normalizedEval n hn r s z *
      conj (normalizedEval n hn p q z)) = diagonalEvalPublic P := by
    funext z
    rw [conj_normalizedEval_swap]
    simp [P, diagonalEvalPublic, normalizedEval, MvPolynomial.eval_mul]
  rw [hfun]
  rw [show (fun z : ℂ ↦ z * (normalizedEval n hn r s z *
      conj (normalizedEval n hn p q z))) =
      fun z ↦ z * diagonalEvalPublic P z by
    funext z
    rw [← congrFun hfun z]]
  exact complexGaussianDbarIntegrationByParts_diagonalEval hn P

theorem integral_normalizedEval_mul_conj_normalizedEval
    (n : ℕ) (hn : 0 < n) (r s p q : ℕ) :
    (∫ z : ℂ, normalizedEval n hn r s z *
      conj (normalizedEval n hn p q z)
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      if r = p ∧ s = q then 1 else 0 := by
  have h := normalizedEval_orthogonal_of_mixedMoments n hn
    (mixedMomentFormula_of_pos n hn) p q r s
  calc
    _ = ∫ z : ℂ, conj (normalizedEval n hn p q z) *
        normalizedEval n hn r s z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
          apply integral_congr_ae
          filter_upwards with z
          ring
    _ = if p = r ∧ q = s then 1 else 0 := h
    _ = if r = p ∧ s = q then 1 else 0 := by
      congr 1
      apply propext
      constructor <;> rintro ⟨h₁, h₂⟩ <;> exact ⟨h₁.symm, h₂.symm⟩

theorem dbarOnePublic_conj_normalizedEval
    (n : ℕ) (hn : 0 < n) (p q : ℕ) (z : ℂ) :
    dbarOnePublic (fun w ↦ conj (normalizedEval n hn p q w)) z =
      Real.sqrt (n * p : ℕ) * conj (normalizedEval n hn (p - 1) q z) := by
  rw [show (fun w ↦ conj (normalizedEval n hn p q w)) =
      normalizedEval n hn q p by funext w; exact conj_normalizedEval_swap n hn p q w]
  rw [dbarOne_normalizedEval_public]
  rw [conj_normalizedEval_swap]

theorem coordinate_normalizedEval_matrix_element
    (n : ℕ) (hn : 0 < n) (r s p q : ℕ) :
    (n : ℂ) * (∫ z : ℂ, z * (normalizedEval n hn r s z *
      conj (normalizedEval n hn p q z))
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (Real.sqrt (n * s : ℕ) : ℂ) *
          (if r = p ∧ s - 1 = q then 1 else 0) +
        (Real.sqrt (n * p : ℕ) : ℂ) *
          (if r = p - 1 ∧ s = q then 1 else 0) := by
  rw [← complexGaussianDbarIntegrationByParts_normalizedEval_mul_conj n hn r s p q]
  have hprod : (∫ z : ℂ, dbarOnePublic (fun w ↦
      normalizedEval n hn r s w * conj (normalizedEval n hn p q w)) z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      ∫ z : ℂ, dbarOnePublic (normalizedEval n hn r s) z *
          conj (normalizedEval n hn p q z) +
        normalizedEval n hn r s z *
          dbarOnePublic (fun w ↦ conj (normalizedEval n hn p q w)) z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
    apply integral_congr_ae
    filter_upwards with z
    exact dbarOnePublic_mul
      (differentiable_normalizedEval n hn r s)
      (Complex.differentiable_conj.comp
        (differentiable_normalizedEval n hn p q)) z
  rw [hprod]
  have hi1 : Integrable (fun z ↦ dbarOnePublic (normalizedEval n hn r s) z *
      conj (normalizedEval n hn p q z))
      (complexCoordinateGaussianProbability n : Measure ℂ) :=
    ((integrable_normalizedEval_mul_conj_normalizedEval n hn
      r (s - 1) p q).const_mul (Real.sqrt (n * s : ℕ) : ℂ)).congr
      (Filter.Eventually.of_forall fun z ↦ by
        change (Real.sqrt (n * s : ℕ) : ℂ) *
            (normalizedEval n hn r (s - 1) z *
              conj (normalizedEval n hn p q z)) =
          dbarOnePublic (normalizedEval n hn r s) z *
            conj (normalizedEval n hn p q z)
        rw [dbarOne_normalizedEval_public]
        ring)
  have hi2 : Integrable (fun z ↦ normalizedEval n hn r s z *
      dbarOnePublic (fun w ↦ conj (normalizedEval n hn p q w)) z)
      (complexCoordinateGaussianProbability n : Measure ℂ) :=
    ((integrable_normalizedEval_mul_conj_normalizedEval n hn
      r s (p - 1) q).const_mul (Real.sqrt (n * p : ℕ) : ℂ)).congr
      (Filter.Eventually.of_forall fun z ↦ by
        change (Real.sqrt (n * p : ℕ) : ℂ) *
            (normalizedEval n hn r s z *
              conj (normalizedEval n hn (p - 1) q z)) =
          normalizedEval n hn r s z *
            dbarOnePublic (fun w ↦ conj (normalizedEval n hn p q w)) z
        rw [dbarOnePublic_conj_normalizedEval]
        ring)
  rw [integral_add hi1 hi2]
  have hInt1 : (∫ z : ℂ, dbarOnePublic (normalizedEval n hn r s) z *
      conj (normalizedEval n hn p q z)
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (Real.sqrt (n * s : ℕ) : ℂ) *
        (if r = p ∧ s - 1 = q then 1 else 0) := by
    calc
      _ = ∫ z : ℂ, (Real.sqrt (n * s : ℕ) : ℂ) *
          (normalizedEval n hn r (s - 1) z *
            conj (normalizedEval n hn p q z))
          ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
            apply integral_congr_ae
            filter_upwards with z
            rw [dbarOne_normalizedEval_public, mul_assoc]
      _ = _ := by rw [integral_const_mul,
        integral_normalizedEval_mul_conj_normalizedEval]
  have hInt2 : (∫ z : ℂ, normalizedEval n hn r s z *
      dbarOnePublic (fun w ↦ conj (normalizedEval n hn p q w)) z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      (Real.sqrt (n * p : ℕ) : ℂ) *
        (if r = p - 1 ∧ s = q then 1 else 0) := by
    calc
      _ = ∫ z : ℂ, (Real.sqrt (n * p : ℕ) : ℂ) *
          (normalizedEval n hn r s z *
            conj (normalizedEval n hn (p - 1) q z))
          ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
            apply integral_congr_ae
            filter_upwards with z
            rw [dbarOnePublic_conj_normalizedEval, mul_left_comm]
      _ = _ := by rw [integral_const_mul,
        integral_normalizedEval_mul_conj_normalizedEval]
  rw [hInt1, hInt2]

theorem multivariate_coordinate_matrix_element_factorization
    (n : ℕ) (hn : 0 < n) (r s p q : Fin n → ℕ) (j : Fin n) :
    (∫ z : Configuration n, z j *
        (multivariateNormalized n hn r s z *
          conj (multivariateNormalized n hn p q z))
        ∂complexGaussianMeasure n) =
      (∫ z : ℂ, z * (normalizedEval n hn (r j) (s j) z *
          conj (normalizedEval n hn (p j) (q j) z))
          ∂(complexCoordinateGaussianProbability n : Measure ℂ)) *
        ∏ i ∈ Finset.univ.erase j,
          (∫ z : ℂ, normalizedEval n hn (r i) (s i) z *
            conj (normalizedEval n hn (p i) (q i) z)
            ∂(complexCoordinateGaussianProbability n : Measure ℂ)) := by
  unfold multivariateNormalized complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi, map_prod]
  let f : (i : Fin n) → ℂ → ℂ := fun i z ↦
    if i = j then z * (normalizedEval n hn (r i) (s i) z *
      conj (normalizedEval n hn (p i) (q i) z))
    else normalizedEval n hn (r i) (s i) z *
      conj (normalizedEval n hn (p i) (q i) z)
  have hfun : (fun z : Fin n → ℂ ↦ z j *
      ((∏ i, normalizedEval n hn (r i) (s i) (z i)) *
        (∏ i, conj (normalizedEval n hn (p i) (q i) (z i))))) =
      fun z ↦ ∏ i, f i (z i) := by
    funext z
    rw [← Finset.prod_mul_distrib]
    rw [Finset.prod_eq_mul_prod_diff_singleton j _ (by simp)]
    rw [show (∏ i, f i (z i)) = f j (z j) *
        ∏ i ∈ Finset.univ \ {j}, f i (z i) by
      exact Finset.prod_eq_mul_prod_diff_singleton j _ (by intro h; simp at h)]
    simp only [f, if_pos]
    ring_nf
    congr 1
    apply Finset.prod_congr rfl
    intro i hi
    have hij : i ≠ j := by
      have := (Finset.mem_sdiff.mp hi).2
      simpa using this
    simp [f, hij]
  rw [hfun, integral_fintype_prod_eq_prod]
  have hsplit := Finset.prod_eq_mul_prod_diff_singleton
    (s := Finset.univ)
    (f := fun i ↦ ∫ z : ℂ, f i z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ))
    j (by simp)
  rw [hsplit]
  simp only [f, if_pos]
  simp only [Finset.erase_eq]
  congr 1
  apply Finset.prod_congr rfl
  intro i hi
  have hij : i ≠ j := by
    have := (Finset.mem_sdiff.mp hi).2
    simpa using this
  simp [f, hij]

theorem multivariate_coordinate_matrix_element
    (n : ℕ) (hn : 0 < n) (r s p q : Fin n → ℕ) (j : Fin n) :
    (n : ℂ) * (∫ z : Configuration n, z j *
        (multivariateNormalized n hn r s z *
          conj (multivariateNormalized n hn p q z))
        ∂complexGaussianMeasure n) =
      ((Real.sqrt (n * s j : ℕ) : ℂ) *
          (if r j = p j ∧ s j - 1 = q j then 1 else 0) +
        (Real.sqrt (n * p j : ℕ) : ℂ) *
          (if r j = p j - 1 ∧ s j = q j then 1 else 0)) *
        ∏ i ∈ Finset.univ.erase j,
          (if r i = p i ∧ s i = q i then (1 : ℂ) else 0) := by
  rw [multivariate_coordinate_matrix_element_factorization n hn r s p q j]
  rw [show (n : ℂ) *
      ((∫ z : ℂ, z * (normalizedEval n hn (r j) (s j) z *
        conj (normalizedEval n hn (p j) (q j) z))
        ∂(complexCoordinateGaussianProbability n : Measure ℂ)) *
        ∏ i ∈ Finset.univ.erase j,
          (∫ z : ℂ, normalizedEval n hn (r i) (s i) z *
            conj (normalizedEval n hn (p i) (q i) z)
            ∂(complexCoordinateGaussianProbability n : Measure ℂ))) =
      ((n : ℂ) * ∫ z : ℂ, z *
        (normalizedEval n hn (r j) (s j) z *
          conj (normalizedEval n hn (p j) (q j) z))
        ∂(complexCoordinateGaussianProbability n : Measure ℂ)) *
        ∏ i ∈ Finset.univ.erase j,
          (∫ z : ℂ, normalizedEval n hn (r i) (s i) z *
            conj (normalizedEval n hn (p i) (q i) z)
            ∂(complexCoordinateGaussianProbability n : Measure ℂ)) by ring]
  rw [coordinate_normalizedEval_matrix_element]
  congr 1
  apply Finset.prod_congr rfl
  intro i hi
  exact integral_normalizedEval_mul_conj_normalizedEval n hn
    (r i) (s i) (p i) (q i)

theorem memLp_two_coordinate_mul_multivariateNormalized
    (n : ℕ) (hn : 0 < n) (p q : Fin n → ℕ) (j : Fin n) :
    MemLp (fun z : Configuration n ↦ z j *
      multivariateNormalized n hn p q z) 2 (complexGaussianMeasure n) := by
  apply (memLp_two_iff_integrable_sq_norm
    ((continuous_apply j).mul
      (continuous_multivariateNormalized n hn p q)).aestronglyMeasurable).mpr
  change Integrable (fun z : Configuration n ↦
    ‖z j * multivariateNormalized n hn p q z‖ ^ 2) (complexGaussianMeasure n)
  rw [show (fun z : Configuration n ↦
      ‖z j * multivariateNormalized n hn p q z‖ ^ 2) =
      fun z ↦ ∏ i, if i = j then
        Complex.normSq (z i * normalizedEval n hn (p i) (q i) (z i))
      else Complex.normSq (normalizedEval n hn (p i) (q i) (z i)) by
    funext z
    unfold multivariateNormalized
    rw [norm_mul, norm_prod, mul_pow, ← Finset.prod_pow]
    rw [show (∏ i, ‖normalizedEval n hn (p i) (q i) (z i)‖ ^ 2) =
        ‖normalizedEval n hn (p j) (q j) (z j)‖ ^ 2 *
          ∏ i ∈ Finset.univ \ {j},
            ‖normalizedEval n hn (p i) (q i) (z i)‖ ^ 2 by
      exact Finset.prod_eq_mul_prod_diff_singleton j _ (by simp)]
    rw [show (∏ i, if i = j then
        Complex.normSq (z i * normalizedEval n hn (p i) (q i) (z i))
      else Complex.normSq (normalizedEval n hn (p i) (q i) (z i))) =
        Complex.normSq (z j * normalizedEval n hn (p j) (q j) (z j)) *
          ∏ i ∈ Finset.univ \ {j},
            (if i = j then Complex.normSq
              (z i * normalizedEval n hn (p i) (q i) (z i))
            else Complex.normSq (normalizedEval n hn (p i) (q i) (z i))) by
      simpa using Finset.prod_eq_mul_prod_sdiff_singleton_of_mem
        (M := ℝ) (Finset.mem_univ j)
        (fun i : Fin n ↦ (if i = j then
          Complex.normSq (z i * normalizedEval n hn (p i) (q i) (z i))
        else Complex.normSq (normalizedEval n hn (p i) (q i) (z i))))]
    simp only [Complex.normSq_mul, Complex.sq_norm]
    ring_nf
    apply congrArg (fun w : ℝ ↦
      Complex.normSq (z j) *
        Complex.normSq (normalizedEval n hn (p j) (q j) (z j)) * w)
    apply Finset.prod_congr rfl
    intro i hi
    have hij : i ≠ j := by
      have := (Finset.mem_sdiff.mp hi).2
      simpa using this
    simp [hij, Complex.sq_norm]]
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  refine Integrable.fintype_prod (μ := fun _ : Fin n ↦
    (complexCoordinateGaussianProbability n : Measure ℂ))
    (f := fun i w ↦ if i = j then Complex.normSq
      (w * normalizedEval n hn (p i) (q i) w)
    else Complex.normSq (normalizedEval n hn (p i) (q i) w)) ?_
  intro i
  by_cases hij : i = j
  · subst i
    simp only [if_pos]
    let P : Poly := MvPolynomial.X 0 * MvPolynomial.X 1 *
      normalized n hn (p j) (q j) * normalized n hn (q j) (p j)
    exact (integrable_mvPolynomial_diagonalEval n P).re.congr
      (Filter.Eventually.of_forall fun z ↦ by
        change (MvPolynomial.eval ![z, conj z] P).re =
          Complex.normSq (z * normalizedEval n hn (p j) (q j) z)
        have hz : MvPolynomial.eval ![z, conj z] P =
            (Complex.normSq (z * normalizedEval n hn (p j) (q j) z) : ℂ) := by
          rw [Complex.normSq_eq_conj_mul_self]
          simp only [P, MvPolynomial.eval_mul, MvPolynomial.eval_X,
            Matrix.cons_val_zero, Matrix.cons_val_one, map_mul]
          rw [conj_normalizedEval_swap]
          change z * conj z * normalizedEval n hn (p j) (q j) z *
            normalizedEval n hn (q j) (p j) z = _
          ring
        rw [hz]
        simp)
  · simp only [if_neg hij]
    exact ComplexHermite.integrable_normSq_normalizedEval n hn (p i) (q i)

def coordinateMulMultivariateNormalizedL2
    (n : ℕ) (hn : 0 < n) (p q : Fin n → ℕ) (j : Fin n) :
    Lp ℂ 2 (complexGaussianMeasure n) :=
  (memLp_two_coordinate_mul_multivariateNormalized n hn p q j).toLp
    (fun z ↦ z j * multivariateNormalized n hn p q z)

theorem coordinateMulMultivariateNormalizedL2_coeFn
    (n : ℕ) (hn : 0 < n) (p q : Fin n → ℕ) (j : Fin n) :
    coordinateMulMultivariateNormalizedL2 n hn p q j =ᵐ[complexGaussianMeasure n]
      fun z ↦ z j * multivariateNormalized n hn p q z :=
  MemLp.coeFn_toLp (memLp_two_coordinate_mul_multivariateNormalized n hn p q j)

theorem gaussianHermiteCoefficient_coordinateMulMultivariateNormalizedL2
    (n : ℕ) (hn : 0 < n) (r s p q : Fin n → ℕ) (j : Fin n) :
    (n : ℂ) * gaussianHermiteCoefficient hn
        (coordinateMulMultivariateNormalizedL2 n hn r s j) (p, q) =
      ((Real.sqrt (n * s j : ℕ) : ℂ) *
          (if r j = p j ∧ s j - 1 = q j then 1 else 0) +
        (Real.sqrt (n * p j : ℕ) : ℂ) *
          (if r j = p j - 1 ∧ s j = q j then 1 else 0)) *
        ∏ i ∈ Finset.univ.erase j,
          (if r i = p i ∧ s i = q i then (1 : ℂ) else 0) := by
  rw [gaussianHermiteCoefficient_eq_inner]
  have hi : inner ℂ (multivariateNormalizedL2 n hn p q)
      (coordinateMulMultivariateNormalizedL2 n hn r s j) =
      ∫ z : Configuration n, z j *
        (multivariateNormalized n hn r s z *
          conj (multivariateNormalized n hn p q z))
        ∂complexGaussianMeasure n := by
    rw [MeasureTheory.L2.inner_def]
    apply integral_congr_ae
    filter_upwards [multivariateNormalizedL2_coeFn n hn p q,
      coordinateMulMultivariateNormalizedL2_coeFn n hn r s j] with z hp hz
    rw [RCLike.inner_apply, hp, hz]
    ring
  rw [hi]
  exact multivariate_coordinate_matrix_element n hn r s p q j

private theorem eq_iff_eq_at_and_eq_off {n : ℕ} (a b : Fin n → ℕ)
    (j : Fin n) :
    a = b ↔ a j = b j ∧ ∀ i ∈ Finset.univ.erase j, a i = b i := by
  constructor
  · rintro rfl
    exact ⟨rfl, fun _ _ ↦ rfl⟩
  · rintro ⟨hj, hoff⟩
    funext i
    by_cases hij : i = j
    · simpa [hij] using hj
    · exact hoff i (by simp [hij])

private theorem lower_local_off_iff {n : ℕ} (r s p q : Fin n → ℕ)
    (j : Fin n) (hs : 0 < s j) :
    ((r j = p j ∧ s j - 1 = q j) ∧
        ∀ i ∈ Finset.univ.erase j, r i = p i ∧ s i = q i) ↔
      (p, q) = (r, lowerAt s j) := by
  rw [Prod.ext_iff]
  constructor
  · rintro ⟨hlocal, hoff⟩
    constructor
    · rw [eq_iff_eq_at_and_eq_off]
      exact ⟨hlocal.1.symm, fun i hi ↦ (hoff i hi).1.symm⟩
    · rw [eq_iff_eq_at_and_eq_off]
      constructor
      · change q j = lowerAt s j j
        simpa [lowerAt] using hlocal.2.symm
      · intro i hi
        have hij : i ≠ j := Finset.ne_of_mem_erase hi
        simpa [lowerAt, Function.update_of_ne hij] using (hoff i hi).2.symm
  · rintro ⟨hp, hq⟩
    constructor
    · constructor
      · exact (congrFun hp j).symm
      · simpa [lowerAt] using (congrFun hq j).symm
    · intro i hi
      have hij : i ≠ j := Finset.ne_of_mem_erase hi
      exact ⟨(congrFun hp i).symm,
        by simpa [lowerAt, Function.update_of_ne hij] using (congrFun hq i).symm⟩

private theorem raise_local_off_iff {n : ℕ} (r s p q : Fin n → ℕ)
    (j : Fin n) (hpj : 0 < p j) :
    ((r j = p j - 1 ∧ s j = q j) ∧
        ∀ i ∈ Finset.univ.erase j, r i = p i ∧ s i = q i) ↔
      (p, q) = (raiseAt r j, s) := by
  rw [Prod.ext_iff]
  constructor
  · rintro ⟨hlocal, hoff⟩
    have hpjr : p j = r j + 1 := by omega
    constructor
    · rw [eq_iff_eq_at_and_eq_off]
      constructor
      · change p j = raiseAt r j j
        simpa [raiseAt] using hpjr
      · intro i hi
        have hij : i ≠ j := Finset.ne_of_mem_erase hi
        simpa [raiseAt, Function.update_of_ne hij] using (hoff i hi).1.symm
    · rw [eq_iff_eq_at_and_eq_off]
      exact ⟨hlocal.2.symm, fun i hi ↦ (hoff i hi).2.symm⟩
  · rintro ⟨hp, hq⟩
    constructor
    · constructor
      · have hj := congrFun hp j
        simp [raiseAt] at hj
        omega
      · exact (congrFun hq j).symm
    · intro i hi
      have hij : i ≠ j := Finset.ne_of_mem_erase hi
      exact ⟨by simpa [raiseAt, Function.update_of_ne hij] using (congrFun hp i).symm,
        (congrFun hq i).symm⟩

private theorem prod_indicator_eq_ite {α : Type*} [DecidableEq α]
    (t : Finset α) (P : α → Prop) [DecidablePred P] :
    (∏ i ∈ t, (if P i then (1 : ℂ) else 0)) =
      if ∀ i ∈ t, P i then 1 else 0 := by
  classical
  induction t using Finset.induction_on with
  | empty => simp
  | @insert a t hat ih =>
      simp only [Finset.prod_insert hat, ih, Finset.mem_insert]
      by_cases ha : P a <;> by_cases ht : ∀ i ∈ t, P i <;> simp [ha, ht]

private theorem lower_scalar_indicator {n : ℕ} (r s p q : Fin n → ℕ)
    (j : Fin n) :
    (Real.sqrt (n * s j : ℕ) : ℂ) *
        (if r j = p j ∧ s j - 1 = q j then 1 else 0) *
        ∏ i ∈ Finset.univ.erase j,
          (if r i = p i ∧ s i = q i then (1 : ℂ) else 0) =
      (Real.sqrt (n * s j : ℕ) : ℂ) *
        (if (p, q) = (r, lowerAt s j) then 1 else 0) := by
  classical
  rw [prod_indicator_eq_ite]
  by_cases hs : s j = 0
  · simp [hs]
  · have hspos := Nat.pos_of_ne_zero hs
    let A := r j = p j ∧ s j - 1 = q j
    let O := ∀ i ∈ Finset.univ.erase j, r i = p i ∧ s i = q i
    have hiff := lower_local_off_iff r s p q j hspos
    by_cases hpair : (p, q) = (r, lowerAt s j)
    · have hAO := hiff.mpr hpair
      rw [if_pos hpair, if_pos hAO.1, if_pos hAO.2]
      ring
    · have hnAO : ¬(A ∧ O) := by
        intro h
        exact hpair (hiff.mp h)
      rw [if_neg hpair]
      by_cases hA : A
      · by_cases hO : O
        · exact (hnAO ⟨hA, hO⟩).elim
        · change ¬∀ i ∈ Finset.univ.erase j,
              r i = p i ∧ s i = q i at hO
          rw [if_pos hA, if_neg hO]
          simp
      · change ¬(r j = p j ∧ s j - 1 = q j) at hA
        rw [if_neg hA]
        simp

private theorem raise_scalar_indicator {n : ℕ} (r s p q : Fin n → ℕ)
    (j : Fin n) :
    (Real.sqrt (n * p j : ℕ) : ℂ) *
        (if r j = p j - 1 ∧ s j = q j then 1 else 0) *
        ∏ i ∈ Finset.univ.erase j,
          (if r i = p i ∧ s i = q i then (1 : ℂ) else 0) =
      (Real.sqrt (n * (r j + 1) : ℕ) : ℂ) *
        (if (p, q) = (raiseAt r j, s) then 1 else 0) := by
  classical
  rw [prod_indicator_eq_ite]
  by_cases hp : p j = 0
  · have hne : (p, q) ≠ (raiseAt r j, s) := by
      intro h
      have hj := congrFun (congrArg Prod.fst h) j
      simp [raiseAt, hp] at hj
    simp [hp, hne]
  · have hppos := Nat.pos_of_ne_zero hp
    let B := r j = p j - 1 ∧ s j = q j
    let O := ∀ i ∈ Finset.univ.erase j, r i = p i ∧ s i = q i
    have hiff := raise_local_off_iff r s p q j hppos
    by_cases hpair : (p, q) = (raiseAt r j, s)
    · have hBO := hiff.mpr hpair
      have heq : p j = r j + 1 := by
        change (r j = p j - 1 ∧ s j = q j) ∧ _ at hBO
        omega
      rw [if_pos hpair, if_pos hBO.1, if_pos hBO.2, heq]
      ring
    · have hnBO : ¬(B ∧ O) := by
        intro h
        exact hpair (hiff.mp h)
      rw [if_neg hpair]
      by_cases hB : B
      · by_cases hO : O
        · exact (hnBO ⟨hB, hO⟩).elim
        · change ¬∀ i ∈ Finset.univ.erase j,
              r i = p i ∧ s i = q i at hO
          rw [if_pos hB, if_neg hO]
          simp
      · change ¬(r j = p j - 1 ∧ s j = q j) at hB
        rw [if_neg hB]
        simp

theorem gaussianHermiteCoefficient_coordinateMul_creation_form
    (n : ℕ) (hn : 0 < n) (r s p q : Fin n → ℕ) (j : Fin n) :
    (n : ℂ) * gaussianHermiteCoefficient hn
        (coordinateMulMultivariateNormalizedL2 n hn r s j) (p, q) =
      (Real.sqrt (n * s j : ℕ) : ℂ) *
          (if (p, q) = (r, lowerAt s j) then 1 else 0) +
        (Real.sqrt (n * (r j + 1) : ℕ) : ℂ) *
          (if (p, q) = (raiseAt r j, s) then 1 else 0) := by
  rw [gaussianHermiteCoefficient_coordinateMulMultivariateNormalizedL2]
  rw [add_mul, lower_scalar_indicator, raise_scalar_indicator]

theorem coordinateMulMultivariateNormalizedL2_creation
    (n : ℕ) (hn : 0 < n) (r s : Fin n → ℕ) (j : Fin n) :
    (n : ℂ) • coordinateMulMultivariateNormalizedL2 n hn r s j =
      (Real.sqrt (n * s j : ℕ) : ℂ) •
          multivariateNormalizedL2 n hn r (lowerAt s j) +
        (Real.sqrt (n * (r j + 1) : ℕ) : ℂ) •
          multivariateNormalizedL2 n hn (raiseAt r j) s := by
  apply (gaussianHermiteHilbertBasis n hn).repr.injective
  ext pq
  change gaussianHermiteCoefficient hn
      ((n : ℂ) • coordinateMulMultivariateNormalizedL2 n hn r s j) pq =
    gaussianHermiteCoefficient hn
      ((Real.sqrt (n * s j : ℕ) : ℂ) •
          multivariateNormalizedL2 n hn r (lowerAt s j) +
        (Real.sqrt (n * (r j + 1) : ℕ) : ℂ) •
          multivariateNormalizedL2 n hn (raiseAt r j) s) pq
  simp only [gaussianHermiteCoefficient, map_smul, map_add,
    Pi.smul_apply, Pi.add_apply]
  change (n : ℂ) * gaussianHermiteCoefficient hn
      (coordinateMulMultivariateNormalizedL2 n hn r s j) pq = _
  rw [gaussianHermiteCoefficient_coordinateMul_creation_form]
  change _ = (Real.sqrt (n * s j : ℕ) : ℂ) *
      (gaussianHermiteHilbertBasis n hn).repr
        (multivariateNormalizedL2 n hn r (lowerAt s j)) pq +
    (Real.sqrt (n * (r j + 1) : ℕ) : ℂ) *
      (gaussianHermiteHilbertBasis n hn).repr
        (multivariateNormalizedL2 n hn (raiseAt r j) s) pq
  have h₁ : (gaussianHermiteHilbertBasis n hn).repr
      (multivariateNormalizedL2 n hn r (lowerAt s j)) pq =
        if pq = (r, lowerAt s j) then 1 else 0 := by
    rw [← gaussianHermiteCoefficient, gaussianHermiteCoefficient_eq_inner]
    simpa [multivariateNormalizedL2, hermiteL2Family] using
      inner_hermiteL2Family n hn (mixedMomentFormula_of_pos n hn) pq
        (r, lowerAt s j)
  have h₂ : (gaussianHermiteHilbertBasis n hn).repr
      (multivariateNormalizedL2 n hn (raiseAt r j) s) pq =
        if pq = (raiseAt r j, s) then 1 else 0 := by
    rw [← gaussianHermiteCoefficient, gaussianHermiteCoefficient_eq_inner]
    simpa [multivariateNormalizedL2, hermiteL2Family] using
      inner_hermiteL2Family n hn (mixedMomentFormula_of_pos n hn) pq
        (raiseAt r j, s)
  rw [h₁, h₂]

theorem coordinate_mul_multivariateNormalized_creation_ae
    (n : ℕ) (hn : 0 < n) (r s : Fin n → ℕ) (j : Fin n) :
    (fun z : Configuration n ↦ (n : ℂ) * z j *
        multivariateNormalized n hn r s z) =ᵐ[complexGaussianMeasure n]
      fun z ↦ (Real.sqrt (n * s j : ℕ) : ℂ) *
          multivariateNormalized n hn r (lowerAt s j) z +
        (Real.sqrt (n * (r j + 1) : ℕ) : ℂ) *
          multivariateNormalized n hn (raiseAt r j) s z := by
  have hv := coordinateMulMultivariateNormalizedL2_creation n hn r s j
  have hvfun := congrArg
    (fun x : Lp ℂ 2 (complexGaussianMeasure n) ↦
      (x : Configuration n → ℂ)) hv
  have hve : ∀ᵐ z ∂complexGaussianMeasure n,
      ((↑((n : ℂ) • coordinateMulMultivariateNormalizedL2 n hn r s j) :
          Configuration n → ℂ) z) =
        ((↑((Real.sqrt (n * s j : ℕ) : ℂ) •
            multivariateNormalizedL2 n hn r (lowerAt s j) +
          (Real.sqrt (n * (r j + 1) : ℕ) : ℂ) •
            multivariateNormalizedL2 n hn (raiseAt r j) s) :
              Configuration n → ℂ) z) :=
    Filter.Eventually.of_forall fun z ↦ congrFun hvfun z
  filter_upwards [hve,
    MeasureTheory.Lp.coeFn_smul (n : ℂ)
      (coordinateMulMultivariateNormalizedL2 n hn r s j),
    MeasureTheory.Lp.coeFn_add
      ((Real.sqrt (n * s j : ℕ) : ℂ) •
        multivariateNormalizedL2 n hn r (lowerAt s j))
      ((Real.sqrt (n * (r j + 1) : ℕ) : ℂ) •
        multivariateNormalizedL2 n hn (raiseAt r j) s),
    MeasureTheory.Lp.coeFn_smul (Real.sqrt (n * s j : ℕ) : ℂ)
      (multivariateNormalizedL2 n hn r (lowerAt s j)),
    MeasureTheory.Lp.coeFn_smul (Real.sqrt (n * (r j + 1) : ℕ) : ℂ)
      (multivariateNormalizedL2 n hn (raiseAt r j) s),
    coordinateMulMultivariateNormalizedL2_coeFn n hn r s j,
    multivariateNormalizedL2_coeFn n hn r (lowerAt s j),
    multivariateNormalizedL2_coeFn n hn (raiseAt r j) s] with
      z hz hns hadd hslo hsra hcoord hlo hra
  calc
    (n : ℂ) * z j * multivariateNormalized n hn r s z =
        ((n : ℂ) • (coordinateMulMultivariateNormalizedL2 n hn r s j :
          Configuration n → ℂ)) z := by
      rw [Pi.smul_apply, hcoord]
      simp only [smul_eq_mul, mul_assoc]
    _ = ((↑((n : ℂ) • coordinateMulMultivariateNormalizedL2 n hn r s j) :
          Configuration n → ℂ) z) := hns.symm
    _ = _ := hz
    _ = ((↑((Real.sqrt (n * s j : ℕ) : ℂ) •
          multivariateNormalizedL2 n hn r (lowerAt s j)) :
            Configuration n → ℂ) +
        ↑((Real.sqrt (n * (r j + 1) : ℕ) : ℂ) •
          multivariateNormalizedL2 n hn (raiseAt r j) s)) z := hadd
    _ = _ := by rw [Pi.add_apply, hslo, hsra, Pi.smul_apply,
      Pi.smul_apply, hlo, hra]; rfl

theorem contDiff_normalizedEval_real (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    ContDiff ℝ 1 (normalizedEval n hn p q) := by
  unfold normalizedEval normalized raw
  simp only [map_mul, map_sum, map_pow, MvPolynomial.eval_C,
    Finset.sum_apply, Z, W, MvPolynomial.eval_X, Matrix.cons_val_zero,
    Matrix.cons_val_one]
  have hsum : ContDiff ℝ 1 (fun z : ℂ ↦
      ∑ k ∈ Finset.range (min p q + 1),
        ((-((n : ℝ)⁻¹) : ℂ) ^ k) * (k.factorial : ℂ) *
          (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ) *
          z ^ (p - k) * conj z ^ (q - k)) := by
    apply ContDiff.sum
    intro k hk
    exact ((contDiff_const.mul (contDiff_id.pow (p - k))).mul
      ((ContinuousLinearEquiv.contDiff Complex.conjCLE).pow (q - k)))
  exact (show ContDiff ℝ 1 (fun _ : ℂ ↦
      ((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ)) from
    contDiff_const).mul hsum

theorem contDiff_multivariateNormalized_real (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) :
    ContDiff ℝ 1 (multivariateNormalized n hn p q) := by
  unfold multivariateNormalized
  let f : Fin n → Configuration n → ℂ :=
    fun i z ↦ normalizedEval n hn (p i) (q i) (z i)
  have hf : ∀ i, ContDiff ℝ 1 (f i) := fun i ↦
    (contDiff_normalizedEval_real n hn (p i) (q i)).comp
      (ContinuousLinearMap.proj i : Configuration n →L[ℝ] ℂ).contDiff
  change ContDiff ℝ 1 (fun z ↦ ∏ i ∈ Finset.univ, f i z)
  induction (Finset.univ : Finset (Fin n)) using Finset.induction_on with
  | empty => simpa using (contDiff_const : ContDiff ℝ 1 (fun _ : Configuration n ↦ (1 : ℂ)))
  | @insert i t hit ih =>
      simpa only [Finset.prod_insert hit] using (hf i).mul ih

theorem C_mul_Z_pow_mul_W_pow_eq_monomial (c : ℂ) (a b : ℕ) :
    MvPolynomial.C c * Z ^ a * W ^ b =
      MvPolynomial.monomial
        (Finsupp.single 0 a + Finsupp.single 1 b) c := by
  rw [show MvPolynomial.C c * Z ^ a =
      MvPolynomial.monomial (Finsupp.single 0 a) c by
    exact MvPolynomial.C_mul_X_pow_eq_monomial]
  rw [show W ^ b = MvPolynomial.monomial (Finsupp.single 1 b) 1 by
    exact MvPolynomial.X_pow_eq_monomial]
  rw [MvPolynomial.monomial_mul, mul_one]

theorem coeff_raw (ρ : ℝ) (p q : ℕ) (d : ComplexHermiteIndex →₀ ℕ) :
    MvPolynomial.coeff d (raw ρ p q) =
      ∑ k ∈ Finset.range (min p q + 1),
        if d = Finsupp.single 0 (p - k) + Finsupp.single 1 (q - k) then
          ((-(ρ : ℂ)) ^ k) * (k.factorial : ℂ) *
            (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ) else 0 := by
  unfold raw
  simp_rw [show ∀ k : ℕ,
      MvPolynomial.C (((-(ρ : ℂ)) ^ k) * (k.factorial : ℂ) *
        (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
        Z ^ (p - k) * W ^ (q - k) =
      MvPolynomial.monomial
        (Finsupp.single 0 (p - k) + Finsupp.single 1 (q - k))
        (((-(ρ : ℂ)) ^ k) * (k.factorial : ℂ) *
          (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) by
    intro k
    exact C_mul_Z_pow_mul_W_pow_eq_monomial _ _ _]
  simp [MvPolynomial.coeff_sum, eq_comm]

theorem hermiteExponent_injective_of_le {p q k l : ℕ}
    (hk : k ≤ p) (hl : l ≤ p)
    (h : Finsupp.single (0 : ComplexHermiteIndex) (p - k) +
        Finsupp.single 1 (q - k) =
      Finsupp.single 0 (p - l) + Finsupp.single 1 (q - l)) :
    k = l := by
  have h0 := congrArg (fun d : ComplexHermiteIndex →₀ ℕ ↦ d 0) h
  have hsub : p - k = p - l := by
    simpa [Finsupp.single_apply] using h0
  omega

theorem hermiteExponent_injective_on_range {p q k l : ℕ}
    (hk : k ∈ Finset.range (min p q + 1))
    (hl : l ∈ Finset.range (min p q + 1))
    (h : Finsupp.single (0 : ComplexHermiteIndex) (p - k) +
        Finsupp.single 1 (q - k) =
      Finsupp.single 0 (p - l) + Finsupp.single 1 (q - l)) :
    k = l := by
  apply hermiteExponent_injective_of_le
  · exact (Nat.le_of_lt_succ (Finset.mem_range.mp hk)).trans (min_le_left p q)
  · exact (Nat.le_of_lt_succ (Finset.mem_range.mp hl)).trans (min_le_left p q)
  · exact h

theorem coeff_raw_eq_of_exponent {ρ : ℝ} {p q k : ℕ}
    (hk : k ∈ Finset.range (min p q + 1)) :
    MvPolynomial.coeff
        (Finsupp.single 0 (p - k) + Finsupp.single 1 (q - k))
        (raw ρ p q) =
      ((-(ρ : ℂ)) ^ k) * (k.factorial : ℂ) *
        (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ) := by
  rw [coeff_raw]
  rw [Finset.sum_eq_single k]
  · simp
  · intro l hl hlk
    simp only [ite_eq_right_iff]
    intro he
    exact (hlk (hermiteExponent_injective_on_range hl hk he.symm)).elim
  · exact fun hkn => (hkn hk).elim

theorem coeff_raw_eq_zero_of_no_exponent {ρ : ℝ} {p q : ℕ}
    {d : ComplexHermiteIndex →₀ ℕ}
    (hd : ∀ k ∈ Finset.range (min p q + 1),
      d ≠ Finsupp.single 0 (p - k) + Finsupp.single 1 (q - k)) :
    MvPolynomial.coeff d (raw ρ p q) = 0 := by
  rw [coeff_raw]
  apply Finset.sum_eq_zero
  intro k hk
  split_ifs with h
  · exact (hd k hk h).elim
  · rfl

theorem raw_creation_scalar_identity (ρ : ℝ) (p q l : ℕ) :
    ((-(ρ : ℂ)) ^ (l + 1)) * ((l + 1).factorial : ℂ) *
          (Nat.choose (p + 1) (l + 1) : ℂ) * (Nat.choose q (l + 1) : ℂ) +
      (ρ : ℂ) * (q : ℂ) *
        (((-(ρ : ℂ)) ^ l) * (l.factorial : ℂ) *
          (Nat.choose p l : ℂ) * (Nat.choose (q - 1) l : ℂ)) =
    ((-(ρ : ℂ)) ^ (l + 1)) * ((l + 1).factorial : ℂ) *
      (Nat.choose p (l + 1) : ℂ) * (Nat.choose q (l + 1) : ℂ) := by
  cases q with
  | zero => simp
  | succ q =>
      rw [Nat.succ_sub_one, Nat.choose_succ_succ, Nat.factorial_succ]
      have hchooseNat := Nat.add_one_mul_choose_eq q l
      have hchoose : ((q + 1 : ℕ) : ℂ) * (Nat.choose q l : ℂ) =
          (Nat.choose (q + 1) (l + 1) : ℂ) * ((l + 1 : ℕ) : ℂ) := by
        exact_mod_cast hchooseNat
      push_cast
      simp only [Nat.succ_eq_add_one]
      rw [pow_succ]
      ring_nf
      push_cast at hchoose
      ring_nf at hchoose
      linear_combination
        ((ρ : ℂ) * (ρ : ℂ) ^ l * (l.factorial : ℂ) *
          (Nat.choose p l : ℂ) * (-1 : ℂ) ^ l) * hchoose

theorem conj_multivariateNormalized_swap (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) (z : Configuration n) :
    conj (multivariateNormalized n hn p q z) =
      multivariateNormalized n hn q p z := by
  unfold multivariateNormalized
  rw [map_prod]
  apply Finset.prod_congr rfl
  intro i _
  exact conj_normalizedEval_swap n hn (p i) (q i) (z i)

theorem dbarComponent_conj_multivariateNormalized (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) (j : Fin n) (z : Configuration n) :
    dbarComponent (fun w ↦ conj (multivariateNormalized n hn p q w)) j z =
      Real.sqrt (n * p j : ℕ) *
        multivariateNormalized n hn q (lowerAt p j) z := by
  rw [show (fun w ↦ conj (multivariateNormalized n hn p q w)) =
      multivariateNormalized n hn q p by
    funext w
    exact conj_multivariateNormalized_swap n hn p q w]
  exact dbarComponent_multivariateNormalized n hn q p j z

theorem continuous_dbarComponent {n : ℕ} {F : Configuration n → ℂ}
    (hF : ContDiff ℝ 1 F) (j : Fin n) :
    Continuous (dbarComponent F j) := by
  unfold dbarComponent
  exact continuous_const.mul
    (((hF.continuous_fderiv (by norm_num)).clm_apply continuous_const).add
      (continuous_const.mul
        ((hF.continuous_fderiv (by norm_num)).clm_apply continuous_const)))

theorem hasCompactSupport_dbarComponent {n : ℕ} {F : Configuration n → ℂ}
    (hFc : HasCompactSupport F) (j : Fin n) :
    HasCompactSupport (dbarComponent F j) := by
  unfold dbarComponent
  exact ((hFc.fderiv_apply ℝ (realCoordinateDirection j)).add
    ((hFc.fderiv_apply ℝ (imaginaryCoordinateDirection j)).mul_left)).mul_left

theorem memLp_dbarComponent {n : ℕ} {F : Configuration n → ℂ}
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) (j : Fin n) :
    MemLp (dbarComponent F j) 2 (complexGaussianMeasure n) :=
  (continuous_dbarComponent hF j).memLp_of_hasCompactSupport
    (hasCompactSupport_dbarComponent hFc j)

/-- The Gaussian `L²` vector represented by a compactly supported smooth
coordinate `∂̄` derivative. -/
def smoothDbarComponentL2 {n : ℕ} (F : Configuration n → ℂ)
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) (j : Fin n) :
    Lp ℂ 2 (complexGaussianMeasure n) :=
  (memLp_dbarComponent hF hFc j).toLp (dbarComponent F j)

theorem smoothDbarComponentL2_coeFn {n : ℕ} (F : Configuration n → ℂ)
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) (j : Fin n) :
    smoothDbarComponentL2 F hF hFc j =ᵐ[complexGaussianMeasure n]
      dbarComponent F j :=
  MemLp.coeFn_toLp (memLp_dbarComponent hF hFc j)

/-- A compactly supported smooth function, regarded as a Gaussian `L²`
vector. -/
def smoothCompactL2 {n : ℕ} (F : Configuration n → ℂ)
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    Lp ℂ 2 (complexGaussianMeasure n) :=
  hF.continuous.memLp_of_hasCompactSupport hFc |>.toLp F

theorem smoothCompactL2_coeFn {n : ℕ} (F : Configuration n → ℂ)
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    smoothCompactL2 F hF hFc =ᵐ[complexGaussianMeasure n] F :=
  MemLp.coeFn_toLp (hF.continuous.memLp_of_hasCompactSupport hFc)

theorem gaussianHermiteCoefficient_smoothCompactL2_eq_integral
    {n : ℕ} (hn : 0 < n) (F : Configuration n → ℂ)
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F)
    (pq : HermiteMultiIndex n) :
    gaussianHermiteCoefficient hn (smoothCompactL2 F hF hFc) pq =
      ∫ z, conj (multivariateNormalized n hn pq.1 pq.2 z) * F z
        ∂complexGaussianMeasure n := by
  rw [gaussianHermiteCoefficient_eq_inner, MeasureTheory.L2.inner_def]
  apply integral_congr_ae
  filter_upwards [multivariateNormalizedL2_coeFn n hn pq.1 pq.2,
    smoothCompactL2_coeFn F hF hFc] with z hH hG
  rw [RCLike.inner_apply, hH, hG]
  ring

theorem gaussianHermiteCoefficient_smoothDbarComponentL2_eq_integral
    {n : ℕ} (hn : 0 < n) (F : Configuration n → ℂ)
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) (j : Fin n)
    (pq : HermiteMultiIndex n) :
    gaussianHermiteCoefficient hn (smoothDbarComponentL2 F hF hFc j) pq =
      ∫ z, conj (multivariateNormalized n hn pq.1 pq.2 z) *
        dbarComponent F j z ∂complexGaussianMeasure n := by
  rw [gaussianHermiteCoefficient_eq_inner, MeasureTheory.L2.inner_def]
  apply integral_congr_ae
  filter_upwards [multivariateNormalizedL2_coeFn n hn pq.1 pq.2,
    smoothDbarComponentL2_coeFn F hF hFc j] with z hH hD
  rw [RCLike.inner_apply, hH, hD]
  ring

/-- Gaussian integration by parts realizes `∂̄` as the Hermite lowering
operator on every compactly supported smooth function. -/
theorem gaussianHermiteCoefficient_smoothDbarComponentL2_raise
    {n : ℕ} (hn : 0 < n) (F : Configuration n → ℂ)
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) (j : Fin n)
    (pq : HermiteMultiIndex n) :
    gaussianHermiteCoefficient hn (smoothDbarComponentL2 F hF hFc j) pq =
      (Real.sqrt (n * (pq.2 j + 1) : ℕ) : ℂ) *
        gaussianHermiteCoefficient hn (smoothCompactL2 F hF hFc)
          (raiseHermiteIndex j pq) := by
  let H : Configuration n → ℂ :=
    fun z => multivariateNormalized n hn pq.1 pq.2 z
  have hH : ContDiff ℝ 1 H := contDiff_multivariateNormalized_real n hn _ _
  have hconjH : ContDiff ℝ 1 (fun z => conj (H z)) :=
    Complex.conjCLE.contDiff.comp hH
  have hprod : ContDiff ℝ 1 (fun z => F z * conj (H z)) := hF.mul hconjH
  have hcprod : HasCompactSupport (fun z => F z * conj (H z)) := hFc.mul_right
  have hibp := configurationGaussianDbarIntegrationByParts hn j hprod hcprod
  have hiD : Integrable (fun z => conj (H z) * dbarComponent F j z)
      (complexGaussianMeasure n) :=
    (hconjH.continuous.mul (continuous_dbarComponent hF j)).integrable_of_hasCompactSupport
      (hasCompactSupport_dbarComponent hFc j).mul_left
  have hiL : Integrable (fun z => F z *
      ((Real.sqrt (n * pq.1 j : ℕ) : ℂ) *
        multivariateNormalized n hn pq.2 (lowerAt pq.1 j) z))
      (complexGaussianMeasure n) :=
    (hF.continuous.mul
      (continuous_const.mul
        (continuous_multivariateNormalized n hn _ _))).integrable_of_hasCompactSupport
      hFc.mul_right
  have hleft : (∫ z, dbarComponent (fun w => F w * conj (H w)) j z
      ∂complexGaussianMeasure n) =
      (∫ z, F z * ((Real.sqrt (n * pq.1 j : ℕ) : ℂ) *
        multivariateNormalized n hn pq.2 (lowerAt pq.1 j) z)
        ∂complexGaussianMeasure n) +
      ∫ z, conj (H z) * dbarComponent F j z
        ∂complexGaussianMeasure n := by
    rw [← integral_add hiL hiD]
    apply integral_congr_ae
    filter_upwards with z
    rw [dbarComponent_mul (hF.differentiable (by norm_num))
        (hconjH.differentiable (by norm_num)),
      dbarComponent_conj_multivariateNormalized n hn]
    ring
  have hright : (n : ℂ) * (∫ z, z j * (F z * conj (H z))
      ∂complexGaussianMeasure n) =
      (∫ z, F z * ((Real.sqrt (n * pq.1 j : ℕ) : ℂ) *
        multivariateNormalized n hn pq.2 (lowerAt pq.1 j) z)
        ∂complexGaussianMeasure n) +
      (Real.sqrt (n * (pq.2 j + 1) : ℕ) : ℂ) *
        ∫ z, multivariateNormalized n hn
          (raiseAt pq.2 j) pq.1 z * F z ∂complexGaussianMeasure n := by
    rw [← integral_const_mul]
    have hae := coordinate_mul_multivariateNormalized_creation_ae
      n hn pq.2 pq.1 j
    have hae' : (fun z => (n : ℂ) * (z j * (F z * conj (H z))))
        =ᵐ[complexGaussianMeasure n]
        (fun z => F z * ((Real.sqrt (n * pq.1 j : ℕ) : ℂ) *
            multivariateNormalized n hn pq.2 (lowerAt pq.1 j) z)) +
          fun z => (Real.sqrt (n * (pq.2 j + 1) : ℕ) : ℂ) *
            (multivariateNormalized n hn (raiseAt pq.2 j) pq.1 z * F z) := by
      filter_upwards [hae] with z hz
      dsimp [H]
      rw [conj_multivariateNormalized_swap]
      calc
        (n : ℂ) * (z j * (F z *
            multivariateNormalized n hn pq.2 pq.1 z)) =
            F z * ((n : ℂ) * z j *
              multivariateNormalized n hn pq.2 pq.1 z) := by ring
        _ = _ := by rw [hz]; ring
    have hiR : Integrable (fun z =>
        (Real.sqrt (n * (pq.2 j + 1) : ℕ) : ℂ) *
          (multivariateNormalized n hn (raiseAt pq.2 j) pq.1 z * F z))
        (complexGaussianMeasure n) := by
      apply Integrable.const_mul
      exact (continuous_multivariateNormalized n hn _ _).mul hF.continuous
          |>.integrable_of_hasCompactSupport hFc.mul_left
    rw [integral_congr_ae hae']
    simp only [Pi.add_apply]
    rw [integral_add hiL hiR, integral_const_mul]
  rw [gaussianHermiteCoefficient_smoothDbarComponentL2_eq_integral,
    gaussianHermiteCoefficient_smoothCompactL2_eq_integral]
  dsimp only [raiseHermiteIndex]
  have htarget :
      (∫ z, conj (multivariateNormalized n hn pq.1 (raiseAt pq.2 j) z) * F z
        ∂complexGaussianMeasure n) =
      ∫ z, multivariateNormalized n hn (raiseAt pq.2 j) pq.1 z * F z
        ∂complexGaussianMeasure n := by
    apply integral_congr_ae
    filter_upwards with z
    rw [conj_multivariateNormalized_swap]
  rw [htarget]
  have hsource :
      (∫ z, conj (multivariateNormalized n hn pq.1 pq.2 z) *
        dbarComponent F j z ∂complexGaussianMeasure n) =
      ∫ z, conj (H z) * dbarComponent F j z
        ∂complexGaussianMeasure n := by rfl
  rw [hsource]
  rw [hleft] at hibp
  rw [hright] at hibp
  exact add_left_cancel hibp

theorem norm_sq_smoothDbarComponentL2 {n : ℕ}
    (F : Configuration n → ℂ) (hF : ContDiff ℝ 1 F)
    (hFc : HasCompactSupport F) (j : Fin n) :
    ‖smoothDbarComponentL2 F hF hFc j‖ ^ 2 =
      ∫ z, Complex.normSq (dbarComponent F j z)
        ∂complexGaussianMeasure n := by
  have hinner : inner ℂ (smoothDbarComponentL2 F hF hFc j)
      (smoothDbarComponentL2 F hF hFc j) =
      ∫ z, inner ℂ ((smoothDbarComponentL2 F hF hFc j) z)
        ((smoothDbarComponentL2 F hF hFc j) z)
        ∂complexGaussianMeasure n :=
    MeasureTheory.L2.inner_def _ _
  rw [inner_self_eq_norm_sq_to_K] at hinner
  have hc := smoothDbarComponentL2_coeFn F hF hFc j
  rw [integral_congr_ae (by filter_upwards [hc] with z hz; rw [hz])] at hinner
  have hi : (fun z => inner ℂ (dbarComponent F j z) (dbarComponent F j z)) =
      fun z => (Complex.normSq (dbarComponent F j z) : ℂ) := by
    funext z
    rw [inner_self_eq_norm_sq_to_K]
    calc
      (‖dbarComponent F j z‖ : ℂ) ^ 2 =
          ((‖dbarComponent F j z‖ ^ 2 : ℝ) : ℂ) := by norm_cast
      _ = _ := congrArg Complex.ofReal (Complex.sq_norm (dbarComponent F j z))
  rw [hi, integral_complex_ofReal] at hinner
  apply Complex.ofReal_injective
  push_cast
  exact hinner

theorem sum_norm_sq_smoothDbarComponentL2 {n : ℕ} (hn : 0 < n)
    (F : Configuration n → ℂ) (hF : ContDiff ℝ 1 F)
    (hFc : HasCompactSupport F) :
    (1 / n : ℝ) * ∑ j : Fin n, ‖smoothDbarComponentL2 F hF hFc j‖ ^ 2 =
      gaussianDbarEnergy n F := by
  unfold gaussianDbarEnergy dbarNormSq
  congr 1
  rw [integral_finset_sum]
  · apply Finset.sum_congr rfl
    intro j _
    exact norm_sq_smoothDbarComponentL2 F hF hFc j
  · intro j _
    exact (Complex.continuous_normSq.comp (continuous_dbarComponent hF j))
      |>.integrable_of_hasCompactSupport
        ((hasCompactSupport_dbarComponent hFc j).comp_left (by simp))

theorem smoothDbarComponent_modeParseval {n : ℕ} (hn : 0 < n)
    (F : Configuration n → ℂ) (hF : ContDiff ℝ 1 F)
    (hFc : HasCompactSupport F) (j : Fin n) :
    ∑' d, ‖gaussianHermiteMode hn d (smoothDbarComponentL2 F hF hFc j)‖ ^ 2 =
      ‖smoothDbarComponentL2 F hF hFc j‖ ^ 2 :=
  tsum_norm_sq_gaussianHermiteMode hn (smoothDbarComponentL2 F hF hFc j)

theorem sum_smoothDbarComponent_modeParseval {n : ℕ} (hn : 0 < n)
    (F : Configuration n → ℂ) (hF : ContDiff ℝ 1 F)
    (hFc : HasCompactSupport F) :
    ∑ j : Fin n, ∑' d,
        ‖gaussianHermiteMode hn d (smoothDbarComponentL2 F hF hFc j)‖ ^ 2 =
      ∑ j : Fin n, ‖smoothDbarComponentL2 F hF hFc j‖ ^ 2 := by
  apply Finset.sum_congr rfl
  intro j _
  exact smoothDbarComponent_modeParseval hn F hF hFc j

theorem dbarComponent_mul_conj {n : ℕ} {F H : Configuration n → ℂ}
    (hF : Differentiable ℝ F) (hH : Differentiable ℝ H)
    (j : Fin n) (z : Configuration n) :
    dbarComponent (fun w ↦ F w * conj (H w)) j z =
      dbarComponent F j z * conj (H z) +
        F z * dbarComponent (fun w ↦ conj (H w)) j z := by
  apply dbarComponent_mul hF
    (Complex.differentiable_conj.comp hH)

/-- The Hilbert-basis coefficient of a finite Hermite synthesis is its
algebraic coefficient. -/
theorem gaussianHermiteCoefficient_finiteHermiteCombination
    (n : ℕ) (hn : 0 < n) (c : HermiteMultiIndex n →₀ ℂ)
    (pq : HermiteMultiIndex n) :
    gaussianHermiteCoefficient hn (finiteHermiteCombination n hn c) pq = c pq := by
  rw [gaussianHermiteCoefficient_eq_inner]
  classical
  have h := inner_finiteHermiteCombination n hn (Finsupp.single pq 1) c
  have hsingle : finiteHermiteCombination n hn (Finsupp.single pq 1) =
      multivariateNormalizedL2 n hn pq.1 pq.2 := by
    simp [finiteHermiteCombination, multivariateNormalizedL2,
      ComplexHermite.hermiteL2Family]
  rw [hsingle] at h
  simpa using h

/-- The Gaussian `L²` vector represented by the `j`th `∂̄` derivative of a
finite Hermite synthesis. -/
def finiteDbarComponentL2 (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) (j : Fin n) :
    Lp ℂ 2 (complexGaussianMeasure n) :=
  finiteHermiteCombination n hn (loweredCoefficients n c j)

theorem finiteDbarComponentL2_coeFn (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) (j : Fin n) :
    finiteDbarComponentL2 n hn c j =ᵐ[complexGaussianMeasure n]
      dbarComponent (finiteHermiteFunction n hn c) j := by
  filter_upwards [finiteHermiteCombination_coeFn n hn
    (loweredCoefficients n c j)] with z hz
  unfold finiteDbarComponentL2
  rw [hz, ← dbarComponent_finiteHermiteFunction n hn c j z]

/-- Exact lowering/adjoint coefficient identity on the finite Hermite core. -/
theorem gaussianHermiteCoefficient_finiteDbarComponentL2
    (n : ℕ) (hn : 0 < n) (c : HermiteMultiIndex n →₀ ℂ)
    (j : Fin n) (pq : HermiteMultiIndex n) :
    gaussianHermiteCoefficient hn (finiteDbarComponentL2 n hn c j) pq =
      (Real.sqrt (n * (pq.2 j + 1) : ℕ) : ℂ) *
        c (raiseHermiteIndex j pq) := by
  rw [finiteDbarComponentL2,
    gaussianHermiteCoefficient_finiteHermiteCombination]
  let r := raiseHermiteIndex j pq
  have hrpos : 0 < r.2 j := by simp [r, raiseHermiteIndex, raiseAt]
  have hlower : lowerHermiteIndex j r = pq := by
    unfold r raiseHermiteIndex lowerHermiteIndex raiseAt lowerAt
    apply Prod.ext
    · rfl
    · funext k
      by_cases hkj : k = j
      · subst k
        simp
      · simp [Function.update_of_ne hkj]
  have h := loweredCoefficients_apply_lowerHermiteIndex n c j r hrpos
  rw [hlower] at h
  rw [h]
  congr 2
  simp [r, raiseHermiteIndex, raiseAt]

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/GaussianDensity.lean #
import GinibrePoincare.Concrete.GaussianProbability
import Mathlib.Probability.Distributions.Gaussian.Real

/-!
# Density of the real coordinates of the Ginibre Gaussian

This file begins the identification of the probability measure constructed in
`Concrete.GaussianProbability` with an explicit Lebesgue density.  The first
step is completely supplied by Mathlib's density theorem for a nondegenerate
real Gaussian; the only point specific to the Ginibre normalization is proving
that the variance `1 / (2n)` is nonzero when `n > 0`.
-/

open MeasureTheory

namespace GinibrePoincare

noncomputable section

/-- For a nonempty particle configuration, the variance `1 / (2n)` of each
real coordinate is nonzero. -/
theorem realCoordinateVariance_ne_zero {n : ℕ} (hn : 0 < n) :
    realCoordinateVariance n ≠ 0 := by
  unfold realCoordinateVariance
  exact inv_ne_zero (mul_ne_zero (by norm_num) (Nat.cast_ne_zero.mpr hn.ne'))

/-- Coercing the real-coordinate variance to `ℝ` gives the expected
normalization. -/
theorem coe_realCoordinateVariance (n : ℕ) :
    (realCoordinateVariance n : ℝ) = ((2 : ℝ) * n)⁻¹ := by
  simp [realCoordinateVariance]

/-- The exponent in the centered one-dimensional Gaussian PDF simplifies to
`-n x²`. -/
theorem realCoordinateGaussian_exponent {n : ℕ} (hn : 0 < n) (x : ℝ) :
    -(x - 0) ^ 2 / (2 * (realCoordinateVariance n : ℝ)) =
      -(n : ℝ) * x ^ 2 := by
  rw [coe_realCoordinateVariance]
  have hn0 : (n : ℝ) ≠ 0 := Nat.cast_ne_zero.mpr hn.ne'
  field_simp
  ring

/-- The real Gaussian PDF in the normalization used by the Ginibre model. -/
theorem realCoordinateGaussianPDFReal_formula {n : ℕ} (hn : 0 < n)
    (x : ℝ) :
    ProbabilityTheory.gaussianPDFReal 0 (realCoordinateVariance n) x =
      (Real.sqrt (Real.pi / n))⁻¹ * Real.exp (-(n : ℝ) * x ^ 2) := by
  rw [ProbabilityTheory.gaussianPDFReal]
  rw [realCoordinateGaussian_exponent hn]
  congr 2
  apply congrArg Real.sqrt
  rw [coe_realCoordinateVariance]
  have hn0 : (n : ℝ) ≠ 0 := Nat.cast_ne_zero.mpr hn.ne'
  field_simp

/-- `ℝ≥0∞`-valued version of the explicit real-coordinate density. -/
theorem realCoordinateGaussianPDF_formula {n : ℕ} (hn : 0 < n)
    (x : ℝ) :
    ProbabilityTheory.gaussianPDF 0 (realCoordinateVariance n) x =
      ENNReal.ofReal
        ((Real.sqrt (Real.pi / n))⁻¹ * Real.exp (-(n : ℝ) * x ^ 2)) := by
  rw [ProbabilityTheory.gaussianPDF,
    realCoordinateGaussianPDFReal_formula hn]

/-- The ordinary measure underlying one real-coordinate Gaussian has
Mathlib's explicit Gaussian PDF with respect to Lebesgue measure. -/
theorem realCoordinateGaussianMeasure_eq_withDensity {n : ℕ} (hn : 0 < n) :
    (realCoordinateGaussianProbability n : Measure ℝ) =
      volume.withDensity
        (ProbabilityTheory.gaussianPDF 0 (realCoordinateVariance n)) := by
  unfold realCoordinateGaussianProbability
  exact ProbabilityTheory.gaussianReal_of_var_ne_zero 0
    (realCoordinateVariance_ne_zero hn)

/-- Setwise form of `realCoordinateGaussianMeasure_eq_withDensity`. -/
theorem realCoordinateGaussian_apply {n : ℕ} (hn : 0 < n)
    (s : Set ℝ) :
    (realCoordinateGaussianProbability n : Measure ℝ) s =
      ∫⁻ x in s, ProbabilityTheory.gaussianPDF 0
        (realCoordinateVariance n) x := by
  rw [realCoordinateGaussianMeasure_eq_withDensity hn]
  exact withDensity_apply' _ _

/-- The real-coordinate Gaussian is absolutely continuous with respect to
Lebesgue measure whenever the particle number is positive. -/
theorem realCoordinateGaussian_absolutelyContinuous {n : ℕ} (hn : 0 < n) :
    (realCoordinateGaussianProbability n : Measure ℝ) ≪ volume := by
  rw [realCoordinateGaussianMeasure_eq_withDensity hn]
  exact withDensity_absolutelyContinuous _ _

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/GaussianFourierCoordinates.lean #
import GinibrePoincare.Analysis.GaussianHermiteMoments
import Mathlib.MeasureTheory.Measure.CharacteristicFunction.Basic

/-! # Euclidean coordinates for complex configurations -/

namespace GinibrePoincare

noncomputable section

/-- Real and imaginary coordinates identify a complex configuration with a
real Euclidean vector. -/
def configurationEuclideanLinearEquiv (n : ℕ) :
    Configuration n ≃ₗ[ℝ] ((Fin n × Fin 2) → ℝ) where
  toFun z := fun ij : Fin n × Fin 2 ↦ ![(z ij.1).re, (z ij.1).im] ij.2
  invFun x i := ⟨x (i, 0), x (i, 1)⟩
  left_inv z := by
    ext i <;> rfl
  right_inv x := by
    ext ⟨i, j⟩
    fin_cases j <;> rfl
  map_add' x y := by
    ext ⟨i, j⟩
    fin_cases j <;> simp
  map_smul' r x := by
    ext ⟨i, j⟩
    fin_cases j <;> simp

/-- The same coordinate identification as a homeomorphic continuous linear
equivalence, hence in particular a measurable equivalence. -/
def configurationEuclideanEquiv (n : ℕ) :
    Configuration n ≃L[ℝ] EuclideanSpace ℝ (Fin n × Fin 2) :=
  (configurationEuclideanLinearEquiv n).toContinuousLinearEquiv.trans
    (EuclideanSpace.equiv (Fin n × Fin 2) ℝ).symm

@[simp] theorem configurationEuclideanEquiv_apply_zero
    (n : ℕ) (z : Configuration n) (i : Fin n) :
    configurationEuclideanEquiv n z (i, 0) = (z i).re := by
  simp [configurationEuclideanEquiv, configurationEuclideanLinearEquiv]

@[simp] theorem configurationEuclideanEquiv_apply_one
    (n : ℕ) (z : Configuration n) (i : Fin n) :
    configurationEuclideanEquiv n z (i, 1) = (z i).im := by
  simp [configurationEuclideanEquiv, configurationEuclideanLinearEquiv]

@[simp] theorem configurationEuclideanEquiv_symm_apply
    (n : ℕ) (x : EuclideanSpace ℝ (Fin n × Fin 2)) (i : Fin n) :
    (configurationEuclideanEquiv n).symm x i =
      ⟨x (i, 0), x (i, 1)⟩ := by
  simp [configurationEuclideanEquiv, configurationEuclideanLinearEquiv]

theorem measurable_configurationEuclideanEquiv (n : ℕ) :
    Measurable (configurationEuclideanEquiv n) :=
  (configurationEuclideanEquiv n).continuous.measurable

theorem measurable_configurationEuclideanEquiv_symm (n : ℕ) :
    Measurable (configurationEuclideanEquiv n).symm :=
  (configurationEuclideanEquiv n).symm.continuous.measurable

theorem real_inner_configurationEuclideanEquiv
    (n : ℕ) (z : Configuration n)
    (x : EuclideanSpace ℝ (Fin n × Fin 2)) :
    inner ℝ (configurationEuclideanEquiv n z) x =
      configurationRealPairing ((configurationEuclideanEquiv n).symm x) z := by
  rw [EuclideanSpace.inner_eq_star_dotProduct]
  unfold dotProduct configurationRealPairing
  rw [Fintype.sum_prod_type]
  apply Finset.sum_congr rfl
  intro i hi
  rw [Fin.sum_univ_two]
  simp only [star_trivial]
  rw [configurationEuclideanEquiv_apply_zero,
    configurationEuclideanEquiv_apply_one]
  simp only [configurationEuclideanEquiv_symm_apply]

end
end GinibrePoincare
Analysis GinibrePoincare/Analysis/GaussianFourierUniqueness.lean #
import GinibrePoincare.Analysis.GaussianFourierCoordinates
import GinibrePoincare.Analysis.GaussianHermiteMoments
import GinibrePoincare.Analysis.HermiteL2Family
import Mathlib.Analysis.InnerProductSpace.l2Space
import Mathlib.MeasureTheory.Integral.Bochner.ContinuousLinearMap

/-! # Positive-measure reduction for Gaussian Fourier uniqueness -/

open MeasureTheory
open scoped ENNReal ComplexConjugate

namespace GinibrePoincare

noncomputable section

theorem integrable_re_Lp_two {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    Integrable (fun z ↦ (v z).re) (complexGaussianMeasure n) :=
  ((Lp.memLp v).integrable (by norm_num : (1 : ℝ≥0∞) ≤ 2)).re

theorem integrable_im_Lp_two {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    Integrable (fun z ↦ (v z).im) (complexGaussianMeasure n) :=
  ((Lp.memLp v).integrable (by norm_num : (1 : ℝ≥0∞) ≤ 2)).im

private theorem integrable_max_zero {n : ℕ} {f : Configuration n → ℝ}
    (hf : Integrable f (complexGaussianMeasure n)) :
    Integrable (fun z ↦ max (f z) 0) (complexGaussianMeasure n) := by
  convert hf.sup
    (integrable_zero (Configuration n) ℝ (complexGaussianMeasure n)) using 1
  funext z
  rfl

/-- Positive and negative density measures associated with the real part of
an `L²` vector. -/
def gaussianRealPartPositiveMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) : Measure (Configuration n) :=
  (complexGaussianMeasure n).withDensity
    (fun z ↦ ENNReal.ofReal (max (v z).re 0))

def gaussianRealPartNegativeMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) : Measure (Configuration n) :=
  (complexGaussianMeasure n).withDensity
    (fun z ↦ ENNReal.ofReal (max (-(v z).re) 0))

/-- Positive and negative density measures associated with the imaginary
part of an `L²` vector. -/
def gaussianImagPartPositiveMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) : Measure (Configuration n) :=
  (complexGaussianMeasure n).withDensity
    (fun z ↦ ENNReal.ofReal (max (v z).im 0))

def gaussianImagPartNegativeMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) : Measure (Configuration n) :=
  (complexGaussianMeasure n).withDensity
    (fun z ↦ ENNReal.ofReal (max (-(v z).im) 0))

theorem isFiniteMeasure_gaussianRealPartPositiveMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    IsFiniteMeasure (gaussianRealPartPositiveMeasure v) := by
  apply isFiniteMeasure_withDensity_ofReal
  exact (integrable_max_zero (integrable_re_Lp_two v)).hasFiniteIntegral

theorem isFiniteMeasure_gaussianRealPartNegativeMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    IsFiniteMeasure (gaussianRealPartNegativeMeasure v) := by
  apply isFiniteMeasure_withDensity_ofReal
  exact (integrable_max_zero (integrable_re_Lp_two v).neg).hasFiniteIntegral

theorem isFiniteMeasure_gaussianImagPartPositiveMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    IsFiniteMeasure (gaussianImagPartPositiveMeasure v) := by
  apply isFiniteMeasure_withDensity_ofReal
  exact (integrable_max_zero (integrable_im_Lp_two v)).hasFiniteIntegral

theorem isFiniteMeasure_gaussianImagPartNegativeMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    IsFiniteMeasure (gaussianImagPartNegativeMeasure v) := by
  apply isFiniteMeasure_withDensity_ofReal
  exact (integrable_max_zero (integrable_im_Lp_two v).neg).hasFiniteIntegral

/-- Euclidean pushforwards of the positive and negative real-part measures. -/
def euclideanRealPartPositiveMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    Measure (EuclideanSpace ℝ (Fin n × Fin 2)) :=
  (gaussianRealPartPositiveMeasure v).map (configurationEuclideanEquiv n)

def euclideanRealPartNegativeMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    Measure (EuclideanSpace ℝ (Fin n × Fin 2)) :=
  (gaussianRealPartNegativeMeasure v).map (configurationEuclideanEquiv n)

/-- Euclidean pushforwards of the positive and negative imaginary-part measures. -/
def euclideanImagPartPositiveMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    Measure (EuclideanSpace ℝ (Fin n × Fin 2)) :=
  (gaussianImagPartPositiveMeasure v).map (configurationEuclideanEquiv n)

def euclideanImagPartNegativeMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    Measure (EuclideanSpace ℝ (Fin n × Fin 2)) :=
  (gaussianImagPartNegativeMeasure v).map (configurationEuclideanEquiv n)

theorem charFun_euclideanRealPartPositiveMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (x : EuclideanSpace ℝ (Fin n × Fin 2)) :
    charFun (euclideanRealPartPositiveMeasure v) x =
      ∫ z, ((max (v z).re 0 : ℝ) : ℂ) *
        configurationFourierCharacter
          ((configurationEuclideanEquiv n).symm x) z
        ∂complexGaussianMeasure n := by
  letI : IsFiniteMeasure (gaussianRealPartPositiveMeasure v) :=
    isFiniteMeasure_gaussianRealPartPositiveMeasure v
  rw [charFun_apply]
  unfold euclideanRealPartPositiveMeasure
  rw [integral_map
    (measurable_configurationEuclideanEquiv n).aemeasurable (by fun_prop)]
  unfold gaussianRealPartPositiveMeasure
  rw [integral_withDensity_eq_integral_toReal_smul₀]
  · apply integral_congr_ae
    filter_upwards with z
    rw [real_inner_configurationEuclideanEquiv]
    simp [configurationFourierCharacter, ENNReal.toReal_ofReal']
  · exact (integrable_max_zero (integrable_re_Lp_two v)).aemeasurable.ennreal_ofReal
  · exact Filter.Eventually.of_forall fun z ↦ ENNReal.ofReal_lt_top

theorem charFun_euclideanRealPartNegativeMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (x : EuclideanSpace ℝ (Fin n × Fin 2)) :
    charFun (euclideanRealPartNegativeMeasure v) x =
      ∫ z, ((max (-(v z).re) 0 : ℝ) : ℂ) *
        configurationFourierCharacter
          ((configurationEuclideanEquiv n).symm x) z
        ∂complexGaussianMeasure n := by
  letI : IsFiniteMeasure (gaussianRealPartNegativeMeasure v) :=
    isFiniteMeasure_gaussianRealPartNegativeMeasure v
  rw [charFun_apply]
  unfold euclideanRealPartNegativeMeasure
  rw [integral_map
    (measurable_configurationEuclideanEquiv n).aemeasurable (by fun_prop)]
  unfold gaussianRealPartNegativeMeasure
  rw [integral_withDensity_eq_integral_toReal_smul₀]
  · apply integral_congr_ae
    filter_upwards with z
    rw [real_inner_configurationEuclideanEquiv]
    simp [configurationFourierCharacter, ENNReal.toReal_ofReal']
  · exact (integrable_max_zero
      (integrable_re_Lp_two v).neg).aemeasurable.ennreal_ofReal
  · exact Filter.Eventually.of_forall fun z ↦ ENNReal.ofReal_lt_top

theorem charFun_euclideanImagPartPositiveMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (x : EuclideanSpace ℝ (Fin n × Fin 2)) :
    charFun (euclideanImagPartPositiveMeasure v) x =
      ∫ z, ((max (v z).im 0 : ℝ) : ℂ) *
        configurationFourierCharacter
          ((configurationEuclideanEquiv n).symm x) z
        ∂complexGaussianMeasure n := by
  letI : IsFiniteMeasure (gaussianImagPartPositiveMeasure v) :=
    isFiniteMeasure_gaussianImagPartPositiveMeasure v
  rw [charFun_apply]
  unfold euclideanImagPartPositiveMeasure
  rw [integral_map
    (measurable_configurationEuclideanEquiv n).aemeasurable (by fun_prop)]
  unfold gaussianImagPartPositiveMeasure
  rw [integral_withDensity_eq_integral_toReal_smul₀]
  · apply integral_congr_ae
    filter_upwards with z
    rw [real_inner_configurationEuclideanEquiv]
    simp [configurationFourierCharacter, ENNReal.toReal_ofReal']
  · exact (integrable_max_zero
      (integrable_im_Lp_two v)).aemeasurable.ennreal_ofReal
  · exact Filter.Eventually.of_forall fun z ↦ ENNReal.ofReal_lt_top

theorem charFun_euclideanImagPartNegativeMeasure {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (x : EuclideanSpace ℝ (Fin n × Fin 2)) :
    charFun (euclideanImagPartNegativeMeasure v) x =
      ∫ z, ((max (-(v z).im) 0 : ℝ) : ℂ) *
        configurationFourierCharacter
          ((configurationEuclideanEquiv n).symm x) z
        ∂complexGaussianMeasure n := by
  letI : IsFiniteMeasure (gaussianImagPartNegativeMeasure v) :=
    isFiniteMeasure_gaussianImagPartNegativeMeasure v
  rw [charFun_apply]
  unfold euclideanImagPartNegativeMeasure
  rw [integral_map
    (measurable_configurationEuclideanEquiv n).aemeasurable (by fun_prop)]
  unfold gaussianImagPartNegativeMeasure
  rw [integral_withDensity_eq_integral_toReal_smul₀]
  · apply integral_congr_ae
    filter_upwards with z
    rw [real_inner_configurationEuclideanEquiv]
    simp [configurationFourierCharacter, ENNReal.toReal_ofReal']
  · exact (integrable_max_zero
      (integrable_im_Lp_two v).neg).aemeasurable.ennreal_ofReal
  · exact Filter.Eventually.of_forall fun z ↦ ENNReal.ofReal_lt_top

private theorem configurationFourierCharacter_neg {n : ℕ}
    (t z : Configuration n) :
    conj (configurationFourierCharacter (-t) z) =
      configurationFourierCharacter t z := by
  unfold configurationFourierCharacter configurationRealPairing
  rw [← Complex.exp_conj]
  congr 1
  simp only [map_mul, Complex.conj_ofReal, Complex.conj_I, Pi.neg_apply,
    Complex.neg_re, Complex.neg_im, neg_mul]
  push_cast
  rw [show (∑ x, (-((t x).re * (z x).re) + -((t x).im * (z x).im) : ℂ)) =
      -(∑ x, ((t x).re * (z x).re + (t x).im * (z x).im : ℂ)) by
    rw [← Finset.sum_neg_distrib]
    apply Finset.sum_congr rfl
    intro i hi
    push_cast
    ring]
  ring

theorem integral_re_mul_configurationFourierCharacter_eq_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (hzero : ∀ t, gaussianL2FourierTest v t = 0)
    (t : Configuration n) :
    (∫ z, ((v z).re : ℂ) * configurationFourierCharacter t z
      ∂complexGaussianMeasure n) = 0 := by
  have hp := hzero t
  have hn := congrArg conj (hzero (-t))
  unfold gaussianL2FourierTest at hp hn
  rw [← integral_conj] at hn
  have hn' : (∫ z, conj (v z) * configurationFourierCharacter t z
      ∂complexGaussianMeasure n) = 0 := by
    simpa only [map_mul, configurationFourierCharacter_neg, map_zero] using hn
  have hvInt := integrable_mul_configurationFourierCharacter v t
  have hvL1 : Integrable (fun z ↦ v z) (complexGaussianMeasure n) :=
    (Lp.memLp v).integrable (by norm_num : (1 : ℝ≥0∞) ≤ 2)
  have hcv : Integrable (fun z ↦ conj (v z)) (complexGaussianMeasure n) :=
    Complex.conjCLE.toContinuousLinearMap.integrable_comp hvL1
  have hcvInt : Integrable (fun z ↦ conj (v z) *
      configurationFourierCharacter t z) (complexGaussianMeasure n) :=
    hcv.mul_bdd (c := 1)
      (continuous_configurationFourierCharacter t).aestronglyMeasurable
      (Filter.Eventually.of_forall fun z ↦ by simp)
  rw [show (fun z ↦ ((v z).re : ℂ) * configurationFourierCharacter t z) =
      fun z ↦ (v z * configurationFourierCharacter t z +
        conj (v z) * configurationFourierCharacter t z) / 2 by
    funext z
    apply Complex.ext <;> simp <;> ring]
  rw [integral_div, integral_add hvInt hcvInt, hp, hn']
  simp

theorem integral_im_mul_configurationFourierCharacter_eq_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (hzero : ∀ t, gaussianL2FourierTest v t = 0)
    (t : Configuration n) :
    (∫ z, ((v z).im : ℂ) * configurationFourierCharacter t z
      ∂complexGaussianMeasure n) = 0 := by
  have hp := hzero t
  have hn := congrArg conj (hzero (-t))
  unfold gaussianL2FourierTest at hp hn
  rw [← integral_conj] at hn
  have hn' : (∫ z, conj (v z) * configurationFourierCharacter t z
      ∂complexGaussianMeasure n) = 0 := by
    simpa only [map_mul, configurationFourierCharacter_neg, map_zero] using hn
  have hvInt := integrable_mul_configurationFourierCharacter v t
  have hvL1 : Integrable (fun z ↦ v z) (complexGaussianMeasure n) :=
    (Lp.memLp v).integrable (by norm_num : (1 : ℝ≥0∞) ≤ 2)
  have hcv : Integrable (fun z ↦ conj (v z)) (complexGaussianMeasure n) :=
    Complex.conjCLE.toContinuousLinearMap.integrable_comp hvL1
  have hcvInt : Integrable (fun z ↦ conj (v z) *
      configurationFourierCharacter t z) (complexGaussianMeasure n) :=
    hcv.mul_bdd (c := 1)
      (continuous_configurationFourierCharacter t).aestronglyMeasurable
      (Filter.Eventually.of_forall fun z ↦ by simp)
  rw [show (fun z ↦ ((v z).im : ℂ) * configurationFourierCharacter t z) =
      fun z ↦ (v z * configurationFourierCharacter t z -
        conj (v z) * configurationFourierCharacter t z) / (2 * Complex.I) by
    funext z
    rw [show ((v z).im : ℂ) = (v z - conj (v z)) / (2 * Complex.I) by
      apply Complex.ext <;> norm_num [Complex.div_re, Complex.div_im] <;> ring]
    ring]
  rw [integral_div, integral_sub hvInt hcvInt, hp, hn']
  simp

private theorem integrable_ofReal_mul_configurationFourierCharacter {n : ℕ}
    {f : Configuration n → ℝ}
    (hf : Integrable f (complexGaussianMeasure n)) (t : Configuration n) :
    Integrable (fun z ↦ (f z : ℂ) * configurationFourierCharacter t z)
      (complexGaussianMeasure n) := by
  exact hf.ofReal.mul_bdd (c := 1)
    (continuous_configurationFourierCharacter t).aestronglyMeasurable
    (Filter.Eventually.of_forall fun z ↦ by simp)

theorem charFun_euclideanRealParts_eq_of_fourierTest_eq_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (hzero : ∀ t, gaussianL2FourierTest v t = 0) :
    charFun (euclideanRealPartPositiveMeasure v) =
      charFun (euclideanRealPartNegativeMeasure v) := by
  funext x
  have hneg : Integrable (fun z ↦ max (-(v z).re) 0)
      (complexGaussianMeasure n) := by
    simpa only [Pi.neg_apply] using integrable_max_zero (integrable_re_Lp_two v).neg
  rw [charFun_euclideanRealPartPositiveMeasure,
    charFun_euclideanRealPartNegativeMeasure, ← sub_eq_zero]
  rw [← integral_sub
    (integrable_ofReal_mul_configurationFourierCharacter
      (integrable_max_zero (integrable_re_Lp_two v)) _)
    (integrable_ofReal_mul_configurationFourierCharacter
      hneg _)]
  convert integral_re_mul_configurationFourierCharacter_eq_zero v hzero
    ((configurationEuclideanEquiv n).symm x) using 1
  apply integral_congr_ae
  filter_upwards with z
  rw [← sub_mul]
  norm_cast
  rw [max_zero_sub_max_neg_zero_eq_self]

theorem charFun_euclideanImagParts_eq_of_fourierTest_eq_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (hzero : ∀ t, gaussianL2FourierTest v t = 0) :
    charFun (euclideanImagPartPositiveMeasure v) =
      charFun (euclideanImagPartNegativeMeasure v) := by
  funext x
  have hneg : Integrable (fun z ↦ max (-(v z).im) 0)
      (complexGaussianMeasure n) := by
    simpa only [Pi.neg_apply] using integrable_max_zero (integrable_im_Lp_two v).neg
  rw [charFun_euclideanImagPartPositiveMeasure,
    charFun_euclideanImagPartNegativeMeasure, ← sub_eq_zero]
  rw [← integral_sub
    (integrable_ofReal_mul_configurationFourierCharacter
      (integrable_max_zero (integrable_im_Lp_two v)) _)
    (integrable_ofReal_mul_configurationFourierCharacter
      hneg _)]
  convert integral_im_mul_configurationFourierCharacter_eq_zero v hzero
    ((configurationEuclideanEquiv n).symm x) using 1
  apply integral_congr_ae
  filter_upwards with z
  rw [← sub_mul]
  norm_cast
  rw [max_zero_sub_max_neg_zero_eq_self]

theorem gaussianRealPartPositiveMeasure_eq_negative_of_fourierTest_eq_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (hzero : ∀ t, gaussianL2FourierTest v t = 0) :
    gaussianRealPartPositiveMeasure v = gaussianRealPartNegativeMeasure v := by
  letI : IsFiniteMeasure (gaussianRealPartPositiveMeasure v) :=
    isFiniteMeasure_gaussianRealPartPositiveMeasure v
  letI : IsFiniteMeasure (gaussianRealPartNegativeMeasure v) :=
    isFiniteMeasure_gaussianRealPartNegativeMeasure v
  apply (configurationEuclideanEquiv n).toHomeomorph.toMeasurableEquiv.measurableEmbedding.map_injective
  exact Measure.ext_of_charFun
    (charFun_euclideanRealParts_eq_of_fourierTest_eq_zero v hzero)

theorem gaussianImagPartPositiveMeasure_eq_negative_of_fourierTest_eq_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (hzero : ∀ t, gaussianL2FourierTest v t = 0) :
    gaussianImagPartPositiveMeasure v = gaussianImagPartNegativeMeasure v := by
  letI : IsFiniteMeasure (gaussianImagPartPositiveMeasure v) :=
    isFiniteMeasure_gaussianImagPartPositiveMeasure v
  letI : IsFiniteMeasure (gaussianImagPartNegativeMeasure v) :=
    isFiniteMeasure_gaussianImagPartNegativeMeasure v
  apply (configurationEuclideanEquiv n).toHomeomorph.toMeasurableEquiv.measurableEmbedding.map_injective
  exact Measure.ext_of_charFun
    (charFun_euclideanImagParts_eq_of_fourierTest_eq_zero v hzero)

theorem ae_re_eq_zero_of_fourierTest_eq_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (hzero : ∀ t, gaussianL2FourierTest v t = 0) :
    ∀ᵐ z ∂complexGaussianMeasure n, (v z).re = 0 := by
  have heq := gaussianRealPartPositiveMeasure_eq_negative_of_fourierTest_eq_zero v hzero
  unfold gaussianRealPartPositiveMeasure gaussianRealPartNegativeMeasure at heq
  have hdens := (withDensity_eq_iff_of_sigmaFinite
    (integrable_max_zero (integrable_re_Lp_two v)).aemeasurable.ennreal_ofReal
    (integrable_max_zero (integrable_re_Lp_two v).neg).aemeasurable.ennreal_ofReal).mp heq
  filter_upwards [hdens] with z hz
  have hm : max (v z).re 0 = max (-(v z).re) 0 :=
    (ENNReal.ofReal_eq_ofReal_iff (le_max_right _ _) (le_max_right _ _)).mp hz
  have hsub := max_zero_sub_max_neg_zero_eq_self ((v z).re)
  rw [hm, sub_self] at hsub
  exact hsub.symm

theorem ae_im_eq_zero_of_fourierTest_eq_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (hzero : ∀ t, gaussianL2FourierTest v t = 0) :
    ∀ᵐ z ∂complexGaussianMeasure n, (v z).im = 0 := by
  have heq := gaussianImagPartPositiveMeasure_eq_negative_of_fourierTest_eq_zero v hzero
  unfold gaussianImagPartPositiveMeasure gaussianImagPartNegativeMeasure at heq
  have hdens := (withDensity_eq_iff_of_sigmaFinite
    (integrable_max_zero (integrable_im_Lp_two v)).aemeasurable.ennreal_ofReal
    (integrable_max_zero (integrable_im_Lp_two v).neg).aemeasurable.ennreal_ofReal).mp heq
  filter_upwards [hdens] with z hz
  have hm : max (v z).im 0 = max (-(v z).im) 0 :=
    (ENNReal.ofReal_eq_ofReal_iff (le_max_right _ _) (le_max_right _ _)).mp hz
  have hsub := max_zero_sub_max_neg_zero_eq_self ((v z).im)
  rw [hm, sub_self] at hsub
  exact hsub.symm

theorem eq_zero_of_gaussianL2FourierTest_eq_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (hzero : ∀ t, gaussianL2FourierTest v t = 0) : v = 0 := by
  apply Lp.ext
  filter_upwards [ae_re_eq_zero_of_fourierTest_eq_zero v hzero,
    ae_im_eq_zero_of_fourierTest_eq_zero v hzero] with z hre him
  apply Complex.ext
  · simpa using hre
  · simpa using him

theorem eq_zero_of_orthogonal_hermites (n : ℕ) (hn : 0 < n)
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (horth : ∀ p q : Fin n → ℕ,
      inner ℂ (multivariateNormalizedL2 n hn p q) v = 0) : v = 0 := by
  apply eq_zero_of_gaussianL2FourierTest_eq_zero v
  exact gaussianL2FourierTest_eq_zero_of_orthogonal_hermites n hn v horth

theorem gaussianHermiteSpan_orthogonal_eq_bot (n : ℕ) (hn : 0 < n) :
    (gaussianHermiteSpan n hn)ᗮ = ⊥ := by
  rw [Submodule.eq_bot_iff]
  intro v hv
  apply eq_zero_of_orthogonal_hermites n hn v
  intro p q
  exact hv (multivariateNormalizedL2 n hn p q)
    (multivariateNormalizedL2_mem_span n hn p q)

theorem gaussianHermiteSpan_topologicalClosure_eq_top (n : ℕ) (hn : 0 < n) :
    (gaussianHermiteSpan n hn).topologicalClosure = ⊤ := by
  rw [← Submodule.orthogonal_eq_bot_iff, Submodule.orthogonal_closure]
  exact gaussianHermiteSpan_orthogonal_eq_bot n hn

/-- The normalized multivariate complex Hermites, packaged as a complete
Hilbert basis of Gaussian `L²`. -/
def gaussianHermiteHilbertBasis (n : ℕ) (hn : 0 < n) :
    HilbertBasis (ComplexHermite.HermiteMultiIndex n) ℂ
      (Lp ℂ 2 (complexGaussianMeasure n)) :=
  HilbertBasis.mkOfOrthogonalEqBot
    (ComplexHermite.orthonormal_hermiteL2Family_gaussian n hn)
    (by
      change (gaussianHermiteSpan n hn)ᗮ = ⊥
      exact gaussianHermiteSpan_orthogonal_eq_bot n hn)

@[simp] theorem gaussianHermiteHilbertBasis_apply (n : ℕ) (hn : 0 < n)
    (pq : ComplexHermite.HermiteMultiIndex n) :
    gaussianHermiteHilbertBasis n hn pq = multivariateNormalizedL2 n hn pq.1 pq.2 := by
  simp [gaussianHermiteHilbertBasis, ComplexHermite.hermiteL2Family,
    multivariateNormalizedL2]

end
end GinibrePoincare
Analysis GinibrePoincare/Analysis/GaussianHermiteMoments.lean #
import GinibrePoincare.Analysis.MultivariateHermiteMonomialSpan
import GinibrePoincare.Analysis.GaussianPolynomialCompleteness
import Mathlib.Probability.Distributions.Gaussian.Real
import Mathlib.Probability.Moments.IntegrableExpMul

/-! # Polynomial Gaussian `L²` vectors and Hermite moments -/

open MeasureTheory
open scoped BigOperators ComplexConjugate ENNReal

namespace GinibrePoincare

noncomputable section

open ComplexHermite

/-- All coordinate/conjugate-coordinate monomials, as pointwise functions. -/
def configurationMixedMonomialSpan (n : ℕ) :
    Submodule ℂ (Configuration n → ℂ) :=
  Submodule.span ℂ {f | ∃ p q : Fin n → ℕ,
    f = fun z ↦ ∏ i, z i ^ p i * (conj (z i)) ^ q i}

private theorem configurationMixedMonomialSpan_one (n : ℕ) :
    (1 : Configuration n → ℂ) ∈ configurationMixedMonomialSpan n := by
  apply Submodule.subset_span
  refine ⟨0, 0, ?_⟩
  funext z
  simp

private theorem configurationMixedMonomialSpan_mul {n : ℕ}
    {f g : Configuration n → ℂ}
    (hf : f ∈ configurationMixedMonomialSpan n)
    (hg : g ∈ configurationMixedMonomialSpan n) :
    f * g ∈ configurationMixedMonomialSpan n := by
  induction hf using Submodule.span_induction with
  | mem f hf =>
      rcases hf with ⟨p, q, rfl⟩
      induction hg using Submodule.span_induction with
      | mem g hg =>
          rcases hg with ⟨r, s, rfl⟩
          apply Submodule.subset_span
          refine ⟨p + r, q + s, ?_⟩
          funext z
          simp only [Pi.add_apply, Pi.mul_apply, pow_add]
          rw [← Finset.prod_mul_distrib]
          apply Finset.prod_congr rfl
          intro i hi
          ring
      | zero => simp
      | add x y hx hy ihx ihy => simpa [mul_add] using
          (configurationMixedMonomialSpan n).add_mem ihx ihy
      | smul c x hx ih =>
          simpa [Pi.smul_apply, smul_eq_mul, mul_assoc] using
            (configurationMixedMonomialSpan n).smul_mem c ih
  | zero => simp
  | add x y hx hy ihx ihy => simpa [add_mul] using
      (configurationMixedMonomialSpan n).add_mem ihx ihy
  | smul c x hx ih =>
      simpa [Pi.smul_apply, smul_eq_mul, mul_assoc] using
        (configurationMixedMonomialSpan n).smul_mem c ih

private theorem configurationMixedMonomialSpan_pow {n : ℕ}
    {f : Configuration n → ℂ} (hf : f ∈ configurationMixedMonomialSpan n)
    (k : ℕ) : f ^ k ∈ configurationMixedMonomialSpan n := by
  induction k with
  | zero => simpa using configurationMixedMonomialSpan_one n
  | succ k ih => simpa [pow_succ] using configurationMixedMonomialSpan_mul ih hf

theorem configurationRealPairing_complex_mem_mixedMonomialSpan {n : ℕ}
    (t : Configuration n) :
    (fun z ↦ (configurationRealPairing t z : ℂ)) ∈
      configurationMixedMonomialSpan n := by
  rw [show (fun z ↦ (configurationRealPairing t z : ℂ)) =
      ∑ i : Fin n, (2 : ℂ)⁻¹ •
        ((conj (t i)) • (fun z : Configuration n ↦ z i) +
          (t i) • (fun z : Configuration n ↦ conj (z i))) by
    funext z
    apply Complex.ext <;>
      simp [configurationRealPairing, Finset.sum_apply] <;> ring
    all_goals simp]
  apply Submodule.sum_mem
  intro i hi
  apply Submodule.smul_mem
  apply Submodule.add_mem
  · apply Submodule.smul_mem
    apply Submodule.subset_span
    refine ⟨Function.update 0 i 1, 0, ?_⟩
    funext z
    simp [Function.update_apply, apply_ite]
  · apply Submodule.smul_mem
    apply Submodule.subset_span
    refine ⟨0, Function.update 0 i 1, ?_⟩
    funext z
    simp [Function.update_apply, apply_ite]

/-- Every pointwise polynomial in coordinates and conjugate coordinates is
`L²`, and its `L²` class lies in the algebraic Hermite span. -/
theorem mixedMonomialSpan_toLp_mem_gaussianHermiteSpan (n : ℕ) (hn : 0 < n)
    {f : Configuration n → ℂ} (hf : f ∈ configurationMixedMonomialSpan n) :
    ∃ hmem : MemLp f 2 (complexGaussianMeasure n),
      hmem.toLp f ∈ gaussianHermiteSpan n hn := by
  induction hf using Submodule.span_induction with
  | mem f hf =>
      rcases hf with ⟨p, q, rfl⟩
      have hpoint : (fun z : Configuration n ↦
          ∏ i, z i ^ p i * (conj (z i)) ^ q i) ∈
          multivariateNormalizedRectangleSpan n hn p q := by
        rw [multivariateNormalizedRectangleSpan_eq_mixedMonomialRectangleSpan]
        apply Submodule.subset_span
        exact ⟨p, q, fun _ ↦ le_rfl, fun _ ↦ le_rfl, rfl⟩
      have lift : ∀ {F : Configuration n → ℂ},
          F ∈ multivariateNormalizedRectangleSpan n hn p q →
          ∃ hmem : MemLp F 2 (complexGaussianMeasure n),
            hmem.toLp F ∈ gaussianHermiteSpan n hn := by
        intro F hF
        induction hF using Submodule.span_induction with
        | mem g hg =>
            rcases hg with ⟨a, b, ha, hb, rfl⟩
            exact ⟨memLp_two_multivariateNormalized n hn a b,
              multivariateNormalizedL2_mem_span n hn a b⟩
        | zero => exact ⟨MemLp.zero, by simp⟩
        | add x y hx hy ihx ihy =>
            rcases ihx with ⟨hxmem, hxspan⟩
            rcases ihy with ⟨hymem, hyspan⟩
            refine ⟨hxmem.add hymem, ?_⟩
            rw [MemLp.toLp_add hxmem hymem]
            exact (gaussianHermiteSpan n hn).add_mem hxspan hyspan
        | smul c x hx ih =>
            rcases ih with ⟨hxmem, hxspan⟩
            refine ⟨hxmem.const_smul c, ?_⟩
            rw [MemLp.toLp_const_smul c hxmem]
            exact (gaussianHermiteSpan n hn).smul_mem c hxspan
      exact lift hpoint
  | zero => exact ⟨MemLp.zero, by simp⟩
  | add x y hx hy ihx ihy =>
      rcases ihx with ⟨hxmem, hxspan⟩
      rcases ihy with ⟨hymem, hyspan⟩
      refine ⟨hxmem.add hymem, ?_⟩
      rw [MemLp.toLp_add hxmem hymem]
      exact (gaussianHermiteSpan n hn).add_mem hxspan hyspan
  | smul c x hx ih =>
      rcases ih with ⟨hxmem, hxspan⟩
      refine ⟨hxmem.const_smul c, ?_⟩
      rw [MemLp.toLp_const_smul c hxmem]
      exact (gaussianHermiteSpan n hn).smul_mem c hxspan

/-- A coordinate/conjugate-coordinate monomial belongs to Gaussian `L²`. -/
theorem memLp_two_multivariateMixedMonomial (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) :
    MemLp (fun z : Configuration n ↦
      ∏ i, z i ^ p i * (conj (z i)) ^ q i) 2
      (complexGaussianMeasure n) := by
  apply (mixedMonomialSpan_toLp_mem_gaussianHermiteSpan n hn ?_).choose
  apply Submodule.subset_span
  exact ⟨p, q, rfl⟩

/-- A coordinate/conjugate-coordinate monomial packaged in Gaussian `L²`. -/
def multivariateMixedMonomialL2 (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) : Lp ℂ 2 (complexGaussianMeasure n) :=
  (memLp_two_multivariateMixedMonomial n hn p q).toLp
    (fun z : Configuration n ↦
      ∏ i, z i ^ p i * (conj (z i)) ^ q i)

theorem multivariateMixedMonomialL2_mem_gaussianHermiteSpan
    (n : ℕ) (hn : 0 < n) (p q : Fin n → ℕ) :
    multivariateMixedMonomialL2 n hn p q ∈ gaussianHermiteSpan n hn := by
  have hgen : (fun z : Configuration n ↦
      ∏ i, z i ^ p i * (conj (z i)) ^ q i) ∈
      configurationMixedMonomialSpan n := by
    apply Submodule.subset_span
    exact ⟨p, q, rfl⟩
  obtain ⟨hmem, hspan⟩ :=
    mixedMonomialSpan_toLp_mem_gaussianHermiteSpan n hn hgen
  simpa [multivariateMixedMonomialL2] using hspan

/-- Every power of a directional real pairing, with the Fourier factor
`I^k`, represents a vector in the Hermite span. -/
theorem exists_memLp_lineMomentPolynomial_mem_gaussianHermiteSpan
    (n : ℕ) (hn : 0 < n) (t : Configuration n) (k : ℕ) :
    ∃ hmem : MemLp (fun z ↦
        ((configurationRealPairing t z : ℂ) * Complex.I) ^ k) 2
        (complexGaussianMeasure n),
      hmem.toLp (fun z ↦
        ((configurationRealPairing t z : ℂ) * Complex.I) ^ k) ∈
        gaussianHermiteSpan n hn := by
  apply mixedMonomialSpan_toLp_mem_gaussianHermiteSpan n hn
  have hp := configurationMixedMonomialSpan_pow
    (configurationRealPairing_complex_mem_mixedMonomialSpan t) k
  convert (configurationMixedMonomialSpan n).smul_mem (Complex.I ^ k) hp using 1
  ext z
  simp [mul_pow, Pi.smul_apply, smul_eq_mul, mul_comm]

/-- Orthogonality to every normalized Hermite tensor forces every
directional Fourier moment to vanish. -/
theorem gaussianL2LineMoment_eq_zero_of_orthogonal_hermites
    (n : ℕ) (hn : 0 < n)
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (horth : ∀ p q : Fin n → ℕ,
      inner ℂ (multivariateNormalizedL2 n hn p q) v = 0)
    (t : Configuration n) (k : ℕ) :
    gaussianL2LineMoment v t k = 0 := by
  have hspan : ∀ x ∈ gaussianHermiteSpan n hn, inner ℂ x v = 0 := by
    intro x hx
    induction hx using Submodule.span_induction with
    | mem x hx =>
        rcases hx with ⟨⟨p, q⟩, rfl⟩
        exact horth p q
    | zero => simp
    | add x y hx hy ihx ihy => rw [inner_add_left, ihx, ihy, add_zero]
    | smul c x hx ih => rw [inner_smul_left, ih, mul_zero]
  let nt : Configuration n := -t
  obtain ⟨hmem, hmemSpan⟩ :=
    exists_memLp_lineMomentPolynomial_mem_gaussianHermiteSpan n hn nt k
  have hz := hspan _ hmemSpan
  rw [MeasureTheory.L2.inner_def] at hz
  rw [gaussianL2LineMoment]
  calc
    ∫ z, v z * ((configurationRealPairing t z : ℂ) * Complex.I) ^ k
        ∂complexGaussianMeasure n =
        ∫ z, inner ℂ (hmem.toLp (fun z ↦
          ((configurationRealPairing nt z : ℂ) * Complex.I) ^ k) z) (v z)
          ∂complexGaussianMeasure n := by
            apply integral_congr_ae
            filter_upwards [hmem.coeFn_toLp] with z hzmem
            rw [hzmem, RCLike.inner_apply]
            have hneg : configurationRealPairing nt z =
                -configurationRealPairing t z := by
              unfold nt configurationRealPairing
              simp only [Pi.neg_apply, Complex.neg_re, Complex.neg_im,
                neg_mul, ← Finset.sum_neg_distrib]
              apply Finset.sum_congr rfl
              intro i hi
              ring
            rw [hneg]
            simp only [map_pow, map_mul, Complex.conj_ofReal, Complex.conj_I]
            simp [mul_pow]
    _ = 0 := hz

private def complexPairingCLM (t : ℂ) : ℂ →L[ℝ] ℝ :=
  t.re • Complex.reCLM + t.im • Complex.imCLM

@[simp] private theorem complexPairingCLM_apply (t z : ℂ) :
    complexPairingCLM t z = t.re * z.re + t.im * z.im := by
  simp [complexPairingCLM]

private theorem integrable_exp_mul_complexPairing (n : ℕ) (t : ℂ) (r : ℝ) :
    Integrable (fun z : ℂ ↦ Real.exp (r * complexPairingCLM t z))
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  let μ : Measure ℂ := complexCoordinateGaussianProbability n
  letI : ProbabilityTheory.IsGaussian μ :=
    isGaussian_complexCoordinateGaussianProbability n
  let L := complexPairingCLM t
  have hg := ProbabilityTheory.integrable_exp_mul_gaussianReal
    (t := r) (μ := ∫ z, L z ∂μ) (v := (ProbabilityTheory.variance L μ).toNNReal)
  rw [← ProbabilityTheory.IsGaussian.map_eq_gaussianReal L] at hg
  exact hg.comp_aemeasurable L.continuous.aemeasurable

/-- Every real exponential of a directional pairing is Gaussian-integrable. -/
theorem integrable_exp_mul_configurationRealPairing
    (n : ℕ) (t : Configuration n) (r : ℝ) :
    Integrable (fun z ↦ Real.exp (r * configurationRealPairing t z))
      (complexGaussianMeasure n) := by
  unfold complexGaussianMeasure complexGaussianProbability configurationRealPairing
  simp only [ProbabilityMeasure.toMeasure_pi]
  rw [show (fun z : Configuration n ↦
      Real.exp (r * ∑ i, ((t i).re * (z i).re + (t i).im * (z i).im))) =
      fun z ↦ ∏ i, Real.exp (r * complexPairingCLM (t i) (z i)) by
    funext z
    rw [← Real.exp_sum, Finset.mul_sum]
    congr 1]
  exact Integrable.fintype_prod fun i ↦
    integrable_exp_mul_complexPairing n (t i) r

/-- Absolute linear exponentials of a directional pairing are integrable. -/
theorem integrable_exp_mul_abs_configurationRealPairing
    (n : ℕ) (t : Configuration n) (r : ℝ) :
    Integrable (fun z ↦ Real.exp (r * |configurationRealPairing t z|))
      (complexGaussianMeasure n) :=
  ProbabilityTheory.integrable_exp_mul_abs
    (integrable_exp_mul_configurationRealPairing n t r)
    (integrable_exp_mul_configurationRealPairing n t (-r))

/-- Terms of the exponential expansion of the Fourier test. -/
def gaussianL2FourierSeriesTerm {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n)
    (k : ℕ) (z : Configuration n) : ℂ :=
  v z * (((configurationRealPairing t z : ℂ) * Complex.I) ^ k /
    (k.factorial : ℂ))

theorem hasSum_gaussianL2FourierSeriesTerm {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t z : Configuration n) :
    HasSum (fun k ↦ gaussianL2FourierSeriesTerm v t k z)
      (v z * configurationFourierCharacter t z) := by
  unfold gaussianL2FourierSeriesTerm configurationFourierCharacter
  simpa [Complex.exp_eq_exp_ℂ] using
    (NormedSpace.expSeries_div_hasSum_exp
      ((configurationRealPairing t z : ℂ) * Complex.I)).mul_left (v z)

private theorem memLp_two_exp_abs_configurationRealPairing {n : ℕ}
    (t : Configuration n) :
    MemLp (fun z ↦ Real.exp |configurationRealPairing t z|) 2
      (complexGaussianMeasure n) := by
  rw [memLp_two_iff_integrable_sq_norm]
  · convert integrable_exp_mul_abs_configurationRealPairing n t 2 using 1
    funext z
    simp only [Real.norm_eq_abs, abs_of_pos (Real.exp_pos _)]
    rw [pow_two, ← Real.exp_add]
    congr 1
    ring
  · exact (Real.continuous_exp.comp
      (continuous_configurationRealPairing_left t).abs).aestronglyMeasurable

private theorem integrable_fourierSeriesMajorant {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) :
    Integrable (fun z ↦ ‖v z‖ * Real.exp |configurationRealPairing t z|)
      (complexGaussianMeasure n) := by
  exact (Lp.memLp v).norm.integrable_mul
    (memLp_two_exp_abs_configurationRealPairing t)

/-- The termwise Fourier-series integrals sum to the Fourier test. -/
theorem hasSum_integral_gaussianL2FourierSeriesTerm {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) :
    HasSum (fun k ↦ ∫ z, gaussianL2FourierSeriesTerm v t k z
        ∂complexGaussianMeasure n)
      (gaussianL2FourierTest v t) := by
  have hdom := integrable_fourierSeriesMajorant v t
  have hsbound : ∀ z : Configuration n,
      HasSum (fun k : ℕ ↦ ‖v z‖ *
        (|configurationRealPairing t z| ^ k / k.factorial))
        (‖v z‖ * Real.exp |configurationRealPairing t z|) := by
    intro z
    simpa [Real.exp_eq_exp_ℝ] using
      (NormedSpace.expSeries_div_hasSum_exp
        |configurationRealPairing t z|).mul_left ‖v z‖
  have hs := MeasureTheory.hasSum_integral_of_dominated_convergence
    (fun k z ↦ ‖v z‖ *
      (|configurationRealPairing t z| ^ k / k.factorial))
    (F := fun k z ↦ gaussianL2FourierSeriesTerm v t k z)
    (f := fun z ↦ v z * configurationFourierCharacter t z)
    (fun k ↦
      ((Lp.aestronglyMeasurable v).mul
        (((((Complex.continuous_ofReal.comp
          (continuous_configurationRealPairing_left t)).mul continuous_const).pow k).div_const _).aestronglyMeasurable)))
    (fun k ↦ Filter.Eventually.of_forall fun z ↦ by
      simp [gaussianL2FourierSeriesTerm, norm_mul, Real.norm_eq_abs,
        abs_pow, Nat.cast_ofNat])
    (Filter.Eventually.of_forall fun z ↦ (hsbound z).summable)
    (by simpa only [(hsbound _).tsum_eq] using hdom)
    (Filter.Eventually.of_forall fun z ↦
      hasSum_gaussianL2FourierSeriesTerm v t z)
  simpa [gaussianL2FourierTest] using hs

/-- Orthogonality to every Hermite tensor makes the full Gaussian Fourier
test vanish at every frequency. -/
theorem gaussianL2FourierTest_eq_zero_of_orthogonal_hermites
    (n : ℕ) (hn : 0 < n)
    (v : Lp ℂ 2 (complexGaussianMeasure n))
    (horth : ∀ p q : Fin n → ℕ,
      inner ℂ (multivariateNormalizedL2 n hn p q) v = 0)
    (t : Configuration n) : gaussianL2FourierTest v t = 0 := by
  have hs := hasSum_integral_gaussianL2FourierSeriesTerm v t
  have hz : ∀ k : ℕ,
      (∫ z, gaussianL2FourierSeriesTerm v t k z
        ∂complexGaussianMeasure n) = 0 := by
    intro k
    unfold gaussianL2FourierSeriesTerm
    rw [show (∫ z, v z *
        (((configurationRealPairing t z : ℂ) * Complex.I) ^ k /
          (k.factorial : ℂ)) ∂complexGaussianMeasure n) =
        gaussianL2LineMoment v t k / (k.factorial : ℂ) by
      rw [gaussianL2LineMoment]
      rw [show (fun z ↦ v z *
          (((configurationRealPairing t z : ℂ) * Complex.I) ^ k /
            (k.factorial : ℂ))) = fun z ↦
          (v z * ((configurationRealPairing t z : ℂ) * Complex.I) ^ k) /
            (k.factorial : ℂ) by funext z; ring]
      rw [integral_div]]
    rw [gaussianL2LineMoment_eq_zero_of_orthogonal_hermites n hn v horth t k]
    simp
  simpa [hz] using hs.tsum_eq.symm

end
end GinibrePoincare
Analysis GinibrePoincare/Analysis/GaussianPolynomialCompleteness.lean #
import GinibrePoincare.Analysis.GaussianPolynomialDensity
import GinibrePoincare.Analysis.GaussianPolynomialIntegrability
import Mathlib.MeasureTheory.Function.L1Space.Integrable

/-! # Fourier tests for Gaussian polynomial completeness -/

open MeasureTheory
open scoped BigOperators ComplexConjugate ENNReal

namespace GinibrePoincare

noncomputable section

/-- A product-form Fernique estimate for the finite complex Gaussian law. -/
theorem exists_integrable_exp_sum_normSq_complexGaussianMeasure (n : ℕ) :
    ∃ C : ℝ, 0 < C ∧ Integrable
      (fun z : Configuration n ↦ Real.exp (C * ∑ i, ‖z i‖ ^ 2))
      (complexGaussianMeasure n) := by
  let μ : Measure ℂ := complexCoordinateGaussianProbability n
  letI : ProbabilityTheory.IsGaussian μ :=
    isGaussian_complexCoordinateGaussianProbability n
  obtain ⟨C, hC, hInt⟩ :=
    ProbabilityTheory.IsGaussian.exists_integrable_exp_sq μ
  refine ⟨C, hC, ?_⟩
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  have hp : Integrable
      (fun z : Configuration n ↦ ∏ i, Real.exp (C * ‖z i‖ ^ 2))
      (Measure.pi fun _ : Fin n ↦ μ) :=
    Integrable.fintype_prod fun _ ↦ hInt
  convert hp using 1
  funext z
  rw [← Real.exp_sum]
  congr 1
  rw [Finset.mul_sum]

/-- The standard real Euclidean pairing on complex configuration space. -/
def configurationRealPairing {n : ℕ}
    (t z : Configuration n) : ℝ :=
  ∑ i : Fin n, ((t i).re * (z i).re + (t i).im * (z i).im)

theorem continuous_configurationRealPairing_left {n : ℕ}
    (t : Configuration n) :
    Continuous (configurationRealPairing t) := by
  unfold configurationRealPairing
  fun_prop

theorem configurationRealPairing_add {n : ℕ}
    (s t z : Configuration n) :
    configurationRealPairing (s + t) z =
      configurationRealPairing s z + configurationRealPairing t z := by
  simp only [configurationRealPairing, Pi.add_apply]
  rw [← Finset.sum_add_distrib]
  apply Finset.sum_congr rfl
  intro i hi
  simp only [Complex.add_re, Complex.add_im]
  ring

/-- Unit-modulus Fourier character associated with a real frequency on
underlying real configuration space. -/
def configurationFourierCharacter {n : ℕ}
    (t z : Configuration n) : ℂ :=
  Complex.exp ((configurationRealPairing t z : ℂ) * Complex.I)

theorem continuous_configurationFourierCharacter {n : ℕ}
    (t : Configuration n) :
    Continuous (configurationFourierCharacter t) := by
  unfold configurationFourierCharacter
  exact Complex.continuous_exp.comp
    ((Complex.continuous_ofReal.comp
      (continuous_configurationRealPairing_left t)).mul continuous_const)

@[simp] theorem norm_configurationFourierCharacter {n : ℕ}
    (t z : Configuration n) :
    ‖configurationFourierCharacter t z‖ = 1 := by
  unfold configurationFourierCharacter
  exact Complex.norm_exp_ofReal_mul_I _

theorem configurationFourierCharacter_add {n : ℕ}
    (s t z : Configuration n) :
    configurationFourierCharacter (s + t) z =
      configurationFourierCharacter s z *
        configurationFourierCharacter t z := by
  unfold configurationFourierCharacter
  rw [configurationRealPairing_add]
  rw [show ((configurationRealPairing s z + configurationRealPairing t z : ℝ) : ℂ) *
      Complex.I = (configurationRealPairing s z : ℂ) * Complex.I +
        (configurationRealPairing t z : ℂ) * Complex.I by push_cast; ring]
  exact Complex.exp_add _ _

/-- Real scalar multiplication of a complex configuration, made explicit to
avoid changing the ambient scalar field. -/
def realScaleConfiguration {n : ℕ} (r : ℝ) (t : Configuration n) :
    Configuration n := fun i ↦ (r : ℂ) * t i

theorem configurationRealPairing_realScale {n : ℕ}
    (r : ℝ) (t z : Configuration n) :
    configurationRealPairing (realScaleConfiguration r t) z =
      r * configurationRealPairing t z := by
  unfold configurationRealPairing realScaleConfiguration
  rw [Finset.mul_sum]
  apply Finset.sum_congr rfl
  intro i hi
  simp only [Complex.mul_re, Complex.ofReal_re, Complex.ofReal_im, zero_mul,
    sub_zero, Complex.mul_im, zero_add]
  ring

/-- A fixed real linear coordinate pairing has every finite Gaussian
moment. -/
theorem memLp_configurationRealPairing_of_ne_top {n : ℕ}
    (t : Configuration n) (p : ℝ≥0∞) (hp : p ≠ ⊤) :
    MemLp (configurationRealPairing t) p (complexGaussianMeasure n) := by
  let μ : Measure ℂ := complexCoordinateGaussianProbability n
  letI : ProbabilityTheory.IsGaussian μ :=
    isGaussian_complexCoordinateGaussianProbability n
  have hid : MemLp (id : ℂ → ℂ) p μ :=
    ProbabilityTheory.IsGaussian.memLp_id μ p hp
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  unfold configurationRealPairing
  induction (Finset.univ : Finset (Fin n)) using Finset.induction_on with
  | empty => simp
  | @insert i s hi ih =>
      have hterm : MemLp (fun z : Configuration n ↦
          (t i).re * (z i).re + (t i).im * (z i).im) p
          (Measure.pi fun _ : Fin n ↦ μ) := by
        have hev : MemLp (fun z : Configuration n ↦ z i) p
            (Measure.pi fun _ : Fin n ↦ μ) := by
          change MemLp (id ∘ Function.eval i) p
            (Measure.pi fun _ : Fin n ↦ μ)
          exact hid.comp_measurePreserving
            (measurePreserving_eval (μ := fun _ : Fin n ↦ μ) i)
        exact (hev.re.const_mul (t i).re).add (hev.im.const_mul (t i).im)
      simp_rw [Finset.sum_insert hi]
      convert hterm.add ih using 1
      ext z
      rfl

/-- A fixed real linear coordinate pairing belongs to Gaussian `L²`. -/
theorem memLp_configurationRealPairing {n : ℕ} (t : Configuration n) :
    MemLp (configurationRealPairing t) 2 (complexGaussianMeasure n) :=
  memLp_configurationRealPairing_of_ne_top t 2 (by norm_num)

/-- Cauchy--Schwarz domination required for differentiating the Fourier test
of an arbitrary Gaussian `L²` vector. -/
theorem integrable_norm_mul_abs_configurationRealPairing {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) :
    Integrable (fun z ↦ ‖v z‖ * |configurationRealPairing t z|)
      (complexGaussianMeasure n) := by
  have h := (Lp.memLp v).norm.integrable_mul
    (memLp_configurationRealPairing t).norm
  convert h using 1
  ext z
  simp [Real.norm_eq_abs]

/-- All directional moments of a Gaussian `L²` vector are integrable. -/
theorem integrable_norm_mul_abs_configurationRealPairing_pow {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) (k : ℕ) :
    Integrable (fun z ↦ ‖v z‖ * |configurationRealPairing t z| ^ k)
      (complexGaussianMeasure n) := by
  cases k with
  | zero =>
      simpa using (Lp.memLp v).integrable (by norm_num : (1 : ℝ≥0∞) ≤ 2) |>.norm
  | succ k =>
      let q : ℝ≥0∞ := (↑(k + 1) : ℝ≥0∞)
      have hq0 : q ≠ 0 := by simp [q]
      have hqtop : q ≠ ⊤ := by simp [q]
      have hp : MemLp (configurationRealPairing t) (2 * q)
          (complexGaussianMeasure n) :=
        memLp_configurationRealPairing_of_ne_top t (2 * q)
          (ENNReal.mul_ne_top (by norm_num) hqtop)
      have hpow : MemLp (fun z ↦ ‖configurationRealPairing t z‖ ^ q.toReal) 2
          (complexGaussianMeasure n) := by
        have hm := (memLp_norm_rpow_iff
          (continuous_configurationRealPairing_left t).aestronglyMeasurable
          hq0 hqtop).2 hp
        rw [show 2 * q / q = 2 by
          rw [div_eq_mul_inv, mul_assoc,
            ENNReal.mul_inv_cancel hq0 hqtop, mul_one]] at hm
        exact hm
      have hqreal : q.toReal = (k + 1 : ℕ) := by
        rw [show q = (k : ℝ≥0∞) + 1 by simp [q], ENNReal.toReal_add]
        · simp
        · simp
        · simp
      have hpowNat : MemLp (fun z ↦ |configurationRealPairing t z| ^ (k + 1)) 2
          (complexGaussianMeasure n) := by
        convert hpow using 1
        ext z
        rw [hqreal]
        rw [show (↑(k + 1) : ℝ) = (k + 1 : ℕ) by norm_num,
          Real.rpow_natCast]
        simp [Real.norm_eq_abs]
      have h := (Lp.memLp v).norm.integrable_mul hpowNat
      convert h using 1
      ext z
      rfl

/-- The `k`th directional Fourier moment of a Gaussian `L²` vector. -/
def gaussianL2LineMoment {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) (k : ℕ) : ℂ :=
  ∫ z, v z * ((configurationRealPairing t z : ℂ) * Complex.I) ^ k
    ∂complexGaussianMeasure n

theorem integrable_gaussianL2LineMoment_integrand {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) (k : ℕ) :
    Integrable (fun z ↦ v z *
      ((configurationRealPairing t z : ℂ) * Complex.I) ^ k)
      (complexGaussianMeasure n) := by
  have hmeas : AEStronglyMeasurable (fun z ↦ v z *
      ((configurationRealPairing t z : ℂ) * Complex.I) ^ k)
      (complexGaussianMeasure n) := by
    have hc : Continuous (fun z ↦
        ((configurationRealPairing t z : ℂ) * Complex.I) ^ k) :=
      (((Complex.continuous_ofReal.comp
        (continuous_configurationRealPairing_left t)).mul continuous_const).pow k)
    exact (Lp.aestronglyMeasurable v).mul hc.aestronglyMeasurable
  rw [← integrable_norm_iff hmeas]
  convert integrable_norm_mul_abs_configurationRealPairing_pow v t k using 1
  ext z
  simp [norm_mul, Real.norm_eq_abs]

/-- Fourier line with `k` powers of the directional generator inserted. -/
def gaussianL2FourierMomentLine {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n)
    (k : ℕ) (r : ℝ) : ℂ :=
  ∫ z, (v z * ((configurationRealPairing t z : ℂ) * Complex.I) ^ k) *
      configurationFourierCharacter (realScaleConfiguration r t) z
    ∂complexGaussianMeasure n

/-- Pointwise derivative of a Fourier character along a real frequency
line.  This is the local derivative used by the dominated integral theorem. -/
theorem hasDerivAt_configurationFourierCharacter_line {n : ℕ}
    (r : ℝ) (t z : Configuration n) :
    HasDerivAt (fun s : ℝ ↦
      configurationFourierCharacter (realScaleConfiguration s t) z)
      (((configurationRealPairing t z : ℂ) * Complex.I) *
        configurationFourierCharacter (realScaleConfiguration r t) z) r := by
  rw [show (fun s : ℝ ↦
      configurationFourierCharacter (realScaleConfiguration s t) z) =
      fun s : ℝ ↦ Complex.exp
        ((s : ℂ) * ((configurationRealPairing t z : ℂ) * Complex.I)) by
    funext s
    unfold configurationFourierCharacter
    rw [configurationRealPairing_realScale]
    push_cast
    ring]
  let A : ℂ := (configurationRealPairing t z : ℂ) * Complex.I
  have hinner : HasDerivAt (fun w : ℂ ↦ w * A) A (r : ℂ) := by
    simpa using ((hasDerivAt_id (r : ℂ)).mul_const A)
  have hd : HasDerivAt (fun w : ℂ ↦ Complex.exp (w * A))
      (Complex.exp ((r : ℂ) * A) * A) (r : ℂ) :=
    (Complex.hasDerivAt_exp ((r : ℂ) * A)).comp (r : ℂ)
      hinner
  have hdr := hd.comp_ofReal
  simpa [A, configurationFourierCharacter, configurationRealPairing_realScale,
    mul_comm, mul_left_comm] using hdr

/-- Every Fourier character is in Gaussian `L²`; in fact it lies in every
finite or infinite `Lᵖ` because its norm is one. -/
theorem memLp_configurationFourierCharacter {n : ℕ}
    (t : Configuration n) (p : ℝ≥0∞) :
    MemLp (configurationFourierCharacter t) p
      (complexGaussianMeasure n) := by
  apply MemLp.of_bound
    (continuous_configurationFourierCharacter t).aestronglyMeasurable 1
  exact Filter.Eventually.of_forall fun z ↦ by simp

/-- The product of a Gaussian `L²` vector with a Fourier character is
integrable.  This is the bounded exponential test needed for the moment
uniqueness argument. -/
theorem integrable_mul_configurationFourierCharacter {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) :
    Integrable (fun z ↦ v z * configurationFourierCharacter t z)
      (complexGaussianMeasure n) := by
  exact (Lp.memLp v).integrable_mul
    (memLp_configurationFourierCharacter t 2)

/-- Every Hermite moment of a Gaussian `L²` vector is absolutely
integrable.  This supplies the moment side of differentiation under the
Fourier integral. -/
theorem integrable_mul_multivariateNormalized {n : ℕ} (hn : 0 < n)
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (p q : Fin n → ℕ) :
    Integrable (fun z ↦ v z *
      ComplexHermite.multivariateNormalized n hn p q z)
      (complexGaussianMeasure n) := by
  exact (Lp.memLp v).integrable_mul
    (ComplexHermite.memLp_two_multivariateNormalized n hn p q)

/-- Fourier transform of the finite complex measure with density represented
by a Gaussian `L²` vector. -/
def gaussianL2FourierTest {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) : ℂ :=
  ∫ z, v z * configurationFourierCharacter t z
    ∂complexGaussianMeasure n

/-- Differentiation of the Gaussian Fourier test along a fixed real
frequency direction. -/
theorem hasDerivAt_gaussianL2FourierTest_line {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) (r : ℝ) :
    HasDerivAt (fun s : ℝ ↦
      gaussianL2FourierTest v (realScaleConfiguration s t))
      (∫ z, v z * (((configurationRealPairing t z : ℂ) * Complex.I) *
        configurationFourierCharacter (realScaleConfiguration r t) z)
        ∂complexGaussianMeasure n) r := by
  let F : ℝ → Configuration n → ℂ := fun s z ↦
    v z * configurationFourierCharacter (realScaleConfiguration s t) z
  let F' : ℝ → Configuration n → ℂ := fun s z ↦
    v z * (((configurationRealPairing t z : ℂ) * Complex.I) *
      configurationFourierCharacter (realScaleConfiguration s t) z)
  let B : Configuration n → ℝ := fun z ↦
    ‖v z‖ * |configurationRealPairing t z|
  have hFint : Integrable (F r) (complexGaussianMeasure n) :=
    integrable_mul_configurationFourierCharacter v (realScaleConfiguration r t)
  have hFmeas : ∀ᶠ s in nhds r,
      AEStronglyMeasurable (F s) (complexGaussianMeasure n) :=
    Filter.Eventually.of_forall fun s ↦
      (integrable_mul_configurationFourierCharacter v
        (realScaleConfiguration s t)).aestronglyMeasurable
  have hF'meas : AEStronglyMeasurable (F' r)
      (complexGaussianMeasure n) := by
    exact (Lp.aestronglyMeasurable v).mul
      (((Complex.continuous_ofReal.comp
        (continuous_configurationRealPairing_left t)).mul
        continuous_const).aestronglyMeasurable.mul
          (continuous_configurationFourierCharacter
            (realScaleConfiguration r t)).aestronglyMeasurable)
  have hbound : ∀ᵐ z ∂complexGaussianMeasure n,
      ∀ s ∈ Set.univ, ‖F' s z‖ ≤ B z := by
    filter_upwards with z s hs
    simp [F', B, norm_mul, Real.norm_eq_abs]
  have hdiff : ∀ᵐ z ∂complexGaussianMeasure n,
      ∀ s ∈ Set.univ, HasDerivAt (F · z) (F' s z) s := by
    filter_upwards with z s hs
    exact (hasDerivAt_configurationFourierCharacter_line s t z).const_mul (v z)
  have h := hasDerivAt_integral_of_dominated_loc_of_deriv_le
    (s := Set.univ) (x₀ := r) (F := F) (F' := F') (bound := B)
    Filter.univ_mem hFmeas hFint hF'meas hbound
    (integrable_norm_mul_abs_configurationRealPairing v t) hdiff
  exact h.2

/-- The inserted-moment Fourier lines form a derivative ladder. -/
theorem hasDerivAt_gaussianL2FourierMomentLine {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n)
    (k : ℕ) (r : ℝ) :
    HasDerivAt (gaussianL2FourierMomentLine v t k)
      (gaussianL2FourierMomentLine v t (k + 1) r) r := by
  let A : Configuration n → ℂ := fun z ↦
    (configurationRealPairing t z : ℂ) * Complex.I
  let F : ℝ → Configuration n → ℂ := fun s z ↦
    (v z * A z ^ k) * configurationFourierCharacter
      (realScaleConfiguration s t) z
  let F' : ℝ → Configuration n → ℂ := fun s z ↦
    (v z * A z ^ k) * (A z * configurationFourierCharacter
      (realScaleConfiguration s t) z)
  let B : Configuration n → ℝ := fun z ↦
    ‖v z‖ * |configurationRealPairing t z| ^ (k + 1)
  have hbase := integrable_gaussianL2LineMoment_integrand v t k
  have hchar (s : ℝ) : AEStronglyMeasurable
      (configurationFourierCharacter (realScaleConfiguration s t))
      (complexGaussianMeasure n) :=
    (continuous_configurationFourierCharacter
      (realScaleConfiguration s t)).aestronglyMeasurable
  have hFint : Integrable (F r) (complexGaussianMeasure n) := by
    exact hbase.mul_bdd (c := 1) (hchar r)
      (Filter.Eventually.of_forall fun z ↦ by simp)
  have hFmeas : ∀ᶠ s in nhds r,
      AEStronglyMeasurable (F s) (complexGaussianMeasure n) :=
    Filter.Eventually.of_forall fun s ↦
      (hbase.mul_bdd (c := 1) (hchar s)
        (Filter.Eventually.of_forall fun z ↦ by simp)).aestronglyMeasurable
  have hA : Continuous A := by
    unfold A
    exact (Complex.continuous_ofReal.comp
      (continuous_configurationRealPairing_left t)).mul continuous_const
  have hF'meas : AEStronglyMeasurable (F' r)
      (complexGaussianMeasure n) :=
    ((Lp.aestronglyMeasurable v).mul (hA.pow k).aestronglyMeasurable).mul
      (hA.aestronglyMeasurable.mul (hchar r))
  have hbound : ∀ᵐ z ∂complexGaussianMeasure n,
      ∀ s ∈ Set.univ, ‖F' s z‖ ≤ B z := by
    filter_upwards with z s hs
    simp [F', B, A, norm_mul, Real.norm_eq_abs, pow_succ]
    rw [mul_assoc]
  have hdiff : ∀ᵐ z ∂complexGaussianMeasure n,
      ∀ s ∈ Set.univ, HasDerivAt (F · z) (F' s z) s := by
    filter_upwards with z s hs
    exact (hasDerivAt_configurationFourierCharacter_line s t z).const_mul
      (v z * A z ^ k)
  have h := hasDerivAt_integral_of_dominated_loc_of_deriv_le
    (s := Set.univ) (x₀ := r) (F := F) (F' := F') (bound := B)
    Filter.univ_mem hFmeas hFint hF'meas hbound
    (integrable_norm_mul_abs_configurationRealPairing_pow v t (k + 1)) hdiff
  have hfun : gaussianL2FourierMomentLine v t k =
      fun s ↦ ∫ z, F s z ∂complexGaussianMeasure n := by
    rfl
  rw [hfun]
  have hmom : gaussianL2FourierMomentLine v t (k + 1) r =
      ∫ z, F' r z ∂complexGaussianMeasure n := by
    apply integral_congr_ae
    filter_upwards with z
    simp [gaussianL2FourierMomentLine, F', A, pow_succ, mul_assoc]
  rw [hmom]
  exact h.2

@[simp] theorem configurationFourierCharacter_zero {n : ℕ}
    (z : Configuration n) :
    configurationFourierCharacter 0 z = 1 := by
  simp [configurationFourierCharacter, configurationRealPairing]

theorem gaussianL2FourierTest_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianL2FourierTest v 0 = ∫ z, v z ∂complexGaussianMeasure n := by
  simp [gaussianL2FourierTest]

theorem gaussianL2FourierMomentLine_zero {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) (k : ℕ) :
    gaussianL2FourierMomentLine v t k 0 = gaussianL2LineMoment v t k := by
  have hzero : realScaleConfiguration 0 t = 0 := by
    ext i
    simp [realScaleConfiguration]
  unfold gaussianL2FourierMomentLine gaussianL2LineMoment
  rw [hzero]
  simp

theorem gaussianL2FourierMomentLine_zeroIndex {n : ℕ}
    (v : Lp ℂ 2 (complexGaussianMeasure n)) (t : Configuration n) (r : ℝ) :
    gaussianL2FourierMomentLine v t 0 r =
      gaussianL2FourierTest v (realScaleConfiguration r t) := by
  simp [gaussianL2FourierMomentLine, gaussianL2FourierTest]

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/GaussianPolynomialDensity.lean #
import GinibrePoincare.Analysis.MultivariateHermiteIntegrability
import GinibrePoincare.Analysis.PolynomialCompactApproximation
import Mathlib.MeasureTheory.Function.ContinuousMapDense

/-! # Polynomial subspaces in Gaussian `L²`

This module packages the multivariate complex Hermite polynomials as actual
vectors of Gaussian `L²`, and records the unconditional analytic density
input supplied by weak regularity: bounded continuous functions are dense in
that space.  This is the natural first reduction in the proof that the
Hermite polynomial span is dense.
-/

open MeasureTheory
open Filter
open scoped ENNReal

namespace GinibrePoincare

noncomputable section

open ComplexHermite

/-- A normalized multivariate complex Hermite polynomial, regarded as a
vector of Gaussian `L²`. -/
def multivariateNormalizedL2 (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) : Lp ℂ 2 (complexGaussianMeasure n) :=
  (memLp_two_multivariateNormalized n hn p q).toLp
    (multivariateNormalized n hn p q)

theorem multivariateNormalizedL2_coeFn (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) :
    multivariateNormalizedL2 n hn p q =ᵐ[complexGaussianMeasure n]
      multivariateNormalized n hn p q :=
  (memLp_two_multivariateNormalized n hn p q).coeFn_toLp

/-- The algebraic subspace generated by all multivariate normalized Hermite
polynomials. -/
def gaussianHermiteSpan (n : ℕ) (hn : 0 < n) :
    Submodule ℂ (Lp ℂ 2 (complexGaussianMeasure n)) :=
  Submodule.span ℂ (Set.range fun pq : (Fin n → ℕ) × (Fin n → ℕ) ↦
    multivariateNormalizedL2 n hn pq.1 pq.2)

theorem multivariateNormalizedL2_mem_span (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) :
    multivariateNormalizedL2 n hn p q ∈ gaussianHermiteSpan n hn := by
  apply Submodule.subset_span
  exact ⟨(p, q), rfl⟩

/-- Bounded continuous functions form an unconditionally dense class in the
finite-dimensional complex Gaussian `L²` space. -/
theorem gaussian_boundedContinuousFunction_dense (n : ℕ) :
    Dense (Lp.boundedContinuousFunction ℂ 2 (complexGaussianMeasure n) :
      Set (Lp ℂ 2 (complexGaussianMeasure n))) := by
  exact Lp.boundedContinuousFunction_dense ℂ (complexGaussianMeasure n)
    (by norm_num)

/-- Equivalently, the continuous map sending a bounded continuous function
to its Gaussian `L²` class has dense range. -/
theorem gaussian_boundedContinuous_toLp_denseRange (n : ℕ) :
    DenseRange (BoundedContinuousFunction.toLp (E := ℂ) 2
      (complexGaussianMeasure n) ℂ) := by
  simpa using (BoundedContinuousFunction.toLp_denseRange
    (p := (2 : ℝ≥0∞)) ℂ (complexGaussianMeasure n) ℂ (by norm_num))

/-- Closed balls exhaust configuration space in Gaussian measure; equivalently
their complements have mass tending to zero.  This is the tail input for the
cutoff step in polynomial approximation. -/
theorem tendsto_complexGaussianMeasure_compl_closedBall (n : ℕ) :
    Tendsto (fun R : ℕ ↦ complexGaussianMeasure n
      (Metric.closedBall (0 : Configuration n) R)ᶜ) atTop (nhds 0) := by
  have hlim : Tendsto (fun R : ℕ ↦ complexGaussianMeasure n
      (Metric.closedBall (0 : Configuration n) R)ᶜ) atTop
      (nhds (complexGaussianMeasure n
        (⋂ R : ℕ, (Metric.closedBall (0 : Configuration n) R)ᶜ))) := by
    refine tendsto_measure_iInter_atTop
      (fun R ↦ measurableSet_closedBall.compl.nullMeasurableSet)
      (fun R S hRS ↦ Set.compl_subset_compl.mpr ?_) ?_
    · exact Metric.closedBall_subset_closedBall (by exact_mod_cast hRS)
    · exact ⟨0, measure_ne_top _ _⟩
  have hinter : (⋂ R : ℕ,
      (Metric.closedBall (0 : Configuration n) R)ᶜ) = ∅ := by
    rw [← Set.compl_iUnion]
    simp
  simpa [hinter] using hlim

theorem exists_complexGaussianMeasure_compl_closedBall_lt (n : ℕ)
    {ε : ℝ≥0∞} (hε : 0 < ε) :
    ∃ R : ℕ, complexGaussianMeasure n
      (Metric.closedBall (0 : Configuration n) R)ᶜ < ε := by
  have heventually := (tendsto_order.1
    (tendsto_complexGaussianMeasure_compl_closedBall n)).2 ε hε
  exact heventually.exists

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/GaussianPolynomialIntegrability.lean #
import GinibrePoincare.Concrete.MeasureModel
import Mathlib.Probability.Distributions.Gaussian.Fernique
import GinibrePoincare.Analysis.HermiteWirtinger

/-! # Polynomial integrability under the Ginibre Gaussian reference law -/

open MeasureTheory
open scoped ENNReal BigOperators ComplexConjugate

namespace GinibrePoincare

noncomputable section

/-- The complex-coordinate law is a Gaussian measure on the underlying real
Banach space. -/
theorem isGaussian_complexCoordinateGaussianProbability (n : ℕ) :
    ProbabilityTheory.IsGaussian
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  let g : Measure ℝ := realCoordinateGaussianProbability n
  have hg : ProbabilityTheory.IsGaussian g := by
    unfold g realCoordinateGaussianProbability
    simp only [ProbabilityMeasure.coe_mk]
    infer_instance
  have hprod : ProbabilityTheory.IsGaussian (g.prod g) := by
    letI : ProbabilityTheory.IsGaussian g := hg
    infer_instance
  have hsource :
      (Measure.pi (fun _ : Fin 2 ↦ g)).map MeasurableEquiv.finTwoArrow =
        g.prod g :=
    (measurePreserving_finTwoArrow g).map_eq
  unfold complexCoordinateGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_map, ProbabilityMeasure.toMeasure_pi]
  rw [show Complex.measurableEquivPi.symm =
      Complex.equivRealProdCLM.symm ∘ MeasurableEquiv.finTwoArrow by
    funext x
    apply Complex.ext <;> simp [MeasurableEquiv.finTwoArrow]]
  have heq :
      (Measure.pi (fun _ : Fin 2 ↦ g)).map
          (Complex.equivRealProdCLM.symm ∘ MeasurableEquiv.finTwoArrow) =
        (g.prod g).map Complex.equivRealProdCLM.symm := by
    rw [← hsource]
    exact (Measure.map_map
      (μ := Measure.pi (fun _ : Fin 2 ↦ g))
      Complex.equivRealProdCLM.symm.continuous.measurable
      MeasurableEquiv.finTwoArrow.measurable).symm
  change ProbabilityTheory.IsGaussian
    ((Measure.pi (fun _ : Fin 2 ↦ g)).map
      (Complex.equivRealProdCLM.symm ∘ MeasurableEquiv.finTwoArrow))
  rw [heq]
  letI : ProbabilityTheory.IsGaussian (g.prod g) := hprod
  infer_instance

/-- Every finite power of the norm of one complex Gaussian coordinate is
integrable. -/
theorem integrable_norm_pow_complexCoordinateGaussianProbability
    (n k : ℕ) :
    Integrable (fun z : ℂ ↦ ‖z‖ ^ k)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  letI : ProbabilityTheory.IsGaussian
      (complexCoordinateGaussianProbability n : Measure ℂ) :=
    isGaussian_complexCoordinateGaussianProbability n
  exact (ProbabilityTheory.IsGaussian.memLp_id
    (complexCoordinateGaussianProbability n : Measure ℂ) k (by simp)).integrable_norm_pow'

/-- Every mixed complex monomial is integrable under one coordinate of the
Gaussian reference law. -/
theorem integrable_pow_mul_conj_pow_complexCoordinateGaussianProbability
    (n a b : ℕ) :
    Integrable (fun z : ℂ ↦ z ^ a * conj z ^ b)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  have hm : AEStronglyMeasurable (fun z : ℂ ↦ z ^ a * conj z ^ b)
      (complexCoordinateGaussianProbability n : Measure ℂ) :=
    ((continuous_id.pow a).mul (Complex.continuous_conj.pow b)).aestronglyMeasurable
  apply (integrable_norm_iff hm).mp
  convert integrable_norm_pow_complexCoordinateGaussianProbability n (a + b) using 1
  funext z
  simp [norm_mul, norm_pow, pow_add]

theorem integrable_const_mul_pow_mul_conj_pow_complexCoordinateGaussianProbability
    (n a b : ℕ) (c : ℂ) :
    Integrable (fun z : ℂ ↦ c * (z ^ a * conj z ^ b))
      (complexCoordinateGaussianProbability n : Measure ℂ) :=
  (integrable_pow_mul_conj_pow_complexCoordinateGaussianProbability n a b).const_mul c

/-- The diagonal evaluation of every two-variable complex polynomial is
integrable under one complex Gaussian coordinate. -/
theorem integrable_mvPolynomial_diagonalEval (n : ℕ)
    (P : MvPolynomial (Fin 2) ℂ) :
    Integrable (fun z : ℂ ↦ MvPolynomial.eval ![z, conj z] P)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  rw [MvPolynomial.as_sum P]
  simp_rw [MvPolynomial.eval_sum, MvPolynomial.eval_monomial]
  apply integrable_finsetSum
  intro d hd
  have heval : (fun z : ℂ ↦ d.prod fun i e ↦ (![z, conj z] i) ^ e) =
      fun z : ℂ ↦ z ^ d 0 * conj z ^ d 1 := by
    funext z
    rw [Finsupp.prod_fintype]
    · simp [Fin.prod_univ_two]
    · intro i
      simp
  exact (integrable_const_mul_pow_mul_conj_pow_complexCoordinateGaussianProbability
      n (d 0) (d 1) (P.coeff d)).congr
    (Filter.Eventually.of_forall fun z =>
      congrArg (fun w : ℂ => P.coeff d * w) (congrFun heval z).symm)

theorem integrable_mul_mvPolynomial_diagonalEval (n : ℕ)
    (P : MvPolynomial (Fin 2) ℂ) :
    Integrable (fun z : ℂ ↦ z * MvPolynomial.eval ![z, conj z] P)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  exact (integrable_mvPolynomial_diagonalEval n (MvPolynomial.X 0 * P)).congr
    (Filter.Eventually.of_forall fun z => by simp [MvPolynomial.eval_mul])

theorem integrable_conj_mul_mvPolynomial_diagonalEval (n : ℕ)
    (P : MvPolynomial (Fin 2) ℂ) :
    Integrable (fun z : ℂ ↦ conj z * MvPolynomial.eval ![z, conj z] P)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  exact (integrable_mvPolynomial_diagonalEval n (MvPolynomial.X 1 * P)).congr
    (Filter.Eventually.of_forall fun z => by simp [MvPolynomial.eval_mul])

theorem integrable_pderiv_Z_mvPolynomial_diagonalEval (n : ℕ)
    (P : MvPolynomial (Fin 2) ℂ) :
    Integrable (fun z : ℂ ↦
      MvPolynomial.eval ![z, conj z] (MvPolynomial.pderiv 0 P))
      (complexCoordinateGaussianProbability n : Measure ℂ) :=
  integrable_mvPolynomial_diagonalEval n (MvPolynomial.pderiv 0 P)

theorem integrable_pderiv_W_mvPolynomial_diagonalEval (n : ℕ)
    (P : MvPolynomial (Fin 2) ℂ) :
    Integrable (fun z : ℂ ↦
      MvPolynomial.eval ![z, conj z] (MvPolynomial.pderiv 1 P))
      (complexCoordinateGaussianProbability n : Measure ℂ) :=
  integrable_mvPolynomial_diagonalEval n (MvPolynomial.pderiv 1 P)

theorem integrable_mul_mvPolynomial_diagonalEval_two (n : ℕ)
    (P Q : MvPolynomial (Fin 2) ℂ) :
    Integrable (fun z : ℂ ↦ MvPolynomial.eval ![z, conj z] P *
      MvPolynomial.eval ![z, conj z] Q)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  exact (integrable_mvPolynomial_diagonalEval n (P * Q)).congr
    (Filter.Eventually.of_forall fun z => by simp [MvPolynomial.eval_mul])

theorem integrable_fderiv_mvPolynomial_diagonalEval (n : ℕ)
    (P : MvPolynomial (Fin 2) ℂ) (v : ℂ) :
    Integrable (fun z : ℂ ↦
      (fderiv ℝ (fun w : ℂ ↦ MvPolynomial.eval ![w, conj w] P) z) v)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  obtain ⟨Q, hQ⟩ := ComplexHermite.exists_fderiv_diagonalEval_polynomial P v
  exact (integrable_mvPolynomial_diagonalEval n Q).congr
    (Filter.Eventually.of_forall fun z => (hQ z).symm)

theorem integrable_fderiv_one_mvPolynomial_diagonalEval (n : ℕ)
    (P : MvPolynomial (Fin 2) ℂ) :
    Integrable (fun z : ℂ ↦
      (fderiv ℝ (fun w : ℂ ↦ MvPolynomial.eval ![w, conj w] P) z) 1)
      (complexCoordinateGaussianProbability n : Measure ℂ) :=
  integrable_fderiv_mvPolynomial_diagonalEval n P 1

theorem integrable_fderiv_I_mvPolynomial_diagonalEval (n : ℕ)
    (P : MvPolynomial (Fin 2) ℂ) :
    Integrable (fun z : ℂ ↦
      (fderiv ℝ (fun w : ℂ ↦ MvPolynomial.eval ![w, conj w] P) z) Complex.I)
      (complexCoordinateGaussianProbability n : Measure ℂ) :=
  integrable_fderiv_mvPolynomial_diagonalEval n P Complex.I

/-- Products of arbitrary coordinate norm powers are integrable under the
finite product complex Gaussian law. -/
theorem integrable_prod_norm_pow_complexGaussianMeasure (n : ℕ)
    (k : Fin n → ℕ) :
    Integrable (fun z : Configuration n ↦ ∏ i, ‖z i‖ ^ k i)
      (complexGaussianMeasure n) := by
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  exact Integrable.fintype_prod fun i ↦
    integrable_norm_pow_complexCoordinateGaussianProbability n (k i)

/-- In particular, any common coordinate norm power has an integrable product
under the finite product complex Gaussian law. -/
theorem integrable_prod_norm_pow_const_complexGaussianMeasure (n k : ℕ) :
    Integrable (fun z : Configuration n ↦ ∏ i, ‖z i‖ ^ k)
      (complexGaussianMeasure n) :=
  integrable_prod_norm_pow_complexGaussianMeasure n (fun _ ↦ k)

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/GinibreConjugationGeometry.lean #
import GinibrePoincare.Analysis.HolomorphicVandermondeL2Closure
import GinibrePoincare.Analysis.GlobalPhaseAction
import GinibrePoincare.Analysis.L2RepresentativeBridges

/-! # Conjugation geometry on symmetric Ginibre L² -/

open MeasureTheory
open scoped ComplexConjugate ENNReal

namespace GinibrePoincare

noncomputable section

local instance completeSpace_gaussianAlternatingL2' (n : ℕ) :
    CompleteSpace (gaussianAlternatingL2 n) :=
  (isClosed_gaussianAlternatingL2 n).completeSpace_coe

local instance completeSpace_ginibreSymmetricL2' (n : ℕ) :
    CompleteSpace (ginibreSymmetricL2 n) :=
  (isClosed_ginibreSymmetricL2 n).completeSpace_coe

theorem ginibreProbabilityInstance {n : ℕ} (hn : 0 < n) :
    IsProbabilityMeasure (ginibreMeasure n) :=
  ginibreMeasure_isProbabilityMeasure hn

/-- Isometric embedding of scalars as constant Ginibre `L²` functions. -/
def ginibreConstantL2 (n : ℕ) (hn : 0 < n) :
    ℂ →ₗᵢ[ℂ] Lp ℂ 2 (ginibreMeasure n) := by
  letI := ginibreProbabilityInstance hn
  exact {
    toLinearMap := Lp.constₗ 2 (ginibreMeasure n) ℂ
    norm_map' := fun c ↦ by
      change ‖Lp.const 2 (ginibreMeasure n) c‖ = ‖c‖
      rw [Lp.norm_const (2 : ℝ≥0∞) (ginibreMeasure n) c (by norm_num)]
      simp }

/-- Closed subspace of constant Ginibre `L²` functions. -/
def ginibreConstantClosedSubspace (n : ℕ) (hn : 0 < n) :
    ClosedSubmodule ℂ (Lp ℂ 2 (ginibreMeasure n)) where
  toSubmodule := LinearMap.range (ginibreConstantL2 n hn).toLinearMap
  isClosed' := (ginibreConstantL2 n hn).isometry.isUniformInducing.isComplete_range.isClosed

private theorem ginibrePermutationL2_star {n : ℕ}
    (σ : ParticlePermutation n) (u : Lp ℂ 2 (ginibreMeasure n)) :
    ginibrePermutationL2 σ (star u) = star (ginibrePermutationL2 σ u) := by
  apply Lp.ext
  have hstarcomp :=
    (ginibre_measurePreserving_permute σ).quasiMeasurePreserving.ae_eq_comp
      (Lp.coeFn_star u)
  filter_upwards [Lp.coeFn_compMeasurePreserving (star u)
      (ginibre_measurePreserving_permute σ),
    Lp.coeFn_compMeasurePreserving u
      (ginibre_measurePreserving_permute σ),
    hstarcomp,
    Lp.coeFn_star (ginibrePermutationL2 σ u)] with z hleft hright hstar hstarperm
  rw [show (ginibrePermutationL2 σ (star u)) z = (star u) (permute σ z) by
    exact hleft]
  rw [show (star (ginibrePermutationL2 σ u)) z =
    star ((ginibrePermutationL2 σ u) z) by exact hstarperm]
  rw [show (star u) (permute σ z) = star (u (permute σ z)) by
    exact hstar]
  rw [show (ginibrePermutationL2 σ u) z = u (permute σ z) by exact hright]

/-- Pointwise complex conjugation preserves the symmetric Ginibre subspace. -/
def ginibreSymmetricConjugation (n : ℕ) :
    ginibreSymmetricL2 n → ginibreSymmetricL2 n :=
  fun u ↦ ⟨star u.1, by
    intro σ
    rw [ginibrePermutationL2_star, u.2 σ]⟩

private theorem Lp_star_add {n : ℕ}
    (u v : Lp ℂ 2 (ginibreMeasure n)) : star (u + v) = star u + star v := by
  apply Lp.ext
  filter_upwards [Lp.coeFn_star (u + v), Lp.coeFn_star u, Lp.coeFn_star v,
    Lp.coeFn_add u v, Lp.coeFn_add (star u) (star v)] with z huv hu hv hadd hstaradd
  change (u + v) z = u z + v z at hadd
  change (star u + star v) z = star u z + star v z at hstaradd
  rw [huv, hstaradd]
  calc
    star ((u + v) z) = star (u z + v z) := congrArg star hadd
    _ = star (u z) + star (v z) := by simp
    _ = star u z + star v z := congrArg₂ (· + ·) hu.symm hv.symm

private theorem Lp_star_real_smul {n : ℕ} (r : ℝ)
    (u : Lp ℂ 2 (ginibreMeasure n)) : star (r • u) = r • star u := by
  apply Lp.ext
  filter_upwards [Lp.coeFn_star (r • u), Lp.coeFn_star u,
    Lp.coeFn_smul r u, Lp.coeFn_smul r (star u)] with z hru hu hsmul hstarsmul
  change (r • u) z = r • u z at hsmul
  change (r • star u) z = r • star u z at hstarsmul
  rw [hru, hstarsmul]
  calc
    star ((r • u) z) = star (r • u z) := congrArg star hsmul
    _ = r • star (u z) := by simp
    _ = r • star u z := congrArg (r • ·) hu.symm

private theorem Lp_norm_star {n : ℕ} (u : Lp ℂ 2 (ginibreMeasure n)) :
    ‖star u‖ = ‖u‖ := by
  rw [Lp.norm_def, Lp.norm_def]
  exact congrArg ENNReal.toReal AEEqFun.eLpNorm_star

/-- Global-phase pullback commutes with value conjugation. -/
theorem ginibreGlobalPhaseL2_star {n : ℕ} (hn : 0 < n)
    (u : ℂ) (hu : ‖u‖ = 1) (h : Lp ℂ 2 (ginibreMeasure n)) :
    ginibreGlobalPhaseL2 hn u hu (star h) =
      star (ginibreGlobalPhaseL2 hn u hu h) := by
  apply Lp.ext
  have hstarcomp :=
    (measurePreserving_globalPhase_ginibreMeasure hn u hu).quasiMeasurePreserving.ae_eq_comp
      (Lp.coeFn_star h)
  filter_upwards [Lp.coeFn_compMeasurePreserving (star h)
      (measurePreserving_globalPhase_ginibreMeasure hn u hu),
    Lp.coeFn_compMeasurePreserving h
      (measurePreserving_globalPhase_ginibreMeasure hn u hu),
    hstarcomp, Lp.coeFn_star (ginibreGlobalPhaseL2 hn u hu h)] with
      z hleft hright hstar hstarphase
  rw [show (ginibreGlobalPhaseL2 hn u hu (star h)) z =
    (star h) (globalPhase u z) by exact hleft]
  rw [show (star (ginibreGlobalPhaseL2 hn u hu h)) z =
    star ((ginibreGlobalPhaseL2 hn u hu h) z) by exact hstarphase]
  rw [show (star h) (globalPhase u z) = star (h (globalPhase u z)) by
    exact hstar]
  rw [show (ginibreGlobalPhaseL2 hn u hu h) z = h (globalPhase u z) by
    exact hright]

/-- Subspace-valued form of phase/conjugation covariance. -/
theorem ginibreGlobalPhaseL2_symmetricConjugation {n : ℕ} (hn : 0 < n)
    (u : ℂ) (hu : ‖u‖ = 1) (h : ginibreSymmetricL2 n) :
    ginibreGlobalPhaseL2 hn u hu (ginibreSymmetricConjugation n h).1 =
      star (ginibreGlobalPhaseL2 hn u hu h.1) :=
  ginibreGlobalPhaseL2_star hn u hu h.1

/-- Value conjugation changes a phase eigenvalue to its complex conjugate. -/
theorem ginibreGlobalPhaseL2_star_eigen {n r : ℕ} (hn : 0 < n)
    (h : Lp ℂ 2 (ginibreMeasure n))
    (hh : ∀ (u : ℂ) (hu : ‖u‖ = 1),
      ginibreGlobalPhaseL2 hn u hu h = u ^ r • h)
    (u : ℂ) (hu : ‖u‖ = 1) :
    ginibreGlobalPhaseL2 hn u hu (star h) = conj (u ^ r) • star h := by
  rw [ginibreGlobalPhaseL2_star, hh u hu]
  apply Lp.ext
  filter_upwards [Lp.coeFn_star (u ^ r • h), Lp.coeFn_star h,
    Lp.coeFn_smul (u ^ r) h,
    Lp.coeFn_smul (conj (u ^ r)) (star h)] with z hl hs hscalar hr
  rw [hl, hr]
  simp only [Pi.smul_apply, smul_eq_mul]
  rw [hs]
  change conj ((u ^ r • h) z) = conj (u ^ r) * conj (h z)
  rw [hscalar]
  simp

/-- Every strictly positive phase-degree vector is orthogonal to its value
conjugate. -/
theorem inner_star_eq_zero_of_positive_ginibre_phase_degree {n r : ℕ}
    (hn : 0 < n) (hr : 0 < r) (h : Lp ℂ 2 (ginibreMeasure n))
    (hh : ∀ (u : ℂ) (hu : ‖u‖ = 1),
      ginibreGlobalPhaseL2 hn u hu h = u ^ r • h) :
    inner ℂ h (star h) = 0 := by
  have hne : 2 * r ≠ 0 := by omega
  obtain ⟨u, hu, hpow⟩ := exists_unit_phase_pow_ne (2 * r) 0 hne
  have hchar : conj (u ^ r) * conj (u ^ r) ≠ 1 := by
    intro hc
    apply hpow
    have hc' := congrArg conj hc
    simp at hc'
    have hp : u ^ (r + r) = 1 := by
      rw [pow_add]
      exact hc'
    simpa only [show 2 * r = r + r by omega, pow_zero] using hp
  exact inner_eq_zero_of_isometry_eigencharacters
    (ginibreGlobalPhaseL2 hn u hu) h (star h) (u ^ r) (conj (u ^ r))
      (hh u hu) (ginibreGlobalPhaseL2_star_eigen hn h hh u hu) hchar

/-- Cross-degree version: two nonnegative holomorphic phase degrees are
orthogonal after conjugating the second whenever their sum is positive. -/
theorem inner_star_eq_zero_of_ginibre_phase_degrees_add_pos {n r s : ℕ}
    (hn : 0 < n) (hrs : 0 < r + s)
    (x y : Lp ℂ 2 (ginibreMeasure n))
    (hx : ∀ (u : ℂ) (hu : ‖u‖ = 1),
      ginibreGlobalPhaseL2 hn u hu x = u ^ r • x)
    (hy : ∀ (u : ℂ) (hu : ‖u‖ = 1),
      ginibreGlobalPhaseL2 hn u hu y = u ^ s • y) :
    inner ℂ x (star y) = 0 := by
  have hne : r + s ≠ 0 := Nat.ne_of_gt hrs
  obtain ⟨u, hu, hpow⟩ := exists_unit_phase_pow_ne (r + s) 0 hne
  have hchar : conj (u ^ r) * conj (u ^ s) ≠ 1 := by
    intro hc
    apply hpow
    have hc' := congrArg conj hc
    simp at hc'
    rw [← pow_add] at hc'
    simpa only [pow_zero] using hc'
  exact inner_eq_zero_of_isometry_eigencharacters
    (ginibreGlobalPhaseL2 hn u hu) x (star y) (u ^ r) (conj (u ^ s))
      (hx u hu) (ginibreGlobalPhaseL2_star_eigen hn y hy u hu) hchar

/-- A positive-degree finite homogeneous Vandermonde quotient is orthogonal
to its value conjugate. -/
theorem inner_conjugate_finiteHomogeneousQuotient_eq_zero {n r : ℕ}
    (hn : 0 < n) (hr : 0 < r)
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
    (hAlt : finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n)
    (Q : ConfigurationPolynomial n)
    (hsum : ∀ z, finiteZeroAntiholomorphicHermiteSum n hn S c z =
      vandermonde z * MvPolynomial.eval z Q)
    (hphase : ∀ (u : ℂ), ‖u‖ = 1 → ∀ z, vandermonde z ≠ 0 →
      MvPolynomial.eval (globalPhase u z) Q =
        u ^ r * MvPolynomial.eval z Q) :
    inner ℂ (finiteHomogeneousQuotientL2 hn S c hAlt).1
      (star (finiteHomogeneousQuotientL2 hn S c hAlt).1) = 0 := by
  apply inner_star_eq_zero_of_positive_ginibre_phase_degree hn hr
  intro u hu
  exact ginibreGlobalPhaseL2_finiteHomogeneousQuotient
    hn S c hAlt Q hsum hphase u hu

/-- The closed common eigenspace of Ginibre global phases with holomorphic
character `u ↦ u^r`.  Defining the closed space by its character makes the
extension from finite homogeneous quotients automatic. -/
def ginibreHolomorphicPhaseDegree (n r : ℕ) (hn : 0 < n) :
    ClosedSubmodule ℂ (Lp ℂ 2 (ginibreMeasure n)) where
  carrier := {h | ∀ (u : ℂ) (hu : ‖u‖ = 1),
    ginibreGlobalPhaseL2 hn u hu h = u ^ r • h}
  zero_mem' := by simp
  add_mem' := by
    intro x y hx hy u hu
    simp [map_add, hx u hu, hy u hu, smul_add]
  smul_mem' := by
    intro c x hx u hu
    rw [map_smul, hx u hu]
    simp [smul_smul, mul_comm]
  isClosed' := by
    rw [show {h | ∀ (u : ℂ) (hu : ‖u‖ = 1),
        ginibreGlobalPhaseL2 hn u hu h = u ^ r • h} =
      ⋂ (u : ℂ) (hu : ‖u‖ = 1),
        {h | ginibreGlobalPhaseL2 hn u hu h = u ^ r • h} by
      ext h
      simp]
    apply isClosed_iInter
    intro u
    apply isClosed_iInter
    intro hu
    exact isClosed_eq
      (ginibreGlobalPhaseL2 hn u hu).continuous
      (continuous_const_smul (u ^ r))

theorem mem_ginibreHolomorphicPhaseDegree_iff {n r : ℕ} (hn : 0 < n)
    (h : Lp ℂ 2 (ginibreMeasure n)) :
    h ∈ ginibreHolomorphicPhaseDegree n r hn ↔
      ∀ (u : ℂ) (hu : ‖u‖ = 1),
        ginibreGlobalPhaseL2 hn u hu h = u ^ r • h :=
  Iff.rfl

/-- Unequal closed phase-degree spaces are orthogonal. -/
theorem ginibreHolomorphicPhaseDegree_orthogonal {n r s : ℕ}
    (hn : 0 < n) (hrs : r ≠ s) :
    (ginibreHolomorphicPhaseDegree n r hn).toSubmodule ⟂
      (ginibreHolomorphicPhaseDegree n s hn).toSubmodule := by
  intro x hx y hy
  exact inner_eq_zero_of_ginibre_phase_degrees_ne hn hrs.symm y x hy hx

/-- Every vector in a positive closed phase-degree space is orthogonal to
its value conjugate. -/
theorem inner_star_eq_zero_of_mem_positive_phaseDegree {n r : ℕ}
    (hn : 0 < n) (hr : 0 < r) {h : Lp ℂ 2 (ginibreMeasure n)}
    (hh : h ∈ ginibreHolomorphicPhaseDegree n r hn) :
    inner ℂ h (star h) = 0 :=
  inner_star_eq_zero_of_positive_ginibre_phase_degree hn hr h hh

/-- Every finite homogeneous quotient of degree `r` belongs to the closed
degree-`r` character space. -/
theorem finiteHomogeneousQuotientL2_mem_phaseDegree {n r : ℕ}
    (hn : 0 < n) (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
    (hAlt : finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n)
    (Q : ConfigurationPolynomial n)
    (hsum : ∀ z, finiteZeroAntiholomorphicHermiteSum n hn S c z =
      vandermonde z * MvPolynomial.eval z Q)
    (hphase : ∀ (u : ℂ), ‖u‖ = 1 → ∀ z, vandermonde z ≠ 0 →
      MvPolynomial.eval (globalPhase u z) Q =
        u ^ r * MvPolynomial.eval z Q) :
    (finiteHomogeneousQuotientL2 hn S c hAlt).1 ∈
      ginibreHolomorphicPhaseDegree n r hn := by
  intro u hu
  exact ginibreGlobalPhaseL2_finiteHomogeneousQuotient
    hn S c hAlt Q hsum hphase u hu

/-- Predicate selecting the genuinely finite homogeneous holomorphic
quotient vectors of degree `r`. -/
def IsFiniteHomogeneousQuotientVector {n : ℕ} (hn : 0 < n) (r : ℕ)
    (h : Lp ℂ 2 (ginibreMeasure n)) : Prop :=
  ∃ (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
      (hAlt : finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n)
      (Q : ConfigurationPolynomial n),
    (∀ p ∈ S, totalHolomorphicDegree p = vandermondeDegree n + r) ∧
    IsAlternatingConfigurationPolynomial
      (finiteZeroAntiholomorphicHermitePolynomial n S c) ∧
    finiteZeroAntiholomorphicHermitePolynomial n S c ≠ 0 ∧
    finiteZeroAntiholomorphicHermitePolynomial n S c =
      polynomialVandermonde n * Q ∧
    (∀ z, finiteZeroAntiholomorphicHermiteSum n hn S c z =
      vandermonde z * MvPolynomial.eval z Q) ∧
    (∀ (u : ℂ), ‖u‖ = 1 → ∀ z, vandermonde z ≠ 0 →
      MvPolynomial.eval (globalPhase u z) Q =
        u ^ r * MvPolynomial.eval z Q) ∧
    h = (finiteHomogeneousQuotientL2 hn S c hAlt).1

/-- Closure of the span of finite homogeneous quotients of degree `r`. -/
def ginibreFiniteQuotientDegreeClosedSpan (n r : ℕ) (hn : 0 < n) :
    ClosedSubmodule ℂ (Lp ℂ 2 (ginibreMeasure n)) where
  toSubmodule := (Submodule.span ℂ
    {h | IsFiniteHomogeneousQuotientVector hn r h}).topologicalClosure
  isClosed' := (Submodule.span ℂ
    {h | IsFiniteHomogeneousQuotientVector hn r h}).isClosed_topologicalClosure

theorem ginibreFiniteQuotientDegreeClosedSpan_le_phaseDegree
    (n r : ℕ) (hn : 0 < n) :
    (ginibreFiniteQuotientDegreeClosedSpan n r hn).toSubmodule ≤
      (ginibreHolomorphicPhaseDegree n r hn).toSubmodule := by
  apply Submodule.topologicalClosure_minimal
  · apply Submodule.span_le.2
    intro h hh
    rcases hh with ⟨S, c, hAlt, Q, hdegree, hpolyAlt, hne, hfactor,
      hsum, hphase, rfl⟩
    exact finiteHomogeneousQuotientL2_mem_phaseDegree hn S c hAlt Q hsum hphase
  · exact (ginibreHolomorphicPhaseDegree n r hn).isClosed

theorem ginibreFiniteQuotientDegreeClosedSpan_orthogonal {n r s : ℕ}
    (hn : 0 < n) (hrs : r ≠ s) :
    (ginibreFiniteQuotientDegreeClosedSpan n r hn).toSubmodule ⟂
      (ginibreFiniteQuotientDegreeClosedSpan n s hn).toSubmodule := by
  exact (ginibreHolomorphicPhaseDegree_orthogonal hn hrs).mono
    (ginibreFiniteQuotientDegreeClosedSpan_le_phaseDegree n r hn)
    (ginibreFiniteQuotientDegreeClosedSpan_le_phaseDegree n s hn)

theorem inner_star_eq_zero_of_mem_positive_finiteQuotientDegreeClosure
    {n r : ℕ} (hn : 0 < n) (hr : 0 < r)
    {h : Lp ℂ 2 (ginibreMeasure n)}
    (hh : h ∈ ginibreFiniteQuotientDegreeClosedSpan n r hn) :
    inner ℂ h (star h) = 0 :=
  inner_star_eq_zero_of_mem_positive_phaseDegree hn hr
    (ginibreFiniteQuotientDegreeClosedSpan_le_phaseDegree n r hn hh)

theorem inner_star_eq_zero_of_mem_finiteQuotientDegreeClosures
    {n r s : ℕ} (hn : 0 < n) (hrs : 0 < r + s)
    {x y : Lp ℂ 2 (ginibreMeasure n)}
    (hx : x ∈ ginibreFiniteQuotientDegreeClosedSpan n r hn)
    (hy : y ∈ ginibreFiniteQuotientDegreeClosedSpan n s hn) :
    inner ℂ x (star y) = 0 := by
  exact inner_star_eq_zero_of_ginibre_phase_degrees_add_pos hn hrs x y
    (ginibreFiniteQuotientDegreeClosedSpan_le_phaseDegree n r hn hx)
    (ginibreFiniteQuotientDegreeClosedSpan_le_phaseDegree n s hn hy)

/-- Every bottom-degree finite quotient generator is represented by a
constant function. -/
theorem finite_bottom_quotient_generator_ae_constant {n : ℕ} (hn : 0 < n)
    {h : Lp ℂ 2 (ginibreMeasure n)}
    (hh : IsFiniteHomogeneousQuotientVector hn 0 h) :
    ∃ a : ℂ, h =ᵐ[ginibreMeasure n] fun _ ↦ a := by
  rcases hh with ⟨S, c, hAlt, Q, hdegree, hpolyAlt, hne, hfactor,
    hsum, hphase, rfl⟩
  have hhom : MvPolynomial.IsHomogeneous
      (finiteZeroAntiholomorphicHermitePolynomial n S c)
      (vandermondeDegree n) := by
    apply isHomogeneous_finiteZeroAntiholomorphicHermitePolynomial_of_degree
    intro p hp
    simpa using hdegree p hp
  have hQ := quotient_eq_C_of_bottom_homogeneous_degree hhom hne hfactor
  refine ⟨(groundStateNormalization n : ℂ) * MvPolynomial.coeff 0 Q, ?_⟩
  filter_upwards [finiteHomogeneousQuotientL2_coeFn hn S c hAlt Q hsum] with z hz
  rw [hz, hQ]
  simp

theorem finite_bottom_quotient_generator_mem_constants {n : ℕ} (hn : 0 < n)
    {h : Lp ℂ 2 (ginibreMeasure n)}
    (hh : IsFiniteHomogeneousQuotientVector hn 0 h) :
    h ∈ ginibreConstantClosedSubspace n hn := by
  obtain ⟨a, ha⟩ := finite_bottom_quotient_generator_ae_constant hn hh
  refine ⟨a, ?_⟩
  apply Lp.ext
  letI := ginibreProbabilityInstance hn
  filter_upwards [ha, Lp.coeFn_const (α := Configuration n)
    (μ := ginibreMeasure n) (p := (2 : ℝ≥0∞)) a] with z hz hconst
  change (Lp.const 2 (ginibreMeasure n) a) z = h z
  rw [hconst, hz]
  rfl

theorem ginibreFiniteQuotientDegreeZero_le_constants (n : ℕ) (hn : 0 < n) :
    (ginibreFiniteQuotientDegreeClosedSpan n 0 hn).toSubmodule ≤
      (ginibreConstantClosedSubspace n hn).toSubmodule := by
  apply Submodule.topologicalClosure_minimal
  · apply Submodule.span_le.2
    intro h hh
    exact finite_bottom_quotient_generator_mem_constants hn hh
  · exact (ginibreConstantClosedSubspace n hn).isClosed

theorem ginibreConstantL2_mem_degreeZeroClosure (n : ℕ) (hn : 0 < n) (a : ℂ) :
    ginibreConstantL2 n hn a ∈
      ginibreFiniteQuotientDegreeClosedSpan n 0 hn := by
  by_cases ha : a = 0
  · subst a
    simp
  let k : ℂ := a / (groundStateNormalization n : ℂ)
  let P : ConfigurationPolynomial n :=
    polynomialVandermonde n * MvPolynomial.C k
  let S := holomorphicHermiteSupport P
  let c := holomorphicHermiteCoefficient P
  have hk : k ≠ 0 := div_ne_zero ha (by
    exact_mod_cast groundStateNormalization_ne_zero_of_pos hn)
  have hPalt : IsAlternatingConfigurationPolynomial P := by
    apply isAlternating_polynomialVandermonde_mul
    intro σ
    simp
  have hPne : P ≠ 0 := mul_ne_zero (polynomialVandermonde_ne_zero n)
    (MvPolynomial.C_ne_zero.mpr hk)
  have hPhom : MvPolynomial.IsHomogeneous P (vandermondeDegree n) := by
    unfold P
    simpa using (isHomogeneous_polynomialVandermonde n).mul
      (MvPolynomial.isHomogeneous_C (σ := Fin n) k)
  have hexpand : finiteZeroAntiholomorphicHermitePolynomial n S c = P :=
    finiteZeroAntiholomorphicHermitePolynomial_support_expansion hn P
  have hAltL2 : finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n := by
    apply finiteZeroHermiteL2_mem_gaussianAlternating hn
    rwa [hexpand]
  let q := finiteHomogeneousQuotientL2 hn S c hAltL2
  have hsum : ∀ z, finiteZeroAntiholomorphicHermiteSum n hn S c z =
      vandermonde z * MvPolynomial.eval z (MvPolynomial.C k) := by
    intro z
    rw [← eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c z,
      hexpand]
    simp [P, eval_polynomialVandermonde]
  have hqcoe := finiteHomogeneousQuotientL2_coeFn hn S c hAltL2
    (MvPolynomial.C k) hsum
  have hqconst : q.1 = ginibreConstantL2 n hn a := by
    apply Lp.ext
    letI := ginibreProbabilityInstance hn
    filter_upwards [hqcoe, Lp.coeFn_const (α := Configuration n)
      (μ := ginibreMeasure n) (p := (2 : ℝ≥0∞)) a] with z hq hc
    change q.1 z = (Lp.const 2 (ginibreMeasure n) a) z
    rw [hq, hc]
    simp only [MvPolynomial.eval_C, Function.const_apply]
    change (groundStateNormalization n : ℂ) * k = a
    unfold k
    have hgn : (groundStateNormalization n : ℂ) ≠ 0 := by
      exact_mod_cast groundStateNormalization_ne_zero_of_pos hn
    field_simp
  change ginibreConstantL2 n hn a ∈
    (Submodule.span ℂ {h | IsFiniteHomogeneousQuotientVector hn 0 h}).topologicalClosure
  apply subset_closure
  apply Submodule.subset_span
  change IsFiniteHomogeneousQuotientVector hn 0 (ginibreConstantL2 n hn a)
  refine ⟨S, c, hAltL2, MvPolynomial.C k, ?_, ?_, ?_, ?_, hsum, ?_, ?_⟩
  · intro p hp
    simpa using totalHolomorphicDegree_eq_of_mem_holomorphicHermiteSupport hPhom hp
  · rwa [hexpand]
  · rwa [hexpand]
  · rw [hexpand]
  · intro u hu z hz
    simp
  · exact hqconst.symm

theorem ginibreFiniteQuotientDegreeZero_eq_constants (n : ℕ) (hn : 0 < n) :
    ginibreFiniteQuotientDegreeClosedSpan n 0 hn =
      ginibreConstantClosedSubspace n hn := by
  ext h
  constructor
  · intro hh
    exact ginibreFiniteQuotientDegreeZero_le_constants n hn hh
  · rintro ⟨a, rfl⟩
    exact ginibreConstantL2_mem_degreeZeroClosure n hn a

/-- Every nonzero homogeneous component of an alternating polynomial gives
a finite quotient generator in the degree shifted by the Vandermonde
degree. -/
theorem homogeneousComponent_gives_finiteQuotientVector
    {n d : ℕ} (hn : 0 < n) {P : ConfigurationPolynomial n}
    (hAlt : IsAlternatingConfigurationPolynomial P)
    (hcomponent : MvPolynomial.homogeneousComponent d P ≠ 0) :
    ∃ (h : Lp ℂ 2 (ginibreMeasure n)),
      IsFiniteHomogeneousQuotientVector hn (d - vandermondeDegree n) h := by
  let Pd := MvPolynomial.homogeneousComponent d P
  have hPdHom : MvPolynomial.IsHomogeneous Pd d :=
    MvPolynomial.homogeneousComponent_isHomogeneous d P
  have hPdAlt : IsAlternatingConfigurationPolynomial Pd :=
    isAlternating_homogeneousComponent hAlt
  obtain ⟨Q, hQsym, hfactor, hle, hphase⟩ :=
    homogeneous_alternating_polynomial_division hPdHom hPdAlt hcomponent
  let S := holomorphicHermiteSupport Pd
  let c := holomorphicHermiteCoefficient Pd
  have hexpand : finiteZeroAntiholomorphicHermitePolynomial n S c = Pd :=
    finiteZeroAntiholomorphicHermitePolynomial_support_expansion hn Pd
  have hAltL2 : finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n := by
    apply finiteZeroHermiteL2_mem_gaussianAlternating hn
    rwa [hexpand]
  let h := (finiteHomogeneousQuotientL2 hn S c hAltL2).1
  refine ⟨h, S, c, hAltL2, Q, ?_, ?_, ?_, ?_, ?_, ?_, rfl⟩
  · intro p hp
    rw [Nat.add_sub_of_le hle]
    exact totalHolomorphicDegree_eq_of_mem_holomorphicHermiteSupport hPdHom hp
  · rwa [hexpand]
  · rwa [hexpand]
  · rwa [hexpand]
  · intro z
    rw [← eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c z,
      hexpand, hfactor, map_mul, eval_polynomialVandermonde]
  · exact hphase

/-- Every alternating polynomial is a finite sum of homogeneous alternating
components; every nonzero summand has at least Vandermonde degree and is
therefore covered by the preceding quotient construction. -/
theorem alternating_polynomial_homogeneous_decomposition
    {n : ℕ} (P : ConfigurationPolynomial n)
    (hAlt : IsAlternatingConfigurationPolynomial P) :
    (∑ d ∈ Finset.range (P.totalDegree + 1),
        MvPolynomial.homogeneousComponent d P) = P ∧
      ∀ d, MvPolynomial.homogeneousComponent d P ≠ 0 →
        IsAlternatingConfigurationPolynomial
          (MvPolynomial.homogeneousComponent d P) ∧
        vandermondeDegree n ≤ d := by
  refine ⟨MvPolynomial.sum_homogeneousComponent P, ?_⟩
  intro d hd
  have hhom := MvPolynomial.homogeneousComponent_isHomogeneous d P
  have halt : IsAlternatingConfigurationPolynomial
      (MvPolynomial.homogeneousComponent d P) :=
    isAlternating_homogeneousComponent hAlt
  exact ⟨halt,
    vandermondeDegree_le_of_homogeneous_alternating hhom halt hd⟩

/-- Orbit of a holomorphic multi-index under coordinate permutations. -/
def holomorphicPermutationOrbitIndex {n : ℕ}
    (p : Fin n → ℕ) (σ : ParticlePermutation n) : Fin n → ℕ :=
  p ∘ σ.symm

/-- Fiber-summed coefficients of the signed alternation of one holomorphic
Hermite tensor. -/
def alternatedHolomorphicCoefficient {n : ℕ} (p q : Fin n → ℕ) : ℂ :=
  ((Fintype.card (ParticlePermutation n) : ℂ)⁻¹) *
    ∑ σ ∈ (Finset.univ : Finset (ParticlePermutation n)) with
      holomorphicPermutationOrbitIndex p σ = q, permutationSign σ

def holomorphicPermutationOrbitSupport {n : ℕ} (p : Fin n → ℕ) :
    Finset (Fin n → ℕ) :=
  Finset.univ.image (holomorphicPermutationOrbitIndex p)

/-- Generic fiberwise regrouping of a finite sum of scalar multiples. -/
theorem sum_smul_comp_eq_sum_fiber
    {ι κ 𝕜 M : Type*} [DecidableEq κ] [Semiring 𝕜]
    [AddCommMonoid M] [Module 𝕜 M]
    (s : Finset ι) (g : ι → κ) (w : ι → 𝕜) (v : κ → M) :
    (∑ i ∈ s, w i • v (g i)) =
      ∑ q ∈ s.image g, (∑ i ∈ s with g i = q, w i) • v q := by
  symm
  have hfiber := Finset.sum_fiberwise_of_maps_to
    (s := s) (t := s.image g) (g := g)
    (fun i hi ↦ Finset.mem_image.mpr ⟨i, hi, rfl⟩)
    (fun i ↦ w i • v (g i))
  rw [← hfiber]
  apply Finset.sum_congr rfl
  intro q hq
  rw [Finset.sum_smul]
  apply Finset.sum_congr rfl
  intro i hi
  rw [(Finset.mem_filter.mp hi).2]

/-- Opaque `L²` instantiation of the generic fiber regrouping lemma. -/
theorem finiteZeroHermiteL2_alternatedHolomorphicCoefficient
    (n : ℕ) (hn : 0 < n) (p : Fin n → ℕ) :
    finiteZeroHermiteL2 n hn (holomorphicPermutationOrbitSupport p)
        (alternatedHolomorphicCoefficient p) =
      ComplexHermite.gaussianAlternationOperator n
        (ComplexHermite.hermiteL2Family n hn (p, 0)) := by
  rw [ComplexHermite.gaussianAlternationOperator_apply]
  have hperm : ∀ σ : ParticlePermutation n,
      gaussianPermutationL2 σ (ComplexHermite.hermiteL2Family n hn (p, 0)) =
        ComplexHermite.hermiteL2Family n hn
          (holomorphicPermutationOrbitIndex p σ, 0) := by
    intro σ
    rw [ComplexHermite.gaussianPermutationL2_hermiteL2Family]
    congr 2
  rw [show (∑ σ : ParticlePermutation n,
      permutationSign σ • gaussianPermutationL2 σ
        (ComplexHermite.hermiteL2Family n hn (p, 0))) =
      ∑ σ : ParticlePermutation n, permutationSign σ •
        ComplexHermite.hermiteL2Family n hn
          (holomorphicPermutationOrbitIndex p σ, 0) by
    apply Finset.sum_congr rfl
    intro σ hσ
    rw [hperm]]
  rw [sum_smul_comp_eq_sum_fiber
    (s := (Finset.univ : Finset (ParticlePermutation n)))
    (g := holomorphicPermutationOrbitIndex p)
    (w := permutationSign)
    (v := fun q ↦ ComplexHermite.hermiteL2Family n hn (q, 0))]
  unfold finiteZeroHermiteL2 holomorphicPermutationOrbitSupport
    alternatedHolomorphicCoefficient
  rw [Finset.smul_sum]
  apply Finset.sum_congr rfl
  intro q hq
  rw [smul_smul]

theorem totalHolomorphicDegree_orbitIndex {n : ℕ}
    (p : Fin n → ℕ) (σ : ParticlePermutation n) :
    totalHolomorphicDegree (holomorphicPermutationOrbitIndex p σ) =
      totalHolomorphicDegree p := by
  unfold totalHolomorphicDegree holomorphicPermutationOrbitIndex
  exact Equiv.sum_comp σ.symm p

theorem totalHolomorphicDegree_eq_of_mem_orbitSupport {n : ℕ}
    (p q : Fin n → ℕ) (hq : q ∈ holomorphicPermutationOrbitSupport p) :
    totalHolomorphicDegree q = totalHolomorphicDegree p := by
  rcases Finset.mem_image.mp hq with ⟨σ, hσ, rfl⟩
  exact totalHolomorphicDegree_orbitIndex p σ

/-- The orbit-fiber polynomial is algebraically alternating. -/
theorem isAlternating_alternatedHolomorphicPolynomial
    (n : ℕ) (hn : 0 < n) (p : Fin n → ℕ) :
    IsAlternatingConfigurationPolynomial
      (finiteZeroAntiholomorphicHermitePolynomial n
        (holomorphicPermutationOrbitSupport p)
        (alternatedHolomorphicCoefficient p)) := by
  let S := holomorphicPermutationOrbitSupport p
  let c := alternatedHolomorphicCoefficient p
  apply (finiteHermiteSum_isAlternating_iff hn S c).1
  intro σ
  have heq : (fun z ↦ finiteZeroAntiholomorphicHermiteSum n hn S c (permute σ z)) =
      fun z ↦ permutationSign σ * finiteZeroAntiholomorphicHermiteSum n hn S c z := by
    apply continuous_eq_of_ae_eq_complexGaussian hn
    · have hc : Continuous (finiteZeroAntiholomorphicHermiteSum n hn S c) := by
        convert MvPolynomial.continuous_eval
          (finiteZeroAntiholomorphicHermitePolynomial n S c) using 1
        funext z
        exact (eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c z).symm
      apply hc.comp
      exact continuous_pi (fun i ↦ continuous_apply (σ i))
    · have hc : Continuous (finiteZeroAntiholomorphicHermiteSum n hn S c) := by
        convert MvPolynomial.continuous_eval
          (finiteZeroAntiholomorphicHermitePolynomial n S c) using 1
        funext z
        exact (eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c z).symm
      exact continuous_const.mul hc
    have hv : finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n := by
      rw [finiteZeroHermiteL2_alternatedHolomorphicCoefficient]
      exact ComplexHermite.gaussianAlternationOperator_mem n _
    have hLp := hv σ
    have hclass :
        (gaussianPermutationL2 σ (finiteZeroHermiteL2 n hn S c) :
          Configuration n → ℂ) =ᵐ[complexGaussianMeasure n]
        (permutationSign σ • finiteZeroHermiteL2 n hn S c :
          Configuration n → ℂ) := by
      rw [hLp]
      exact Lp.coeFn_smul _ _
    have hcoe := finiteZeroHermiteL2_coeFn n hn S c
    have hcomp := (gaussian_measurePreserving_permute σ).quasiMeasurePreserving.ae_eq_comp hcoe
    filter_upwards [hclass, Lp.coeFn_compMeasurePreserving (finiteZeroHermiteL2 n hn S c)
        (gaussian_measurePreserving_permute σ), hcomp, hcoe] with
        z hpoint hpull hsrc htgt
    rw [show (gaussianPermutationL2 σ (finiteZeroHermiteL2 n hn S c)) z =
      finiteZeroHermiteL2 n hn S c (permute σ z) by exact hpull] at hpoint
    simp only [Pi.smul_apply, smul_eq_mul] at hpoint
    change finiteZeroHermiteL2 n hn S c (permute σ z) =
      finiteZeroAntiholomorphicHermiteSum n hn S c (permute σ z) at hsrc
    change finiteZeroHermiteL2 n hn S c (permute σ z) =
      permutationSign σ * finiteZeroHermiteL2 n hn S c z at hpoint
    rw [hsrc, htgt] at hpoint
    exact hpoint
  exact fun z ↦ congrFun heq z

/-- The inverse Vandermonde image of an alternated holomorphic Hermite basis
vector belongs to its shifted homogeneous quotient closure. -/
theorem inverse_alternatedHermite_mem_degreeClosure
    (n : ℕ) (hn : 0 < n) (p : Fin n → ℕ) :
    ((vandermondeSymmetricAlternatingEquiv n hn).symm
      ⟨ComplexHermite.gaussianAlternationOperator n
          (ComplexHermite.hermiteL2Family n hn (p, 0)),
        ComplexHermite.gaussianAlternationOperator_mem n _⟩).1 ∈
      ginibreFiniteQuotientDegreeClosedSpan n
        (totalHolomorphicDegree p - vandermondeDegree n) hn := by
  let S := holomorphicPermutationOrbitSupport p
  let c := alternatedHolomorphicCoefficient p
  let P := finiteZeroAntiholomorphicHermitePolynomial n S c
  have hvEq : finiteZeroHermiteL2 n hn S c =
      ComplexHermite.gaussianAlternationOperator n
        (ComplexHermite.hermiteL2Family n hn (p, 0)) :=
    finiteZeroHermiteL2_alternatedHolomorphicCoefficient n hn p
  have hAltP : IsAlternatingConfigurationPolynomial P :=
    isAlternating_alternatedHolomorphicPolynomial n hn p
  have hHom : MvPolynomial.IsHomogeneous P (totalHolomorphicDegree p) := by
    apply isHomogeneous_finiteZeroAntiholomorphicHermitePolynomial_of_degree
    intro q hq
    exact totalHolomorphicDegree_eq_of_mem_orbitSupport p q hq

  have hAltL2 : finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n := by
    rw [hvEq]
    exact ComplexHermite.gaussianAlternationOperator_mem n _
  let x : gaussianAlternatingL2 n :=
    ⟨ComplexHermite.gaussianAlternationOperator n
      (ComplexHermite.hermiteL2Family n hn (p, 0)),
      ComplexHermite.gaussianAlternationOperator_mem n _⟩
  let y : gaussianAlternatingL2 n := ⟨finiteZeroHermiteL2 n hn S c, hAltL2⟩
  have hxy : x = y := Subtype.ext hvEq.symm
  change ((vandermondeSymmetricAlternatingEquiv n hn).symm x).1 ∈ _
  rw [hxy]
  by_cases hP0 : P = 0
  · have hv0 : finiteZeroHermiteL2 n hn S c = 0 := by
      apply Lp.ext
      filter_upwards [finiteZeroHermiteL2_coeFn n hn S c,
        Lp.coeFn_zero ℂ 2 (complexGaussianMeasure n)] with z hv hz
      rw [hv, ← eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c z]
      change MvPolynomial.eval z P = _
      rw [hP0, map_zero]
      exact hz.symm
    change ((vandermondeSymmetricAlternatingEquiv n hn).symm
      (⟨finiteZeroHermiteL2 n hn S c, hAltL2⟩ : gaussianAlternatingL2 n)).1 ∈ _
    have hy0 : (⟨finiteZeroHermiteL2 n hn S c, hAltL2⟩ :
        gaussianAlternatingL2 n) = 0 := Subtype.ext hv0
    rw [hy0]
    simp
  · obtain ⟨Q, hQ, hfactor, hle, hphase⟩ :=
      homogeneous_alternating_polynomial_division hHom hAltP hP0
    have hsum : ∀ z, finiteZeroAntiholomorphicHermiteSum n hn S c z =
        vandermonde z * MvPolynomial.eval z Q := by
      intro z
      rw [← eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c z]
      change MvPolynomial.eval z P = _
      rw [hfactor, map_mul, eval_polynomialVandermonde]
    change (finiteHomogeneousQuotientL2 hn S c hAltL2).1 ∈ _
    apply subset_closure
    apply Submodule.subset_span
    refine ⟨S, c, hAltL2, Q, ?_, hAltP, hP0, hfactor, hsum, hphase, rfl⟩
    intro q hq
    rw [Nat.add_sub_of_le hle]
    exact totalHolomorphicDegree_eq_of_mem_orbitSupport p q hq

/-- The closed ambient Ginibre space generated by all homogeneous polynomial
quotient degrees. -/
def ginibreFiniteQuotientGradedClosedSpan (n : ℕ) (hn : 0 < n) :
    ClosedSubmodule ℂ (Lp ℂ 2 (ginibreMeasure n)) :=
  ⨆ r : ℕ, ginibreFiniteQuotientDegreeClosedSpan n r hn

theorem inverse_alternatedHermite_mem_gradedClosedSpan
    (n : ℕ) (hn : 0 < n) (p : Fin n → ℕ) :
    ((vandermondeSymmetricAlternatingEquiv n hn).symm
      ⟨ComplexHermite.gaussianAlternationOperator n
          (ComplexHermite.hermiteL2Family n hn (p, 0)),
        ComplexHermite.gaussianAlternationOperator_mem n _⟩).1 ∈
      ginibreFiniteQuotientGradedClosedSpan n hn := by
  exact le_iSup (fun r : ℕ ↦ ginibreFiniteQuotientDegreeClosedSpan n r hn)
    (totalHolomorphicDegree p - vandermondeDegree n)
    (inverse_alternatedHermite_mem_degreeClosure n hn p)

/-- Alternation followed by inverse Vandermonde division, regarded as an
ambient continuous linear map. -/
def alternatedInverseVandermondeL2 (n : ℕ) (hn : 0 < n) :
    Lp ℂ 2 (complexGaussianMeasure n) →L[ℂ] Lp ℂ 2 (ginibreMeasure n) :=
  (ginibreSymmetricL2 n).subtypeL.comp
    ((vandermondeSymmetricAlternatingEquiv n hn).symm.toContinuousLinearEquiv.toContinuousLinearMap.comp
      ((ComplexHermite.gaussianAlternationOperator n).codRestrict
        (gaussianAlternatingL2 n)
        (ComplexHermite.gaussianAlternationOperator_mem n)))

/-- Every finite Gaussian antiholomorphic-degree-zero vector, after
alternation and inverse Vandermonde division, lies in the graded quotient
closed span. -/
theorem alternatedInverseVandermondeL2_mem_gradedClosedSpan
    (n : ℕ) (hn : 0 < n) (v : Lp ℂ 2 (complexGaussianMeasure n))
    (hv : v ∈ ComplexHermite.hermiteAntiDegreeSpan n hn 0) :
    alternatedInverseVandermondeL2 n hn v ∈
      ginibreFiniteQuotientGradedClosedSpan n hn := by
  refine Submodule.span_induction (p := fun w _ ↦
    alternatedInverseVandermondeL2 n hn w ∈
      ginibreFiniteQuotientGradedClosedSpan n hn) ?basis
      (map_zero (alternatedInverseVandermondeL2 n hn) ▸
        (ginibreFiniteQuotientGradedClosedSpan n hn).zero_mem)
      (fun x y _ _ hx hy ↦ by simpa using
        (ginibreFiniteQuotientGradedClosedSpan n hn).add_mem hx hy)
      (fun a x _ hx ↦ by
        rw [map_smul]
        exact (ginibreFiniteQuotientGradedClosedSpan n hn).smul_mem a hx) hv
  rintro w ⟨pq, hpq, rfl⟩
  rcases pq with ⟨p, q⟩
  have hq : q = 0 := by
    ext i
    have hall := (Finset.sum_eq_zero_iff_of_nonneg
      (fun j _ ↦ Nat.zero_le (q j))).mp hpq i (Finset.mem_univ i)
    exact hall
  subst q
  have hsub :
      ((ComplexHermite.gaussianAlternationOperator n).codRestrict
          (gaussianAlternatingL2 n)
          (ComplexHermite.gaussianAlternationOperator_mem n))
          (ComplexHermite.hermiteL2Family n hn (p, 0)) =
        (⟨ComplexHermite.gaussianAlternationOperator n
            (ComplexHermite.hermiteL2Family n hn (p, 0)),
          ComplexHermite.gaussianAlternationOperator_mem n _⟩ :
            gaussianAlternatingL2 n) := Subtype.ext rfl
  simp only [alternatedInverseVandermondeL2, ContinuousLinearMap.comp_apply]
  rw [hsub]
  exact inverse_alternatedHermite_mem_gradedClosedSpan n hn p

/-- The established holomorphic polynomial closure is contained in the
closed sum of its homogeneous quotient degrees. -/
theorem ginibreHolomorphicClosedSpan_le_gradedClosedSpan
    (n : ℕ) (hn : 0 < n) (u : ginibreSymmetricL2 n)
    (hu : u ∈ ComplexHermite.ginibreSymmetricHolomorphicPolynomialClosedSpan n hn) :
    u.1 ∈ ginibreFiniteQuotientGradedClosedSpan n hn := by
  change u ∈ (ComplexHermite.ginibreSymmetricHolomorphicPolynomialSpan n hn).topologicalClosure at hu
  have hle : ComplexHermite.ginibreSymmetricHolomorphicPolynomialSpan n hn ≤
      (ginibreFiniteQuotientGradedClosedSpan n hn).toSubmodule.comap
        (ginibreSymmetricL2 n).subtype := by
    rintro w ⟨v, hv, rfl⟩
    have hfin := alternatedInverseVandermondeL2_mem_gradedClosedSpan n hn v.1 hv
    have hfix : ComplexHermite.gaussianAlternationOperator n v.1 = v.1 :=
      ComplexHermite.gaussianAlternationOperator_eq_self_of_mem v.2
    have heq : alternatedInverseVandermondeL2 n hn v.1 =
        ((vandermondeSymmetricAlternatingEquiv n hn).symm v).1 := by
      have harg :
          ((ComplexHermite.gaussianAlternationOperator n).codRestrict
            (gaussianAlternatingL2 n)
            (ComplexHermite.gaussianAlternationOperator_mem n)) v.1 = v :=
        Subtype.ext hfix
      change (((vandermondeSymmetricAlternatingEquiv n hn).symm
        (((ComplexHermite.gaussianAlternationOperator n).codRestrict
          (gaussianAlternatingL2 n)
          (ComplexHermite.gaussianAlternationOperator_mem n)) v.1))).1 = _
      rw [harg]
    rw [heq] at hfin
    exact hfin
  have hclosed : IsClosed
      ((ginibreFiniteQuotientGradedClosedSpan n hn).toSubmodule.comap
        (ginibreSymmetricL2 n).subtype : Set (ginibreSymmetricL2 n)) :=
    (ginibreFiniteQuotientGradedClosedSpan n hn).isClosed.preimage
      (ginibreSymmetricL2 n).subtypeL.continuous
  exact (Submodule.topologicalClosure_minimal _ hle hclosed) hu

theorem finiteZeroHermiteL2_mem_antiDegreeZeroSpan
    (n : ℕ) (hn : 0 < n) (S : Finset (Fin n → ℕ))
    (c : (Fin n → ℕ) → ℂ) :
    finiteZeroHermiteL2 n hn S c ∈
      ComplexHermite.hermiteAntiDegreeSpan n hn 0 := by
  unfold finiteZeroHermiteL2
  apply Submodule.sum_mem
  intro p hp
  apply Submodule.smul_mem
  apply Submodule.subset_span
  refine ⟨(p, 0), ?_, rfl⟩
  simp [ComplexHermite.totalAntiDegree]

/-- Each finite homogeneous quotient generator is already one of the
finite holomorphic Ginibre vectors in the original definition. -/
theorem finiteHomogeneousQuotient_mem_holomorphicPolynomialSpan
    {n r : ℕ} (hn : 0 < n) {h : Lp ℂ 2 (ginibreMeasure n)}
    (hh : IsFiniteHomogeneousQuotientVector hn r h) :
    ∃ w : ginibreSymmetricL2 n,
      w ∈ ComplexHermite.ginibreSymmetricHolomorphicPolynomialSpan n hn ∧
        w.1 = h := by
  rcases hh with ⟨S, c, hAlt, Q, hdegree, hpolyAlt, hne, hfactor,
    hsum, hphase, rfl⟩
  let v : gaussianAlternatingL2 n := ⟨finiteZeroHermiteL2 n hn S c, hAlt⟩
  let w : ginibreSymmetricL2 n :=
    (vandermondeSymmetricAlternatingEquiv n hn).symm v
  refine ⟨w, ?_, rfl⟩
  exact ⟨v, finiteZeroHermiteL2_mem_antiDegreeZeroSpan n hn S c, rfl⟩

/-- The original symmetric holomorphic closed span, embedded in ambient
Ginibre `L²`. -/
def ginibreHolomorphicAmbientClosedSpan (n : ℕ) (hn : 0 < n) :
    ClosedSubmodule ℂ (Lp ℂ 2 (ginibreMeasure n)) where
  toSubmodule :=
    (ComplexHermite.ginibreSymmetricHolomorphicPolynomialClosedSpan n hn).toSubmodule.map
      (ginibreSymmetricL2 n).subtype
  isClosed' := by
    have he : Topology.IsClosedEmbedding
      (fun w : ginibreSymmetricL2 n ↦ w.1) :=
      (isClosed_ginibreSymmetricL2 n).isClosedEmbedding_subtypeVal
    change IsClosed ((fun w : ginibreSymmetricL2 n ↦ w.1) ''
      (ComplexHermite.ginibreSymmetricHolomorphicPolynomialClosedSpan n hn :
        Set (ginibreSymmetricL2 n)))
    rw [← he.isClosed_iff_image_isClosed]
    exact (ComplexHermite.ginibreSymmetricHolomorphicPolynomialClosedSpan n hn).isClosed

theorem ginibreFiniteQuotientDegreeClosedSpan_le_holomorphicAmbient
    (n r : ℕ) (hn : 0 < n) :
    ginibreFiniteQuotientDegreeClosedSpan n r hn ≤
      ginibreHolomorphicAmbientClosedSpan n hn := by
  apply Submodule.topologicalClosure_minimal
  · apply Submodule.span_le.2
    intro h hh
    obtain ⟨w, hw, rfl⟩ :=
      finiteHomogeneousQuotient_mem_holomorphicPolynomialSpan hn hh
    refine ⟨w, ?_, rfl⟩
    change w ∈ (ComplexHermite.ginibreSymmetricHolomorphicPolynomialSpan n hn).topologicalClosure
    exact (ComplexHermite.ginibreSymmetricHolomorphicPolynomialSpan n hn).le_topologicalClosure hw
  · exact (ginibreHolomorphicAmbientClosedSpan n hn).isClosed

theorem ginibreGradedClosedSpan_le_holomorphicAmbient
    (n : ℕ) (hn : 0 < n) :
    ginibreFiniteQuotientGradedClosedSpan n hn ≤
      ginibreHolomorphicAmbientClosedSpan n hn := by
  apply iSup_le
  intro r
  exact ginibreFiniteQuotientDegreeClosedSpan_le_holomorphicAmbient n r hn

theorem ginibreHolomorphicAmbientClosedSpan_eq_graded
    (n : ℕ) (hn : 0 < n) :
    ginibreHolomorphicAmbientClosedSpan n hn =
      ginibreFiniteQuotientGradedClosedSpan n hn := by
  apply le_antisymm
  · rintro h ⟨w, hw, rfl⟩
    exact ginibreHolomorphicClosedSpan_le_gradedClosedSpan n hn w hw
  · exact ginibreGradedClosedSpan_le_holomorphicAmbient n hn

/-- Closed sum of the strictly positive homogeneous quotient degrees. -/
def ginibrePositiveQuotientGradedClosedSpan (n : ℕ) (hn : 0 < n) :
    ClosedSubmodule ℂ (Lp ℂ 2 (ginibreMeasure n)) :=
  ⨆ r : {r : ℕ // 0 < r},
    ginibreFiniteQuotientDegreeClosedSpan n r.1 hn

theorem ginibrePositiveQuotientGradedClosedSpan_le_graded
    (n : ℕ) (hn : 0 < n) :
    ginibrePositiveQuotientGradedClosedSpan n hn ≤
      ginibreFiniteQuotientGradedClosedSpan n hn := by
  apply iSup_le
  intro r
  exact le_iSup (fun d : ℕ ↦ ginibreFiniteQuotientDegreeClosedSpan n d hn) r.1

theorem ginibreFiniteQuotientDegreeClosedSpan_le_positive
    (n r : ℕ) (hn : 0 < n) (hr : 0 < r) :
    ginibreFiniteQuotientDegreeClosedSpan n r hn ≤
      ginibrePositiveQuotientGradedClosedSpan n hn := by
  exact le_iSup (fun d : {d : ℕ // 0 < d} ↦
    ginibreFiniteQuotientDegreeClosedSpan n d.1 hn) ⟨r, hr⟩

theorem ginibreGradedClosedSpan_eq_degreeZero_sup_positive
    (n : ℕ) (hn : 0 < n) :
    ginibreFiniteQuotientGradedClosedSpan n hn =
      ginibreFiniteQuotientDegreeClosedSpan n 0 hn ⊔
        ginibrePositiveQuotientGradedClosedSpan n hn := by
  apply le_antisymm
  · apply iSup_le
    intro r
    by_cases hr : r = 0
    · subst r
      exact le_sup_left
    · exact (ginibreFiniteQuotientDegreeClosedSpan_le_positive n r hn
        (Nat.pos_of_ne_zero hr)).trans le_sup_right
  · apply sup_le
    · exact le_iSup (fun d : ℕ ↦
        ginibreFiniteQuotientDegreeClosedSpan n d hn) 0
    · exact ginibrePositiveQuotientGradedClosedSpan_le_graded n hn

private def ginibrePositiveQuotientAlgebraicSpan (n : ℕ) (hn : 0 < n) :
    Submodule ℂ (Lp ℂ 2 (ginibreMeasure n)) :=
  ⨆ r : {r : ℕ // 0 < r},
    (ginibreFiniteQuotientDegreeClosedSpan n r.1 hn).toSubmodule

theorem inner_star_eq_zero_of_mem_positiveQuotientAlgebraicSpan
    {n : ℕ} (hn : 0 < n) {x y : Lp ℂ 2 (ginibreMeasure n)}
    (hx : x ∈ ginibrePositiveQuotientAlgebraicSpan n hn)
    (hy : y ∈ ginibrePositiveQuotientAlgebraicSpan n hn) :
    inner ℂ x (star y) = 0 := by
  refine Submodule.iSup_induction
    (fun r : {r : ℕ // 0 < r} ↦
      (ginibreFiniteQuotientDegreeClosedSpan n r.1 hn).toSubmodule)
    (motive := fun x ↦ inner ℂ x (star y) = 0)
    hx ?_ (by simp) (fun a b ha hb ↦ by rw [inner_add_left, ha, hb, add_zero])
  intro r xr hxr
  refine Submodule.iSup_induction
    (fun s : {s : ℕ // 0 < s} ↦
      (ginibreFiniteQuotientDegreeClosedSpan n s.1 hn).toSubmodule)
    (motive := fun y ↦ inner ℂ xr (star y) = 0)
    hy ?_ (by
      have hz : star (0 : Lp ℂ 2 (ginibreMeasure n)) = 0 := by
        apply norm_eq_zero.mp
        rw [Lp_norm_star, norm_zero]
      rw [hz, inner_zero_right]) (fun a b ha hb ↦ by
      rw [Lp_star_add, inner_add_right, ha, hb, add_zero])
  intro s ys hys
  exact inner_star_eq_zero_of_mem_finiteQuotientDegreeClosures hn
    (Nat.add_pos_left r.2 s.1) hxr hys

private def ginibreLpConjugationIsometry (n : ℕ) :
    Lp ℂ 2 (ginibreMeasure n) →ₗᵢ[ℝ] Lp ℂ 2 (ginibreMeasure n) where
  toLinearMap :=
    { toFun := star
      map_add' := Lp_star_add
      map_smul' := Lp_star_real_smul }
  norm_map' := Lp_norm_star

private theorem inner_star_eq_zero_positiveClosure_left
    {n : ℕ} (hn : 0 < n) {x y : Lp ℂ 2 (ginibreMeasure n)}
    (hx : x ∈ ginibrePositiveQuotientGradedClosedSpan n hn)
    (hy : y ∈ ginibrePositiveQuotientAlgebraicSpan n hn) :
    inner ℂ x (star y) = 0 := by
  rw [ginibrePositiveQuotientGradedClosedSpan, ClosedSubmodule.mem_iSup] at hx
  change x ∈ closure (ginibrePositiveQuotientAlgebraicSpan n hn :
    Set (Lp ℂ 2 (ginibreMeasure n))) at hx
  let Z : Set (Lp ℂ 2 (ginibreMeasure n)) :=
    {x | inner ℂ x (star y) = 0}
  have hZ : IsClosed Z := by
    apply isClosed_eq
    · exact continuous_inner.comp (continuous_id.prodMk continuous_const)
    · exact continuous_const
  exact (closure_minimal (fun z hz ↦
    inner_star_eq_zero_of_mem_positiveQuotientAlgebraicSpan hn hz hy) hZ) hx

theorem inner_star_eq_zero_of_mem_positiveQuotientGradedClosedSpan
    {n : ℕ} (hn : 0 < n) {x y : Lp ℂ 2 (ginibreMeasure n)}
    (hx : x ∈ ginibrePositiveQuotientGradedClosedSpan n hn)
    (hy : y ∈ ginibrePositiveQuotientGradedClosedSpan n hn) :
    inner ℂ x (star y) = 0 := by
  rw [ginibrePositiveQuotientGradedClosedSpan, ClosedSubmodule.mem_iSup] at hy
  change y ∈ closure (ginibrePositiveQuotientAlgebraicSpan n hn :
    Set (Lp ℂ 2 (ginibreMeasure n))) at hy
  let Z : Set (Lp ℂ 2 (ginibreMeasure n)) :=
    {y | inner ℂ x (star y) = 0}
  have hZ : IsClosed Z := by
    apply isClosed_eq
    · exact continuous_inner.comp
        (continuous_const.prodMk (ginibreLpConjugationIsometry n).continuous)
    · exact continuous_const
  exact (closure_minimal (fun z hz ↦
    inner_star_eq_zero_positiveClosure_left hn hx hz) hZ) hy

/-- The complex `L²` representative of a centered real observable is fixed
by pointwise conjugation. -/
theorem star_centeredObservableL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    star (centeredObservableL2 hn f hf) = centeredObservableL2 hn f hf := by
  apply Lp.ext
  filter_upwards [Lp.coeFn_star (centeredObservableL2 hn f hf),
    centeredObservableL2_coeFn hn f hf] with z hs hc
  rw [hs]
  calc
    star ((centeredObservableL2 hn f hf) z) =
        star (centeredObservable n f z : ℂ) := congrArg star hc
    _ = (centeredObservable n f z : ℂ) := by simp
    _ = (centeredObservableL2 hn f hf) z := hc.symm

theorem integral_centeredObservable_eq_zero {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    ∫ z, centeredObservable n f z ∂ginibreMeasure n = 0 := by
  letI := ginibreProbabilityInstance hn
  have hfi : Integrable f (ginibreMeasure n) :=
    hf.1.continuous.integrable_of_hasCompactSupport hf.2.1
  simp only [centeredObservable]
  rw [integral_sub hfi (integrable_const (smoothGinibreMean n f))]
  simp [smoothGinibreMean]

theorem inner_ginibreConstantL2_centeredObservableL2_eq_zero
    {n : ℕ} (hn : 0 < n) (a : ℂ)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    inner ℂ (ginibreConstantL2 n hn a) (centeredObservableL2 hn f hf) = 0 := by
  rw [MeasureTheory.L2.inner_def]
  letI := ginibreProbabilityInstance hn
  rw [integral_congr_ae (show
    (fun z ↦ inner ℂ ((ginibreConstantL2 n hn a) z)
      ((centeredObservableL2 hn f hf) z)) =ᵐ[ginibreMeasure n]
      (fun z ↦ (centeredObservable n f z : ℂ) * star a) by
    filter_upwards [Lp.coeFn_const (α := Configuration n)
        (μ := ginibreMeasure n) (p := (2 : ℝ≥0∞)) a,
      centeredObservableL2_coeFn hn f hf] with z ha hc
    change inner ℂ ((Lp.const 2 (ginibreMeasure n) a) z)
      ((centeredObservableL2 hn f hf) z) = _
    rw [ha, hc]
    simp [RCLike.inner_apply])]
  rw [integral_mul_const]
  have hz : ∫ z, (centeredObservable n f z : ℂ) ∂ginibreMeasure n = 0 := by
    rw [integral_complex_ofReal, integral_centeredObservable_eq_zero hn f hf]
    simp
  rw [hz, zero_mul]

theorem inner_eq_zero_of_mem_constants_centeredObservableL2
    {n : ℕ} (hn : 0 < n) {c : Lp ℂ 2 (ginibreMeasure n)}
    (hc : c ∈ ginibreConstantClosedSubspace n hn)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    inner ℂ c (centeredObservableL2 hn f hf) = 0 := by
  rcases hc with ⟨a, rfl⟩
  exact inner_ginibreConstantL2_centeredObservableL2_eq_zero hn a f hf

theorem degreeZero_orthogonal_positiveGraded
    {n : ℕ} (hn : 0 < n) {c p : Lp ℂ 2 (ginibreMeasure n)}
    (hc : c ∈ ginibreFiniteQuotientDegreeClosedSpan n 0 hn)
    (hp : p ∈ ginibrePositiveQuotientGradedClosedSpan n hn) :
    inner ℂ c p = 0 := by
  rw [ginibrePositiveQuotientGradedClosedSpan, ClosedSubmodule.mem_iSup] at hp
  let Z : Set (Lp ℂ 2 (ginibreMeasure n)) := {p | inner ℂ c p = 0}
  have hZ : IsClosed Z := by
    apply isClosed_eq
    · exact continuous_inner.comp (continuous_const.prodMk continuous_id)
    · exact continuous_const
  apply (closure_minimal ?_ hZ) hp
  intro p hp
  refine Submodule.iSup_induction
    (fun r : {r : ℕ // 0 < r} ↦
      (ginibreFiniteQuotientDegreeClosedSpan n r.1 hn).toSubmodule)
    (motive := fun p ↦ p ∈ Z)
    hp ?_ (by
      change inner ℂ c (0 : Lp ℂ 2 (ginibreMeasure n)) = 0
      simp)
      (fun x y hx hy ↦ by
        change inner ℂ c (x + y) = 0
        rw [inner_add_right, hx, hy, add_zero])
  intro r x hx
  change inner ℂ c x = 0
  have hxc := ginibreFiniteQuotientDegreeClosedSpan_orthogonal hn
    (Nat.ne_of_lt r.2) hc x hx
  rw [← inner_conj_symm c x, hxc, map_zero]

theorem eq_zero_of_mem_holomorphic_of_orthogonal_degreeZero_positive
    {n : ℕ} (hn : 0 < n) {d : Lp ℂ 2 (ginibreMeasure n)}
    (hdH : d ∈ ginibreHolomorphicAmbientClosedSpan n hn)
    (hdC : ∀ c ∈ ginibreFiniteQuotientDegreeClosedSpan n 0 hn,
      inner ℂ d c = 0)
    (hdP : ∀ p ∈ ginibrePositiveQuotientGradedClosedSpan n hn,
      inner ℂ d p = 0) : d = 0 := by
  have hdH' : d ∈
      ginibreFiniteQuotientDegreeClosedSpan n 0 hn ⊔
        ginibrePositiveQuotientGradedClosedSpan n hn := by
    rw [ginibreHolomorphicAmbientClosedSpan_eq_graded,
      ginibreGradedClosedSpan_eq_degreeZero_sup_positive] at hdH
    exact hdH
  rw [ClosedSubmodule.mem_sup] at hdH'
  let Z : Set (Lp ℂ 2 (ginibreMeasure n)) := {z | inner ℂ d z = 0}
  have hZ : IsClosed Z := by
    apply isClosed_eq
    · exact continuous_inner.comp (continuous_const.prodMk continuous_id)
    · exact continuous_const
  have hsub :
      {z | z ∈ (ginibreFiniteQuotientDegreeClosedSpan n 0 hn).toSubmodule ⊔
        (ginibrePositiveQuotientGradedClosedSpan n hn).toSubmodule} ⊆ Z := by
    intro z hz
    rcases Submodule.mem_sup.mp hz with ⟨c, hc, p, hp, rfl⟩
    change inner ℂ d (c + p) = 0
    rw [inner_add_right, hdC c hc, hdP p hp, add_zero]
  have hdd : inner ℂ d d = 0 := (closure_minimal hsub hZ) hdH'
  exact inner_self_eq_zero.mp hdd

theorem holomorphicProjection_centeredObservable_mem_positive
    {n : ℕ} (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) :
    (ginibreHolomorphicAmbientClosedSpan n hn).starProjection
        (centeredObservableL2 hn f hf) ∈
      ginibrePositiveQuotientGradedClosedSpan n hn := by
  let H := ginibreHolomorphicAmbientClosedSpan n hn
  let P := ginibrePositiveQuotientGradedClosedSpan n hn
  let u := centeredObservableL2 hn f hf
  let h := H.starProjection u
  let q := P.starProjection h
  have hhH : h ∈ H.toSubmodule := by
    exact Submodule.starProjection_apply_mem H.toSubmodule u
  have hqP : q ∈ P.toSubmodule := by
    exact Submodule.starProjection_apply_mem P.toSubmodule h
  have hPH : P ≤ H := by
    dsimp [P, H]
    rw [ginibreHolomorphicAmbientClosedSpan_eq_graded]
    exact ginibrePositiveQuotientGradedClosedSpan_le_graded n hn
  have hqH : q ∈ H := hPH hqP
  have hdH : h - q ∈ H := H.sub_mem hhH hqH
  have hdP : ∀ p ∈ P, inner ℂ (h - q) p = 0 := by
    intro p hp
    exact Submodule.starProjection_inner_eq_zero h p hp
  have hhC : ∀ c ∈ ginibreFiniteQuotientDegreeClosedSpan n 0 hn,
      inner ℂ h c = 0 := by
    intro c hc
    have hcconst : c ∈ ginibreConstantClosedSubspace n hn := by
      rw [← ginibreFiniteQuotientDegreeZero_eq_constants n hn]
      exact hc
    have hcu : inner ℂ c u = 0 :=
      inner_eq_zero_of_mem_constants_centeredObservableL2 hn hcconst f hf
    have huc : inner ℂ u c = 0 := by
      rw [← inner_conj_symm u c, hcu, map_zero]
    have hcH : c ∈ H := by
      dsimp [H]
      rw [ginibreHolomorphicAmbientClosedSpan_eq_graded]
      exact le_iSup (fun d : ℕ ↦
        ginibreFiniteQuotientDegreeClosedSpan n d hn) 0 hc
    have hres : inner ℂ (u - h) c = 0 :=
      Submodule.starProjection_inner_eq_zero u c hcH
    rw [inner_sub_left] at hres
    rw [huc, zero_sub] at hres
    exact neg_eq_zero.mp hres
  have hdC : ∀ c ∈ ginibreFiniteQuotientDegreeClosedSpan n 0 hn,
      inner ℂ (h - q) c = 0 := by
    intro c hc
    have hcq := degreeZero_orthogonal_positiveGraded hn hc hqP
    have hqc : inner ℂ q c = 0 := by
      rw [← inner_conj_symm q c, hcq, map_zero]
    rw [inner_sub_left, hhC c hc, hqc, sub_zero]
  have hd0 := eq_zero_of_mem_holomorphic_of_orthogonal_degreeZero_positive
    hn hdH hdC hdP
  have hhq : h = q := sub_eq_zero.mp hd0
  have : h ∈ P := by rwa [hhq]
  simpa [h, P] using this

theorem inner_holomorphicProjection_star_eq_zero
    {n : ℕ} (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) :
    let h := (ginibreHolomorphicAmbientClosedSpan n hn).starProjection
      (centeredObservableL2 hn f hf)
    inner ℂ h (star h) = 0 := by
  dsimp
  apply inner_star_eq_zero_of_mem_positiveQuotientGradedClosedSpan hn
  · exact holomorphicProjection_centeredObservable_mem_positive hn f hf
  · exact holomorphicProjection_centeredObservable_mem_positive hn f hf

private theorem inner_Lp_star_star {n : ℕ}
    (x y : Lp ℂ 2 (ginibreMeasure n)) :
    inner ℂ (star x) (star y) = star (inner ℂ x y) := by
  rw [MeasureTheory.L2.inner_def, MeasureTheory.L2.inner_def]
  rw [integral_congr_ae (show
    (fun z ↦ inner ℂ ((star x) z) ((star y) z)) =ᵐ[ginibreMeasure n]
      (fun z ↦ star (inner ℂ (x z) (y z))) by
    filter_upwards [Lp.coeFn_star x, Lp.coeFn_star y] with z hx hy
    change inner ℂ ((star x) z) ((star y) z) = _
    rw [hx, hy]
    simp [RCLike.inner_apply])]
  exact integral_conj

/-- Pythagorean identity for the three-term real/holomorphic geometry once
the three pairwise orthogonality relations have been established. -/
theorem norm_sq_eq_two_mul_norm_sq_add_of_h_star_remainder_orthogonal
    {n : ℕ} (h r : Lp ℂ 2 (ginibreMeasure n))
    (hhs : inner ℂ h (star h) = 0)
    (hhr : inner ℂ h r = 0)
    (hsr : inner ℂ (star h) r = 0) :
    ‖h + star h + r‖ ^ 2 = 2 * ‖h‖ ^ 2 + ‖r‖ ^ 2 := by
  simp only [pow_two]
  have hadd : inner ℂ (h + star h) r = 0 := by
    rw [inner_add_left, hhr, hsr, add_zero]
  rw [norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero _ _ hadd]
  rw [norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero _ _ hhs]
  rw [Lp_norm_star]
  ring

/-- The complete centered holomorphic/conjugate/remainder geometry. -/
theorem centeredHolomorphicRemainderGeometry
    {n : ℕ} (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) :
    let u := centeredObservableL2 hn f hf
    let h := (ginibreHolomorphicAmbientClosedSpan n hn).starProjection u
    let r := u - h - star h
    inner ℂ h (star h) = 0 ∧ inner ℂ h r = 0 ∧
      inner ℂ (star h) r = 0 ∧
      smoothGinibreVariance n f = 2 * ‖h‖ ^ 2 + ‖r‖ ^ 2 := by
  dsimp
  let u := centeredObservableL2 hn f hf
  let H := ginibreHolomorphicAmbientClosedSpan n hn
  let h := H.starProjection u
  let r := u - h - star h
  have hhs : inner ℂ h (star h) = 0 := by
    exact inner_holomorphicProjection_star_eq_zero hn f hf
  have hhH : h ∈ H.toSubmodule := by
    exact Submodule.starProjection_apply_mem H.toSubmodule u
  have heh : inner ℂ (u - h) h = 0 :=
    Submodule.starProjection_inner_eq_zero u h hhH
  have hhe : inner ℂ h (u - h) = 0 := by
    rw [← inner_conj_symm h (u - h), heh, map_zero]
  have hhr : inner ℂ h r = 0 := by
    dsimp [r]
    rw [inner_sub_right, hhe, hhs, sub_zero]
  have hstaru : star u = u := star_centeredObservableL2 hn f hf
  have hstarsub : star (u - h) = u - star h := by
    rw [sub_eq_add_neg, Lp_star_add]
    have hneg : star (-h) = -star h := by
      simpa using Lp_star_real_smul (-1) h
    rw [hneg, hstaru]
    simp [sub_eq_add_neg]
  have hse : inner ℂ (star h) (u - star h) = 0 := by
    have hc := inner_Lp_star_star h (u - h)
    rw [hhe, hstarsub] at hc
    simpa using hc
  have hsr : inner ℂ (star h) r = 0 := by
    dsimp [r]
    rw [inner_sub_right, inner_sub_right]
    have hsh : inner ℂ (star h) h = 0 := by
      rw [← inner_conj_symm (star h) h, hhs, map_zero]
    rw [hsh, sub_zero]
    simpa [inner_sub_right] using hse
  refine ⟨hhs, hhr, hsr, ?_⟩
  have hnorm := norm_sq_eq_two_mul_norm_sq_add_of_h_star_remainder_orthogonal
    h r hhs hhr hsr
  have hur : h + star h + r = u := by
    dsimp [r]
    abel
  rw [hur] at hnorm
  rw [← norm_sq_centeredObservableL2 hn f hf]
  exact hnorm

@[simp] theorem ginibreSymmetricConjugation_coe (n : ℕ)
    (u : ginibreSymmetricL2 n) :
    (ginibreSymmetricConjugation n u).1 = star u.1 := rfl

@[simp] theorem ginibreSymmetricConjugation_involutive (n : ℕ)
    (u : ginibreSymmetricL2 n) :
    ginibreSymmetricConjugation n (ginibreSymmetricConjugation n u) = u := by
  apply Subtype.ext
  simp [ginibreSymmetricConjugation]

/-- Pointwise conjugation as a real-linear isometric involution. -/
def ginibreSymmetricConjugationEquiv (n : ℕ) :
    ginibreSymmetricL2 n ≃ₗᵢ[ℝ] ginibreSymmetricL2 n where
  toFun := ginibreSymmetricConjugation n
  invFun := ginibreSymmetricConjugation n
  left_inv := ginibreSymmetricConjugation_involutive n
  right_inv := ginibreSymmetricConjugation_involutive n
  map_add' u v := by
    apply Subtype.ext
    exact Lp_star_add u.1 v.1
  map_smul' r u := by
    apply Subtype.ext
    exact Lp_star_real_smul r u.1
  norm_map' u := by
    change ‖star u.1‖ = ‖u.1‖
    exact Lp_norm_star u.1

@[simp] theorem ginibreSymmetricConjugationEquiv_apply (n : ℕ)
    (u : ginibreSymmetricL2 n) :
    ginibreSymmetricConjugationEquiv n u = ginibreSymmetricConjugation n u :=
  rfl

end
end GinibrePoincare
Analysis GinibrePoincare/Analysis/GinibreGeneratorL2.lean #
import GinibrePoincare.Analysis.GinibreIntegrationByParts

open MeasureTheory
open Filter Topology

namespace GinibrePoincare

noncomputable section

/-- The concrete pregenerator vanishes away from the topological support of
the observable. -/
theorem ginibrePregenerator_eq_zero_of_notMem_tsupport {n : ℕ}
    (f : Configuration n → ℝ) {z : Configuration n}
    (hz : z ∉ tsupport f) : ginibrePregenerator n f z = 0 := by
  have hdf : fderiv ℝ f z = 0 := fderiv_of_notMem_tsupport ℝ hz
  have hsecond (v : Configuration n) :
      secondDirectionalDerivative f v z = 0 := by
    unfold secondDirectionalDerivative
    have hsub : tsupport (fun x => fderiv ℝ f x v) ⊆ tsupport f :=
      tsupport_fderiv_apply_subset ℝ v
    have hz' : z ∉ tsupport (fun x => fderiv ℝ f x v) :=
      fun h => hz (hsub h)
    rw [fderiv_of_notMem_tsupport ℝ hz']
    rfl
  simp [ginibrePregenerator, configurationLaplacian, hdf, hsecond]

/-- The pregenerator of a compactly supported observable remains compactly
supported. -/
theorem hasCompactSupport_ginibrePregenerator {n : ℕ}
    {f : Configuration n → ℝ} (hf : HasCompactSupport f) :
    HasCompactSupport (ginibrePregenerator n f) := by
  apply HasCompactSupport.intro hf
  intro z hz
  exact ginibrePregenerator_eq_zero_of_notMem_tsupport f hz

theorem continuousAt_ginibrePregenerator_of_collisionFree {n : ℕ}
    {f : Configuration n → ℝ} (hf : ContDiff ℝ 2 f)
    {z : Configuration n} (hz : CollisionFree z) :
    ContinuousAt (ginibrePregenerator n f) z := by
  have hdf : Continuous (fderiv ℝ f) := hf.continuous_fderiv (by simp)
  have hsecond (v : Configuration n) :
      Continuous (fun x => secondDirectionalDerivative f v x) := by
    unfold secondDirectionalDerivative
    have hfirst : ContDiff ℝ 1 (fun x => fderiv ℝ f x v) := by
      have hp : ContDiff ℝ 1 (fun x : Configuration n => (x, v)) :=
        contDiff_id.prodMk contDiff_const
      exact (hf.contDiff_fderiv_apply (m := 1) (by norm_num)).comp hp
    exact (hfirst.continuous_fderiv (by simp)).clm_apply continuous_const
  have hcoul (j k : Fin n) (hjk : j < k) :
      ContinuousAt (fun x => fderiv ℝ f x (coulombPairDirection j k x)) z := by
    have hne : z j - z k ≠ 0 := sub_ne_zero.mpr (fun h => hjk.ne (hz h))
    apply hdf.continuousAt.clm_apply
    have hsub : Continuous (fun x : Configuration n => x j - x k) :=
      (continuous_apply j).sub (continuous_apply k)
    have hfrac : ContinuousAt
        (fun x : Configuration n => (x j - x k) /
          (Complex.normSq (x j - x k) : ℂ)) z := by
      apply hsub.continuousAt.div₀
        (Complex.continuous_ofReal.comp (Complex.continuous_normSq.comp hsub)).continuousAt
      exact Complex.ofReal_ne_zero.mpr (ne_of_gt (Complex.normSq_pos.mpr hne))
    unfold coulombPairDirection
    apply ContinuousAt.sub <;> unfold coordinateDirection <;>
      rw [continuousAt_pi] <;> intro i
    · by_cases hi : i = j
      · subst i
        simp only [if_pos]
        exact hfrac
      · simp only [hi, if_neg]
        exact continuousAt_const
    · by_cases hi : i = k
      · subst i
        simp only [if_pos]
        exact hfrac
      · simp only [hi, if_neg]
        exact continuousAt_const
  unfold ginibrePregenerator configurationLaplacian
  apply ContinuousAt.add
  · apply ContinuousAt.sub
    · exact ((continuous_finset_sum _ fun j _ =>
        (hsecond _).add (hsecond _)).continuousAt).const_mul _
    · apply ContinuousAt.const_mul
      apply (continuous_finset_sum _ fun j _ => ?_).continuousAt
      apply hdf.clm_apply
      unfold coordinateDirection
      apply continuous_pi
      intro i
      by_cases hi : i = j
      · subst i; simpa using continuous_apply j
      · simpa [hi] using (continuous_const : Continuous (fun _ : Configuration n => (0 : ℂ)))
  · apply ContinuousAt.const_mul
    have hsum {ι : Type} (s : Finset ι) (g : ι → Configuration n → ℝ)
        (hg : ∀ i ∈ s, ContinuousAt (g i) z) :
        ContinuousAt (fun x => ∑ i ∈ s, g i x) z := by
      classical
      induction s using Finset.induction_on with
      | empty => simpa using (continuousAt_const : ContinuousAt (fun _ : Configuration n => (0 : ℝ)) z)
      | @insert a s ha ih =>
          simp only [Finset.sum_insert ha]
          exact (hg a (Finset.mem_insert_self _ _)).add
            (ih fun i hi => hg i (Finset.mem_insert_of_mem hi))
    apply hsum Finset.univ
    intro j hj
    apply hsum (Finset.Ioi j)
    intro k hk
    exact hcoul j k (Finset.mem_Ioi.mp hk)

/-- On the theorem core the apparent Coulomb singularity never meets the
support, so the concrete pregenerator has a continuous representative. -/
theorem continuous_ginibrePregenerator_of_core {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    Continuous (ginibrePregenerator n f) := by
  rw [continuous_iff_continuousAt]
  intro z
  by_cases hz : z ∈ tsupport f
  · have h2 : (2 : WithTop ℕ∞) ≤ (↑(⊤ : ℕ∞) : WithTop ℕ∞) :=
      WithTop.coe_le_coe.mpr le_top
    exact continuousAt_ginibrePregenerator_of_collisionFree (hf.1.of_le h2)
      ((collisionFree_iff_not_mem_collisionSet z).mpr (hf.2.2.1 hz))
  · have heq : ginibrePregenerator n f =ᶠ[𝓝 z] (fun _ => 0) := by
      filter_upwards [((isClosed_tsupport f).isOpen_compl.mem_nhds hz)] with y hy
      exact ginibrePregenerator_eq_zero_of_notMem_tsupport f hy
    exact continuousAt_const.congr_of_eventuallyEq heq

/-- The complex-valued concrete pregenerator belongs to Ginibre `L²`. -/
theorem memLp_ginibrePregenerator_of_core {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    MemLp (fun z => (ginibrePregenerator n f z : ℂ)) 2 (ginibreMeasure n) := by
  letI := ginibreMeasure_isProbabilityMeasure hn
  apply (Complex.continuous_ofReal.comp
    (continuous_ginibrePregenerator_of_core hf)).memLp_of_hasCompactSupport
  apply (hasCompactSupport_ginibrePregenerator hf.2.1).mono
  intro z hz hzero
  apply hz
  simp [hzero]

/-- The Ginibre `L²` class represented by the concrete pregenerator. -/
def ginibrePregeneratorL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    Lp ℂ 2 (ginibreMeasure n) :=
  (memLp_ginibrePregenerator_of_core hn f hf).toLp _

theorem ginibrePregeneratorL2_coeFn {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    ginibrePregeneratorL2 hn f hf =ᵐ[ginibreMeasure n]
      fun z => (ginibrePregenerator n f z : ℂ) :=
  (memLp_ginibrePregenerator_of_core hn f hf).coeFn_toLp

theorem norm_sq_ginibrePregeneratorL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    ‖ginibrePregeneratorL2 hn f hf‖ ^ 2 = ginibreGeneratorNormSq n f := by
  have hinner : inner ℂ (ginibrePregeneratorL2 hn f hf)
      (ginibrePregeneratorL2 hn f hf) =
      ∫ z, inner ℂ ((ginibrePregeneratorL2 hn f hf) z)
        ((ginibrePregeneratorL2 hn f hf) z) ∂ginibreMeasure n :=
    MeasureTheory.L2.inner_def _ _
  rw [inner_self_eq_norm_sq_to_K] at hinner
  have hc := ginibrePregeneratorL2_coeFn hn f hf
  rw [integral_congr_ae (by
    filter_upwards [hc] with z hz
    rw [hz])] at hinner
  have hi : (fun z => inner ℂ (ginibrePregenerator n f z : ℂ)
      (ginibrePregenerator n f z : ℂ)) =
      fun z => ((ginibrePregenerator n f z ^ 2 : ℝ) : ℂ) := by
    funext z
    simp only [RCLike.inner_apply, Complex.conj_ofReal, ← Complex.ofReal_mul,
      Complex.ofReal_inj, pow_two]
  rw [hi, integral_complex_ofReal] at hinner
  have hr : ‖ginibrePregeneratorL2 hn f hf‖ ^ 2 =
      ∫ z, ginibrePregenerator n f z ^ 2 ∂ginibreMeasure n := by
    apply Complex.ofReal_injective
    convert hinner using 1 <;>
      simp [RCLike.inner_apply, ← Complex.ofReal_mul, ← Complex.ofReal_pow]
  exact hr

theorem memLp_shiftedGinibrePregenerator_of_core {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    MemLp (fun z => ((ginibrePregenerator n f z + 2 * f z : ℝ) : ℂ)) 2
      (ginibreMeasure n) := by
  have hgen := memLp_ginibrePregenerator_of_core hn f hf
  letI := ginibreMeasure_isProbabilityMeasure hn
  have hfun : MemLp (fun z => (f z : ℂ)) 2 (ginibreMeasure n) :=
    (Complex.continuous_ofReal.comp hf.1.continuous).memLp_of_hasCompactSupport
      (by
        apply hf.2.1.mono
        intro z hz hzero
        apply hz
        simp [hzero])
  convert hgen.add (hfun.const_mul 2) using 1 <;> ext z <;> simp

/-- The `L²` class represented by `(Aₙ + 2)f`. -/
def shiftedGinibrePregeneratorL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    Lp ℂ 2 (ginibreMeasure n) :=
  (memLp_shiftedGinibrePregenerator_of_core hn f hf).toLp _

theorem shiftedGinibrePregeneratorL2_coeFn {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    shiftedGinibrePregeneratorL2 hn f hf =ᵐ[ginibreMeasure n]
      fun z => ((ginibrePregenerator n f z + 2 * f z : ℝ) : ℂ) :=
  (memLp_shiftedGinibrePregenerator_of_core hn f hf).coeFn_toLp

theorem norm_sq_shiftedGinibrePregeneratorL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    ‖shiftedGinibrePregeneratorL2 hn f hf‖ ^ 2 =
      shiftedGinibreGeneratorNormSq n f := by
  have hinner : inner ℂ (shiftedGinibrePregeneratorL2 hn f hf)
      (shiftedGinibrePregeneratorL2 hn f hf) =
      ∫ z, inner ℂ ((shiftedGinibrePregeneratorL2 hn f hf) z)
        ((shiftedGinibrePregeneratorL2 hn f hf) z) ∂ginibreMeasure n :=
    MeasureTheory.L2.inner_def _ _
  rw [inner_self_eq_norm_sq_to_K] at hinner
  have hc := shiftedGinibrePregeneratorL2_coeFn hn f hf
  rw [integral_congr_ae (by
    filter_upwards [hc] with z hz
    rw [hz])] at hinner
  have hi : (fun z => inner ℂ
      ((ginibrePregenerator n f z + 2 * f z : ℝ) : ℂ)
      ((ginibrePregenerator n f z + 2 * f z : ℝ) : ℂ)) =
      fun z => (((ginibrePregenerator n f z + 2 * f z) ^ 2 : ℝ) : ℂ) := by
    funext z
    simp only [RCLike.inner_apply, Complex.conj_ofReal, ← Complex.ofReal_mul,
      Complex.ofReal_inj, pow_two]
  rw [hi, integral_complex_ofReal] at hinner
  have hr : ‖shiftedGinibrePregeneratorL2 hn f hf‖ ^ 2 =
      ∫ z, (ginibrePregenerator n f z + 2 * f z) ^ 2 ∂ginibreMeasure n := by
    apply Complex.ofReal_injective
    convert hinner using 1 <;>
      simp [RCLike.inner_apply, ← Complex.ofReal_mul, ← Complex.ofReal_pow,
        Complex.normSq_apply]
  exact hr

/-- The Hilbert inner product of the centered observable with its concrete
pregenerator is exactly minus the Dirichlet energy. -/
theorem inner_centeredObservableL2_ginibrePregeneratorL2 {n : ℕ}
    (hn : 0 < n) (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    inner ℂ (centeredObservableL2 hn f hf) (ginibrePregeneratorL2 hn f hf) =
      (-smoothGinibreEnergy n f : ℂ) := by
  rw [MeasureTheory.L2.inner_def]
  have hc := centeredObservableL2_coeFn hn f hf
  have hA := ginibrePregeneratorL2_coeFn hn f hf
  rw [integral_congr_ae (by
    filter_upwards [hc, hA] with z hcz hAz
    rw [hcz, hAz])]
  have hi : (fun z => inner ℂ (centeredObservable n f z : ℂ)
      (ginibrePregenerator n f z : ℂ)) =
      fun z => ((ginibrePregenerator n f z * centeredObservable n f z : ℝ) : ℂ) := by
    funext z
    simp only [RCLike.inner_apply, Complex.conj_ofReal, ← Complex.ofReal_mul]
  rw [hi]
  rw [integral_complex_ofReal]
  congr 1
  letI := ginibreMeasure_isProbabilityMeasure hn
  have hgen : Integrable (ginibrePregenerator n f) (ginibreMeasure n) := by
    exact (continuous_ginibrePregenerator_of_core hf).integrable_of_hasCompactSupport
      (hasCompactSupport_ginibrePregenerator hf.2.1)
  have hprod : Integrable (fun z => ginibrePregenerator n f z * f z)
      (ginibreMeasure n) := by
    have hpcont : Continuous (fun z => ginibrePregenerator n f z * f z) :=
      (continuous_ginibrePregenerator_of_core hf).mul hf.1.continuous
    exact hpcont.integrable_of_hasCompactSupport
      ((hasCompactSupport_ginibrePregenerator hf.2.1).mul_right)
  rw [show (fun z => ginibrePregenerator n f z * centeredObservable n f z) =
      fun z => ginibrePregenerator n f z * f z -
        smoothGinibreMean n f * ginibrePregenerator n f z by
    funext z
    simp [centeredObservable]
    ring]
  rw [integral_sub hprod (hgen.const_mul _), integral_const_mul,
    integral_ginibrePregenerator_eq_zero hn hf,
    ginibrePregenerator_integrationByParts hn hf]
  simp

theorem inner_ginibrePregeneratorL2_centeredObservableL2 {n : ℕ}
    (hn : 0 < n) (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    inner ℂ (ginibrePregeneratorL2 hn f hf) (centeredObservableL2 hn f hf) =
      (-smoothGinibreEnergy n f : ℂ) := by
  rw [← inner_conj_symm]
  rw [inner_centeredObservableL2_ginibrePregeneratorL2 hn f hf]
  simp

/-- The centered realization of `(Aₙ + 2)f` in Ginibre `L²`. -/
def centeredShiftedGinibreGeneratorL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    Lp ℂ 2 (ginibreMeasure n) :=
  ginibrePregeneratorL2 hn f hf +
    (2 : ℂ) • centeredObservableL2 hn f hf

theorem centeredShiftedGinibreGeneratorL2_coeFn {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    centeredShiftedGinibreGeneratorL2 hn f hf =ᵐ[ginibreMeasure n]
      fun z => ((ginibrePregenerator n f z +
        2 * centeredObservable n f z : ℝ) : ℂ) := by
  change (ginibrePregeneratorL2 hn f hf +
      (2 : ℂ) • centeredObservableL2 hn f hf) =ᵐ[ginibreMeasure n] _
  filter_upwards [ginibrePregeneratorL2_coeFn hn f hf,
    centeredObservableL2_coeFn hn f hf,
    Lp.coeFn_add (ginibrePregeneratorL2 hn f hf)
      ((2 : ℂ) • centeredObservableL2 hn f hf),
    Lp.coeFn_smul (2 : ℂ) (centeredObservableL2 hn f hf)] with z hA hc hadd hsmul
  rw [hadd]
  change (ginibrePregeneratorL2 hn f hf) z +
      ((2 : ℂ) • centeredObservableL2 hn f hf) z = _
  rw [hsmul, hA]
  change (ginibrePregenerator n f z : ℂ) +
      (2 : ℂ) * (centeredObservableL2 hn f hf) z = _
  rw [hc]
  norm_num

theorem norm_sq_centeredShiftedGinibreGeneratorL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    ‖centeredShiftedGinibreGeneratorL2 hn f hf‖ ^ 2 =
      shiftedGinibreGeneratorNormSq n (centeredObservable n f) := by
  have hinner : inner ℂ (centeredShiftedGinibreGeneratorL2 hn f hf)
      (centeredShiftedGinibreGeneratorL2 hn f hf) =
      ∫ z, inner ℂ ((centeredShiftedGinibreGeneratorL2 hn f hf) z)
        ((centeredShiftedGinibreGeneratorL2 hn f hf) z) ∂ginibreMeasure n :=
    MeasureTheory.L2.inner_def _ _
  rw [inner_self_eq_norm_sq_to_K] at hinner
  have hc := centeredShiftedGinibreGeneratorL2_coeFn hn f hf
  rw [integral_congr_ae (by filter_upwards [hc] with z hz; rw [hz])] at hinner
  have hcent : ∀ z, ginibrePregenerator n (centeredObservable n f) z =
      ginibrePregenerator n f z := fun z => by
    exact ginibrePregenerator_sub_const n f (smoothGinibreMean n f) z
  have hi : (fun z => inner ℂ
      ((ginibrePregenerator n f z + 2 * centeredObservable n f z : ℝ) : ℂ)
      ((ginibrePregenerator n f z + 2 * centeredObservable n f z : ℝ) : ℂ)) =
      fun z => (((ginibrePregenerator n (centeredObservable n f) z +
        2 * centeredObservable n f z) ^ 2 : ℝ) : ℂ) := by
    funext z
    rw [hcent]
    simp only [RCLike.inner_apply, Complex.conj_ofReal, ← Complex.ofReal_mul,
      pow_two]
  rw [hi, integral_complex_ofReal] at hinner
  apply Complex.ofReal_injective
  simpa [shiftedGinibreGeneratorNormSq, ← Complex.ofReal_pow] using hinner

/-- Concrete square completion, with the shifted square applied to the
centered observable as in Theorem 1.9. -/
theorem ginibreGenerator_squareCompletion {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    ginibreGeneratorNormSq n f - 2 * smoothGinibreEnergy n f =
      shiftedGinibreGeneratorNormSq n (centeredObservable n f) +
        2 * (smoothGinibreEnergy n f - 2 * smoothGinibreVariance n f) := by
  have h := norm_add_sq (𝕜 := ℂ) (ginibrePregeneratorL2 hn f hf)
    ((2 : ℂ) • centeredObservableL2 hn f hf)
  rw [← centeredShiftedGinibreGeneratorL2] at h
  have hcross : RCLike.re (inner ℂ (ginibrePregeneratorL2 hn f hf)
      ((2 : ℂ) • centeredObservableL2 hn f hf)) =
      -2 * smoothGinibreEnergy n f := by
    rw [inner_smul_right,
      inner_ginibrePregeneratorL2_centeredObservableL2 hn f hf]
    norm_num
  have hscaled : ‖(2 : ℂ) • centeredObservableL2 hn f hf‖ ^ 2 =
      4 * smoothGinibreVariance n f := by
    calc
      _ = 4 * ‖centeredObservableL2 hn f hf‖ ^ 2 := by
        rw [norm_smul, Complex.norm_ofNat]
        ring
      _ = 4 * smoothGinibreVariance n f := by
        rw [norm_sq_centeredObservableL2 hn f hf]
  rw [norm_sq_centeredShiftedGinibreGeneratorL2 hn f hf,
    norm_sq_ginibrePregeneratorL2 hn f hf,
    hcross, hscaled] at h
  linarith

/-- Any concrete first deficit identity immediately yields the second
Theorem 1.9 identity by square completion. -/
theorem ginibre_second_deficit_identity_of_first {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f)
    (deficit : ℝ) (hfirst :
      smoothGinibreEnergy n f - 2 * smoothGinibreVariance n f = deficit) :
    ginibreGeneratorNormSq n f - 2 * smoothGinibreEnergy n f =
      shiftedGinibreGeneratorNormSq n (centeredObservable n f) + 2 * deficit := by
  rw [ginibreGenerator_squareCompletion hn f hf, hfirst]

end
end GinibrePoincare
Analysis GinibrePoincare/Analysis/GinibreIntegrationByParts.lean #
import GinibrePoincare.Analysis.L2RepresentativeBridges
import GinibrePoincare.Analysis.ComplexGaussianIntegrationByParts
import Mathlib.MeasureTheory.Integral.IntegralEqImproper

/-! # Integrability preliminaries for Ginibre integration by parts -/

open MeasureTheory
open scoped BigOperators ContDiff ComplexConjugate

namespace GinibrePoincare

noncomputable section

set_option maxHeartbeats 800000

/-- The integral over the real line of the derivative of a compactly
supported `C¹` function vanishes. -/
theorem integral_deriv_eq_zero_of_contDiff_hasCompactSupport
    (g : ℝ → ℝ) (hg : ContDiff ℝ 1 g) (hgc : HasCompactSupport g) :
    ∫ x, deriv g x = 0 := by
  have hi : Integrable (deriv g) :=
    (hg.continuous_deriv (by simp)).integrable_of_hasCompactSupport hgc.deriv
  rw [← integral_add_compl (μ := volume) measurableSet_Iic hi]
  rw [show (Set.Iic (0 : ℝ))ᶜ = Set.Ioi 0 by ext x; simp]
  rw [hgc.integral_Iic_deriv_eq hg 0, hgc.integral_Ioi_deriv_eq hg 0]
  ring

private theorem hasCompactSupport_complexRealSlice {H : ℂ → ℝ}
    (hH : HasCompactSupport H) (y : ℝ) :
    HasCompactSupport (fun x : ℝ => H ⟨x, y⟩) := by
  apply HasCompactSupport.of_support_subset_isCompact
    (hH.image (Complex.reCLM.continuous))
  intro x hx
  exact ⟨⟨x, y⟩, subset_tsupport _ hx, rfl⟩

private theorem deriv_complexRealSlice_real {H : ℂ → ℝ}
    (hH : ContDiff ℝ 1 H) (y x : ℝ) :
    deriv (fun r : ℝ => H ⟨r, y⟩) x =
      fderiv ℝ H ⟨x, y⟩ (1 : ℂ) := by
  apply HasDerivAt.deriv
  have hfun : (fun r : ℝ => H ⟨r, y⟩) =
      H ∘ fun r : ℝ => (r : ℂ) + (y : ℂ) * Complex.I := by
    funext r
    congr 1
    apply Complex.ext <;> simp
  rw [hfun]
  have hi : HasDerivAt (fun r : ℝ => (r : ℂ) + (y : ℂ) * Complex.I)
      (1 : ℂ) x := by
    simpa using (Complex.ofRealCLM.hasFDerivAt.hasDerivAt.add_const
      ((y : ℂ) * Complex.I))
  have heq : (x : ℂ) + (y : ℂ) * Complex.I = ⟨x, y⟩ := by
    apply Complex.ext <;> simp
  rw [← heq]
  change HasDerivAt (H ∘ fun r : ℝ => (r : ℂ) + (y : ℂ) * Complex.I) _ x
  exact (hH.differentiable (by simp) _).hasFDerivAt.comp_hasDerivAt x hi

/-- A compactly supported smooth scalar field on the complex plane has zero
integral of its real directional derivative. -/
theorem integral_fderiv_complex_real_eq_zero (H : ℂ → ℝ)
    (hH : ContDiff ℝ 1 H) (hHc : HasCompactSupport H) :
    ∫ z : ℂ, fderiv ℝ H z (1 : ℂ) = 0 := by
  have hi : Integrable (fun z : ℂ => fderiv ℝ H z (1 : ℂ)) :=
    ((hH.continuous_fderiv (by simp)).clm_apply continuous_const)
      |>.integrable_of_hasCompactSupport
        (HasCompactSupport.fderiv_apply (𝕜 := ℝ) hHc (1 : ℂ))
  rw [← Complex.volume_preserving_equiv_real_prod.symm.integral_comp']
  have hip : Integrable (fun p : ℝ × ℝ =>
      fderiv ℝ H (Complex.measurableEquivRealProd.symm p) (1 : ℂ)) := by
    rw [← Complex.volume_preserving_equiv_real_prod.symm.map_eq] at hi
    exact (integrable_map_equiv Complex.measurableEquivRealProd.symm _).mp hi
  change (∫ p : ℝ × ℝ,
    fderiv ℝ H (Complex.measurableEquivRealProd.symm p) (1 : ℂ)
      ∂volume.prod volume) = 0
  rw [integral_prod_symm _ hip]
  apply integral_eq_zero_of_ae
  filter_upwards with y
  simp only [Complex.measurableEquivRealProd_symm_apply]
  change (∫ x : ℝ, fderiv ℝ H ⟨x, y⟩ 1) = 0
  rw [show (fun x : ℝ => fderiv ℝ H ⟨x, y⟩ 1) =
      fun x => deriv (fun r : ℝ => H ⟨r, y⟩) x by
    funext x
    exact (deriv_complexRealSlice_real hH y x).symm]
  exact integral_deriv_eq_zero_of_contDiff_hasCompactSupport _
    (by
      rw [show (fun r : ℝ => H ⟨r, y⟩) =
          fun r : ℝ => H ((r : ℂ) + (y : ℂ) * Complex.I) by
        funext r; congr 1; apply Complex.ext <;> simp]
      apply hH.comp
      exact Complex.ofRealCLM.contDiff.add
        (contDiff_const.mul contDiff_const))
    (hasCompactSupport_complexRealSlice hHc y)

/-- Fubini splitting of a finite product measure at an arbitrary coordinate. -/
theorem integral_configuration_finSucc_split_measure {k : ℕ}
    (μ : Measure ℂ) [SigmaFinite μ] (j : Fin (k + 1))
    {H : Configuration (k + 1) → ℝ}
    (hH : Integrable H (Measure.pi fun _ : Fin (k + 1) => μ)) :
    (∫ z, H z ∂(Measure.pi fun _ : Fin (k + 1) => μ)) =
      ∫ r : Fin k → ℂ, ∫ w : ℂ,
        H ((MeasurableEquiv.piFinSuccAbove
          (fun _ : Fin (k + 1) => ℂ) j).symm (w, r))
        ∂μ ∂(Measure.pi fun _ : Fin k => μ) := by
  let ν : Fin (k + 1) → Measure ℂ := fun _ => μ
  let e := MeasurableEquiv.piFinSuccAbove
    (fun _ : Fin (k + 1) => ℂ) j
  have he : MeasurePreserving e (Measure.pi ν)
      ((ν j).prod (Measure.pi fun i : Fin k => ν (j.succAbove i))) :=
    measurePreserving_piFinSuccAbove ν j
  have hprod : Integrable (H ∘ e.symm)
      ((ν j).prod (Measure.pi fun i : Fin k => ν (j.succAbove i))) :=
    he.symm.integrable_comp_of_integrable hH
  calc
    _ = ∫ p : ℂ × (Fin k → ℂ), H (e.symm p)
        ∂((ν j).prod (Measure.pi fun i : Fin k => ν (j.succAbove i))) :=
      (he.symm.integral_comp' H).symm
    _ = ∫ r : Fin k → ℂ, ∫ w : ℂ, H (e.symm (w, r))
        ∂(ν j) ∂(Measure.pi fun i : Fin k => ν (j.succAbove i)) :=
      integral_prod_symm _ hprod
    _ = _ := by simp only [ν, e]

private theorem fderiv_comp_configurationCoordinateSlice_apply_real {m : ℕ}
    {F : Configuration m → ℝ} (hF : ContDiff ℝ 1 F)
    (r : Configuration m) (j : Fin m) (w v : ℂ) :
    fderiv ℝ (fun u => F (configurationCoordinateSlice r j u)) w v =
      fderiv ℝ F (configurationCoordinateSlice r j w) (coordinateDirection j v) := by
  change fderiv ℝ (F ∘ configurationCoordinateSlice r j) w v = _
  have hout := (hF.differentiable (by simp)
    (configurationCoordinateSlice r j w)).hasFDerivAt
  have hcomp := HasFDerivAt.comp w hout
    (hasFDerivAt_configurationCoordinateSlice r j w)
  have hv := congrArg (fun L : ℂ →L[ℝ] ℝ => L v) hcomp.fderiv
  rw [show coordinateDirection j v = Pi.single j v by
    funext i; simp [coordinateDirection, Pi.single_apply]]
  simpa only [ContinuousLinearMap.comp_apply, ContinuousLinearMap.single_apply] using hv

private theorem hasCompactSupport_comp_configurationCoordinateSlice_real {m : ℕ}
    {F : Configuration m → ℝ} (hF : HasCompactSupport F)
    (r : Configuration m) (j : Fin m) :
    HasCompactSupport (fun w => F (configurationCoordinateSlice r j w)) := by
  apply HasCompactSupport.intro
    ((isometry_configurationCoordinateSlice r j).isClosedEmbedding.isCompact_preimage hF)
  intro w hw
  by_contra hne
  exact hw (subset_closure hne)

/-- A compactly supported `C¹` function has zero integral of each real
configuration-coordinate derivative. -/
theorem integral_fderiv_configuration_real_eq_zero {n : ℕ}
    (Φ : Configuration n → ℝ) (hΦ : ContDiff ℝ 1 Φ)
    (hΦc : HasCompactSupport Φ) (j : Fin n) :
    ∫ z, fderiv ℝ Φ z (realCoordinateDirection j) = 0 := by
  cases n with
  | zero => exact Fin.elim0 j
  | succ k =>
    have hi : Integrable (fun z => fderiv ℝ Φ z (realCoordinateDirection j)) :=
      ((hΦ.continuous_fderiv (by simp)).clm_apply continuous_const)
        |>.integrable_of_hasCompactSupport
          (HasCompactSupport.fderiv_apply (𝕜 := ℝ) hΦc _)
    change (∫ z, fderiv ℝ Φ z (realCoordinateDirection j)
      ∂(Measure.pi fun _ : Fin (k + 1) => (volume : Measure ℂ))) = 0
    rw [integral_configuration_finSucc_split_measure volume j hi]
    apply integral_eq_zero_of_ae
    filter_upwards with r
    let b : Configuration (k + 1) :=
      (MeasurableEquiv.piFinSuccAbove
        (fun _ : Fin (k + 1) => ℂ) j).symm (0, r)
    rw [show (fun w => fderiv ℝ Φ
        ((MeasurableEquiv.piFinSuccAbove (fun _ : Fin (k + 1) => ℂ) j).symm (w, r))
          (realCoordinateDirection j)) =
        fun w => fderiv ℝ (fun u => Φ (configurationCoordinateSlice b j u)) w 1 by
      funext w
      rw [piFinSuccAbove_symm_eq_coordinateSlice j]
      exact (fderiv_comp_configurationCoordinateSlice_apply_real hΦ b j w 1).symm]
    exact integral_fderiv_complex_real_eq_zero _
      (hΦ.comp (contDiff_configurationCoordinateSlice b j))
      (hasCompactSupport_comp_configurationCoordinateSlice_real hΦc b j)

private theorem hasCompactSupport_complexImagSlice_real {H : ℂ → ℝ}
    (hH : HasCompactSupport H) (x : ℝ) :
    HasCompactSupport (fun y : ℝ => H ⟨x, y⟩) := by
  apply HasCompactSupport.of_support_subset_isCompact
    (hH.image Complex.imCLM.continuous)
  intro y hy
  exact ⟨⟨x, y⟩, subset_tsupport _ hy, rfl⟩

private theorem deriv_complexImagSlice_real {H : ℂ → ℝ}
    (hH : ContDiff ℝ 1 H) (x y : ℝ) :
    deriv (fun r : ℝ => H ⟨x, r⟩) y = fderiv ℝ H ⟨x, y⟩ Complex.I := by
  apply HasDerivAt.deriv
  have hfun : (fun r : ℝ => H ⟨x, r⟩) =
      H ∘ fun r : ℝ => (x : ℂ) + (r : ℂ) * Complex.I := by
    funext r; congr 1; apply Complex.ext <;> simp
  rw [hfun]
  have hi : HasDerivAt (fun r : ℝ => (x : ℂ) + (r : ℂ) * Complex.I)
      Complex.I y := by
    simpa using ((Complex.ofRealCLM.hasFDerivAt.hasDerivAt.mul_const
      Complex.I).const_add (x : ℂ))
  have heq : (x : ℂ) + (y : ℂ) * Complex.I = ⟨x, y⟩ := by
    apply Complex.ext <;> simp
  rw [← heq]
  exact (hH.differentiable (by simp) _).hasFDerivAt.comp_hasDerivAt y hi

theorem integral_fderiv_complex_imag_eq_zero (H : ℂ → ℝ)
    (hH : ContDiff ℝ 1 H) (hHc : HasCompactSupport H) :
    ∫ z : ℂ, fderiv ℝ H z Complex.I = 0 := by
  have hi : Integrable (fun z : ℂ => fderiv ℝ H z Complex.I) :=
    ((hH.continuous_fderiv (by simp)).clm_apply continuous_const)
      |>.integrable_of_hasCompactSupport
        (HasCompactSupport.fderiv_apply (𝕜 := ℝ) hHc Complex.I)
  rw [← Complex.volume_preserving_equiv_real_prod.symm.integral_comp']
  rw [← Complex.volume_preserving_equiv_real_prod.symm.map_eq] at hi
  have hip : Integrable (fun p : ℝ × ℝ =>
      fderiv ℝ H (Complex.measurableEquivRealProd.symm p) Complex.I)
      (volume.prod volume) :=
    (integrable_map_equiv Complex.measurableEquivRealProd.symm _).mp hi
  change (∫ p : ℝ × ℝ,
    fderiv ℝ H (Complex.measurableEquivRealProd.symm p) Complex.I
      ∂volume.prod volume) = 0
  rw [integral_prod _ hip]
  apply integral_eq_zero_of_ae
  filter_upwards with x
  simp only [Complex.measurableEquivRealProd_symm_apply]
  change (∫ y : ℝ, fderiv ℝ H ⟨x, y⟩ Complex.I) = 0
  rw [show (fun y : ℝ => fderiv ℝ H ⟨x, y⟩ Complex.I) =
      fun y => deriv (fun r : ℝ => H ⟨x, r⟩) y by
    funext y; exact (deriv_complexImagSlice_real hH x y).symm]
  exact integral_deriv_eq_zero_of_contDiff_hasCompactSupport _
    (by
      rw [show (fun r : ℝ => H ⟨x, r⟩) =
          fun r : ℝ => H ((x : ℂ) + (r : ℂ) * Complex.I) by
        funext r; congr 1; apply Complex.ext <;> simp]
      exact hH.comp (contDiff_const.add
        (Complex.ofRealCLM.contDiff.mul contDiff_const)))
    (hasCompactSupport_complexImagSlice_real hHc x)

theorem integral_fderiv_configuration_imag_eq_zero {n : ℕ}
    (Φ : Configuration n → ℝ) (hΦ : ContDiff ℝ 1 Φ)
    (hΦc : HasCompactSupport Φ) (j : Fin n) :
    ∫ z, fderiv ℝ Φ z (imaginaryCoordinateDirection j) = 0 := by
  cases n with
  | zero => exact Fin.elim0 j
  | succ k =>
    have hi : Integrable (fun z => fderiv ℝ Φ z (imaginaryCoordinateDirection j)) :=
      ((hΦ.continuous_fderiv (by simp)).clm_apply continuous_const)
        |>.integrable_of_hasCompactSupport
          (HasCompactSupport.fderiv_apply (𝕜 := ℝ) hΦc _)
    change (∫ z, fderiv ℝ Φ z (imaginaryCoordinateDirection j)
      ∂(Measure.pi fun _ : Fin (k + 1) => (volume : Measure ℂ))) = 0
    rw [integral_configuration_finSucc_split_measure volume j hi]
    apply integral_eq_zero_of_ae
    filter_upwards with r
    let b : Configuration (k + 1) :=
      (MeasurableEquiv.piFinSuccAbove (fun _ : Fin (k + 1) => ℂ) j).symm (0, r)
    rw [show (fun w => fderiv ℝ Φ
        ((MeasurableEquiv.piFinSuccAbove (fun _ : Fin (k + 1) => ℂ) j).symm (w, r))
          (imaginaryCoordinateDirection j)) =
        fun w => fderiv ℝ (fun u => Φ (configurationCoordinateSlice b j u)) w Complex.I by
      funext w
      rw [piFinSuccAbove_symm_eq_coordinateSlice j]
      exact (fderiv_comp_configurationCoordinateSlice_apply_real hΦ b j w Complex.I).symm]
    exact integral_fderiv_complex_imag_eq_zero _
      (hΦ.comp (contDiff_configurationCoordinateSlice b j))
      (hasCompactSupport_comp_configurationCoordinateSlice_real hΦc b j)

/-- The ordinary real density whose `ENNReal.ofReal` is the product of the
Vandermonde and explicit complex-Gaussian densities. -/
def ginibreLebesgueDensityReal (n : ℕ) (z : Configuration n) : ℝ :=
  (((n : ℝ) / Real.pi) ^ n) * vandermondeWeight z * gaussianWeight n z

/-- The real Ginibre Lebesgue density is nonnegative. -/
theorem ginibreLebesgueDensityReal_nonneg (n : ℕ) (z : Configuration n) :
    0 ≤ ginibreLebesgueDensityReal n z := by
  unfold ginibreLebesgueDensityReal
  exact mul_nonneg (mul_nonneg (pow_nonneg (div_nonneg (Nat.cast_nonneg n)
    Real.pi_pos.le) _) (vandermondeWeight_nonneg z)) (gaussianWeight_nonneg n z)

/-- The two extended nonnegative density factors multiply to the `ofReal`
of the ordinary real density. -/
theorem vandermondeDensity_mul_complexGaussianDensity (n : ℕ)
    (z : Configuration n) :
    vandermondeDensity z * complexGaussianDensity n z =
      ENNReal.ofReal (ginibreLebesgueDensityReal n z) := by
  unfold vandermondeDensity complexGaussianDensity ginibreLebesgueDensityReal
  rw [← ENNReal.ofReal_mul (vandermondeWeight_nonneg z)]
  congr 1
  ring

/-- Integration against normalized Ginibre measure as ordinary Lebesgue
integration against the explicit real density. -/
theorem integral_ginibreMeasure_eq_density_volume {n : ℕ} (hn : 0 < n)
    (h : Configuration n → ℝ) :
    ∫ z, h z ∂ginibreMeasure n =
      (ginibreNormalizingMass n).toReal⁻¹ *
        ∫ z, ginibreLebesgueDensityReal n z * h z := by
  rw [integral_ginibreMeasure, complexGaussianDensityIdentification n hn]
  unfold complexGaussianDensityMeasure
  rw [integral_withDensity_eq_integral_toReal_smul
    (measurable_complexGaussianDensity n)
    (ae_of_all _ fun z => ENNReal.ofReal_lt_top)]
  simp_rw [complexGaussianDensity,
    ENNReal.toReal_ofReal (mul_nonneg
      (pow_nonneg (div_nonneg (Nat.cast_nonneg n) Real.pi_pos.le) _)
      (gaussianWeight_nonneg n _)), smul_eq_mul]
  congr 2
  funext z
  unfold ginibreLebesgueDensityReal
  ring

/-- The ordinary Ginibre density is smooth on the whole configuration
space (and hence, in particular, on the collision-free locus). -/
theorem contDiff_ginibreLebesgueDensityReal (n : ℕ) :
    ContDiff ℝ ∞ (ginibreLebesgueDensityReal n) := by
  unfold ginibreLebesgueDensityReal vandermondeWeight gaussianWeight
  have hV : ContDiff ℝ ∞ (fun z : Configuration n => vandermonde z) :=
    contDiff_vandermonde n
  have hVre : ContDiff ℝ ∞ (fun z : Configuration n => (vandermonde z).re) :=
    Complex.reCLM.contDiff.comp hV
  have hVim : ContDiff ℝ ∞ (fun z : Configuration n => (vandermonde z).im) :=
    Complex.imCLM.contDiff.comp hV
  simp_rw [Complex.normSq_apply]
  have hnorm : ContDiff ℝ ∞ (configurationNormSq : Configuration n → ℝ) := by
    unfold configurationNormSq
    simp_rw [Complex.normSq_apply]
    change ContDiff ℝ ∞ (fun z : Configuration n =>
      ∑ i ∈ Finset.univ, ((z i).re * (z i).re + (z i).im * (z i).im))
    apply ContDiff.sum
    intro i hi
    have hp : ContDiff ℝ ∞ (fun z : Configuration n => z i) :=
      (ContinuousLinearMap.proj i : Configuration n →L[ℝ] ℂ).contDiff
    exact ((Complex.reCLM.contDiff.comp hp).mul (Complex.reCLM.contDiff.comp hp)).add
      ((Complex.imCLM.contDiff.comp hp).mul (Complex.imCLM.contDiff.comp hp))
  have hexp : ContDiff ℝ ∞ (fun z : Configuration n =>
      Real.exp (-(n : ℝ) * configurationNormSq z)) := by
    simpa only [neg_mul] using
      (((contDiff_const : ContDiff ℝ ∞
        (fun _ : Configuration n => (n : ℝ))).mul hnorm).neg.exp)
  exact (contDiff_const.mul ((hVre.mul hVre).add (hVim.mul hVim))).mul hexp

/-- Smoothness restricted to the collision-free open set. -/
theorem contDiffOn_ginibreLebesgueDensityReal_collisionFree (n : ℕ) :
    ContDiffOn ℝ ∞ (ginibreLebesgueDensityReal n) (collisionSet n)ᶜ :=
  (contDiff_ginibreLebesgueDensityReal n).contDiffOn

/-- Logarithmic derivative of a finite nonvanishing product.  This is the
calculus lemma used for the collision-free Vandermonde product. -/
theorem fderiv_finsetProd_apply_eq_prod_mul_sum_div
    {ι : Type*} [DecidableEq ι] {E : Type*} [NormedAddCommGroup E]
    [NormedSpace ℝ E] (s : Finset ι) (g : ι → E → ℂ) (x v : E)
    (hg : ∀ i ∈ s, DifferentiableAt ℝ (g i) x)
    (hne : ∀ i ∈ s, g i x ≠ 0) :
    fderiv ℝ (fun y => ∏ i ∈ s, g i y) x v =
      (∏ i ∈ s, g i x) *
        ∑ i ∈ s, fderiv ℝ (g i) x v / g i x := by
  rw [fderiv_finsetProd hg]
  simp only [sum_apply, smul_apply, Finset.mul_sum]
  apply Finset.sum_congr rfl
  intro i hi
  simp only [smul_eq_mul]
  field_simp [hne i hi]
  calc
    _ = (fderiv ℝ (g i) x) v *
        ((∏ j ∈ s.erase i, g j x) * g i x) := by ring
    _ = _ := by rw [Finset.prod_erase_mul s (fun j => g j x) hi]

/-- Every factor in the ordered Vandermonde product is nonzero at a
collision-free configuration. -/
theorem vandermondeFactor_ne_zero_of_collisionFree {n : ℕ}
    {z : Configuration n} (hz : CollisionFree z) {i k : Fin n} (hik : i < k) :
    z k - z i ≠ 0 := by
  apply sub_ne_zero.mpr
  intro h
  exact (ne_of_gt hik) (hz h)

/-- A single ordered factor in the Vandermonde product. -/
def vandermondeFactor {n : ℕ} (i k : Fin n) (z : Configuration n) : ℂ :=
  z k - z i

/-- Strictly ordered particle pairs indexing the Vandermonde factors. -/
abbrev VandermondePair (n : ℕ) := {ik : Fin n × Fin n // ik.1 < ik.2}

/-- The Vandermonde product flattened over its subtype of strictly ordered
pairs. -/
theorem vandermonde_eq_prod_pair {n : ℕ} (z : Configuration n) :
    vandermonde z =
      ∏ ik : VandermondePair n, vandermondeFactor ik.1.1 ik.1.2 z := by
  rw [vandermonde_eq_product]
  rw [← Finset.prod_subtype
    (Finset.univ.filter (fun ik : Fin n × Fin n => ik.1 < ik.2)) (by simp)
    (fun ik => vandermondeFactor ik.1 ik.2 z)]
  rw [Finset.prod_filter]
  rw [Fintype.prod_prod_type]
  simp only [vandermondeFactor]
  apply Finset.prod_congr rfl
  intro i hi
  rw [← Finset.prod_filter]
  apply Finset.prod_congr
  · ext j
    simp
  · intro j hj
    rfl

/-- Exact real Fréchet derivative of one Vandermonde factor in a coordinate
direction. -/
theorem fderiv_vandermondeFactor_apply_coordinateDirection {n : ℕ}
    (i k j : Fin n) (hik : i ≠ k) (w : ℂ) (z : Configuration n) :
    fderiv ℝ (vandermondeFactor i k) z (coordinateDirection j w) =
      if j = k then w else if j = i then -w else 0 := by
  let L : Configuration n →L[ℝ] ℂ :=
    (ContinuousLinearMap.proj k : Configuration n →L[ℝ] ℂ) -
      (ContinuousLinearMap.proj i : Configuration n →L[ℝ] ℂ)
  have hfun : vandermondeFactor i k = L := by
    funext x
    rfl
  rw [hfun, L.fderiv]
  simp only [L, ContinuousLinearMap.sub_apply]
  by_cases hjk : j = k
  · simp [coordinateDirection, hjk, hik]
  · by_cases hji : j = i
    · simp [coordinateDirection, hjk, hji, hik, eq_comm]
    · have hkj : k ≠ j := Ne.symm hjk
      have hij : i ≠ j := Ne.symm hji
      simp [coordinateDirection, hjk, hji, hkj, hij]

/-- Direct specialization of the finite-product logarithmic derivative to
the subtype of ordered Vandermonde pairs. -/
theorem fderiv_vandermonde_apply_coordinateDirection_eq_pairSum {n : ℕ}
    (z : Configuration n) (hz : CollisionFree z) (j : Fin n) (w : ℂ) :
    fderiv ℝ vandermonde z (coordinateDirection j w) = vandermonde z *
      ∑ ik : VandermondePair n,
        (if j = ik.1.2 then w else if j = ik.1.1 then -w else 0) /
          (z ik.1.2 - z ik.1.1) := by
  rw [show vandermonde = fun y =>
      ∏ ik : VandermondePair n, vandermondeFactor ik.1.1 ik.1.2 y by
    funext y
    exact vandermonde_eq_prod_pair y]
  rw [fderiv_finsetProd_apply_eq_prod_mul_sum_div Finset.univ
    (fun ik : VandermondePair n => vandermondeFactor ik.1.1 ik.1.2)
    z (coordinateDirection j w)]
  · congr 1
    apply Finset.sum_congr rfl
    intro ik hik
    rw [fderiv_vandermondeFactor_apply_coordinateDirection _ _ _
      (ne_of_lt ik.2) w z]
    rfl
  · intro ik hik
    let L : Configuration n →L[ℝ] ℂ :=
      (ContinuousLinearMap.proj ik.1.2 : Configuration n →L[ℝ] ℂ) -
        (ContinuousLinearMap.proj ik.1.1 : Configuration n →L[ℝ] ℂ)
    exact L.differentiable.differentiableAt
  · intro ik hik
    exact vandermondeFactor_ne_zero_of_collisionFree hz ik.2

/-- Ordered pairs incident to a fixed particle. -/
abbrev IncidentVandermondePair {n : ℕ} (j : Fin n) :=
  {ik : VandermondePair n // j = ik.1.1 ∨ j = ik.1.2}

/-- The unique ordered pair associated with a particle distinct from `j`. -/
def incidentPair {n : ℕ} (j : Fin n) (k : {k : Fin n // k ≠ j}) :
    IncidentVandermondePair j := by
  classical
  by_cases h : k.1 < j
  · exact ⟨⟨(k.1, j), h⟩, Or.inr rfl⟩
  · have hjk : j < k.1 := lt_of_le_of_ne (le_of_not_gt h) (Ne.symm k.2)
    exact ⟨⟨(j, k.1), hjk⟩, Or.inl rfl⟩

@[simp] theorem incidentPair_fst_snd {n : ℕ} (j : Fin n)
    (k : {k : Fin n // k ≠ j}) :
    ((incidentPair j k).1.1.1 = k.1 ∧ (incidentPair j k).1.1.2 = j) ∨
      ((incidentPair j k).1.1.1 = j ∧ (incidentPair j k).1.1.2 = k.1) := by
  classical
  unfold incidentPair
  split_ifs <;> simp

/-- Distinct particles give distinct incident ordered pairs. -/
theorem incidentPair_injective {n : ℕ} (j : Fin n) :
    Function.Injective (incidentPair j) := by
  intro a b hab
  unfold incidentPair at hab
  split at hab <;> split at hab <;> apply Subtype.ext <;> simp_all

/-- Every ordered pair incident to `j` arises from its other endpoint. -/
theorem incidentPair_surjective {n : ℕ} (j : Fin n) :
    Function.Surjective (incidentPair j) := by
  intro ik
  rcases ik.2 with hjfst | hjsnd
  · let k : {k : Fin n // k ≠ j} :=
      ⟨ik.1.1.2, by
        intro h
        exact (ne_of_gt ik.1.2) (h.trans hjfst)⟩
    refine ⟨k, ?_⟩
    apply Subtype.ext
    apply Subtype.ext
    unfold incidentPair
    dsimp only [k]
    rw [dif_neg (by
      intro h
      exact (not_lt_of_ge (le_of_lt ik.1.2)) (lt_of_lt_of_eq h hjfst))]
    simp [hjfst]
  · let k : {k : Fin n // k ≠ j} :=
      ⟨ik.1.1.1, by
        intro h
        exact (ne_of_gt ik.1.2) (h.trans hjsnd).symm⟩
    refine ⟨k, ?_⟩
    apply Subtype.ext
    apply Subtype.ext
    unfold incidentPair
    dsimp only [k]
    rw [dif_pos (by simpa [hjsnd] using ik.1.2)]
    simp [hjsnd]

/-- The explicit incident-pair parametrization is an equivalence. -/
def incidentPairEquiv {n : ℕ} (j : Fin n) :
    {k : Fin n // k ≠ j} ≃ IncidentVandermondePair j :=
  Equiv.ofBijective (incidentPair j)
    ⟨incidentPair_injective j, incidentPair_surjective j⟩

/-- The logarithmic-derivative summand attached to an incident ordered pair
has a uniform expression independent of which endpoint is smaller. -/
theorem incidentPair_logDerivative_summand {n : ℕ}
    (z : Configuration n) (hz : CollisionFree z) (j : Fin n)
    (k : {k : Fin n // k ≠ j}) (w : ℂ) :
    (if j = (incidentPair j k).1.1.2 then w
      else if j = (incidentPair j k).1.1.1 then -w else 0) /
        (z (incidentPair j k).1.1.2 - z (incidentPair j k).1.1.1) =
      w / (z j - z k.1) := by
  classical
  unfold incidentPair
  by_cases h : k.1 < j
  · rw [dif_pos h]
    simp
  · rw [dif_neg h]
    dsimp only
    have hjk : j < k.1 := lt_of_le_of_ne (le_of_not_gt h) (Ne.symm k.2)
    have hne : z j - z k.1 ≠ 0 :=
      sub_ne_zero.mpr (fun heq => k.2 (hz heq).symm)
    have hjkne : j ≠ k.1 := ne_of_lt hjk
    rw [if_neg hjkne, if_pos rfl]
    rw [show z k.1 - z j = -(z j - z k.1) by ring]
    field_simp

/-- Reindexing the logarithmic-derivative sum over incident pairs by their
other endpoint. -/
theorem sum_incidentPair_logDerivative {n : ℕ}
    (z : Configuration n) (hz : CollisionFree z) (j : Fin n) (w : ℂ) :
    (∑ ik : IncidentVandermondePair j,
      (if j = ik.1.1.2 then w else if j = ik.1.1.1 then -w else 0) /
        (z ik.1.1.2 - z ik.1.1.1)) =
      ∑ k : {k : Fin n // k ≠ j}, w / (z j - z k.1) := by
  rw [← (incidentPairEquiv j).sum_comp]
  apply Finset.sum_congr rfl
  intro k hk
  exact incidentPair_logDerivative_summand z hz j k w

/-- Nonincident ordered pairs contribute zero, so the full ordered-pair sum
is the sum over particles distinct from `j`. -/
theorem sum_vandermondePair_logDerivative {n : ℕ}
    (z : Configuration n) (hz : CollisionFree z) (j : Fin n) (w : ℂ) :
    (∑ ik : VandermondePair n,
      (if j = ik.1.2 then w else if j = ik.1.1 then -w else 0) /
        (z ik.1.2 - z ik.1.1)) =
      ∑ k : {k : Fin n // k ≠ j}, w / (z j - z k.1) := by
  calc
    _ = ∑ ik : IncidentVandermondePair j,
        (if j = ik.1.1.2 then w else if j = ik.1.1.1 then -w else 0) /
          (z ik.1.1.2 - z ik.1.1.1) := by
      have hsub :
          (∑ ik ∈ Finset.univ.filter (fun ik : VandermondePair n =>
              j = ik.1.1 ∨ j = ik.1.2),
            (if j = ik.1.2 then w else if j = ik.1.1 then -w else 0) /
              (z ik.1.2 - z ik.1.1)) =
          ∑ ik : IncidentVandermondePair j,
            (if j = ik.1.1.2 then w else if j = ik.1.1.1 then -w else 0) /
              (z ik.1.1.2 - z ik.1.1.1) :=
        Finset.sum_subtype _ (by simp) _
      rw [← hsub]
      rw [Finset.sum_filter]
      apply Finset.sum_congr rfl
      intro ik hik
      split_ifs <;> simp_all
    _ = _ := sum_incidentPair_logDerivative z hz j w

/-- Collision-free logarithmic derivative of the Vandermonde, indexed by
all particles other than the differentiated coordinate. -/
theorem fderiv_vandermonde_apply_coordinateDirection {n : ℕ}
    (z : Configuration n) (hz : CollisionFree z) (j : Fin n) (w : ℂ) :
    fderiv ℝ vandermonde z (coordinateDirection j w) =
      vandermonde z * ∑ k ∈ Finset.univ.erase j, w / (z j - z k) := by
  rw [fderiv_vandermonde_apply_coordinateDirection_eq_pairSum z hz j w,
    sum_vandermondePair_logDerivative z hz j w]
  congr 1
  symm
  exact Finset.sum_subtype (Finset.univ.erase j)
    (fun k => by simp [ne_comm]) (fun k => w / (z j - z k))

/-- Directional derivative of the squared modulus of the Vandermonde. -/
theorem fderiv_vandermondeWeight_apply {n : ℕ}
    (z v : Configuration n) :
    fderiv ℝ vandermondeWeight z v =
      2 * (conj (vandermonde z) * (fderiv ℝ vandermonde z v)).re := by
  have hV : DifferentiableAt ℝ vandermonde z :=
    (contDiff_vandermonde n).differentiable (by simp) |>.differentiableAt
  have hre := Complex.reCLM.hasFDerivAt.comp z hV.hasFDerivAt
  have him := Complex.imCLM.hasFDerivAt.comp z hV.hasFDerivAt
  have hsq := (hre.mul hre).add (him.mul him)
  rw [show vandermondeWeight = fun y : Configuration n =>
      (vandermonde y).re * (vandermonde y).re +
        (vandermonde y).im * (vandermonde y).im by
    funext y
    rw [vandermondeWeight, Complex.normSq_apply]]
  change fderiv ℝ
      (Complex.reCLM ∘ vandermonde * Complex.reCLM ∘ vandermonde +
        Complex.imCLM ∘ vandermonde * Complex.imCLM ∘ vandermonde) z v = _
  rw [hsq.fderiv]
  simp only [add_apply, smul_apply]
  simp [RCLike.inner_apply, Complex.mul_re]
  ring

/-- Directional derivative of the configuration squared norm. -/
theorem contDiff_configurationNormSq {n : ℕ} :
    ContDiff ℝ ∞ (configurationNormSq : Configuration n → ℝ) := by
  unfold configurationNormSq
  simp_rw [Complex.normSq_apply]
  apply ContDiff.sum
  intro i hi
  have hp : ContDiff ℝ ∞ (fun z : Configuration n => z i) :=
    (ContinuousLinearMap.proj i : Configuration n →L[ℝ] ℂ).contDiff
  exact ((Complex.reCLM.contDiff.comp hp).mul (Complex.reCLM.contDiff.comp hp)).add
    ((Complex.imCLM.contDiff.comp hp).mul (Complex.imCLM.contDiff.comp hp))

theorem fderiv_configurationNormSq_apply {n : ℕ}
    (z v : Configuration n) :
    fderiv ℝ configurationNormSq z v =
      2 * ∑ i : Fin n, (conj (z i) * v i).re := by
  unfold configurationNormSq
  rw [fderiv_fun_sum]
  · simp only [sum_apply]
    rw [Finset.mul_sum]
    apply Finset.sum_congr rfl
    intro i hi
    let P : Configuration n →L[ℝ] ℂ :=
      ContinuousLinearMap.proj i
    have hre := Complex.reCLM.hasFDerivAt.comp z P.hasFDerivAt
    have him := Complex.imCLM.hasFDerivAt.comp z P.hasFDerivAt
    have hsq := (hre.mul hre).add (him.mul him)
    rw [show (fun y : Configuration n => Complex.normSq (y i)) =
        fun y => (y i).re * (y i).re + (y i).im * (y i).im by
      funext y
      rw [Complex.normSq_apply]]
    change fderiv ℝ
      (Complex.reCLM ∘ P * Complex.reCLM ∘ P +
        Complex.imCLM ∘ P * Complex.imCLM ∘ P) z v = _
    rw [hsq.fderiv]
    simp [P, Complex.mul_re]
    ring
  · intro i hi
    have hp : Differentiable ℝ (fun y : Configuration n => y i) :=
      (ContinuousLinearMap.proj i : Configuration n →L[ℝ] ℂ).differentiable
    have hre := Complex.reCLM.differentiable.comp hp
    have him := Complex.imCLM.differentiable.comp hp
    rw [show (fun y : Configuration n => Complex.normSq (y i)) =
        fun y => (y i).re * (y i).re + (y i).im * (y i).im by
      funext y
      rw [Complex.normSq_apply]]
    change DifferentiableAt ℝ
      (Complex.reCLM ∘ (fun y : Configuration n => y i) *
        Complex.reCLM ∘ (fun y : Configuration n => y i) +
        Complex.imCLM ∘ (fun y : Configuration n => y i) *
        Complex.imCLM ∘ (fun y : Configuration n => y i)) z
    exact ((hre.mul hre).add (him.mul him)).differentiableAt

/-- Directional derivative of the Gaussian factor. -/
theorem fderiv_gaussianWeight_apply {n : ℕ} (z v : Configuration n) :
    fderiv ℝ (gaussianWeight n) z v =
      gaussianWeight n z * (-(n : ℝ) * fderiv ℝ configurationNormSq z v) := by
  have hnorm : DifferentiableAt ℝ configurationNormSq z :=
    (contDiff_configurationNormSq.differentiable (by simp)).differentiableAt
  have hin := hnorm.hasFDerivAt.const_mul (-(n : ℝ))
  have hexp := (Real.hasDerivAt_exp (-(n : ℝ) * configurationNormSq z)).comp_hasFDerivAt
    z hin
  unfold gaussianWeight
  change fderiv ℝ (Real.exp ∘ fun y => -(n : ℝ) * configurationNormSq y) z v = _
  rw [hexp.fderiv]
  simp only [smul_apply, smul_eq_mul]

/-- Real-coordinate derivative of the Gaussian factor. -/
theorem fderiv_gaussianWeight_realCoordinate {n : ℕ}
    (z : Configuration n) (j : Fin n) :
    fderiv ℝ (gaussianWeight n) z (realCoordinateDirection j) =
      -2 * n * (z j).re * gaussianWeight n z := by
  rw [fderiv_gaussianWeight_apply, fderiv_configurationNormSq_apply]
  simp only [realCoordinateDirection, coordinateDirection]
  rw [show (∑ x : Fin n, (conj (z x) * if x = j then 1 else 0).re) =
      (z j).re by
    rw [Finset.sum_eq_single j]
    · simp
    · intro b hb hbj
      simp [hbj]
    · simp]
  ring

/-- Imaginary-coordinate derivative of the Gaussian factor. -/
theorem fderiv_gaussianWeight_imaginaryCoordinate {n : ℕ}
    (z : Configuration n) (j : Fin n) :
    fderiv ℝ (gaussianWeight n) z (imaginaryCoordinateDirection j) =
      -2 * n * (z j).im * gaussianWeight n z := by
  rw [fderiv_gaussianWeight_apply, fderiv_configurationNormSq_apply]
  simp only [imaginaryCoordinateDirection, coordinateDirection]
  rw [show (∑ x : Fin n, (conj (z x) * if x = j then Complex.I else 0).re) =
      (z j).im by
    rw [Finset.sum_eq_single j]
    · simp [Complex.mul_re]
    · intro b hb hbj
      simp [hbj]
    · simp]
  ring

/-- Collision-free logarithmic derivative of the Vandermonde weight. -/
theorem fderiv_vandermondeWeight_apply_coordinateDirection {n : ℕ}
    (z : Configuration n) (hz : CollisionFree z) (j : Fin n) (w : ℂ) :
    fderiv ℝ vandermondeWeight z (coordinateDirection j w) =
      2 * vandermondeWeight z *
        (∑ k ∈ Finset.univ.erase j, w / (z j - z k)).re := by
  rw [fderiv_vandermondeWeight_apply,
    fderiv_vandermonde_apply_coordinateDirection z hz]
  unfold vandermondeWeight
  rw [← mul_assoc, ← Complex.normSq_eq_conj_mul_self]
  simp only [Complex.mul_re, Complex.ofReal_re, Complex.ofReal_im, zero_mul,
    sub_zero]
  ring

/-- Potential-gradient drift in a real coordinate.  The pregenerator uses
the negative of this coefficient. -/
def ginibreRealDriftCoordinate (n : ℕ) (j : Fin n)
    (z : Configuration n) : ℝ :=
  2 * (z j).re - (2 / (n : ℝ)) *
    ∑ k ∈ Finset.univ.erase j, ((z j - z k)⁻¹).re

/-- Potential-gradient drift in an imaginary coordinate. -/
def ginibreImagDriftCoordinate (n : ℕ) (j : Fin n)
    (z : Configuration n) : ℝ :=
  2 * (z j).im + (2 / (n : ℝ)) *
    ∑ k ∈ Finset.univ.erase j, ((z j - z k)⁻¹).im

/-- A complex coordinate direction, viewed over `ℝ`, splits into its real
and imaginary coordinate directions. -/
theorem coordinateDirection_eq_re_smul_real_add_im_smul_imaginary {n : ℕ}
    (j : Fin n) (w : ℂ) :
    coordinateDirection j w =
      w.re • realCoordinateDirection j +
        w.im • imaginaryCoordinateDirection j := by
  ext k
  by_cases h : k = j
  · subst k
    simp [coordinateDirection, realCoordinateDirection,
      imaginaryCoordinateDirection, Complex.ext_iff]
  · simp [coordinateDirection, realCoordinateDirection,
      imaginaryCoordinateDirection, h]

/-- The confinement directional derivative is the dot product with the
real and imaginary particle coordinates. -/
theorem fderiv_coordinateDirection_self {n : ℕ}
    (f : Configuration n → ℝ) (z : Configuration n) (j : Fin n) :
    fderiv ℝ f z (coordinateDirection j (z j)) =
      (z j).re * fderiv ℝ f z (realCoordinateDirection j) +
        (z j).im * fderiv ℝ f z (imaginaryCoordinateDirection j) := by
  rw [coordinateDirection_eq_re_smul_real_add_im_smul_imaginary]
  simp

/-- One unordered Coulomb-pair direction is exactly the difference of its
two endpoint real/imaginary inverse-distance drifts. -/
theorem fderiv_coulombPairDirection_eq_inverse_components {n : ℕ}
    (f : Configuration n → ℝ) (z : Configuration n) (i k : Fin n) :
    fderiv ℝ f z (coulombPairDirection i k z) =
      ((z i - z k)⁻¹).re *
          (fderiv ℝ f z (realCoordinateDirection i) -
            fderiv ℝ f z (realCoordinateDirection k)) -
        ((z i - z k)⁻¹).im *
          (fderiv ℝ f z (imaginaryCoordinateDirection i) -
            fderiv ℝ f z (imaginaryCoordinateDirection k)) := by
  unfold coulombPairDirection
  rw [map_sub]
  rw [coordinateDirection_eq_re_smul_real_add_im_smul_imaginary,
    coordinateDirection_eq_re_smul_real_add_im_smul_imaginary]
  simp only [map_add, map_smul, smul_eq_mul]
  rw [Complex.inv_re, Complex.inv_im]
  simp only [Complex.div_ofReal_re, Complex.div_ofReal_im]
  ring

/-- Reindex an ordered off-diagonal sum as the two orientations of every
strictly ordered pair. -/
theorem sum_erase_eq_sum_Ioi_add_swap {n : ℕ} (F : Fin n → Fin n → ℝ) :
    ∑ j : Fin n, ∑ k ∈ Finset.univ.erase j, F j k =
      ∑ j : Fin n, ∑ k ∈ Finset.Ioi j, (F j k + F k j) := by
  have herase (j : Fin n) : Finset.univ.erase j =
      Finset.Iio j ∪ Finset.Ioi j := by
    ext k
    simp only [Finset.mem_erase, Finset.mem_univ, true_and,
      Finset.mem_union, Finset.mem_Iio, Finset.mem_Ioi]
    simpa using (ne_iff_lt_or_gt : k ≠ j ↔ k < j ∨ k > j)
  have hdis (j : Fin n) : Disjoint (Finset.Iio j) (Finset.Ioi j) := by
    rw [Finset.disjoint_left]
    intro k hkio hkoi
    rw [Finset.mem_Iio] at hkio
    rw [Finset.mem_Ioi] at hkoi
    exact asymm hkio hkoi
  simp_rw [herase, Finset.sum_union (hdis _)]
  rw [Finset.sum_add_distrib]
  have htranspose :
      (∑ j : Fin n, ∑ k ∈ Finset.Iio j, F j k) =
        ∑ j : Fin n, ∑ k ∈ Finset.Ioi j, F k j := by
    calc
      _ = ∑ j : Fin n, ∑ k : Fin n, if k < j then F j k else 0 := by
        congr 1
        funext j
        rw [← Finset.sum_filter]
        apply Finset.sum_congr
        · ext k
          simp
        · intro k hk
          rfl
      _ = ∑ k : Fin n, ∑ j : Fin n, if k < j then F j k else 0 :=
        Finset.sum_comm
      _ = _ := by
        congr 1
        funext k
        rw [← Finset.sum_filter]
        apply Finset.sum_congr
        · ext j
          simp
        · intro j hj
          rfl
  rw [htranspose]
  simp_rw [Finset.sum_add_distrib]
  ring

/-- The coordinate drift dot gradient is the confinement contribution minus
the unordered-pair Coulomb contribution. -/
theorem sum_ginibreDrift_mul_fderiv {n : ℕ} (f : Configuration n → ℝ)
    (z : Configuration n) :
    ∑ j : Fin n,
        (ginibreRealDriftCoordinate n j z *
            fderiv ℝ f z (realCoordinateDirection j) +
          ginibreImagDriftCoordinate n j z *
            fderiv ℝ f z (imaginaryCoordinateDirection j)) =
      2 * ∑ j : Fin n, fderiv ℝ f z (coordinateDirection j (z j)) -
        (2 / (n : ℝ)) * ∑ j : Fin n, ∑ k ∈ Finset.Ioi j,
          fderiv ℝ f z (coulombPairDirection j k z) := by
  let F : Fin n → Fin n → ℝ := fun j k =>
    ((z j - z k)⁻¹).re * fderiv ℝ f z (realCoordinateDirection j) -
      ((z j - z k)⁻¹).im * fderiv ℝ f z (imaginaryCoordinateDirection j)
  have hp (j k : Fin n) : F j k + F k j =
      fderiv ℝ f z (coulombPairDirection j k z) := by
    rw [fderiv_coulombPairDirection_eq_inverse_components]
    unfold F
    rw [show z k - z j = -(z j - z k) by abel, inv_neg]
    simp only [Complex.neg_re, Complex.neg_im]
    ring
  unfold ginibreRealDriftCoordinate ginibreImagDriftCoordinate
  simp_rw [fderiv_coordinateDirection_self]
  simp_rw [← hp]
  rw [← sum_erase_eq_sum_Ioi_add_swap F]
  have hF (j : Fin n) : (∑ k ∈ Finset.univ.erase j, F j k) =
      (∑ k ∈ Finset.univ.erase j, ((z j - z k)⁻¹).re) *
          fderiv ℝ f z (realCoordinateDirection j) -
        (∑ k ∈ Finset.univ.erase j, ((z j - z k)⁻¹).im) *
          fderiv ℝ f z (imaginaryCoordinateDirection j) := by
    unfold F
    rw [Finset.sum_sub_distrib, ← Finset.sum_mul, ← Finset.sum_mul]
  simp_rw [hF]
  rw [Finset.mul_sum, Finset.mul_sum, ← Finset.sum_sub_distrib]
  apply Finset.sum_congr rfl
  intro j hj
  ring

/-- Exact drift-coordinate form of the Ginibre pregenerator. -/
theorem ginibrePregenerator_eq_laplacian_sub_drift {n : ℕ}
    (f : Configuration n → ℝ) (z : Configuration n) :
    ginibrePregenerator n f z =
      (1 / (n : ℝ)) * configurationLaplacian f z -
        ∑ j : Fin n,
          (ginibreRealDriftCoordinate n j z *
              fderiv ℝ f z (realCoordinateDirection j) +
            ginibreImagDriftCoordinate n j z *
              fderiv ℝ f z (imaginaryCoordinateDirection j)) := by
  rw [sum_ginibreDrift_mul_fderiv]
  unfold ginibrePregenerator
  ring

private theorem differentiableAt_vandermondeWeight {n : ℕ}
    (z : Configuration n) : DifferentiableAt ℝ vandermondeWeight z := by
  rw [show vandermondeWeight = fun y : Configuration n =>
      (vandermonde y).re * (vandermonde y).re +
        (vandermonde y).im * (vandermonde y).im by
    funext y
    rw [vandermondeWeight, Complex.normSq_apply]]
  have hV := (contDiff_vandermonde n).differentiable (by simp)
  fun_prop

private theorem differentiableAt_gaussianWeight (n : ℕ)
    (z : Configuration n) : DifferentiableAt ℝ (gaussianWeight n) z := by
  unfold gaussianWeight
  have h : ContDiff ℝ ∞ (fun y : Configuration n =>
      Real.exp (-(n : ℝ) * configurationNormSq y)) := by
    simpa only [neg_mul] using
      (((contDiff_const : ContDiff ℝ ∞
        (fun _ : Configuration n => (n : ℝ))).mul
          contDiff_configurationNormSq).neg.exp)
  exact (h.differentiable (by simp)).differentiableAt

/-- Real-coordinate logarithmic derivative of the full Ginibre Lebesgue
density. -/
theorem fderiv_ginibreLebesgueDensityReal_realCoordinate {n : ℕ}
    (hn : 0 < n) (z : Configuration n) (hz : CollisionFree z) (j : Fin n) :
    fderiv ℝ (ginibreLebesgueDensityReal n) z (realCoordinateDirection j) =
      -(n : ℝ) * ginibreLebesgueDensityReal n z *
        ginibreRealDriftCoordinate n j z := by
  unfold ginibreLebesgueDensityReal
  rw [show (fun y : Configuration n =>
      (n / Real.pi) ^ n * vandermondeWeight y * gaussianWeight n y) =
      fun y => (n / Real.pi) ^ n *
        (vandermondeWeight y * gaussianWeight n y) by funext y; ring]
  change fderiv ℝ (fun y : Configuration n =>
    (n / Real.pi) ^ n *
      ((vandermondeWeight : Configuration n → ℝ) * gaussianWeight n) y) z _ = _
  rw [fderiv_const_mul
    ((differentiableAt_vandermondeWeight z).mul
      (differentiableAt_gaussianWeight n z))]
  rw [fderiv_mul (differentiableAt_vandermondeWeight z)
    (differentiableAt_gaussianWeight n z)]
  simp only [smul_apply, add_apply, smul_eq_mul]
  change _ * (_ * fderiv ℝ (gaussianWeight n) z (realCoordinateDirection j) +
    _ * fderiv ℝ vandermondeWeight z (coordinateDirection j 1)) = _
  rw [fderiv_vandermondeWeight_apply_coordinateDirection z hz j 1,
    fderiv_gaussianWeight_realCoordinate]
  simp_rw [one_div]
  unfold ginibreRealDriftCoordinate
  have hs : (∑ k ∈ Finset.univ.erase j, (z j - z k)⁻¹).re =
      ∑ k ∈ Finset.univ.erase j, ((z j - z k)⁻¹).re := by
    change Complex.reCLM (∑ k ∈ Finset.univ.erase j, (z j - z k)⁻¹) = _
    exact map_sum Complex.reCLM _ _
  rw [hs]
  field_simp [Nat.cast_ne_zero.mpr hn.ne']
  ring

/-- Imaginary-coordinate logarithmic derivative of the full Ginibre
Lebesgue density. -/
theorem fderiv_ginibreLebesgueDensityReal_imaginaryCoordinate {n : ℕ}
    (hn : 0 < n) (z : Configuration n) (hz : CollisionFree z) (j : Fin n) :
    fderiv ℝ (ginibreLebesgueDensityReal n) z (imaginaryCoordinateDirection j) =
      -(n : ℝ) * ginibreLebesgueDensityReal n z *
        ginibreImagDriftCoordinate n j z := by
  unfold ginibreLebesgueDensityReal
  rw [show (fun y : Configuration n =>
      (n / Real.pi) ^ n * vandermondeWeight y * gaussianWeight n y) =
      fun y => (n / Real.pi) ^ n *
        (vandermondeWeight y * gaussianWeight n y) by funext y; ring]
  change fderiv ℝ (fun y : Configuration n =>
    (n / Real.pi) ^ n *
      ((vandermondeWeight : Configuration n → ℝ) * gaussianWeight n) y) z _ = _
  rw [fderiv_const_mul
    ((differentiableAt_vandermondeWeight z).mul
      (differentiableAt_gaussianWeight n z))]
  rw [fderiv_mul (differentiableAt_vandermondeWeight z)
    (differentiableAt_gaussianWeight n z)]
  simp only [smul_apply, add_apply, smul_eq_mul]
  change _ * (_ * fderiv ℝ (gaussianWeight n) z (imaginaryCoordinateDirection j) +
    _ * fderiv ℝ vandermondeWeight z (coordinateDirection j Complex.I)) = _
  rw [fderiv_vandermondeWeight_apply_coordinateDirection z hz j Complex.I,
    fderiv_gaussianWeight_imaginaryCoordinate]
  simp_rw [div_eq_mul_inv]
  unfold ginibreImagDriftCoordinate
  have hs : (∑ k ∈ Finset.univ.erase j,
      Complex.I * (z j - z k)⁻¹).re =
      -(∑ k ∈ Finset.univ.erase j, ((z j - z k)⁻¹).im) := by
    change Complex.reCLM (∑ k ∈ Finset.univ.erase j,
      Complex.I * (z j - z k)⁻¹) = _
    rw [map_sum]
    simpa [Complex.mul_re] using
      (Finset.sum_neg_distrib :
        ∑ k ∈ Finset.univ.erase j, -((z j - z k)⁻¹).im =
          -(∑ k ∈ Finset.univ.erase j, ((z j - z k)⁻¹).im))
  rw [hs]
  field_simp [Nat.cast_ne_zero.mpr hn.ne']
  ring

/-- Pointwise divergence form of the Ginibre pregenerator away from particle
collisions. -/
theorem ginibreLebesgueDensityReal_mul_pregenerator_eq_divergence {n : ℕ}
    (hn : 0 < n) (f : Configuration n → ℝ) (hf : ContDiff ℝ ∞ f)
    (z : Configuration n) (hz : CollisionFree z) :
    ginibreLebesgueDensityReal n z * ginibrePregenerator n f z =
      (1 / (n : ℝ)) * ∑ j : Fin n,
        (fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
            fderiv ℝ f y (realCoordinateDirection j)) z
              (realCoordinateDirection j) +
          fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
            fderiv ℝ f y (imaginaryCoordinateDirection j)) z
              (imaginaryCoordinateDirection j)) := by
  have hdir (v : Configuration n) :
      DifferentiableAt ℝ (fun y => fderiv ℝ f y v) z := by
    have hp : ContDiff ℝ ∞ (fun y : Configuration n => (y, v)) :=
      contDiff_id.prodMk contDiff_const
    exact ((hf.contDiff_fderiv_apply (m := ∞) (by simp)).comp hp).differentiable
      (by simp) z
  have hprod (v : Configuration n) :
      fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
          fderiv ℝ f y v) z v =
        ginibreLebesgueDensityReal n z * secondDirectionalDerivative f v z +
          fderiv ℝ (ginibreLebesgueDensityReal n) z v * fderiv ℝ f z v := by
    change fderiv ℝ
      ((ginibreLebesgueDensityReal n) * fun y => fderiv ℝ f y v) z v = _
    rw [fderiv_mul ((contDiff_ginibreLebesgueDensityReal n).differentiable
      (by simp) z)
      (hdir v)]
    simp only [smul_apply, add_apply, smul_eq_mul]
    unfold secondDirectionalDerivative
    ring
  simp_rw [hprod]
  simp_rw [fderiv_ginibreLebesgueDensityReal_realCoordinate hn z hz,
    fderiv_ginibreLebesgueDensityReal_imaginaryCoordinate hn z hz]
  rw [ginibrePregenerator_eq_laplacian_sub_drift]
  unfold configurationLaplacian
  field_simp [Nat.cast_ne_zero.mpr hn.ne']
  rw [mul_sub, Finset.mul_sum, Finset.mul_sum, Finset.mul_sum,
    ← Finset.sum_sub_distrib]
  apply Finset.sum_congr rfl
  intro j hj
  ring

/-- Each density-weighted directional flux of a core observable is smooth. -/
theorem contDiff_ginibreDirectionalFlux_core {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f)
    (v : Configuration n) :
    ContDiff ℝ ∞ (fun z => ginibreLebesgueDensityReal n z *
      fderiv ℝ f z v) := by
  apply (contDiff_ginibreLebesgueDensityReal n).mul
  have hp : ContDiff ℝ ∞ (fun z : Configuration n => (z, v)) :=
    contDiff_id.prodMk contDiff_const
  exact (hf.1.contDiff_fderiv_apply (m := ∞) (by simp)).comp hp

/-- Each density-weighted directional flux of a core observable has compact
support (contained in the support of the derivative of the observable). -/
theorem hasCompactSupport_ginibreDirectionalFlux_core {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f)
    (v : Configuration n) :
    HasCompactSupport (fun z => ginibreLebesgueDensityReal n z *
      fderiv ℝ f z v) := by
  exact (HasCompactSupport.fderiv_apply (𝕜 := ℝ) hf.2.1 v).mul_left

/-- The directional derivative of every density-weighted core flux is
Lebesgue integrable. -/
theorem integrable_fderiv_ginibreDirectionalFlux_core {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f)
    (v : Configuration n) :
    Integrable (fun z => fderiv ℝ
      (fun y => ginibreLebesgueDensityReal n y * fderiv ℝ f y v) z v)
      volume := by
  have hs := hasCompactSupport_ginibreDirectionalFlux_core hf v
  have hds : HasCompactSupport (fun z => fderiv ℝ
      (fun y => ginibreLebesgueDensityReal n y * fderiv ℝ f y v) z v) :=
    HasCompactSupport.fderiv_apply (𝕜 := ℝ) hs v
  have hc : Continuous (fun z => fderiv ℝ
      (fun y => ginibreLebesgueDensityReal n y * fderiv ℝ f y v) z v) :=
    ((contDiff_ginibreDirectionalFlux_core hf v).continuous_fderiv (by simp)).clm_apply
      continuous_const
  exact hc.integrable_of_hasCompactSupport hds

/-- Product-rule identity for the density-weighted directional flux times
the observable. -/
theorem fderiv_core_mul_ginibreDirectionalFlux {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f)
    (v : Configuration n) (z : Configuration n) :
    fderiv ℝ (fun y => f y *
      (ginibreLebesgueDensityReal n y * fderiv ℝ f y v)) z v =
      ginibreLebesgueDensityReal n z * (fderiv ℝ f z v) ^ 2 +
        f z * fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
          fderiv ℝ f y v) z v := by
  have hflux : DifferentiableAt ℝ (fun y => ginibreLebesgueDensityReal n y *
      fderiv ℝ f y v) z :=
    ((contDiff_ginibreDirectionalFlux_core hf v).differentiable (by simp) z)
  change fderiv ℝ (f * fun y => ginibreLebesgueDensityReal n y *
    fderiv ℝ f y v) z v = _
  rw [fderiv_mul (hf.1.differentiable (by simp) z) hflux]
  simp only [smul_apply, add_apply, smul_eq_mul]
  ring

/-- The density-weighted flux times a core observable remains smooth and
compactly supported. -/
theorem contDiff_hasCompactSupport_core_mul_ginibreDirectionalFlux {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f)
    (v : Configuration n) :
    ContDiff ℝ ∞ (fun z => f z *
        (ginibreLebesgueDensityReal n z * fderiv ℝ f z v)) ∧
      HasCompactSupport (fun z => f z *
        (ginibreLebesgueDensityReal n z * fderiv ℝ f z v)) := by
  exact ⟨hf.1.mul (contDiff_ginibreDirectionalFlux_core hf v),
    hf.2.1.mul_right⟩

private theorem integral_density_directional_sq_eq_neg_flux
    {n : ℕ} {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f)
    (v : Configuration n)
    (hzero : ∫ z, fderiv ℝ (fun y => f y *
      (ginibreLebesgueDensityReal n y * fderiv ℝ f y v)) z v = 0) :
    ∫ z, ginibreLebesgueDensityReal n z * (fderiv ℝ f z v) ^ 2 =
      - ∫ z, f z * fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
        fderiv ℝ f y v) z v := by
  have hA : Integrable (fun z => ginibreLebesgueDensityReal n z *
      (fderiv ℝ f z v) ^ 2) := by
    apply ((contDiff_ginibreLebesgueDensityReal n).continuous.mul
      (((hf.1.continuous_fderiv (by simp)).clm_apply continuous_const).pow 2))
      |>.integrable_of_hasCompactSupport
    have hs := HasCompactSupport.fderiv_apply (𝕜 := ℝ) hf.2.1 v
    simpa only [pow_two] using hs.mul_right.mul_left
  have hB : Integrable (fun z => f z * fderiv ℝ
      (fun y => ginibreLebesgueDensityReal n y * fderiv ℝ f y v) z v) := by
    have hc : Continuous (fun z => fderiv ℝ
        (fun y => ginibreLebesgueDensityReal n y * fderiv ℝ f y v) z v) :=
      ((contDiff_ginibreDirectionalFlux_core hf v).continuous_fderiv (by simp)).clm_apply
        continuous_const
    exact (hf.1.continuous.mul hc).integrable_of_hasCompactSupport hf.2.1.mul_right
  have hs : (∫ z, ginibreLebesgueDensityReal n z * (fderiv ℝ f z v) ^ 2) +
      ∫ z, f z * fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
        fderiv ℝ f y v) z v = 0 := by
    rw [← integral_add hA hB]
    rw [← hzero]
    apply integral_congr_ae
    filter_upwards with z
    exact (fderiv_core_mul_ginibreDirectionalFlux hf v z).symm
  linarith

theorem integral_density_realDirectional_sq_eq_neg_flux {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) (j : Fin n) :
    ∫ z, ginibreLebesgueDensityReal n z *
        (fderiv ℝ f z (realCoordinateDirection j)) ^ 2 =
      - ∫ z, f z * fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
        fderiv ℝ f y (realCoordinateDirection j)) z
          (realCoordinateDirection j) := by
  apply integral_density_directional_sq_eq_neg_flux hf
  let hc := contDiff_hasCompactSupport_core_mul_ginibreDirectionalFlux hf
    (realCoordinateDirection j)
  exact integral_fderiv_configuration_real_eq_zero _ (hc.1.of_le (by simp)) hc.2 j

theorem integral_density_imagDirectional_sq_eq_neg_flux {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) (j : Fin n) :
    ∫ z, ginibreLebesgueDensityReal n z *
        (fderiv ℝ f z (imaginaryCoordinateDirection j)) ^ 2 =
      - ∫ z, f z * fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
        fderiv ℝ f y (imaginaryCoordinateDirection j)) z
          (imaginaryCoordinateDirection j) := by
  apply integral_density_directional_sq_eq_neg_flux hf
  let hc := contDiff_hasCompactSupport_core_mul_ginibreDirectionalFlux hf
    (imaginaryCoordinateDirection j)
  exact integral_fderiv_configuration_imag_eq_zero _ (hc.1.of_le (by simp)) hc.2 j

/-- Summed coordinate form of the density-weighted integration-by-parts
identity. -/
theorem sum_integral_density_gradient_sq_eq_neg_flux {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    ∑ j : Fin n,
        ((∫ z, ginibreLebesgueDensityReal n z *
            (fderiv ℝ f z (realCoordinateDirection j)) ^ 2) +
          ∫ z, ginibreLebesgueDensityReal n z *
            (fderiv ℝ f z (imaginaryCoordinateDirection j)) ^ 2) =
      - ∑ j : Fin n,
        ((∫ z, f z * fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
            fderiv ℝ f y (realCoordinateDirection j)) z
              (realCoordinateDirection j)) +
          ∫ z, f z * fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
            fderiv ℝ f y (imaginaryCoordinateDirection j)) z
              (imaginaryCoordinateDirection j)) := by
  rw [← Finset.sum_neg_distrib]
  apply Finset.sum_congr rfl
  intro j hj
  rw [integral_density_realDirectional_sq_eq_neg_flux hf j,
    integral_density_imagDirectional_sq_eq_neg_flux hf j]
  ring

theorem sum_density_directional_sq_eq_realGradientNormSq {n : ℕ}
    (f : Configuration n → ℝ) (z : Configuration n) :
    ∑ j : Fin n, ginibreLebesgueDensityReal n z *
        ((fderiv ℝ f z (realCoordinateDirection j)) ^ 2 +
          (fderiv ℝ f z (imaginaryCoordinateDirection j)) ^ 2) =
      ginibreLebesgueDensityReal n z * realGradientNormSq f z := by
  simp [realGradientNormSq, Finset.mul_sum]

theorem sum_core_flux_divergence_eq_density_mul_pregenerator {n : ℕ}
    (hn : 0 < n) {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f)
    (z : Configuration n) (hz : CollisionFree z) :
    ∑ j : Fin n, f z *
        (fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
            fderiv ℝ f y (realCoordinateDirection j)) z
              (realCoordinateDirection j) +
          fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
            fderiv ℝ f y (imaginaryCoordinateDirection j)) z
              (imaginaryCoordinateDirection j)) =
      (n : ℝ) * ginibreLebesgueDensityReal n z *
        f z * ginibrePregenerator n f z := by
  have hd := ginibreLebesgueDensityReal_mul_pregenerator_eq_divergence
    hn f hf.1 z hz
  field_simp [Nat.cast_ne_zero.mpr hn.ne'] at hd
  calc
    _ = f z * ∑ j : Fin n,
        (fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
            fderiv ℝ f y (realCoordinateDirection j)) z
              (realCoordinateDirection j) +
          fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
            fderiv ℝ f y (imaginaryCoordinateDirection j)) z
              (imaginaryCoordinateDirection j)) := by rw [Finset.mul_sum]
    _ = f z * (ginibreLebesgueDensityReal n z *
        ginibrePregenerator n f z * (n : ℝ)) := by rw [hd]
    _ = _ := by ring

/-- Unnormalized density form of the Ginibre generator integration-by-parts
identity. -/
theorem integral_density_gradient_eq_generator {n : ℕ} (hn : 0 < n)
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    (∫ z, ginibreLebesgueDensityReal n z * realGradientNormSq f z) =
      -(n : ℝ) * ∫ z, ginibreLebesgueDensityReal n z * f z *
        ginibrePregenerator n f z := by
  let R : Fin n → Configuration n → ℝ := fun j z =>
    ginibreLebesgueDensityReal n z *
      (fderiv ℝ f z (realCoordinateDirection j)) ^ 2
  let I : Fin n → Configuration n → ℝ := fun j z =>
    ginibreLebesgueDensityReal n z *
      (fderiv ℝ f z (imaginaryCoordinateDirection j)) ^ 2
  let FR : Fin n → Configuration n → ℝ := fun j z =>
    f z * fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
      fderiv ℝ f y (realCoordinateDirection j)) z (realCoordinateDirection j)
  let FI : Fin n → Configuration n → ℝ := fun j z =>
    f z * fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
      fderiv ℝ f y (imaginaryCoordinateDirection j)) z
        (imaginaryCoordinateDirection j)
  have hR (j : Fin n) : Integrable (R j) := by
    apply ((contDiff_ginibreLebesgueDensityReal n).continuous.mul
      (((hf.1.continuous_fderiv (by simp)).clm_apply continuous_const).pow 2))
      |>.integrable_of_hasCompactSupport
    have hs := HasCompactSupport.fderiv_apply (𝕜 := ℝ) hf.2.1
      (realCoordinateDirection j)
    simpa only [pow_two] using hs.mul_right.mul_left
  have hI (j : Fin n) : Integrable (I j) := by
    apply ((contDiff_ginibreLebesgueDensityReal n).continuous.mul
      (((hf.1.continuous_fderiv (by simp)).clm_apply continuous_const).pow 2))
      |>.integrable_of_hasCompactSupport
    have hs := HasCompactSupport.fderiv_apply (𝕜 := ℝ) hf.2.1
      (imaginaryCoordinateDirection j)
    simpa only [pow_two] using hs.mul_right.mul_left
  have hFR (j : Fin n) : Integrable (FR j) := by
    apply (hf.1.continuous.mul
      (((contDiff_ginibreDirectionalFlux_core hf (realCoordinateDirection j)).continuous_fderiv
        (by simp)).clm_apply continuous_const)).integrable_of_hasCompactSupport
    exact hf.2.1.mul_right
  have hFI (j : Fin n) : Integrable (FI j) := by
    apply (hf.1.continuous.mul
      (((contDiff_ginibreDirectionalFlux_core hf (imaginaryCoordinateDirection j)).continuous_fderiv
        (by simp)).clm_apply continuous_const)).integrable_of_hasCompactSupport
    exact hf.2.1.mul_right
  have hsum := sum_integral_density_gradient_sq_eq_neg_flux hf
  change (∑ j : Fin n, ((∫ z, R j z) + ∫ z, I j z)) =
    -∑ j : Fin n, ((∫ z, FR j z) + ∫ z, FI j z) at hsum
  have hleft : (∑ j : Fin n, ((∫ z, R j z) + ∫ z, I j z)) =
      ∫ z, ginibreLebesgueDensityReal n z * realGradientNormSq f z := by
    calc
      _ = ∑ j : Fin n, ∫ z, (R j z + I j z) := by
        apply Finset.sum_congr rfl
        intro j hj
        rw [integral_add (hR j) (hI j)]
      _ = ∫ z, ∑ j : Fin n, (R j z + I j z) := by
        rw [integral_finset_sum]
        intro j hj
        exact (hR j).add (hI j)
      _ = _ := by
        apply integral_congr_ae
        filter_upwards with z
        rw [← sum_density_directional_sq_eq_realGradientNormSq f z]
        apply Finset.sum_congr rfl
        intro j hj
        simp only [R, I]
        ring
  have hright : (∑ j : Fin n, ((∫ z, FR j z) + ∫ z, FI j z)) =
      ∫ z, (n : ℝ) * ginibreLebesgueDensityReal n z * f z *
        ginibrePregenerator n f z := by
    calc
      _ = ∑ j : Fin n, ∫ z, (FR j z + FI j z) := by
        apply Finset.sum_congr rfl
        intro j hj
        rw [integral_add (hFR j) (hFI j)]
      _ = ∫ z, ∑ j : Fin n, (FR j z + FI j z) := by
        rw [integral_finset_sum]
        intro j hj
        exact (hFR j).add (hFI j)
      _ = _ := by
        apply integral_congr_ae
        filter_upwards with z
        by_cases hz : CollisionFree z
        · simpa [FR, FI, mul_add] using
            sum_core_flux_divergence_eq_density_mul_pregenerator hn hf z hz
        · have hfz : f z = 0 := by
            by_contra hfne
            exact hz (hf.support_collisionFree hfne)
          simp [FR, FI, hfz]
  rw [hleft, hright] at hsum
  calc
    _ = -∫ z, (n : ℝ) * ginibreLebesgueDensityReal n z * f z *
        ginibrePregenerator n f z := hsum
    _ = -(n : ℝ) * ∫ z, ginibreLebesgueDensityReal n z * f z *
        ginibrePregenerator n f z := by
      have hc : (∫ z, (n : ℝ) * ginibreLebesgueDensityReal n z * f z *
          ginibrePregenerator n f z) =
          (n : ℝ) * ∫ z, ginibreLebesgueDensityReal n z * f z *
            ginibrePregenerator n f z := by
        rw [← integral_const_mul]
        congr 1
        funext z
        ring
      rw [hc]
      ring

/-- Concrete normalized Ginibre integration by parts on the collision-free
smooth symmetric core. -/
theorem ginibrePregenerator_integrationByParts {n : ℕ} (hn : 0 < n)
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    (∫ z, ginibrePregenerator n f z * f z ∂ginibreMeasure n) =
      -smoothGinibreEnergy n f := by
  rw [integral_ginibreMeasure_eq_density_volume hn]
  unfold smoothGinibreEnergy
  rw [integral_ginibreMeasure_eq_density_volume hn]
  have h := integral_density_gradient_eq_generator hn hf
  have hswap : (∫ z, ginibreLebesgueDensityReal n z *
      (ginibrePregenerator n f z * f z)) =
      ∫ z, ginibreLebesgueDensityReal n z * f z *
        ginibrePregenerator n f z := by
    apply integral_congr_ae
    filter_upwards with z
    ring
  rw [hswap]
  have hn0 : (n : ℝ) ≠ 0 := Nat.cast_ne_zero.mpr hn.ne'
  calc
    (ginibreNormalizingMass n).toReal⁻¹ *
        (∫ z, ginibreLebesgueDensityReal n z * f z *
          ginibrePregenerator n f z) =
      -(1 / (n : ℝ)) * ((ginibreNormalizingMass n).toReal⁻¹ *
        ∫ z, ginibreLebesgueDensityReal n z * realGradientNormSq f z) := by
          rw [h]
          field_simp
    _ = _ := by ring

/-- The collision locus is also null for configuration Lebesgue measure. -/
theorem configurationVolume_collisionSet {n : ℕ} (hn : 0 < n) :
    configurationVolume n (collisionSet n) = 0 := by
  have hac : configurationVolume n ≪
      (configurationVolume n).withDensity (complexGaussianDensity n) := by
    apply withDensity_absolutelyContinuous'
    · exact (measurable_complexGaussianDensity n).aemeasurable
    · filter_upwards with z
      unfold complexGaussianDensity gaussianWeight
      positivity
  apply hac
  rw [← show complexGaussianDensityMeasure n =
      (configurationVolume n).withDensity (complexGaussianDensity n) by rfl]
  rw [← complexGaussianDensityIdentification n hn]
  exact complexGaussianMeasure_collisionSet n

/-- The concrete Ginibre pregenerator has zero mean on its smooth core. -/
theorem integral_ginibrePregenerator_eq_zero {n : ℕ} (hn : 0 < n)
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    ∫ z, ginibrePregenerator n f z ∂ginibreMeasure n = 0 := by
  rw [integral_ginibreMeasure_eq_density_volume hn]
  have hcf : ∀ᵐ z ∂(configurationVolume n), CollisionFree z := by
    rw [ae_iff]
    have heq : {z : Configuration n | ¬ CollisionFree z} = collisionSet n := by
      ext z
      rw [Set.mem_setOf_eq, collisionFree_iff_not_mem_collisionSet]
      simp
    rw [heq]
    exact configurationVolume_collisionSet hn
  have hdiv : (∫ z, ginibreLebesgueDensityReal n z *
      ginibrePregenerator n f z) =
      ∫ z, (1 / (n : ℝ)) * ∑ j : Fin n,
        (fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
            fderiv ℝ f y (realCoordinateDirection j)) z
              (realCoordinateDirection j) +
          fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
            fderiv ℝ f y (imaginaryCoordinateDirection j)) z
              (imaginaryCoordinateDirection j)) := by
    apply integral_congr_ae
    filter_upwards [hcf] with z hz
    exact ginibreLebesgueDensityReal_mul_pregenerator_eq_divergence
      hn f hf.1 z hz
  rw [hdiv, integral_const_mul, integral_finset_sum]
  · simp_rw [integral_add
        (integrable_fderiv_ginibreDirectionalFlux_core hf _)
        (integrable_fderiv_ginibreDirectionalFlux_core hf _)]
    have hzR (j : Fin n) :
        (∫ z, fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
          fderiv ℝ f y (realCoordinateDirection j)) z
            (realCoordinateDirection j)) = 0 :=
      integral_fderiv_configuration_real_eq_zero _
        ((contDiff_ginibreDirectionalFlux_core hf _).of_le (by simp))
        (hasCompactSupport_ginibreDirectionalFlux_core hf _) j
    have hzI (j : Fin n) :
        (∫ z, fderiv ℝ (fun y => ginibreLebesgueDensityReal n y *
          fderiv ℝ f y (imaginaryCoordinateDirection j)) z
            (imaginaryCoordinateDirection j)) = 0 :=
      integral_fderiv_configuration_imag_eq_zero _
        ((contDiff_ginibreDirectionalFlux_core hf _).of_le (by simp))
        (hasCompactSupport_ginibreDirectionalFlux_core hf _) j
    simp [hzR, hzI]
  · intro j hj
    exact (integrable_fderiv_ginibreDirectionalFlux_core hf _).add
      (integrable_fderiv_ginibreDirectionalFlux_core hf _)

/-- A compactly supported core observable is Ginibre-integrable. -/
theorem integrable_core_ginibre {n : ℕ} (hn : 0 < n)
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    Integrable f (ginibreMeasure n) := by
  letI := ginibreMeasure_isProbabilityMeasure hn
  exact hf.1.continuous.integrable_of_hasCompactSupport hf.2.1

/-- The Euclidean squared gradient of a core observable is continuous. -/
theorem continuous_realGradientNormSq_of_core {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    Continuous (realGradientNormSq f) := by
  unfold realGradientNormSq
  apply continuous_finset_sum
  intro k hk
  have hdf : Continuous (fderiv ℝ f) := hf.1.continuous_fderiv (by simp)
  have hre : Continuous (fun z : Configuration n =>
      fderiv ℝ f z (realCoordinateDirection k)) :=
    hdf.clm_apply continuous_const
  have him : Continuous (fun z : Configuration n =>
      fderiv ℝ f z (imaginaryCoordinateDirection k)) :=
    hdf.clm_apply continuous_const
  exact hre.pow 2 |>.add (him.pow 2)

/-- The squared gradient vanishes off the compact support of a core
observable, hence is itself compactly supported. -/
theorem hasCompactSupport_realGradientNormSq_of_core {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    HasCompactSupport (realGradientNormSq f) := by
  apply hf.2.1.of_isClosed_subset (isClosed_tsupport _)
  apply closure_minimal
  · intro z hz
    by_contra hzt
    apply hz
    have hzero : fderiv ℝ f z = 0 := fderiv_of_notMem_tsupport ℝ hzt
    simp [realGradientNormSq, hzero]
  · exact isClosed_tsupport _

/-- The Dirichlet density of a core observable is Ginibre-integrable. -/
theorem integrable_realGradientNormSq_core_ginibre {n : ℕ} (hn : 0 < n)
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    Integrable (realGradientNormSq f) (ginibreMeasure n) := by
  letI := ginibreMeasure_isProbabilityMeasure hn
  exact (continuous_realGradientNormSq_of_core hf).integrable_of_hasCompactSupport
    (hasCompactSupport_realGradientNormSq_of_core hf)

/-- The square of a compactly supported core observable is
Ginibre-integrable. -/
theorem integrable_sq_core_ginibre {n : ℕ} (hn : 0 < n)
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    Integrable (fun z => (f z) ^ 2) (ginibreMeasure n) := by
  letI := ginibreMeasure_isProbabilityMeasure hn
  apply (hf.1.continuous.pow 2).integrable_of_hasCompactSupport
  apply hf.2.1.mono
  intro z hz hzero
  exact hz (by simp [hzero])

end
end GinibrePoincare
Analysis GinibrePoincare/Analysis/GinibreMassFiniteness.lean #
import GinibrePoincare.Analysis.GaussianPolynomialIntegrability
import GinibrePoincare.Analysis.GinibreMassPositivity

/-! # Finiteness of the Ginibre normalizing mass -/

open MeasureTheory
open scoped ENNReal BigOperators

namespace GinibrePoincare

noncomputable section

/-- A polynomial growth majorant for one coordinate is integrable under its
complex Gaussian law. -/
theorem integrable_one_add_norm_pow_complexCoordinateGaussianProbability
    (n k : ℕ) :
    Integrable (fun z : ℂ ↦ (1 + ‖z‖) ^ k)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  rw [show (fun z : ℂ ↦ (1 + ‖z‖) ^ k) =
      fun z ↦ ∑ m ∈ Finset.range (k + 1),
        ‖z‖ ^ (k - m) * (Nat.choose k m : ℝ) by
    funext z
    rw [add_pow]
    apply Finset.sum_congr rfl
    intro m hm
    simp only [one_pow, one_mul]]
  apply integrable_finsetSum
  intro m hm
  exact (integrable_norm_pow_complexCoordinateGaussianProbability n (k - m)).mul_const _

/-- Products of coordinatewise polynomial majorants are integrable under the
concrete product Gaussian law. -/
theorem integrable_prod_one_add_norm_pow_complexGaussianMeasure
    (n : ℕ) (k : Fin n → ℕ) :
    Integrable (fun z : Configuration n ↦ ∏ i, (1 + ‖z i‖) ^ k i)
      (complexGaussianMeasure n) := by
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  exact Integrable.fintype_prod fun i ↦
    integrable_one_add_norm_pow_complexCoordinateGaussianProbability n (k i)

/-- Constant-exponent form of
`integrable_prod_one_add_norm_pow_complexGaussianMeasure`. -/
theorem integrable_prod_one_add_norm_pow_const_complexGaussianMeasure
    (n k : ℕ) :
    Integrable (fun z : Configuration n ↦ ∏ i, (1 + ‖z i‖) ^ k)
      (complexGaussianMeasure n) :=
  integrable_prod_one_add_norm_pow_complexGaussianMeasure n (fun _ ↦ k)

/-- A deliberately generous separable polynomial bound for the Vandermonde
square. -/
theorem vandermondeWeight_le_prod_one_add_norm_pow (n : ℕ)
    (z : Configuration n) :
    vandermondeWeight z ≤ ∏ i, (1 + ‖z i‖) ^ (4 * n * n) := by
  let B : ℝ := ∏ i : Fin n, (1 + ‖z i‖)
  have hfac (i : Fin n) : 1 ≤ 1 + ‖z i‖ := by
    linarith [norm_nonneg (z i)]
  have hB : 1 ≤ B := by
    dsimp [B]
    exact Finset.one_le_prod fun i _ ↦ hfac i
  have hiB (i : Fin n) : 1 + ‖z i‖ ≤ B := by
    have he : B = (1 + ‖z i‖) *
        ∏ j ∈ (Finset.univ : Finset (Fin n)).erase i, (1 + ‖z j‖) := by
      dsimp [B]
      exact (Finset.mul_prod_erase (Finset.univ : Finset (Fin n))
        (fun j ↦ 1 + ‖z j‖) (Finset.mem_univ i)).symm
    have ho : 1 ≤ ∏ j ∈ (Finset.univ : Finset (Fin n)).erase i,
        (1 + ‖z j‖) := Finset.one_le_prod fun j _ ↦ hfac j
    rw [he]
    nlinarith [hfac i]
  have hdiff (i j : Fin n) : ‖z j - z i‖ ≤ B ^ 2 := by
    calc
      ‖z j - z i‖ ≤ ‖z j‖ + ‖z i‖ := norm_sub_le _ _
      _ ≤ (1 + ‖z j‖) * (1 + ‖z i‖) := by nlinarith [norm_nonneg (z i), norm_nonneg (z j)]
      _ ≤ B * B := mul_le_mul (hiB j) (hiB i) (by positivity) (by positivity)
      _ = B ^ 2 := by ring
  have hinner (i : Fin n) :
      ∏ j > i, ‖z j - z i‖ ≤ (B ^ 2) ^ n := by
    calc
      _ ≤ ∏ j > i, B ^ 2 := by
        apply Finset.prod_le_prod
        · intro j hj
          positivity
        · intro j hj
          exact hdiff i j
      _ ≤ (B ^ 2) ^ n := by
        rw [Finset.prod_const]
        apply pow_le_pow_right₀ (by nlinarith [hB])
        exact (Finset.card_le_card (Finset.subset_univ _)).trans_eq (by simp)
  have hvnorm : ‖vandermonde z‖ ≤ (B ^ 2) ^ (n * n) := by
    rw [vandermonde_eq_product, norm_prod]
    simp_rw [norm_prod]
    calc
      _ ≤ ∏ _i : Fin n, (B ^ 2) ^ n :=
        Finset.prod_le_prod (fun _ _ ↦ by positivity) fun i _ ↦ hinner i
      _ = ((B ^ 2) ^ n) ^ n := by simp
      _ = (B ^ 2) ^ (n * n) := by rw [← pow_mul]
  unfold vandermondeWeight
  rw [Complex.normSq_eq_norm_sq]
  calc
    ‖vandermonde z‖ ^ 2 ≤ ((B ^ 2) ^ (n * n)) ^ 2 :=
      pow_le_pow_left₀ (norm_nonneg _) hvnorm 2
    _ = B ^ (4 * n * n) := by ring
    _ = ∏ i, (1 + ‖z i‖) ^ (4 * n * n) := by
      dsimp [B]
      rw [Finset.prod_pow]

/-- The Vandermonde square is integrable under the concrete Gaussian
reference probability measure. -/
theorem integrable_vandermondeWeight_complexGaussianMeasure (n : ℕ) :
    Integrable (vandermondeWeight : Configuration n → ℝ)
      (complexGaussianMeasure n) := by
  apply Integrable.mono'
    (integrable_prod_one_add_norm_pow_const_complexGaussianMeasure
      n (4 * n * n))
  · exact (Complex.continuous_normSq.comp continuous_vandermonde).aestronglyMeasurable
  · filter_upwards with z
    rw [Real.norm_eq_abs, abs_of_nonneg (vandermondeWeight_nonneg z)]
    exact vandermondeWeight_le_prod_one_add_norm_pow n z

/-- The actual normalizing mass of the raw Ginibre measure is finite. -/
theorem ginibreNormalizingMass_lt_top (n : ℕ) :
    ginibreNormalizingMass n < ⊤ := by
  unfold ginibreNormalizingMass rawGinibreMeasure
  rw [withDensity_apply' _ Set.univ, Measure.restrict_univ]
  exact (integrable_vandermondeWeight_complexGaussianMeasure n).lintegral_lt_top

/-- The concrete Ginibre normalizing mass is positive and finite at every
positive particle number. -/
theorem ginibreMassEvaluation : GinibreMassEvaluationStatement := by
  intro n hn
  exact ⟨ginibreNormalizingMass_pos hn, ginibreNormalizingMass_lt_top n⟩

/-- The normalized concrete Ginibre measure has total mass one. -/
theorem ginibreMeasureIsProbability : GinibreMeasureIsProbabilityStatement :=
  ginibreMeasureIsProbability_of_mass_evaluation ginibreMassEvaluation

/-- Typeclass-valued probability assertion for the concrete normalized law. -/
theorem ginibreMeasure_isProbabilityMeasure {n : ℕ} (hn : 0 < n) :
    IsProbabilityMeasure (ginibreMeasure n) :=
  ginibreMeasure_isProbabilityMeasure_of_mass_evaluation
    ginibreMassEvaluation n hn


end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/GinibreMassPositivity.lean #
import GinibrePoincare.Analysis.ComplexGaussianDensity
import Mathlib.MeasureTheory.Measure.OpenPos

/-! # Strict positivity of the Ginibre normalizing mass -/

open MeasureTheory
open scoped ENNReal BigOperators

namespace GinibrePoincare

noncomputable section

/-- The Vandermonde polynomial is continuous on configuration space. -/
theorem continuous_vandermonde {n : ℕ} :
    Continuous (vandermonde : Configuration n → ℂ) := by
  rw [show (vandermonde : Configuration n → ℂ) =
      fun z ↦ ∏ i : Fin n, ∏ j > i, (z j - z i) by
    funext z
    exact vandermonde_eq_product z]
  fun_prop

/-- The extended nonnegative Vandermonde density is measurable. -/
theorem measurable_vandermondeDensity {n : ℕ} :
    Measurable (vandermondeDensity : Configuration n → ℝ≥0∞) := by
  unfold vandermondeDensity vandermondeWeight
  exact ENNReal.measurable_ofReal.comp
    (Complex.continuous_normSq.comp continuous_vandermonde).measurable

/-- The explicit complex Gaussian density is measurable. -/
theorem measurable_complexGaussianDensity (n : ℕ) :
    Measurable (complexGaussianDensity n) := by
  unfold complexGaussianDensity gaussianWeight configurationNormSq
  fun_prop

/-- At positive particle number the explicit Gaussian density is everywhere
strictly positive. -/
theorem complexGaussianDensity_pos {n : ℕ} (hn : 0 < n)
    (z : Configuration n) : 0 < complexGaussianDensity n z := by
  unfold complexGaussianDensity
  rw [ENNReal.ofReal_pos]
  exact mul_pos
    (pow_pos (div_pos (show (0 : ℝ) < (n : ℝ) by exact_mod_cast hn)
      Real.pi_pos) n)
    (gaussianWeight_pos n z)

/-- Every nonempty open subset of configuration space has positive Gaussian
measure. -/
theorem complexGaussianMeasure_isOpenPosMeasure {n : ℕ} (hn : 0 < n)
    {U : Set (Configuration n)} (hU : IsOpen U) (hne : U.Nonempty) :
    0 < complexGaussianMeasure n U := by
  rw [complexGaussianDensityIdentification n hn,
    complexGaussianDensityMeasure, configurationVolume,
    withDensity_apply _ hU.measurableSet]
  rw [setLIntegral_pos_iff (measurable_complexGaussianDensity n)]
  have hsupp : Function.support (complexGaussianDensity n) = Set.univ := by
    ext z
    simp only [Function.mem_support, Set.mem_univ, iff_true]
    exact (complexGaussianDensity_pos hn z).ne'
  rw [hsupp, Set.univ_inter]
  exact hU.measure_pos (volume : Measure (Configuration n)) hne

/-- A canonical collision-free configuration, obtained by placing the
particles at distinct nonnegative integers on the real axis. -/
def integerConfiguration (n : ℕ) : Configuration n :=
  fun i ↦ (i.val : ℂ)

theorem integerConfiguration_collisionFree (n : ℕ) :
    CollisionFree (integerConfiguration n) := by
  intro i j hij
  apply Fin.ext
  have h := congrArg Complex.re hij
  simp [integerConfiguration] at h
  exact_mod_cast h

/-- The set on which the Vandermonde density is nonzero is open and nonempty. -/
theorem support_vandermondeDensity_isOpen_nonempty (n : ℕ) :
    IsOpen (Function.support
      (vandermondeDensity : Configuration n → ℝ≥0∞)) ∧
    (Function.support
      (vandermondeDensity : Configuration n → ℝ≥0∞)).Nonempty := by
  constructor
  · have hcont : Continuous
        (fun z : Configuration n ↦ Complex.normSq (vandermonde z)) :=
      Complex.continuous_normSq.comp continuous_vandermonde
    have hopen : IsOpen
        {z : Configuration n | Complex.normSq (vandermonde z) ≠ 0} :=
      isClosed_singleton.isOpen_compl.preimage hcont
    simpa [Function.support, vandermondeDensity, vandermondeWeight,
      ENNReal.ofReal_eq_zero, Complex.normSq_nonneg] using hopen
  · refine ⟨integerConfiguration n, ?_⟩
    simp only [Function.mem_support, vandermondeDensity, vandermondeWeight]
    exact (ENNReal.ofReal_pos.mpr (Complex.normSq_pos.mpr
      ((vandermonde_ne_zero_iff _).mpr
        (integerConfiguration_collisionFree n)))).ne'

/-- The raw Ginibre normalizing mass is strictly positive.  This result is
independent of its finiteness. -/
theorem ginibreNormalizingMass_pos {n : ℕ} (hn : 0 < n) :
    0 < ginibreNormalizingMass n := by
  unfold ginibreNormalizingMass rawGinibreMeasure
  rw [withDensity_apply' _ Set.univ]
  rw [Measure.restrict_univ]
  rw [lintegral_pos_iff_support measurable_vandermondeDensity]
  rcases support_vandermondeDensity_isOpen_nonempty n with ⟨hopen, hne⟩
  exact complexGaussianMeasure_isOpenPosMeasure hn hopen hne

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/GlobalPhaseAction.lean #
import GinibrePoincare.Analysis.HolomorphicVandermondeDivision
import Mathlib.Analysis.InnerProductSpace.Basic
import Mathlib.MeasureTheory.Measure.Lebesgue.Complex
import GinibrePoincare.Analysis.ComplexGaussianDensity
import GinibrePoincare.Analysis.MeasureTransport
import GinibrePoincare.Analysis.VandermondeL2
import GinibrePoincare.Analysis.VandermondeL2Inverse
import GinibrePoincare.Analysis.HermiteL2Family
import GinibrePoincare.Analysis.HermiteEnergy
import Mathlib.RingTheory.RootsOfUnity.Complex
import Mathlib.RingTheory.MvPolynomial.Homogeneous
import Mathlib.Algebra.MvPolynomial.NoZeroDivisors

/-! # Global phase rotations -/

open scoped BigOperators ComplexConjugate ENNReal
open MeasureTheory

namespace GinibrePoincare

noncomputable section

/-- Simultaneous multiplication of every particle coordinate by a phase. -/
def globalPhase {n : ℕ} (u : ℂ) (z : Configuration n) : Configuration n :=
  fun i ↦ u * z i

@[simp] theorem globalPhase_apply {n : ℕ} (u : ℂ)
    (z : Configuration n) (i : Fin n) : globalPhase u z i = u * z i := rfl

@[simp] theorem globalPhase_one {n : ℕ} (z : Configuration n) :
    globalPhase 1 z = z := by ext; simp

theorem globalPhase_mul {n : ℕ} (u v : ℂ) (z : Configuration n) :
    globalPhase u (globalPhase v z) = globalPhase (u * v) z := by
  ext i
  simp [globalPhase, mul_assoc]

def totalHolomorphicDegree {n : ℕ} (p : Fin n → ℕ) : ℕ := ∑ i, p i

/-- Total degree of the `n`-particle Vandermonde. -/
def vandermondeDegree (n : ℕ) : ℕ := Fintype.card (OrderedParticlePair n)

theorem vandermondeDegree_eq_sum_Ioi_card (n : ℕ) :
    vandermondeDegree n = ∑ i : Fin n, (Finset.Ioi i).card := by
  unfold vandermondeDegree
  rw [Fintype.card_sigma]
  apply Finset.sum_congr rfl
  intro i hi
  exact Fintype.card_coe _

theorem inner_eq_zero_of_isometry_eigencharacters
    {E : Type*} [NormedAddCommGroup E] [InnerProductSpace ℂ E]
    (T : E →ₗᵢ[ℂ] E) (x y : E) (a b : ℂ)
    (hx : T x = a • x) (hy : T y = b • y)
    (hsep : conj a * b ≠ 1) : inner ℂ x y = 0 := by
  have hinner := T.inner_map_map x y
  rw [hx, hy, inner_smul_left, inner_smul_right] at hinner
  have hmul : (conj a * b - 1) * inner ℂ x y = 0 := by
    calc
      _ = conj a * b * inner ℂ x y - inner ℂ x y := by ring
      _ = 0 := sub_eq_zero.mpr (by simpa [mul_assoc] using hinner)
  exact (mul_eq_zero.mp hmul).resolve_left (sub_ne_zero.mpr hsep)

/-- The real `2 × 2` matrix of multiplication by `u`. -/
def complexMultiplicationMatrix (u : ℂ) : Matrix (Fin 2) (Fin 2) ℝ :=
  !![u.re, -u.im; u.im, u.re]

/-- Its determinant is the squared complex norm. -/
theorem det_complexMultiplicationMatrix (u : ℂ) :
    (complexMultiplicationMatrix u).det = Complex.normSq u := by
  simp [complexMultiplicationMatrix, Matrix.det_fin_two, Complex.normSq_apply]

/-- In real coordinates, the explicit matrix acts as complex
multiplication. -/
theorem toLin_complexMultiplicationMatrix (u z : ℂ) :
    Matrix.toLin' (complexMultiplicationMatrix u)
        (Complex.measurableEquivPi z) =
      Complex.measurableEquivPi (u * z) := by
  funext i
  fin_cases i <;>
    simp only [Matrix.toLin'_apply]
  all_goals simp [complexMultiplicationMatrix, Matrix.mulVec,
      Fin.sum_univ_two, Complex.mul_re, Complex.mul_im] <;> ring

/-- Multiplication by a unit complex number preserves planar Lebesgue
measure. -/
theorem measurePreserving_complex_mul_of_norm_one (u : ℂ) (hu : ‖u‖ = 1) :
    MeasurePreserving (fun z : ℂ ↦ u * z) volume volume := by
  have hnormSq : Complex.normSq u = 1 := by
    rw [← Complex.sq_norm, hu]
    norm_num
  have hdet : (complexMultiplicationMatrix u).det ≠ 0 := by
    rw [det_complexMultiplicationMatrix, hnormSq]
    norm_num
  have hmap := Real.map_matrix_volume_pi_eq_smul_volume_pi hdet
  have hmap' : Measure.map (Matrix.toLin' (complexMultiplicationMatrix u)) volume =
      (volume : Measure (Fin 2 → ℝ)) := by
    rw [hmap, det_complexMultiplicationMatrix, hnormSq]
    simp
  have hlinear : MeasurePreserving
      (Matrix.toLin' (complexMultiplicationMatrix u)) volume volume :=
    ⟨(Matrix.toLin' (complexMultiplicationMatrix u)).continuous_of_finiteDimensional.measurable,
      hmap'⟩
  have hcomp := Complex.volume_preserving_equiv_pi.symm.comp
    (hlinear.comp Complex.volume_preserving_equiv_pi)
  have hfun :
      (Complex.measurableEquivPi.symm ∘
        Matrix.toLin' (complexMultiplicationMatrix u) ∘
          Complex.measurableEquivPi) = (fun z : ℂ ↦ u * z) := by
    funext z
    apply Complex.measurableEquivPi.injective
    simp only [Function.comp_apply, MeasurableEquiv.apply_symm_apply]
    exact toLin_complexMultiplicationMatrix u z
  rw [hfun] at hcomp
  exact hcomp

/-- Multiplication by a nonzero complex scalar as a measurable equivalence. -/
def complexMulMeasurableEquiv (u : ℂ) (hu : u ≠ 0) : ℂ ≃ᵐ ℂ where
  toFun z := u * z
  invFun z := u⁻¹ * z
  left_inv z := by field_simp
  right_inv z := by field_simp
  measurable_toFun := (continuous_const.mul continuous_id).measurable
  measurable_invFun := (continuous_const.mul continuous_id).measurable

theorem complexCoordinateGaussianDensity_globalPhase (n : ℕ) (u z : ℂ)
    (hu : ‖u‖ = 1) :
    complexCoordinateGaussianDensity n (u * z) =
      complexCoordinateGaussianDensity n z := by
  unfold complexCoordinateGaussianDensity
  congr 2
  rw [Complex.normSq_mul, ← Complex.sq_norm, hu]
  norm_num

/-- A unit phase preserves one complex Gaussian coordinate law. -/
theorem measurePreserving_complexCoordinateGaussian_mul {n : ℕ} (hn : 0 < n)
    (u : ℂ) (hu : ‖u‖ = 1) :
    MeasurePreserving (fun z : ℂ ↦ u * z)
      (complexCoordinateGaussianProbability n : Measure ℂ)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  have hu0 : u ≠ 0 := by
    intro h
    subst u
    simp at hu
  let e := complexMulMeasurableEquiv u hu0
  rw [complexCoordinateGaussianMeasure_eq_withDensity hn]
  refine ⟨e.measurable, ?_⟩
  have hbase : MeasurePreserving e (volume : Measure ℂ) volume := by
    exact measurePreserving_complex_mul_of_norm_one u hu
  have hd : complexCoordinateGaussianDensity n ∘ e =
      complexCoordinateGaussianDensity n := by
    funext z
    exact complexCoordinateGaussianDensity_globalPhase n u z hu
  have hm := MeasurePreserving.map_withDensity_comp e hbase
    (measurable_complexCoordinateGaussianDensity n)
  change Measure.map e
      ((volume : Measure ℂ).withDensity (complexCoordinateGaussianDensity n)) =
    (volume : Measure ℂ).withDensity (complexCoordinateGaussianDensity n)
  simpa only [hd] using hm

/-- A unit global phase preserves the finite product complex Gaussian law. -/
theorem measurePreserving_globalPhase_complexGaussianMeasure {n : ℕ}
    (hn : 0 < n) (u : ℂ) (hu : ‖u‖ = 1) :
    MeasurePreserving (globalPhase u) (complexGaussianMeasure n)
      (complexGaussianMeasure n) := by
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  exact measurePreserving_pi _ _ fun _ ↦
    measurePreserving_complexCoordinateGaussian_mul hn u hu

theorem vandermonde_globalPhase (n : ℕ) (u : ℂ) (z : Configuration n) :
    vandermonde (globalPhase u z) =
      u ^ (∑ i : Fin n, (Finset.Ioi i).card) * vandermonde z := by
  rw [vandermonde_eq_product, vandermonde_eq_product]
  simp_rw [globalPhase_apply, ← mul_sub]
  simp_rw [Finset.prod_mul_distrib, Finset.prod_const]
  have hp : (∏ i : Fin n, u ^ (Finset.Ioi i).card) =
      u ^ ∑ i : Fin n, (Finset.Ioi i).card := by
    simpa using (Finset.prod_pow_eq_pow_sum Finset.univ
      (fun i : Fin n ↦ (Finset.Ioi i).card) u)
  rw [hp]

theorem vandermondeDensity_globalPhase (n : ℕ) (u : ℂ)
    (hu : ‖u‖ = 1) (z : Configuration n) :
    vandermondeDensity (globalPhase u z) = vandermondeDensity z := by
  unfold vandermondeDensity vandermondeWeight
  rw [vandermonde_globalPhase]
  rw [Complex.normSq_mul]
  have hp : Complex.normSq
      (u ^ ∑ i : Fin n, (Finset.Ioi i).card) = 1 := by
    rw [← Complex.sq_norm, norm_pow, hu]
    norm_num
  rw [hp, one_mul]

/-- Coordinatewise unit multiplication as a measurable equivalence. -/
def globalPhaseMeasurableEquiv {n : ℕ} (u : ℂ) (hu : u ≠ 0) :
    Configuration n ≃ᵐ Configuration n :=
  MeasurableEquiv.piCongrRight (fun _ ↦ complexMulMeasurableEquiv u hu)

@[simp] theorem globalPhaseMeasurableEquiv_apply {n : ℕ} (u : ℂ)
    (hu : u ≠ 0) (z : Configuration n) :
    globalPhaseMeasurableEquiv u hu z = globalPhase u z := rfl

/-- A unit global phase preserves the normalized Ginibre law. -/
theorem measurePreserving_globalPhase_ginibreMeasure {n : ℕ}
    (hn : 0 < n) (u : ℂ) (hu : ‖u‖ = 1) :
    MeasurePreserving (globalPhase u) (ginibreMeasure n) (ginibreMeasure n) := by
  have hu0 : u ≠ 0 := by
    intro h
    subst u
    simp at hu
  let e := globalPhaseMeasurableEquiv (n := n) u hu0
  refine ⟨e.measurable, ?_⟩
  unfold ginibreMeasure rawGinibreMeasure
  rw [Measure.map_smul]
  congr 1
  have hbase : MeasurePreserving e (complexGaussianMeasure n)
      (complexGaussianMeasure n) := by
    exact measurePreserving_globalPhase_complexGaussianMeasure hn u hu
  have hd : vandermondeDensity ∘ e =
      (vandermondeDensity : Configuration n → ℝ≥0∞) := by
    funext z
    exact vandermondeDensity_globalPhase n u hu z
  nth_rw 1 [← hd]
  exact MeasurePreserving.map_withDensity_comp e hbase
    measurable_vandermondeDensity

theorem multivariateNormalized_zero_globalPhase (n : ℕ) (hn : 0 < n)
    (u : ℂ) (p : Fin n → ℕ) (z : Configuration n) :
    ComplexHermite.multivariateNormalized n hn p 0 (globalPhase u z) =
      u ^ totalHolomorphicDegree p *
        ComplexHermite.multivariateNormalized n hn p 0 z := by
  simp only [ComplexHermite.multivariateNormalized_zero_right]
  simp_rw [globalPhase_apply, mul_pow, ← mul_assoc]
  have hu : (∏ i : Fin n, u ^ p i) = u ^ totalHolomorphicDegree p := by
    simpa [totalHolomorphicDegree] using
      (Finset.prod_pow_eq_pow_sum Finset.univ p u)
  simp_rw [mul_assoc]
  simp_rw [show ∀ x : Fin n,
      (ComplexHermite.oneDimNormalization n (p x) : ℂ) *
          (u ^ p x * z x ^ p x) =
        u ^ p x * ((ComplexHermite.oneDimNormalization n (p x) : ℂ) *
          z x ^ p x) by intro x; ring]
  rw [Finset.prod_mul_distrib, hu]

/-- Pullback by a unit global phase on Gaussian `L²`. -/
def gaussianGlobalPhaseL2 {n : ℕ} (hn : 0 < n) (u : ℂ) (hu : ‖u‖ = 1) :
    Lp ℂ 2 (complexGaussianMeasure n) →ₗᵢ[ℂ]
      Lp ℂ 2 (complexGaussianMeasure n) :=
  Lp.compMeasurePreservingₗᵢ ℂ (globalPhase u)
    (measurePreserving_globalPhase_complexGaussianMeasure hn u hu)

/-- Pullback by a unit global phase on Ginibre `L²`. -/
def ginibreGlobalPhaseL2 {n : ℕ} (hn : 0 < n) (u : ℂ) (hu : ‖u‖ = 1) :
    Lp ℂ 2 (ginibreMeasure n) →ₗᵢ[ℂ] Lp ℂ 2 (ginibreMeasure n) :=
  Lp.compMeasurePreservingₗᵢ ℂ (globalPhase u)
    (measurePreserving_globalPhase_ginibreMeasure hn u hu)

/-- A zero-antiholomorphic Hermite mode is an exact eigenvector of global
phase pullback, with eigenvalue its total holomorphic degree character. -/
theorem gaussianGlobalPhaseL2_hermite_zero (n : ℕ) (hn : 0 < n)
    (u : ℂ) (hu : ‖u‖ = 1) (p : Fin n → ℕ) :
    gaussianGlobalPhaseL2 hn u hu
        (ComplexHermite.hermiteL2Family n hn (p, 0)) =
      u ^ totalHolomorphicDegree p •
        ComplexHermite.hermiteL2Family n hn (p, 0) := by
  apply Lp.ext
  have hsourcecomp :=
    (measurePreserving_globalPhase_complexGaussianMeasure hn u hu).quasiMeasurePreserving.ae_eq_comp
      (ComplexHermite.hermiteL2Family_coeFn n hn (p, 0))
  filter_upwards [Lp.coeFn_compMeasurePreserving
      (ComplexHermite.hermiteL2Family n hn (p, 0))
      (measurePreserving_globalPhase_complexGaussianMeasure hn u hu),
    hsourcecomp,
    ComplexHermite.hermiteL2Family_coeFn n hn (p, 0),
    Lp.coeFn_smul (u ^ totalHolomorphicDegree p)
      (ComplexHermite.hermiteL2Family n hn (p, 0))] with z hcomp hsrc htgt hsmul
  change (gaussianGlobalPhaseL2 hn u hu
      (ComplexHermite.hermiteL2Family n hn (p, 0))) z = _
  rw [show (gaussianGlobalPhaseL2 hn u hu
      (ComplexHermite.hermiteL2Family n hn (p, 0))) z =
      ComplexHermite.hermiteL2Family n hn (p, 0) (globalPhase u z) by
    exact hcomp]
  change ComplexHermite.hermiteL2Family n hn (p, 0) (globalPhase u z) =
    ComplexHermite.multivariateNormalized n hn p 0 (globalPhase u z) at hsrc
  change ComplexHermite.hermiteL2Family n hn (p, 0) z =
    ComplexHermite.multivariateNormalized n hn p 0 z at htgt
  change (u ^ totalHolomorphicDegree p •
      ComplexHermite.hermiteL2Family n hn (p, 0)) z =
    u ^ totalHolomorphicDegree p *
      ComplexHermite.hermiteL2Family n hn (p, 0) z at hsmul
  rw [hsrc, hsmul, htgt, multivariateNormalized_zero_globalPhase]

/-- Algebraic span of zero-antiholomorphic Hermite modes of a fixed total
holomorphic degree. -/
def gaussianHolomorphicDegreeSpan (n : ℕ) (hn : 0 < n) (d : ℕ) :
    Submodule ℂ (Lp ℂ 2 (complexGaussianMeasure n)) :=
  Submodule.span ℂ
    (ComplexHermite.hermiteL2Family n hn ''
      {(p, q) | q = 0 ∧ totalHolomorphicDegree p = d})

/-- Every vector in a fixed homogeneous span has the corresponding exact
phase character. -/
theorem gaussianGlobalPhaseL2_eq_smul_on_degreeSpan
    (n : ℕ) (hn : 0 < n) (d : ℕ) (u : ℂ) (hu : ‖u‖ = 1)
    {x : Lp ℂ 2 (complexGaussianMeasure n)}
    (hx : x ∈ gaussianHolomorphicDegreeSpan n hn d) :
    gaussianGlobalPhaseL2 hn u hu x = u ^ d • x := by
  unfold gaussianHolomorphicDegreeSpan at hx
  refine Submodule.span_induction
    (p := fun x _ ↦ gaussianGlobalPhaseL2 hn u hu x = u ^ d • x)
    ?_ (by simp) ?_ ?_ hx
  · intro x hx
    obtain ⟨⟨p, q⟩, ⟨hq, hp⟩, rfl⟩ := hx
    subst q
    rw [gaussianGlobalPhaseL2_hermite_zero, hp]
  · intro x y hx hy hxi hyi
    rw [map_add, hxi, hyi, smul_add]
  · intro a x hx hxi
    rw [map_smul, hxi]
    simp [smul_smul, mul_comm]

/-- Fixed-degree spans with separated phase characters are orthogonal. -/
theorem inner_eq_zero_of_mem_holomorphicDegreeSpans
    (n : ℕ) (hn : 0 < n) (d e : ℕ) (u : ℂ) (hu : ‖u‖ = 1)
    {x y : Lp ℂ 2 (complexGaussianMeasure n)}
    (hx : x ∈ gaussianHolomorphicDegreeSpan n hn d)
    (hy : y ∈ gaussianHolomorphicDegreeSpan n hn e)
    (hsep : conj (u ^ d) * u ^ e ≠ 1) :
    inner ℂ x y = 0 :=
  inner_eq_zero_of_isometry_eigencharacters
    (gaussianGlobalPhaseL2 hn u hu) x y (u ^ d) (u ^ e)
    (gaussianGlobalPhaseL2_eq_smul_on_degreeSpan n hn d u hu hx)
    (gaussianGlobalPhaseL2_eq_smul_on_degreeSpan n hn e u hu hy) hsep

/-- Two distinct natural exponents are separated by a unit complex phase. -/
theorem exists_unit_phase_pow_ne (d e : ℕ) (hde : d ≠ e) :
    ∃ u : ℂ, ‖u‖ = 1 ∧ u ^ d ≠ u ^ e := by
  let N := max d e + 1
  let u : ℂ := Complex.exp (2 * Real.pi * Complex.I / N)
  have hN : N ≠ 0 := by
    unfold N
    omega
  have hprim : IsPrimitiveRoot u N := by
    exact Complex.isPrimitiveRoot_exp N hN
  refine ⟨u, ?_, ?_⟩
  · unfold u
    rw [Complex.norm_exp]
    simp
  · intro hp
    apply hde
    apply hprim.pow_inj
    · unfold N
      omega
    · unfold N
      omega
    · exact hp

/-- Homogeneous Gaussian holomorphic spans of unequal degrees are
unconditionally orthogonal. -/
theorem inner_eq_zero_of_mem_holomorphicDegreeSpans_of_ne
    (n : ℕ) (hn : 0 < n) {d e : ℕ} (hde : d ≠ e)
    {x y : Lp ℂ 2 (complexGaussianMeasure n)}
    (hx : x ∈ gaussianHolomorphicDegreeSpan n hn d)
    (hy : y ∈ gaussianHolomorphicDegreeSpan n hn e) :
    inner ℂ x y = 0 := by
  obtain ⟨u, hu, hp⟩ := exists_unit_phase_pow_ne d e hde
  apply inner_eq_zero_of_mem_holomorphicDegreeSpans n hn d e u hu hx hy
  intro hchar
  apply hp
  have hnorm : Complex.normSq (u ^ d) = 1 := by
    rw [← Complex.sq_norm, norm_pow, hu]
    norm_num
  calc
    u ^ d = u ^ d * 1 := by ring
    _ = u ^ d * (conj (u ^ d) * u ^ e) := by rw [hchar]
    _ = (u ^ d * conj (u ^ d)) * u ^ e := by ring
    _ = Complex.normSq (u ^ d) * u ^ e := by rw [Complex.mul_conj]
    _ = u ^ e := by simp [hnorm]

/-- Restrict a finite Hermite coefficient vector to zero antiholomorphic
index and a fixed total holomorphic degree. -/
def coefficientsAtHolomorphicDegree {n : ℕ}
    (c : ComplexHermite.HermiteMultiIndex n →₀ ℂ) (d : ℕ) :
    ComplexHermite.HermiteMultiIndex n →₀ ℂ :=
  c.filter fun pq ↦ pq.2 = 0 ∧ totalHolomorphicDegree pq.1 = d

/-- Holomorphic degrees occurring in a finite zero-antiholomorphic
coefficient vector. -/
def activeHolomorphicDegrees {n : ℕ}
    (c : ComplexHermite.HermiteMultiIndex n →₀ ℂ) : Finset ℕ :=
  c.support.image fun pq ↦ totalHolomorphicDegree pq.1

/-- A finite coefficient vector supported at antiholomorphic index zero is
the finite sum of its homogeneous holomorphic-degree pieces. -/
theorem sum_coefficientsAtHolomorphicDegree {n : ℕ}
    (c : ComplexHermite.HermiteMultiIndex n →₀ ℂ)
    (hc : ∀ pq ∈ c.support, pq.2 = 0) :
    ∑ d ∈ activeHolomorphicDegrees c,
        coefficientsAtHolomorphicDegree c d = c := by
  ext pq
  by_cases hpq : pq ∈ c.support
  · have hd : totalHolomorphicDegree pq.1 ∈ activeHolomorphicDegrees c :=
      Finset.mem_image.mpr ⟨pq, hpq, rfl⟩
    change (Finsupp.lapply pq :
      (ComplexHermite.HermiteMultiIndex n →₀ ℂ) →ₗ[ℂ] ℂ)
        (∑ d ∈ activeHolomorphicDegrees c,
          coefficientsAtHolomorphicDegree c d) = c pq
    simp_rw [map_sum, Finsupp.lapply_apply]
    rw [Finset.sum_eq_single
      (totalHolomorphicDegree pq.1)]
    · simp [coefficientsAtHolomorphicDegree, hc pq hpq]
    · intro d hdmem hne
      simp [coefficientsAtHolomorphicDegree, hne.symm]
    · exact fun hnot ↦ (hnot hd).elim
  · have hz : c pq = 0 := by
      simpa [Finsupp.mem_support_iff] using hpq
    change (Finsupp.lapply pq :
      (ComplexHermite.HermiteMultiIndex n →₀ ℂ) →ₗ[ℂ] ℂ)
        (∑ d ∈ activeHolomorphicDegrees c,
          coefficientsAtHolomorphicDegree c d) = c pq
    simp_rw [map_sum, Finsupp.lapply_apply]
    rw [hz]
    apply Finset.sum_eq_zero
    intro d hd
    unfold coefficientsAtHolomorphicDegree
    simp only [Finsupp.filter_apply]
    split <;> simp [hz]

/-- The associated finite Gaussian Hermite vector decomposes into the sum
of its homogeneous holomorphic-degree pieces. -/
theorem finiteHermiteCombination_eq_sum_holomorphicDegrees
    (n : ℕ) (hn : 0 < n)
    (c : ComplexHermite.HermiteMultiIndex n →₀ ℂ)
    (hc : ∀ pq ∈ c.support, pq.2 = 0) :
    ComplexHermite.finiteHermiteCombination n hn c =
      ∑ d ∈ activeHolomorphicDegrees c,
        ComplexHermite.finiteHermiteCombination n hn
          (coefficientsAtHolomorphicDegree c d) := by
  have hcoeff := sum_coefficientsAtHolomorphicDegree c hc
  have h := congrArg (ComplexHermite.finiteHermiteCombination n hn) hcoeff
  simpa [ComplexHermite.finiteHermiteCombination, map_sum] using h.symm

/-- Every homogeneous piece belongs to its corresponding Gaussian
holomorphic-degree span. -/
theorem finiteHermiteCombination_coefficientsAtHolomorphicDegree_mem
    (n : ℕ) (hn : 0 < n)
    (c : ComplexHermite.HermiteMultiIndex n →₀ ℂ) (d : ℕ) :
    ComplexHermite.finiteHermiteCombination n hn
        (coefficientsAtHolomorphicDegree c d) ∈
      gaussianHolomorphicDegreeSpan n hn d := by
  unfold ComplexHermite.finiteHermiteCombination
  rw [Finsupp.linearCombination_apply]
  apply Submodule.sum_mem
  intro pq hpq
  apply Submodule.smul_mem
  apply Submodule.subset_span
  refine ⟨pq, ?_, rfl⟩
  have hnz := Finsupp.mem_support_iff.mp hpq
  unfold coefficientsAtHolomorphicDegree at hnz
  simp only [Finsupp.filter_apply] at hnz
  split at hnz
  · exact ‹pq.2 = 0 ∧ totalHolomorphicDegree pq.1 = d›
  · simp at hnz

/-- The polynomial representing a zero-antiholomorphic Hermite mode is
homogeneous in Mathlib's algebraic grading. -/
theorem isHomogeneous_holomorphicHermitePolynomial (n : ℕ)
    (p : Fin n → ℕ) :
    MvPolynomial.IsHomogeneous (holomorphicHermitePolynomial n p)
      (totalHolomorphicDegree p) := by
  unfold holomorphicHermitePolynomial totalHolomorphicDegree
  apply MvPolynomial.IsHomogeneous.prod Finset.univ _ p
  intro i hi
  exact (MvPolynomial.isHomogeneous_X_pow i (p i)).C_mul _

/-- The polynomial Vandermonde is homogeneous of its number of linear
factors. -/
theorem isHomogeneous_polynomialVandermonde (n : ℕ) :
    MvPolynomial.IsHomogeneous (polynomialVandermonde n)
      (vandermondeDegree n) := by
  rw [← prod_orderedPairFactor n]
  unfold vandermondeDegree
  simpa using MvPolynomial.IsHomogeneous.prod
    (Finset.univ : Finset (OrderedParticlePair n)) orderedPairFactor
    (fun _ ↦ 1) (fun p hp ↦ by
      unfold orderedPairFactor
      exact (MvPolynomial.isHomogeneous_X _ _).sub
        (MvPolynomial.isHomogeneous_X _ _))

/-- A nonzero homogeneous alternating polynomial cannot have degree below
the Vandermonde degree. -/
theorem vandermondeDegree_le_of_homogeneous_alternating {n d : ℕ}
    {P : ConfigurationPolynomial n}
    (hP : MvPolynomial.IsHomogeneous P d)
    (hAlt : IsAlternatingConfigurationPolynomial P) (hP0 : P ≠ 0) :
    vandermondeDegree n ≤ d := by
  obtain ⟨Q, hQ, hfactor⟩ := alternating_polynomial_vandermonde_division hAlt
  have hQ0 : Q ≠ 0 := by
    intro hzero
    rw [hzero, mul_zero] at hfactor
    exact hP0 hfactor
  have hdegP := hP.totalDegree hP0
  have hdegV := (isHomogeneous_polynomialVandermonde n).totalDegree
    (polynomialVandermonde_ne_zero n)
  rw [hfactor, MvPolynomial.totalDegree_mul_of_isDomain
    (polynomialVandermonde_ne_zero n) hQ0, hdegV] at hdegP
  omega

/-- A holomorphic coordinate monomial transforms by its degree character. -/
theorem eval_monomial_globalPhase {n : ℕ} (u : ℂ)
    (p : Fin n → ℕ) (z : Configuration n) :
    (∏ i, (globalPhase u z i) ^ p i) =
      u ^ totalHolomorphicDegree p * ∏ i, z i ^ p i := by
  simp_rw [globalPhase_apply, mul_pow]
  have hu : (∏ i : Fin n, u ^ p i) = u ^ totalHolomorphicDegree p := by
    simpa [totalHolomorphicDegree] using
      (Finset.prod_pow_eq_pow_sum Finset.univ p u)
  rw [Finset.prod_mul_distrib, hu]

/-- Functional homogeneity of a holomorphic configuration polynomial. -/
def IsHomogeneousConfigurationPolynomial {n : ℕ} (d : ℕ)
    (P : ConfigurationPolynomial n) : Prop :=
  ∀ u : ℂ, ∀ z : Configuration n,
    MvPolynomial.eval (globalPhase u z) P =
      u ^ d * MvPolynomial.eval z P

/-- The monomial of multiexponent `p` is homogeneous of total degree `p`. -/
theorem isHomogeneous_monomial {n : ℕ} (p : Fin n → ℕ) :
    IsHomogeneousConfigurationPolynomial (totalHolomorphicDegree p)
      (∏ i, MvPolynomial.X i ^ p i : ConfigurationPolynomial n) := by
  intro u z
  simp only [map_prod, map_pow, MvPolynomial.eval_X]
  exact eval_monomial_globalPhase u p z

/-- Algebraic homogeneity implies the expected functional scaling law. -/
theorem isHomogeneousConfigurationPolynomial_of_isHomogeneous {n d : ℕ}
    {P : ConfigurationPolynomial n} (hP : MvPolynomial.IsHomogeneous P d) :
    IsHomogeneousConfigurationPolynomial d P := by
  intro u z
  rw [← P.support_sum_monomial_coeff]
  simp only [map_sum, MvPolynomial.eval_monomial, globalPhase_apply,
    Finset.prod_mul_distrib, mul_pow]
  rw [Finset.mul_sum]
  apply Finset.sum_congr rfl
  intro m hm
  have hmdeg : m.degree = d := by
    rw [Finsupp.degree_eq_weight_one]
    exact hP (MvPolynomial.mem_support_iff.mp hm)
  simp only [Finsupp.prod, Finset.prod_mul_distrib]
  have hu : (∏ x ∈ m.support, u ^ m x) = u ^ d := by
    rw [Finset.prod_pow_eq_pow_sum, ← Finsupp.degree_apply, hmdeg]
  rw [hu]
  ring

/-- A finite zero-antiholomorphic Hermite polynomial supported in one total
holomorphic degree is homogeneous in that degree. -/
theorem isHomogeneous_finiteZeroAntiholomorphicHermitePolynomial_of_degree
    {n d : ℕ} (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
    (hdegree : ∀ p ∈ S, totalHolomorphicDegree p = d) :
    MvPolynomial.IsHomogeneous
      (finiteZeroAntiholomorphicHermitePolynomial n S c) d := by
  unfold finiteZeroAntiholomorphicHermitePolynomial
  apply MvPolynomial.IsHomogeneous.sum S _ d
  intro p hp
  rw [← hdegree p hp]
  exact (isHomogeneous_holomorphicHermitePolynomial n p).C_mul _

/-- Homogeneous Vandermonde division, including the exact quotient phase
character away from the (irrelevant) collision locus. -/
theorem homogeneous_alternating_polynomial_division {n d : ℕ}
    {P : ConfigurationPolynomial n}
    (hP : MvPolynomial.IsHomogeneous P d)
    (hAlt : IsAlternatingConfigurationPolynomial P) (hP0 : P ≠ 0) :
    ∃ Q : ConfigurationPolynomial n,
      IsSymmetricConfigurationPolynomial Q ∧
      P = polynomialVandermonde n * Q ∧
      vandermondeDegree n ≤ d ∧
      ∀ (u : ℂ), ‖u‖ = 1 → ∀ z : Configuration n,
        vandermonde z ≠ 0 →
        MvPolynomial.eval (globalPhase u z) Q =
          u ^ (d - vandermondeDegree n) * MvPolynomial.eval z Q := by
  obtain ⟨Q, hQ, hfactor⟩ := alternating_polynomial_vandermonde_division hAlt
  have hle := vandermondeDegree_le_of_homogeneous_alternating hP hAlt hP0
  refine ⟨Q, hQ, hfactor, hle, ?_⟩
  intro u hu z hz
  have hu0 : u ≠ 0 := by
    intro h
    simpa [h] using hu
  have hscale :=
    isHomogeneousConfigurationPolynomial_of_isHomogeneous hP u z
  rw [hfactor, map_mul, map_mul, eval_polynomialVandermonde,
    eval_polynomialVandermonde, vandermonde_globalPhase] at hscale
  rw [← vandermondeDegree_eq_sum_Ioi_card] at hscale
  have hpow : u ^ d = u ^ vandermondeDegree n *
      u ^ (d - vandermondeDegree n) := by
    rw [← pow_add, Nat.add_sub_of_le hle]
  rw [hpow] at hscale
  have hs : u ^ vandermondeDegree n *
      (vandermonde z * MvPolynomial.eval (globalPhase u z) Q) =
      u ^ vandermondeDegree n *
        (u ^ (d - vandermondeDegree n) *
          (vandermonde z * MvPolynomial.eval z Q)) := by
    simpa only [mul_assoc] using hscale
  have hscale' := mul_left_cancel₀
    (pow_ne_zero (vandermondeDegree n) hu0) hs
  exact mul_left_cancel₀ hz (by
    simpa only [mul_assoc, mul_left_comm, mul_comm] using hscale')

/-- The preceding division theorem specialized to a finite, single-degree
zero-antiholomorphic Hermite sum. -/
theorem finite_homogeneous_zeroHermite_division {n d : ℕ}
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
    (hdegree : ∀ p ∈ S, totalHolomorphicDegree p = d)
    (hAlt : IsAlternatingConfigurationPolynomial
      (finiteZeroAntiholomorphicHermitePolynomial n S c))
    (hne : finiteZeroAntiholomorphicHermitePolynomial n S c ≠ 0) :
    ∃ Q : ConfigurationPolynomial n,
      IsSymmetricConfigurationPolynomial Q ∧
      finiteZeroAntiholomorphicHermitePolynomial n S c =
        polynomialVandermonde n * Q ∧
      vandermondeDegree n ≤ d ∧
      ∀ (u : ℂ), ‖u‖ = 1 → ∀ z : Configuration n,
        vandermonde z ≠ 0 →
        MvPolynomial.eval (globalPhase u z) Q =
          u ^ (d - vandermondeDegree n) * MvPolynomial.eval z Q :=
  homogeneous_alternating_polynomial_division
    (isHomogeneous_finiteZeroAntiholomorphicHermitePolynomial_of_degree
      S c hdegree) hAlt hne

/-- In the bottom possible alternating degree, the Vandermonde quotient is
constant. -/
theorem quotient_eq_C_of_bottom_homogeneous_degree {n : ℕ}
    {P Q : ConfigurationPolynomial n}
    (hP : MvPolynomial.IsHomogeneous P (vandermondeDegree n))
    (hP0 : P ≠ 0)
    (hfactor : P = polynomialVandermonde n * Q) :
    Q = MvPolynomial.C (MvPolynomial.coeff 0 Q) := by
  have hQ0 : Q ≠ 0 := by
    intro hQ
    rw [hQ, mul_zero] at hfactor
    exact hP0 hfactor
  have hdegP := hP.totalDegree hP0
  have hdegV := (isHomogeneous_polynomialVandermonde n).totalDegree
    (polynomialVandermonde_ne_zero n)
  have hdegmul := MvPolynomial.totalDegree_mul_of_isDomain
    (polynomialVandermonde_ne_zero n) hQ0
  rw [← hfactor, hdegP, hdegV] at hdegmul
  have hQdeg : MvPolynomial.totalDegree Q = 0 := by omega
  exact MvPolynomial.totalDegree_eq_zero_iff_eq_C.mp hQdeg

/-- Product of the one-dimensional normalization constants in a
zero-antiholomorphic tensor Hermite. -/
def holomorphicTensorNormalization (n : ℕ) (p : Fin n → ℕ) : ℂ :=
  ∏ i, (ComplexHermite.oneDimNormalization n (p i) : ℂ)

theorem holomorphicTensorNormalization_ne_zero (n : ℕ) (hn : 0 < n)
    (p : Fin n → ℕ) : holomorphicTensorNormalization n p ≠ 0 := by
  unfold holomorphicTensorNormalization
  apply Finset.prod_ne_zero_iff.mpr
  intro i hi
  exact Complex.ofReal_ne_zero.mpr (by
    unfold ComplexHermite.oneDimNormalization
    positivity)

theorem holomorphicHermitePolynomial_eq_normalization_monomial
    (n : ℕ) (p : Fin n → ℕ) :
    holomorphicHermitePolynomial n p =
      MvPolynomial.C (holomorphicTensorNormalization n p) *
        MvPolynomial.monomial
          (Finsupp.equivFunOnFinite.symm p) 1 := by
  unfold holomorphicHermitePolynomial holomorphicTensorNormalization
  rw [← MvPolynomial.prod_X_pow_eq_monomial]
  simp only [map_prod, Finset.prod_mul_distrib]
  rw [show (∏ i : Fin n, MvPolynomial.X i ^ p i) =
      ∏ i ∈ (Finsupp.equivFunOnFinite.symm p).support,
        MvPolynomial.X i ^ (Finsupp.equivFunOnFinite.symm p) i by
    symm
    apply Finset.prod_subset (by simp)
    intro i hi hi'
    have hp0 : p i = 0 := by
      simpa [Finsupp.equivFunOnFinite] using hi'
    simp [hp0]]

/-- Explicit inversion of the normalization on a holomorphic monomial. -/
theorem C_mul_monomial_eq_smul_holomorphicHermitePolynomial
    (n : ℕ) (hn : 0 < n) (p : Fin n → ℕ) (a : ℂ) :
    MvPolynomial.C a *
        MvPolynomial.monomial (Finsupp.equivFunOnFinite.symm p) 1 =
      MvPolynomial.C (a / holomorphicTensorNormalization n p) *
        holomorphicHermitePolynomial n p := by
  rw [holomorphicHermitePolynomial_eq_normalization_monomial]
  have hN := holomorphicTensorNormalization_ne_zero n hn p
  rw [← mul_assoc, ← map_mul]
  field_simp

/-- Hermite coefficient obtained by dividing a polynomial monomial
coefficient by its nonzero tensor normalization. -/
def holomorphicHermiteCoefficient {n : ℕ} (P : ConfigurationPolynomial n)
    (p : Fin n → ℕ) : ℂ :=
  MvPolynomial.coeff (Finsupp.equivFunOnFinite.symm p) P /
    holomorphicTensorNormalization n p

/-- The finite support of a configuration polynomial, viewed as ordinary
multi-index functions. -/
def holomorphicHermiteSupport {n : ℕ} (P : ConfigurationPolynomial n) :
    Finset (Fin n → ℕ) :=
  P.support.image Finsupp.equivFunOnFinite

/-- Every configuration polynomial is exactly its coefficientwise finite
zero-antiholomorphic Hermite expansion. -/
theorem finiteZeroAntiholomorphicHermitePolynomial_support_expansion
    {n : ℕ} (hn : 0 < n) (P : ConfigurationPolynomial n) :
    finiteZeroAntiholomorphicHermitePolynomial n
        (holomorphicHermiteSupport P) (holomorphicHermiteCoefficient P) = P := by
  unfold finiteZeroAntiholomorphicHermitePolynomial holomorphicHermiteSupport
    holomorphicHermiteCoefficient
  rw [Finset.sum_image]
  · calc
      _ = ∑ m ∈ P.support, MvPolynomial.monomial m
          (MvPolynomial.coeff m P) := by
        apply Finset.sum_congr rfl
        intro m hm
        rw [Finsupp.equivFunOnFinite.symm_apply_apply]
        rw [← C_mul_monomial_eq_smul_holomorphicHermitePolynomial n hn]
        simp [MvPolynomial.monomial_eq]
      _ = P := P.support_sum_monomial_coeff
  · intro a ha b hb hab
    exact Finsupp.equivFunOnFinite.injective hab

/-- The explicit support expansion preserves a polynomial's homogeneous
degree coefficient by coefficient. -/
theorem totalHolomorphicDegree_eq_of_mem_holomorphicHermiteSupport
    {n d : ℕ} {P : ConfigurationPolynomial n}
    (hP : MvPolynomial.IsHomogeneous P d)
    {p : Fin n → ℕ} (hp : p ∈ holomorphicHermiteSupport P) :
    totalHolomorphicDegree p = d := by
  rcases Finset.mem_image.mp hp with ⟨m, hm, rfl⟩
  unfold totalHolomorphicDegree
  have hmdeg : m.degree = d := by
    rw [Finsupp.degree_eq_weight_one]
    exact hP (MvPolynomial.mem_support_iff.mp hm)
  simpa [Finsupp.degree_eq_sum] using hmdeg

/-- Consequently every homogeneous polynomial has an exact finite Hermite
expansion supported in that same degree. -/
theorem homogeneous_polynomial_finiteHermite_expansion {n d : ℕ}
    (hn : 0 < n) {P : ConfigurationPolynomial n}
    (hP : MvPolynomial.IsHomogeneous P d) :
    (∀ p ∈ holomorphicHermiteSupport P,
      totalHolomorphicDegree p = d) ∧
    finiteZeroAntiholomorphicHermitePolynomial n
      (holomorphicHermiteSupport P) (holomorphicHermiteCoefficient P) = P := by
  exact ⟨fun _ hp ↦
    totalHolomorphicDegree_eq_of_mem_holomorphicHermiteSupport hP hp,
    finiteZeroAntiholomorphicHermitePolynomial_support_expansion hn P⟩

/-- Alternation is preserved by taking a homogeneous component. -/
theorem isAlternating_homogeneousComponent {n d : ℕ}
    {P : ConfigurationPolynomial n}
    (hP : IsAlternatingConfigurationPolynomial P) :
    IsAlternatingConfigurationPolynomial (MvPolynomial.homogeneousComponent d P) := by
  intro σ
  have h := congrArg (MvPolynomial.homogeneousComponent d) (hP σ)
  unfold permuteConfigurationPolynomial at h ⊢
  change MvPolynomial.homogeneousComponent d (MvPolynomial.rename σ P) = _ at h
  change MvPolynomial.rename σ (MvPolynomial.homogeneousComponent d P) = _
  rw [← MvPolynomial.rename_homogeneousComponent,
    MvPolynomial.homogeneousComponent_C_mul] at h
  exact h

/-- The finite Gaussian `L²` vector represented by a holomorphic Hermite
sum. -/
def finiteZeroHermiteL2 (n : ℕ) (hn : 0 < n)
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ) :
    Lp ℂ 2 (complexGaussianMeasure n) :=
  ∑ p ∈ S, c p • ComplexHermite.hermiteL2Family n hn (p, 0)

theorem finiteZeroHermiteL2_coeFn (n : ℕ) (hn : 0 < n)
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ) :
    finiteZeroHermiteL2 n hn S c =ᵐ[complexGaussianMeasure n]
      finiteZeroAntiholomorphicHermiteSum n hn S c := by
  unfold finiteZeroHermiteL2 finiteZeroAntiholomorphicHermiteSum
  induction S using Finset.induction_on with
  | empty =>
      filter_upwards [Lp.coeFn_zero ℂ 2 (complexGaussianMeasure n)] with z hz
      change (0 : Lp ℂ 2 (complexGaussianMeasure n)) z = 0
      rw [hz]
      exact Pi.zero_apply z
  | @insert p S hp ih =>
      filter_upwards [Lp.coeFn_add
          (c p • ComplexHermite.hermiteL2Family n hn (p, 0))
          (∑ q ∈ S, c q • ComplexHermite.hermiteL2Family n hn (q, 0)),
        Lp.coeFn_smul (c p) (ComplexHermite.hermiteL2Family n hn (p, 0)),
        ComplexHermite.hermiteL2Family_coeFn n hn (p, 0), ih] with
          z hadd hsmul hmode hsum
      simp only [Finset.sum_insert hp]
      rw [hadd]
      simp only [Pi.add_apply]
      rw [hsmul]
      simp only [Pi.smul_apply, smul_eq_mul]
      rw [hmode, hsum]

theorem finiteZeroHermiteL2_mem_gaussianAlternating {n : ℕ} (hn : 0 < n)
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
    (hAlt : IsAlternatingConfigurationPolynomial
      (finiteZeroAntiholomorphicHermitePolynomial n S c)) :
    finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n := by
  intro σ
  apply Lp.ext
  have hfun := (finiteHermiteSum_isAlternating_iff hn S c).2 hAlt σ
  have hcoe := finiteZeroHermiteL2_coeFn n hn S c
  have hcoecomp := (gaussian_measurePreserving_permute σ).quasiMeasurePreserving.ae_eq_comp hcoe
  filter_upwards [Lp.coeFn_compMeasurePreserving (finiteZeroHermiteL2 n hn S c)
      (gaussian_measurePreserving_permute σ), hcoecomp, hcoe,
    Lp.coeFn_smul (permutationSign σ) (finiteZeroHermiteL2 n hn S c)] with
      z hperm hsrc htgt hsmul
  rw [show (gaussianPermutationL2 σ (finiteZeroHermiteL2 n hn S c)) z =
    finiteZeroHermiteL2 n hn S c (permute σ z) by exact hperm]
  rw [show (permutationSign σ • finiteZeroHermiteL2 n hn S c) z =
    permutationSign σ • finiteZeroHermiteL2 n hn S c z by exact hsmul]
  change finiteZeroHermiteL2 n hn S c (permute σ z) =
    permutationSign σ * finiteZeroHermiteL2 n hn S c z
  change finiteZeroHermiteL2 n hn S c (permute σ z) =
    _ at hsrc
  rw [hsrc, htgt]
  exact hfun z

/-- Public representative formula for inverse Vandermonde multiplication. -/
theorem inverseVandermondeL2_coeFn_public {n : ℕ} (hn : 0 < n)
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    inverseVandermondeL2 n hn v =ᵐ[ginibreMeasure n]
      inverseVandermondeFunction n v := by
  unfold inverseVandermondeL2
  dsimp only
  generalize_proofs h1 h2 h3 h4 h5
  exact (h5 v).coeFn_toLp

/-- The symmetric Ginibre quotient vector attached to an alternating finite
holomorphic Hermite sum. -/
def finiteHomogeneousQuotientL2 {n : ℕ} (hn : 0 < n)
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
    (hAlt : finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n) :
    ginibreSymmetricL2 n :=
  (vandermondeSymmetricAlternatingEquiv n hn).symm
    ⟨finiteZeroHermiteL2 n hn S c, hAlt⟩

theorem finiteHomogeneousQuotientL2_coeFn {n : ℕ} (hn : 0 < n)
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
    (hAlt : finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n)
    (Q : ConfigurationPolynomial n)
    (hsum : ∀ z, finiteZeroAntiholomorphicHermiteSum n hn S c z =
      vandermonde z * MvPolynomial.eval z Q) :
    (finiteHomogeneousQuotientL2 hn S c hAlt).1 =ᵐ[ginibreMeasure n]
      fun z ↦ (groundStateNormalization n : ℂ) * MvPolynomial.eval z Q := by
  have hcoe := inverseVandermondeL2_coeFn_public hn
    (finiteZeroHermiteL2 n hn S c)
  have hfinite := (ginibreMeasure_absolutelyContinuous_complexGaussianMeasure n).ae_eq
    (finiteZeroHermiteL2_coeFn n hn S c)
  have hcoll : ginibreMeasure n (collisionSet n) = 0 :=
    (ginibreMeasure_absolutelyContinuous_complexGaussianMeasure n)
      (complexGaussianMeasure_collisionSet n)
  have hout : ∀ᵐ z ∂ginibreMeasure n, z ∉ collisionSet n := by
    rw [ae_iff]
    rw [show {z : Configuration n | ¬ z ∉ collisionSet n} = collisionSet n by
      ext z
      simp]
    exact hcoll
  change inverseVandermondeL2 n hn (finiteZeroHermiteL2 n hn S c) =ᵐ[_] _
  filter_upwards [hcoe, hfinite, hout] with z hin hfin hz
  rw [hin]
  unfold inverseVandermondeFunction inverseVandermondeMultiplier
  rw [hfin, hsum z]
  have hv : vandermonde z ≠ 0 :=
    fun h ↦ hz ((vandermonde_eq_zero_iff z).mp h)
  field_simp

theorem ginibreGlobalPhaseL2_finiteHomogeneousQuotient {n d : ℕ}
    (hn : 0 < n) (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
    (hAlt : finiteZeroHermiteL2 n hn S c ∈ gaussianAlternatingL2 n)
    (Q : ConfigurationPolynomial n)
    (hsum : ∀ z, finiteZeroAntiholomorphicHermiteSum n hn S c z =
      vandermonde z * MvPolynomial.eval z Q)
    (hphase : ∀ (u : ℂ), ‖u‖ = 1 → ∀ z, vandermonde z ≠ 0 →
      MvPolynomial.eval (globalPhase u z) Q =
        u ^ d * MvPolynomial.eval z Q)
    (u : ℂ) (hu : ‖u‖ = 1) :
    ginibreGlobalPhaseL2 hn u hu
        (finiteHomogeneousQuotientL2 hn S c hAlt).1 =
      u ^ d • (finiteHomogeneousQuotientL2 hn S c hAlt).1 := by
  let q := finiteHomogeneousQuotientL2 hn S c hAlt
  change ginibreGlobalPhaseL2 hn u hu q.1 = u ^ d • q.1
  apply Lp.ext
  have hq := finiteHomogeneousQuotientL2_coeFn hn S c hAlt Q hsum
  change q.1 =ᵐ[ginibreMeasure n]
    (fun z ↦ (groundStateNormalization n : ℂ) * MvPolynomial.eval z Q) at hq
  have hqcomp :=
    (measurePreserving_globalPhase_ginibreMeasure hn u hu).quasiMeasurePreserving.ae_eq_comp hq
  have hcoll : ginibreMeasure n (collisionSet n) = 0 :=
    (ginibreMeasure_absolutelyContinuous_complexGaussianMeasure n)
      (complexGaussianMeasure_collisionSet n)
  have hout : ∀ᵐ z ∂ginibreMeasure n, z ∉ collisionSet n := by
    rw [ae_iff]
    rw [show {z : Configuration n | ¬ z ∉ collisionSet n} = collisionSet n by
      ext z
      simp]
    exact hcoll
  filter_upwards [Lp.coeFn_compMeasurePreserving q.1
      (measurePreserving_globalPhase_ginibreMeasure hn u hu),
    hqcomp, hq, Lp.coeFn_smul (u ^ d) q.1, hout] with
      z hcomp hsrc htgt hsmul hz
  rw [show (ginibreGlobalPhaseL2 hn u hu q.1) z =
      q.1 (globalPhase u z) by exact hcomp]
  rw [show (u ^ d • q.1) z = u ^ d • q.1 z by exact hsmul]
  change q.1 (globalPhase u z) =
    (groundStateNormalization n : ℂ) *
      MvPolynomial.eval (globalPhase u z) Q at hsrc
  rw [hsrc]
  simp only [Pi.smul_apply, smul_eq_mul]
  rw [htgt, hphase u hu z (fun hv ↦ hz ((vandermonde_eq_zero_iff z).mp hv))]
  ring

/-- Ginibre vectors carrying unequal global-phase degrees are orthogonal. -/
theorem inner_eq_zero_of_ginibre_phase_degrees_ne {n d e : ℕ}
    (hn : 0 < n) (hde : d ≠ e)
    (x y : Lp ℂ 2 (ginibreMeasure n))
    (hx : ∀ (u : ℂ) (hu : ‖u‖ = 1),
      ginibreGlobalPhaseL2 hn u hu x = u ^ d • x)
    (hy : ∀ (u : ℂ) (hu : ‖u‖ = 1),
      ginibreGlobalPhaseL2 hn u hu y = u ^ e • y) :
    inner ℂ x y = 0 := by
  obtain ⟨u, hu, hpow⟩ := exists_unit_phase_pow_ne d e hde
  have hchar : conj (u ^ d) * u ^ e ≠ 1 := by
    intro h
    apply hpow
    calc
      u ^ d = u ^ d * 1 := by ring
      _ = u ^ d * (conj (u ^ d) * u ^ e) := by rw [h]
      _ = (u ^ d * conj (u ^ d)) * u ^ e := by ring
      _ = u ^ e := by
        rw [Complex.mul_conj]
        have hud : ‖u ^ d‖ = 1 := by simp [norm_pow, hu]
        rw [← Complex.sq_norm, hud]
        norm_num
  exact inner_eq_zero_of_isometry_eigencharacters
    (ginibreGlobalPhaseL2 hn u hu) x y (u ^ d) (u ^ e)
      (hx u hu) (hy u hu) hchar

end
end GinibrePoincare
Analysis GinibrePoincare/Analysis/GroundStateDbar.lean #
import GinibrePoincare.Analysis.GinibreMassFiniteness
import GinibrePoincare.Concrete.AnalyticStatements
import Mathlib.Analysis.Calculus.FDeriv.Mul
import Mathlib.Analysis.Calculus.FDeriv.RestrictScalars

/-! # The Vandermonde ground-state transform and `∂̄` -/

open MeasureTheory
open scoped BigOperators ComplexConjugate ContDiff

namespace GinibrePoincare

noncomputable section

/-- The Vandermonde polynomial is holomorphic on configuration space. -/
theorem differentiable_vandermonde (n : ℕ) :
    Differentiable ℂ (fun z : Configuration n ↦ vandermonde z) := by
  rw [show (fun z : Configuration n ↦ vandermonde z) =
      fun z ↦ ∏ i : Fin n, ∏ j ∈ Finset.Ioi i, (z j - z i) by
    funext z
    rw [vandermonde_eq_product]]
  fun_prop

/-- A complex-differentiable function has vanishing coordinate `∂̄`. -/
theorem dbarComponent_eq_zero_of_differentiable_complex {n : ℕ}
    {g : Configuration n → ℂ} (hg : Differentiable ℂ g)
    (k : Fin n) (z : Configuration n) :
    dbarComponent g k z = 0 := by
  rw [dbarComponent, (hg z).fderiv_restrictScalars ℝ]
  have hi : imaginaryCoordinateDirection k =
      Complex.I • realCoordinateDirection k := by
    ext j
    by_cases hj : j = k <;>
      simp [realCoordinateDirection, imaginaryCoordinateDirection,
        coordinateDirection, hj]
  change (1 / 2 : ℂ) *
    ((fderiv ℂ g z) (realCoordinateDirection k) +
      Complex.I * (fderiv ℂ g z) (imaginaryCoordinateDirection k)) = 0
  rw [hi, (fderiv ℂ g z).map_smul]
  have hI (x : ℂ) : Complex.I * (Complex.I * x) = -x := by
    rw [← mul_assoc, Complex.I_mul_I]
    simp
  change (1 / 2 : ℂ) *
    ((fderiv ℂ g z) (realCoordinateDirection k) +
      Complex.I * (Complex.I *
        (fderiv ℂ g z) (realCoordinateDirection k))) = 0
  rw [hI]
  ring

/-- Every coordinate `∂̄` derivative of the Vandermonde vanishes. -/
@[simp] theorem dbarComponent_vandermonde {n : ℕ}
    (k : Fin n) (z : Configuration n) :
    dbarComponent (fun w : Configuration n ↦ vandermonde w) k z = 0 :=
  dbarComponent_eq_zero_of_differentiable_complex
    (differentiable_vandermonde n) k z

/-- Product rule for the concrete coordinate `∂̄` operator. -/
theorem dbarComponent_mul {n : ℕ} {f g : Configuration n → ℂ}
    (hf : Differentiable ℝ f) (hg : Differentiable ℝ g)
    (k : Fin n) (z : Configuration n) :
    dbarComponent (fun w ↦ f w * g w) k z =
      dbarComponent f k z * g z + f z * dbarComponent g k z := by
  change dbarComponent (f * g) k z = _
  rw [dbarComponent, dbarComponent, dbarComponent,
    fderiv_mul (hf z) (hg z)]
  simp only [add_apply, smul_apply, smul_eq_mul]
  ring

/-- Multiplication by a holomorphic factor commutes with `∂̄`. -/
theorem dbarComponent_holomorphic_mul {n : ℕ}
    {h g : Configuration n → ℂ} (hh : Differentiable ℂ h)
    (hg : Differentiable ℝ g) (k : Fin n) (z : Configuration n) :
    dbarComponent (fun w ↦ h w * g w) k z =
      h z * dbarComponent g k z := by
  rw [dbarComponent_mul (hh.restrictScalars ℝ) hg,
    dbarComponent_eq_zero_of_differentiable_complex hh]
  simp

/-- Exact product rule for the normalized Vandermonde transform. -/
theorem dbarComponent_normalizedVandermondeTransform {n : ℕ}
    {g : Configuration n → ℂ} (hg : Differentiable ℝ g)
    (k : Fin n) (z : Configuration n) :
    dbarComponent (normalizedVandermondeTransform n g) k z =
      ((groundStateNormalization n : ℂ)⁻¹ * vandermonde z) *
        dbarComponent g k z := by
  rw [show normalizedVandermondeTransform n g = fun w ↦
      (((groundStateNormalization n : ℂ)⁻¹ * vandermonde w) * g w) by
    funext w
    exact normalizedVandermondeTransform_apply n g w]
  apply dbarComponent_holomorphic_mul
  · exact (differentiable_const (c := (groundStateNormalization n : ℂ)⁻¹)).mul
      (differentiable_vandermonde n)
  · exact hg

/-- Pointwise squared `∂̄` norm under the normalized ground-state transform. -/
theorem dbarNormSq_normalizedVandermondeTransform {n : ℕ}
    {g : Configuration n → ℂ} (hg : Differentiable ℝ g)
    (z : Configuration n) :
    dbarNormSq (normalizedVandermondeTransform n g) z =
      Complex.normSq ((groundStateNormalization n : ℂ)⁻¹) *
        vandermondeWeight z * dbarNormSq g z := by
  unfold dbarNormSq
  simp_rw [dbarComponent_normalizedVandermondeTransform hg,
    Complex.normSq_mul]
  unfold vandermondeWeight
  rw [Finset.mul_sum]

/-- The squared normalization multiplier is the reciprocal of the actual
Vandermonde mass. -/
theorem normSq_groundStateNormalization_inv (n : ℕ) :
    Complex.normSq ((groundStateNormalization n : ℂ)⁻¹) =
      (ginibreNormalizingMass n).toReal⁻¹ := by
  rw [Complex.normSq_inv, Complex.normSq_ofReal]
  rw [← pow_two]
  unfold groundStateNormalization
  rw [Real.sq_sqrt ENNReal.toReal_nonneg]

/-- Pointwise ground-state scaling, expressed using the normalizing mass. -/
theorem dbarNormSq_normalizedVandermondeTransform_mass {n : ℕ}
    {g : Configuration n → ℂ} (hg : Differentiable ℝ g)
    (z : Configuration n) :
    dbarNormSq (normalizedVandermondeTransform n g) z =
      (ginibreNormalizingMass n).toReal⁻¹ * vandermondeWeight z *
        dbarNormSq g z := by
  rw [dbarNormSq_normalizedVandermondeTransform hg,
    normSq_groundStateNormalization_inv n]

/-- Coordinate formula for `∂̄` of a complexified real function. -/
theorem dbarComponent_ofReal {n : ℕ} {f : Configuration n → ℝ}
    (hf : Differentiable ℝ f) (k : Fin n) (z : Configuration n) :
    dbarComponent (fun w ↦ (f w : ℂ)) k z =
      (1 / 2 : ℂ) *
        (((fderiv ℝ f z (realCoordinateDirection k) : ℝ) : ℂ) +
          Complex.I *
            ((fderiv ℝ f z (imaginaryCoordinateDirection k) : ℝ) : ℂ)) := by
  unfold dbarComponent
  rw [show (fun w ↦ (f w : ℂ)) = Complex.ofRealCLM ∘ f by rfl,
    fderiv_comp z Complex.ofRealCLM.differentiableAt (hf z),
    Complex.ofRealCLM.fderiv]
  rfl

/-- Squared coordinate `∂̄` norm of a complexified real function. -/
theorem normSq_dbarComponent_ofReal {n : ℕ} {f : Configuration n → ℝ}
    (hf : Differentiable ℝ f) (k : Fin n) (z : Configuration n) :
    Complex.normSq (dbarComponent (fun w ↦ (f w : ℂ)) k z) =
      (1 / 4 : ℝ) *
        ((fderiv ℝ f z (realCoordinateDirection k)) ^ 2 +
          (fderiv ℝ f z (imaginaryCoordinateDirection k)) ^ 2) := by
  rw [dbarComponent_ofReal hf]
  simp only [Complex.normSq_apply, Complex.mul_re, Complex.mul_im,
    Complex.add_re, Complex.add_im, Complex.ofReal_re, Complex.ofReal_im,
    Complex.I_re, Complex.I_im]
  norm_num
  ring

/-- Sum-of-coordinate-squares formula for the `∂̄` norm of a complexified
real function. -/
theorem dbarNormSq_ofReal {n : ℕ} {f : Configuration n → ℝ}
    (hf : Differentiable ℝ f) (z : Configuration n) :
    dbarNormSq (fun w ↦ (f w : ℂ)) z =
      (1 / 4 : ℝ) * ∑ k : Fin n,
        ((fderiv ℝ f z (realCoordinateDirection k)) ^ 2 +
          (fderiv ℝ f z (imaginaryCoordinateDirection k)) ^ 2) := by
  unfold dbarNormSq
  simp_rw [normSq_dbarComponent_ofReal hf]
  rw [Finset.mul_sum]

/-- In the concrete Euclidean-coordinate definition, complexification turns
the real gradient square into four times the `∂̄` square. -/
theorem dbarNormSq_ofReal_eq_realGradientNormSq {n : ℕ}
    {f : Configuration n → ℝ} (hf : Differentiable ℝ f)
    (z : Configuration n) :
    dbarNormSq (fun w ↦ (f w : ℂ)) z =
      (1 / 4 : ℝ) * realGradientNormSq f z := by
  rw [dbarNormSq_ofReal hf]
  rfl

/-- Integration against the normalized Ginibre measure is normalized
Vandermonde-weighted Gaussian integration. -/
theorem integral_ginibreMeasure (n : ℕ) (h : Configuration n → ℝ) :
    ∫ z, h z ∂ginibreMeasure n =
      (ginibreNormalizingMass n).toReal⁻¹ *
        ∫ z, vandermondeWeight z * h z ∂complexGaussianMeasure n := by
  unfold ginibreMeasure rawGinibreMeasure
  rw [integral_smul_measure, ENNReal.toReal_inv]
  rw [integral_withDensity_eq_integral_toReal_smul
    measurable_vandermondeDensity
    (ae_of_all _ fun z ↦ ENNReal.ofReal_lt_top)]
  simp_rw [vandermondeDensity,
    ENNReal.toReal_ofReal (vandermondeWeight_nonneg _), smul_eq_mul]

/-- Centering does not change the real Fréchet derivative. -/
theorem fderiv_centeredObservable {n : ℕ} {f : Configuration n → ℝ}
    (hf : Differentiable ℝ f) (z : Configuration n) :
    fderiv ℝ (centeredObservable n f) z = fderiv ℝ f z := by
  unfold centeredObservable
  change fderiv ℝ (f - fun _ ↦ smoothGinibreMean n f) z = _
  rw [fderiv_sub (hf z) (differentiableAt_const _)]
  simp

/-- Centering does not change the pointwise gradient square. -/
theorem realGradientNormSq_centeredObservable {n : ℕ}
    {f : Configuration n → ℝ} (hf : Differentiable ℝ f)
    (z : Configuration n) :
    realGradientNormSq (centeredObservable n f) z =
      realGradientNormSq f z := by
  unfold realGradientNormSq
  rw [fderiv_centeredObservable hf]

/-- Fully expanded pointwise ground-state identity for a real observable. -/
theorem dbarNormSq_normalizedVandermondeTransform_ofReal {n : ℕ}
    {f : Configuration n → ℝ} (hf : Differentiable ℝ f)
    (z : Configuration n) :
    dbarNormSq
        (normalizedVandermondeTransform n (fun w ↦ (f w : ℂ))) z =
      (ginibreNormalizingMass n).toReal⁻¹ * vandermondeWeight z *
        ((1 / 4 : ℝ) * ∑ k : Fin n,
          ((fderiv ℝ f z (realCoordinateDirection k)) ^ 2 +
            (fderiv ℝ f z (imaginaryCoordinateDirection k)) ^ 2)) := by
  have hfc : Differentiable ℝ (fun w ↦ (f w : ℂ)) := by
    fun_prop
  rw [dbarNormSq_normalizedVandermondeTransform_mass hfc,
    dbarNormSq_ofReal hf]

/-- Pointwise ground-state identity specialized to a centered smooth real
observable. -/
theorem dbarNormSq_normalized_centeredObservable {n : ℕ}
    {f : Configuration n → ℝ} (hf : Differentiable ℝ f)
    (z : Configuration n) :
    dbarNormSq
        (normalizedVandermondeTransform n
          (fun w ↦ (centeredObservable n f w : ℂ))) z =
      (ginibreNormalizingMass n).toReal⁻¹ * vandermondeWeight z *
        ((1 / 4 : ℝ) * realGradientNormSq f z) := by
  have hc : Differentiable ℝ (centeredObservable n f) := by
    unfold centeredObservable
    fun_prop
  rw [dbarNormSq_normalizedVandermondeTransform_ofReal hc]
  rw [fderiv_centeredObservable hf]
  rfl

/-- Exact Dirichlet-form identity under the normalized Vandermonde
ground-state transform. -/
theorem groundStateEnergyIdentity : GroundStateEnergyIdentityStatement := by
  intro n hn hprob f hf
  have hdiff : Differentiable ℝ f := hf.1.differentiable (by simp)
  unfold smoothGinibreEnergy gaussianDbarEnergy
  rw [integral_ginibreMeasure]
  have hint :
      (∫ z,
          dbarNormSq
            (normalizedVandermondeTransform n
              (fun w ↦ (centeredObservable n f w : ℂ))) z
          ∂complexGaussianMeasure n) =
        (ginibreNormalizingMass n).toReal⁻¹ * (1 / 4 : ℝ) *
          ∫ z, vandermondeWeight z * realGradientNormSq f z
            ∂complexGaussianMeasure n := by
    calc
      _ = ∫ z,
          (ginibreNormalizingMass n).toReal⁻¹ *
            ((1 / 4 : ℝ) *
              (vandermondeWeight z * realGradientNormSq f z))
          ∂complexGaussianMeasure n := by
            apply integral_congr_ae
            filter_upwards with z
            rw [dbarNormSq_normalized_centeredObservable hdiff]
            ring
      _ = _ := by
        rw [integral_const_mul, integral_const_mul]
        ring
  rw [hint]
  ring

/-- A compactly supported continuous factor remains integrable after
multiplication by the Vandermonde weight. -/
theorem integrable_vandermondeWeight_mul_of_compactSupport {n : ℕ}
    {h : Configuration n → ℝ} (hh : Continuous h)
    (hcompact : HasCompactSupport h) :
    Integrable (fun z ↦ vandermondeWeight z * h z)
      (complexGaussianMeasure n) := by
  apply Continuous.integrable_of_hasCompactSupport
  · exact (Complex.continuous_normSq.comp continuous_vandermonde).mul hh
  · change HasCompactSupport
      ((vandermondeWeight : Configuration n → ℝ) * h)
    exact hcompact.mul_left

/-- A centered compactly supported smooth observable has an integrable
Vandermonde-weighted square. -/
theorem integrable_vandermondeWeight_mul_centered_sq {n : ℕ}
    {f : Configuration n → ℝ} (hf : Continuous f)
    (hcompact : HasCompactSupport f) :
    Integrable
      (fun z ↦ vandermondeWeight z * (centeredObservable n f z) ^ 2)
      (complexGaussianMeasure n) := by
  have hf1 : Integrable (fun z ↦ vandermondeWeight z * f z)
      (complexGaussianMeasure n) :=
    integrable_vandermondeWeight_mul_of_compactSupport hf hcompact
  have hf2 : Integrable (fun z ↦ vandermondeWeight z * f z ^ 2)
    (complexGaussianMeasure n) :=
    integrable_vandermondeWeight_mul_of_compactSupport
      (hf.pow 2) (by
        apply hcompact.mono
        intro z hz
        simp only [Function.mem_support, ne_eq] at hz ⊢
        intro hzero
        apply hz
        simp [hzero])
  have hv := integrable_vandermondeWeight_complexGaussianMeasure n
  have hmid := hf1.const_mul (2 * smoothGinibreMean n f)
  have hlast := hv.const_mul ((smoothGinibreMean n f) ^ 2)
  have hcomb := (hf2.sub hmid).add hlast
  apply hcomb.congr
  filter_upwards with z
  unfold centeredObservable
  change vandermondeWeight z * f z ^ 2 -
      2 * smoothGinibreMean n f * (vandermondeWeight z * f z) +
        smoothGinibreMean n f ^ 2 * vandermondeWeight z =
    vandermondeWeight z * (f z - smoothGinibreMean n f) ^ 2
  ring

/-- The normalized transform has the expected pointwise squared modulus. -/
theorem normSq_normalizedVandermondeTransform {n : ℕ}
    (g : Configuration n → ℂ) (z : Configuration n) :
    Complex.normSq (normalizedVandermondeTransform n g z) =
      (ginibreNormalizingMass n).toReal⁻¹ * vandermondeWeight z *
        Complex.normSq (g z) := by
  rw [normalizedVandermondeTransform_apply, Complex.normSq_mul,
    Complex.normSq_mul, normSq_groundStateNormalization_inv]
  unfold vandermondeWeight
  ring

/-- The Vandermonde polynomial is real-smooth to every order. -/
theorem contDiff_vandermonde (n : ℕ) :
    ContDiff ℝ ∞ (fun z : Configuration n ↦ vandermonde z) := by
  rw [show (fun z : Configuration n ↦ vandermonde z) =
      fun z ↦ ∏ i : Fin n, ∏ j ∈ Finset.Ioi i, (z j - z i) by
    funext z
    rw [vandermonde_eq_product]]
  fun_prop

/-- The normalized transform of a centered smooth function remains smooth. -/
theorem contDiff_normalizedVandermonde_centered {n : ℕ}
    {f : Configuration n → ℝ} (hf : ContDiff ℝ ∞ f) :
    ContDiff ℝ ∞
      (normalizedVandermondeTransform n
        (fun z ↦ (centeredObservable n f z : ℂ))) := by
  rw [show normalizedVandermondeTransform n
      (fun z ↦ (centeredObservable n f z : ℂ)) = fun z ↦
        ((groundStateNormalization n : ℂ)⁻¹ * vandermonde z) *
          (centeredObservable n f z : ℂ) by
    funext z
    exact normalizedVandermondeTransform_apply n _ z]
  unfold centeredObservable
  have hc : ContDiff ℝ ∞ (fun z ↦ f z - smoothGinibreMean n f) :=
    hf.sub contDiff_const
  exact (contDiff_const.mul (contDiff_vandermonde n)).mul
    (Complex.ofRealCLM.contDiff.comp hc)

theorem contDiff_normalizedVandermonde_ofReal {n : ℕ}
    {f : Configuration n → ℝ} (hf : ContDiff ℝ ∞ f) :
    ContDiff ℝ ∞
      (normalizedVandermondeTransform n (fun z ↦ (f z : ℂ))) := by
  rw [show normalizedVandermondeTransform n (fun z ↦ (f z : ℂ)) = fun z ↦
      ((groundStateNormalization n : ℂ)⁻¹ * vandermonde z) * (f z : ℂ) by
    funext z
    exact normalizedVandermondeTransform_apply n _ z]
  exact (contDiff_const.mul (contDiff_vandermonde n)).mul
    (Complex.ofRealCLM.contDiff.comp hf)

theorem hasCompactSupport_normalizedVandermonde_ofReal {n : ℕ}
    {f : Configuration n → ℝ} (hf : HasCompactSupport f) :
    HasCompactSupport
      (normalizedVandermondeTransform n (fun z ↦ (f z : ℂ))) := by
  rw [show normalizedVandermondeTransform n (fun z ↦ (f z : ℂ)) = fun z ↦
      ((groundStateNormalization n : ℂ)⁻¹ * vandermonde z) * (f z : ℂ) by
    funext z
    exact normalizedVandermondeTransform_apply n _ z]
  have hfC : HasCompactSupport (fun z => (f z : ℂ)) :=
    hf.comp_left (g := fun x : ℝ => (x : ℂ)) (by simp)
  exact hfC.mul_left

theorem gaussianDbarEnergy_normalizedVandermonde_centered_eq_uncentered
    {n : ℕ} {f : Configuration n → ℝ} (hf : Differentiable ℝ f) :
    gaussianDbarEnergy n
        (normalizedVandermondeTransform n
          (fun z ↦ (centeredObservable n f z : ℂ))) =
      gaussianDbarEnergy n
        (normalizedVandermondeTransform n (fun z ↦ (f z : ℂ))) := by
  unfold gaussianDbarEnergy
  congr 1
  apply integral_congr_ae
  filter_upwards with z
  rw [dbarNormSq_normalized_centeredObservable hf,
    dbarNormSq_normalizedVandermondeTransform_ofReal hf]
  rfl

/-- Gaussian square-integrability of the normalized centered transform. -/
theorem isGaussianL2_normalizedVandermonde_centered {n : ℕ}
    {f : Configuration n → ℝ} (hf : Continuous f)
    (hcompact : HasCompactSupport f) :
    IsGaussianL2 n
      (normalizedVandermondeTransform n
        (fun z ↦ (centeredObservable n f z : ℂ))) := by
  unfold IsGaussianL2
  have hi := (integrable_vandermondeWeight_mul_centered_sq hf hcompact).const_mul
    (ginibreNormalizingMass n).toReal⁻¹
  apply hi.congr
  filter_upwards with z
  rw [normSq_normalizedVandermondeTransform]
  simp only [Complex.normSq_ofReal]
  ring

private theorem integrable_vandermondeWeight_mul_fderiv_sq {n : ℕ}
    {f : Configuration n → ℝ} (hf : ContDiff ℝ ∞ f)
    (hcompact : HasCompactSupport f) (v : Configuration n) :
    Integrable (fun z ↦ vandermondeWeight z * (fderiv ℝ f z v) ^ 2)
      (complexGaussianMeasure n) := by
  apply integrable_vandermondeWeight_mul_of_compactSupport
  · exact ((hf.continuous_fderiv (by simp)).clm_apply continuous_const).pow 2
  · apply (hcompact.fderiv_apply ℝ v).mono
    intro z hz
    simp only [Function.mem_support, ne_eq] at hz ⊢
    intro hzero
    apply hz
    simp [hzero]

/-- Each transformed coordinate `∂̄` square is Gaussian-integrable. -/
theorem integrable_normSq_dbarComponent_normalized_centered {n : ℕ}
    {f : Configuration n → ℝ} (hf : ContDiff ℝ ∞ f)
    (hcompact : HasCompactSupport f) (k : Fin n) :
    Integrable
      (fun z ↦ Complex.normSq
        (dbarComponent
          (normalizedVandermondeTransform n
            (fun w ↦ (centeredObservable n f w : ℂ))) k z))
      (complexGaussianMeasure n) := by
  have hr := integrable_vandermondeWeight_mul_fderiv_sq hf hcompact
    (realCoordinateDirection k)
  have hi := integrable_vandermondeWeight_mul_fderiv_sq hf hcompact
    (imaginaryCoordinateDirection k)
  have hbase := (hr.add hi).const_mul
    ((ginibreNormalizingMass n).toReal⁻¹ * (1 / 4 : ℝ))
  have hdiff : Differentiable ℝ f := hf.differentiable (by simp)
  have hcenter : Differentiable ℝ (centeredObservable n f) := by
    unfold centeredObservable
    fun_prop
  have hcenterC : Differentiable ℝ
      (fun w ↦ (centeredObservable n f w : ℂ)) := by fun_prop
  apply hbase.congr
  filter_upwards with z
  rw [dbarComponent_normalizedVandermondeTransform hcenterC,
    Complex.normSq_mul, Complex.normSq_mul,
    normSq_groundStateNormalization_inv]
  unfold vandermondeWeight
  rw [normSq_dbarComponent_ofReal hcenter]
  rw [fderiv_centeredObservable hdiff]
  simp only [Pi.add_apply]
  ring

/-- The normalized Vandermonde transform of every smooth compactly supported
observable satisfies the concrete Gaussian `∂̄` form-domain conditions. -/
theorem groundStateAdmissibility : GroundStateAdmissibilityStatement := by
  intro n hn hprob f hf
  refine ⟨contDiff_normalizedVandermonde_centered hf.1,
    isGaussianL2_normalizedVandermonde_centered hf.1.continuous hf.2.1, ?_⟩
  intro k
  exact integrable_normSq_dbarComponent_normalized_centered hf.1 hf.2.1 k

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/HermiteBinomialIdentity.lean #
import GinibrePoincare.Analysis.HermiteOrthogonalityCombinatorics
import Mathlib.Algebra.Polynomial.Coeff

/-! # Alternating Vandermonde identities for complex Hermites -/

open scoped BigOperators ComplexConjugate

namespace GinibrePoincare
namespace ComplexHermite

/-- An alternating form of Vandermonde's identity.  The proof extracts a
coefficient from
`(1+X)^N ((1+X)-1)^r = (1+X)^N X^r`. -/
theorem alternating_vandermonde (N K r : ℕ) :
    (∑ l ∈ Finset.range (r + 1),
      ((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ) *
        (Nat.choose (N + r - l) K : ℤ)) =
      if r ≤ K then (Nat.choose N (K - r) : ℤ) else 0 := by
  let A : Polynomial ℤ := Polynomial.X + 1
  have hpoly :
      ∑ l ∈ Finset.range (r + 1),
          Polynomial.C (((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ)) *
            A ^ (N + r - l) =
        Polynomial.X ^ r * A ^ N := by
    calc
      _ = A ^ N *
          ∑ l ∈ Finset.range (r + 1),
            Polynomial.C (((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ)) *
              A ^ (r - l) := by
        rw [Finset.mul_sum]
        apply Finset.sum_congr rfl
        intro l hl
        have hlr : l ≤ r := Nat.le_of_lt_succ (Finset.mem_range.mp hl)
        rw [show N + r - l = N + (r - l) by omega, pow_add]
        ring
      _ = A ^ N * ((Polynomial.C (-1) + A) ^ r) := by
        congr 1
        rw [add_pow]
        apply Finset.sum_congr rfl
        intro l hl
        rw [show (Nat.choose r l : Polynomial ℤ) =
            Polynomial.C (Nat.choose r l : ℤ) by rfl,
          ← Polynomial.C_pow, Polynomial.C_mul]
        ring
      _ = Polynomial.X ^ r * A ^ N := by
        simp [A]
        ring
  have hcoeff := congrArg (fun P : Polynomial ℤ => P.coeff K) hpoly
  unfold A at hcoeff
  rw [Polynomial.coeff_X_pow_mul'] at hcoeff
  let coeffHom : Polynomial ℤ →+ ℤ :=
    { toFun := fun P => P.coeff K
      map_zero' := Polynomial.coeff_zero K
      map_add' := fun P Q => Polynomial.coeff_add P Q K }
  change coeffHom
      (∑ l ∈ Finset.range (r + 1),
        Polynomial.C (((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ)) *
          (Polynomial.X + 1) ^ (N + r - l)) = _ at hcoeff
  simp only [map_sum] at hcoeff
  change (∑ l ∈ Finset.range (r + 1),
      (Polynomial.C (((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ)) *
        (Polynomial.X + 1) ^ (N + r - l)).coeff K) = _ at hcoeff
  simpa only [Polynomial.coeff_C_mul,
    Polynomial.coeff_X_add_one_pow] using hcoeff

private theorem factorial_choose_balance (s l P M : ℕ)
    (hls : l ≤ s) (hM : M = P + (s - l)) :
    l.factorial * Nat.choose s l * M.factorial =
      s.factorial * P.factorial * Nat.choose M P := by
  have hPM : P ≤ M := by omega
  apply Nat.mul_right_cancel (m := (s - l).factorial)
  · positivity
  calc
    (l.factorial * Nat.choose s l * M.factorial) * (s - l).factorial =
        (Nat.choose s l * l.factorial * (s - l).factorial) * M.factorial := by ring
    _ = s.factorial * M.factorial := by
      rw [Nat.choose_mul_factorial_mul_factorial hls]
    _ = s.factorial *
        (Nat.choose M P * P.factorial * (M - P).factorial) := by
      rw [Nat.choose_mul_factorial_mul_factorial hPM]
    _ = (s.factorial * P.factorial * Nat.choose M P) *
        (s - l).factorial := by
      rw [hM]
      simp only [Nat.add_sub_cancel_left]
      ring

private theorem inner_hermite_alternating (p q r s k : ℕ)
    (hbal : p + s = q + r) (hkp : k ≤ p) (hkq : k ≤ q) :
    (∑ l ∈ Finset.range (min r s + 1),
      ((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ) * (Nat.choose s l : ℤ) *
        (l.factorial : ℤ) * (((q - k) + (r - l)).factorial : ℤ)) =
      (s.factorial : ℤ) * ((p - k).factorial : ℤ) *
        (if r ≤ p - k then (Nat.choose (q - k) (p - k - r) : ℤ) else 0) := by
  let F : ℕ → ℤ := fun l =>
    ((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ) * (Nat.choose s l : ℤ) *
      (l.factorial : ℤ) * (((q - k) + (r - l)).factorial : ℤ)
  let G : ℕ → ℤ := fun l =>
    ((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ) *
      ((s.factorial * (p - k).factorial : ℕ) : ℤ) *
        (Nat.choose ((q - k) + r - l) (p - k) : ℤ)
  have hsub : Finset.range (min r s + 1) ⊆ Finset.range (r + 1) :=
    Finset.range_mono (Nat.succ_le_succ (min_le_left r s))
  have hext : (∑ l ∈ Finset.range (min r s + 1), F l) =
      ∑ l ∈ Finset.range (r + 1), F l := by
    apply Finset.sum_subset hsub
    intro l hlr hls
    have hsl : s < l := by
      have hlr' : l ≤ r := Nat.lt_succ_iff.mp (Finset.mem_range.mp hlr)
      by_contra h
      exact hls (Finset.mem_range.mpr
        (Nat.lt_succ_of_le (le_min hlr' (Nat.le_of_not_gt h))))
    simp [F, Nat.choose_eq_zero_of_lt hsl]
  rw [show (∑ l ∈ Finset.range (min r s + 1),
      ((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ) * (Nat.choose s l : ℤ) *
        (l.factorial : ℤ) * (((q - k) + (r - l)).factorial : ℤ)) =
      ∑ l ∈ Finset.range (min r s + 1), F l by rfl, hext]
  have hFG : ∀ l ∈ Finset.range (r + 1), F l = G l := by
    intro l hl
    dsimp [F, G]
    have hlr : l ≤ r := Nat.lt_succ_iff.mp (Finset.mem_range.mp hl)
    by_cases hls : l ≤ s
    · have hM : (q - k) + (r - l) = (p - k) + (s - l) := by omega
      have hfac := factorial_choose_balance s l (p - k)
        ((q - k) + (r - l)) hls hM
      have hfacZ := congrArg (fun x : ℕ => (x : ℤ)) hfac
      push_cast at hfacZ
      have hfacZ' : (Nat.choose s l : ℤ) * (l.factorial : ℤ) *
          (((q - k) + (r - l)).factorial : ℤ) =
          (s.factorial : ℤ) * ((p - k).factorial : ℤ) *
            (Nat.choose ((q - k) + (r - l)) (p - k) : ℤ) := by
        rw [← hfacZ]
        ring
      rw [show (q - k) + r - l = (q - k) + (r - l) by omega]
      calc
        _ = ((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ) *
            ((Nat.choose s l : ℤ) * (l.factorial : ℤ) *
              (((q - k) + (r - l)).factorial : ℤ)) := by ring
        _ = ((-1 : ℤ) ^ l) * (Nat.choose r l : ℤ) *
            ((s.factorial : ℤ) * ((p - k).factorial : ℤ) *
              (Nat.choose ((q - k) + (r - l)) (p - k) : ℤ)) := by rw [hfacZ']
        _ = _ := by ring
    · have hsl : s < l := Nat.lt_of_not_ge hls
      have hsmall : (q - k) + r - l < p - k := by omega
      simp [Nat.choose_eq_zero_of_lt hsl,
        Nat.choose_eq_zero_of_lt hsmall]
  rw [Finset.sum_congr rfl hFG]
  unfold G
  calc
    _ = (s.factorial : ℤ) * ((p - k).factorial : ℤ) *
        ∑ x ∈ Finset.range (r + 1),
          (((-1 : ℤ) ^ x) * (Nat.choose r x : ℤ) *
            (Nat.choose ((q - k) + r - x) (p - k) : ℤ)) := by
      simp_rw [Finset.mul_sum]
      apply Finset.sum_congr rfl
      intro l hl
      push_cast
      ring
    _ = _ := by rw [alternating_vandermonde (q - k) (p - k) r]

private theorem outer_hermite_alternating (p q r s : ℕ)
    (hbal : p + s = q + r) :
    (∑ k ∈ Finset.range (min p q + 1),
      ((-1 : ℤ) ^ k) * (Nat.choose p k : ℤ) * (Nat.choose q k : ℤ) *
        (k.factorial : ℤ) * (s.factorial : ℤ) * ((p - k).factorial : ℤ) *
          (if r ≤ p - k then (Nat.choose (q - k) (p - k - r) : ℤ) else 0)) =
      if p = r then (p.factorial : ℤ) * (q.factorial : ℤ) else 0 := by
  by_cases hrp : r ≤ p
  · let d := p - r
    have hdP : d ≤ p := Nat.sub_le _ _
    have hdQ : d ≤ q := by
      dsimp [d]
      omega
    have hdmin : Finset.range (d + 1) ⊆ Finset.range (min p q + 1) :=
      Finset.range_mono (Nat.succ_le_succ (le_min hdP hdQ))
    rw [show (∑ k ∈ Finset.range (min p q + 1),
        ((-1 : ℤ) ^ k) * (Nat.choose p k : ℤ) * (Nat.choose q k : ℤ) *
          (k.factorial : ℤ) * (s.factorial : ℤ) * ((p - k).factorial : ℤ) *
            (if r ≤ p - k then
              (Nat.choose (q - k) (p - k - r) : ℤ) else 0)) =
        ∑ k ∈ Finset.range (d + 1),
          ((-1 : ℤ) ^ k) * (Nat.choose p k : ℤ) * (Nat.choose q k : ℤ) *
            (k.factorial : ℤ) * (s.factorial : ℤ) * ((p - k).factorial : ℤ) *
              (if r ≤ p - k then
                (Nat.choose (q - k) (p - k - r) : ℤ) else 0) by
      symm
      apply Finset.sum_subset hdmin
      intro k hk hkd
      have hdk : d < k := by
        by_contra h
        exact hkd (Finset.mem_range.mpr (Nat.lt_succ_of_le (Nat.le_of_not_gt h)))
      have hkp : k ≤ p := (le_min_iff.mp
        (Nat.lt_succ_iff.mp (Finset.mem_range.mp hk))).1
      have hnot : ¬r ≤ p - k := by omega
      simp [hnot]]
    have hterm : ∀ k ∈ Finset.range (d + 1),
        ((-1 : ℤ) ^ k) * (Nat.choose p k : ℤ) * (Nat.choose q k : ℤ) *
            (k.factorial : ℤ) * (s.factorial : ℤ) * ((p - k).factorial : ℤ) *
              (if r ≤ p - k then
                (Nat.choose (q - k) (p - k - r) : ℤ) else 0) =
          (p.factorial : ℤ) * (s.factorial : ℤ) * (Nat.choose q d : ℤ) *
            (((-1 : ℤ) ^ k) * (Nat.choose d k : ℤ)) := by
      intro k hk
      have hkd : k ≤ d := Nat.lt_succ_iff.mp (Finset.mem_range.mp hk)
      have hkp : k ≤ p := hkd.trans hdP
      have hkq : k ≤ q := hkd.trans hdQ
      have hrpk : r ≤ p - k := by omega
      have hchoose := Nat.choose_mul (n := q) (k := d) (s := k) hkd
      have hpfac := Nat.choose_mul_factorial_mul_factorial hkp
      simp only [if_pos hrpk]
      rw [show p - k - r = d - k by dsimp [d]; omega]
      have hchooseZ := congrArg (fun x : ℕ => (x : ℤ)) hchoose
      have hpfacZ := congrArg (fun x : ℕ => (x : ℤ)) hpfac
      push_cast at hchooseZ hpfacZ
      calc
        _ = ((-1 : ℤ) ^ k) * (s.factorial : ℤ) *
            ((Nat.choose p k : ℤ) * (k.factorial : ℤ) *
              ((p - k).factorial : ℤ)) *
            ((Nat.choose q k : ℤ) *
              (Nat.choose (q - k) (d - k) : ℤ)) := by ring
        _ = ((-1 : ℤ) ^ k) * (s.factorial : ℤ) *
            (p.factorial : ℤ) *
            ((Nat.choose q d : ℤ) * (Nat.choose d k : ℤ)) := by
              rw [hpfacZ, ← hchooseZ]
        _ = _ := by ring
    rw [Finset.sum_congr rfl hterm]
    rw [show (∑ k ∈ Finset.range (d + 1),
        (p.factorial : ℤ) * (s.factorial : ℤ) * (Nat.choose q d : ℤ) *
          (((-1 : ℤ) ^ k) * (Nat.choose d k : ℤ))) =
        (p.factorial : ℤ) * (s.factorial : ℤ) * (Nat.choose q d : ℤ) *
          ∑ k ∈ Finset.range (d + 1),
            (((-1 : ℤ) ^ k) * (Nat.choose d k : ℤ)) by
      simp_rw [Finset.mul_sum]
      ]
    rw [Int.alternating_sum_range_choose]
    by_cases hpr : p = r
    · subst r
      have hs : s = q := by omega
      subst s
      simp [d]
    · have hd0 : d ≠ 0 := by omega
      simp [hpr, hd0]
  · have hpr : p ≠ r := by omega
    rw [if_neg hpr]
    apply Finset.sum_eq_zero
    intro k hk
    have hnot : ¬r ≤ p - k := by omega
    simp [hnot]

set_option maxRecDepth 2000 in
/-- Evaluation of the finite moment sum before applying the square-root
normalization factors. -/
theorem hermiteInnerMomentSum_eq (n p q r s : ℕ) :
    hermiteInnerMomentSum n p q r s =
      if p = r ∧ q = s then
        (p.factorial : ℂ) * (q.factorial : ℂ) *
          ((n : ℂ)⁻¹) ^ (p + q)
      else 0 := by
  by_cases hbal : p + s = q + r
  · unfold hermiteInnerMomentSum diagonalRawCoeff
    rw [show (∑ k ∈ Finset.range (min p q + 1),
        ∑ l ∈ Finset.range (min r s + 1),
          conj ((-((n : ℝ)⁻¹ : ℂ)) ^ k * (k.factorial : ℂ) *
              (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
            ((-((n : ℝ)⁻¹ : ℂ)) ^ l * (l.factorial : ℂ) *
              (Nat.choose r l : ℂ) * (Nat.choose s l : ℂ)) *
            (if q - k + (r - l) = p - k + (s - l) then
              ((q - k + (r - l)).factorial : ℂ) *
                (n : ℂ)⁻¹ ^ (q - k + (r - l))
            else 0)) =
        ((n : ℂ)⁻¹) ^ (q + r) *
          ∑ k ∈ Finset.range (min p q + 1),
            ((-1 : ℂ) ^ k) * (Nat.choose p k : ℂ) *
              (Nat.choose q k : ℂ) * (k.factorial : ℂ) *
              (∑ l ∈ Finset.range (min r s + 1),
                ((-1 : ℂ) ^ l) * (Nat.choose r l : ℂ) *
                  (Nat.choose s l : ℂ) * (l.factorial : ℂ) *
                    ((q - k + (r - l)).factorial : ℂ)) by
      rw [Finset.mul_sum]
      apply Finset.sum_congr rfl
      intro k hk
      have hkp : k ≤ p := (le_min_iff.mp
        (Nat.lt_succ_iff.mp (Finset.mem_range.mp hk))).1
      have hkq : k ≤ q := (le_min_iff.mp
        (Nat.lt_succ_iff.mp (Finset.mem_range.mp hk))).2
      rw [Finset.mul_sum, Finset.mul_sum]
      apply Finset.sum_congr rfl
      intro l hl
      have hlr : l ≤ r := (le_min_iff.mp
        (Nat.lt_succ_iff.mp (Finset.mem_range.mp hl))).1
      have hls : l ≤ s := (le_min_iff.mp
        (Nat.lt_succ_iff.mp (Finset.mem_range.mp hl))).2
      have heq : q - k + (r - l) = p - k + (s - l) := by omega
      simp only [if_pos heq, map_mul, map_pow,
        Complex.conj_natCast, Complex.conj_ofReal, map_neg, map_inv₀]
      have hexp : k + l + (q - k + (r - l)) = q + r := by omega
      rw [show (((n : ℝ)⁻¹ : ℂ)) = (n : ℂ)⁻¹ by push_cast; rfl]
      have hpows :
          (-(n : ℂ)⁻¹) ^ k * (-(n : ℂ)⁻¹) ^ l *
              (n : ℂ)⁻¹ ^ (q - k + (r - l)) =
            (-1 : ℂ) ^ k * (-1 : ℂ) ^ l * (n : ℂ)⁻¹ ^ (q + r) := by
        have hnexp :
            (n : ℂ)⁻¹ ^ k * (n : ℂ)⁻¹ ^ l *
                (n : ℂ)⁻¹ ^ (q - k + (r - l)) =
              (n : ℂ)⁻¹ ^ (q + r) := by
          rw [← pow_add, ← pow_add]
          congr 1
        rw [neg_pow, neg_pow]
        calc
          _ = ((n : ℂ)⁻¹ ^ k * (n : ℂ)⁻¹ ^ l *
                (n : ℂ)⁻¹ ^ (q - k + (r - l))) *
                (-1 : ℂ) ^ k * (-1 : ℂ) ^ l := by ring
          _ = _ := by rw [hnexp]; ring
      calc
        _ = ((-(n : ℂ)⁻¹) ^ k * (-(n : ℂ)⁻¹) ^ l *
              (n : ℂ)⁻¹ ^ (q - k + (r - l))) *
              (k.factorial : ℂ) * (Nat.choose p k : ℂ) *
              (Nat.choose q k : ℂ) * (l.factorial : ℂ) *
              (Nat.choose r l : ℂ) * (Nat.choose s l : ℂ) *
              ((q - k + (r - l)).factorial : ℂ) := by ring
        _ = _ := by rw [hpows]; ring]
    have hinner : ∀ k ∈ Finset.range (min p q + 1),
        (∑ l ∈ Finset.range (min r s + 1),
          ((-1 : ℂ) ^ l) * (Nat.choose r l : ℂ) *
            (Nat.choose s l : ℂ) * (l.factorial : ℂ) *
              ((q - k + (r - l)).factorial : ℂ)) =
          (s.factorial : ℂ) * ((p - k).factorial : ℂ) *
            (if r ≤ p - k then
              (Nat.choose (q - k) (p - k - r) : ℂ) else 0) := by
      intro k hk
      have hkp : k ≤ p := (le_min_iff.mp
        (Nat.lt_succ_iff.mp (Finset.mem_range.mp hk))).1
      have hkq : k ≤ q := (le_min_iff.mp
        (Nat.lt_succ_iff.mp (Finset.mem_range.mp hk))).2
      exact_mod_cast inner_hermite_alternating p q r s k hbal hkp hkq
    rw [Finset.sum_congr rfl (fun k hk => by rw [hinner k hk])]
    have houter := outer_hermite_alternating p q r s hbal
    have houterC := congrArg (fun z : ℤ => (z : ℂ)) houter
    push_cast at houterC
    have hsum :
        (∑ k ∈ Finset.range (min p q + 1),
          ((-1 : ℂ) ^ k) * (Nat.choose p k : ℂ) *
            (Nat.choose q k : ℂ) * (k.factorial : ℂ) *
            ((s.factorial : ℂ) * ((p - k).factorial : ℂ) *
              (if r ≤ p - k then
                (Nat.choose (q - k) (p - k - r) : ℂ) else 0))) =
          if p = r then (p.factorial : ℂ) * (q.factorial : ℂ) else 0 := by
      calc
        _ = ∑ k ∈ Finset.range (min p q + 1),
            ((-1 : ℂ) ^ k) * (Nat.choose p k : ℂ) *
              (Nat.choose q k : ℂ) * (k.factorial : ℂ) *
              (s.factorial : ℂ) * ((p - k).factorial : ℂ) *
                (if r ≤ p - k then
                  (Nat.choose (q - k) (p - k - r) : ℂ) else 0) := by
            apply Finset.sum_congr rfl
            intro k hk
            ring
        _ = _ := houterC
    rw [hsum]
    by_cases hpr : p = r
    · subst r
      have hqs : q = s := by omega
      subst s
      simp
      ring
    · have hqs : ¬(p = r ∧ q = s) := by simp [hpr]
      simp [hpr]
  · unfold hermiteInnerMomentSum
    have hdelta : ¬(p = r ∧ q = s) := by
      rintro ⟨rfl, rfl⟩
      exact hbal (Nat.add_comm _ _)
    rw [if_neg hdelta]
    apply Finset.sum_eq_zero
    intro k hk
    apply Finset.sum_eq_zero
    intro l hl
    have hkp : k ≤ p := (le_min_iff.mp
      (Nat.lt_succ_iff.mp (Finset.mem_range.mp hk))).1
    have hkq : k ≤ q := (le_min_iff.mp
      (Nat.lt_succ_iff.mp (Finset.mem_range.mp hk))).2
    have hlr : l ≤ r := (le_min_iff.mp
      (Nat.lt_succ_iff.mp (Finset.mem_range.mp hl))).1
    have hls : l ≤ s := (le_min_iff.mp
      (Nat.lt_succ_iff.mp (Finset.mem_range.mp hl))).2
    have hne : q - k + (r - l) ≠ p - k + (s - l) := by omega
    simp [hne]

private theorem oneDimNormalization_square_mul (n p : ℕ) (hn : 0 < n) :
    (oneDimNormalization n p) ^ 2 * (p.factorial : ℝ) *
        ((n : ℝ)⁻¹) ^ p = 1 := by
  have hn0 : (n : ℝ) ≠ 0 := by exact_mod_cast hn.ne'
  have hsqrtfac : Real.sqrt (p.factorial : ℝ) ≠ 0 := by positivity
  have hsqrtn : Real.sqrt (n : ℝ) ^ 2 = n := by
    rw [sq, Real.mul_self_sqrt]
    positivity
  have hsqrtfac_sq : Real.sqrt (p.factorial : ℝ) ^ 2 = p.factorial := by
    rw [sq, Real.mul_self_sqrt]
    positivity
  unfold oneDimNormalization
  rw [div_pow]
  rw [← pow_mul, mul_comm p 2, pow_mul, hsqrtn, hsqrtfac_sq]
  field_simp
  rw [← mul_pow]
  field_simp
  norm_num

/-- The mixed-moment formula implies exact orthonormality of the normalized
one-coordinate complex Hermite system. -/
theorem normalizedEval_orthogonal_of_mixedMoments
    (n : ℕ) (hn : 0 < n) (hMom : MixedMomentFormula n)
    (p q r s : ℕ) :
    ∫ z : ℂ, conj (normalizedEval n hn p q z) *
        normalizedEval n hn r s z
      ∂(complexCoordinateGaussianProbability n : MeasureTheory.Measure ℂ) =
      if p = r ∧ q = s then 1 else 0 := by
  rw [normalizedEval_inner_eq_momentSum_of_mixedMoments n hn hMom,
    hermiteInnerMomentSum_eq]
  by_cases h : p = r ∧ q = s
  · rcases h with ⟨rfl, rfl⟩
    simp
    have hp := oneDimNormalization_square_mul n p hn
    have hq := oneDimNormalization_square_mul n q hn
    have hpC :
        (oneDimNormalization n p : ℂ) ^ 2 * (p.factorial : ℂ) *
            ((n : ℂ)⁻¹) ^ p = 1 := by
      simpa only [Complex.ofReal_mul, Complex.ofReal_pow, Complex.ofReal_inv,
        Complex.ofReal_natCast, Complex.ofReal_one] using
          congrArg (fun x : ℝ => (x : ℂ)) hp
    have hqC :
        (oneDimNormalization n q : ℂ) ^ 2 * (q.factorial : ℂ) *
            ((n : ℂ)⁻¹) ^ q = 1 := by
      simpa only [Complex.ofReal_mul, Complex.ofReal_pow, Complex.ofReal_inv,
        Complex.ofReal_natCast, Complex.ofReal_one] using
          congrArg (fun x : ℝ => (x : ℂ)) hq
    calc
      _ = ((oneDimNormalization n p : ℂ) ^ 2 * (p.factorial : ℂ) *
            ((n : ℂ)⁻¹) ^ p) *
          ((oneDimNormalization n q : ℂ) ^ 2 * (q.factorial : ℂ) *
            ((n : ℂ)⁻¹) ^ q) := by rw [pow_add]; ring
      _ = 1 := by rw [hpC, hqC]; norm_num
  · simp [h]

/-- Exact multivariate orthonormality follows from the coordinate mixed
moments and the previously established product-measure factorization. -/
theorem multivariate_orthogonality_of_mixedMoments
    (n : ℕ) (hn : 0 < n) (hMom : MixedMomentFormula n)
    (p q r s : Fin n → ℕ) :
    ∫ z, conj (multivariateNormalized n hn p q z) *
        multivariateNormalized n hn r s z ∂complexGaussianMeasure n =
      if p = r ∧ q = s then 1 else 0 :=
  multivariate_orthogonality_of_oneCoordinate n hn
    (normalizedEval_orthogonal_of_mixedMoments n hn hMom) p q r s

end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/HermiteEnergy.lean #
import GinibrePoincare.Analysis.HermiteL2Family
import GinibrePoincare.Analysis.HermiteWirtinger

/-! # Finite Hermite expansions and antiholomorphic energy -/

open MeasureTheory
open scoped BigOperators ComplexConjugate

namespace GinibrePoincare
namespace ComplexHermite

noncomputable section

/-- A finite Hermite coefficient vector synthesized in Gaussian `L²`. -/
def finiteHermiteCombination (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    Lp ℂ 2 (complexGaussianMeasure n) :=
  Finsupp.linearCombination ℂ (hermiteL2Family n hn) c

/-- Parseval's identity for two finite Hermite expansions. -/
theorem inner_finiteHermiteCombination (n : ℕ) (hn : 0 < n)
    (c d : HermiteMultiIndex n →₀ ℂ) :
    inner ℂ (finiteHermiteCombination n hn c)
        (finiteHermiteCombination n hn d) =
      c.sum fun a z => conj z * d a := by
  exact (orthonormal_hermiteL2Family_gaussian n hn).inner_finsupp_eq_sum_left c d

/-- Parseval's norm decomposition for a finite Hermite expansion. -/
theorem norm_sq_finiteHermiteCombination (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    ‖finiteHermiteCombination n hn c‖ ^ 2 =
      c.sum fun _ z => Complex.normSq z := by
  have h := inner_finiteHermiteCombination n hn c c
  rw [inner_self_eq_norm_sq_to_K] at h
  have hr := congrArg Complex.re h
  simpa [Finsupp.sum, map_sum, Complex.mul_re, Complex.sq_norm,
    Complex.normSq_apply, pow_two] using hr

/-- Restriction of a finite coefficient vector to one total
antiholomorphic degree. -/
def coefficientsAtAntiDegree {n : ℕ}
    (c : HermiteMultiIndex n →₀ ℂ) (d : ℕ) :
    HermiteMultiIndex n →₀ ℂ :=
  c.filter fun pq => totalAntiDegree pq = d

/-- Distinct antiholomorphic-degree pieces are orthogonal. -/
theorem antiDegreePieces_inner_eq_zero (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) {d e : ℕ} (hde : d ≠ e) :
    inner ℂ
        (finiteHermiteCombination n hn (coefficientsAtAntiDegree c d))
        (finiteHermiteCombination n hn (coefficientsAtAntiDegree c e)) = 0 := by
  rw [inner_finiteHermiteCombination]
  unfold Finsupp.sum
  apply Finset.sum_eq_zero
  intro pq hpq
  simp only [coefficientsAtAntiDegree, Finsupp.filter_apply]
  by_cases hd : totalAntiDegree pq = d
  · have he : totalAntiDegree pq ≠ e := by simpa [hd] using hde
    simp [hd, hde]
  · simp [hd]

/-- The exact `j`-coordinate lowering of an individual Hermite mode. -/
theorem dbarComponent_hermiteMode (n : ℕ) (hn : 0 < n)
    (pq : HermiteMultiIndex n) (j : Fin n) (z : Configuration n) :
    dbarComponent (multivariateNormalized n hn pq.1 pq.2) j z =
      Real.sqrt (n * pq.2 j : ℕ) *
        multivariateNormalized n hn pq.1 (Function.update pq.2 j (pq.2 j - 1)) z :=
  dbarComponent_multivariateNormalized n hn pq.1 pq.2 j z

/-- Diagonal antiholomorphic energy of a finite coefficient vector.  The
factor `n * totalAntiDegree` is the sum of the squared exact lowering
coefficients over all coordinates. -/
def finiteDbarEnergy {n : ℕ} (c : HermiteMultiIndex n →₀ ℂ) : ℝ :=
  c.sum fun pq z => (n * totalAntiDegree pq : ℕ) * ‖z‖ ^ 2

/-- Coordinate form of the finite antiholomorphic energy diagonalization. -/
theorem finiteDbarEnergy_eq_sum_coordinates {n : ℕ}
    (c : HermiteMultiIndex n →₀ ℂ) :
    finiteDbarEnergy c =
      ∑ j : Fin n, c.sum fun pq z => (n * pq.2 j : ℕ) * ‖z‖ ^ 2 := by
  unfold finiteDbarEnergy totalAntiDegree
  unfold Finsupp.sum
  simp_rw [Nat.cast_mul, Nat.cast_sum, Finset.mul_sum,
    Finset.sum_mul]
  rw [Finset.sum_comm]

/-- Joint-index lowering in coordinate `j`. -/
def lowerHermiteIndex {n : ℕ} (j : Fin n) (pq : HermiteMultiIndex n) :
    HermiteMultiIndex n := (pq.1, lowerAt pq.2 j)

/-- Raise the `j`th entry of an antiholomorphic multi-index by one. -/
def raiseAt {n : ℕ} (q : Fin n → ℕ) (j : Fin n) : Fin n → ℕ :=
  Function.update q j (q j + 1)

/-- Joint-index raising in coordinate `j`. -/
def raiseHermiteIndex {n : ℕ} (j : Fin n) (pq : HermiteMultiIndex n) :
    HermiteMultiIndex n := (pq.1, raiseAt pq.2 j)

/-- Raising cancels truncated lowering when the lowered coordinate was
strictly positive. -/
theorem raiseAt_lowerAt {n : ℕ} (q : Fin n → ℕ) (j : Fin n)
    (hq : 0 < q j) :
    raiseAt (lowerAt q j) j = q := by
  funext k
  by_cases hkj : k = j
  · subst k
    simp [raiseAt, lowerAt]
    omega
  · simp [raiseAt, lowerAt, Function.update_of_ne hkj]

/-- The joint-index raising map is a left inverse to lowering on indices
whose `j`th antiholomorphic exponent is positive. -/
theorem raiseHermiteIndex_lowerHermiteIndex {n : ℕ} (j : Fin n)
    (pq : HermiteMultiIndex n) (hq : 0 < pq.2 j) :
    raiseHermiteIndex j (lowerHermiteIndex j pq) = pq := by
  apply Prod.ext
  · rfl
  · exact raiseAt_lowerAt pq.2 j hq

/-- Coordinate lowering is injective after restricting to source indices
with positive `j`th antiholomorphic exponent. -/
theorem lowerHermiteIndex_injective_of_positive {n : ℕ} (j : Fin n)
    {a b : HermiteMultiIndex n} (ha : 0 < a.2 j) (hb : 0 < b.2 j)
    (h : lowerHermiteIndex j a = lowerHermiteIndex j b) : a = b := by
  calc
    a = raiseHermiteIndex j (lowerHermiteIndex j a) :=
      (raiseHermiteIndex_lowerHermiteIndex j a ha).symm
    _ = raiseHermiteIndex j (lowerHermiteIndex j b) := congrArg _ h
    _ = b := raiseHermiteIndex_lowerHermiteIndex j b hb

/-- A mode with zero `j`th antiholomorphic exponent contributes the zero
coefficient to coordinate lowering. -/
theorem loweringCoefficient_eq_zero_of_coordinate_eq_zero
    (n : ℕ) {m : ℕ} (q : Fin m → ℕ) (j : Fin m) (a : ℂ)
    (hq : q j = 0) :
    (Real.sqrt (n * q j : ℕ) : ℂ) * a = 0 := by
  simp [hq]

/-- Collision-safe lowered coefficients.  `Finsupp.sum` adds coefficients
when several source indices lower to the same target index. -/
def loweredCoefficients (n : ℕ)
    (c : HermiteMultiIndex n →₀ ℂ) (j : Fin n) :
    HermiteMultiIndex n →₀ ℂ :=
  c.sum fun pq a => Finsupp.single (lowerHermiteIndex j pq)
    ((Real.sqrt (n * pq.2 j : ℕ) : ℂ) * a)

/-- Evaluation of the aggregated lowered coefficients at the image of a
positive source index. -/
theorem loweredCoefficients_apply_lowerHermiteIndex (n : ℕ)
    (c : HermiteMultiIndex n →₀ ℂ) (j : Fin n)
    (pq : HermiteMultiIndex n) (hq : 0 < pq.2 j) :
    loweredCoefficients n c j (lowerHermiteIndex j pq) =
      (Real.sqrt (n * pq.2 j : ℕ) : ℂ) * c pq := by
  classical
  unfold loweredCoefficients
  rw [Finsupp.sum_apply]
  unfold Finsupp.sum
  by_cases hpq : pq ∈ c.support
  · rw [Finset.sum_eq_single pq]
    · simp
    · intro a ha hane
      dsimp
      rw [Finsupp.single_apply]
      split_ifs with heq
      · by_cases ha0 : a.2 j = 0
        · exact loweringCoefficient_eq_zero_of_coordinate_eq_zero n a.2 j (c a) ha0
        · have hapos : 0 < a.2 j := Nat.pos_of_ne_zero ha0
          exact (hane (lowerHermiteIndex_injective_of_positive j hapos hq heq)).elim
      · rfl
    · exact fun h => (h hpq).elim
  · have hpq0 : c pq = 0 := by simpa using hpq
    rw [hpq0, mul_zero]
    apply Finset.sum_eq_zero
    intro a ha
    dsimp
    rw [Finsupp.single_apply]
    split_ifs with heq
    · by_cases ha0 : a.2 j = 0
      · exact loweringCoefficient_eq_zero_of_coordinate_eq_zero n a.2 j (c a) ha0
      · have hapos : 0 < a.2 j := Nat.pos_of_ne_zero ha0
        have hapq := lowerHermiteIndex_injective_of_positive j hapos hq heq
        subst a
        exact (hpq ha).elim
    · rfl

/-- An index outside the image of positive coordinate lowering has zero
aggregated lowered coefficient. -/
theorem loweredCoefficients_apply_eq_zero_of_offImage (n : ℕ)
    (c : HermiteMultiIndex n →₀ ℂ) (j : Fin n) (b : HermiteMultiIndex n)
    (hoff : ∀ pq : HermiteMultiIndex n,
      pq ∈ c.support → 0 < pq.2 j → lowerHermiteIndex j pq ≠ b) :
    loweredCoefficients n c j b = 0 := by
  classical
  unfold loweredCoefficients
  rw [Finsupp.sum_apply]
  unfold Finsupp.sum
  apply Finset.sum_eq_zero
  intro pq hpq
  dsimp
  rw [Finsupp.single_apply]
  split_ifs with heq
  · by_cases hq0 : pq.2 j = 0
    · exact loweringCoefficient_eq_zero_of_coordinate_eq_zero n pq.2 j (c pq) hq0
    · exact (hoff pq hpq (Nat.pos_of_ne_zero hq0) heq).elim
  · rfl

/-- The support of lowered coefficients is exactly the image of positive
source-support indices. -/
theorem mem_support_loweredCoefficients_iff (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) (j : Fin n) (b : HermiteMultiIndex n) :
    b ∈ (loweredCoefficients n c j).support ↔
      ∃ pq ∈ c.support, 0 < pq.2 j ∧ lowerHermiteIndex j pq = b := by
  classical
  constructor
  · intro hb
    by_contra h
    push Not at h
    have hz := loweredCoefficients_apply_eq_zero_of_offImage n c j b
      (fun pq hpq hp => h pq hpq hp)
    exact (Finsupp.mem_support_iff.mp hb) hz
  · rintro ⟨pq, hpq, hpos, rfl⟩
    rw [Finsupp.mem_support_iff,
      loweredCoefficients_apply_lowerHermiteIndex n c j pq hpos]
    apply mul_ne_zero
    · exact_mod_cast (Real.sqrt_pos.2 (by positivity : (0 : ℝ) < n * pq.2 j)).ne'
    · exact Finsupp.mem_support_iff.mp hpq

/-- Squared coefficient mass after coordinate lowering is the original
coefficient mass weighted by the exact squared lowering coefficient. -/
theorem loweredCoefficients_normSq_sum (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) (j : Fin n) :
    (loweredCoefficients n c j).sum (fun _ a => Complex.normSq a) =
      c.sum fun pq a => (n * pq.2 j : ℕ) * Complex.normSq a := by
  classical
  unfold Finsupp.sum
  have hreindex :
      (∑ pq ∈ c.support.filter (fun pq => 0 < pq.2 j),
        Complex.normSq
          ((Real.sqrt (n * pq.2 j : ℕ) : ℂ) * c pq)) =
      ∑ b ∈ (loweredCoefficients n c j).support,
        Complex.normSq (loweredCoefficients n c j b) := by
    apply Finset.sum_bij
      (fun pq _ => lowerHermiteIndex j pq)
    · intro pq hpq
      rw [mem_support_loweredCoefficients_iff n hn]
      exact ⟨pq, (Finset.mem_filter.mp hpq).1,
        (Finset.mem_filter.mp hpq).2, rfl⟩
    · intro a ha b hb hab
      exact lowerHermiteIndex_injective_of_positive j
        (Finset.mem_filter.mp ha).2 (Finset.mem_filter.mp hb).2 hab
    · intro b hb
      rw [mem_support_loweredCoefficients_iff n hn] at hb
      obtain ⟨pq, hpq, hpos, rfl⟩ := hb
      exact ⟨pq, Finset.mem_filter.mpr ⟨hpq, hpos⟩, rfl⟩
    · intro pq hpq
      rw [loweredCoefficients_apply_lowerHermiteIndex n c j pq
        (Finset.mem_filter.mp hpq).2]
  rw [← hreindex]
  change (∑ pq ∈ c.support.filter (fun pq => 0 < pq.2 j),
      Complex.normSq ((Real.sqrt (n * pq.2 j : ℕ) : ℂ) * c pq)) =
    ∑ pq ∈ c.support, ((n * pq.2 j : ℕ) : ℝ) * Complex.normSq (c pq)
  rw [show (∑ pq ∈ c.support,
      ((n * pq.2 j : ℕ) : ℝ) * Complex.normSq (c pq)) =
      ∑ pq ∈ c.support.filter (fun pq => 0 < pq.2 j),
        ((n * pq.2 j : ℕ) : ℝ) * Complex.normSq (c pq) by
    rw [Finset.sum_filter]
    apply Finset.sum_congr rfl
    intro pq hpq
    split_ifs with hpos
    · rfl
    · have hz : pq.2 j = 0 := by omega
      simp [hz]]
  apply Finset.sum_congr rfl
  intro pq hpq
  rw [Complex.normSq_mul]
  have hsqrt : Real.sqrt (n * pq.2 j : ℕ) ^ 2 = (n * pq.2 j : ℕ) := by
    rw [sq, Real.mul_self_sqrt]
    positivity
  rw [Complex.normSq_ofReal, ← sq, hsqrt]

/-- Parseval turns the lowered coefficient identity into the exact
coordinatewise Gaussian `L²` norm formula. -/
theorem norm_sq_finiteHermiteCombination_lowered (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) (j : Fin n) :
    ‖finiteHermiteCombination n hn (loweredCoefficients n c j)‖ ^ 2 =
      c.sum fun pq a => (n * pq.2 j : ℕ) * Complex.normSq a := by
  rw [norm_sq_finiteHermiteCombination, loweredCoefficients_normSq_sum n hn]

/-- Total Gaussian `L²` energy of the finitely synthesized coordinate
`∂̄` expansions is the diagonal antiholomorphic Hermite energy. -/
theorem sum_norm_sq_lowered_eq_finiteDbarEnergy (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    (∑ j : Fin n,
      ‖finiteHermiteCombination n hn (loweredCoefficients n c j)‖ ^ 2) =
      finiteDbarEnergy c := by
  simp_rw [norm_sq_finiteHermiteCombination_lowered]
  rw [finiteDbarEnergy_eq_sum_coordinates]
  apply Finset.sum_congr rfl
  intro j hj
  apply Finsupp.sum_congr
  intro pq hpq
  rw [Complex.sq_norm]

/-- The underlying pointwise finite Hermite polynomial. -/
def finiteHermiteFunction (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) : Configuration n → ℂ :=
  Finsupp.linearCombination ℂ
    (fun pq => multivariateNormalized n hn pq.1 pq.2) c

/-- The pointwise finite Hermite function represents its synthesized
Gaussian `L²` vector. -/
theorem finiteHermiteCombination_coeFn (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    finiteHermiteCombination n hn c =ᵐ[complexGaussianMeasure n]
      finiteHermiteFunction n hn c := by
  classical
  unfold finiteHermiteCombination finiteHermiteFunction
  simp only [Finsupp.linearCombination_apply]
  have h :
      (∑ pq ∈ c.support,
        fun z => c pq • (hermiteL2Family n hn pq : Configuration n → ℂ) z) =ᵐ[
          complexGaussianMeasure n]
      ∑ pq ∈ c.support,
        fun z => c pq • multivariateNormalized n hn pq.1 pq.2 z := by
    apply eventuallyEq_sum
    intro pq hpq
    exact (hermiteL2Family_coeFn n hn pq).const_smul (c pq)
  have hcoe :
      ((∑ pq ∈ c.support, c pq • hermiteL2Family n hn pq :
          Lp ℂ 2 (complexGaussianMeasure n)) : Configuration n → ℂ) =ᵐ[
        complexGaussianMeasure n]
      ∑ pq ∈ c.support,
        fun z => c pq • (hermiteL2Family n hn pq : Configuration n → ℂ) z := by
    induction c.support using Finset.induction_on with
    | empty => simpa only [Finset.sum_empty] using
        (Lp.coeFn_zero ℂ 2 (complexGaussianMeasure n))
    | @insert pq s hpq ih =>
        filter_upwards [Lp.coeFn_add
          (c pq • hermiteL2Family n hn pq)
          (∑ x ∈ s, c x • hermiteL2Family n hn x),
          Lp.coeFn_smul (c pq) (hermiteL2Family n hn pq), ih] with z hAdd hSmul hSum
        simp only [Finset.sum_insert hpq]
        rw [hAdd]
        simp only [Pi.add_apply]
        rw [hSmul, hSum]
        simp only [Pi.smul_apply]
  filter_upwards [hcoe, h] with z hcz hz
  unfold Finsupp.sum
  rw [hcz]
  exact hz

private theorem differentiable_multivariateNormalized_real (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) :
    Differentiable ℝ (multivariateNormalized n hn p q) := by
  unfold multivariateNormalized
  let f : Fin n → Configuration n → ℂ :=
    fun i z => normalizedEval n hn (p i) (q i) (z i)
  have hf : ∀ i, Differentiable ℝ (f i) := fun i =>
    (differentiable_normalizedEval n hn (p i) (q i)).comp
      (ContinuousLinearMap.proj i : Configuration n →L[ℝ] ℂ).differentiable
  change Differentiable ℝ (fun z => ∏ i ∈ Finset.univ, f i z)
  induction (Finset.univ : Finset (Fin n)) using Finset.induction_on with
  | empty => simp
  | @insert i s hi ih =>
      rw [show (fun z => ∏ k ∈ insert i s, f k z) =
          f i * fun z => ∏ k ∈ s, f k z by
        funext z
        simp [Finset.prod_insert hi]]
      exact (hf i).mul ih

private theorem dbarComponent_const_mul {n : ℕ} (a : ℂ)
    (f : Configuration n → ℂ) (hf : Differentiable ℝ f)
    (j : Fin n) (z : Configuration n) :
    dbarComponent (fun w => a * f w) j z = a * dbarComponent f j z := by
  unfold dbarComponent
  rw [fderiv_const_mul (hf z)]
  simp only [smul_apply, smul_eq_mul]
  ring

private theorem dbarComponent_finset_sum {n : ℕ} {ι : Type*}
    (s : Finset ι) (f : ι → Configuration n → ℂ)
    (hf : ∀ i ∈ s, Differentiable ℝ (f i)) (j : Fin n) (z : Configuration n) :
    dbarComponent (fun w => ∑ i ∈ s, f i w) j z =
      ∑ i ∈ s, dbarComponent (f i) j z := by
  unfold dbarComponent
  rw [fderiv_fun_sum (fun i hi => hf i hi z)]
  simp only [sum_apply]
  calc
    _ = (∑ i ∈ s, (1 / 2 : ℂ) *
          (fderiv ℝ (f i) z) (realCoordinateDirection j)) +
        ∑ i ∈ s, (1 / 2 : ℂ) * Complex.I *
          (fderiv ℝ (f i) z) (imaginaryCoordinateDirection j) := by
      rw [mul_add, Finset.mul_sum]
      congr 1
      simp_rw [Finset.mul_sum]
      ring
    _ = _ := by
      rw [← Finset.sum_add_distrib]
      apply Finset.sum_congr rfl
      intro i hi
      ring

/-- Pointwise `∂̄` of a finite Hermite expansion is the expansion synthesized
from the collision-safe lowered coefficients. -/
theorem dbarComponent_finiteHermiteFunction (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) (j : Fin n) (z : Configuration n) :
    dbarComponent (finiteHermiteFunction n hn c) j z =
      finiteHermiteFunction n hn (loweredCoefficients n c j) z := by
  classical
  rw [show finiteHermiteFunction n hn c = fun z =>
      c.sum fun pq a => a * multivariateNormalized n hn pq.1 pq.2 z by
    funext w
    simp [finiteHermiteFunction, Finsupp.linearCombination_apply,
      Finsupp.sum, Finset.sum_apply, smul_eq_mul]]
  unfold Finsupp.sum
  rw [dbarComponent_finset_sum]
  · have hsum :
        (∑ pq ∈ c.support,
          dbarComponent
            (fun w => c pq * multivariateNormalized n hn pq.1 pq.2 w) j z) =
        ∑ pq ∈ c.support, c pq *
          (Real.sqrt (n * pq.2 j : ℕ) *
            multivariateNormalized n hn pq.1 (lowerAt pq.2 j) z) := by
      apply Finset.sum_congr rfl
      intro pq hpq
      rw [dbarComponent_const_mul _ _
        ((differentiable_multivariateNormalized_real n hn pq.1 pq.2))]
      rw [dbarComponent_multivariateNormalized]
    rw [hsum]
    simp [finiteHermiteFunction, loweredCoefficients,
      Finsupp.linearCombination_apply, lowerHermiteIndex,
      map_finsuppSum, Finsupp.sum_single_index]
    unfold Finsupp.sum
    rw [Finset.sum_apply]
    apply Finset.sum_congr rfl
    intro pq hpq
    simp only [Pi.smul_apply, smul_eq_mul]
    ring
  · intro pq hpq
    exact (differentiable_multivariateNormalized_real n hn pq.1 pq.2).const_mul _

/-- The Gaussian integral of a coordinate `∂̄` square is the squared norm
of the collision-safe lowered `L²` synthesis. -/
theorem integral_conj_dbarComponent_finiteHermiteFunction_mul (n : ℕ)
    (hn : 0 < n) (c : HermiteMultiIndex n →₀ ℂ) (j : Fin n) :
    ∫ z, conj (dbarComponent (finiteHermiteFunction n hn c) j z) *
        dbarComponent (finiteHermiteFunction n hn c) j z
      ∂complexGaussianMeasure n =
      (‖finiteHermiteCombination n hn (loweredCoefficients n c j)‖ ^ 2 : ℂ) := by
  let u := finiteHermiteCombination n hn (loweredCoefficients n c j)
  calc
    _ = inner ℂ u u := by
      rw [MeasureTheory.L2.inner_def]
      apply integral_congr_ae
      filter_upwards [finiteHermiteCombination_coeFn n hn
        (loweredCoefficients n c j)] with z hz
      rw [hz, ← dbarComponent_finiteHermiteFunction n hn c j z]
      rw [RCLike.inner_apply]
      ring
    _ = _ := inner_self_eq_norm_sq_to_K u

/-- Exact finite Gaussian `∂̄` integral energy identity. -/
theorem finiteGaussianDbarIntegralEnergy (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    (∑ j : Fin n,
      ∫ z, conj (dbarComponent (finiteHermiteFunction n hn c) j z) *
          dbarComponent (finiteHermiteFunction n hn c) j z
        ∂complexGaussianMeasure n) =
      (finiteDbarEnergy c : ℂ) := by
  simp_rw [integral_conj_dbarComponent_finiteHermiteFunction_mul]
  exact_mod_cast sum_norm_sq_lowered_eq_finiteDbarEnergy n hn c

end
end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/HermiteL2Family.lean #
import GinibrePoincare.Analysis.HermiteBinomialIdentity
import GinibrePoincare.Analysis.ComplexGaussianMoments
import Mathlib.Analysis.InnerProductSpace.Projection.Submodule

/-!
# The multivariate Hermite family in Gaussian `L²`

This file packages the normalized Hermite tensors as an orthonormal family,
conditional on the explicit mixed-moment formula.  It also defines the closed
spans and orthogonal projections associated with a fixed total
antiholomorphic degree.  No completeness assertion for the Hermite family is
made here.
-/

open MeasureTheory
open scoped BigOperators ComplexConjugate

namespace GinibrePoincare
namespace ComplexHermite

noncomputable section

/-- The joint pair of holomorphic and antiholomorphic multi-indices. -/
abbrev HermiteMultiIndex (n : ℕ) :=
  (Fin n → ℕ) × (Fin n → ℕ)

/-- The normalized multivariate Hermite family as vectors of Gaussian `L²`. -/
def hermiteL2Family (n : ℕ) (hn : 0 < n) :
    HermiteMultiIndex n → Lp ℂ 2 (complexGaussianMeasure n) :=
  fun pq => (memLp_two_multivariateNormalized n hn pq.1 pq.2).toLp
    (multivariateNormalized n hn pq.1 pq.2)

theorem hermiteL2Family_coeFn (n : ℕ) (hn : 0 < n)
    (pq : HermiteMultiIndex n) :
    hermiteL2Family n hn pq =ᵐ[complexGaussianMeasure n]
      multivariateNormalized n hn pq.1 pq.2 :=
  (memLp_two_multivariateNormalized n hn pq.1 pq.2).coeFn_toLp

/-- The `L²` inner product of two packaged Hermite tensors is their concrete
Gaussian integral. -/
theorem inner_hermiteL2Family_eq_integral (n : ℕ) (hn : 0 < n)
    (a b : HermiteMultiIndex n) :
    inner ℂ (hermiteL2Family n hn a) (hermiteL2Family n hn b) =
      ∫ z, conj (multivariateNormalized n hn a.1 a.2 z) *
          multivariateNormalized n hn b.1 b.2 z
        ∂complexGaussianMeasure n := by
  rw [MeasureTheory.L2.inner_def]
  apply integral_congr_ae
  filter_upwards [hermiteL2Family_coeFn n hn a,
    hermiteL2Family_coeFn n hn b] with z ha hb
  rw [RCLike.inner_apply, ha, hb]
  ring

/-- Under the mixed-moment formula, the packaged multivariate Hermites have
the Kronecker-delta inner products. -/
theorem inner_hermiteL2Family (n : ℕ) (hn : 0 < n)
    (hMom : MixedMomentFormula n) (a b : HermiteMultiIndex n) :
    inner ℂ (hermiteL2Family n hn a) (hermiteL2Family n hn b) =
      if a = b then 1 else 0 := by
  rw [inner_hermiteL2Family_eq_integral,
    multivariate_orthogonality_of_mixedMoments n hn hMom]
  by_cases h : a = b
  · subst b
    simp
  · have hab : ¬(a.1 = b.1 ∧ a.2 = b.2) := by
      intro hpq
      exact h (Prod.ext hpq.1 hpq.2)
    simp [h, hab]

/-- Under the mixed-moment formula, all normalized multivariate Hermite
tensors form an orthonormal indexed family in Gaussian `L²`. -/
theorem orthonormal_hermiteL2Family (n : ℕ) (hn : 0 < n)
    (hMom : MixedMomentFormula n) :
    Orthonormal ℂ (hermiteL2Family n hn) := by
  rw [orthonormal_iff_ite]
  exact inner_hermiteL2Family n hn hMom

/-- The normalized multivariate Hermite family is unconditionally
orthonormal for the concrete Gaussian measure. -/
theorem orthonormal_hermiteL2Family_gaussian (n : ℕ) (hn : 0 < n) :
    Orthonormal ℂ (hermiteL2Family n hn) := by
  apply orthonormal_hermiteL2Family n hn
  intro a b
  rw [show (∫ z : ℂ, z ^ a * (conj z) ^ b
      ∂(complexCoordinateGaussianProbability n : Measure ℂ)) =
      complexGaussianMixedMoment n a b by rfl]
  rw [complexGaussianMixedMoment_formula hn]
  simp [div_eq_mul_inv]

/-- Total antiholomorphic degree of a joint Hermite multi-index. -/
def totalAntiDegree {n : ℕ} (pq : HermiteMultiIndex n) : ℕ :=
  ∑ i, pq.2 i

/-- Algebraic span of normalized Hermites of fixed total antiholomorphic
degree. -/
def hermiteAntiDegreeSpan (n : ℕ) (hn : 0 < n) (d : ℕ) :
    Submodule ℂ (Lp ℂ 2 (complexGaussianMeasure n)) :=
  Submodule.span ℂ
    (hermiteL2Family n hn '' {pq | totalAntiDegree pq = d})

/-- Closed `L²` subspace generated by normalized Hermites of fixed total
antiholomorphic degree. -/
def hermiteAntiDegreeClosedSpan (n : ℕ) (hn : 0 < n) (d : ℕ) :
    ClosedSubmodule ℂ (Lp ℂ 2 (complexGaussianMeasure n)) where
  toSubmodule := (hermiteAntiDegreeSpan n hn d).topologicalClosure
  isClosed' := (hermiteAntiDegreeSpan n hn d).isClosed_topologicalClosure

/-- Orthogonal projection onto the closed span of Hermites having total
antiholomorphic degree `d`. -/
def hermiteAntiDegreeProjection (n : ℕ) (hn : 0 < n) (d : ℕ) :
    Lp ℂ 2 (complexGaussianMeasure n) →L[ℂ]
      Lp ℂ 2 (complexGaussianMeasure n) :=
  (hermiteAntiDegreeClosedSpan n hn d).starProjection

/-- A Hermite tensor of total antiholomorphic degree `d` belongs to the
corresponding closed span. -/
theorem hermiteL2Family_mem_antiDegreeClosedSpan (n : ℕ) (hn : 0 < n)
    (pq : HermiteMultiIndex n) (d : ℕ) (hd : totalAntiDegree pq = d) :
    hermiteL2Family n hn pq ∈ hermiteAntiDegreeClosedSpan n hn d := by
  apply (hermiteAntiDegreeSpan n hn d).le_topologicalClosure
  apply Submodule.subset_span
  exact ⟨pq, hd, rfl⟩

/-- The degree projection fixes each normalized Hermite tensor in that
degree. -/
theorem hermiteAntiDegreeProjection_apply_family (n : ℕ) (hn : 0 < n)
    (pq : HermiteMultiIndex n) (d : ℕ) (hd : totalAntiDegree pq = d) :
    hermiteAntiDegreeProjection n hn d (hermiteL2Family n hn pq) =
      hermiteL2Family n hn pq := by
  exact Submodule.starProjection_eq_self_iff.mpr
    (hermiteL2Family_mem_antiDegreeClosedSpan n hn pq d hd)

end
end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/HermiteMonomialSpan.lean #
import GinibrePoincare.Analysis.ComplexHermiteOrthogonality

/-! # Triangular inversion between complex Hermites and monomials -/

open scoped ComplexConjugate BigOperators

namespace GinibrePoincare
namespace ComplexHermite

noncomputable section

/-- Span of normalized complex Hermite functions whose two indices lie in a
fixed rectangle. -/
def normalizedEvalRectangleSpan (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    Submodule ℂ (ℂ → ℂ) :=
  Submodule.span ℂ {f | ∃ a ≤ p, ∃ b ≤ q, f = normalizedEval n hn a b}

theorem normalizedEval_mem_rectangleSpan (n : ℕ) (hn : 0 < n)
    {p q a b : ℕ} (ha : a ≤ p) (hb : b ≤ q) :
    normalizedEval n hn a b ∈ normalizedEvalRectangleSpan n hn p q := by
  apply Submodule.subset_span
  exact ⟨a, ha, b, hb, rfl⟩

theorem normalizedEvalRectangleSpan_mono (n : ℕ) (hn : 0 < n)
    {p q P Q : ℕ} (hp : p ≤ P) (hq : q ≤ Q) :
    normalizedEvalRectangleSpan n hn p q ≤
      normalizedEvalRectangleSpan n hn P Q := by
  apply Submodule.span_mono
  rintro f ⟨a, ha, b, hb, rfl⟩
  exact ⟨a, ha.trans hp, b, hb.trans hq, rfl⟩

private theorem oneDimNormalization_ne_zero (n : ℕ) (hn : 0 < n) (p : ℕ) :
    oneDimNormalization n p ≠ 0 := by
  unfold oneDimNormalization
  positivity

/-- Every diagonal mixed monomial is in the rectangular span of normalized
complex Hermite functions.  This is the algebraic triangular inversion. -/
theorem mixedMonomial_mem_normalizedEvalRectangleSpan
    (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    (fun z : ℂ ↦ z ^ p * (conj z) ^ q) ∈
      normalizedEvalRectangleSpan n hn p q := by
  induction h : min p q using Nat.strong_induction_on generalizing p q with
  | h m ih =>
      let S := normalizedEvalRectangleSpan n hn p q
      let N : ℂ :=
        ((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ)
      have hN : N ≠ 0 := by
        unfold N
        exact Complex.ofReal_ne_zero.mpr
          (mul_ne_zero (oneDimNormalization_ne_zero n hn p)
            (oneDimNormalization_ne_zero n hn q))
      have hHerm : normalizedEval n hn p q ∈ S :=
        normalizedEval_mem_rectangleSpan n hn le_rfl le_rfl
      let rest : ℂ → ℂ := fun z ↦
        ∑ k ∈ (Finset.range (min p q + 1)).erase 0,
          (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
              (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
            z ^ (p - k) * (conj z) ^ (q - k)
      have hrest : rest ∈ S := by
        rw [show rest = ∑ k ∈ (Finset.range (min p q + 1)).erase 0,
            fun z ↦ (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
              (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
              z ^ (p - k) * (conj z) ^ (q - k) by
          funext z
          simp [rest]]
        apply Submodule.sum_mem
        intro k hk
        have hkRange : k ∈ Finset.range (min p q + 1) :=
          (Finset.mem_erase.mp hk).2
        have hk0 : k ≠ 0 := (Finset.mem_erase.mp hk).1
        have hkpos : 0 < k := Nat.pos_of_ne_zero hk0
        have hk_le : k ≤ min p q := by
          exact Nat.lt_succ_iff.mp (Finset.mem_range.mp hkRange)
        have hkmin : min (p - k) (q - k) < m := by
          omega
        have hlower := ih _ hkmin (p - k) (q - k) (by rfl)
        have hmono : normalizedEvalRectangleSpan n hn (p - k) (q - k) ≤ S :=
          normalizedEvalRectangleSpan_mono n hn (Nat.sub_le _ _) (Nat.sub_le _ _)
        have hsmul := S.smul_mem
          (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
            (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ))
          (hmono hlower)
        convert hsmul using 1
        ext z
        simp [smul_eq_mul]
        ring
      have hexpand : normalizedEval n hn p q =
          fun z ↦ N * (z ^ p * (conj z) ^ q + rest z) := by
        funext z
        rw [normalizedEval_eq_sum]
        change N * _ = _
        congr 1
        have hzero : 0 ∈ Finset.range (min p q + 1) := by simp
        rw [← Finset.sum_erase_add _ _ hzero]
        simp [rest]
      have hsum : (fun z ↦ N * (z ^ p * (conj z) ^ q + rest z)) ∈ S := by
        rw [← hexpand]
        exact hHerm
      have hscaled : (fun z ↦ N * (z ^ p * (conj z) ^ q)) ∈ S := by
        have := S.sub_mem hsum (S.smul_mem N hrest)
        convert this using 1
        ext z
        simp
        ring
      have := S.smul_mem N⁻¹ hscaled
      convert this using 1
      ext z
      simp [hN]

/-- Rectangular span of ordinary diagonal mixed monomials. -/
def mixedMonomialRectangleSpan (p q : ℕ) : Submodule ℂ (ℂ → ℂ) :=
  Submodule.span ℂ {f | ∃ a ≤ p, ∃ b ≤ q,
    f = fun z : ℂ ↦ z ^ a * (conj z) ^ b}

theorem mixedMonomialRectangleSpan_mono {p q P Q : ℕ}
    (hp : p ≤ P) (hq : q ≤ Q) :
    mixedMonomialRectangleSpan p q ≤ mixedMonomialRectangleSpan P Q := by
  apply Submodule.span_mono
  rintro f ⟨a, ha, b, hb, rfl⟩
  exact ⟨a, ha.trans hp, b, hb.trans hq, rfl⟩

theorem normalizedEval_mem_mixedMonomialRectangleSpan
    (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    normalizedEval n hn p q ∈ mixedMonomialRectangleSpan p q := by
  rw [show normalizedEval n hn p q = fun z ↦
      ((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ) *
        ∑ k ∈ Finset.range (min p q + 1),
          (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
              (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
            z ^ (p - k) * (conj z) ^ (q - k) by
    funext z
    exact normalizedEval_eq_sum n hn p q z]
  have hsum : (fun z : ℂ ↦
      ∑ k ∈ Finset.range (min p q + 1),
        (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
            (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
          z ^ (p - k) * (conj z) ^ (q - k)) ∈
      mixedMonomialRectangleSpan p q := by
    rw [show (fun z : ℂ ↦ ∑ k ∈ Finset.range (min p q + 1),
        (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
          (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
          z ^ (p-k) * (conj z) ^ (q-k)) =
        ∑ k ∈ Finset.range (min p q + 1), fun z : ℂ ↦
          (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
            (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
            z ^ (p-k) * (conj z) ^ (q-k) by funext z; simp]
    apply Submodule.sum_mem
    intro k hk
    have hm : (fun z : ℂ ↦ z ^ (p-k) * (conj z) ^ (q-k)) ∈
        mixedMonomialRectangleSpan p q := by
      apply Submodule.subset_span
      exact ⟨p-k, Nat.sub_le _ _, q-k, Nat.sub_le _ _, rfl⟩
    have hs := (mixedMonomialRectangleSpan p q).smul_mem
      (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
        (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) hm
    convert hs using 1
    ext z
    simp [smul_eq_mul]
    ring
  have hs := (mixedMonomialRectangleSpan p q).smul_mem
    (((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ)) hsum
  convert hs using 1
  ext z
  simp [smul_eq_mul]

theorem normalizedEvalRectangleSpan_eq_mixedMonomialRectangleSpan
    (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    normalizedEvalRectangleSpan n hn p q = mixedMonomialRectangleSpan p q := by
  apply le_antisymm
  · apply Submodule.span_le.2
    rintro f ⟨a, ha, b, hb, rfl⟩
    exact (mixedMonomialRectangleSpan_mono ha hb)
      (normalizedEval_mem_mixedMonomialRectangleSpan n hn a b)
  · apply Submodule.span_le.2
    rintro f ⟨a, ha, b, hb, rfl⟩
    exact (normalizedEvalRectangleSpan_mono n hn ha hb)
      (mixedMonomial_mem_normalizedEvalRectangleSpan n hn a b)

end
end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/HermiteOrthogonalityCombinatorics.lean #
import GinibrePoincare.Analysis.MultivariateHermiteIntegrability

/-!
# Moment expansion for complex-Hermite orthogonality

This module isolates the exact finite combinatorics produced by the mixed
moments of a rotationally invariant complex Gaussian.  It introduces no
orthogonality assumption: the sole input is the value of every mixed
monomial moment.
-/

open MeasureTheory
open scoped BigOperators ComplexConjugate

namespace GinibrePoincare
namespace ComplexHermite

noncomputable section

/-- The exact mixed-moment formula for a centered complex Gaussian of
precision `n`. -/
def MixedMomentFormula (n : ℕ) : Prop :=
  ∀ a b : ℕ,
    ∫ z : ℂ, z ^ a * (conj z) ^ b
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) =
      if a = b then (a.factorial : ℂ) * ((n : ℂ)⁻¹) ^ a else 0

/-- Coefficient of the `k`th monomial in the raw Hermite polynomial of
bidegree `(p,q)` and precision `n`. -/
def diagonalRawCoeff (n p q k : ℕ) : ℂ :=
  (-((n : ℝ)⁻¹ : ℂ)) ^ k * (k.factorial : ℂ) *
    (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)

/-- The explicit finite double sum to which a normalized Hermite inner
product reduces under the mixed-moment formula. -/
def hermiteInnerMomentSum (n p q r s : ℕ) : ℂ :=
  ∑ k ∈ Finset.range (min p q + 1),
    ∑ l ∈ Finset.range (min r s + 1),
      conj (diagonalRawCoeff n p q k) * diagonalRawCoeff n r s l *
        (if (q - k) + (r - l) = (p - k) + (s - l) then
          ((((q - k) + (r - l)).factorial : ℂ) *
            ((n : ℂ)⁻¹) ^ ((q - k) + (r - l)))
        else 0)

/-- Rigorous finite-sum expansion of a normalized one-coordinate Hermite
inner product from the values of all mixed monomial moments. -/
theorem normalizedEval_inner_eq_momentSum_of_mixedMoments
    (n : ℕ) (hn : 0 < n) (hMom : MixedMomentFormula n)
    (p q r s : ℕ) :
    ∫ z : ℂ, conj (normalizedEval n hn p q z) *
        normalizedEval n hn r s z
      ∂(complexCoordinateGaussianProbability n : Measure ℂ) =
      (((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ) *
        ((oneDimNormalization n r * oneDimNormalization n s : ℝ) : ℂ)) *
        hermiteInnerMomentSum n p q r s := by
  rw [show (fun z : ℂ => conj (normalizedEval n hn p q z) *
      normalizedEval n hn r s z) =
      fun z =>
        (((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ) *
          ((oneDimNormalization n r * oneDimNormalization n s : ℝ) : ℂ)) *
          ∑ k ∈ Finset.range (min p q + 1),
            ∑ l ∈ Finset.range (min r s + 1),
              (conj (diagonalRawCoeff n p q k) * diagonalRawCoeff n r s l) *
                (z ^ ((q - k) + (r - l)) *
                  (conj z) ^ ((p - k) + (s - l))) by
    funext z
    rw [normalizedEval_eq_sum, normalizedEval_eq_sum]
    simp only [map_mul, map_sum, map_pow, starRingEnd_apply]
    simp_rw [Finset.mul_sum, Finset.sum_mul, pow_add]
    rw [Finset.sum_comm]
    apply Finset.sum_congr rfl
    intro k hk
    apply Finset.sum_congr rfl
    intro l hl
    simp [diagonalRawCoeff]
    ring]
  rw [integral_const_mul]
  congr 1
  unfold hermiteInnerMomentSum
  rw [integral_finsetSum]
  · apply Finset.sum_congr rfl
    intro k hk
    rw [integral_finsetSum]
    · apply Finset.sum_congr rfl
      intro l hl
      rw [integral_const_mul, hMom]
    · intro l hl
      exact (integrable_complex_monomial_complexCoordinateGaussianProbability n
        ((q - k) + (r - l)) ((p - k) + (s - l))).const_mul _
  · intro k hk
    exact integrable_finsetSum (Finset.range (min r s + 1)) fun l hl =>
      (integrable_complex_monomial_complexCoordinateGaussianProbability n
        ((q - k) + (r - l)) ((p - k) + (s - l))).const_mul _

/-- If the one-coordinate moment sums have been combinatorially evaluated,
the already-proved Fubini factorization immediately yields multivariate
orthogonality.  This theorem records that final tensor-product step. -/
theorem multivariate_orthogonality_of_oneCoordinate
    (n : ℕ) (hn : 0 < n)
    (horth : ∀ p q r s : ℕ,
      ∫ z : ℂ, conj (normalizedEval n hn p q z) *
          normalizedEval n hn r s z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) =
        if p = r ∧ q = s then 1 else 0)
    (p q r s : Fin n → ℕ) :
    ∫ z, conj (multivariateNormalized n hn p q z) *
        multivariateNormalized n hn r s z ∂complexGaussianMeasure n =
      if p = r ∧ q = s then 1 else 0 := by
  rw [integral_conj_multivariateNormalized_mul_eq_prod]
  simp_rw [horth]
  by_cases hp : p = r
  · subst r
    by_cases hq : q = s
    · subst s
      simp
    · simp only [true_and, if_neg hq]
      obtain ⟨j, hj⟩ := Function.ne_iff.mp hq
      exact Finset.prod_eq_zero (Finset.mem_univ j) (if_neg hj)
  · rw [if_neg (by simp [hp])]
    obtain ⟨j, hj⟩ := Function.ne_iff.mp hp
    exact Finset.prod_eq_zero (Finset.mem_univ j) (if_neg (by simp [hj]))

end
end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/HermiteParsevalModes.lean #
import GinibrePoincare.Analysis.GaussianFourierUniqueness
import GinibrePoincare.Analysis.PermutationLp
import GinibrePoincare.Analysis.HolomorphicVandermondeL2Closure

/-! # Hermite antiholomorphic-degree modes in Gaussian L² -/

open MeasureTheory
open scoped BigOperators ENNReal

namespace GinibrePoincare

noncomputable section

open ComplexHermite

/-- Hermite coefficient of a Gaussian `L²` vector. -/
def gaussianHermiteCoefficient {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) (pq : HermiteMultiIndex n) : ℂ :=
  (gaussianHermiteHilbertBasis n hn).repr g pq

theorem gaussianHermiteCoefficient_eq_inner {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) (pq : HermiteMultiIndex n) :
    gaussianHermiteCoefficient hn g pq =
      inner ℂ (multivariateNormalizedL2 n hn pq.1 pq.2) g := by
  rw [gaussianHermiteCoefficient, HilbertBasis.repr_apply_apply]
  congr 1
  exact gaussianHermiteHilbertBasis_apply n hn pq

/-- The summand of `g` whose joint Hermite index has antiholomorphic degree `d`. -/
def gaussianHermiteModeTerm {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) (d : ℕ)
    (pq : HermiteMultiIndex n) : Lp ℂ 2 (complexGaussianMeasure n) :=
  if totalAntiDegree pq = d then
    gaussianHermiteCoefficient hn g pq • multivariateNormalizedL2 n hn pq.1 pq.2
  else 0

theorem summable_gaussianHermiteModeTerm {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) (d : ℕ) :
    Summable (gaussianHermiteModeTerm hn g d) := by
  have hs := (gaussianHermiteHilbertBasis n hn).hasSum_repr g
  refine (hs.summable.indicator (s := {pq | totalAntiDegree pq = d})).congr ?_
  intro pq
  simp only [gaussianHermiteModeTerm, Set.indicator, Set.mem_setOf_eq]
  split_ifs with h
  · rw [gaussianHermiteCoefficient, gaussianHermiteHilbertBasis_apply]
  · rfl

/-- The antiholomorphic-degree `d` Hermite mode of `g`. -/
def gaussianHermiteMode {n : ℕ} (hn : 0 < n)
    (d : ℕ) (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    Lp ℂ 2 (complexGaussianMeasure n) :=
  ∑' pq, gaussianHermiteModeTerm hn g d pq

theorem gaussianHermiteMode_mem_closedSpan {n : ℕ} (hn : 0 < n)
    (d : ℕ) (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianHermiteMode hn d g ∈ hermiteAntiDegreeClosedSpan n hn d := by
  apply (hermiteAntiDegreeClosedSpan n hn d).isClosed'.mem_of_tendsto
    (summable_gaussianHermiteModeTerm hn g d).hasSum
  filter_upwards with s
  apply Submodule.sum_mem
  intro pq hpq
  unfold gaussianHermiteModeTerm
  split_ifs with h
  · exact (hermiteAntiDegreeClosedSpan n hn d).smul_mem _
      (hermiteL2Family_mem_antiDegreeClosedSpan n hn pq d h)
  · exact (hermiteAntiDegreeClosedSpan n hn d).zero_mem

/-- The antiholomorphic-degree modes sum to the original Gaussian `L²` vector. -/
theorem hasSum_gaussianHermiteMode {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    HasSum (fun d ↦ gaussianHermiteMode hn d g) g := by
  let F : HermiteMultiIndex n → Lp ℂ 2 (complexGaussianMeasure n) :=
    fun pq ↦ gaussianHermiteCoefficient hn g pq •
      multivariateNormalizedL2 n hn pq.1 pq.2
  have hF : HasSum F g := by
    simpa [F, gaussianHermiteCoefficient] using
      (gaussianHermiteHilbertBasis n hn).hasSum_repr g
  let e := Equiv.sigmaFiberEquiv (@totalAntiDegree n)
  have hsigma : HasSum (F ∘ e) g := (e.hasSum_iff).2 hF
  apply hsigma.sigma
  intro d
  have hsub : Summable (F ∘ fun pq : {pq // totalAntiDegree pq = d} ↦ pq.1) :=
    hF.summable.subtype (fun pq ↦ totalAntiDegree pq = d)
  have hmode : gaussianHermiteMode hn d g =
      ∑' pq : {pq // totalAntiDegree pq = d}, F pq.1 := by
    rw [gaussianHermiteMode]
    calc
      (∑' pq, gaussianHermiteModeTerm hn g d pq) =
          ∑' pq, {pq | totalAntiDegree pq = d}.indicator F pq := by
            apply tsum_congr
            intro pq
            simp [gaussianHermiteModeTerm, F, Set.indicator]
      _ = ∑' pq : {pq // totalAntiDegree pq = d}, F pq.1 :=
        (tsum_subtype {pq | totalAntiDegree pq = d} F).symm
  rw [hmode]
  apply hsub.hasSum.congr_fun
  intro c
  rfl

theorem tsum_gaussianHermiteMode {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    ∑' d, gaussianHermiteMode hn d g = g :=
  (hasSum_gaussianHermiteMode hn g).tsum_eq

theorem inner_gaussianHermiteMode_eq_zero {n : ℕ} (hn : 0 < n)
    {d e : ℕ} (hde : d ≠ e)
    (g h : Lp ℂ 2 (complexGaussianMeasure n)) :
    inner ℂ (gaussianHermiteMode hn d g) (gaussianHermiteMode hn e h) = 0 := by
  have hterm (p q : HermiteMultiIndex n) :
      inner ℂ (gaussianHermiteModeTerm hn g d p)
        (gaussianHermiteModeTerm hn h e q) = 0 := by
    unfold gaussianHermiteModeTerm
    split_ifs with hp hq
    · have hpq : p ≠ q := by
        intro hpq
        subst q
        exact hde (hp.symm.trans hq)
      rw [inner_smul_left, inner_smul_right]
      have ho := (gaussianHermiteHilbertBasis n hn).orthonormal.inner_eq_zero hpq
      rw [gaussianHermiteHilbertBasis_apply, gaussianHermiteHilbertBasis_apply] at ho
      simp [ho]
    all_goals simp
  have htermMode (p : HermiteMultiIndex n) :
      inner ℂ (gaussianHermiteModeTerm hn g d p)
        (gaussianHermiteMode hn e h) = 0 := by
    rw [gaussianHermiteMode]
    change innerSL ℂ (gaussianHermiteModeTerm hn g d p)
      (∑' pq, gaussianHermiteModeTerm hn h e pq) = 0
    rw [(innerSL ℂ (gaussianHermiteModeTerm hn g d p)).map_tsum
        (summable_gaussianHermiteModeTerm hn h e)]
    simp_rw [innerSL_apply_apply, hterm p]
    exact tsum_zero
  rw [gaussianHermiteMode]
  change innerSLFlip ℂ (gaussianHermiteMode hn e h)
    (∑' pq, gaussianHermiteModeTerm hn g d pq) = 0
  rw [(innerSLFlip ℂ (gaussianHermiteMode hn e h)).map_tsum
      (summable_gaussianHermiteModeTerm hn g d)]
  simp_rw [innerSLFlip_apply_apply, htermMode]
  exact tsum_zero

theorem inner_gaussianHermiteMode_self_sum {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) (d : ℕ) :
    inner ℂ g (gaussianHermiteMode hn d g) =
      inner ℂ (gaussianHermiteMode hn d g) (gaussianHermiteMode hn d g) := by
  calc
    inner ℂ g (gaussianHermiteMode hn d g) =
        inner ℂ (∑' e, gaussianHermiteMode hn e g)
          (gaussianHermiteMode hn d g) := by rw [tsum_gaussianHermiteMode]
    _ = ∑' e, inner ℂ (gaussianHermiteMode hn e g)
          (gaussianHermiteMode hn d g) := by
      change innerSLFlip ℂ (gaussianHermiteMode hn d g)
        (∑' e, gaussianHermiteMode hn e g) = _
      rw [(innerSLFlip ℂ (gaussianHermiteMode hn d g)).map_tsum
        (hasSum_gaussianHermiteMode hn g).summable]
      simp_rw [innerSLFlip_apply_apply]
    _ = inner ℂ (gaussianHermiteMode hn d g)
          (gaussianHermiteMode hn d g) := by
      rw [tsum_eq_single d]
      · intro e hed
        exact inner_gaussianHermiteMode_eq_zero hn hed g g

/-- Parseval's identity for the antiholomorphic-degree decomposition. -/
theorem hasSum_norm_sq_gaussianHermiteMode {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    HasSum (fun d ↦ ‖gaussianHermiteMode hn d g‖ ^ 2) (‖g‖ ^ 2) := by
  have hs := (hasSum_gaussianHermiteMode hn g).mapL (innerSL ℂ g)
  have hs' : HasSum
      (fun d ↦ inner ℂ g (gaussianHermiteMode hn d g)) (inner ℂ g g) := by
    simpa only [innerSL_apply_apply] using hs
  have hcomplex : HasSum
      (fun d ↦ (‖gaussianHermiteMode hn d g‖ : ℂ) ^ 2)
      ((‖g‖ : ℂ) ^ 2) := by
    convert hs' using 1
    · funext d
      rw [inner_gaussianHermiteMode_self_sum hn g d, inner_self_eq_norm_sq_to_K]
      norm_cast
    · rw [inner_self_eq_norm_sq_to_K]
      norm_cast
  convert hcomplex.mapL Complex.reCLM using 1
  · funext d
    norm_cast
  · norm_cast

theorem tsum_norm_sq_gaussianHermiteMode {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    ∑' d, ‖gaussianHermiteMode hn d g‖ ^ 2 = ‖g‖ ^ 2 :=
  (hasSum_norm_sq_gaussianHermiteMode hn g).tsum_eq

/-- Squared mass of the positive antiholomorphic mode indexed from zero,
so that entry `k` is the mass of mode `k + 1`. -/
def positiveHermiteModeMass {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) (k : ℕ) : ℝ :=
  ‖gaussianHermiteMode hn (k + 1) g‖ ^ 2

theorem summable_positiveHermiteModeMass {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    Summable (positiveHermiteModeMass hn g) := by
  unfold positiveHermiteModeMass
  exact (hasSum_norm_sq_gaussianHermiteMode hn g).summable.comp_injective
    Nat.succ_injective

/-- Parseval split into the zero antiholomorphic mode and all strictly
positive modes, in exactly the indexing used by the deficit series. -/
theorem norm_sq_eq_zeroMode_add_positiveModeMass {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    ‖g‖ ^ 2 = ‖gaussianHermiteMode hn 0 g‖ ^ 2 +
      ∑' k, positiveHermiteModeMass hn g k := by
  let a : ℕ → ℝ := fun d => ‖gaussianHermiteMode hn d g‖ ^ 2
  have hs : HasSum a (‖g‖ ^ 2) := hasSum_norm_sq_gaussianHermiteMode hn g
  have htail : HasSum (fun k => a (k + 1)) (‖g‖ ^ 2 - a 0) := by
    simpa using (hasSum_nat_add_iff' 1).2 hs
  calc
    ‖g‖ ^ 2 = a 0 + (‖g‖ ^ 2 - a 0) := by ring
    _ = a 0 + ∑' k, a (k + 1) := by rw [htail.tsum_eq]
    _ = _ := rfl

theorem inner_basis_gaussianHermiteMode {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) (d : ℕ)
    (pq : HermiteMultiIndex n) :
    inner ℂ (multivariateNormalizedL2 n hn pq.1 pq.2)
      (gaussianHermiteMode hn d g) =
      if totalAntiDegree pq = d then gaussianHermiteCoefficient hn g pq else 0 := by
  rw [gaussianHermiteMode]
  change innerSL ℂ (multivariateNormalizedL2 n hn pq.1 pq.2)
    (∑' r, gaussianHermiteModeTerm hn g d r) = _
  rw [(innerSL ℂ (multivariateNormalizedL2 n hn pq.1 pq.2)).map_tsum
    (summable_gaussianHermiteModeTerm hn g d)]
  simp_rw [innerSL_apply_apply]
  rw [tsum_eq_single pq]
  · unfold gaussianHermiteModeTerm
    split_ifs with hp
    · rw [inner_smul_right]
      have hone := (gaussianHermiteHilbertBasis n hn).orthonormal.1 pq
      rw [gaussianHermiteHilbertBasis_apply] at hone
      rw [inner_self_eq_norm_sq_to_K]
      simp [hone]
    · simp
  · intro r hr
    unfold gaussianHermiteModeTerm
    split_ifs
    · rw [inner_smul_right]
      have ho := (gaussianHermiteHilbertBasis n hn).orthonormal.inner_eq_zero hr.symm
      rw [gaussianHermiteHilbertBasis_apply, gaussianHermiteHilbertBasis_apply] at ho
      simp [ho]
    · simp

theorem gaussianHermiteMode_eq_antiDegreeProjection {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) (d : ℕ) :
    gaussianHermiteMode hn d g = hermiteAntiDegreeProjection n hn d g := by
  symm
  apply Submodule.eq_starProjection_of_mem_of_inner_eq_zero
    (gaussianHermiteMode_mem_closedSpan hn d g)
  intro w hw
  rw [inner_sub_left]
  have hspan : ∀ x ∈ hermiteAntiDegreeSpan n hn d,
      inner ℂ (g - gaussianHermiteMode hn d g) x = 0 := by
    intro x hx
    induction hx using Submodule.span_induction with
    | mem x hx =>
        rcases hx with ⟨pq, hpq, rfl⟩
        change totalAntiDegree pq = d at hpq
        change inner ℂ (g - gaussianHermiteMode hn d g)
          (multivariateNormalizedL2 n hn pq.1 pq.2) = 0
        rw [inner_sub_left]
        have hg : inner ℂ g (multivariateNormalizedL2 n hn pq.1 pq.2) =
            (starRingEnd ℂ) (gaussianHermiteCoefficient hn g pq) := by
          calc
            _ = (starRingEnd ℂ)
                (inner ℂ (multivariateNormalizedL2 n hn pq.1 pq.2) g) :=
              (inner_conj_symm _ _).symm
            _ = _ := by rw [← gaussianHermiteCoefficient_eq_inner]
        have hm : inner ℂ (gaussianHermiteMode hn d g)
            (multivariateNormalizedL2 n hn pq.1 pq.2) =
            (starRingEnd ℂ) (gaussianHermiteCoefficient hn g pq) := by
          rw [← inner_conj_symm,
            inner_basis_gaussianHermiteMode hn g d pq, if_pos hpq]
        rw [hg, hm, sub_self]
    | zero => simp
    | add x y hx hy ihx ihy => simp [inner_add_right, ihx, ihy]
    | smul c x hx ih => simp [inner_smul_right, ih]
  have hz := closure_minimal hspan
    (isClosed_eq (continuous_const.inner continuous_id) continuous_const) hw
  change inner ℂ (g - gaussianHermiteMode hn d g) w = 0 at hz
  simpa only [inner_sub_left] using hz

theorem gaussianPermutationL2_mem_antiDegreeClosedSpan {n : ℕ} (hn : 0 < n)
    (d : ℕ) (σ : ParticlePermutation n)
    {u : Lp ℂ 2 (complexGaussianMeasure n)}
    (hu : u ∈ hermiteAntiDegreeClosedSpan n hn d) :
    gaussianPermutationL2 σ u ∈ hermiteAntiDegreeClosedSpan n hn d := by
  exact (Set.MapsTo.closure
    (fun x hx ↦ gaussianPermutationL2_mem_hermiteAntiDegreeSpan n hn d σ hx)
    (gaussianPermutationL2 σ).continuous) hu

theorem totalAntiDegree_comp_permutation_symm {n : ℕ}
    (σ : ParticlePermutation n) (p q : Fin n → ℕ) :
    totalAntiDegree (p ∘ σ.symm, q ∘ σ.symm) = totalAntiDegree (p, q) := by
  change (∑ i, q (σ.symm i)) = ∑ i, q i
  exact Equiv.sum_comp σ.symm q

theorem gaussianPermutationL2_multivariateNormalizedL2 {n : ℕ} (hn : 0 < n)
    (σ : ParticlePermutation n) (p q : Fin n → ℕ) :
    gaussianPermutationL2 σ (multivariateNormalizedL2 n hn p q) =
      multivariateNormalizedL2 n hn (p ∘ σ.symm) (q ∘ σ.symm) := by
  exact gaussianPermutationL2_hermiteL2Family n hn σ p q

private theorem gaussianPermutationL2_one {n : ℕ}
    (u : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianPermutationL2 (1 : ParticlePermutation n) u = u := by
  apply Lp.ext
  filter_upwards [Lp.coeFn_compMeasurePreserving u
    (gaussian_measurePreserving_permute (1 : ParticlePermutation n))] with z hz
  unfold gaussianPermutationL2
  change (Lp.compMeasurePreserving (permute (1 : ParticlePermutation n))
    (gaussian_measurePreserving_permute (1 : ParticlePermutation n)) u) z = u z
  rw [hz]
  rfl

theorem gaussianPermutationL2_comm_antiDegreeProjection {n : ℕ} (hn : 0 < n)
    (d : ℕ) (σ : ParticlePermutation n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianPermutationL2 σ (hermiteAntiDegreeProjection n hn d g) =
      hermiteAntiDegreeProjection n hn d (gaussianPermutationL2 σ g) := by
  let U : Submodule ℂ (Lp ℂ 2 (complexGaussianMeasure n)) :=
    hermiteAntiDegreeClosedSpan n hn d
  let T := gaussianPermutationL2 σ
  have hmap : U.map T.toLinearMap = U := by
    apply le_antisymm
    · rintro y ⟨x, hx, rfl⟩
      exact gaussianPermutationL2_mem_antiDegreeClosedSpan hn d σ hx
    · intro y hy
      refine ⟨gaussianPermutationL2 σ.symm y,
        gaussianPermutationL2_mem_antiDegreeClosedSpan hn d σ.symm hy, ?_⟩
      change gaussianPermutationL2 σ (gaussianPermutationL2 σ.symm y) = y
      rw [gaussianPermutationL2_comp_apply]
      change gaussianPermutationL2 (σ * σ⁻¹) y = y
      rw [mul_inv_cancel, gaussianPermutationL2_one]
  letI : (U.map T.toLinearMap).HasOrthogonalProjection := hmap.symm ▸ inferInstance
  calc
    T (U.starProjection g) = (U.map T.toLinearMap).starProjection (T g) :=
      T.map_starProjection U g
    _ = U.starProjection (T g) := by simpa only [hmap]

theorem gaussianPermutationL2_comm_gaussianHermiteMode {n : ℕ} (hn : 0 < n)
    (d : ℕ) (σ : ParticlePermutation n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianPermutationL2 σ (gaussianHermiteMode hn d g) =
      gaussianHermiteMode hn d (gaussianPermutationL2 σ g) := by
  rw [gaussianHermiteMode_eq_antiDegreeProjection,
    gaussianHermiteMode_eq_antiDegreeProjection,
    gaussianPermutationL2_comm_antiDegreeProjection]

theorem gaussianHermiteMode_mem_alternating {n : ℕ} (hn : 0 < n)
    (d : ℕ) {g : Lp ℂ 2 (complexGaussianMeasure n)}
    (hg : g ∈ gaussianAlternatingL2 n) :
    gaussianHermiteMode hn d g ∈ gaussianAlternatingL2 n := by
  intro σ
  rw [gaussianPermutationL2_comm_gaussianHermiteMode, hg σ,
    gaussianHermiteMode_eq_antiDegreeProjection, map_smul]
  rw [← gaussianHermiteMode_eq_antiDegreeProjection]

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/HermiteWeightedEnergy.lean #
import GinibrePoincare.Analysis.HermiteParsevalModes
import GinibrePoincare.Analysis.HermiteEnergy
import GinibrePoincare.Analysis.GaussianDbarParseval

open MeasureTheory
open scoped BigOperators ENNReal

namespace GinibrePoincare

noncomputable section

open ComplexHermite


/-- Parseval written directly in terms of Hermite coefficients. -/
theorem hasSum_norm_sq_gaussianHermiteCoefficient {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    HasSum (fun pq : HermiteMultiIndex n => ‖gaussianHermiteCoefficient hn g pq‖ ^ 2)
      (‖g‖ ^ 2) := by
  have hnorm : ‖(gaussianHermiteHilbertBasis n hn).repr g‖ ^ 2 = ‖g‖ ^ 2 := by
    rw [(gaussianHermiteHilbertBasis n hn).repr.norm_map]
  have htsum := lp.norm_rpow_eq_tsum
    (f := (gaussianHermiteHilbertBasis n hn).repr g) (by norm_num)
  have heq : (∑' pq : HermiteMultiIndex n,
      ‖gaussianHermiteCoefficient hn g pq‖ ^ 2) = ‖g‖ ^ 2 := by
    rw [← hnorm]
    simpa [gaussianHermiteCoefficient] using htsum.symm
  have hs := lp.hasSum_norm (f := (gaussianHermiteHilbertBasis n hn).repr g)
    (by norm_num)
  convert hs using 1
  · funext pq
    simp [gaussianHermiteCoefficient]
  · norm_num

/-- Raising one antiholomorphic coordinate parametrizes exactly the indices
whose corresponding coordinate is positive. -/
def raiseHermiteIndexEquivPositive {n : ℕ} (j : Fin n) :
    HermiteMultiIndex n ≃ {r : HermiteMultiIndex n // 0 < r.2 j} where
  toFun pq := ⟨raiseHermiteIndex j pq, by simp [raiseHermiteIndex, raiseAt]⟩
  invFun r := lowerHermiteIndex j r.1
  left_inv pq := by
    apply Prod.ext
    · rfl
    · funext k
      by_cases hkj : k = j
      · subst k
        simp [raiseHermiteIndex, lowerHermiteIndex, raiseAt, lowerAt]
      · simp [raiseHermiteIndex, lowerHermiteIndex, raiseAt, lowerAt]
  right_inv r := by
    apply Subtype.ext
    exact raiseHermiteIndex_lowerHermiteIndex j r.1 r.2

/-- The squared norm of one anti-degree mode is exactly the coefficient
mass on the corresponding fiber. -/
theorem hasSum_coefficient_norm_sq_of_totalAntiDegree {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) (d : ℕ) :
    HasSum (fun pq : {pq : HermiteMultiIndex n // totalAntiDegree pq = d} =>
      ‖gaussianHermiteCoefficient hn g pq.1‖ ^ 2)
      (‖gaussianHermiteMode hn d g‖ ^ 2) := by
  have hs := hasSum_norm_sq_gaussianHermiteCoefficient hn
    (gaussianHermiteMode hn d g)
  have hi := hs.summable.subtype (fun pq : HermiteMultiIndex n =>
    totalAntiDegree pq = d)
  have hterm (pq : {pq : HermiteMultiIndex n // totalAntiDegree pq = d}) :
      ‖gaussianHermiteCoefficient hn (gaussianHermiteMode hn d g) pq.1‖ ^ 2 =
        ‖gaussianHermiteCoefficient hn g pq.1‖ ^ 2 := by
    rw [gaussianHermiteCoefficient_eq_inner,
      inner_basis_gaussianHermiteMode hn g d pq.1, if_pos pq.2]
  have htotal : (∑' pq : {pq : HermiteMultiIndex n // totalAntiDegree pq = d},
      ‖gaussianHermiteCoefficient hn (gaussianHermiteMode hn d g) pq.1‖ ^ 2) =
      ‖gaussianHermiteMode hn d g‖ ^ 2 := by
    let f : HermiteMultiIndex n → ℝ := fun pq =>
      ‖gaussianHermiteCoefficient hn (gaussianHermiteMode hn d g) pq‖ ^ 2
    change (∑' pq : ↥({pq : HermiteMultiIndex n | totalAntiDegree pq = d} :
      Set (HermiteMultiIndex n)), f pq.1) = _
    rw [tsum_subtype {pq | totalAntiDegree pq = d} f]
    rw [← hs.tsum_eq]
    apply tsum_congr
    intro pq
    simp only [Set.indicator, Set.mem_ofPred_eq]
    split_ifs with hpq
    · rfl
    · rw [gaussianHermiteCoefficient_eq_inner,
        inner_basis_gaussianHermiteMode hn g d pq, if_neg hpq]
      simp
  have hsTarget : Summable (fun pq : {pq : HermiteMultiIndex n //
      totalAntiDegree pq = d} => ‖gaussianHermiteCoefficient hn g pq.1‖ ^ 2) :=
    hi.congr (fun pq => hterm pq)
  convert hsTarget.hasSum using 1
  rw [← htotal]
  apply tsum_congr
  exact fun pq => hterm pq

/-- One coordinate of the raising identity gives the corresponding weighted
coefficient mass. -/
theorem hasSum_coordinate_weighted_gaussianHermiteCoefficient {n : ℕ}
    (hn : 0 < n) (g D : Lp ℂ 2 (complexGaussianMeasure n)) (j : Fin n)
    (hcoeff : ∀ pq : HermiteMultiIndex n,
      gaussianHermiteCoefficient hn D pq =
        (Real.sqrt (n * (pq.2 j + 1) : ℕ) : ℂ) *
          gaussianHermiteCoefficient hn g (raiseHermiteIndex j pq)) :
    HasSum (fun r : HermiteMultiIndex n =>
      (n * r.2 j : ℕ) * ‖gaussianHermiteCoefficient hn g r‖ ^ 2)
      (‖D‖ ^ 2) := by
  have hsD := hasSum_norm_sq_gaussianHermiteCoefficient hn D
  have hsRaise : HasSum (fun pq : HermiteMultiIndex n =>
      (n * (pq.2 j + 1) : ℕ) *
        ‖gaussianHermiteCoefficient hn g (raiseHermiteIndex j pq)‖ ^ 2)
      (‖D‖ ^ 2) := by
    apply hsD.congr_fun
    intro pq
    rw [hcoeff pq, norm_mul, mul_pow]
    have hnonneg : (0 : ℝ) ≤ n * (pq.2 j + 1) := by positivity
    rw [Complex.norm_real, Real.norm_eq_abs, abs_of_nonneg (Real.sqrt_nonneg _),
      Real.sq_sqrt (by exact_mod_cast hnonneg)]
  let e := raiseHermiteIndexEquivPositive j
  let f : {r : HermiteMultiIndex n // 0 < r.2 j} → ℝ := fun r =>
    (n * r.1.2 j : ℕ) * ‖gaussianHermiteCoefficient hn g r.1‖ ^ 2
  have hsSub : HasSum f (‖D‖ ^ 2) := by
    apply (e.hasSum_iff).1
    convert hsRaise using 1
    funext pq
    simp [e, f, raiseHermiteIndexEquivPositive, raiseHermiteIndex, raiseAt]
  let F : HermiteMultiIndex n → ℝ := fun r =>
    (n * r.2 j : ℕ) * ‖gaussianHermiteCoefficient hn g r‖ ^ 2
  have hsInd : Summable (({r : HermiteMultiIndex n | 0 < r.2 j} :
      Set (HermiteMultiIndex n)).indicator F) :=
    summable_subtype_iff_indicator.mp hsSub.summable
  have hFind : ({r : HermiteMultiIndex n | 0 < r.2 j} :
      Set (HermiteMultiIndex n)).indicator F = F := by
    funext r
    simp only [Set.indicator, Set.mem_ofPred_eq]
    split_ifs with hr
    · rfl
    · have hz : r.2 j = 0 := Nat.eq_zero_of_not_pos hr
      simp [F, hz]
  have hsF : Summable F := by simpa [hFind] using hsInd
  change HasSum F (‖D‖ ^ 2)
  rw [← hsSub.tsum_eq]
  convert hsF.hasSum using 1
  calc
    (∑' b, f b) =
        ∑' b : {r : HermiteMultiIndex n // 0 < r.2 j}, F b.1 := by rfl
    _ = ∑' b : HermiteMultiIndex n,
          ({r : HermiteMultiIndex n | 0 < r.2 j} : Set _).indicator F b :=
      tsum_subtype {r : HermiteMultiIndex n | 0 < r.2 j} F
    _ = ∑' b : HermiteMultiIndex n, F b := by rw [hFind]

/-- Abstract weighted Hermite-energy identity.  The only analytic input is
the displayed coordinate coefficient identity; all summation, reindexing,
and Parseval steps are discharged here. -/
theorem hasSum_weighted_gaussianHermiteMode_of_coefficient_raise {n : ℕ}
    (hn : 0 < n) (g : Lp ℂ 2 (complexGaussianMeasure n))
    (D : Fin n → Lp ℂ 2 (complexGaussianMeasure n))
    (hcoeff : ∀ (j : Fin n) (pq : HermiteMultiIndex n),
      gaussianHermiteCoefficient hn (D j) pq =
        (Real.sqrt (n * (pq.2 j + 1) : ℕ) : ℂ) *
          gaussianHermiteCoefficient hn g (raiseHermiteIndex j pq)) :
    HasSum (fun d : ℕ => d * ‖gaussianHermiteMode hn d g‖ ^ 2)
      ((1 / n : ℝ) * ∑ j : Fin n, ‖D j‖ ^ 2) := by
  let a : HermiteMultiIndex n → ℝ := fun pq =>
    ‖gaussianHermiteCoefficient hn g pq‖ ^ 2
  have hj (j : Fin n) : HasSum (fun pq : HermiteMultiIndex n =>
      (n * pq.2 j : ℕ) * a pq) (‖D j‖ ^ 2) :=
    hasSum_coordinate_weighted_gaussianHermiteCoefficient hn g (D j) j
      (hcoeff j)
  have hsum := hasSum_sum (s := Finset.univ) (fun j _ => hj j)
  have hdegree : HasSum (fun pq : HermiteMultiIndex n =>
      (n : ℝ) * totalAntiDegree pq * a pq)
      (∑ j : Fin n, ‖D j‖ ^ 2) := by
    convert hsum using 1
    funext pq
    simp only [Nat.cast_mul]
    rw [totalAntiDegree, Nat.cast_sum, Finset.mul_sum, Finset.sum_mul]
  have hn0 : (n : ℝ) ≠ 0 := by exact_mod_cast hn.ne'
  have hweighted : HasSum (fun pq : HermiteMultiIndex n =>
      totalAntiDegree pq * a pq)
      ((1 / n : ℝ) * ∑ j : Fin n, ‖D j‖ ^ 2) := by
    simpa [hn0, mul_assoc] using hdegree.mul_left (1 / n : ℝ)
  let e := Equiv.sigmaFiberEquiv (@totalAntiDegree n)
  let F : (Σ d, {pq : HermiteMultiIndex n // totalAntiDegree pq = d}) → ℝ :=
    fun x => x.1 * a x.2.1
  have hsigma : HasSum F ((1 / n : ℝ) * ∑ j : Fin n, ‖D j‖ ^ 2) := by
    have hc := (e.hasSum_iff).mpr hweighted
    apply hc.congr_fun
    intro x
    change (x.1 : ℝ) * a x.2.1 = totalAntiDegree x.2.1 * a x.2.1
    rw [x.2.2]
  have hFnonneg : ∀ x, 0 ≤ F x := by
    intro x
    exact mul_nonneg (Nat.cast_nonneg _) (sq_nonneg _)
  have houter : Summable (fun d => ∑' pq :
      {pq : HermiteMultiIndex n // totalAntiDegree pq = d}, F ⟨d, pq⟩) :=
    ((summable_sigma_of_nonneg hFnonneg).mp hsigma.summable).2
  have hfiber (d : ℕ) : HasSum (fun pq :
      {pq : HermiteMultiIndex n // totalAntiDegree pq = d} => F ⟨d, pq⟩)
      (d * ‖gaussianHermiteMode hn d g‖ ^ 2) := by
    simpa [F, a] using
      (hasSum_coefficient_norm_sq_of_totalAntiDegree hn g d).mul_left (d : ℝ)
  have htarget : Summable (fun d : ℕ =>
      d * ‖gaussianHermiteMode hn d g‖ ^ 2) :=
    houter.congr (fun d => (hfiber d).tsum_eq)
  have htotal :
    (∑' d : ℕ, d * ‖gaussianHermiteMode hn d g‖ ^ 2) =
        ∑' d : ℕ, ∑' pq :
          {pq : HermiteMultiIndex n // totalAntiDegree pq = d}, F ⟨d, pq⟩ := by
      apply tsum_congr
      intro d
      exact (hfiber d).tsum_eq.symm
  rw [← hsigma.tsum_eq, hsigma.summable.tsum_sigma, ← htotal]
  exact htarget.hasSum

/-- The same weighted energy series in the positive-mode indexing used by
the deficit formula (`k` denotes anti-degree `k + 1`). -/
theorem hasSum_weighted_positiveHermiteModeMass_of_hasSum_modes {n : ℕ}
    (hn : 0 < n) (g : Lp ℂ 2 (complexGaussianMeasure n)) (E : ℝ)
    (h : HasSum (fun d : ℕ => d * ‖gaussianHermiteMode hn d g‖ ^ 2) E) :
    HasSum (fun k : ℕ => (k + 1) * positiveHermiteModeMass hn g k) E := by
  let a : ℕ → ℝ := fun d => d * ‖gaussianHermiteMode hn d g‖ ^ 2
  have htail : HasSum (fun k => a (k + 1)) E := by
    simpa [a] using (hasSum_nat_add_iff' 1).2 h
  simpa [a, positiveHermiteModeMass] using htail

/-- Positive-mode form of the abstract coordinate-derivative energy
identity. -/
theorem hasSum_weighted_positiveHermiteModeMass_of_coefficient_raise {n : ℕ}
    (hn : 0 < n) (g : Lp ℂ 2 (complexGaussianMeasure n))
    (D : Fin n → Lp ℂ 2 (complexGaussianMeasure n))
    (hcoeff : ∀ (j : Fin n) (pq : HermiteMultiIndex n),
      gaussianHermiteCoefficient hn (D j) pq =
        (Real.sqrt (n * (pq.2 j + 1) : ℕ) : ℂ) *
          gaussianHermiteCoefficient hn g (raiseHermiteIndex j pq)) :
    HasSum (fun k : ℕ => (k + 1) * positiveHermiteModeMass hn g k)
      ((1 / n : ℝ) * ∑ j : Fin n, ‖D j‖ ^ 2) :=
  hasSum_weighted_positiveHermiteModeMass_of_hasSum_modes hn g _
    (hasSum_weighted_gaussianHermiteMode_of_coefficient_raise hn g D hcoeff)

/-- The full weighted Hermite energy identity for a compactly supported
smooth Gaussian function. -/
theorem hasSum_weighted_positiveHermiteModeMass_smoothCompact
    {n : ℕ} (hn : 0 < n) (F : Configuration n → ℂ)
    (hF : ContDiff ℝ 1 F) (hFc : HasCompactSupport F) :
    HasSum (fun k : ℕ => (k + 1) *
      positiveHermiteModeMass hn (smoothCompactL2 F hF hFc) k)
      (gaussianDbarEnergy n F) := by
  have hs := hasSum_weighted_positiveHermiteModeMass_of_coefficient_raise hn
    (smoothCompactL2 F hF hFc)
    (fun j => smoothDbarComponentL2 F hF hFc j)
    (fun j pq => gaussianHermiteCoefficient_smoothDbarComponentL2_raise
      hn F hF hFc j pq)
  rw [sum_norm_sq_smoothDbarComponentL2 hn F hF hFc] at hs
  exact hs

end
end GinibrePoincare
Analysis GinibrePoincare/Analysis/HermiteWirtinger.lean #
import GinibrePoincare.Analysis.MultivariateComplexHermite
import GinibrePoincare.Concrete.Wirtinger
import Mathlib.Analysis.Calculus.FDeriv.Mul
import Mathlib.Analysis.Calculus.FDeriv.Pow
import Mathlib.Analysis.Calculus.FDeriv.Pi
import Mathlib.Analysis.Calculus.FDeriv.Comp

/-!
# Complex Hermite functions and concrete Wirtinger derivatives

This file connects formal partial differentiation of the two-variable
Hermite polynomial with the real-Fréchet definition of `∂̄` used by the
concrete Ginibre development.
-/

namespace GinibrePoincare

open scoped BigOperators ComplexConjugate

namespace ComplexHermite

noncomputable section

private def diagonalEval (P : Poly) (z : ℂ) : ℂ :=
  MvPolynomial.eval ![z, conj z] P

def diagonalEvalPublic (P : Poly) (z : ℂ) : ℂ :=
  MvPolynomial.eval ![z, conj z] P

private def dbarOne (f : ℂ → ℂ) (z : ℂ) : ℂ :=
  (1 / 2 : ℂ) *
    (fderiv ℝ f z 1 + Complex.I * fderiv ℝ f z Complex.I)

/-- Public one-variable Wirtinger `∂̄` operator. -/
def dbarOnePublic (f : ℂ → ℂ) (z : ℂ) : ℂ :=
  (1 / 2 : ℂ) *
    (fderiv ℝ f z 1 + Complex.I * fderiv ℝ f z Complex.I)

theorem dbarOnePublic_eq_dbarOne (f : ℂ → ℂ) :
    dbarOnePublic f = dbarOne f := rfl

private theorem differentiable_diagonalEval (P : Poly) :
    Differentiable ℝ (diagonalEval P) := by
  induction P using MvPolynomial.induction_on with
  | C a =>
      rw [show diagonalEval (MvPolynomial.C a) = fun _ : ℂ => a by
        funext z
        simp [diagonalEval]]
      exact (differentiable_const (c := a) :
        Differentiable ℝ (fun _ : ℂ => a))
  | add P Q hP hQ =>
      rw [show diagonalEval (P + Q) = diagonalEval P + diagonalEval Q by
        funext z
        simp [diagonalEval]]
      exact hP.add hQ
  | mul_X P i hP =>
      by_cases hi : i = (0 : ComplexHermiteIndex)
      · subst i
        rw [show diagonalEval (P * MvPolynomial.X (0 : ComplexHermiteIndex)) =
            diagonalEval P * id by
          funext z
          simp [diagonalEval]]
        exact hP.mul differentiable_id
      · have hi' : i = (1 : ComplexHermiteIndex) := by
          have hne : i.val ≠ 0 := by
            intro hzero
            apply hi
            apply Fin.ext
            simpa using hzero
          apply Fin.ext
          omega
        subst i
        rw [show diagonalEval (P * MvPolynomial.X (1 : ComplexHermiteIndex)) =
            diagonalEval P * (conj : ℂ → ℂ) by
          funext z
          simp [diagonalEval]]
        exact hP.mul Complex.conjCLE.differentiable

theorem differentiable_diagonalEval_public (P : Poly) :
    Differentiable ℝ (diagonalEval P) := differentiable_diagonalEval P

theorem contDiff_diagonalEval_public (P : Poly) :
    ContDiff ℝ 1 (diagonalEval P) := by
  induction P using MvPolynomial.induction_on with
  | C a =>
      rw [show diagonalEval (MvPolynomial.C a) = fun _ : ℂ ↦ a by
        funext z; simp [diagonalEval]]
      fun_prop
  | add P Q hP hQ =>
      rw [show diagonalEval (P + Q) = diagonalEval P + diagonalEval Q by
        funext z; simp [diagonalEval]]
      exact hP.add hQ
  | mul_X P i hP =>
      by_cases hi : i = (0 : ComplexHermiteIndex)
      · subst i
        rw [show diagonalEval (P * MvPolynomial.X 0) = diagonalEval P * id by
          funext z; simp [diagonalEval]]
        exact hP.mul contDiff_id
      · have hi' : i = (1 : ComplexHermiteIndex) := by
          have hne : i.val ≠ 0 := by
            intro hz; apply hi; apply Fin.ext; simpa using hz
          apply Fin.ext
          omega
        subst i
        rw [show diagonalEval (P * MvPolynomial.X 1) =
            diagonalEval P * (conj : ℂ → ℂ) by
          funext z; simp [diagonalEval]]
        exact hP.mul Complex.conjCLE.contDiff

theorem exists_fderiv_diagonalEval_polynomial (P : Poly) (v : ℂ) :
    ∃ Q : Poly, ∀ z : ℂ,
      (fderiv ℝ (diagonalEval P) z) v = diagonalEval Q z := by
  induction P using MvPolynomial.induction_on with
  | C a =>
      refine ⟨0, ?_⟩
      intro z
      rw [show diagonalEval (MvPolynomial.C a) = fun _ : ℂ ↦ a by
        funext w; simp [diagonalEval]]
      simp [diagonalEval]
  | add P Q hP hQ =>
      obtain ⟨R, hR⟩ := hP
      obtain ⟨S, hS⟩ := hQ
      refine ⟨R + S, ?_⟩
      intro z
      rw [show diagonalEval (P + Q) = diagonalEval P + diagonalEval Q by
        funext w; simp [diagonalEval],
        fderiv_add ((differentiable_diagonalEval P) z)
          ((differentiable_diagonalEval Q) z)]
      simp [hR, hS, diagonalEval]
  | mul_X P i hP =>
      obtain ⟨Q, hQ⟩ := hP
      by_cases hi : i = (0 : ComplexHermiteIndex)
      · subst i
        refine ⟨Q * MvPolynomial.X 0 + MvPolynomial.C v * P, ?_⟩
        intro z
        rw [show diagonalEval (P * MvPolynomial.X 0) = diagonalEval P * id by
          funext w; simp [diagonalEval],
          fderiv_mul ((differentiable_diagonalEval P) z) differentiableAt_id]
        simp [hQ, diagonalEval]
        ring

      · have hi' : i = (1 : ComplexHermiteIndex) := by
          have hne : i.val ≠ 0 := by
            intro hz
            apply hi
            apply Fin.ext
            simpa using hz
          apply Fin.ext
          omega
        subst i
        refine ⟨Q * MvPolynomial.X 1 + MvPolynomial.C (conj v) * P, ?_⟩
        intro z
        rw [show diagonalEval (P * MvPolynomial.X 1) =
            diagonalEval P * (conj : ℂ → ℂ) by
          funext w; simp [diagonalEval],
          fderiv_mul ((differentiable_diagonalEval P) z)
            (Complex.differentiable_conj z)]
        have hc : (fderiv ℝ (conj : ℂ → ℂ) z) v = conj v := by
          change (fderiv ℝ (Complex.conjCLE : ℂ → ℂ) z) v = _
          rw [Complex.conjCLE.hasFDerivAt.fderiv]
          rfl
        simp [hQ, diagonalEval, hc]
        ring

theorem contDiff_diagonalEvalPublic (P : Poly) :
    ContDiff ℝ 1 (diagonalEvalPublic P) :=
  contDiff_diagonalEval_public P

theorem exists_fderiv_diagonalEvalPublic_polynomial (P : Poly) (v : ℂ) :
    ∃ Q : Poly, ∀ z : ℂ,
      (fderiv ℝ (diagonalEvalPublic P) z) v = diagonalEvalPublic Q z :=
  exists_fderiv_diagonalEval_polynomial P v

private theorem dbarOne_add {f g : ℂ → ℂ} (hf : Differentiable ℝ f)
    (hg : Differentiable ℝ g) (z : ℂ) :
    dbarOne (fun w => f w + g w) z = dbarOne f z + dbarOne g z := by
  change dbarOne (f + g) z = dbarOne f z + dbarOne g z
  rw [dbarOne, dbarOne, dbarOne, fderiv_add (hf z) (hg z)]
  simp only [add_apply]
  ring

private theorem dbarOne_mul {f g : ℂ → ℂ} (hf : Differentiable ℝ f)
    (hg : Differentiable ℝ g) (z : ℂ) :
    dbarOne (fun w => f w * g w) z =
      dbarOne f z * g z + f z * dbarOne g z := by
  change dbarOne (f * g) z = dbarOne f z * g z + f z * dbarOne g z
  rw [dbarOne, dbarOne, dbarOne, fderiv_mul (hf z) (hg z)]
  simp only [add_apply, smul_apply, smul_eq_mul]
  ring

theorem dbarOnePublic_mul {f g : ℂ → ℂ} (hf : Differentiable ℝ f)
    (hg : Differentiable ℝ g) (z : ℂ) :
    dbarOnePublic (fun w ↦ f w * g w) z =
      dbarOnePublic f z * g z + f z * dbarOnePublic g z := by
  change dbarOne (fun w ↦ f w * g w) z =
    dbarOne f z * g z + f z * dbarOne g z
  exact dbarOne_mul hf hg z

@[simp] private theorem dbarOne_id (z : ℂ) : dbarOne id z = 0 := by
  rw [dbarOne, (hasFDerivAt_id z).fderiv]
  simp

@[simp] private theorem dbarOne_conj (z : ℂ) : dbarOne conj z = 1 := by
  change dbarOne (fun z => Complex.conjCLE z) z = 1
  rw [dbarOne, Complex.conjCLE.fderiv]
  norm_num [Complex.conjCLE_apply]

/-- Diagonal evaluation turns formal differentiation in `W` into the
real-Fréchet Wirtinger derivative. -/
private theorem dbarOne_diagonalEval (P : Poly) (z : ℂ) :
    dbarOne (diagonalEval P) z =
      diagonalEval (MvPolynomial.pderiv (1 : ComplexHermiteIndex) P) z := by
  induction P using MvPolynomial.induction_on with
  | C a =>
      rw [show diagonalEval (MvPolynomial.C a) = fun _ : ℂ => a by
        funext w
        simp [diagonalEval]]
      simp [dbarOne, diagonalEval]
  | add P Q hP hQ =>
      rw [show diagonalEval (P + Q) = fun z => diagonalEval P z + diagonalEval Q z by
        funext w
        simp [diagonalEval]]
      rw [dbarOne_add (differentiable_diagonalEval P)
        (differentiable_diagonalEval Q), hP, hQ]
      simp [diagonalEval]
  | mul_X P i hP =>
      by_cases hi : i = (0 : ComplexHermiteIndex)
      · subst i
        rw [show diagonalEval (P * MvPolynomial.X (0 : ComplexHermiteIndex)) =
            fun z => diagonalEval P z * id z by
          funext w
          simp [diagonalEval]]
        rw [dbarOne_mul (differentiable_diagonalEval P) differentiable_id,
          hP, dbarOne_id]
        simp [diagonalEval]
        ring
      · have hi' : i = (1 : ComplexHermiteIndex) := by
          have hne : i.val ≠ 0 := by
            intro hzero
            apply hi
            apply Fin.ext
            simpa using hzero
          apply Fin.ext
          omega
        subst i
        rw [show diagonalEval (P * MvPolynomial.X (1 : ComplexHermiteIndex)) =
            fun z => diagonalEval P z * conj z by
          funext w
          simp [diagonalEval]]
        rw [dbarOne_mul (g := conj) (differentiable_diagonalEval P)
          Complex.conjCLE.differentiable, hP, dbarOne_conj]
        simp [diagonalEval]
        ring

/-- Exact univariate Wirtinger lowering after normalized diagonal
evaluation. -/
theorem dbarOne_normalizedEval (n : ℕ) (hn : 0 < n) (p q : ℕ) (z : ℂ) :
    dbarOne (normalizedEval n hn p q) z =
      Real.sqrt (n * q : ℕ) * normalizedEval n hn p (q - 1) z := by
  rw [show normalizedEval n hn p q = diagonalEval (normalized n hn p q) by rfl,
    dbarOne_diagonalEval, pderiv_W_normalized]
  simp [diagonalEval, normalizedEval]

theorem dbarOne_normalizedEval_public (n : ℕ) (hn : 0 < n)
    (p q : ℕ) (z : ℂ) :
    dbarOnePublic (normalizedEval n hn p q) z =
      Real.sqrt (n * q : ℕ) * normalizedEval n hn p (q - 1) z := by
  rw [dbarOnePublic_eq_dbarOne]
  exact dbarOne_normalizedEval n hn p q z

theorem differentiable_normalizedEval (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    Differentiable ℝ (normalizedEval n hn p q) := by
  rw [show normalizedEval n hn p q = diagonalEval (normalized n hn p q) by rfl]
  exact differentiable_diagonalEval _

private theorem dbarComponent_coordinateLift {m : ℕ} (f : ℂ → ℂ)
    (hf : Differentiable ℝ f) (i j : Fin m) (z : Configuration m) :
    dbarComponent (fun w => f (w i)) j z =
      if i = j then dbarOne f (z i) else 0 := by
  have hcomp : (fun w : Configuration m => f (w i)) =
      f ∘ (ContinuousLinearMap.proj i : Configuration m →L[ℝ] ℂ) := rfl
  rw [dbarComponent, hcomp,
    fderiv_comp (𝕜 := ℝ) z (hf (z i))
      (ContinuousLinearMap.proj i).differentiableAt]
  simp only [ContinuousLinearMap.comp_apply, ContinuousLinearMap.proj_apply]
  rw [dbarOne]
  by_cases hij : i = j
  · subst j
    simp [realCoordinateDirection, imaginaryCoordinateDirection,
      coordinateDirection]
  · simp [realCoordinateDirection, imaginaryCoordinateDirection,
      coordinateDirection, hij]

/-- Concrete coordinate `∂̄` lowering for a single normalized Hermite factor
lifted to configuration space. -/
theorem dbarComponent_normalizedEval_coordinate {m n : ℕ} (hn : 0 < n)
    (p q : ℕ) (i j : Fin m) (z : Configuration m) :
    dbarComponent (fun w => normalizedEval n hn p q (w i)) j z =
      if i = j then
        Real.sqrt (n * q : ℕ) * normalizedEval n hn p (q - 1) (z i)
      else 0 := by
  rw [dbarComponent_coordinateLift _ (differentiable_normalizedEval n hn p q)]
  split_ifs with hij
  · rw [dbarOne_normalizedEval]
  · rfl

private theorem dbarComponent_finsetProd {m : ℕ} {ι : Type*}
    [DecidableEq ι] (s : Finset ι) (f : ι → Configuration m → ℂ)
    (hf : ∀ i ∈ s, Differentiable ℝ (f i)) (j : Fin m) (z : Configuration m) :
    dbarComponent (fun w => ∏ i ∈ s, f i w) j z =
      ∑ i ∈ s, (∏ k ∈ s.erase i, f k z) * dbarComponent (f i) j z := by
  unfold dbarComponent
  rw [fderiv_finsetProd (u := s) (g := f) (fun i hi => (hf i hi z))]
  simp only [sum_apply, smul_apply, smul_eq_mul]
  rw [Finset.mul_sum, ← Finset.sum_add_distrib, Finset.mul_sum]
  apply Finset.sum_congr rfl
  intro i hi
  ring

/-- Lower the `j`th entry of a multi-index, using truncated natural
subtraction at zero. -/
def lowerAt {n : ℕ} (q : Fin n → ℕ) (j : Fin n) : Fin n → ℕ :=
  Function.update q j (q j - 1)

/-- Exact concrete coordinatewise `∂̄` lowering for a multivariate normalized
complex Hermite function. -/
theorem dbarComponent_multivariateNormalized (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) (j : Fin n) (z : Configuration n) :
    dbarComponent (multivariateNormalized n hn p q) j z =
      Real.sqrt (n * q j : ℕ) *
        multivariateNormalized n hn p (lowerAt q j) z := by
  rw [show multivariateNormalized n hn p q =
      fun w => ∏ i ∈ Finset.univ,
        normalizedEval n hn (p i) (q i) (w i) by
    funext w
    simp [multivariateNormalized]]
  rw [dbarComponent_finsetProd Finset.univ
    (fun i w => normalizedEval n hn (p i) (q i) (w i))]
  · simp_rw [dbarComponent_normalizedEval_coordinate]
    rw [Finset.sum_eq_single j]
    · simp only [if_pos]
      unfold multivariateNormalized lowerAt
      rw [← Finset.mul_prod_erase Finset.univ
        (fun i => normalizedEval n hn (p i)
          ((Function.update q j (q j - 1)) i) (z i)) (Finset.mem_univ j)]
      simp only [Function.update_self]
      have hprod :
          (∏ x ∈ Finset.univ.erase j,
              normalizedEval n hn (p x) (Function.update q j (q j - 1) x) (z x)) =
            ∏ x ∈ Finset.univ.erase j,
              normalizedEval n hn (p x) (q x) (z x) := by
        apply Finset.prod_congr rfl
        intro k hk
        rw [Function.update_of_ne (Finset.ne_of_mem_erase hk)]
      rw [hprod]
      ring
    · intro i hi hij
      simp [hij]
    · simp
  · intro i hi
    exact (differentiable_normalizedEval n hn (p i) (q i)).comp
      (ContinuousLinearMap.proj i : Configuration n →L[ℝ] ℂ).differentiable

end

end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/HolomorphicVandermondeDivision.lean #
import GinibrePoincare.Analysis.MultivariateComplexHermite
import GinibrePoincare.Analysis.GinibreMassFiniteness
import GinibrePoincare.Concrete.Vandermonde
import GinibrePoincare.Concrete.NormalizedGroundState
import Mathlib.RingTheory.MvPolynomial.Symmetric.FundamentalTheorem
import Mathlib.Algebra.Polynomial.Div
import Mathlib.Algebra.Polynomial.RingDivision
import Mathlib.RingTheory.Coprime.Lemmas
import Mathlib.RingTheory.Polynomial.UniqueFactorization
import Mathlib.Algebra.MvPolynomial.Funext

/-! # Algebraic alternating polynomials and the Vandermonde -/

open scoped BigOperators

namespace GinibrePoincare

noncomputable section

attribute [local simp] MvPolynomial.optionEquivLeft_X_none
  MvPolynomial.optionEquivLeft_X_some MvPolynomial.optionEquivLeft_C

/-- Holomorphic polynomials in the particle coordinates. -/
abbrev ConfigurationPolynomial (n : ℕ) := MvPolynomial (Fin n) ℂ

/-- Relabel the variables of a configuration polynomial. -/
def permuteConfigurationPolynomial {n : ℕ} (σ : ParticlePermutation n) :
    ConfigurationPolynomial n →ₐ[ℂ] ConfigurationPolynomial n :=
  MvPolynomial.renameEquiv ℂ σ

/-- Algebraic symmetry under all particle relabellings. -/
def IsSymmetricConfigurationPolynomial {n : ℕ}
    (P : ConfigurationPolynomial n) : Prop :=
  ∀ σ : ParticlePermutation n, permuteConfigurationPolynomial σ P = P

/-- Algebraic alternation under all particle relabellings. -/
def IsAlternatingConfigurationPolynomial {n : ℕ}
    (P : ConfigurationPolynomial n) : Prop :=
  ∀ σ : ParticlePermutation n,
    permuteConfigurationPolynomial σ P =
      MvPolynomial.C (permutationSign σ) * P

/-- The polynomial Vandermonde determinant. -/
def polynomialVandermonde (n : ℕ) : ConfigurationPolynomial n :=
  (Matrix.vandermonde (fun i : Fin n ↦
    MvPolynomial.X i : Fin n → ConfigurationPolynomial n)).det

/-- Its usual product formula. -/
theorem polynomialVandermonde_eq_product (n : ℕ) :
    polynomialVandermonde n =
      ∏ i : Fin n, ∏ j > i, (MvPolynomial.X j - MvPolynomial.X i) := by
  exact Matrix.det_vandermonde _

/-- Evaluation of the polynomial Vandermonde is the concrete Vandermonde. -/
@[simp] theorem eval_polynomialVandermonde (n : ℕ) (z : Configuration n) :
    MvPolynomial.eval z (polynomialVandermonde n) = vandermonde z := by
  rw [polynomialVandermonde_eq_product, vandermonde_eq_product]
  simp

/-- Evaluation after relabelling variables is evaluation on the relabelled
configuration. -/
theorem eval_permuteConfigurationPolynomial {n : ℕ}
    (σ : ParticlePermutation n) (P : ConfigurationPolynomial n)
    (z : Configuration n) :
    MvPolynomial.eval z (permuteConfigurationPolynomial σ P) =
      MvPolynomial.eval (permute σ z) P := by
  change MvPolynomial.eval z (MvPolynomial.rename σ P) = _
  rw [MvPolynomial.eval_rename]
  rfl

/-- Algebraic symmetry implies symmetry of the evaluated polynomial
function. -/
theorem isSymmetric_eval_of_polynomial {n : ℕ}
    {P : ConfigurationPolynomial n} (hP : IsSymmetricConfigurationPolynomial P) :
    IsSymmetric (fun z : Configuration n ↦ MvPolynomial.eval z P) := by
  intro σ z
  change MvPolynomial.eval (permute σ z) P = MvPolynomial.eval z P
  rw [← eval_permuteConfigurationPolynomial σ P z, hP σ]

/-- Algebraic alternation implies alternation of the evaluated polynomial
function. -/
theorem isAlternating_eval_of_polynomial {n : ℕ}
    {P : ConfigurationPolynomial n}
    (hP : IsAlternatingConfigurationPolynomial P) :
    IsAlternating (fun z : Configuration n ↦ MvPolynomial.eval z P) := by
  intro σ z
  change MvPolynomial.eval (permute σ z) P =
    permutationSign σ * MvPolynomial.eval z P
  rw [← eval_permuteConfigurationPolynomial σ P z, hP σ]
  simp

/-- The polynomial Vandermonde is algebraically alternating. -/
theorem isAlternating_polynomialVandermonde (n : ℕ) :
    IsAlternatingConfigurationPolynomial (polynomialVandermonde n) := by
  intro σ
  have hmatrix :
      Matrix.vandermonde (fun i : Fin n ↦ MvPolynomial.X (σ i) :
        Fin n → ConfigurationPolynomial n) =
        (Matrix.vandermonde (fun i : Fin n ↦ MvPolynomial.X i :
          Fin n → ConfigurationPolynomial n)).submatrix σ id := by
    ext i j
    simp
  unfold permuteConfigurationPolynomial polynomialVandermonde
  change MvPolynomial.rename σ
      (Matrix.vandermonde (fun i : Fin n ↦ MvPolynomial.X i :
        Fin n → ConfigurationPolynomial n)).det = _
  calc
    _ = ((MvPolynomial.rename σ).mapMatrix
        (Matrix.vandermonde (fun i : Fin n ↦ MvPolynomial.X i :
          Fin n → ConfigurationPolynomial n))).det :=
      RingHom.map_det _ _
    _ = (Matrix.vandermonde (fun i : Fin n ↦ MvPolynomial.X (σ i) :
          Fin n → ConfigurationPolynomial n)).det := by
      congr 1
      ext i j
      simp
    _ = _ := by
      rw [hmatrix, Matrix.det_permute]
      simp [permutationSign]

/-- The polynomial Vandermonde is nonzero. -/
theorem polynomialVandermonde_ne_zero (n : ℕ) :
    polynomialVandermonde n ≠ 0 := by
  intro hzero
  have heval := congrArg
    (MvPolynomial.eval (fun i : Fin n ↦ ((i : ℕ) : ℂ))) hzero
  simp only [eval_polynomialVandermonde, map_zero] at heval
  exact (vandermonde_ne_zero_iff _).2 (fun i j hij ↦ by
    exact Fin.ext (by exact_mod_cast Complex.ofReal_injective hij)) heval

/-- A symmetric polynomial multiplied by the Vandermonde is alternating. -/
theorem isAlternating_polynomialVandermonde_mul {n : ℕ}
    {Q : ConfigurationPolynomial n}
    (hQ : IsSymmetricConfigurationPolynomial Q) :
    IsAlternatingConfigurationPolynomial (polynomialVandermonde n * Q) := by
  intro σ
  rw [map_mul]
  rw [isAlternating_polynomialVandermonde n σ, hQ σ]
  ring

/-- If an alternating polynomial is presented as a Vandermonde multiple,
then its quotient is symmetric. -/
theorem isSymmetric_quotient_of_vandermonde_mul_alternating {n : ℕ}
    {Q : ConfigurationPolynomial n}
    (hAlt : IsAlternatingConfigurationPolynomial
      (polynomialVandermonde n * Q)) :
    IsSymmetricConfigurationPolynomial Q := by
  intro σ
  have h := hAlt σ
  rw [map_mul] at h
  rw [isAlternating_polynomialVandermonde n σ] at h
  have hsign : MvPolynomial.C (permutationSign σ) ≠
      (0 : ConfigurationPolynomial n) := by
    rw [MvPolynomial.C_ne_zero]
    unfold permutationSign
    norm_num
  have hfac : MvPolynomial.C (permutationSign σ) *
      polynomialVandermonde n ≠ 0 :=
    mul_ne_zero hsign (polynomialVandermonde_ne_zero n)
  apply mul_left_cancel₀ hfac
  simpa only [mul_assoc] using h

/-- Division with symmetric quotient, once Vandermonde divisibility has been
established.  This isolates the factor-theorem step from quotient symmetry. -/
theorem alternating_polynomial_division_of_dvd {n : ℕ}
    {P : ConfigurationPolynomial n}
    (hAlt : IsAlternatingConfigurationPolynomial P)
    (hdiv : polynomialVandermonde n ∣ P) :
    ∃ Q : ConfigurationPolynomial n,
      IsSymmetricConfigurationPolynomial Q ∧
        P = polynomialVandermonde n * Q := by
  obtain ⟨Q, rfl⟩ := hdiv
  exact ⟨Q, isSymmetric_quotient_of_vandermonde_mul_alternating hAlt, rfl⟩

/-- Polynomial representing a normalized multivariate Hermite tensor of
zero antiholomorphic degree. -/
def holomorphicHermitePolynomial (n : ℕ) (p : Fin n → ℕ) :
    ConfigurationPolynomial n :=
  ∏ i : Fin n,
    MvPolynomial.C (ComplexHermite.oneDimNormalization n (p i) : ℂ) *
      MvPolynomial.X i ^ p i

/-- Zero-antiholomorphic-degree Hermite tensors are evaluations of genuine
holomorphic configuration polynomials. -/
theorem eval_holomorphicHermitePolynomial (n : ℕ) (hn : 0 < n)
    (p : Fin n → ℕ) (z : Configuration n) :
    MvPolynomial.eval z (holomorphicHermitePolynomial n p) =
      ComplexHermite.multivariateNormalized n hn p 0 z := by
  simp [holomorphicHermitePolynomial,
    ComplexHermite.multivariateNormalized_zero_right]

/-- Identify variable `j` with variable `i`. -/
def identifyVariable {n : ℕ} (i j : Fin n) : Fin n → Fin n :=
  fun k ↦ if k = j then i else k

/-- Identifying a pair of variables annihilates a polynomial which is
alternating under their transposition. -/
theorem rename_identifyVariable_eq_zero_of_swap_alternating {n : ℕ}
    {P : ConfigurationPolynomial n} {i j : Fin n} (hij : i ≠ j)
    (hP : permuteConfigurationPolynomial (Equiv.swap i j) P =
      MvPolynomial.C (permutationSign (Equiv.swap i j)) * P) :
    MvPolynomial.rename (identifyVariable i j) P = 0 := by
  have hcomp : identifyVariable i j ∘ Equiv.swap i j =
      identifyVariable i j := by
    funext k
    by_cases hki : k = i
    · subst k
      simp [identifyVariable, hij]
    · by_cases hkj : k = j
      · subst k
        simp [identifyVariable, hij]
      · simp [identifyVariable, Equiv.swap_apply_of_ne_of_ne hki hkj]
  have h := congrArg (MvPolynomial.rename (identifyVariable i j)) hP
  rw [show permuteConfigurationPolynomial (Equiv.swap i j) P =
      MvPolynomial.rename (Equiv.swap i j) P by rfl,
    MvPolynomial.rename_rename, hcomp] at h
  simp [permutationSign, hij] at h
  have htwo : (2 : ℂ) • MvPolynomial.rename (identifyVariable i j) P = 0 := by
    rw [two_smul]
    exact add_eq_zero_iff_eq_neg.mpr h
  exact (smul_eq_zero.mp htwo).resolve_left (by norm_num)

/-- Coefficient ring consisting of the variables other than `j`. -/
abbrev ConfigurationPolynomialAway {n : ℕ} (j : Fin n) :=
  MvPolynomial {k : Fin n // k ≠ j} ℂ

/-- Regard a multivariate polynomial as a univariate polynomial in `X j`,
with all other variables in the coefficient ring. -/
def asPolynomialInVariable {n : ℕ} (j : Fin n) :
    ConfigurationPolynomial n ≃ₐ[ℂ]
      Polynomial (ConfigurationPolynomialAway j) :=
  (MvPolynomial.renameEquiv ℂ (Equiv.optionSubtypeNe j).symm).trans
    (MvPolynomial.optionEquivLeft ℂ _)

/-- Constants become constant polynomials over the coefficient ring. -/
@[simp] theorem asPolynomialInVariable_C {n : ℕ} (j : Fin n) (c : ℂ) :
    asPolynomialInVariable j (MvPolynomial.C c) =
      Polynomial.C (MvPolynomial.C c) := by
  unfold asPolynomialInVariable
  simp only [AlgEquiv.trans_apply, MvPolynomial.renameEquiv_apply,
    MvPolynomial.rename_C]
  exact MvPolynomial.optionEquivLeft_C ℂ {k : Fin n // k ≠ j} c

/-- The distinguished variable becomes the univariate indeterminate. -/
@[simp] theorem asPolynomialInVariable_X_self {n : ℕ} (j : Fin n) :
    asPolynomialInVariable j (MvPolynomial.X j) = Polynomial.X := by
  unfold asPolynomialInVariable
  simp only [AlgEquiv.trans_apply, MvPolynomial.renameEquiv_apply,
    MvPolynomial.rename_X]
  have hnone : (Equiv.optionSubtypeNe j).symm j = none := by
    apply (Equiv.optionSubtypeNe j).injective
    simp
  rw [hnone, MvPolynomial.optionEquivLeft_X_none]

/-- Every other variable becomes a coefficient variable. -/
@[simp] theorem asPolynomialInVariable_X_of_ne {n : ℕ}
    {i j : Fin n} (hij : i ≠ j) :
    asPolynomialInVariable j (MvPolynomial.X i) =
      Polynomial.C (MvPolynomial.X ⟨i, hij⟩) := by
  unfold asPolynomialInVariable
  simp only [AlgEquiv.trans_apply, MvPolynomial.renameEquiv_apply,
    MvPolynomial.rename_X]
  have hsome : (Equiv.optionSubtypeNe j).symm i = some ⟨i, hij⟩ := by
    apply (Equiv.optionSubtypeNe j).injective
    simp [hij]
  rw [hsome, MvPolynomial.optionEquivLeft_X_some]

/-- In particular, the variable identified with `j` is represented by its
coefficient-ring indeterminate. -/
@[simp] theorem asPolynomialInVariable_X_identified {n : ℕ}
    {i j : Fin n} (hij : i ≠ j) :
    asPolynomialInVariable j (MvPolynomial.X i) =
      Polynomial.C (MvPolynomial.X ⟨i, hij⟩) :=
  asPolynomialInVariable_X_of_ne hij

/-- Identifying `X j` with `X i` corresponds, in the univariate view, to
evaluation at the coefficient variable `X i` and reinsertion as a constant
polynomial. -/
theorem asPolynomialInVariable_rename_identifyVariable {n : ℕ}
    (P : ConfigurationPolynomial n) {i j : Fin n} (hij : i ≠ j) :
    asPolynomialInVariable j
        (MvPolynomial.rename (identifyVariable i j) P) =
      Polynomial.C
        ((asPolynomialInVariable j P).eval (MvPolynomial.X ⟨i, hij⟩)) := by
  let L : ConfigurationPolynomial n →+*
      Polynomial (ConfigurationPolynomialAway j) :=
    (asPolynomialInVariable j).toRingEquiv.toRingHom.comp
      (MvPolynomial.rename (identifyVariable i j)).toRingHom
  let R : ConfigurationPolynomial n →+*
      Polynomial (ConfigurationPolynomialAway j) :=
    Polynomial.C.comp
      ((Polynomial.evalRingHom (MvPolynomial.X ⟨i, hij⟩)).comp
        (asPolynomialInVariable j).toRingEquiv.toRingHom)
  have hLR : L = R := by
    apply MvPolynomial.ringHom_ext
    · intro c
      simp [L, R]
    · intro k
      by_cases hkj : k = j
      · subst k
        simp [L, R, identifyVariable, hij]
      · simp [L, R, identifyVariable, hkj]
  exact DFunLike.congr_fun hLR P

/-- The kernel of identifying `j` with `i` is contained in the principal
ideal generated by `X j - X i`. -/
theorem X_sub_X_dvd_of_rename_identifyVariable_eq_zero {n : ℕ}
    {P : ConfigurationPolynomial n} {i j : Fin n} (hij : i ≠ j)
    (hzero : MvPolynomial.rename (identifyVariable i j) P = 0) :
    MvPolynomial.X j - MvPolynomial.X i ∣ P := by
  let e := asPolynomialInVariable j
  let a : ConfigurationPolynomialAway j := MvPolynomial.X ⟨i, hij⟩
  have heval : (e P).eval a = 0 := by
    have hconst : Polynomial.C ((e P).eval a) = 0 := by
      rw [← asPolynomialInVariable_rename_identifyVariable P hij,
        hzero, map_zero]
    apply Polynomial.C_injective
    simpa using hconst
  have hd : Polynomial.X - Polynomial.C a ∣ e P :=
    (Polynomial.dvd_iff_isRoot).2 heval
  have hmapped := map_dvd e.symm.toRingHom hd
  have hfactor : e.symm (Polynomial.X - Polynomial.C a) =
      MvPolynomial.X j - MvPolynomial.X i := by
    apply e.injective
    rw [e.apply_symm_apply]
    rw [map_sub, asPolynomialInVariable_X_self,
      asPolynomialInVariable_X_of_ne hij]
  change e.symm (Polynomial.X - Polynomial.C a) ∣ e.symm (e P) at hmapped
  rw [hfactor, e.symm_apply_apply] at hmapped
  exact hmapped

/-- A single transposition-antisymmetry forces the corresponding linear
Vandermonde factor. -/
theorem X_sub_X_dvd_of_swap_alternating {n : ℕ}
    {P : ConfigurationPolynomial n} {i j : Fin n} (hij : i ≠ j)
    (hP : permuteConfigurationPolynomial (Equiv.swap i j) P =
      MvPolynomial.C (permutationSign (Equiv.swap i j)) * P) :
    MvPolynomial.X j - MvPolynomial.X i ∣ P :=
  X_sub_X_dvd_of_rename_identifyVariable_eq_zero hij
    (rename_identifyVariable_eq_zero_of_swap_alternating hij hP)

/-- Every pairwise Vandermonde factor divides an alternating polynomial. -/
theorem X_sub_X_dvd_of_alternating {n : ℕ}
    {P : ConfigurationPolynomial n}
    (hP : IsAlternatingConfigurationPolynomial P)
    {i j : Fin n} (hij : i ≠ j) :
    MvPolynomial.X j - MvPolynomial.X i ∣ P :=
  X_sub_X_dvd_of_swap_alternating hij (hP (Equiv.swap i j))

/-- Each linear Vandermonde factor is prime. -/
theorem prime_X_sub_X {n : ℕ} {i j : Fin n} (hij : i ≠ j) :
    Prime (MvPolynomial.X j - MvPolynomial.X i : ConfigurationPolynomial n) := by
  let e := asPolynomialInVariable j
  have hmap : e (MvPolynomial.X j - MvPolynomial.X i) =
      Polynomial.X - Polynomial.C (MvPolynomial.X ⟨i, hij⟩) := by
    rw [map_sub, asPolynomialInVariable_X_self,
      asPolynomialInVariable_X_of_ne hij]
  apply (MulEquiv.prime_iff e.toMulEquiv).mp
  change Prime (e (MvPolynomial.X j - MvPolynomial.X i))
  rw [hmap]
  exact Polynomial.prime_X_sub_C _

private theorem identifyVariable_ne_of_ordered_pairs_ne {n : ℕ}
    {i j k l : Fin n} (hij : i < j) (hkl : k < l)
    (hpairs : (i, j) ≠ (k, l)) :
    identifyVariable i j k ≠ identifyVariable i j l := by
  intro h
  by_cases hlj : l = j
  · subst l
    have hkj : k ≠ j := ne_of_lt hkl
    have hki : k = i := by simpa [identifyVariable, hkj] using h
    subst k
    exact hpairs rfl
  · by_cases hkj : k = j
    · subst k
      have hli : l = i := by simpa [identifyVariable, hij.ne, hlj] using h.symm
      subst l
      exact lt_asymm hij hkl
    · have : k = l := by simpa [identifyVariable, hkj, hlj] using h
      exact hkl.ne this

/-- Distinct oriented Vandermonde factors do not divide one another. -/
theorem not_dvd_X_sub_X_of_ordered_pairs_ne {n : ℕ}
    {i j k l : Fin n} (hij : i < j) (hkl : k < l)
    (hpairs : (i, j) ≠ (k, l)) :
    ¬(MvPolynomial.X j - MvPolynomial.X i : ConfigurationPolynomial n) ∣
      MvPolynomial.X l - MvPolynomial.X k := by
  intro hdvd
  have hmapped := map_dvd (MvPolynomial.rename (identifyVariable i j)) hdvd
  have hleft : MvPolynomial.rename (identifyVariable i j)
      (MvPolynomial.X j - MvPolynomial.X i : ConfigurationPolynomial n) = 0 := by
    simp [identifyVariable, hij.ne]
  rw [hleft, zero_dvd_iff] at hmapped
  simp only [map_sub, MvPolynomial.rename_X] at hmapped
  have hx : MvPolynomial.X (identifyVariable i j l) =
      (MvPolynomial.X (identifyVariable i j k) : ConfigurationPolynomial n) :=
    sub_eq_zero.mp hmapped
  exact identifyVariable_ne_of_ordered_pairs_ne hij hkl hpairs
    (MvPolynomial.X_injective hx.symm)

/-- Distinct oriented Vandermonde factors are relatively prime. -/
theorem isRelPrime_X_sub_X_of_ordered_pairs_ne {n : ℕ}
    {i j k l : Fin n} (hij : i < j) (hkl : k < l)
    (hpairs : (i, j) ≠ (k, l)) :
    IsRelPrime
      (MvPolynomial.X j - MvPolynomial.X i : ConfigurationPolynomial n)
      (MvPolynomial.X l - MvPolynomial.X k) := by
  rw [(prime_X_sub_X hij.ne).irreducible.isRelPrime_iff_not_dvd]
  exact not_dvd_X_sub_X_of_ordered_pairs_ne hij hkl hpairs

/-- The finite type of strictly ordered particle pairs. -/
abbrev OrderedParticlePair (n : ℕ) :=
  Σ i : Fin n, {j : Fin n // j ∈ Finset.Ioi i}

/-- Linear Vandermonde factor attached to an ordered pair. -/
def orderedPairFactor {n : ℕ} (p : OrderedParticlePair n) :
    ConfigurationPolynomial n :=
  MvPolynomial.X p.2.1 - MvPolynomial.X p.1

theorem pairwise_isRelPrime_orderedPairFactor (n : ℕ) :
    Pairwise (fun p q : OrderedParticlePair n ↦
      IsRelPrime (orderedPairFactor p) (orderedPairFactor q)) := by
  rintro ⟨i, j, hij⟩ ⟨k, l, hkl⟩ hpq
  apply isRelPrime_X_sub_X_of_ordered_pairs_ne
    (Finset.mem_Ioi.mp hij) (Finset.mem_Ioi.mp hkl)
  intro hpairs
  apply hpq
  have hik : i = k := congrArg Prod.fst hpairs
  have hjl : j = l := congrArg Prod.snd hpairs
  subst k
  subst l
  rfl

/-- The product over ordered pairs is the polynomial Vandermonde. -/
theorem prod_orderedPairFactor (n : ℕ) :
    ∏ p : OrderedParticlePair n, orderedPairFactor p =
      polynomialVandermonde n := by
  rw [polynomialVandermonde_eq_product]
  rw [Fintype.prod_sigma]
  apply Finset.prod_congr rfl
  intro i hi
  symm
  exact Finset.prod_subtype (Finset.Ioi i) (by simp) _

/-- Every alternating configuration polynomial is divisible by the complete
Vandermonde polynomial. -/
theorem polynomialVandermonde_dvd_of_alternating {n : ℕ}
    {P : ConfigurationPolynomial n}
    (hP : IsAlternatingConfigurationPolynomial P) :
    polynomialVandermonde n ∣ P := by
  rw [← prod_orderedPairFactor n]
  apply Fintype.prod_dvd_of_isRelPrime
    (pairwise_isRelPrime_orderedPairFactor n)
  intro p
  have hp : p.1 < p.2.1 := Finset.mem_Ioi.mp p.2.2
  exact X_sub_X_dvd_of_alternating hP hp.ne

/-- Algebraic Vandermonde division for alternating polynomials, with a
symmetric quotient. -/
theorem alternating_polynomial_vandermonde_division {n : ℕ}
    {P : ConfigurationPolynomial n}
    (hP : IsAlternatingConfigurationPolynomial P) :
    ∃ Q : ConfigurationPolynomial n,
      IsSymmetricConfigurationPolynomial Q ∧
        P = polynomialVandermonde n * Q :=
  alternating_polynomial_division_of_dvd hP
    (polynomialVandermonde_dvd_of_alternating hP)

/-! ## Finite zero-antiholomorphic Hermite sums -/

/-- The holomorphic polynomial attached coefficient-by-coefficient to a
finite linear combination of zero-antiholomorphic Hermite tensors. -/
def finiteZeroAntiholomorphicHermitePolynomial (n : ℕ)
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ) :
    ConfigurationPolynomial n :=
  ∑ p ∈ S, MvPolynomial.C (c p) * holomorphicHermitePolynomial n p

/-- The corresponding finite Hermite function. -/
def finiteZeroAntiholomorphicHermiteSum (n : ℕ) (hn : 0 < n)
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
    (z : Configuration n) : ℂ :=
  ∑ p ∈ S, c p * ComplexHermite.multivariateNormalized n hn p 0 z

/-- Evaluation commutes exactly with formation of the finite Hermite sum. -/
theorem eval_finiteZeroAntiholomorphicHermitePolynomial (n : ℕ)
    (hn : 0 < n) (S : Finset (Fin n → ℕ))
    (c : (Fin n → ℕ) → ℂ) (z : Configuration n) :
    MvPolynomial.eval z
        (finiteZeroAntiholomorphicHermitePolynomial n S c) =
      finiteZeroAntiholomorphicHermiteSum n hn S c z := by
  unfold finiteZeroAntiholomorphicHermitePolynomial
    finiteZeroAntiholomorphicHermiteSum
  simp only [map_sum, map_mul, MvPolynomial.eval_C]
  apply Finset.sum_congr rfl
  intro p hp
  rw [eval_holomorphicHermitePolynomial n hn p z]

/-- At positive particle number the ground-state normalization is nonzero. -/
theorem groundStateNormalization_ne_zero_of_pos {n : ℕ} (hn : 0 < n) :
    groundStateNormalization n ≠ 0 := by
  apply ne_of_gt
  unfold groundStateNormalization
  apply Real.sqrt_pos.2
  exact ENNReal.toReal_pos (ginibreNormalizingMass_pos hn).ne'
    (ginibreNormalizingMass_lt_top n).ne

/-- Coefficient-level finite Hermite division.  An algebraically alternating
finite zero-antiholomorphic Hermite sum is exactly a Vandermonde times the
evaluation of a symmetric holomorphic polynomial. -/
theorem finiteZeroAntiholomorphicHermiteSum_division {n : ℕ} (hn : 0 < n)
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ)
    (hAlt : IsAlternatingConfigurationPolynomial
      (finiteZeroAntiholomorphicHermitePolynomial n S c)) :
    ∃ Q : ConfigurationPolynomial n,
      IsSymmetricConfigurationPolynomial Q ∧
      ∀ z : Configuration n,
        finiteZeroAntiholomorphicHermiteSum n hn S c z =
          vandermonde z * MvPolynomial.eval z Q := by
  obtain ⟨Q, hQ, hfactor⟩ := alternating_polynomial_vandermonde_division hAlt
  refine ⟨Q, hQ, fun z ↦ ?_⟩
  rw [← eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c z,
    hfactor, map_mul, eval_polynomialVandermonde]

/-- Functional alternation of a finite zero-antiholomorphic Hermite sum is
equivalent to algebraic alternation of its coefficient polynomial. -/
theorem isAlternatingConfigurationPolynomial_of_finiteHermiteSum
    {n : ℕ} (hn : 0 < n) (S : Finset (Fin n → ℕ))
    (c : (Fin n → ℕ) → ℂ)
    (hAlt : IsAlternating
      (finiteZeroAntiholomorphicHermiteSum n hn S c)) :
    IsAlternatingConfigurationPolynomial
      (finiteZeroAntiholomorphicHermitePolynomial n S c) := by
  intro σ
  apply MvPolynomial.funext
  intro z
  rw [eval_permuteConfigurationPolynomial,
    eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c,
    map_mul, MvPolynomial.eval_C,
    eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c]
  exact hAlt σ z

/-- Thus no alternation information is lost when passing between the finite
Hermite coefficient sum and its holomorphic polynomial representative. -/
theorem finiteHermiteSum_isAlternating_iff {n : ℕ} (hn : 0 < n)
    (S : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ) :
    IsAlternating (finiteZeroAntiholomorphicHermiteSum n hn S c) ↔
      IsAlternatingConfigurationPolynomial
        (finiteZeroAntiholomorphicHermitePolynomial n S c) := by
  constructor
  · exact isAlternatingConfigurationPolynomial_of_finiteHermiteSum hn S c
  · intro hP
    have heval := isAlternating_eval_of_polynomial hP
    intro σ z
    rw [← eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c]
    rw [← eval_finiteZeroAntiholomorphicHermitePolynomial n hn S c]
    exact heval σ z

/-- The preceding factorization is precisely the normalized Vandermonde
transform after multiplying the symmetric quotient by the ground-state
normalization. -/
theorem finiteZeroAntiholomorphicHermiteSum_eq_normalizedTransform
    {n : ℕ} (hn : 0 < n) (S : Finset (Fin n → ℕ))
    (c : (Fin n → ℕ) → ℂ)
    (hAlt : IsAlternatingConfigurationPolynomial
      (finiteZeroAntiholomorphicHermitePolynomial n S c)) :
    ∃ Q : ConfigurationPolynomial n,
      IsSymmetricConfigurationPolynomial Q ∧
      ∀ z : Configuration n,
        finiteZeroAntiholomorphicHermiteSum n hn S c z =
          normalizedVandermondeTransform n
            (fun w ↦ (groundStateNormalization n : ℂ) *
              MvPolynomial.eval w Q) z := by
  obtain ⟨Q, hQ, hsum⟩ :=
    finiteZeroAntiholomorphicHermiteSum_division hn S c hAlt
  refine ⟨Q, hQ, fun z ↦ ?_⟩
  rw [hsum z, normalizedVandermondeTransform_apply]
  have hnorm : (groundStateNormalization n : ℂ) ≠ 0 := by
    exact_mod_cast groundStateNormalization_ne_zero_of_pos hn
  field_simp

/-- Function-level finite-span identification: every alternating finite
zero-antiholomorphic Hermite combination is the normalized Vandermonde
transform of the evaluation of a symmetric holomorphic polynomial (with the
exact ground-state scalar). -/
theorem alternating_finiteZeroAntiholomorphicHermiteSpan
    {n : ℕ} (hn : 0 < n) (S : Finset (Fin n → ℕ))
    (c : (Fin n → ℕ) → ℂ)
    (hAlt : IsAlternating
      (finiteZeroAntiholomorphicHermiteSum n hn S c)) :
    ∃ Q : ConfigurationPolynomial n,
      IsSymmetricConfigurationPolynomial Q ∧
      ∀ z : Configuration n,
        finiteZeroAntiholomorphicHermiteSum n hn S c z =
          normalizedVandermondeTransform n
            (fun w ↦ (groundStateNormalization n : ℂ) *
              MvPolynomial.eval w Q) z :=
  finiteZeroAntiholomorphicHermiteSum_eq_normalizedTransform hn S c
    (isAlternatingConfigurationPolynomial_of_finiteHermiteSum hn S c hAlt)

/-- Away from the collision locus, division by the normalized Vandermonde
recovers the symmetric polynomial quotient pointwise. -/
theorem finiteZeroAntiholomorphicHermiteSum_normalizedInverse
    {n : ℕ} (hn : 0 < n) (S : Finset (Fin n → ℕ))
    (c : (Fin n → ℕ) → ℂ)
    (hAlt : IsAlternatingConfigurationPolynomial
      (finiteZeroAntiholomorphicHermitePolynomial n S c)) :
    ∃ Q : ConfigurationPolynomial n,
      IsSymmetricConfigurationPolynomial Q ∧
      ∀ z : Configuration n, vandermonde z ≠ 0 →
        (groundStateNormalization n : ℂ) *
            finiteZeroAntiholomorphicHermiteSum n hn S c z /
              vandermonde z =
          (groundStateNormalization n : ℂ) * MvPolynomial.eval z Q := by
  obtain ⟨Q, hQ, hsum⟩ :=
    finiteZeroAntiholomorphicHermiteSum_division hn S c hAlt
  refine ⟨Q, hQ, fun z hz ↦ ?_⟩
  rw [hsum z]
  field_simp

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/HolomorphicVandermondeL2Closure.lean #
import GinibrePoincare.Analysis.HolomorphicVandermondeDivision
import GinibrePoincare.Analysis.HermiteEnergy
import GinibrePoincare.Analysis.VandermondeL2Inverse

/-! # Closed zero-mode Vandermonde correspondence -/

open MeasureTheory

namespace GinibrePoincare
namespace ComplexHermite

noncomputable section

local instance completeSpace_gaussianAlternatingL2 (n : ℕ) :
    CompleteSpace (gaussianAlternatingL2 n) :=
  (isClosed_gaussianAlternatingL2 n).completeSpace_coe

local instance completeSpace_ginibreSymmetricL2 (n : ℕ) :
    CompleteSpace (ginibreSymmetricL2 n) :=
  (isClosed_ginibreSymmetricL2 n).completeSpace_coe

/-- The signed finite average of coordinate permutations on Gaussian `L²`. -/
def gaussianAlternationOperator (n : ℕ) :
    Lp ℂ 2 (complexGaussianMeasure n) →L[ℂ]
      Lp ℂ 2 (complexGaussianMeasure n) :=
  ((Fintype.card (ParticlePermutation n) : ℂ)⁻¹) •
    ∑ σ : ParticlePermutation n,
      (permutationSign σ) •
        (gaussianPermutationL2 σ).toContinuousLinearMap

@[simp] theorem gaussianAlternationOperator_apply (n : ℕ)
    (u : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianAlternationOperator n u =
      ((Fintype.card (ParticlePermutation n) : ℂ)⁻¹) •
        ∑ σ : ParticlePermutation n,
          (permutationSign σ) • gaussianPermutationL2 σ u := by
  simp [gaussianAlternationOperator]

private theorem permutationSign_mul_self {n : ℕ}
    (σ : ParticlePermutation n) :
    (permutationSign σ : ℂ) * permutationSign σ = 1 := by
  unfold permutationSign
  rcases Int.units_eq_one_or (Equiv.Perm.sign σ) with h | h <;>
    simp [h]

/-- The signed average fixes every alternating Gaussian vector. -/
theorem gaussianAlternationOperator_eq_self_of_mem {n : ℕ}
    {u : Lp ℂ 2 (complexGaussianMeasure n)}
    (hu : u ∈ gaussianAlternatingL2 n) :
    gaussianAlternationOperator n u = u := by
  change ∀ σ : ParticlePermutation n,
    gaussianPermutationL2 σ u = permutationSign σ • u at hu
  rw [gaussianAlternationOperator_apply]
  simp_rw [hu, smul_smul, permutationSign_mul_self, one_smul]
  rw [Finset.sum_const, ← Nat.cast_smul_eq_nsmul ℂ]
  simp only [Finset.card_univ]
  have hcard : (Fintype.card (ParticlePermutation n) : ℂ) ≠ 0 := by
    exact_mod_cast Fintype.card_ne_zero
  rw [← mul_smul, inv_mul_cancel₀ hcard, one_smul]

/-- Coordinate relabelling simply reindexes both Hermite multi-indices. -/
theorem multivariateNormalized_permute (n : ℕ) (hn : 0 < n)
    (σ : ParticlePermutation n) (p q : Fin n → ℕ) (z : Configuration n) :
    multivariateNormalized n hn p q (permute σ z) =
      multivariateNormalized n hn (p ∘ σ.symm) (q ∘ σ.symm) z := by
  unfold multivariateNormalized
  rw [← Equiv.prod_comp σ.symm]
  apply Finset.prod_congr rfl
  intro i hi
  simp [Function.comp_def]

/-- The Gaussian permutation operator reindexes Hermite basis vectors. -/
theorem gaussianPermutationL2_hermiteL2Family (n : ℕ) (hn : 0 < n)
    (σ : ParticlePermutation n) (p q : Fin n → ℕ) :
    gaussianPermutationL2 σ (hermiteL2Family n hn (p, q)) =
      hermiteL2Family n hn (p ∘ σ.symm, q ∘ σ.symm) := by
  apply Lp.ext
  have hsourcecomp :=
    (gaussian_measurePreserving_permute σ).quasiMeasurePreserving.ae_eq_comp
      (hermiteL2Family_coeFn n hn (p, q))
  filter_upwards [Lp.coeFn_compMeasurePreserving
      (hermiteL2Family n hn (p, q))
      (gaussian_measurePreserving_permute σ),
    hsourcecomp,
    hermiteL2Family_coeFn n hn (p ∘ σ.symm, q ∘ σ.symm)] with z hcomp hsource htarget
  change (gaussianPermutationL2 σ (hermiteL2Family n hn (p, q))) z = _
  rw [show (gaussianPermutationL2 σ (hermiteL2Family n hn (p, q))) z =
      hermiteL2Family n hn (p, q) (permute σ z) by exact hcomp]
  change hermiteL2Family n hn (p, q) (permute σ z) =
    multivariateNormalized n hn p q (permute σ z) at hsource
  rw [hsource, htarget, multivariateNormalized_permute]

/-- Every coordinate permutation preserves each finite antiholomorphic-degree
Hermite span. -/
theorem gaussianPermutationL2_mem_hermiteAntiDegreeSpan
    (n : ℕ) (hn : 0 < n) (d : ℕ) (σ : ParticlePermutation n)
    {u : Lp ℂ 2 (complexGaussianMeasure n)}
    (hu : u ∈ hermiteAntiDegreeSpan n hn d) :
    gaussianPermutationL2 σ u ∈ hermiteAntiDegreeSpan n hn d := by
  unfold hermiteAntiDegreeSpan at hu ⊢
  refine Submodule.span_induction
    (p := fun x _ ↦ gaussianPermutationL2 σ x ∈
      Submodule.span ℂ (hermiteL2Family n hn ''
        {pq | totalAntiDegree pq = d}))
    ?_ (by simp) ?_ ?_ hu
  · intro y hy
    obtain ⟨⟨p, q⟩, hpq, rfl⟩ := hy
    rw [gaussianPermutationL2_hermiteL2Family]
    apply Submodule.subset_span
    refine ⟨(p ∘ σ.symm, q ∘ σ.symm), ?_, rfl⟩
    change (∑ i, q (σ.symm i)) = d
    exact (Equiv.sum_comp σ.symm q).trans hpq
  · intro x y hx hy hx' hy'
    rw [map_add]
    exact add_mem hx' hy'
  · intro a x hx hx'
    rw [map_smul]
    exact Submodule.smul_mem _ _ hx'

/-- Consequently the signed finite average preserves every finite
antiholomorphic-degree Hermite span. -/
theorem gaussianAlternationOperator_mem_hermiteAntiDegreeSpan
    (n : ℕ) (hn : 0 < n) (d : ℕ)
    {u : Lp ℂ 2 (complexGaussianMeasure n)}
    (hu : u ∈ hermiteAntiDegreeSpan n hn d) :
    gaussianAlternationOperator n u ∈ hermiteAntiDegreeSpan n hn d := by
  rw [gaussianAlternationOperator_apply]
  apply Submodule.smul_mem
  apply Submodule.sum_mem
  intro σ hσ
  apply Submodule.smul_mem
  exact gaussianPermutationL2_mem_hermiteAntiDegreeSpan n hn d σ hu

/-- Gaussian coordinate pullback is an antihomomorphism of the permutation
group (the outer pullback appears on the left of the product). -/
theorem gaussianPermutationL2_comp_apply {n : ℕ}
    (τ σ : ParticlePermutation n)
    (u : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianPermutationL2 τ (gaussianPermutationL2 σ u) =
      gaussianPermutationL2 (τ * σ) u := by
  unfold gaussianPermutationL2
  change (Lp.compMeasurePreserving (permute τ)
      (gaussian_measurePreserving_permute τ))
      ((Lp.compMeasurePreserving (permute σ)
        (gaussian_measurePreserving_permute σ)) u) = _
  rw [← Lp.compMeasurePreserving_comp_apply]
  have hfun : permute σ ∘ permute τ = permute (τ * σ) := by
    funext z
    ext i
    simp [Function.comp_def, permute]
  cases hfun
  rfl

/-- The complex-valued permutation sign is multiplicative. -/
theorem permutationSign_mul {n : ℕ} (τ σ : ParticlePermutation n) :
    permutationSign (τ * σ) = permutationSign τ * permutationSign σ := by
  simp [permutationSign, Equiv.Perm.sign_mul]

/-- The signed average transforms according to the sign character. -/
theorem gaussianPermutationL2_gaussianAlternationOperator {n : ℕ}
    (τ : ParticlePermutation n)
    (u : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianPermutationL2 τ (gaussianAlternationOperator n u) =
      permutationSign τ • gaussianAlternationOperator n u := by
  rw [gaussianAlternationOperator_apply, map_smul, map_sum]
  simp_rw [map_smul, gaussianPermutationL2_comp_apply]
  have hsum :
      (∑ σ : ParticlePermutation n,
          permutationSign σ • gaussianPermutationL2 (τ * σ) u) =
        permutationSign τ •
          ∑ σ : ParticlePermutation n,
            permutationSign σ • gaussianPermutationL2 σ u := by
    calc
      _ = ∑ σ : ParticlePermutation n,
          permutationSign τ • (permutationSign (τ * σ) •
            gaussianPermutationL2 (τ * σ) u) := by
        apply Finset.sum_congr rfl
        intro σ hσ
        rw [permutationSign_mul, smul_smul]
        have hs := permutationSign_mul_self τ
        rw [← mul_assoc, hs, one_mul]
      _ = permutationSign τ •
          ∑ σ : ParticlePermutation n,
            permutationSign (τ * σ) •
              gaussianPermutationL2 (τ * σ) u := by
        rw [Finset.smul_sum]
      _ = _ := by
        change permutationSign τ •
          ∑ σ, (fun ρ : ParticlePermutation n ↦
            permutationSign ρ • gaussianPermutationL2 ρ u)
              ((Equiv.mulLeft τ) σ) = _
        congr 1
        exact Equiv.sum_comp (Equiv.mulLeft τ)
          (fun ρ : ParticlePermutation n ↦
            permutationSign ρ • gaussianPermutationL2 ρ u)
  rw [hsum, smul_smul]
  module

/-- The image of the signed average is alternating. -/
theorem gaussianAlternationOperator_mem (n : ℕ)
    (u : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianAlternationOperator n u ∈ gaussianAlternatingL2 n := by
  intro τ
  exact gaussianPermutationL2_gaussianAlternationOperator τ u

/-- Hence the signed average fixes exactly the alternating Gaussian vectors. -/
theorem gaussianAlternationOperator_eq_self_iff {n : ℕ}
    (u : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianAlternationOperator n u = u ↔ u ∈ gaussianAlternatingL2 n := by
  constructor
  · intro h
    rw [← h]
    exact gaussianAlternationOperator_mem n u
  · exact gaussianAlternationOperator_eq_self_of_mem

/-- Alternating Gaussian vectors which are finite linear combinations of
Hermite tensors of antiholomorphic degree zero. -/
def gaussianAlternatingFiniteZeroModeSpan (n : ℕ) (hn : 0 < n) :
    Submodule ℂ (gaussianAlternatingL2 n) :=
  (hermiteAntiDegreeSpan n hn 0).comap
    (gaussianAlternatingL2 n).subtype

/-- The closed alternating part of the degree-zero Hermite span. -/
def gaussianAlternatingZeroModeClosedSpan (n : ℕ) (hn : 0 < n) :
    ClosedSubmodule ℂ (gaussianAlternatingL2 n) where
  toSubmodule := (gaussianAlternatingFiniteZeroModeSpan n hn).topologicalClosure
  isClosed' := (gaussianAlternatingFiniteZeroModeSpan n hn).isClosed_topologicalClosure

/-- Symmetric Ginibre finite holomorphic-polynomial vectors, defined exactly
as inverse normalized-Vandermonde transforms of alternating finite zero-mode
Hermite vectors.  The coefficient-level division theorem identifies these
inverse transforms with symmetric holomorphic polynomial evaluations. -/
def ginibreSymmetricHolomorphicPolynomialSpan (n : ℕ) (hn : 0 < n) :
    Submodule ℂ (ginibreSymmetricL2 n) :=
  (gaussianAlternatingFiniteZeroModeSpan n hn).map
    (vandermondeSymmetricAlternatingEquiv n hn).symm.toLinearMap

/-- Closure of the symmetric holomorphic-polynomial Ginibre vectors. -/
def ginibreSymmetricHolomorphicPolynomialClosedSpan (n : ℕ) (hn : 0 < n) :
    ClosedSubmodule ℂ (ginibreSymmetricL2 n) where
  toSubmodule :=
    (ginibreSymmetricHolomorphicPolynomialSpan n hn).topologicalClosure
  isClosed' :=
    (ginibreSymmetricHolomorphicPolynomialSpan n hn).isClosed_topologicalClosure

theorem map_ginibreSymmetricHolomorphicPolynomialSpan (n : ℕ) (hn : 0 < n) :
    (ginibreSymmetricHolomorphicPolynomialSpan n hn).map
        (vandermondeSymmetricAlternatingEquiv n hn).toLinearMap =
      gaussianAlternatingFiniteZeroModeSpan n hn := by
  ext v
  constructor
  · rintro ⟨u, ⟨w, hw, rfl⟩, rfl⟩
    simpa using hw
  · intro hv
    refine ⟨(vandermondeSymmetricAlternatingEquiv n hn).symm v, ?_, by simp⟩
    exact ⟨v, hv, rfl⟩

/-- The unitary Vandermonde equivalence maps the closure of symmetric
holomorphic polynomial vectors onto the closed alternating zero mode. -/
theorem map_ginibreSymmetricHolomorphicPolynomialClosedSpan
    (n : ℕ) (hn : 0 < n) :
    (ginibreSymmetricHolomorphicPolynomialClosedSpan n hn).toSubmodule.map
        (vandermondeSymmetricAlternatingEquiv n hn).toLinearMap =
      (gaussianAlternatingZeroModeClosedSpan n hn).toSubmodule := by
  apply le_antisymm
  · refine (Submodule.topologicalClosure_map
      (vandermondeSymmetricAlternatingEquiv n hn).toLinearIsometry.toContinuousLinearMap
      (ginibreSymmetricHolomorphicPolynomialSpan n hn)).trans ?_
    change ((ginibreSymmetricHolomorphicPolynomialSpan n hn).map
      (vandermondeSymmetricAlternatingEquiv n hn).toLinearMap).topologicalClosure ≤
        (gaussianAlternatingFiniteZeroModeSpan n hn).topologicalClosure
    rw [map_ginibreSymmetricHolomorphicPolynomialSpan]
  · intro v hv
    change v ∈ (gaussianAlternatingFiniteZeroModeSpan n hn).topologicalClosure at hv
    have hback :
        (vandermondeSymmetricAlternatingEquiv n hn).symm v ∈
          (ginibreSymmetricHolomorphicPolynomialSpan n hn).topologicalClosure := by
      apply (Submodule.topologicalClosure_map
        (vandermondeSymmetricAlternatingEquiv n hn).symm.toLinearIsometry.toContinuousLinearMap
        (gaussianAlternatingFiniteZeroModeSpan n hn))
      exact ⟨v, hv, rfl⟩
    exact ⟨(vandermondeSymmetricAlternatingEquiv n hn).symm v, hback, by simp⟩

/-- In particular, the closed alternating zero mode embeds in the ambient
closed degree-zero Hermite span. -/
theorem gaussianAlternatingZeroModeClosedSpan_le_hermiteZeroMode
    (n : ℕ) (hn : 0 < n) :
    (gaussianAlternatingZeroModeClosedSpan n hn).toSubmodule ≤
      (hermiteAntiDegreeClosedSpan n hn 0).toSubmodule.comap
        (gaussianAlternatingL2 n).subtype := by
  apply Submodule.topologicalClosure_minimal
  · intro v hv
    exact (hermiteAntiDegreeSpan n hn 0).le_topologicalClosure hv
  · exact (hermiteAntiDegreeClosedSpan n hn 0).isClosed.preimage
      (gaussianAlternatingL2 n).subtypeL.continuous

/-- Alternation of finite approximants proves that the closed alternating
zero mode is exactly the intersection of the full closed zero mode with the
alternating Gaussian subspace. -/
theorem gaussianAlternatingZeroModeClosedSpan_eq_hermiteZeroMode_comap
    (n : ℕ) (hn : 0 < n) :
    (gaussianAlternatingZeroModeClosedSpan n hn).toSubmodule =
      (hermiteAntiDegreeClosedSpan n hn 0).toSubmodule.comap
        (gaussianAlternatingL2 n).subtype := by
  apply le_antisymm
  · exact gaussianAlternatingZeroModeClosedSpan_le_hermiteZeroMode n hn
  · intro v hv
    change v.1 ∈ (hermiteAntiDegreeSpan n hn 0).topologicalClosure at hv
    have himage : gaussianAlternationOperator n v.1 ∈
        closure (gaussianAlternationOperator n ''
          (hermiteAntiDegreeSpan n hn 0 :
            Set (Lp ℂ 2 (complexGaussianMeasure n)))) :=
      image_closure_subset_closure_image
        (gaussianAlternationOperator n).continuous ⟨v.1, hv, rfl⟩
    rw [gaussianAlternationOperator_eq_self_of_mem v.2] at himage
    have hsubset :
        gaussianAlternationOperator n ''
            (hermiteAntiDegreeSpan n hn 0 :
              Set (Lp ℂ 2 (complexGaussianMeasure n))) ⊆
          ((fun w : gaussianAlternatingL2 n ↦ w.1) ''
            (gaussianAlternatingFiniteZeroModeSpan n hn :
              Set (gaussianAlternatingL2 n))) := by
      rintro _ ⟨u, hu, rfl⟩
      let w : gaussianAlternatingL2 n :=
        ⟨gaussianAlternationOperator n u,
          gaussianAlternationOperator_mem n u⟩
      refine ⟨w, ?_, rfl⟩
      exact gaussianAlternationOperator_mem_hermiteAntiDegreeSpan n hn 0 hu
    have hclosure := closure_mono hsubset himage
    have hclosedEmbedding : Topology.IsClosedEmbedding
        (fun w : gaussianAlternatingL2 n ↦ w.1) :=
      (isClosed_gaussianAlternatingL2 n).isClosedEmbedding_subtypeVal
    rw [hclosedEmbedding.closure_image_eq] at hclosure
    obtain ⟨w, hw, hwv⟩ := hclosure
    have : w = v := Subtype.ext hwv
    subst w
    exact hw

/-! ## Closed holomorphic projectors -/

/-- Orthogonal projection of symmetric Ginibre `L²` onto the closed
holomorphic-polynomial subspace. -/
def ginibreSymmetricHolomorphicProjection (n : ℕ) (hn : 0 < n) :
    ginibreSymmetricL2 n →L[ℂ] ginibreSymmetricL2 n :=
  (ginibreSymmetricHolomorphicPolynomialClosedSpan n hn).starProjection

/-- Orthogonal projection of alternating Gaussian `L²` onto its closed
degree-zero Hermite subspace. -/
def gaussianAlternatingZeroModeProjection (n : ℕ) (hn : 0 < n) :
    gaussianAlternatingL2 n →L[ℂ] gaussianAlternatingL2 n :=
  ((ginibreSymmetricHolomorphicPolynomialClosedSpan n hn).toSubmodule.map
    ((vandermondeSymmetricAlternatingEquiv n hn).toLinearEquiv :
      ginibreSymmetricL2 n →ₗ[ℂ] gaussianAlternatingL2 n)).starProjection

/-- The Vandermonde unitary intertwines the two closed-subspace
projections. -/
theorem vandermondeEquiv_intertwines_holomorphicProjection
    (n : ℕ) (hn : 0 < n) (u : ginibreSymmetricL2 n) :
    vandermondeSymmetricAlternatingEquiv n hn
        (ginibreSymmetricHolomorphicProjection n hn u) =
      gaussianAlternatingZeroModeProjection n hn
        (vandermondeSymmetricAlternatingEquiv n hn u) := by
  unfold ginibreSymmetricHolomorphicProjection
    gaussianAlternatingZeroModeProjection
  simpa only [LinearIsometryEquiv.symm_apply_apply] using
    (Submodule.starProjection_map_apply
    (vandermondeSymmetricAlternatingEquiv n hn)
    (ginibreSymmetricHolomorphicPolynomialClosedSpan n hn).toSubmodule
    (vandermondeSymmetricAlternatingEquiv n hn u)).symm

/-- The symmetric Ginibre holomorphic component of `u`. -/
def ginibreSymmetricHolomorphicPart (n : ℕ) (hn : 0 < n)
    (u : ginibreSymmetricL2 n) : ginibreSymmetricL2 n :=
  ginibreSymmetricHolomorphicProjection n hn u

/-- The Gaussian degree-zero component obtained from a symmetric Ginibre
vector by the normalized Vandermonde transform. -/
def gaussianZeroModeOfGinibre (n : ℕ) (hn : 0 < n)
    (u : ginibreSymmetricL2 n) : gaussianAlternatingL2 n :=
  gaussianAlternatingZeroModeProjection n hn
    (vandermondeSymmetricAlternatingEquiv n hn u)

/-- For every symmetric Ginibre vector, its projected holomorphic part `h`
has normalized Vandermonde transform equal to its Gaussian zero mode `g₀`. -/
theorem transform_ginibreSymmetricHolomorphicPart_eq_gaussianZeroMode
    (n : ℕ) (hn : 0 < n) (u : ginibreSymmetricL2 n) :
    vandermondeSymmetricAlternatingEquiv n hn
        (ginibreSymmetricHolomorphicPart n hn u) =
      gaussianZeroModeOfGinibre n hn u :=
  vandermondeEquiv_intertwines_holomorphicProjection n hn u

/-- The Gaussian component `g₀` belongs to the ambient degree-zero Hermite
closed span. -/
theorem gaussianZeroModeOfGinibre_mem_hermiteZeroMode
    (n : ℕ) (hn : 0 < n) (u : ginibreSymmetricL2 n) :
    (gaussianZeroModeOfGinibre n hn u).1 ∈
      hermiteAntiDegreeClosedSpan n hn 0 := by
  have hmem : gaussianZeroModeOfGinibre n hn u ∈
      (ginibreSymmetricHolomorphicPolynomialClosedSpan n hn).toSubmodule.map
        ((vandermondeSymmetricAlternatingEquiv n hn).toLinearEquiv :
          ginibreSymmetricL2 n →ₗ[ℂ] gaussianAlternatingL2 n) :=
    Submodule.starProjection_apply_mem _ _
  rw [map_ginibreSymmetricHolomorphicPolynomialClosedSpan n hn] at hmem
  exact gaussianAlternatingZeroModeClosedSpan_le_hermiteZeroMode n hn hmem

end
end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/L2RepresentativeBridges.lean #
import GinibrePoincare.Analysis.FiniteHermiteDeficit
import GinibrePoincare.Analysis.HermiteParsevalModes
import GinibrePoincare.Analysis.GroundStateDbar
import GinibrePoincare.Analysis.VandermondeL2Inverse
import GinibrePoincare.Analysis.ComplexGaussianDensity
import GinibrePoincare.Analysis.GinibreMassFiniteness
import GinibrePoincare.Concrete.Generator
import Mathlib.MeasureTheory.Measure.OpenPos
import Mathlib.MeasureTheory.Function.LpSpace.Indicator
import Mathlib.Topology.ContinuousMap.BoundedCompactlySupported

/-! # Bridges between concrete representatives and `L²` classes -/

open MeasureTheory

namespace GinibrePoincare

noncomputable section

/-- Continuous Gaussian representatives that agree almost everywhere agree
pointwise. -/
theorem continuous_eq_of_ae_eq_complexGaussian {n : ℕ}
    (hn : 0 < n) {f g : Configuration n → ℂ} (hf : Continuous f) (hg : Continuous g)
    (h : f =ᵐ[complexGaussianMeasure n] g) : f = g := by
  letI : (complexGaussianMeasure n).IsOpenPosMeasure := by
    rw [complexGaussianDensityIdentification n hn]
    letI : (configurationVolume n).IsOpenPosMeasure := by
      unfold configurationVolume
      infer_instance
    have hac : configurationVolume n ≪
        (configurationVolume n).withDensity (complexGaussianDensity n) := by
      apply withDensity_absolutelyContinuous'
      · exact (measurable_complexGaussianDensity n).aemeasurable
      · filter_upwards with z
        unfold complexGaussianDensity gaussianWeight
        positivity
    exact hac.isOpenPosMeasure
  exact Measure.eq_of_ae_eq h hf hg

/-- A centered core observable is square-integrable for the Ginibre measure. -/
theorem memLp_centeredObservable_of_core {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    MemLp (fun z => (centeredObservable n f z : ℂ)) 2 (ginibreMeasure n) := by
  letI := ginibreMeasure_isProbabilityMeasure hn
  let F : Configuration n → ℂ := fun z => (f z : ℂ)
  have hFc : Continuous F := by
    exact Complex.continuous_ofReal.comp hf.1.continuous
  have hFcomp : HasCompactSupport F := by
    apply hf.2.1.mono
    intro z hz
    intro hzero
    apply hz
    simp only [F, hzero, Complex.ofReal_zero]
  let Fb := ofCompactSupport F hFc hFcomp
  have hmemF : MemLp F 2 (ginibreMeasure n) := by
    apply MemLp.of_bound hFc.aestronglyMeasurable ‖Fb‖
    filter_upwards with z
    exact Fb.norm_coe_le_norm z
  convert hmemF.sub (memLp_const (smoothGinibreMean n f : ℂ)) using 1
  ext z
  simp [F, centeredObservable]

/-- The centered real observable, embedded into complex Ginibre `L²`. -/
def centeredObservableL2 {n : ℕ} (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) : Lp ℂ 2 (ginibreMeasure n) :=
  (memLp_centeredObservable_of_core hn f hf).toLp _

theorem centeredObservableL2_coeFn {n : ℕ} (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) :
    centeredObservableL2 hn f hf =ᵐ[ginibreMeasure n]
      fun z => (centeredObservable n f z : ℂ) := by
  exact (memLp_centeredObservable_of_core hn f hf).coeFn_toLp

/-- The squared Ginibre `L²` norm of the centered observable is its concrete
variance. -/
theorem norm_sq_centeredObservableL2 {n : ℕ} (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) :
    ‖centeredObservableL2 hn f hf‖ ^ 2 = smoothGinibreVariance n f := by
  have hinner :
      inner ℂ (centeredObservableL2 hn f hf) (centeredObservableL2 hn f hf) =
        ∫ z, inner ℂ ((centeredObservableL2 hn f hf) z)
          ((centeredObservableL2 hn f hf) z) ∂ginibreMeasure n :=
    MeasureTheory.L2.inner_def (centeredObservableL2 hn f hf)
      (centeredObservableL2 hn f hf)
  rw [inner_self_eq_norm_sq_to_K] at hinner
  have hc := centeredObservableL2_coeFn hn f hf
  rw [integral_congr_ae (by
    filter_upwards [hc] with z hz
    rw [hz])] at hinner
  have hi :
      (fun z => inner ℂ (centeredObservable n f z : ℂ)
        (centeredObservable n f z : ℂ)) =
      fun z => ((centeredObservable n f z) ^ 2 : ℂ) := by
    funext z
    simp only [RCLike.inner_apply, Complex.conj_ofReal, ← Complex.ofReal_mul,
      Complex.ofReal_inj, pow_two]
  rw [hi] at hinner
  simp_rw [← Complex.ofReal_pow] at hinner
  rw [integral_complex_ofReal] at hinner
  have hr : ‖centeredObservableL2 hn f hf‖ ^ 2 =
      ∫ z, centeredObservable n f z ^ 2 ∂ginibreMeasure n := by
    apply Complex.ofReal_injective
    convert hinner using 1 <;> simp [Complex.ofReal_pow]
  simpa [smoothGinibreVariance, centeredObservable] using hr

/-- The normalized Vandermonde image of the centered observable. -/
def transformedCenteredObservableL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    Lp ℂ 2 (complexGaussianMeasure n) :=
  normalizedVandermondeL2 n hn (centeredObservableL2 hn f hf)

/-- Vandermonde multiplication preserves the centered-observable norm and
hence realizes the variance in Gaussian `L²`. -/
theorem norm_sq_transformedCenteredObservableL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    ‖transformedCenteredObservableL2 hn f hf‖ ^ 2 =
      smoothGinibreVariance n f := by
  rw [transformedCenteredObservableL2,
    (normalizedVandermondeL2 n hn).norm_map,
    norm_sq_centeredObservableL2 hn]

/-- Concrete Parseval decomposition of the Ginibre variance into the
holomorphic (zero antiholomorphic degree) part and the positive modes. -/
theorem smoothGinibreVariance_eq_zeroMode_add_positiveModeMass {n : ℕ}
    (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) :
    smoothGinibreVariance n f =
      ‖gaussianHermiteMode hn 0
        (transformedCenteredObservableL2 hn f hf)‖ ^ 2 +
      ∑' k, positiveHermiteModeMass hn
        (transformedCenteredObservableL2 hn f hf) k := by
  rw [← norm_sq_transformedCenteredObservableL2 hn f hf]
  exact norm_sq_eq_zeroMode_add_positiveModeMass hn _

theorem summable_transformedCentered_positiveModeMass {n : ℕ}
    (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) :
    Summable (positiveHermiteModeMass hn
      (transformedCenteredObservableL2 hn f hf)) :=
  summable_positiveHermiteModeMass hn _

end
end GinibrePoincare
Analysis GinibrePoincare/Analysis/MeasureTransport.lean #
import GinibrePoincare.Analysis.GaussianDensity
import Mathlib.MeasureTheory.Integral.Lebesgue.Map

/-! # Transporting densities through measure-preserving equivalences -/

open MeasureTheory

namespace MeasureTheory

variable {α β : Type*} [MeasurableSpace α] [MeasurableSpace β]
  {μ : Measure α} {ν : Measure β}

/-- A density pulled back along a measure-preserving measurable equivalence
pushes forward to the original density. -/
theorem MeasurePreserving.map_withDensity_comp
    (e : α ≃ᵐ β) (h : MeasurePreserving e μ ν)
    {f : β → ENNReal} (hf : Measurable f) :
    Measure.map e (μ.withDensity (f ∘ e)) = ν.withDensity f := by
  ext s hs
  rw [Measure.map_apply e.measurable hs,
    withDensity_apply _ (e.measurable hs), withDensity_apply _ hs]
  exact h.setLIntegral_comp_preimage hs hf

/-- Specialization to the standard real-coordinate representation of `ℂ`. -/
theorem map_complexPi_withDensity
    {f : ℂ → ENNReal} (hf : Measurable f) :
    Measure.map Complex.measurableEquivPi.symm
        ((volume : Measure (Fin 2 → ℝ)).withDensity
          (f ∘ Complex.measurableEquivPi.symm)) =
      (volume : Measure ℂ).withDensity f := by
  exact MeasurePreserving.map_withDensity_comp _
    Complex.volume_preserving_equiv_pi.symm hf

end MeasureTheory
Analysis GinibrePoincare/Analysis/MultivariateComplexHermite.lean #
import GinibrePoincare.Analysis.NormalizedComplexHermite
import Mathlib.Analysis.Complex.Basic
import Mathlib.Topology.Algebra.MvPolynomial

/-!
# Multivariate normalized complex Hermite functions

This file evaluates the normalized two-variable polynomial on the complex
diagonal and forms the finite tensor product over coordinates.  No analytic
completion is used at this stage.
-/

namespace GinibrePoincare

open scoped BigOperators ComplexConjugate

namespace ComplexHermite

@[simp] theorem oneDimNormalization_zero (n : ℕ) :
    oneDimNormalization n 0 = 1 := by
  simp [oneDimNormalization]

/-- Diagonal evaluation of the normalized univariate complex Hermite
polynomial. -/
noncomputable def normalizedEval (n : ℕ) (hn : 0 < n) (p q : ℕ) (z : ℂ) : ℂ :=
  MvPolynomial.eval ![z, conj z] (normalized n hn p q)

@[simp] theorem normalizedEval_zero_right (n : ℕ) (hn : 0 < n)
    (p : ℕ) (z : ℂ) :
    normalizedEval n hn p 0 z = (oneDimNormalization n p : ℂ) * z ^ p := by
  simp [normalizedEval, normalized, oneDimNormalization_zero, raw_zero_right, Z]

@[simp] theorem normalizedEval_zero_left (n : ℕ) (hn : 0 < n)
    (q : ℕ) (z : ℂ) :
    normalizedEval n hn 0 q z =
      (oneDimNormalization n q : ℂ) * (conj z) ^ q := by
  simp [normalizedEval, normalized, oneDimNormalization_zero, raw_zero_left, W]

@[simp] theorem normalizedEval_zero_zero (n : ℕ) (hn : 0 < n) (z : ℂ) :
    normalizedEval n hn 0 0 z = 1 := by
  simp

/-- A multivariate normalized complex Hermite function, indexed by two
multi-indices and defined as the coordinatewise tensor product. -/
noncomputable def multivariateNormalized (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) (z : Fin n → ℂ) : ℂ :=
  ∏ i, normalizedEval n hn (p i) (q i) (z i)

@[simp] theorem multivariateNormalized_zero_right (n : ℕ) (hn : 0 < n)
    (p : Fin n → ℕ) (z : Fin n → ℂ) :
    multivariateNormalized n hn p 0 z =
      ∏ i, (oneDimNormalization n (p i) : ℂ) * (z i) ^ p i := by
  simp [multivariateNormalized]

@[simp] theorem multivariateNormalized_zero_left (n : ℕ) (hn : 0 < n)
    (q : Fin n → ℕ) (z : Fin n → ℂ) :
    multivariateNormalized n hn 0 q z =
      ∏ i, (oneDimNormalization n (q i) : ℂ) * (conj (z i)) ^ q i := by
  simp [multivariateNormalized]

@[simp] theorem multivariateNormalized_zero_zero (n : ℕ) (hn : 0 < n)
    (z : Fin n → ℂ) :
    multivariateNormalized n hn 0 0 z = 1 := by
  simp [multivariateNormalized]

/-- Every normalized diagonal Hermite function is continuous. -/
theorem continuous_normalizedEval (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    Continuous (normalizedEval n hn p q) := by
  unfold normalizedEval
  apply (MvPolynomial.continuous_eval (normalized n hn p q)).comp
  apply continuous_pi
  intro i
  fin_cases i
  · exact continuous_id
  · exact Complex.continuous_conj

/-- A finite coordinate product of normalized Hermite functions is
continuous on `ℂⁿ`. -/
theorem continuous_multivariateNormalized (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) :
    Continuous (multivariateNormalized n hn p q) := by
  unfold multivariateNormalized
  apply continuous_finsetProd Finset.univ
  intro i hi
  exact (continuous_normalizedEval n hn (p i) (q i)).comp (continuous_apply i)

end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/MultivariateHermiteIntegrability.lean #
import GinibrePoincare.Analysis.ComplexHermiteOrthogonality
import Mathlib.MeasureTheory.Function.L2Space
import Mathlib.MeasureTheory.Integral.Pi

/-!
# Integrability of multivariate complex Hermite functions

Finite complex-Hermite tensors have polynomial growth, hence belong to both
`L¹` and `L²` of the concrete product Gaussian measure.  Their inner products
factor coordinatewise by finite-dimensional Fubini.
-/

open MeasureTheory
open scoped BigOperators ComplexConjugate ENNReal

namespace GinibrePoincare
namespace ComplexHermite

noncomputable section

/-- The product of any two normalized one-coordinate Hermite functions is
integrable. -/
theorem integrable_normalizedEval_mul (n : ℕ) (hn : 0 < n)
    (p q r s : ℕ) :
    Integrable (fun z : ℂ =>
      normalizedEval n hn p q z * normalizedEval n hn r s z)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  rw [show (fun z : ℂ =>
      normalizedEval n hn p q z * normalizedEval n hn r s z) =
      fun z =>
        (((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ) *
          ∑ k ∈ Finset.range (min p q + 1),
            (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
                (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
              z ^ (p - k) * (conj z) ^ (q - k)) *
        (((oneDimNormalization n r * oneDimNormalization n s : ℝ) : ℂ) *
          ∑ l ∈ Finset.range (min r s + 1),
            (((-((n : ℝ)⁻¹ : ℂ)) ^ l) * (l.factorial : ℂ) *
                (Nat.choose r l : ℂ) * (Nat.choose s l : ℂ)) *
              z ^ (r - l) * (conj z) ^ (s - l)) by
    funext z
    rw [normalizedEval_eq_sum, normalizedEval_eq_sum]]
  rw [show (fun z : ℂ =>
      (((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ) *
        ∑ k ∈ Finset.range (min p q + 1),
          (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
              (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
            z ^ (p - k) * (conj z) ^ (q - k)) *
      (((oneDimNormalization n r * oneDimNormalization n s : ℝ) : ℂ) *
        ∑ l ∈ Finset.range (min r s + 1),
          (((-((n : ℝ)⁻¹ : ℂ)) ^ l) * (l.factorial : ℂ) *
              (Nat.choose r l : ℂ) * (Nat.choose s l : ℂ)) *
            z ^ (r - l) * (conj z) ^ (s - l))) =
      fun z => ∑ k ∈ Finset.range (min p q + 1),
        ∑ l ∈ Finset.range (min r s + 1),
          (((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ) *
            ((oneDimNormalization n r * oneDimNormalization n s : ℝ) : ℂ) *
            (((-((n : ℝ)⁻¹ : ℂ)) ^ k) * (k.factorial : ℂ) *
              (Nat.choose p k : ℂ) * (Nat.choose q k : ℂ)) *
            (((-((n : ℝ)⁻¹ : ℂ)) ^ l) * (l.factorial : ℂ) *
              (Nat.choose r l : ℂ) * (Nat.choose s l : ℂ))) *
            (z ^ ((p - k) + (r - l)) *
              (conj z) ^ ((q - k) + (s - l))) by
    funext z
    simp_rw [Finset.mul_sum, Finset.sum_mul, pow_add]
    rw [Finset.sum_comm]
    apply Finset.sum_congr rfl
    intro k hk
    apply Finset.sum_congr rfl
    intro l hl
    ring]
  apply integrable_finsetSum
  intro k hk
  apply integrable_finsetSum
  intro l hl
  have hmono := integrable_complex_monomial_complexCoordinateGaussianProbability
    n ((p - k) + (r - l)) ((q - k) + (s - l))
  exact hmono.const_mul _

/-- A normalized one-coordinate Hermite function times the conjugate of
another is integrable. -/
theorem integrable_conj_normalizedEval_mul (n : ℕ) (hn : 0 < n)
    (p q r s : ℕ) :
    Integrable (fun z : ℂ =>
      conj (normalizedEval n hn p q z) * normalizedEval n hn r s z)
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  apply Integrable.congr'_enorm
    (integrable_normalizedEval_mul n hn p q r s)
  · exact ((Complex.continuous_conj.comp
      (continuous_normalizedEval n hn p q)).mul
        (continuous_normalizedEval n hn r s)).aestronglyMeasurable
  · filter_upwards with z
    simp [enorm_eq_nnnorm]

/-- The squared norm of every normalized one-coordinate Hermite function is
integrable. -/
theorem integrable_normSq_normalizedEval (n : ℕ) (hn : 0 < n)
    (p q : ℕ) :
    Integrable (fun z : ℂ => Complex.normSq (normalizedEval n hn p q z))
      (complexCoordinateGaussianProbability n : Measure ℂ) := by
  apply Integrable.congr'_enorm
    (integrable_conj_normalizedEval_mul n hn p q p q)
  · exact (Complex.continuous_normSq.comp
      (continuous_normalizedEval n hn p q)).aestronglyMeasurable
  · filter_upwards with z
    rw [← Complex.sq_norm]
    simp [enorm_eq_nnnorm, pow_two]

/-- Every multivariate normalized Hermite tensor is in `L¹` of the concrete
Gaussian product measure. -/
theorem integrable_multivariateNormalized (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) :
    Integrable (multivariateNormalized n hn p q) (complexGaussianMeasure n) := by
  unfold multivariateNormalized complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  exact Integrable.fintype_prod fun i => integrable_normalizedEval n hn (p i) (q i)

/-- Pointwise squared norms of multivariate normalized Hermite tensors are
integrable. -/
theorem integrable_normSq_multivariateNormalized (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) :
    Integrable (fun z => Complex.normSq (multivariateNormalized n hn p q z))
      (complexGaussianMeasure n) := by
  rw [show (fun z => Complex.normSq (multivariateNormalized n hn p q z)) =
      fun z => ∏ i, Complex.normSq (normalizedEval n hn (p i) (q i) (z i)) by
    funext z
    simp [multivariateNormalized, Complex.normSq_apply, map_prod]]
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  exact Integrable.fintype_prod fun i =>
    integrable_normSq_normalizedEval n hn (p i) (q i)

/-- Every multivariate normalized Hermite tensor belongs to Gaussian `L²`. -/
theorem memLp_two_multivariateNormalized (n : ℕ) (hn : 0 < n)
    (p q : Fin n → ℕ) :
    MemLp (multivariateNormalized n hn p q) 2 (complexGaussianMeasure n) := by
  rw [memLp_two_iff_integrable_sq_norm
    (continuous_multivariateNormalized n hn p q).aestronglyMeasurable]
  apply Integrable.congr (integrable_normSq_multivariateNormalized n hn p q)
  filter_upwards with z
  rw [Complex.sq_norm]

/-- The Gaussian inner product of two Hermite tensors factors as the product
of their one-coordinate inner products. -/
theorem integral_conj_multivariateNormalized_mul_eq_prod (n : ℕ) (hn : 0 < n)
    (p q r s : Fin n → ℕ) :
    ∫ z, conj (multivariateNormalized n hn p q z) *
        multivariateNormalized n hn r s z ∂complexGaussianMeasure n =
      ∏ i, ∫ z : ℂ, conj (normalizedEval n hn (p i) (q i) z) *
          normalizedEval n hn (r i) (s i) z
        ∂(complexCoordinateGaussianProbability n : Measure ℂ) := by
  unfold multivariateNormalized complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi, map_prod]
  rw [show (fun z : Fin n → ℂ =>
      (∏ x, conj (normalizedEval n hn (p x) (q x) (z x))) *
        ∏ x, normalizedEval n hn (r x) (s x) (z x)) =
      fun z => ∏ i, conj (normalizedEval n hn (p i) (q i) (z i)) *
        normalizedEval n hn (r i) (s i) (z i) by
    funext z
    rw [← Finset.prod_mul_distrib]]
  simpa using (integral_fintype_prod_eq_prod
    (𝕜 := ℂ)
    (E := fun _ : Fin n => ℂ)
    (μ := fun _ : Fin n =>
      (complexCoordinateGaussianProbability n : Measure ℂ))
    (fun i (z : ℂ) => conj (normalizedEval n hn (p i) (q i) z) *
      normalizedEval n hn (r i) (s i) z))

end
end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/MultivariateHermiteMonomialSpan.lean #
import GinibrePoincare.Analysis.HermiteMonomialSpan
import Mathlib.Algebra.Algebra.Operations

/-! # Pointwise multivariate triangular inversion

This file tensors the one-variable rectangular span equality over the finitely
many coordinates.  Everything here concerns actual functions; no `L²`
quotient or integrability assertion is involved.
-/

open scoped BigOperators ComplexConjugate Pointwise

namespace GinibrePoincare
namespace ComplexHermite

noncomputable section

/-- Coordinatewise pullback of a one-variable function. -/
def coordinatePullback {n : ℕ} (i : Fin n) :
    (ℂ → ℂ) →ₗ[ℂ] ((Fin n → ℂ) → ℂ) where
  toFun f z := f (z i)
  map_add' _ _ := rfl
  map_smul' _ _ := rfl

@[simp] theorem coordinatePullback_apply {n : ℕ} (i : Fin n)
    (f : ℂ → ℂ) (z : Fin n → ℂ) :
    coordinatePullback i f z = f (z i) := rfl

/-- The finite rectangular span of multivariate normalized Hermite
functions. -/
def multivariateNormalizedRectangleSpan (n : ℕ) (hn : 0 < n)
    (P Q : Fin n → ℕ) : Submodule ℂ ((Fin n → ℂ) → ℂ) :=
  Submodule.span ℂ {f | ∃ p q : Fin n → ℕ,
    (∀ i, p i ≤ P i) ∧ (∀ i, q i ≤ Q i) ∧
      f = multivariateNormalized n hn p q}

/-- The finite rectangular span of coordinate/conjugate-coordinate
monomials. -/
def multivariateMixedMonomialRectangleSpan (n : ℕ)
    (P Q : Fin n → ℕ) : Submodule ℂ ((Fin n → ℂ) → ℂ) :=
  Submodule.span ℂ {f | ∃ p q : Fin n → ℕ,
    (∀ i, p i ≤ P i) ∧ (∀ i, q i ≤ Q i) ∧
      f = fun z ↦ ∏ i, z i ^ p i * (conj (z i)) ^ q i}

private def coordinateHermiteSet (n : ℕ) (hn : 0 < n)
    (P Q : Fin n → ℕ) (i : Fin n) : Set ((Fin n → ℂ) → ℂ) :=
  {f | ∃ a ≤ P i, ∃ b ≤ Q i,
    f = coordinatePullback i (normalizedEval n hn a b)}

private def coordinateMonomialSet (P Q : Fin n → ℕ) (i : Fin n) :
    Set ((Fin n → ℂ) → ℂ) :=
  {f | ∃ a ≤ P i, ∃ b ≤ Q i,
    f = coordinatePullback i (fun z : ℂ ↦ z ^ a * (conj z) ^ b)}

private theorem coordinateHermite_span_eq_coordinateMonomial_span
    (n : ℕ) (hn : 0 < n) (P Q : Fin n → ℕ) (i : Fin n) :
    Submodule.span ℂ (coordinateHermiteSet n hn P Q i) =
      Submodule.span ℂ (coordinateMonomialSet P Q i) := by
  rw [show coordinateHermiteSet n hn P Q i =
      coordinatePullback i ''
        {f | ∃ a ≤ P i, ∃ b ≤ Q i, f = normalizedEval n hn a b} by
    ext f
    constructor
    · rintro ⟨a, ha, b, hb, rfl⟩
      exact ⟨normalizedEval n hn a b, ⟨a, ha, b, hb, rfl⟩, rfl⟩
    · rintro ⟨_, ⟨a, ha, b, hb, rfl⟩, rfl⟩
      exact ⟨a, ha, b, hb, rfl⟩]
  rw [show coordinateMonomialSet P Q i =
      coordinatePullback i ''
        {f | ∃ a ≤ P i, ∃ b ≤ Q i,
          f = fun z : ℂ ↦ z ^ a * (conj z) ^ b} by
    ext f
    constructor
    · rintro ⟨a, ha, b, hb, rfl⟩
      exact ⟨_, ⟨a, ha, b, hb, rfl⟩, rfl⟩
    · rintro ⟨_, ⟨a, ha, b, hb, rfl⟩, rfl⟩
      exact ⟨a, ha, b, hb, rfl⟩]
  rw [← Submodule.map_span, ← Submodule.map_span]
  change (normalizedEvalRectangleSpan n hn (P i) (Q i)).map
      (coordinatePullback i) =
    (mixedMonomialRectangleSpan (P i) (Q i)).map (coordinatePullback i)
  rw [normalizedEvalRectangleSpan_eq_mixedMonomialRectangleSpan n hn]

private theorem hermite_generator_set_eq_prod (n : ℕ) (hn : 0 < n)
    (P Q : Fin n → ℕ) :
    {f | ∃ p q : Fin n → ℕ,
      (∀ i, p i ≤ P i) ∧ (∀ i, q i ≤ Q i) ∧
        f = multivariateNormalized n hn p q} =
      ∏ i, coordinateHermiteSet n hn P Q i := by
  ext f
  rw [Set.mem_fintype_prod]
  constructor
  · rintro ⟨p, q, hp, hq, rfl⟩
    refine ⟨fun i ↦ coordinatePullback i (normalizedEval n hn (p i) (q i)), ?_, ?_⟩
    · intro i
      exact ⟨p i, hp i, q i, hq i, rfl⟩
    · funext z
      simp [multivariateNormalized]
  · rintro ⟨g, hg, rfl⟩
    choose p hp q hq heq using hg
    refine ⟨p, q, hp, hq, ?_⟩
    funext z
    simp only [multivariateNormalized]
    simp only [Finset.prod_apply]
    apply Finset.prod_congr rfl
    intro i hi
    rw [heq i]
    rfl

private theorem monomial_generator_set_eq_prod (n : ℕ)
    (P Q : Fin n → ℕ) :
    {f | ∃ p q : Fin n → ℕ,
      (∀ i, p i ≤ P i) ∧ (∀ i, q i ≤ Q i) ∧
        f = fun z ↦ ∏ i, z i ^ p i * (conj (z i)) ^ q i} =
      ∏ i, coordinateMonomialSet P Q i := by
  ext f
  rw [Set.mem_fintype_prod]
  constructor
  · rintro ⟨p, q, hp, hq, rfl⟩
    refine ⟨fun i ↦ coordinatePullback i
      (fun z : ℂ ↦ z ^ p i * (conj z) ^ q i), ?_, ?_⟩
    · intro i
      exact ⟨p i, hp i, q i, hq i, rfl⟩
    · funext z
      simp only [Finset.prod_apply, coordinatePullback_apply]
  · rintro ⟨g, hg, rfl⟩
    choose p hp q hq heq using hg
    refine ⟨p, q, hp, hq, ?_⟩
    funext z
    simp only [Finset.prod_apply]
    apply Finset.prod_congr rfl
    intro i hi
    rw [heq i]
    rfl

/-- Pointwise multivariate triangular inversion: on every finite index
rectangle, normalized tensor Hermites and coordinate/conjugate-coordinate
monomials have exactly the same complex linear span. -/
theorem multivariateNormalizedRectangleSpan_eq_mixedMonomialRectangleSpan
    (n : ℕ) (hn : 0 < n) (P Q : Fin n → ℕ) :
    multivariateNormalizedRectangleSpan n hn P Q =
      multivariateMixedMonomialRectangleSpan n P Q := by
  rw [multivariateNormalizedRectangleSpan,
    multivariateMixedMonomialRectangleSpan,
    hermite_generator_set_eq_prod n hn P Q,
    monomial_generator_set_eq_prod n P Q]
  rw [← Submodule.prod_span, ← Submodule.prod_span]
  apply Finset.prod_congr rfl
  intro i hi
  exact coordinateHermite_span_eq_coordinateMonomial_span n hn P Q i

end
end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/NormalizedComplexHermite.lean #
import GinibrePoincare.Analysis.ComplexHermiteLowering
import Mathlib.Analysis.SpecialFunctions.Sqrt
import Mathlib.Tactic.FieldSimp

/-!
# Normalized univariate complex Hermite polynomials

For the centered complex Gaussian of precision `n`, the raw polynomial has
variance `1 / n`.  Multiplication by

`sqrt(n)^p / sqrt(p!) * (sqrt(n)^q / sqrt(q!))`

gives the paper's orthonormal normalization.  This file proves its two formal
lowering identities, including the exact coefficients `sqrt(n * p)` and
`sqrt(n * q)`.
-/

namespace GinibrePoincare

namespace ComplexHermite

/-- The one-index normalization factor for complex Hermite polynomials of
Gaussian precision `n`. -/
noncomputable def oneDimNormalization (n p : ℕ) : ℝ :=
  Real.sqrt n ^ p / Real.sqrt p.factorial

/-- The paper-normalized complex Hermite polynomial for Gaussian precision
`n`.  The positivity assumption on `n` is recorded in the definition's
interface because the variance is `1 / n`. -/
noncomputable def normalized (n : ℕ) (_hn : 0 < n) (p q : ℕ) : Poly :=
  MvPolynomial.C
      ((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ) *
    raw ((n : ℝ)⁻¹) p q

private theorem oneDimNormalization_succ (n p : ℕ) (hn : 0 < n) :
    (p + 1 : ℝ) * oneDimNormalization n (p + 1) =
      Real.sqrt (n * (p + 1) : ℕ) * oneDimNormalization n p := by
  have hn0 : (0 : ℝ) < n := by exact_mod_cast hn
  have hp0 : (0 : ℝ) < p.factorial := by positivity
  have hsp : Real.sqrt (p.factorial : ℝ) ≠ 0 := ne_of_gt (Real.sqrt_pos.2 hp0)
  have hsps : Real.sqrt ((p + 1).factorial : ℝ) ≠ 0 := by positivity
  have hsn : Real.sqrt (n : ℝ) ^ 2 = n := by
    rw [sq, Real.mul_self_sqrt (le_of_lt hn0)]
  have hsp_sq : Real.sqrt (p.factorial : ℝ) ^ 2 = p.factorial := by
    rw [sq, Real.mul_self_sqrt (by positivity)]
  have hsps_sq : Real.sqrt ((p + 1).factorial : ℝ) ^ 2 = (p + 1).factorial := by
    rw [sq, Real.mul_self_sqrt (by positivity)]
  have hsnp_sq : Real.sqrt (n * (p + 1) : ℕ) ^ 2 = n * (p + 1) := by
    rw [sq, Real.mul_self_sqrt (by positivity)]
    norm_cast
  have hroot :
      (p + 1 : ℝ) * Real.sqrt n * Real.sqrt p.factorial =
        Real.sqrt (n * (p + 1) : ℕ) * Real.sqrt (p + 1).factorial := by
    have hleft : 0 ≤ (p + 1 : ℝ) * Real.sqrt n * Real.sqrt p.factorial := by positivity
    have hright : 0 ≤ Real.sqrt (n * (p + 1) : ℕ) *
        Real.sqrt (p + 1).factorial := by positivity
    apply (sq_eq_sq₀ hleft hright).mp
    calc
      _ = (p + 1 : ℝ) ^ 2 * Real.sqrt n ^ 2 *
          Real.sqrt p.factorial ^ 2 := by ring
      _ = (p + 1 : ℝ) ^ 2 * n * p.factorial := by rw [hsn, hsp_sq]
      _ = Real.sqrt (n * (p + 1) : ℕ) ^ 2 *
          Real.sqrt (p + 1).factorial ^ 2 := by
        rw [hsnp_sq, hsps_sq, Nat.factorial_succ]
        push_cast
        ring
      _ = _ := by ring
  unfold oneDimNormalization
  rw [pow_succ]
  field_simp
  nlinarith

/-- Formal holomorphic lowering for the normalized complex Hermite
polynomial. -/
theorem pderiv_Z_normalized (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    MvPolynomial.pderiv (0 : ComplexHermiteIndex) (normalized n hn p q) =
      MvPolynomial.C (Real.sqrt (n * p : ℕ) : ℂ) *
        normalized n hn (p - 1) q := by
  cases p with
  | zero =>
      rw [normalized, MvPolynomial.pderiv_C_mul, pderiv_Z_raw_zero_left]
      simp
  | succ p =>
      rw [normalized, MvPolynomial.pderiv_C_mul, pderiv_Z_raw, normalized]
      rw [Nat.succ_sub_one]
      have hnorm := oneDimNormalization_succ n p hn
      have hreal :
          (oneDimNormalization n (p + 1) * oneDimNormalization n q) * (p + 1 : ℝ) =
            Real.sqrt (n * (p + 1) : ℕ) *
              (oneDimNormalization n p * oneDimNormalization n q) := by
        calc
          _ = ((p + 1 : ℝ) * oneDimNormalization n (p + 1)) *
              oneDimNormalization n q := by ring
          _ = (Real.sqrt (n * (p + 1) : ℕ) * oneDimNormalization n p) *
              oneDimNormalization n q := by rw [hnorm]
          _ = _ := by ring
      have hc :
          ((MvPolynomial.C
              ((oneDimNormalization n (p + 1) * oneDimNormalization n q : ℝ) : ℂ) *
              MvPolynomial.C ((p + 1 : ℕ) : ℂ)) : Poly) =
            ((MvPolynomial.C (Real.sqrt (n * (p + 1) : ℕ) : ℂ) *
              MvPolynomial.C
                ((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ)) : Poly) := by
        rw [← MvPolynomial.C_mul, ← MvPolynomial.C_mul]
        congr 1
        exact_mod_cast hreal
      rw [show ((p + 1 : ℕ) : Poly) = MvPolynomial.C ((p + 1 : ℕ) : ℂ) by rfl]
      calc
        _ = (MvPolynomial.C
              ((oneDimNormalization n (p + 1) * oneDimNormalization n q : ℝ) : ℂ) *
              MvPolynomial.C ((p + 1 : ℕ) : ℂ)) * raw ((n : ℝ)⁻¹) p q := by ring
        _ = (MvPolynomial.C (Real.sqrt (n * (p + 1) : ℕ) : ℂ) *
              MvPolynomial.C
                ((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ)) *
              raw ((n : ℝ)⁻¹) p q := by rw [hc]
        _ = _ := by ring

/-- Formal antiholomorphic lowering for the normalized complex Hermite
polynomial. -/
theorem pderiv_W_normalized (n : ℕ) (hn : 0 < n) (p q : ℕ) :
    MvPolynomial.pderiv (1 : ComplexHermiteIndex) (normalized n hn p q) =
      MvPolynomial.C (Real.sqrt (n * q : ℕ) : ℂ) *
        normalized n hn p (q - 1) := by
  cases q with
  | zero =>
      rw [normalized, MvPolynomial.pderiv_C_mul, pderiv_W_raw_zero_right]
      simp
  | succ q =>
      rw [normalized, MvPolynomial.pderiv_C_mul, pderiv_W_raw, normalized]
      rw [Nat.succ_sub_one]
      have hnorm := oneDimNormalization_succ n q hn
      have hreal :
          (oneDimNormalization n p * oneDimNormalization n (q + 1)) * (q + 1 : ℝ) =
            Real.sqrt (n * (q + 1) : ℕ) *
              (oneDimNormalization n p * oneDimNormalization n q) := by
        calc
          _ = oneDimNormalization n p *
              ((q + 1 : ℝ) * oneDimNormalization n (q + 1)) := by ring
          _ = oneDimNormalization n p *
              (Real.sqrt (n * (q + 1) : ℕ) * oneDimNormalization n q) := by rw [hnorm]
          _ = _ := by ring
      have hc :
          ((MvPolynomial.C
              ((oneDimNormalization n p * oneDimNormalization n (q + 1) : ℝ) : ℂ) *
              MvPolynomial.C ((q + 1 : ℕ) : ℂ)) : Poly) =
            ((MvPolynomial.C (Real.sqrt (n * (q + 1) : ℕ) : ℂ) *
              MvPolynomial.C
                ((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ)) : Poly) := by
        rw [← MvPolynomial.C_mul, ← MvPolynomial.C_mul]
        congr 1
        exact_mod_cast hreal
      rw [show ((q + 1 : ℕ) : Poly) = MvPolynomial.C ((q + 1 : ℕ) : ℂ) by rfl]
      calc
        _ = (MvPolynomial.C
              ((oneDimNormalization n p * oneDimNormalization n (q + 1) : ℝ) : ℂ) *
              MvPolynomial.C ((q + 1 : ℕ) : ℂ)) * raw ((n : ℝ)⁻¹) p q := by ring
        _ = (MvPolynomial.C (Real.sqrt (n * (q + 1) : ℕ) : ℂ) *
              MvPolynomial.C
                ((oneDimNormalization n p * oneDimNormalization n q : ℝ) : ℂ)) *
              raw ((n : ℝ)⁻¹) p q := by rw [hc]
        _ = _ := by ring

end ComplexHermite
end GinibrePoincare
Analysis GinibrePoincare/Analysis/PermutationLp.lean #
import GinibrePoincare.Analysis.VandermondeL2
import Mathlib.MeasureTheory.Function.LpSpace.ContinuousCompMeasurePreserving

/-! # Permutation actions and symmetric/alternating `L²` subspaces -/

open MeasureTheory
open scoped ENNReal

namespace GinibrePoincare

noncomputable section

/-- Coordinate permutation as a measurable equivalence of configuration
space. -/
def permutationMeasurableEquiv {n : ℕ} (σ : ParticlePermutation n) :
    Configuration n ≃ᵐ Configuration n :=
  MeasurableEquiv.piCongrLeft (fun _ : Fin n ↦ ℂ) σ.symm

@[simp]
theorem permutationMeasurableEquiv_apply {n : ℕ}
    (σ : ParticlePermutation n) (z : Configuration n) :
    permutationMeasurableEquiv σ z = permute σ z := by
  simp [permutationMeasurableEquiv, MeasurableEquiv.piCongrLeft,
    Equiv.piCongrLeft, Equiv.piCongrLeft']
  rfl

/-- The product complex Gaussian law is invariant under coordinate
permutations. -/
theorem gaussian_measurePreserving_permute {n : ℕ}
    (σ : ParticlePermutation n) :
    MeasurePreserving (permute σ) (complexGaussianMeasure n)
      (complexGaussianMeasure n) := by
  unfold complexGaussianMeasure complexGaussianProbability
  simp only [ProbabilityMeasure.toMeasure_pi]
  have heq : ⇑(permutationMeasurableEquiv σ) = permute σ := by
    funext z
    exact permutationMeasurableEquiv_apply σ z
  rw [← heq]
  exact measurePreserving_piCongrLeft
    (fun _ : Fin n ↦ (complexCoordinateGaussianProbability n : Measure ℂ)) σ.symm

theorem vandermondeDensity_permute {n : ℕ} (σ : ParticlePermutation n)
    (z : Configuration n) :
    vandermondeDensity (permute σ z) = vandermondeDensity z := by
  unfold vandermondeDensity vandermondeWeight
  rw [vandermonde_permute]
  congr 1
  rw [map_mul]
  have hs : Complex.normSq (permutationSign σ) = 1 := by
    unfold permutationSign
    rcases Int.units_eq_one_or (Equiv.Perm.sign σ) with h | h
    · simp [h, Complex.normSq_apply]
    · simp [h, Complex.normSq_apply]
  rw [hs, one_mul]

/-- The normalized Ginibre law is invariant under coordinate permutations. -/
theorem ginibre_measurePreserving_permute {n : ℕ}
    (σ : ParticlePermutation n) :
    MeasurePreserving (permute σ) (ginibreMeasure n)
      (ginibreMeasure n) := by
  refine ⟨(gaussian_measurePreserving_permute σ).measurable, ?_⟩
  unfold ginibreMeasure rawGinibreMeasure
  rw [Measure.map_smul]
  congr 1
  have hd : vandermondeDensity ∘ permute σ =
      (vandermondeDensity : Configuration n → ℝ≥0∞) := by
    funext z
    exact vandermondeDensity_permute σ z
  nth_rw 1 [← hd]
  have heq : ⇑(permutationMeasurableEquiv σ) = permute σ := by
    funext z
    exact permutationMeasurableEquiv_apply σ z
  rw [← heq] at hd ⊢
  exact MeasurePreserving.map_withDensity_comp
    (permutationMeasurableEquiv σ)
    (heq ▸ gaussian_measurePreserving_permute σ)
    measurable_vandermondeDensity

/-- Pullback by a particle permutation on Gaussian `L²`. -/
def gaussianPermutationL2 {n : ℕ} (σ : ParticlePermutation n) :
    Lp ℂ 2 (complexGaussianMeasure n) →ₗᵢ[ℂ]
      Lp ℂ 2 (complexGaussianMeasure n) :=
  Lp.compMeasurePreservingₗᵢ ℂ (permute σ)
    (gaussian_measurePreserving_permute σ)

/-- Pullback by a particle permutation on Ginibre `L²`. -/
def ginibrePermutationL2 {n : ℕ} (σ : ParticlePermutation n) :
    Lp ℂ 2 (ginibreMeasure n) →ₗᵢ[ℂ] Lp ℂ 2 (ginibreMeasure n) :=
  Lp.compMeasurePreservingₗᵢ ℂ (permute σ)
    (ginibre_measurePreserving_permute σ)

/-- The AE-symmetric subspace of Gaussian `L²`. -/
def gaussianSymmetricL2 (n : ℕ) :
    Submodule ℂ (Lp ℂ 2 (complexGaussianMeasure n)) :=
  { carrier := {u | ∀ σ : ParticlePermutation n,
      gaussianPermutationL2 σ u = u}
    zero_mem' := by simp
    add_mem' := by
      intro u v hu hv σ
      simp [map_add, hu σ, hv σ]
    smul_mem' := by
      intro c u hu σ
      simp [map_smul, hu σ] }

/-- The AE-alternating subspace of Gaussian `L²`. -/
def gaussianAlternatingL2 (n : ℕ) :
    Submodule ℂ (Lp ℂ 2 (complexGaussianMeasure n)) :=
  { carrier := {u | ∀ σ : ParticlePermutation n,
      gaussianPermutationL2 σ u = permutationSign σ • u}
    zero_mem' := by simp
    add_mem' := by
      intro u v hu hv σ
      simp [map_add, hu σ, hv σ, smul_add]
    smul_mem' := by
      intro c u hu σ
      rw [map_smul, hu σ]
      simp [smul_smul, mul_comm] }

/-- The AE-symmetric subspace of Ginibre `L²`. -/
def ginibreSymmetricL2 (n : ℕ) :
    Submodule ℂ (Lp ℂ 2 (ginibreMeasure n)) :=
  { carrier := {u | ∀ σ : ParticlePermutation n,
      ginibrePermutationL2 σ u = u}
    zero_mem' := by simp
    add_mem' := by
      intro u v hu hv σ
      simp [map_add, hu σ, hv σ]
    smul_mem' := by
      intro c u hu σ
      simp [map_smul, hu σ] }

/-- The AE-alternating subspace of Ginibre `L²`. -/
def ginibreAlternatingL2 (n : ℕ) :
    Submodule ℂ (Lp ℂ 2 (ginibreMeasure n)) :=
  { carrier := {u | ∀ σ : ParticlePermutation n,
      ginibrePermutationL2 σ u = permutationSign σ • u}
    zero_mem' := by simp
    add_mem' := by
      intro u v hu hv σ
      simp [map_add, hu σ, hv σ, smul_add]
    smul_mem' := by
      intro c u hu σ
      rw [map_smul, hu σ]
      simp [smul_smul, mul_comm] }

theorem isClosed_gaussianSymmetricL2 (n : ℕ) :
    IsClosed (gaussianSymmetricL2 n :
      Set (Lp ℂ 2 (complexGaussianMeasure n))) := by
  change IsClosed {u | ∀ σ : ParticlePermutation n,
    gaussianPermutationL2 σ u = u}
  rw [show {u | ∀ σ : ParticlePermutation n,
      gaussianPermutationL2 σ u = u} =
      ⋂ σ, {u | gaussianPermutationL2 σ u = u} by ext; simp]
  exact isClosed_iInter fun σ ↦ isClosed_eq
    (gaussianPermutationL2 σ).continuous continuous_id

theorem isClosed_gaussianAlternatingL2 (n : ℕ) :
    IsClosed (gaussianAlternatingL2 n :
      Set (Lp ℂ 2 (complexGaussianMeasure n))) := by
  change IsClosed {u | ∀ σ : ParticlePermutation n,
    gaussianPermutationL2 σ u = permutationSign σ • u}
  rw [show {u | ∀ σ : ParticlePermutation n,
      gaussianPermutationL2 σ u = permutationSign σ • u} =
      ⋂ σ, {u | gaussianPermutationL2 σ u = permutationSign σ • u} by
        ext; simp]
  exact isClosed_iInter fun σ ↦ isClosed_eq
    (gaussianPermutationL2 σ).continuous (continuous_const_smul _)

theorem isClosed_ginibreSymmetricL2 (n : ℕ) :
    IsClosed (ginibreSymmetricL2 n : Set (Lp ℂ 2 (ginibreMeasure n))) := by
  change IsClosed {u | ∀ σ : ParticlePermutation n,
    ginibrePermutationL2 σ u = u}
  rw [show {u | ∀ σ : ParticlePermutation n,
      ginibrePermutationL2 σ u = u} =
      ⋂ σ, {u | ginibrePermutationL2 σ u = u} by ext; simp]
  exact isClosed_iInter fun σ ↦ isClosed_eq
    (ginibrePermutationL2 σ).continuous continuous_id

theorem isClosed_ginibreAlternatingL2 (n : ℕ) :
    IsClosed (ginibreAlternatingL2 n : Set (Lp ℂ 2 (ginibreMeasure n))) := by
  change IsClosed {u | ∀ σ : ParticlePermutation n,
    ginibrePermutationL2 σ u = permutationSign σ • u}
  rw [show {u | ∀ σ : ParticlePermutation n,
      ginibrePermutationL2 σ u = permutationSign σ • u} =
      ⋂ σ, {u | ginibrePermutationL2 σ u = permutationSign σ • u} by
        ext; simp]
  exact isClosed_iInter fun σ ↦ isClosed_eq
    (ginibrePermutationL2 σ).continuous (continuous_const_smul _)

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/PolarGaussianMoments.lean #
import GinibrePoincare.Analysis.AngularMoments
import GinibrePoincare.Analysis.RadialMoments
import GinibrePoincare.Analysis.ComplexGaussianDensity
import Mathlib.MeasureTheory.Integral.Prod

/-! # Polar factorization of complex Gaussian moments -/

open MeasureTheory Set
open scoped ComplexConjugate Real

namespace GinibrePoincare

noncomputable section

/-- The complex monomial separates into a radial power and an angular Fourier
mode in polar coordinates. -/
theorem mixedMonomial_polar (a b : ℕ) (r θ : ℝ) :
    (Complex.polarCoord.symm (r, θ)) ^ a *
        conj (Complex.polarCoord.symm (r, θ)) ^ b =
      (r ^ (a + b) : ℂ) * angularMode a b θ := by
  rw [Complex.polarCoord_symm_apply]
  rw [show (Real.cos θ + Real.sin θ * Complex.I) =
      Complex.exp (θ * Complex.I) by
    rw [Complex.exp_mul_I]
    push_cast
    ring]
  simp only [mul_pow, map_mul, Complex.conj_ofReal]
  rw [show conj (Complex.exp (θ * Complex.I)) =
      Complex.exp (-(θ * Complex.I)) by
    rw [← Complex.exp_conj]
    congr 1
    simp]
  unfold angularMode
  rw [← Complex.exp_nat_mul, ← Complex.exp_nat_mul]
  calc
    _ = (r ^ (a + b) : ℂ) *
        (Complex.exp ((a : ℂ) * (θ * Complex.I)) *
          Complex.exp ((b : ℂ) * -(θ * Complex.I))) := by
      rw [pow_add]
      ring
    _ = (r ^ (a + b) : ℂ) *
        Complex.exp ((a : ℂ) * (θ * Complex.I) +
          (b : ℂ) * -(θ * Complex.I)) := by rw [Complex.exp_add]
    _ = _ := by
      congr 2
      push_cast
      ring

/-- The Jacobian, Gaussian density, and mixed monomial separate into a radial
factor and the angular Fourier mode.  This formulation makes all real-to-
complex coercions explicit, avoiding expensive elaboration inside an
integral. -/
theorem gaussianMixedIntegrand_polar (n a b : ℕ) (r θ : ℝ) :
    r • (((n : ℝ) / Real.pi) * Real.exp (-(n : ℝ) * r ^ 2)) •
        ((Complex.polarCoord.symm (r, θ)) ^ a *
          conj (Complex.polarCoord.symm (r, θ)) ^ b) =
      ((r : ℂ) *
        ((((n : ℝ) : ℂ) / Real.pi) *
          (Real.exp (-(n : ℝ) * r ^ 2) : ℂ)) *
        (r : ℂ) ^ (a + b)) * angularMode a b θ := by
  rw [mixedMonomial_polar]
  simp only [Algebra.smul_def, RCLike.algebraMap_eq_ofReal]
  have hd : ((((n : ℝ) / Real.pi) * Real.exp (-(n : ℝ) * r ^ 2) : ℝ) : ℂ) =
      (((n : ℝ) : ℂ) / Real.pi) *
        (Real.exp (-(n : ℝ) * r ^ 2) : ℂ) := by
    rw [Complex.ofReal_mul, Complex.ofReal_div]
  change (r : ℂ) *
      (((((n : ℝ) / Real.pi) * Real.exp (-(n : ℝ) * r ^ 2) : ℝ) : ℂ) *
        ((r : ℂ) ^ (a + b) * angularMode a b θ)) = _
  rw [hd]
  simp only [mul_assoc]

/-- Fubini factorization for the separated polar Gaussian mixed-moment
integrand. -/
theorem integral_gaussianMixedIntegrand_polar (n a b : ℕ) :
    ∫ p : ℝ × ℝ in Set.Ioi 0 ×ˢ Set.Ioo (-Real.pi) Real.pi,
        ((((n : ℝ) : ℂ) / Real.pi) * (p.1 : ℂ) ^ (a + b + 1) *
          (Real.exp (-(n : ℝ) * p.1 ^ 2) : ℂ)) * angularMode a b p.2 =
      (∫ r : ℝ in Set.Ioi 0,
          (((n : ℝ) : ℂ) / Real.pi) * (r : ℂ) ^ (a + b + 1) *
            (Real.exp (-(n : ℝ) * r ^ 2) : ℂ)) *
        ∫ θ : ℝ in Set.Ioo (-Real.pi) Real.pi, angularMode a b θ := by
  rw [Measure.volume_eq_prod]
  simpa only [mul_assoc] using
    (setIntegral_prod_mul
      (fun r : ℝ ↦ (((n : ℝ) : ℂ) / Real.pi) * (r : ℂ) ^ (a + b + 1) *
        (Real.exp (-(n : ℝ) * r ^ 2) : ℂ))
      (angularMode a b) (Set.Ioi 0) (Set.Ioo (-Real.pi) Real.pi))

/-- The angular evaluation in the open interval used by `polarCoord.target`. -/
theorem integral_angularMode_Ioo (a b : ℕ) :
    ∫ θ : ℝ in Set.Ioo (-Real.pi) Real.pi, angularMode a b θ =
      if a = b then (2 * Real.pi : ℂ) else 0 := by
  rw [← integral_Ioc_eq_integral_Ioo]
  exact integral_angularMode_Ioc a b

/-- Exact evaluation of the separated Gaussian mixed integrand on the polar
coordinate target. -/
theorem integral_gaussianMixedIntegrand_polar_eq (n a b : ℕ) (hn : 0 < n) :
    ∫ p : ℝ × ℝ in Set.Ioi 0 ×ˢ Set.Ioo (-Real.pi) Real.pi,
        ((((n : ℝ) : ℂ) / Real.pi) * (p.1 : ℂ) ^ (a + b + 1) *
          (Real.exp (-(n : ℝ) * p.1 ^ 2) : ℂ)) * angularMode a b p.2 =
      if a = b then (a.factorial : ℂ) / (n : ℂ) ^ a else 0 := by
  rw [integral_gaussianMixedIntegrand_polar, integral_angularMode_Ioo]
  by_cases hab : a = b
  · subst b
    simp only [if_pos]
    have hrad := integral_pow_mul_exp_neg_mul_sq_Ioi_complex n a hn
    rw [show a + a + 1 = 2 * a + 1 by omega]
    have hint :
        (∫ r : ℝ in Set.Ioi 0,
            (((n : ℝ) : ℂ) / Real.pi) * (r : ℂ) ^ (2 * a + 1) *
              (Real.exp (-(n : ℝ) * r ^ 2) : ℂ)) =
          (((n : ℝ) : ℂ) / Real.pi) *
            ∫ r : ℝ in Set.Ioi 0,
              ((r ^ (2 * a + 1) * Real.exp (-(n : ℝ) * r ^ 2) : ℝ) : ℂ) := by
      calc
        _ = ∫ r : ℝ in Set.Ioi 0,
            (((n : ℝ) : ℂ) / Real.pi) *
              ((r ^ (2 * a + 1) * Real.exp (-(n : ℝ) * r ^ 2) : ℝ) : ℂ) := by
                apply integral_congr_ae
                filter_upwards with r
                push_cast
                ring
        _ = _ := integral_const_mul
          (((n : ℝ) : ℂ) / Real.pi)
          (fun r : ℝ ↦
            ((r ^ (2 * a + 1) * Real.exp (-(n : ℝ) * r ^ 2) : ℝ) : ℂ))
    rw [hint, hrad]
    field_simp [show (n : ℂ) ≠ 0 by exact_mod_cast hn.ne']
    rw [pow_succ]
    push_cast
    simp only [mul_comm, mul_left_comm, mul_assoc]
  · simp only [if_neg hab, mul_zero]

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/PolynomialCompactApproximation.lean #
import GinibrePoincare.Concrete.Configuration
import Mathlib.Topology.ContinuousMap.StoneWeierstrass

/-! # Polynomial approximation on compact configuration sets -/

open scoped ComplexConjugate

namespace GinibrePoincare

noncomputable section

/-- Restriction of a complex coordinate to a compact configuration set. -/
def compactCoordinate (n : ℕ) (K : Set (Configuration n)) (i : Fin n) :
    C(K, ℂ) :=
  ⟨fun z ↦ z.1 i, (continuous_apply i).comp continuous_subtype_val⟩

/-- The star algebra generated by the coordinate functions.  Its elements
are precisely finite algebraic expressions in coordinates and their complex
conjugates, hence restrictions of complex coordinate/conjugate-coordinate
polynomials. -/
def configurationPolynomialStarAlgebra (n : ℕ)
    (K : Set (Configuration n)) : StarSubalgebra ℂ C(K, ℂ) :=
  StarAlgebra.adjoin ℂ
    (Set.range fun i : Fin n ↦ compactCoordinate n K i)

theorem compactCoordinate_mem_configurationPolynomialStarAlgebra
    (n : ℕ) (K : Set (Configuration n)) (i : Fin n) :
    compactCoordinate n K i ∈ configurationPolynomialStarAlgebra n K := by
  exact (StarAlgebra.subset_adjoin ℂ _) ⟨i, rfl⟩

theorem configurationPolynomialStarAlgebra_one_mem
    (n : ℕ) (K : Set (Configuration n)) :
    (1 : C(K, ℂ)) ∈ configurationPolynomialStarAlgebra n K :=
  (configurationPolynomialStarAlgebra n K).one_mem

/-- Coordinate polynomials separate configurations on every subset. -/
theorem configurationPolynomialStarAlgebra_separatesPoints
    (n : ℕ) (K : Set (Configuration n)) :
    (configurationPolynomialStarAlgebra n K).SeparatesPoints := by
  intro x y hxy
  have hi : ∃ i : Fin n, x.1 i ≠ y.1 i := by
    by_contra h
    push_neg at h
    apply hxy
    apply Subtype.ext
    exact funext h
  obtain ⟨i, hi⟩ := hi
  exact ⟨compactCoordinate n K i,
    ⟨compactCoordinate n K i,
      compactCoordinate_mem_configurationPolynomialStarAlgebra n K i, rfl⟩, hi⟩

/-- Complex coordinate/conjugate-coordinate polynomials are uniformly dense
in continuous functions on any compact configuration set. -/
theorem configurationPolynomialStarAlgebra_topologicalClosure
    (n : ℕ) (K : Set (Configuration n)) [CompactSpace K] :
    (configurationPolynomialStarAlgebra n K).topologicalClosure = ⊤ := by
  exact ContinuousMap.starSubalgebra_topologicalClosure_eq_top_of_separatesPoints
    _ (configurationPolynomialStarAlgebra_separatesPoints n K)

/-- Epsilon form of uniform polynomial approximation on a compact
configuration set. -/
theorem exists_configurationPolynomial_uniform_approximation
    (n : ℕ) (K : Set (Configuration n)) [CompactSpace K]
    (f : C(K, ℂ)) {ε : ℝ} (hε : 0 < ε) :
    ∃ g : configurationPolynomialStarAlgebra n K,
      ‖(g : C(K, ℂ)) - f‖ < ε := by
  have hf : f ∈ (configurationPolynomialStarAlgebra n K).topologicalClosure := by
    rw [configurationPolynomialStarAlgebra_topologicalClosure n K]
    simp
  have hf' : f ∈ closure
      (configurationPolynomialStarAlgebra n K : Set C(K, ℂ)) := hf
  obtain ⟨g, hg, hgf⟩ := (Metric.mem_closure_iff.mp hf') ε hε
  exact ⟨⟨g, hg⟩, by simpa [dist_eq_norm, norm_sub_rev] using hgf⟩

/-- Stone--Weierstrass on a closed configuration ball. -/
theorem configurationPolynomial_closedBall_topologicalClosure
    (n : ℕ) (R : ℝ) :
    let K : Set (Configuration n) := Metric.closedBall 0 R
    (configurationPolynomialStarAlgebra n K).topologicalClosure = ⊤ := by
  let K : Set (Configuration n) := Metric.closedBall 0 R
  have hK : IsCompact K := ProperSpace.isCompact_closedBall 0 R
  letI : CompactSpace K := isCompact_iff_compactSpace.mp hK
  exact configurationPolynomialStarAlgebra_topologicalClosure n K

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/RadialMoments.lean #
import Mathlib.MeasureTheory.Integral.Gamma

/-! # Radial Gaussian moments -/

open MeasureTheory Set Real

namespace GinibrePoincare

noncomputable section

/-- The exact radial moment appearing in polar integration of a complex
Gaussian monomial. -/
theorem integral_pow_mul_exp_neg_mul_sq_Ioi (n a : ℕ) (hn : 0 < n) :
    ∫ r : ℝ in Ioi 0, r ^ (2 * a + 1) * Real.exp (-(n : ℝ) * r ^ 2) =
      (a.factorial : ℝ) / (2 * (n : ℝ) ^ (a + 1)) := by
  have hnR : (0 : ℝ) < n := by exact_mod_cast hn
  have h := integral_rpow_mul_exp_neg_mul_rpow
    (p := (2 : ℝ)) (q := (2 * a + 1 : ℝ)) (b := (n : ℝ))
    (by norm_num) (by
      have ha : (0 : ℝ) ≤ a := by positivity
      linarith) hnR
  have hintegrand :
      (fun r : ℝ ↦ r ^ (2 * a + 1) * Real.exp (-(n : ℝ) * r ^ 2)) =ᵐ[volume.restrict (Ioi 0)]
        (fun r : ℝ ↦ r ^ (2 * a + 1 : ℝ) *
          Real.exp (-(n : ℝ) * r ^ (2 : ℝ))) := by
    filter_upwards [ae_restrict_mem measurableSet_Ioi] with r hr
    have hp : r ^ (2 * a + 1) = r ^ (2 * (a : ℝ) + 1) := by
      rw [← Real.rpow_natCast r (2 * a + 1)]
      congr 1
      push_cast
      rfl
    have htwo : r ^ (2 : ℕ) = r ^ (2 : ℝ) :=
      (Real.rpow_natCast r 2).symm
    rw [hp, htwo]
  rw [integral_congr_ae hintegrand, h]
  have hquot : ((2 * a + 1 : ℝ) + 1) / 2 = (a + 1 : ℕ) := by
    push_cast
    ring
  rw [hquot]
  rw [show ((a + 1 : ℕ) : ℝ) = (a : ℝ) + 1 by push_cast; ring,
    Real.Gamma_nat_eq_factorial]
  have hneg : -((2 * a + 1 : ℝ) + 1) / 2 = -((a + 1 : ℕ) : ℝ) := by
    linarith [hquot]
  rw [hneg]
  rw [Real.rpow_neg hnR.le, Real.rpow_natCast]
  field_simp [hnR.ne']

/-- Complex-valued version of the radial Gaussian moment. -/
theorem integral_pow_mul_exp_neg_mul_sq_Ioi_complex (n a : ℕ) (hn : 0 < n) :
    ∫ r : ℝ in Ioi 0,
        ((r ^ (2 * a + 1) * Real.exp (-(n : ℝ) * r ^ 2) : ℝ) : ℂ) =
      (a.factorial : ℂ) / (2 * (n : ℂ) ^ (a + 1)) := by
  rw [integral_complex_ofReal]
  rw [integral_pow_mul_exp_neg_mul_sq_Ioi n a hn]
  push_cast
  rfl

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/RealGaussianIntegrationByParts.lean #
import GinibrePoincare.Analysis.GaussianDensity
import Mathlib.MeasureTheory.Integral.IntegralEqImproper
import Mathlib.MeasureTheory.Integral.Bochner.ContinuousLinearMap

/-! # One-dimensional Gaussian integration by parts -/

open MeasureTheory
open scoped ENNReal

namespace GinibrePoincare

noncomputable section

/-- The real density of one coordinate in the normalization of the Ginibre
Gaussian reference measure. -/
def realCoordinateDensity (n : ℕ) (x : ℝ) : ℝ :=
  (Real.sqrt (Real.pi / n))⁻¹ * Real.exp (-(n : ℝ) * x ^ 2)

theorem continuous_realCoordinateDensity (n : ℕ) :
    Continuous (realCoordinateDensity n) := by
  unfold realCoordinateDensity
  fun_prop

theorem hasDerivAt_realCoordinateDensity (n : ℕ) (x : ℝ) :
    HasDerivAt (realCoordinateDensity n)
      (-2 * (n : ℝ) * x * realCoordinateDensity n x) x := by
  have he : HasDerivAt (fun y : ℝ => -(n : ℝ) * y ^ 2)
      (-2 * (n : ℝ) * x) x := by
    have hraw := (hasDerivAt_const x (-(n : ℝ))).mul
      ((hasDerivAt_id x).pow 2)
    change HasDerivAt (fun y : ℝ => -(n : ℝ) * y ^ 2)
      (0 * x ^ 2 + -(n : ℝ) * ((2 : ℕ) * x ^ (2 - 1) * 1)) x at hraw
    apply hraw.congr_deriv
    norm_num
    ring
  have hexp := (Real.hasDerivAt_exp (-(n : ℝ) * x ^ 2)).comp x he
  have h := hexp.const_mul (Real.sqrt (Real.pi / n))⁻¹
  have hfun : realCoordinateDensity n =
      fun y => (Real.sqrt (Real.pi / n))⁻¹ *
        Real.exp (-(n : ℝ) * y ^ 2) := by rfl
  rw [hfun]
  apply h.congr_deriv
  ring

theorem integrable_mul_realCoordinateDensity {n : ℕ} {f : ℝ → ℂ}
    (hf : Continuous f) (hfc : HasCompactSupport f) :
    Integrable (fun x ↦ f x * realCoordinateDensity n x) := by
  apply (hf.mul (Complex.continuous_ofReal.comp
    (continuous_realCoordinateDensity n))).integrable_of_hasCompactSupport
  exact hfc.mul_right

theorem integrable_deriv_mul_realCoordinateDensity {n : ℕ} {f : ℝ → ℂ}
    (hf : ContDiff ℝ 1 f) (hfc : HasCompactSupport f) :
    Integrable (fun x ↦ deriv f x * realCoordinateDensity n x) := by
  apply ((hf.continuous_deriv le_rfl).mul (Complex.continuous_ofReal.comp
    (continuous_realCoordinateDensity n))).integrable_of_hasCompactSupport
  exact hfc.deriv.mul_right

theorem integrable_mul_realCoordinateDensity_deriv {n : ℕ} {f : ℝ → ℂ}
    (hf : Continuous f) (hfc : HasCompactSupport f) :
    Integrable (fun x ↦ f x *
      ((-2 * (n : ℝ) * x * realCoordinateDensity n x : ℝ) : ℂ)) := by
  have hc : Continuous (fun x : ℝ ↦
      ((-2 * (n : ℝ) * x * realCoordinateDensity n x : ℝ) : ℂ)) := by
    exact Complex.continuous_ofReal.comp
      ((continuous_const.mul continuous_id).mul (continuous_realCoordinateDensity n))
  apply (hf.mul hc).integrable_of_hasCompactSupport
  exact hfc.mul_right

theorem integrable_deriv_product_realCoordinateDensity {n : ℕ} {f : ℝ → ℂ}
    (hf : ContDiff ℝ 1 f) (hfc : HasCompactSupport f) :
    Integrable (fun x ↦
      deriv f x * realCoordinateDensity n x +
        f x * ((-2 * (n : ℝ) * x * realCoordinateDensity n x : ℝ) : ℂ)) :=
  (integrable_deriv_mul_realCoordinateDensity hf hfc).add
    (integrable_mul_realCoordinateDensity_deriv hf.continuous hfc)

theorem realGaussianIntegrationByPartsLebesgue {n : ℕ}
    {f : ℝ → ℂ} (hf : ContDiff ℝ 1 f) (hfc : HasCompactSupport f) :
    (∫ x, deriv f x * realCoordinateDensity n x) =
      ∫ x, (((2 * n : ℝ) * x : ℝ) : ℂ) * f x * realCoordinateDensity n x := by
  let ρ : ℝ → ℂ := fun x ↦ realCoordinateDensity n x
  let ρ' : ℝ → ℂ := fun x ↦
    ((-2 * (n : ℝ) * x * realCoordinateDensity n x : ℝ) : ℂ)
  have hfder (x : ℝ) : HasDerivAt f (deriv f x) x :=
    (hf.differentiable (by norm_num) x).hasDerivAt
  have hρ (x : ℝ) : HasDerivAt ρ (ρ' x) x := by
    exact (hasDerivAt_realCoordinateDensity n x).ofReal_comp
  have hibp := integral_mul_deriv_eq_deriv_mul_of_integrable
    (u := f) (u' := deriv f) (v := ρ) (v' := ρ')
    (fun x hx ↦ hfder x) (fun x hx ↦ hρ x)
    (integrable_mul_realCoordinateDensity_deriv hf.continuous hfc)
    (integrable_deriv_mul_realCoordinateDensity hf hfc)
    (integrable_mul_realCoordinateDensity hf.continuous hfc)
  change (∫ x, deriv f x * ρ x) = _
  calc
    (∫ x, deriv f x * ρ x) = -(∫ x, f x * ρ' x) := by
      rw [hibp]
      simp
    _ = ∫ x, (((2 * n : ℝ) * x : ℝ) : ℂ) * f x * realCoordinateDensity n x := by
      rw [← integral_neg]
      apply integral_congr_ae
      filter_upwards with x
      dsimp [ρ']
      push_cast
      ring

/-- Integration by parts without compact support.  This formulation is
tailored to polynomial test functions: Gaussian moment estimates discharge
the three explicit integrability hypotheses. -/
theorem realGaussianIntegrationByPartsLebesgue_of_integrable {n : ℕ}
    {f : ℝ → ℂ} (hf : Differentiable ℝ f)
    (hfd : Integrable (fun x ↦ deriv f x * realCoordinateDensity n x))
    (hfrho' : Integrable (fun x ↦ f x *
      ((-2 * (n : ℝ) * x * realCoordinateDensity n x : ℝ) : ℂ)))
    (hfrho : Integrable (fun x ↦ f x * realCoordinateDensity n x)) :
    (∫ x, deriv f x * realCoordinateDensity n x) =
      ∫ x, (((2 * n : ℝ) * x : ℝ) : ℂ) * f x *
        realCoordinateDensity n x := by
  let ρ : ℝ → ℂ := fun x ↦ realCoordinateDensity n x
  let ρ' : ℝ → ℂ := fun x ↦
    ((-2 * (n : ℝ) * x * realCoordinateDensity n x : ℝ) : ℂ)
  have hfder (x : ℝ) : HasDerivAt f (deriv f x) x := (hf x).hasDerivAt
  have hρ (x : ℝ) : HasDerivAt ρ (ρ' x) x := by
    exact (hasDerivAt_realCoordinateDensity n x).ofReal_comp
  have hibp := integral_mul_deriv_eq_deriv_mul_of_integrable
    (u := f) (u' := deriv f) (v := ρ) (v' := ρ')
    (fun x _ ↦ hfder x) (fun x _ ↦ hρ x) hfrho' hfd hfrho
  change (∫ x, deriv f x * ρ x) = _
  calc
    (∫ x, deriv f x * ρ x) = -(∫ x, f x * ρ' x) := by
      rw [hibp]
      simp
    _ = ∫ x, (((2 * n : ℝ) * x : ℝ) : ℂ) * f x *
        realCoordinateDensity n x := by
      rw [← integral_neg]
      apply integral_congr_ae
      filter_upwards with x
      dsimp [ρ']
      push_cast
      ring

theorem integral_realCoordinateGaussian_eq_density {n : ℕ} (hn : 0 < n)
    (f : ℝ → ℂ) :
    (∫ x, f x ∂(realCoordinateGaussianProbability n : Measure ℝ)) =
      ∫ x, f x * realCoordinateDensity n x := by
  rw [realCoordinateGaussianMeasure_eq_withDensity hn,
    integral_withDensity_eq_integral_toReal_smul]
  · apply integral_congr_ae
    filter_upwards with x
    rw [realCoordinateGaussianPDF_formula hn]
    rw [ENNReal.toReal_ofReal (by positivity)]
    simp [realCoordinateDensity, smul_eq_mul, mul_comm]
  · exact ProbabilityTheory.measurable_gaussianPDF 0 (realCoordinateVariance n)
  · exact Filter.Eventually.of_forall fun x ↦
      ProbabilityTheory.gaussianPDF_lt_top

theorem integrable_mul_realCoordinateDensity_of_integrable
    {n : ℕ} (hn : 0 < n) {f : ℝ → ℂ}
    (hfm : AEStronglyMeasurable f)
    (hf : Integrable f (realCoordinateGaussianProbability n : Measure ℝ)) :
    Integrable (fun x ↦ f x * realCoordinateDensity n x) := by
  rw [realCoordinateGaussianMeasure_eq_withDensity hn] at hf
  have h := (integrable_withDensity_iff
    (ProbabilityTheory.measurable_gaussianPDF 0 (realCoordinateVariance n))
    (Filter.Eventually.of_forall fun x ↦
      ProbabilityTheory.gaussianPDF_lt_top)).mp hf.norm
  apply (integrable_norm_iff
    (hfm.mul ((Complex.continuous_ofReal.comp
      (continuous_realCoordinateDensity n)).aestronglyMeasurable))).mp
  apply h.congr
  filter_upwards with x
  rw [realCoordinateGaussianPDF_formula hn,
    ENNReal.toReal_ofReal (by positivity)]
  change ‖f x‖ * realCoordinateDensity n x =
    ‖f x * (realCoordinateDensity n x : ℂ)‖
  have hd : 0 ≤ realCoordinateDensity n x := by
    unfold realCoordinateDensity
    positivity
  rw [norm_mul]
  simp [abs_of_nonneg hd]

/-- Gaussian integration by parts in the exact variance `1/(2n)`
normalization used for each real coordinate. -/
theorem realGaussianIntegrationByParts {n : ℕ} (hn : 0 < n)
    {f : ℝ → ℂ} (hf : ContDiff ℝ 1 f) (hfc : HasCompactSupport f) :
    (∫ x, deriv f x ∂(realCoordinateGaussianProbability n : Measure ℝ)) =
      (2 * n : ℝ) *
        ∫ x, (x : ℂ) * f x
          ∂(realCoordinateGaussianProbability n : Measure ℝ) := by
  rw [integral_realCoordinateGaussian_eq_density hn,
    integral_realCoordinateGaussian_eq_density hn,
    realGaussianIntegrationByPartsLebesgue hf hfc, ← integral_const_mul]
  apply integral_congr_ae
  filter_upwards with x
  push_cast
  ring

/-- Gaussian-measure form of the non-compactly-supported integration by
parts theorem. -/
theorem realGaussianIntegrationByParts_of_integrable {n : ℕ} (hn : 0 < n)
    {f : ℝ → ℂ} (hf : Differentiable ℝ f)
    (hfd : Integrable (fun x ↦ deriv f x * realCoordinateDensity n x))
    (hfrho' : Integrable (fun x ↦ f x *
      ((-2 * (n : ℝ) * x * realCoordinateDensity n x : ℝ) : ℂ)))
    (hfrho : Integrable (fun x ↦ f x * realCoordinateDensity n x)) :
    (∫ x, deriv f x ∂(realCoordinateGaussianProbability n : Measure ℝ)) =
      (2 * n : ℝ) *
        ∫ x, (x : ℂ) * f x
          ∂(realCoordinateGaussianProbability n : Measure ℝ) := by
  rw [integral_realCoordinateGaussian_eq_density hn,
    integral_realCoordinateGaussian_eq_density hn,
    realGaussianIntegrationByPartsLebesgue_of_integrable hf hfd hfrho' hfrho,
    ← integral_const_mul]
  apply integral_congr_ae
  filter_upwards with x
  push_cast
  ring

theorem realGaussianIntegrationByParts_of_gaussian_integrable
    {n : ℕ} (hn : 0 < n) {f : ℝ → ℂ}
    (hf : ContDiff ℝ 1 f)
    (hfi : Integrable f (realCoordinateGaussianProbability n : Measure ℝ))
    (hfdi : Integrable (deriv f)
      (realCoordinateGaussianProbability n : Measure ℝ))
    (hxfi : Integrable (fun x : ℝ ↦ (x : ℂ) * f x)
      (realCoordinateGaussianProbability n : Measure ℝ)) :
    (∫ x, deriv f x ∂(realCoordinateGaussianProbability n : Measure ℝ)) =
      (2 * n : ℝ) * ∫ x, (x : ℂ) * f x
        ∂(realCoordinateGaussianProbability n : Measure ℝ) := by
  apply realGaussianIntegrationByParts_of_integrable hn
    (hf.differentiable (by norm_num))
  · exact integrable_mul_realCoordinateDensity_of_integrable hn
      (hf.continuous_deriv le_rfl).aestronglyMeasurable hfdi
  · have h := (integrable_mul_realCoordinateDensity_of_integrable hn
        ((Complex.continuous_ofReal.mul hf.continuous).aestronglyMeasurable) hxfi).const_mul
        ((-2 * (n : ℝ) : ℝ) : ℂ)
    exact h.congr (Filter.Eventually.of_forall fun x ↦ by
      simp only [Pi.mul_apply]
      push_cast
      ring)
  · exact integrable_mul_realCoordinateDensity_of_integrable hn
      hf.continuous.aestronglyMeasurable hfi

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/VandermondeGroundStateZeroMode.lean #
import GinibrePoincare.Analysis.GaussianHermiteMoments
import GinibrePoincare.Analysis.VandermondeL2
import GinibrePoincare.Analysis.HermiteParsevalModes
import GinibrePoincare.Analysis.HolomorphicVandermondeDivision

open MeasureTheory
open scoped BigOperators ENNReal

namespace GinibrePoincare

noncomputable section

open ComplexHermite

/-- A holomorphic coordinate monomial is an algebraic zero-antiholomorphic
Hermite vector. -/
theorem exists_memLp_holomorphicMonomial_mem_antiDegreeZeroSpan
    (n : ℕ) (hn : 0 < n) (p : Fin n → ℕ) :
    ∃ hmem : MemLp (fun z : Configuration n => ∏ i, z i ^ p i) 2
        (complexGaussianMeasure n),
      hmem.toLp (fun z : Configuration n => ∏ i, z i ^ p i) ∈
        hermiteAntiDegreeSpan n hn 0 := by
  have hpoint : (fun z : Configuration n => ∏ i, z i ^ p i) ∈
      multivariateNormalizedRectangleSpan n hn p 0 := by
    rw [multivariateNormalizedRectangleSpan_eq_mixedMonomialRectangleSpan]
    apply Submodule.subset_span
    refine ⟨p, 0, fun _ => le_rfl, fun _ => le_rfl, ?_⟩
    funext z
    simp
  have lift : ∀ {F : Configuration n → ℂ},
      F ∈ multivariateNormalizedRectangleSpan n hn p 0 →
      ∃ hmem : MemLp F 2 (complexGaussianMeasure n),
        hmem.toLp F ∈ hermiteAntiDegreeSpan n hn 0 := by
    intro F hF
    induction hF using Submodule.span_induction with
    | mem f hf =>
        rcases hf with ⟨a, b, ha, hb, rfl⟩
        have hb0 : b = 0 := by funext i; exact Nat.eq_zero_of_le_zero (hb i)
        subst b
        refine ⟨memLp_two_multivariateNormalized n hn a 0, ?_⟩
        apply Submodule.subset_span
        exact ⟨(a, 0), by simp [totalAntiDegree], rfl⟩
    | zero => exact ⟨MemLp.zero, by simp⟩
    | add x y hx hy ihx ihy =>
        rcases ihx with ⟨hxmem, hxspan⟩
        rcases ihy with ⟨hymem, hyspan⟩
        refine ⟨hxmem.add hymem, ?_⟩
        rw [MemLp.toLp_add hxmem hymem]
        exact (hermiteAntiDegreeSpan n hn 0).add_mem hxspan hyspan
    | smul c x hx ih =>
        rcases ih with ⟨hxmem, hxspan⟩
        refine ⟨hxmem.const_smul c, ?_⟩
        rw [MemLp.toLp_const_smul c hxmem]
        exact (hermiteAntiDegreeSpan n hn 0).smul_mem c hxspan
  exact lift hpoint

/-- Evaluation of every holomorphic configuration polynomial is an
algebraic zero-antiholomorphic Hermite vector. -/
theorem exists_memLp_configurationPolynomial_mem_antiDegreeZeroSpan
    (n : ℕ) (hn : 0 < n) (P : ConfigurationPolynomial n) :
    ∃ hmem : MemLp (fun z : Configuration n => MvPolynomial.eval z P) 2
        (complexGaussianMeasure n),
      hmem.toLp (fun z : Configuration n => MvPolynomial.eval z P) ∈
        hermiteAntiDegreeSpan n hn 0 := by
  induction P using MvPolynomial.induction_on' with
  | monomial u c =>
      obtain ⟨hm, hspan⟩ :=
        exists_memLp_holomorphicMonomial_mem_antiDegreeZeroSpan n hn
          (fun i => u i)
      have heval : (fun z : Configuration n =>
          MvPolynomial.eval z (MvPolynomial.monomial u c)) =
          fun z => c * ∏ i, z i ^ u i := by
        funext z
        rw [MvPolynomial.eval_monomial]
        congr 1
        rw [Finsupp.prod]
        apply Finset.prod_subset (Finset.subset_univ _)
        intro i hi hnot
        have hz : u i = 0 := by simpa using hnot
        rw [hz, pow_zero]
      rw [heval]
      refine ⟨hm.const_smul c, ?_⟩
      change (hm.const_smul c).toLp
        (c • fun z : Configuration n => ∏ i, z i ^ u i) ∈ _
      rw [MemLp.toLp_const_smul c hm]
      exact (hermiteAntiDegreeSpan n hn 0).smul_mem c hspan
  | add P Q ihP ihQ =>
      rcases ihP with ⟨hP, hPspan⟩
      rcases ihQ with ⟨hQ, hQspan⟩
      have heval : (fun z : Configuration n => MvPolynomial.eval z (P + Q)) =
          (fun z => MvPolynomial.eval z P) + fun z => MvPolynomial.eval z Q := by
        funext z
        simp
      rw [heval]
      refine ⟨hP.add hQ, ?_⟩
      rw [MemLp.toLp_add hP hQ]
      exact (hermiteAntiDegreeSpan n hn 0).add_mem hPspan hQspan

/-- The normalized Vandermonde ground state, regarded as a Gaussian `L²`
vector.  Its representative is
`groundStateNormalization n⁻¹ * vandermonde`. -/
def normalizedVandermondeGroundStateL2 (n : ℕ) (hn : 0 < n) :
    Lp ℂ 2 (complexGaussianMeasure n) :=
  ((groundStateNormalization n : ℂ)⁻¹) •
    ((exists_memLp_configurationPolynomial_mem_antiDegreeZeroSpan n hn
      (polynomialVandermonde n)).choose.toLp
        (fun z : Configuration n =>
          MvPolynomial.eval z (polynomialVandermonde n)))

/-- The normalized Vandermonde ground state is a zero-antiholomorphic-degree
Hermite vector. -/
theorem normalizedVandermondeGroundStateL2_mem_hermiteAntiDegreeClosedSpan
    (n : ℕ) (hn : 0 < n) :
    normalizedVandermondeGroundStateL2 n hn ∈
      hermiteAntiDegreeClosedSpan n hn 0 := by
  apply (hermiteAntiDegreeClosedSpan n hn 0).toSubmodule.smul_mem
  exact (hermiteAntiDegreeSpan n hn 0).le_topologicalClosure
    (exists_memLp_configurationPolynomial_mem_antiDegreeZeroSpan n hn
      (polynomialVandermonde n)).choose_spec

/-- Pointwise representative of the normalized Vandermonde ground state. -/
theorem normalizedVandermondeGroundStateL2_coeFn (n : ℕ) (hn : 0 < n) :
    (normalizedVandermondeGroundStateL2 n hn : Configuration n → ℂ) =ᵐ[
      complexGaussianMeasure n]
      normalizedVandermondeMultiplier n := by
  unfold normalizedVandermondeGroundStateL2
  let hP := (exists_memLp_configurationPolynomial_mem_antiDegreeZeroSpan n hn
    (polynomialVandermonde n)).choose
  filter_upwards [Lp.coeFn_smul ((groundStateNormalization n : ℂ)⁻¹)
      (hP.toLp (fun z : Configuration n =>
        MvPolynomial.eval z (polynomialVandermonde n))),
    hP.coeFn_toLp] with z hsmul heval
  rw [hsmul]
  simp only [Pi.smul_apply, smul_eq_mul]
  rw [heval]
  rw [eval_polynomialVandermonde]
  rfl

end
end GinibrePoincare
Analysis GinibrePoincare/Analysis/VandermondeL2.lean #
import GinibrePoincare.Analysis.CollisionNull
import GinibrePoincare.Analysis.GinibreMassFiniteness
import GinibrePoincare.Concrete.NormalizedGroundState
import Mathlib.MeasureTheory.Function.LpSpace.Complete

/-! # The normalized Vandermonde isometry on `L²` -/

open MeasureTheory
open scoped ENNReal

namespace GinibrePoincare

noncomputable section

/-- Pointwise multiplier used by the normalized ground-state transform. -/
def normalizedVandermondeMultiplier (n : ℕ) (z : Configuration n) : ℂ :=
  ((groundStateNormalization n : ℂ)⁻¹) * vandermonde z

private theorem groundStateNormalization_pos {n : ℕ}
    (h : GinibreMassIsValid n) : 0 < groundStateNormalization n := by
  unfold groundStateNormalization
  apply Real.sqrt_pos.2
  exact ENNReal.toReal_pos h.1.ne' h.2.ne

private theorem enorm_normalizedVandermondeMultiplier_sq {n : ℕ}
    (h : GinibreMassIsValid n) (z : Configuration n) :
    ‖normalizedVandermondeMultiplier n z‖ₑ ^ (2 : ℝ) =
      (ginibreNormalizingMass n)⁻¹ * vandermondeDensity z := by
  have hMtop : ginibreNormalizingMass n ≠ ⊤ := h.2.ne
  have hM0 : ginibreNormalizingMass n ≠ 0 := h.1.ne'
  have hnorm : 0 < groundStateNormalization n := groundStateNormalization_pos h
  unfold normalizedVandermondeMultiplier vandermondeDensity vandermondeWeight
  have hsquare (x : ℂ) : ‖x‖ₑ ^ (2 : ℝ) =
      ENNReal.ofReal (Complex.normSq x) := by
    rw [ENNReal.rpow_two, ← Complex.sq_norm]
    simp [enorm]
  rw [hsquare]
  rw [Complex.normSq_mul, Complex.normSq_inv, Complex.normSq_ofReal]
  rw [ENNReal.ofReal_mul (by positivity :
    0 ≤ ((groundStateNormalization n) * groundStateNormalization n)⁻¹)]
  congr 1
  have hsqrt : groundStateNormalization n ^ 2 =
      (ginibreNormalizingMass n).toReal := by
    unfold groundStateNormalization
    exact Real.sq_sqrt ENNReal.toReal_nonneg
  have hinv : ((groundStateNormalization n) * groundStateNormalization n)⁻¹ =
      (ginibreNormalizingMass n).toReal⁻¹ := by
    rw [← pow_two, hsqrt]
  rw [hinv, ← ENNReal.toReal_inv]
  exact ENNReal.ofReal_toReal (ENNReal.inv_ne_top.mpr hM0)

private theorem normalizedMultiplier_withDensity {n : ℕ}
    (h : GinibreMassIsValid n) :
    (complexGaussianMeasure n).withDensity
        (fun z ↦ ‖normalizedVandermondeMultiplier n z‖ₑ ^ (2 : ℝ)) =
      ginibreMeasure n := by
  simp_rw [enorm_normalizedVandermondeMultiplier_sq h]
  unfold ginibreMeasure rawGinibreMeasure
  exact withDensity_smul _ measurable_vandermondeDensity

private theorem normalizedVandermonde_lintegral {n : ℕ}
    (h : GinibreMassIsValid n) (u : Lp ℂ 2 (ginibreMeasure n)) :
    (∫⁻ z, ‖normalizedVandermondeMultiplier n z * u z‖ₑ ^ (2 : ℝ)
      ∂complexGaussianMeasure n) =
      ∫⁻ z, ‖u z‖ₑ ^ (2 : ℝ) ∂ginibreMeasure n := by
  let d := fun z : Configuration n ↦
    ‖normalizedVandermondeMultiplier n z‖ₑ ^ (2 : ℝ)
  have hd : Measurable d := by
    unfold d normalizedVandermondeMultiplier
    exact (ENNReal.continuous_rpow_const.comp
      (continuous_vandermonde.const_mul _).enorm).measurable
  have hdtop : ∀ᵐ z ∂complexGaussianMeasure n, d z < ⊤ :=
    Filter.Eventually.of_forall fun z ↦ by
      unfold d
      rw [enorm_normalizedVandermondeMultiplier_sq h]
      exact ENNReal.mul_lt_top (ENNReal.inv_ne_top.mpr h.1.ne').lt_top
        (by unfold vandermondeDensity; exact ENNReal.ofReal_ne_top.lt_top)
  calc
    _ = ∫⁻ z, d z * ‖u z‖ₑ ^ (2 : ℝ) ∂complexGaussianMeasure n := by
      apply lintegral_congr
      intro z
      unfold d
      rw [enorm_mul, ENNReal.mul_rpow_of_nonneg]
      positivity
    _ = ∫⁻ z, ‖u z‖ₑ ^ (2 : ℝ)
        ∂(complexGaussianMeasure n).withDensity d := by
      exact (lintegral_withDensity_eq_lintegral_mul_non_measurable
        _ hd hdtop _).symm
    _ = _ := by
      have hm := normalizedMultiplier_withDensity h
      change (∫⁻ z, ‖u z‖ₑ ^ (2 : ℝ)
        ∂(complexGaussianMeasure n).withDensity d) = _
      rw [hm]

private theorem normalizedVandermonde_memLp {n : ℕ}
    (h : GinibreMassIsValid n) (u : Lp ℂ 2 (ginibreMeasure n)) :
    MemLp (fun z ↦ normalizedVandermondeMultiplier n z * u z) 2
      (complexGaussianMeasure n) := by
  have hac := complexGaussianMeasure_absolutelyContinuous_ginibreMeasure h
  constructor
  · exact ((continuous_vandermonde.const_mul _).aestronglyMeasurable).mul
      ((Lp.aestronglyMeasurable u).mono_ac hac)
  · rw [eLpNorm_eq_eLpNorm' (by norm_num) (by norm_num),
      eLpNorm'_eq_lintegral_enorm]
    norm_num only [ENNReal.toReal_ofNat]
    rw [normalizedVandermonde_lintegral h u]
    have hu := (Lp.memLp u).2
    rw [eLpNorm_eq_eLpNorm' (by norm_num) (by norm_num),
      eLpNorm'_eq_lintegral_enorm] at hu
    exact hu

private theorem normalizedVandermonde_norm {n : ℕ}
    (h : GinibreMassIsValid n) (u : Lp ℂ 2 (ginibreMeasure n)) :
    ‖(normalizedVandermonde_memLp h u).toLp
        (fun z ↦ normalizedVandermondeMultiplier n z * u z)‖ = ‖u‖ := by
  simp only [Lp.norm_def]
  congr 1
  rw [eLpNorm_congr_ae (normalizedVandermonde_memLp h u).coeFn_toLp]
  rw [eLpNorm_eq_eLpNorm' (by norm_num) (by norm_num),
    eLpNorm_eq_eLpNorm' (by norm_num) (by norm_num),
    eLpNorm'_eq_lintegral_enorm, eLpNorm'_eq_lintegral_enorm]
  norm_num only [ENNReal.toReal_ofNat]
  rw [normalizedVandermonde_lintegral h u]

/-- Normalized multiplication by the Vandermonde as a genuine complex linear
isometry from Ginibre `L²` into Gaussian `L²`. -/
def normalizedVandermondeL2 (n : ℕ) (hn : 0 < n) :
    Lp ℂ 2 (ginibreMeasure n) →ₗᵢ[ℂ]
      Lp ℂ 2 (complexGaussianMeasure n) := by
  let h := ginibreMassEvaluation n hn
  exact
    { toFun := fun u ↦ (normalizedVandermonde_memLp h u).toLp
          (fun z ↦ normalizedVandermondeMultiplier n z * u z)
      map_add' := by
        intro u v
        apply Lp.ext
        filter_upwards [(normalizedVandermonde_memLp h (u + v)).coeFn_toLp,
          (normalizedVandermonde_memLp h u).coeFn_toLp,
          (normalizedVandermonde_memLp h v).coeFn_toLp,
          (complexGaussianMeasure_absolutelyContinuous_ginibreMeasure h).ae_eq
            (Lp.coeFn_add u v),
          Lp.coeFn_add
            ((normalizedVandermonde_memLp h u).toLp _)
            ((normalizedVandermonde_memLp h v).toLp _)] with z huv hu hv hadd hout
        rw [huv, hout]
        simp only [Pi.add_apply] at hadd ⊢
        rw [hadd, hu, hv, mul_add]
      map_smul' := by
        intro c u
        apply Lp.ext
        filter_upwards [(normalizedVandermonde_memLp h (c • u)).coeFn_toLp,
          (normalizedVandermonde_memLp h u).coeFn_toLp,
          (complexGaussianMeasure_absolutelyContinuous_ginibreMeasure h).ae_eq
            (Lp.coeFn_smul c u),
          Lp.coeFn_smul c ((normalizedVandermonde_memLp h u).toLp _)] with z hcu hu hin hout
        rw [hcu]
        simp only [RingHom.id_apply]
        rw [hout]
        simp only [Pi.smul_apply] at hin ⊢
        rw [hin, hu]
        simp only [smul_eq_mul]
        ring
      norm_map' := normalizedVandermonde_norm h }

/-- The normalized Vandermonde transform is an isometric equivalence onto its
range. -/
def normalizedVandermondeL2EquivRange (n : ℕ) (hn : 0 < n) :=
  (normalizedVandermondeL2 n hn).equivRange

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/VandermondeL2Inverse.lean #
import GinibrePoincare.Analysis.VandermondeSymmetryL2

/-! # Inverse of normalized Vandermonde multiplication on `L²` -/

open MeasureTheory
open scoped ENNReal

namespace GinibrePoincare

noncomputable section

/-- Measurable pointwise inverse multiplier; its value on collisions is
irrelevant because that locus is Gaussian-null. -/
def inverseVandermondeMultiplier (n : ℕ) (z : Configuration n) : ℂ :=
  (groundStateNormalization n : ℂ) * (vandermonde z)⁻¹

theorem measurable_inverseVandermondeMultiplier (n : ℕ) :
    Measurable (inverseVandermondeMultiplier n) := by
  unfold inverseVandermondeMultiplier
  exact measurable_const.mul continuous_vandermonde.measurable.inv

theorem inverse_mul_normalizedVandermondeMultiplier {n : ℕ}
    (h : GinibreMassIsValid n) {z : Configuration n}
    (hz : z ∉ collisionSet n) :
    inverseVandermondeMultiplier n z * normalizedVandermondeMultiplier n z = 1 := by
  have hV : vandermonde z ≠ 0 := by
    exact fun hv ↦ hz ((vandermonde_eq_zero_iff z).mp hv)
  have hN : groundStateNormalization n ≠ 0 := by
    unfold groundStateNormalization
    rw [Real.sqrt_ne_zero']
    exact ENNReal.toReal_pos h.1.ne' h.2.ne
  unfold inverseVandermondeMultiplier normalizedVandermondeMultiplier
  field_simp
  exact div_self (Complex.ofReal_ne_zero.mpr hN)

theorem normalized_mul_inverseVandermondeMultiplier {n : ℕ}
    (h : GinibreMassIsValid n) {z : Configuration n}
    (hz : z ∉ collisionSet n) :
    normalizedVandermondeMultiplier n z * inverseVandermondeMultiplier n z = 1 := by
  rw [mul_comm]
  exact inverse_mul_normalizedVandermondeMultiplier h hz

/-- Ginibre measure is always absolutely continuous with respect to the
Gaussian reference measure. -/
theorem ginibreMeasure_absolutelyContinuous_complexGaussianMeasure (n : ℕ) :
    ginibreMeasure n ≪ complexGaussianMeasure n := by
  unfold ginibreMeasure rawGinibreMeasure
  exact (Measure.smul_absolutelyContinuous.trans
    (withDensity_absolutelyContinuous _ _))

/-- The inverse multiplier applied to a Gaussian `L²` representative. -/
def inverseVandermondeFunction (n : ℕ)
    (v : Lp ℂ 2 (complexGaussianMeasure n)) : Configuration n → ℂ :=
  fun z ↦ inverseVandermondeMultiplier n z * v z

theorem inverseVandermondeFunction_aestronglyMeasurable (n : ℕ)
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    AEStronglyMeasurable (inverseVandermondeFunction n v)
      (ginibreMeasure n) := by
  exact (measurable_inverseVandermondeMultiplier n).aestronglyMeasurable.mul
    ((Lp.aestronglyMeasurable v).mono_ac
      (ginibreMeasure_absolutelyContinuous_complexGaussianMeasure n))

/-- Pointwise inverse cancellation holds Gaussian-almost everywhere. -/
theorem normalized_inverse_cancel_ae {n : ℕ} (h : GinibreMassIsValid n)
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    (fun z ↦ normalizedVandermondeMultiplier n z *
      inverseVandermondeFunction n v z) =ᵐ[complexGaussianMeasure n] v := by
  have houtside : ∀ᵐ z ∂complexGaussianMeasure n, z ∉ collisionSet n := by
    rw [ae_iff]
    rw [show {z : Configuration n | ¬z ∉ collisionSet n} = collisionSet n by
      ext z
      simp]
    exact complexGaussianMeasure_collisionSet n
  filter_upwards [houtside] with z hz
  unfold inverseVandermondeFunction
  rw [← mul_assoc, normalized_mul_inverseVandermondeMultiplier h hz]
  simp

/-- The inverse transform respects the expected permutation character: an
alternating input produces a symmetric pointwise transform away from the
collision locus. -/
theorem inverseMultiplier_permute {n : ℕ} (σ : ParticlePermutation n)
    {z : Configuration n} (hz : z ∉ collisionSet n) :
    inverseVandermondeMultiplier n (permute σ z) =
      permutationSign σ * inverseVandermondeMultiplier n z := by
  have hs : permutationSign σ * permutationSign σ = 1 := by
    unfold permutationSign
    rcases Int.units_eq_one_or (Equiv.Perm.sign σ) with h | h <;> simp [h]
  have hV : vandermonde z ≠ 0 :=
    fun hv ↦ hz ((vandermonde_eq_zero_iff z).mp hv)
  have hs0 : permutationSign σ ≠ 0 := by
    intro h0
    rw [h0, zero_mul] at hs
    exact zero_ne_one hs
  unfold inverseVandermondeMultiplier
  rw [vandermonde_permute]
  field_simp
  have hs' : permutationSign σ ^ 2 = 1 := by simpa [pow_two] using hs
  rw [hs']
  simp

/-- Exact squared extended norm of the inverse multiplier away from the
collision locus. -/
theorem enorm_inverseVandermondeMultiplier_sq {n : ℕ}
    (h : GinibreMassIsValid n) {z : Configuration n}
    (hz : z ∉ collisionSet n) :
    ‖inverseVandermondeMultiplier n z‖ₑ ^ (2 : ℝ) =
      ginibreNormalizingMass n * (vandermondeDensity z)⁻¹ := by
  have hV : vandermonde z ≠ 0 :=
    fun hv ↦ hz ((vandermonde_eq_zero_iff z).mp hv)
  have htop : ginibreNormalizingMass n ≠ ⊤ := h.2.ne
  have hsqrt :
      (ENNReal.ofReal (Real.sqrt (ginibreNormalizingMass n).toReal)) ^ 2 =
        ginibreNormalizingMass n := by
    rw [← ENNReal.ofReal_pow (Real.sqrt_nonneg _), Real.sq_sqrt ENNReal.toReal_nonneg]
    exact ENNReal.ofReal_toReal htop
  unfold inverseVandermondeMultiplier groundStateNormalization
  rw [ENNReal.rpow_two, enorm_mul, mul_pow]
  simp only [enorm]
  rw [show (↑‖(Real.sqrt (ginibreNormalizingMass n).toReal : ℂ)‖₊ : ℝ≥0∞) =
      ENNReal.ofReal (Real.sqrt (ginibreNormalizingMass n).toReal) by
    rw [ENNReal.coe_nnreal_eq]
    congr 1
    simp]
  rw [hsqrt]
  simp only [nnnorm_inv]
  unfold vandermondeDensity vandermondeWeight
  rw [show ENNReal.ofReal (Complex.normSq (vandermonde z)) =
      (‖vandermonde z‖₊ : ℝ≥0∞) ^ 2 by
    rw [Complex.normSq_eq_norm_sq]
    simp [ENNReal.ofReal_pow, enorm]]
  rw [ENNReal.coe_inv (by simpa using hV)]
  congr 1
  exact ENNReal.inv_pow.symm

/-- The inverse multiplier transports the Gaussian squared norm back to the
Ginibre squared norm. -/
theorem inverseVandermonde_lintegral {n : ℕ}
    (h : GinibreMassIsValid n) (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    (∫⁻ z, ‖inverseVandermondeFunction n v z‖ₑ ^ (2 : ℝ)
      ∂ginibreMeasure n) =
      ∫⁻ z, ‖v z‖ₑ ^ (2 : ℝ) ∂complexGaussianMeasure n := by
  have houtside : ∀ᵐ z ∂complexGaussianMeasure n, z ∉ collisionSet n := by
    rw [ae_iff]
    rw [show {z : Configuration n | ¬z ∉ collisionSet n} = collisionSet n by
      ext z
      simp]
    exact complexGaussianMeasure_collisionSet n
  have hinvmeas : AEStronglyMeasurable (inverseVandermondeFunction n v)
      (complexGaussianMeasure n) := by
    exact (measurable_inverseVandermondeMultiplier n).aestronglyMeasurable.mul
      (Lp.aestronglyMeasurable v)
  have hfmeas : AEMeasurable (fun z ↦ vandermondeDensity z *
      ‖inverseVandermondeFunction n v z‖ₑ ^ (2 : ℝ))
      (complexGaussianMeasure n) :=
    measurable_vandermondeDensity.aemeasurable.mul
      (hinvmeas.enorm.pow_const 2)
  unfold ginibreMeasure rawGinibreMeasure
  rw [lintegral_smul_measure]
  change (ginibreNormalizingMass n)⁻¹ *
      (∫⁻ z, ‖inverseVandermondeFunction n v z‖ₑ ^ (2 : ℝ)
        ∂(complexGaussianMeasure n).withDensity vandermondeDensity) = _
  rw [lintegral_withDensity_eq_lintegral_mul_non_measurable]
  · change (ginibreNormalizingMass n)⁻¹ *
        (∫⁻ z, vandermondeDensity z *
          ‖inverseVandermondeFunction n v z‖ₑ ^ (2 : ℝ)
          ∂complexGaussianMeasure n) = _
    rw [← lintegral_const_mul'' _ hfmeas]
    apply lintegral_congr_ae
    filter_upwards [houtside] with z hz
    unfold inverseVandermondeFunction
    rw [enorm_mul, ENNReal.mul_rpow_of_nonneg]
    · rw [enorm_inverseVandermondeMultiplier_sq h hz]
      have hd0 : vandermondeDensity z ≠ 0 := by
        unfold vandermondeDensity vandermondeWeight
        exact (ENNReal.ofReal_pos.mpr
          (Complex.normSq_pos.mpr
            (fun hv ↦ hz ((vandermonde_eq_zero_iff z).mp hv)))).ne'
      rw [show (ginibreNormalizingMass n)⁻¹ * (vandermondeDensity z *
          (ginibreNormalizingMass n * (vandermondeDensity z)⁻¹ * ‖v z‖ₑ ^ (2 : ℝ))) =
          ((ginibreNormalizingMass n)⁻¹ * ginibreNormalizingMass n) *
            (vandermondeDensity z * (vandermondeDensity z)⁻¹) *
              ‖v z‖ₑ ^ (2 : ℝ) by ac_rfl]
      rw [ENNReal.inv_mul_cancel h.1.ne' h.2.ne,
        ENNReal.mul_inv_cancel hd0 (by simp [vandermondeDensity])]
      simp
    · positivity
  · exact measurable_vandermondeDensity
  · exact Filter.Eventually.of_forall fun z ↦ by
      unfold vandermondeDensity
      exact ENNReal.ofReal_ne_top.lt_top

/-- The inverse Vandermonde transform of a Gaussian `L²` function belongs to
Ginibre `L²`. -/
theorem inverseVandermonde_memLp {n : ℕ}
    (h : GinibreMassIsValid n) (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    MemLp (inverseVandermondeFunction n v) 2 (ginibreMeasure n) := by
  constructor
  · exact inverseVandermondeFunction_aestronglyMeasurable n v
  · rw [eLpNorm_eq_eLpNorm' (by norm_num) (by norm_num),
      eLpNorm'_eq_lintegral_enorm]
    norm_num only [ENNReal.toReal_ofNat]
    rw [inverseVandermonde_lintegral h v]
    have hv := (Lp.memLp v).2
    rw [eLpNorm_eq_eLpNorm' (by norm_num) (by norm_num),
      eLpNorm'_eq_lintegral_enorm] at hv
    exact hv

private theorem inverseVandermonde_norm {n : ℕ}
    (h : GinibreMassIsValid n) (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    ‖(inverseVandermonde_memLp h v).toLp (inverseVandermondeFunction n v)‖ = ‖v‖ := by
  simp only [Lp.norm_def]
  congr 1
  rw [eLpNorm_congr_ae (inverseVandermonde_memLp h v).coeFn_toLp]
  rw [eLpNorm_eq_eLpNorm' (by norm_num) (by norm_num),
    eLpNorm_eq_eLpNorm' (by norm_num) (by norm_num),
    eLpNorm'_eq_lintegral_enorm, eLpNorm'_eq_lintegral_enorm]
  norm_num only [ENNReal.toReal_ofNat]
  rw [inverseVandermonde_lintegral h v]

/-- Multiplication by the normalized inverse Vandermonde as a complex linear
isometry from Gaussian `L²` to Ginibre `L²`. -/
def inverseVandermondeL2 (n : ℕ) (hn : 0 < n) :
    Lp ℂ 2 (complexGaussianMeasure n) →ₗᵢ[ℂ] Lp ℂ 2 (ginibreMeasure n) := by
  let h := ginibreMassEvaluation n hn
  exact
    { toFun := fun v ↦ (inverseVandermonde_memLp h v).toLp
          (inverseVandermondeFunction n v)
      map_add' := by
        intro u v
        apply Lp.ext
        filter_upwards [(inverseVandermonde_memLp h (u + v)).coeFn_toLp,
          (inverseVandermonde_memLp h u).coeFn_toLp,
          (inverseVandermonde_memLp h v).coeFn_toLp,
          (ginibreMeasure_absolutelyContinuous_complexGaussianMeasure n).ae_eq
            (Lp.coeFn_add u v),
          Lp.coeFn_add ((inverseVandermonde_memLp h u).toLp _)
            ((inverseVandermonde_memLp h v).toLp _)] with z huv hu hv hadd hout
        rw [huv, hout]
        simp only [Pi.add_apply] at hadd ⊢
        rw [hu, hv]
        change inverseVandermondeMultiplier n z * (u + v) z =
          inverseVandermondeMultiplier n z * u z +
            inverseVandermondeMultiplier n z * v z
        rw [hadd]
        exact mul_add _ _ _
      map_smul' := by
        intro c v
        apply Lp.ext
        filter_upwards [(inverseVandermonde_memLp h (c • v)).coeFn_toLp,
          (inverseVandermonde_memLp h v).coeFn_toLp,
          (ginibreMeasure_absolutelyContinuous_complexGaussianMeasure n).ae_eq
            (Lp.coeFn_smul c v),
          Lp.coeFn_smul c ((inverseVandermonde_memLp h v).toLp _)] with z hcv hv hin hout
        rw [hcv]
        simp only [RingHom.id_apply]
        rw [hout]
        simp only [Pi.smul_apply] at hin ⊢
        rw [hv]
        change inverseVandermondeMultiplier n z * (c • v) z =
          c * (inverseVandermondeMultiplier n z * v z)
        rw [hin]
        simp only [smul_eq_mul]
        ring
      norm_map' := inverseVandermonde_norm h }

private theorem inverseVandermondeL2_coeFn {n : ℕ} (hn : 0 < n)
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    inverseVandermondeL2 n hn v =ᵐ[ginibreMeasure n]
      inverseVandermondeFunction n v := by
  unfold inverseVandermondeL2
  dsimp only
  generalize_proofs h1 h2 h3 h4 h5
  exact (h5 v).coeFn_toLp

private theorem forwardVandermondeL2_coeFn {n : ℕ} (hn : 0 < n)
    (u : Lp ℂ 2 (ginibreMeasure n)) :
    normalizedVandermondeL2 n hn u =ᵐ[complexGaussianMeasure n]
      fun z ↦ normalizedVandermondeMultiplier n z * u z := by
  unfold normalizedVandermondeL2
  dsimp only
  generalize_proofs h1 h2 h3 h4 h5
  exact (h5 u).coeFn_toLp

theorem normalizedVandermondeL2_inverseVandermondeL2 {n : ℕ} (hn : 0 < n)
    (v : Lp ℂ 2 (complexGaussianMeasure n)) :
    normalizedVandermondeL2 n hn (inverseVandermondeL2 n hn v) = v := by
  apply Lp.ext
  have h := ginibreMassEvaluation n hn
  filter_upwards [forwardVandermondeL2_coeFn hn (inverseVandermondeL2 n hn v),
    (complexGaussianMeasure_absolutelyContinuous_ginibreMeasure h).ae_eq
      (inverseVandermondeL2_coeFn hn v), normalized_inverse_cancel_ae h v] with z hF hI hc
  rw [hF, hI]
  exact hc

theorem inverseVandermondeL2_normalizedVandermondeL2 {n : ℕ} (hn : 0 < n)
    (u : Lp ℂ 2 (ginibreMeasure n)) :
    inverseVandermondeL2 n hn (normalizedVandermondeL2 n hn u) = u := by
  apply (normalizedVandermondeL2 n hn).injective
  rw [normalizedVandermondeL2_inverseVandermondeL2]

/-- The inverse transform sends alternating Gaussian functions to symmetric
Ginibre functions. -/
theorem inverseVandermondeL2_mem_ginibreSymmetric {n : ℕ} (hn : 0 < n)
    (v : gaussianAlternatingL2 n) :
    inverseVandermondeL2 n hn v.1 ∈ ginibreSymmetricL2 n := by
  intro σ
  apply (normalizedVandermondeL2 n hn).injective
  rw [normalizedVandermondeL2_inverseVandermondeL2]
  have ht := normalizedVandermondeL2_intertwines hn σ
    (inverseVandermondeL2 n hn v.1)
  rw [normalizedVandermondeL2_inverseVandermondeL2] at ht
  have hv := v.2 σ
  rcases Int.units_eq_one_or (Equiv.Perm.sign σ) with hs | hs <;>
    simp [permutationSign, hs] at ht hv ⊢ <;> grind

/-- Unitary identification of symmetric Ginibre `L²` with alternating
Gaussian `L²`. -/
def vandermondeSymmetricAlternatingEquiv (n : ℕ) (hn : 0 < n) :
    ginibreSymmetricL2 n ≃ₗᵢ[ℂ] gaussianAlternatingL2 n where
  toFun := normalizedVandermondeSymmetricL2 n hn
  invFun v := ⟨inverseVandermondeL2 n hn v.1,
    inverseVandermondeL2_mem_ginibreSymmetric hn v⟩
  left_inv u := by
    apply Subtype.ext
    exact inverseVandermondeL2_normalizedVandermondeL2 hn u.1
  right_inv v := by
    apply Subtype.ext
    exact normalizedVandermondeL2_inverseVandermondeL2 hn v.1
  map_add' := map_add (normalizedVandermondeSymmetricL2 n hn)
  map_smul' := map_smul (normalizedVandermondeSymmetricL2 n hn)
  norm_map' := (normalizedVandermondeSymmetricL2 n hn).norm_map

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/VandermondeSymmetryL2.lean #
import GinibrePoincare.Analysis.PermutationLp

/-! # Vandermonde multiplication and permutation symmetry in `L²` -/

open MeasureTheory

namespace GinibrePoincare

noncomputable section

private theorem normalizedVandermondeL2_coeFn {n : ℕ} (hn : 0 < n)
    (u : Lp ℂ 2 (ginibreMeasure n)) :
    normalizedVandermondeL2 n hn u =ᵐ[complexGaussianMeasure n]
      fun z ↦ normalizedVandermondeMultiplier n z * u z := by
  unfold normalizedVandermondeL2
  dsimp only
  generalize_proofs h1 h2 h3 h4 h5
  exact (h5 u).coeFn_toLp

private theorem normalizedMultiplier_permute {n : ℕ}
    (σ : ParticlePermutation n) (z : Configuration n) :
    normalizedVandermondeMultiplier n (permute σ z) =
      permutationSign σ * normalizedVandermondeMultiplier n z := by
  unfold normalizedVandermondeMultiplier
  rw [vandermonde_permute]
  ring

/-- Normalized Vandermonde multiplication intertwines the permutation action
with its sign twist. -/
theorem normalizedVandermondeL2_intertwines {n : ℕ} (hn : 0 < n)
    (σ : ParticlePermutation n) (u : Lp ℂ 2 (ginibreMeasure n)) :
    gaussianPermutationL2 σ (normalizedVandermondeL2 n hn u) =
      permutationSign σ •
        normalizedVandermondeL2 n hn (ginibrePermutationL2 σ u) := by
  unfold gaussianPermutationL2 ginibrePermutationL2
  change Lp.compMeasurePreserving (permute σ)
      (gaussian_measurePreserving_permute σ) (normalizedVandermondeL2 n hn u) =
    permutationSign σ • normalizedVandermondeL2 n hn
      (Lp.compMeasurePreserving (permute σ)
        (ginibre_measurePreserving_permute σ) u)
  apply Lp.ext
  have hvalid := ginibreMassEvaluation n hn
  have hac := complexGaussianMeasure_absolutelyContinuous_ginibreMeasure hvalid
  filter_upwards [Lp.coeFn_compMeasurePreserving
      (normalizedVandermondeL2 n hn u)
      (gaussian_measurePreserving_permute σ),
    (gaussian_measurePreserving_permute σ).quasiMeasurePreserving.ae_eq_comp
      (normalizedVandermondeL2_coeFn hn u),
    normalizedVandermondeL2_coeFn hn
      (Lp.compMeasurePreserving (permute σ)
        (ginibre_measurePreserving_permute σ) u),
    hac.ae_eq (Lp.coeFn_compMeasurePreserving u
      (ginibre_measurePreserving_permute σ)),
    Lp.coeFn_smul (permutationSign σ)
      (normalizedVandermondeL2 n hn
        (Lp.compMeasurePreserving (permute σ)
          (ginibre_measurePreserving_permute σ) u))] with
      z hleft hFu hFperm huperm hsmul
  rw [hleft, hFu, hsmul]
  simp only [Pi.smul_apply]
  rw [hFperm, huperm]
  simp only [Function.comp_apply, smul_eq_mul]
  rw [normalizedMultiplier_permute]
  ring

/-- The normalized Vandermonde isometry sends AE-symmetric Ginibre functions
to AE-alternating Gaussian functions. -/
theorem normalizedVandermondeL2_mem_gaussianAlternating {n : ℕ} (hn : 0 < n)
    (u : ginibreSymmetricL2 n) :
    normalizedVandermondeL2 n hn u.1 ∈ gaussianAlternatingL2 n := by
  intro σ
  rw [normalizedVandermondeL2_intertwines hn σ u.1, u.2 σ]

/-- Restriction of the normalized Vandermonde isometry from the symmetric
Ginibre subspace to the alternating Gaussian subspace. -/
def normalizedVandermondeSymmetricL2 (n : ℕ) (hn : 0 < n) :
    ginibreSymmetricL2 n →ₗᵢ[ℂ] gaussianAlternatingL2 n where
  toFun u := ⟨normalizedVandermondeL2 n hn u.1,
    normalizedVandermondeL2_mem_gaussianAlternating hn u⟩
  map_add' u v := by
    apply Subtype.ext
    exact map_add (normalizedVandermondeL2 n hn) u.1 v.1
  map_smul' c u := by
    apply Subtype.ext
    exact map_smul (normalizedVandermondeL2 n hn) c u.1
  norm_map' u := (normalizedVandermondeL2 n hn).norm_map u.1

/-- Isometric equivalence of the symmetric Ginibre subspace with the range of
normalized Vandermonde multiplication inside the alternating Gaussian
subspace. -/
def normalizedVandermondeSymmetricL2EquivRange (n : ℕ) (hn : 0 < n) :=
  (normalizedVandermondeSymmetricL2 n hn).equivRange

/-- The ambient range of the restricted map is contained in the alternating
Gaussian subspace. -/
theorem normalizedVandermondeL2_range_symmetry_le {n : ℕ} (hn : 0 < n) :
    LinearMap.range
        ((normalizedVandermondeL2 n hn).toLinearMap.comp
          (ginibreSymmetricL2 n).subtype) ≤
      gaussianAlternatingL2 n := by
  rintro v ⟨u, rfl⟩
  exact normalizedVandermondeL2_mem_gaussianAlternating hn u

end

end GinibrePoincare
Analysis GinibrePoincare/Analysis/WeightedSeriesTruncation.lean #
import GinibrePoincare.Analysis.HermiteParsevalModes

/-! # Truncation of weighted real series -/

open Filter
open scoped BigOperators Topology

namespace GinibrePoincare

open MeasureTheory

theorem tendsto_weighted_partialSums {a : ℕ → ℝ}
    (ha : Summable (fun k : ℕ ↦ (k : ℝ) * a k)) :
    Tendsto (fun N ↦ ∑ k ∈ Finset.range N, (k : ℝ) * a k) atTop
      (𝓝 (∑' k : ℕ, (k : ℝ) * a k)) := by
  simpa only [Finset.sum_filter] using ha.hasSum.tendsto_sum_nat

theorem tendsto_weighted_tails_zero {a : ℕ → ℝ}
    (ha : Summable (fun k : ℕ ↦ (k : ℝ) * a k)) :
    Tendsto
      (fun N ↦ (∑' k : ℕ, (k : ℝ) * a k) -
        ∑ k ∈ Finset.range N, (k : ℝ) * a k)
      atTop (𝓝 0) := by
  convert tendsto_const_nhds.sub (tendsto_weighted_partialSums ha) using 1
  all_goals simp

theorem tendsto_summable_tails_zero {a : ℕ → ℝ} (ha : Summable a) :
    Tendsto (fun N ↦ (∑' k, a k) - ∑ k ∈ Finset.range N, a k)
      atTop (𝓝 0) := by
  convert tendsto_const_nhds.sub ha.hasSum.tendsto_sum_nat using 1
  all_goals simp

theorem tendsto_gaussianHermiteMode_partialSums {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    Tendsto (fun N ↦ ∑ d ∈ Finset.range N, gaussianHermiteMode hn d g)
      atTop (𝓝 g) := by
  simpa only [Finset.sum_filter] using
    (hasSum_gaussianHermiteMode hn g).tendsto_sum_nat

theorem tendsto_gaussianHermiteMode_weightedEnergy_tails_zero
    {n : ℕ} (hn : 0 < n) (g : Lp ℂ 2 (complexGaussianMeasure n))
    (hs : Summable (fun d : ℕ ↦
      (d : ℝ) * ‖gaussianHermiteMode hn d g‖ ^ 2)) :
    Tendsto
      (fun N ↦
        (∑' d : ℕ, (d : ℝ) * ‖gaussianHermiteMode hn d g‖ ^ 2) -
          ∑ d ∈ Finset.range N,
            (d : ℝ) * ‖gaussianHermiteMode hn d g‖ ^ 2)
      atTop (𝓝 0) :=
  tendsto_weighted_tails_zero hs

/-- Gaussian `L²` vectors with summable antiholomorphic-degree weighted
Hermite-mode mass. -/
def HermiteWeightedDomain {n : ℕ} (hn : 0 < n) :
    Set (Lp ℂ 2 (complexGaussianMeasure n)) :=
  {g | Summable (fun k : ℕ ↦ ((k + 1 : ℕ) : ℝ) *
    positiveHermiteModeMass hn g k)}

/-- Finite truncation of the Hermite antiholomorphic-degree decomposition. -/
noncomputable def gaussianHermiteModePartialSum {n : ℕ} (hn : 0 < n) (N : ℕ)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    Lp ℂ 2 (complexGaussianMeasure n) :=
  ∑ d ∈ Finset.range N, gaussianHermiteMode hn d g

@[simp] theorem gaussianHermiteMode_idempotent {n : ℕ} (hn : 0 < n)
    (d : ℕ) (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianHermiteMode hn d (gaussianHermiteMode hn d g) =
      gaussianHermiteMode hn d g := by
  rw [gaussianHermiteMode_eq_antiDegreeProjection]
  exact (Submodule.starProjection_eq_self_iff).2
    (gaussianHermiteMode_mem_closedSpan hn d g)

theorem gaussianHermiteMode_cross_eq_zero {n : ℕ} (hn : 0 < n)
    {d e : ℕ} (hde : d ≠ e)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianHermiteMode hn d (gaussianHermiteMode hn e g) = 0 := by
  let x := gaussianHermiteMode hn e g
  have he : gaussianHermiteMode hn e x = x :=
    gaussianHermiteMode_idempotent hn e g
  have horth := inner_gaussianHermiteMode_eq_zero hn hde x x
  rw [he] at horth
  have horth' : inner ℂ x (gaussianHermiteMode hn d x) = 0 := by
    rw [← inner_conj_symm, horth, map_zero]
  have hself := inner_gaussianHermiteMode_self_sum hn x d
  rw [horth'] at hself
  change gaussianHermiteMode hn d x = 0
  exact inner_self_eq_zero.mp hself.symm

theorem gaussianHermiteMode_partialSum_eq_zero_of_le {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) {N d : ℕ} (hNd : N ≤ d) :
    gaussianHermiteMode hn d (gaussianHermiteModePartialSum hn N g) = 0 := by
  rw [gaussianHermiteMode_eq_antiDegreeProjection]
  unfold gaussianHermiteModePartialSum
  rw [map_sum]
  apply Finset.sum_eq_zero
  intro e he
  rw [← gaussianHermiteMode_eq_antiDegreeProjection]
  exact gaussianHermiteMode_cross_eq_zero hn (by
    have hed := Finset.mem_range.mp he
    omega) g

theorem gaussianHermiteModePartialSum_mem_weightedDomain {n : ℕ}
    (hn : 0 < n) (N : ℕ) (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    gaussianHermiteModePartialSum hn N g ∈ HermiteWeightedDomain hn := by
  unfold HermiteWeightedDomain positiveHermiteModeMass
  apply summable_of_hasFiniteSupport
  apply (Finset.finite_toSet (Finset.range N)).subset
  intro k hk
  by_contra hkrange
  have hNk : N ≤ k := by simpa using hkrange
  have hz : ((k + 1 : ℕ) : ℝ) * ‖gaussianHermiteMode hn (k + 1)
      (gaussianHermiteModePartialSum hn N g)‖ ^ 2 = 0 := by
    rw [gaussianHermiteMode_partialSum_eq_zero_of_le hn g
      (hNk.trans (Nat.le_succ k))]
    simp
  exact hk hz

theorem tendsto_gaussianHermiteModePartialSum {n : ℕ} (hn : 0 < n)
    (g : Lp ℂ 2 (complexGaussianMeasure n)) :
    Tendsto (fun N ↦ gaussianHermiteModePartialSum hn N g) atTop (𝓝 g) :=
  tendsto_gaussianHermiteMode_partialSums hn g

theorem HermiteWeightedDomain.tendsto_weightedEnergy_tails_zero
    {n : ℕ} {hn : 0 < n} {g : Lp ℂ 2 (complexGaussianMeasure n)}
    (hg : g ∈ HermiteWeightedDomain hn) :
    Tendsto
      (fun N ↦
        (∑' k : ℕ, ((k + 1 : ℕ) : ℝ) * positiveHermiteModeMass hn g k) -
          ∑ k ∈ Finset.range N,
            ((k + 1 : ℕ) : ℝ) * positiveHermiteModeMass hn g k)
      atTop (𝓝 0) :=
  tendsto_summable_tails_zero hg

/-- Finite Hermite-mode truncations form an explicit form core: they
converge in Gaussian `L²`, and their omitted weighted energy tends to zero. -/
theorem HermiteWeightedDomain.finiteMode_formCore
    {n : ℕ} {hn : 0 < n} {g : Lp ℂ 2 (complexGaussianMeasure n)}
    (hg : g ∈ HermiteWeightedDomain hn) :
    Tendsto (fun N ↦ gaussianHermiteModePartialSum hn N g) atTop (𝓝 g) ∧
      Tendsto
        (fun N ↦
          (∑' k : ℕ, ((k + 1 : ℕ) : ℝ) * positiveHermiteModeMass hn g k) -
            ∑ k ∈ Finset.range N,
              ((k + 1 : ℕ) : ℝ) * positiveHermiteModeMass hn g k)
        atTop (𝓝 0) :=
  ⟨tendsto_gaussianHermiteModePartialSum hn g,
    HermiteWeightedDomain.tendsto_weightedEnergy_tails_zero hg⟩

end GinibrePoincare
Concrete GinibrePoincare/Concrete/AnalyticStatements.lean #
import GinibrePoincare.Concrete.HolomorphicDistance
import Mathlib.MeasureTheory.Measure.Typeclasses.Probability

/-!
# Exact analytic statements remaining in the main proof

Each proposition is written using the concrete measures, derivatives, and
normalized ground-state transform.  None is bundled into a certificate and
none is postulated by a declaration.
-/

namespace GinibrePoincare

noncomputable section

/-- The transformed centered observable belongs to the Gaussian `∂̄` domain. -/
def GroundStateAdmissibilityStatement : Prop :=
  ∀ n : ℕ, 0 < n →
    MeasureTheory.IsProbabilityMeasure (ginibreMeasure n) →
    ∀ f : Configuration n → ℝ,
      IsSmoothCompactSymmetric f →
      IsGaussianDbarAdmissible n
        (normalizedVandermondeTransform n
          (fun z => (centeredObservable n f z : ℂ)))

/-- The Dirichlet-form identity after normalized multiplication by `V_n`. -/
def GroundStateEnergyIdentityStatement : Prop :=
  ∀ n : ℕ, 0 < n →
    MeasureTheory.IsProbabilityMeasure (ginibreMeasure n) →
    ∀ f : Configuration n → ℝ,
      IsSmoothCompactSymmetric f →
      smoothGinibreEnergy n f =
        4 * gaussianDbarEnergy n
          (normalizedVandermondeTransform n
            (fun z => (centeredObservable n f z : ℂ)))


end

end GinibrePoincare
Concrete GinibrePoincare/Concrete/CenterOfMass.lean #
import GinibrePoincare.Concrete.Configuration
import Mathlib.Algebra.BigOperators.Group.Finset.Basic

/-!
# Centre of mass

The real and imaginary parts of the coordinate sum are the equality
directions in the optimal Ginibre Poincaré inequality.
-/

open scoped BigOperators

namespace GinibrePoincare

/-- Sum of the particle coordinates. -/
def coordinateSum {n : ℕ} (z : Configuration n) : ℂ :=
  ∑ i : Fin n, z i

/-- Real part of the coordinate sum. -/
def centerOfMassReal {n : ℕ} (z : Configuration n) : ℝ :=
  (coordinateSum z).re

/-- Imaginary part of the coordinate sum. -/
def centerOfMassImag {n : ℕ} (z : Configuration n) : ℝ :=
  (coordinateSum z).im

/-- The coordinate sum is permutation invariant. -/
theorem coordinateSum_permute {n : ℕ}
    (σ : ParticlePermutation n) (z : Configuration n) :
    coordinateSum (permute σ z) = coordinateSum z := by
  unfold coordinateSum
  simpa [permute] using (Equiv.sum_comp σ z)

/-- The real centre-of-mass statistic is symmetric. -/
theorem centerOfMassReal_isSymmetric {n : ℕ} :
    IsSymmetric (fun z : Configuration n => centerOfMassReal z) := by
  intro σ z
  simp [centerOfMassReal, coordinateSum_permute]

/-- The imaginary centre-of-mass statistic is symmetric. -/
theorem centerOfMassImag_isSymmetric {n : ℕ} :
    IsSymmetric (fun z : Configuration n => centerOfMassImag z) := by
  intro σ z
  simp [centerOfMassImag, coordinateSum_permute]

end GinibrePoincare
Concrete GinibrePoincare/Concrete/Configuration.lean #
import Mathlib.Analysis.Complex.Basic
import Mathlib.GroupTheory.Perm.Sign
import Mathlib.Data.Set.Basic

/-!
# Configuration space and particle permutations

The configuration space of `n` planar particles is `Fin n → ℂ`.  This file
defines particle relabelling, symmetric and alternating observables, and the
collision locus.  It contains no measure-theoretic or analytic input.
-/

namespace GinibrePoincare

/-- The configuration space of `n` labelled particles in the complex plane. -/
abbrev Configuration (n : ℕ) := Fin n → ℂ

/-- The symmetric group acting on `n` labelled particles. -/
abbrev ParticlePermutation (n : ℕ) := Equiv.Perm (Fin n)

/-- Relabelling of a configuration by a permutation. -/
def permute {n : ℕ} (σ : ParticlePermutation n) (z : Configuration n) :
    Configuration n :=
  fun i => z (σ i)

@[simp]
theorem permute_apply {n : ℕ} (σ : ParticlePermutation n)
    (z : Configuration n) (i : Fin n) :
    permute σ z i = z (σ i) :=
  rfl

@[simp]
theorem permute_refl {n : ℕ} (z : Configuration n) :
    permute (Equiv.refl (Fin n)) z = z := by
  rfl

/-- A scalar-valued observable invariant under every particle relabelling. -/
def IsSymmetric {n : ℕ} {α : Type*} (f : Configuration n → α) : Prop :=
  ∀ (σ : ParticlePermutation n) (z : Configuration n),
    f (permute σ z) = f z

/-- The complex scalar corresponding to the sign of a permutation. -/
def permutationSign {n : ℕ} (σ : ParticlePermutation n) : ℂ :=
  ((↑(Equiv.Perm.sign σ) : ℤ) : ℂ)

/-- A complex-valued observable transforming according to the sign character. -/
def IsAlternating {n : ℕ} (f : Configuration n → ℂ) : Prop :=
  ∀ (σ : ParticlePermutation n) (z : Configuration n),
    f (permute σ z) = permutationSign σ * f z

/-- The collision locus: at least two particle coordinates coincide. -/
def collisionSet (n : ℕ) : Set (Configuration n) :=
  {z | ∃ i j : Fin n, z i = z j ∧ i ≠ j}

/-- A collision-free configuration has pairwise distinct coordinates. -/
def CollisionFree {n : ℕ} (z : Configuration n) : Prop :=
  Function.Injective z

@[simp]
theorem mem_collisionSet_iff {n : ℕ} {z : Configuration n} :
    z ∈ collisionSet n ↔ ∃ i j : Fin n, z i = z j ∧ i ≠ j :=
  Iff.rfl

/-- Collision-freeness is exactly exclusion from the collision locus. -/
theorem collisionFree_iff_not_mem_collisionSet {n : ℕ}
    (z : Configuration n) :
    CollisionFree z ↔ z ∉ collisionSet n := by
  constructor
  · intro hz hmem
    rcases hmem with ⟨i, j, hij, hne⟩
    exact hne (hz hij)
  · intro hz i j hij
    by_contra hne
    exact hz ⟨i, j, hij, hne⟩

end GinibrePoincare
Concrete GinibrePoincare/Concrete/GaussianProbability.lean #
import GinibrePoincare.Concrete.Configuration
import Mathlib.Probability.Distributions.Gaussian.Real
import Mathlib.MeasureTheory.Measure.FiniteMeasurePi
import Mathlib.MeasureTheory.Measure.Lebesgue.Complex

/-!
# The normalized complex Gaussian probability measure

For `n` particles, each real coordinate has variance `1 / (2n)`.  We first
use Mathlib's normalized real Gaussian probability measure, take two
independent copies to obtain one complex coordinate, and then take the finite
product over the particle labels.

This construction proves the probability normalization without evaluating a
multidimensional integral.  Identification with the explicit density
`(n / π)^n exp (-n |z|²)` is deliberately kept as a separate theorem target in
`MeasureModel.lean`.
-/

open MeasureTheory

namespace GinibrePoincare

noncomputable section

/-- Variance of each real coordinate of the complex Gaussian reference law. -/
def realCoordinateVariance (n : ℕ) : NNReal :=
  ((2 : NNReal) * (n : NNReal))⁻¹

/-- Centered real Gaussian probability measure with variance `1 / (2n)`. -/
def realCoordinateGaussianProbability (n : ℕ) : ProbabilityMeasure ℝ :=
  ⟨ProbabilityTheory.gaussianReal 0 (realCoordinateVariance n), by
    infer_instance⟩

/-- One complex Gaussian coordinate, assembled from two independent real
coordinates of variance `1 / (2n)`. -/
def complexCoordinateGaussianProbability (n : ℕ) : ProbabilityMeasure ℂ :=
  (ProbabilityMeasure.pi
      (fun _ : Fin 2 => realCoordinateGaussianProbability n)).map
    Complex.measurableEquivPi.symm.measurable.aemeasurable

/-- Product complex Gaussian probability measure on `ℂⁿ`. -/
def complexGaussianProbability (n : ℕ) :
    ProbabilityMeasure (Configuration n) :=
  ProbabilityMeasure.pi
    (fun _ : Fin n => complexCoordinateGaussianProbability n)

/-- The Gaussian reference measure `γ_n`, viewed as an ordinary measure. -/
def complexGaussianMeasure (n : ℕ) : Measure (Configuration n) :=
  (complexGaussianProbability n : Measure (Configuration n))

instance instIsProbabilityMeasureComplexGaussianMeasure (n : ℕ) :
    IsProbabilityMeasure (complexGaussianMeasure n) := by
  unfold complexGaussianMeasure
  infer_instance

/-- The Gaussian reference measure has total mass one. -/
@[simp]
theorem complexGaussianMeasure_univ (n : ℕ) :
    complexGaussianMeasure n Set.univ = 1 := by
  simp

/-- Named version of the Gaussian probability-measure assertion used by the
concrete development. -/
def ComplexGaussianIsProbabilityStatement : Prop :=
  ∀ n : ℕ, 0 < n → complexGaussianMeasure n Set.univ = 1

/-- The concrete Gaussian probability-measure assertion is proved. -/
theorem complexGaussianIsProbability :
    ComplexGaussianIsProbabilityStatement := by
  intro n _
  exact complexGaussianMeasure_univ n

end

end GinibrePoincare
Concrete GinibrePoincare/Concrete/Generator.lean #
import GinibrePoincare.Concrete.SmoothTarget
import GinibrePoincare.Concrete.Wirtinger
import Mathlib.Analysis.Calculus.FDeriv.Add
import Mathlib.Analysis.Calculus.FDeriv.Mul

/-!
# The concrete Ginibre pregenerator

This is the speed `αₙ = n` realization used in Theorem 1.9 of the paper.
It is defined on representatives; its closed `L²` realization is a later
milestone.
-/

open scoped BigOperators ContDiff

namespace GinibrePoincare

noncomputable section

/-- The real symmetric test-function core used in Theorem 1.9: smooth,
compactly supported, and supported away from particle collisions. -/
def IsTheoremOneNineCore {n : ℕ} (f : Configuration n → ℝ) : Prop :=
  ContDiff ℝ ∞ f ∧ HasCompactSupport f ∧
    tsupport f ⊆ (collisionSet n)ᶜ ∧ IsSymmetric f

/-- The collision-free core refines the smooth compact symmetric core used by
the Poincaré reduction. -/
theorem IsTheoremOneNineCore.isSmoothCompactSymmetric {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f) :
    IsSmoothCompactSymmetric f :=
  ⟨hf.1, hf.2.1, hf.2.2.2⟩

/-- Every point in the support of a Theorem 1.9 core function is
collision-free. -/
theorem IsTheoremOneNineCore.support_collisionFree {n : ℕ}
    {f : Configuration n → ℝ} (hf : IsTheoremOneNineCore f)
    {z : Configuration n} (hz : z ∈ Function.support f) :
    CollisionFree z := by
  rw [collisionFree_iff_not_mem_collisionSet]
  exact hf.2.2.1 (subset_tsupport _ hz)

/-- Second real directional derivative, expressed using Fréchet derivatives. -/
def secondDirectionalDerivative {n : ℕ}
    (f : Configuration n → ℝ) (v : Configuration n)
    (z : Configuration n) : ℝ :=
  fderiv ℝ (fun x => fderiv ℝ f x v) z v

theorem secondDirectionalDerivative_sub_const {n : ℕ}
    (f : Configuration n → ℝ) (c : ℝ) (v : Configuration n)
    (z : Configuration n) :
    secondDirectionalDerivative (fun x => f x - c) v z =
      secondDirectionalDerivative f v z := by
  unfold secondDirectionalDerivative
  have hfun :
      (fun x => fderiv ℝ (fun y => f y - c) x v) =
        fun x => fderiv ℝ f x v := by
    funext x
    rw [fderiv_sub_const]
  rw [hfun]

theorem fderiv_apply_sub_const {n : ℕ}
    (f : Configuration n → ℝ) (c : ℝ) (z v : Configuration n) :
    fderiv ℝ (fun x => f x - c) z v = fderiv ℝ f z v := by
  rw [fderiv_sub_const]

/-- Euclidean Laplacian on `ℂⁿ ≃ ℝ²ⁿ`. -/
def configurationLaplacian {n : ℕ}
    (f : Configuration n → ℝ) (z : Configuration n) : ℝ :=
  ∑ j : Fin n,
    (secondDirectionalDerivative f (realCoordinateDirection j) z +
      secondDirectionalDerivative f (imaginaryCoordinateDirection j) z)

/-- Direction of the pairwise Coulomb drift for a pair of particles.  Its
value on the collision set is immaterial for compactly supported core
functions whose support avoids collisions. -/
def coulombPairDirection {n : ℕ} (j k : Fin n)
    (z : Configuration n) : Configuration n :=
  coordinateDirection j
      ((z j - z k) / Complex.normSq (z j - z k)) -
    coordinateDirection k
      ((z j - z k) / Complex.normSq (z j - z k))

/-- The Ginibre Langevin pregenerator at speed `αₙ = n` and inverse
temperature `βₙ = n²`.

The three terms are respectively `(1/n) Δ`, the quadratic confinement
drift, and the symmetrized Coulomb drift. -/
def ginibrePregenerator (n : ℕ)
    (f : Configuration n → ℝ) (z : Configuration n) : ℝ :=
  (1 / (n : ℝ)) * configurationLaplacian f z -
    2 * ∑ j : Fin n,
      fderiv ℝ f z (coordinateDirection j (z j)) +
    (2 / (n : ℝ)) * ∑ j : Fin n, ∑ k ∈ Finset.Ioi j,
      fderiv ℝ f z (coulombPairDirection j k z)

/-- The pregenerator kills constants. -/
@[simp] theorem ginibrePregenerator_const (n : ℕ) (c : ℝ) (z : Configuration n) :
    ginibrePregenerator n (fun _ => c) z = 0 := by
  simp [ginibrePregenerator, configurationLaplacian,
    secondDirectionalDerivative]

/-- Centering an observable does not change its pregenerator. -/
theorem ginibrePregenerator_sub_const (n : ℕ)
    (f : Configuration n → ℝ) (c : ℝ) (z : Configuration n) :
    ginibrePregenerator n (fun x => f x - c) z =
      ginibrePregenerator n f z := by
  simp [ginibrePregenerator, configurationLaplacian,
    secondDirectionalDerivative_sub_const, fderiv_apply_sub_const]

/-- Squared `L²(μₙ)` norm of the concrete pregenerator. -/
def ginibreGeneratorNormSq (n : ℕ)
    (f : Configuration n → ℝ) : ℝ :=
  ∫ z, (ginibrePregenerator n f z) ^ 2 ∂ginibreMeasure n

/-- Centering does not change the squared generator norm. -/
theorem ginibreGeneratorNormSq_sub_const (n : ℕ)
    (f : Configuration n → ℝ) (c : ℝ) :
    ginibreGeneratorNormSq n (fun z => f z - c) =
      ginibreGeneratorNormSq n f := by
  simp [ginibreGeneratorNormSq, ginibrePregenerator_sub_const]

/-- Squared norm of `(Aₙ + 2)f`. -/
def shiftedGinibreGeneratorNormSq (n : ℕ)
    (f : Configuration n → ℝ) : ℝ :=
  ∫ z, (ginibrePregenerator n f z + 2 * f z) ^ 2 ∂ginibreMeasure n

end

end GinibrePoincare
Concrete GinibrePoincare/Concrete/GroundState.lean #
import GinibrePoincare.Concrete.Weights
import Mathlib.Data.ENNReal.Real
import Mathlib.Tactic.Ring

/-!
# Vandermonde ground-state transform

The unnormalised transform is multiplication by the holomorphic Vandermonde.
A normalised transform is also defined from the actual mass of
`|V_n|² γ_n`; positivity and finiteness of that mass remain explicit analytic
obligations.
-/

namespace GinibrePoincare

noncomputable section

/-- Multiplication by the Vandermonde determinant. -/
def vandermondeTransform {n : ℕ} (f : Configuration n → ℂ) :
    Configuration n → ℂ :=
  fun z => vandermonde z * f z

/-- Symmetric observables become alternating after multiplication by `V_n`. -/
theorem vandermondeTransform_isAlternating {n : ℕ}
    (f : Configuration n → ℂ) (hf : IsSymmetric f) :
    IsAlternating (vandermondeTransform f) := by
  intro σ z
  unfold vandermondeTransform
  rw [vandermonde_permute σ z, hf σ z]
  ring

/-- Pointwise squared-modulus identity for the unnormalised transform. -/
theorem normSq_vandermondeTransform {n : ℕ}
    (f : Configuration n → ℂ) (z : Configuration n) :
    Complex.normSq (vandermondeTransform f z) =
      vandermondeWeight z * Complex.normSq (f z) := by
  simp [vandermondeTransform, vandermondeWeight, Complex.normSq_mul]

end

end GinibrePoincare
Concrete GinibrePoincare/Concrete/HolomorphicDistance.lean #
import GinibrePoincare.Concrete.NormalizedGroundState
import GinibrePoincare.Concrete.SmoothTarget
import GinibrePoincare.Concrete.Wirtinger

/-!
# Holomorphic distance on the Ginibre side

The main proof compares the Gaussian distance to alternating holomorphic
functions with the Ginibre distance to symmetric entire functions.  The
quantities are defined here directly on representatives.
-/

open MeasureTheory

namespace GinibrePoincare

noncomputable section

/-- Square-integrability of a complex function for the Ginibre measure. -/
def IsGinibreL2 (n : ℕ) (h : Configuration n → ℂ) : Prop :=
  Integrable (fun z => Complex.normSq (h z)) (ginibreMeasure n)

/-- Symmetric entire square-integrable functions on the Ginibre space. -/
def IsSymmetricEntireL2 {n : ℕ}
    (h : Configuration n → ℂ) : Prop :=
  IsSymmetric h ∧ IsEntire h ∧ IsGinibreL2 n h

/-- Squared Ginibre `L²` error from a real observable to a complex function. -/
def ginibreComplexError (n : ℕ) (f : Configuration n → ℝ)
    (h : Configuration n → ℂ) : ℝ :=
  ∫ z, Complex.normSq ((f z : ℂ) - h z) ∂ginibreMeasure n

/-- Errors of symmetric entire Ginibre approximants. -/
def ginibreHolomorphicErrors (n : ℕ)
    (f : Configuration n → ℝ) : Set ℝ :=
  {r | ∃ h : Configuration n → ℂ,
    IsSymmetricEntireL2 h ∧ r = ginibreComplexError n f h}

/-- Squared distance to the symmetric entire Ginibre subspace. -/
def ginibreHolomorphicDistanceSq (n : ℕ)
    (f : Configuration n → ℝ) : ℝ :=
  sInf (ginibreHolomorphicErrors n f)

/-- Centering of a real observable. -/
def centeredObservable (n : ℕ) (f : Configuration n → ℝ) :
    Configuration n → ℝ :=
  fun z => f z - smoothGinibreMean n f

/-- Distance identity required from the isometry and holomorphic divisibility. -/
def GroundStateDistanceIdentityStatement : Prop :=
  ∀ n : ℕ, 0 < n →
    IsProbabilityMeasure (ginibreMeasure n) →
    ∀ f : Configuration n → ℝ,
      IsSmoothCompactSymmetric f →
      gaussianHolomorphicDistanceSq n
          (normalizedVandermondeTransform n
            (fun z => (centeredObservable n f z : ℂ))) =
        ginibreHolomorphicDistanceSq n (centeredObservable n f)

/-- Half-distance estimate supplied by the real projection geometry. -/
def GinibreHalfDistanceStatement : Prop :=
  ∀ n : ℕ, 0 < n →
    IsProbabilityMeasure (ginibreMeasure n) →
    ∀ f : Configuration n → ℝ,
      IsSmoothCompactSymmetric f →
      smoothGinibreVariance n f / 2 ≤
        ginibreHolomorphicDistanceSq n (centeredObservable n f)

end

end GinibrePoincare
Concrete GinibrePoincare/Concrete/MainProofReduction.lean #
import GinibrePoincare.Concrete.AnalyticStatements
import Mathlib.Tactic.Linarith

/-!
# Checked endgame of the main proof

After normalizing the ground-state transform, the proof has the scalar shape

* `E = 4 D`;
* `δ_γ ≤ D`;
* `δ_γ = δ_μ`;
* `Var / 2 ≤ δ_μ`.

The first theorem verifies this scalar implication.  The second applies it to
the literal Ginibre quantities.  Its five hypotheses are displayed separately;
there is no bundled certificate argument.
-/

namespace GinibrePoincare

/-- Exact scalar implication used in the main proof. -/
theorem mainProof_scalar_endgame
    (variance energy dbarEnergy gaussianDistance ginibreDistance : ℝ)
    (hEnergy : energy = 4 * dbarEnergy)
    (hGaussian : gaussianDistance ≤ dbarEnergy)
    (hIsometry : gaussianDistance = ginibreDistance)
    (hHalf : variance / 2 ≤ ginibreDistance) :
    variance ≤ energy / 2 := by
  linarith

/-- The smooth-core theorem follows from the five concrete analytic statements. -/
theorem smoothGinibrePoincare_of_main_analytic_statements
    (hAdmissible : GroundStateAdmissibilityStatement)
    (hEnergy : GroundStateEnergyIdentityStatement)
    (hGaussian : GaussianDbarEstimateStatement)
    (hDistance : GroundStateDistanceIdentityStatement)
    (hHalf : GinibreHalfDistanceStatement) :
    SmoothGinibrePoincareStatement := by
  intro n hn hProbability f hf
  let g : Configuration n → ℂ :=
    normalizedVandermondeTransform n
      (fun z => (centeredObservable n f z : ℂ))
  have hgAdmissible : IsGaussianDbarAdmissible n g := by
    exact hAdmissible n hn hProbability f hf
  have hgEnergy :
      smoothGinibreEnergy n f = 4 * gaussianDbarEnergy n g := by
    exact hEnergy n hn hProbability f hf
  have hgGaussian :
      gaussianHolomorphicDistanceSq n g ≤ gaussianDbarEnergy n g := by
    exact hGaussian n hn g hgAdmissible
  have hgDistance :
      gaussianHolomorphicDistanceSq n g =
        ginibreHolomorphicDistanceSq n (centeredObservable n f) := by
    exact hDistance n hn hProbability f hf
  have hgHalf :
      smoothGinibreVariance n f / 2 ≤
        ginibreHolomorphicDistanceSq n (centeredObservable n f) := by
    exact hHalf n hn hProbability f hf
  exact mainProof_scalar_endgame
    (smoothGinibreVariance n f)
    (smoothGinibreEnergy n f)
    (gaussianDbarEnergy n g)
    (gaussianHolomorphicDistanceSq n g)
    (ginibreHolomorphicDistanceSq n (centeredObservable n f))
    hgEnergy hgGaussian hgDistance hgHalf

end GinibrePoincare
Concrete GinibrePoincare/Concrete/MeasureModel.lean #
import GinibrePoincare.Concrete.Weights
import GinibrePoincare.Concrete.GaussianProbability
import Mathlib.MeasureTheory.Measure.Lebesgue.Complex
import Mathlib.MeasureTheory.Measure.Haar.OfBasis
import Mathlib.MeasureTheory.Measure.WithDensity
import Mathlib.Data.ENNReal.Real

/-!
# Concrete Gaussian density and Ginibre measure

The Gaussian reference measure `complexGaussianMeasure n` is constructed in
`GaussianProbability.lean` as a genuine finite product probability measure.
This file also defines the explicit density measure

`(n / π)^n exp (-n |z|²) dz`.

Equality of these two descriptions is stated explicitly as
`ComplexGaussianDensityIdentificationStatement`; it is not hidden in a
definition.  The unnormalised Ginibre measure is then `|V_n|² γ_n`, and its
actual total mass is used for normalization.
-/

open MeasureTheory
open scoped ENNReal

namespace GinibrePoincare

noncomputable section

/-- Canonical Lebesgue/Haar volume on the finite-dimensional real space `ℂⁿ`. -/
def configurationVolume (n : ℕ) : Measure (Configuration n) :=
  volume

/-- Explicit density of the normalized complex Gaussian reference measure. -/
def complexGaussianDensity (n : ℕ) (z : Configuration n) : ℝ≥0∞ :=
  ENNReal.ofReal
    ((((n : ℝ) / Real.pi) ^ n) * gaussianWeight n z)

/-- Measure defined directly by the explicit Gaussian density. -/
def complexGaussianDensityMeasure (n : ℕ) : Measure (Configuration n) :=
  (configurationVolume n).withDensity (complexGaussianDensity n)

/-- Identification of the product Gaussian law with its explicit Lebesgue
 density.  This is the remaining Gaussian density theorem. -/
def ComplexGaussianDensityIdentificationStatement : Prop :=
  ∀ n : ℕ, 0 < n →
    complexGaussianMeasure n = complexGaussianDensityMeasure n

/-- Once the density identification is available, normalization of the
explicit density follows from the already proved probability normalization. -/
theorem complexGaussianDensityMeasure_univ_of_identification
    (h : ComplexGaussianDensityIdentificationStatement)
    (n : ℕ) (hn : 0 < n) :
    complexGaussianDensityMeasure n Set.univ = 1 := by
  rw [← h n hn]
  exact complexGaussianMeasure_univ n

/-- Vandermonde density as an extended nonnegative real. -/
def vandermondeDensity {n : ℕ} (z : Configuration n) : ℝ≥0∞ :=
  ENNReal.ofReal (vandermondeWeight z)

/-- The unnormalised measure `|V_n|² γ_n`. -/
def rawGinibreMeasure (n : ℕ) : Measure (Configuration n) :=
  (complexGaussianMeasure n).withDensity vandermondeDensity

/-- Actual total mass of the unnormalised Ginibre measure. -/
def ginibreNormalizingMass (n : ℕ) : ℝ≥0∞ :=
  rawGinibreMeasure n Set.univ

/-- The normalized Ginibre measure `μ_n`. -/
def ginibreMeasure (n : ℕ) : Measure (Configuration n) :=
  (ginibreNormalizingMass n)⁻¹ • rawGinibreMeasure n

/-- Positivity and finiteness of the actual normalizing mass. -/
def GinibreMassIsValid (n : ℕ) : Prop :=
  0 < ginibreNormalizingMass n ∧ ginibreNormalizingMass n < ⊤

/-- Exact Selberg/Gram determinant normalization statement for the Ginibre gas. -/
def GinibreMassEvaluationStatement : Prop :=
  ∀ n : ℕ, 0 < n → GinibreMassIsValid n

/-- Exact probability-measure statement for the normalized Ginibre law. -/
def GinibreMeasureIsProbabilityStatement : Prop :=
  ∀ n : ℕ, 0 < n →
    ginibreMeasure n Set.univ = 1

/-- Normalizing by a positive finite raw mass produces total mass one. -/
theorem ginibreMeasure_univ_of_mass_valid (n : ℕ)
    (h : GinibreMassIsValid n) :
    ginibreMeasure n Set.univ = 1 := by
  rcases h with ⟨hpos, htop⟩
  simp only [ginibreMeasure, Measure.smul_apply, ginibreNormalizingMass]
  exact ENNReal.inv_mul_cancel hpos.ne' htop.ne

/-- A positive finite raw mass equips the normalized Ginibre measure with the
usual probability-measure typeclass. -/
theorem ginibreMeasure_isProbabilityMeasure_of_mass_valid (n : ℕ)
    (h : GinibreMassIsValid n) :
    IsProbabilityMeasure (ginibreMeasure n) :=
  ⟨ginibreMeasure_univ_of_mass_valid n h⟩

/-- The mass-validity theorem implies the probability-measure theorem. -/
theorem ginibreMeasureIsProbability_of_mass_evaluation
    (h : GinibreMassEvaluationStatement) :
    GinibreMeasureIsProbabilityStatement := by
  intro n hn
  exact ginibreMeasure_univ_of_mass_valid n (h n hn)

/-- Mass evaluation supplies the probability typeclass at every positive
particle number. -/
theorem ginibreMeasure_isProbabilityMeasure_of_mass_evaluation
    (h : GinibreMassEvaluationStatement) (n : ℕ) (hn : 0 < n) :
    IsProbabilityMeasure (ginibreMeasure n) :=
  ginibreMeasure_isProbabilityMeasure_of_mass_valid n (h n hn)

end

end GinibrePoincare
Concrete GinibrePoincare/Concrete/ModeReduction.lean #
import GinibrePoincare.Concrete.SmoothTarget
import GinibrePoincare.Endgame.SeriesDeficit
import Mathlib.Tactic.Linarith

/-!
# Concrete mode-by-mode reduction

This file identifies precisely how an actual sequence of Gaussian mode
functions feeds the already checked infinite-series algebra.  It does not
postulate a Hermite basis: the mode functions and the three analytic identities
remain explicit hypotheses of the theorem.
-/

open MeasureTheory
open scoped BigOperators

namespace GinibrePoincare

noncomputable section

/-- Squared Gaussian `L²` mass of a complex function. -/
def gaussianModeMass (n : ℕ) (g : Configuration n → ℂ) : ℝ :=
  ∫ z, Complex.normSq (g z) ∂complexGaussianMeasure n

/-- Shifted sequence `a_k = ‖g_{k+1}‖²`. -/
def positiveModeMasses (n : ℕ)
    (modes : ℕ → Configuration n → ℂ) (k : ℕ) : ℝ :=
  gaussianModeMass n (modes (k + 1))

/-- Concrete deficit identity from actual mode functions and visible identities. -/
theorem smoothGinibre_deficit_of_mode_identities
    (n : ℕ)
    (f : Configuration n → ℝ)
    (modes : ℕ → Configuration n → ℂ)
    (holomorphicSq remainderSq : ℝ)
    (hSummable : Summable (positiveModeMasses n modes))
    (hTailSummable :
      Summable (fun k : ℕ =>
        (k : ℝ) * positiveModeMasses n modes k))
    (hParseval :
      smoothGinibreVariance n f =
        holomorphicSq + modeMass (positiveModeMasses n modes))
    (hGeometry :
      smoothGinibreVariance n f =
        2 * holomorphicSq + remainderSq)
    (hEnergy :
      smoothGinibreEnergy n f =
        4 * modeEnergy (positiveModeMasses n modes)) :
    smoothGinibreEnergy n f - 2 * smoothGinibreVariance n f =
      2 * remainderSq + 4 * modeTail (positiveModeMasses n modes) := by
  exact infinite_deficit_identity
    (positiveModeMasses n modes)
    hSummable hTailSummable
    (smoothGinibreVariance n f)
    holomorphicSq remainderSq
    (smoothGinibreEnergy n f)
    hParseval hGeometry hEnergy

/-- Poincaré follows when the concrete remainder and all mode masses are nonnegative. -/
theorem smoothGinibre_poincare_of_mode_identities
    (n : ℕ)
    (f : Configuration n → ℝ)
    (modes : ℕ → Configuration n → ℂ)
    (holomorphicSq remainderSq : ℝ)
    (hSummable : Summable (positiveModeMasses n modes))
    (hTailSummable :
      Summable (fun k : ℕ =>
        (k : ℝ) * positiveModeMasses n modes k))
    (hParseval :
      smoothGinibreVariance n f =
        holomorphicSq + modeMass (positiveModeMasses n modes))
    (hGeometry :
      smoothGinibreVariance n f =
        2 * holomorphicSq + remainderSq)
    (hEnergy :
      smoothGinibreEnergy n f =
        4 * modeEnergy (positiveModeMasses n modes))
    (hRemainder : 0 ≤ remainderSq) :
    smoothGinibreVariance n f ≤ smoothGinibreEnergy n f / 2 := by
  apply infinite_poincare_half
    (positiveModeMasses n modes)
    hSummable hTailSummable
    (smoothGinibreVariance n f)
    holomorphicSq remainderSq
    (smoothGinibreEnergy n f)
    hParseval hGeometry hEnergy hRemainder
  intro k
  unfold positiveModeMasses gaussianModeMass
  exact integral_nonneg fun z => Complex.normSq_nonneg _

end

end GinibrePoincare
Concrete GinibrePoincare/Concrete/NormalizedGroundState.lean #
import GinibrePoincare.Concrete.GroundState
import GinibrePoincare.Concrete.MeasureModel
import Mathlib.Analysis.SpecialFunctions.Pow.Real
import Mathlib.Tactic.Ring

/-!
# Normalized Vandermonde transform

The scale is the square root of the actual mass of `|V_n|² γ_n`.  The
definition therefore agrees with the ground-state transform once positivity
and finiteness of the mass have been proved.
-/

namespace GinibrePoincare

noncomputable section

/-- Real square-root normalization associated with the raw Ginibre mass. -/
def groundStateNormalization (n : ℕ) : ℝ :=
  Real.sqrt (ginibreNormalizingMass n).toReal

/-- Normalized multiplication by the Vandermonde. -/
def normalizedVandermondeTransform (n : ℕ)
    (f : Configuration n → ℂ) : Configuration n → ℂ :=
  fun z => ((groundStateNormalization n : ℂ)⁻¹) *
    vandermondeTransform f z

/-- Pointwise formula for the normalized transform. -/
theorem normalizedVandermondeTransform_apply (n : ℕ)
    (f : Configuration n → ℂ) (z : Configuration n) :
    normalizedVandermondeTransform n f z =
      ((groundStateNormalization n : ℂ)⁻¹) *
        vandermonde z * f z := by
  unfold normalizedVandermondeTransform vandermondeTransform
  ring

/-- The normalized transform sends symmetric functions to alternating ones. -/
theorem normalizedVandermondeTransform_isAlternating {n : ℕ}
    (f : Configuration n → ℂ) (hf : IsSymmetric f) :
    IsAlternating (normalizedVandermondeTransform n f) := by
  intro σ z
  unfold normalizedVandermondeTransform
  rw [vandermondeTransform_isAlternating f hf σ z]
  ring

end

end GinibrePoincare
Concrete GinibrePoincare/Concrete/SmoothTarget.lean #
import Mathlib.Analysis.Calculus.ContDiff.Defs
import GinibrePoincare.Concrete.CenterOfMass
import GinibrePoincare.Concrete.MeasureModel
import GinibrePoincare.Concrete.Wirtinger
import Mathlib.Analysis.Calculus.FDeriv.Basic
import Mathlib.MeasureTheory.Integral.Bochner.Basic
import Mathlib.MeasureTheory.Measure.Typeclasses.Probability
import Mathlib.Topology.Algebra.Support

/-!
# Exact smooth-core statement

This file gives the literal variance and gradient energy of the Ginibre
measure, together with the exact smooth-core Poincaré and sharpness
propositions.  These are definitions of the mathematical targets, not
asserted theorems.
-/

open MeasureTheory
open scoped ContDiff

namespace GinibrePoincare

noncomputable section

/-- Mean of a real observable under `μ_n`. -/
def smoothGinibreMean (n : ℕ) (f : Configuration n → ℝ) : ℝ :=
  ∫ z, f z ∂ginibreMeasure n

/-- Variance of a real observable under `μ_n`. -/
def smoothGinibreVariance (n : ℕ) (f : Configuration n → ℝ) : ℝ :=
  ∫ z, (f z - smoothGinibreMean n f) ^ 2 ∂ginibreMeasure n

/-- Euclidean pointwise squared norm of the real Fréchet derivative, expanded
in the real and imaginary coordinate directions.  This explicit formula is
necessary because the function-space norm on `Fin n → ℂ` is the sup norm,
whereas the Ginibre Dirichlet form uses the Euclidean product metric. -/
def realGradientNormSq {n : ℕ} (f : Configuration n → ℝ)
    (z : Configuration n) : ℝ :=
  ∑ k : Fin n, (
    (fderiv ℝ f z (realCoordinateDirection k)) ^ 2 +
      (fderiv ℝ f z (imaginaryCoordinateDirection k)) ^ 2)

/-- Dirichlet energy in the normalization of the paper. -/
def smoothGinibreEnergy (n : ℕ) (f : Configuration n → ℝ) : ℝ :=
  (1 / (n : ℝ)) *
    ∫ z, realGradientNormSq f z ∂ginibreMeasure n

/-- Smooth, compactly supported, coordinate-symmetric real observables. -/
def IsSmoothCompactSymmetric {n : ℕ}
    (f : Configuration n → ℝ) : Prop :=
  ContDiff ℝ ∞ f ∧ HasCompactSupport f ∧ IsSymmetric f

/-- The optimal smooth-core Poincaré theorem, written as one exact proposition. -/
def SmoothGinibrePoincareStatement : Prop :=
  ∀ n : ℕ, 0 < n →
    IsProbabilityMeasure (ginibreMeasure n) →
    ∀ f : Configuration n → ℝ,
      IsSmoothCompactSymmetric f →
      smoothGinibreVariance n f ≤ smoothGinibreEnergy n f / 2

/-- Equality statement for the real center-of-mass direction. -/
def RealCenterSharpnessStatement : Prop :=
  ∀ n : ℕ, 0 < n →
    IsProbabilityMeasure (ginibreMeasure n) →
    smoothGinibreVariance n
        (fun z : Configuration n => centerOfMassReal z) =
      smoothGinibreEnergy n
        (fun z : Configuration n => centerOfMassReal z) / 2

/-- Equality statement for the imaginary center-of-mass direction. -/
def ImagCenterSharpnessStatement : Prop :=
  ∀ n : ℕ, 0 < n →
    IsProbabilityMeasure (ginibreMeasure n) →
    smoothGinibreVariance n
        (fun z : Configuration n => centerOfMassImag z) =
      smoothGinibreEnergy n
        (fun z : Configuration n => centerOfMassImag z) / 2

end

end GinibrePoincare
Concrete GinibrePoincare/Concrete/Vandermonde.lean #
import GinibrePoincare.Concrete.Configuration
import Mathlib.LinearAlgebra.Vandermonde
import Mathlib.LinearAlgebra.Matrix.Determinant.Basic

/-!
# The complex Vandermonde polynomial

This file connects the Vandermonde determinant used in the Ginibre density to
Mathlib's Vandermonde matrix.  It proves the product formula, the precise
collision zero set, nonvanishing on collision-free configurations, and
alternation under particle permutations.
-/

namespace GinibrePoincare

/-- The Vandermonde determinant of a complex particle configuration. -/
def vandermonde {n : ℕ} (z : Configuration n) : ℂ :=
  (Matrix.vandermonde z).det

/-- Product formula for the Vandermonde determinant. -/
theorem vandermonde_eq_product {n : ℕ} (z : Configuration n) :
    vandermonde z = ∏ i : Fin n, ∏ j > i, (z j - z i) := by
  exact Matrix.det_vandermonde z

/-- The Vandermonde vanishes exactly on the collision locus. -/
theorem vandermonde_eq_zero_iff {n : ℕ} (z : Configuration n) :
    vandermonde z = 0 ↔ z ∈ collisionSet n := by
  simpa only [vandermonde, mem_collisionSet_iff] using
    (Matrix.det_vandermonde_eq_zero_iff (v := z))

/-- The Vandermonde is nonzero exactly at collision-free configurations. -/
theorem vandermonde_ne_zero_iff {n : ℕ} (z : Configuration n) :
    vandermonde z ≠ 0 ↔ CollisionFree z := by
  simpa only [vandermonde, CollisionFree] using
    (Matrix.det_vandermonde_ne_zero_iff (v := z))

/-- Relabelling the particles multiplies the Vandermonde by the permutation sign. -/
theorem vandermonde_permute {n : ℕ} (σ : ParticlePermutation n)
    (z : Configuration n) :
    vandermonde (permute σ z) =
      permutationSign σ * vandermonde z := by
  have hmatrix :
      Matrix.vandermonde (permute σ z) =
        (Matrix.vandermonde z).submatrix σ id := by
    ext i j
    simp [permute]
  unfold vandermonde
  rw [hmatrix]
  simpa [permutationSign] using
    (Matrix.det_permute σ (Matrix.vandermonde z))

/-- The Vandermonde observable is alternating. -/
theorem vandermonde_isAlternating {n : ℕ} :
    IsAlternating (fun z : Configuration n => vandermonde z) := by
  intro σ z
  exact vandermonde_permute σ z

end GinibrePoincare
Concrete GinibrePoincare/Concrete/Weights.lean #
import GinibrePoincare.Concrete.Vandermonde
import Mathlib.Analysis.SpecialFunctions.Exp
import Mathlib.Algebra.BigOperators.Group.Finset.Basic
import Mathlib.Data.NNReal.Defs
import Mathlib.Tactic.Positivity

/-!
# Gaussian and Ginibre weights

This file defines the Euclidean square norm, the Gaussian weight, the
Vandermonde square, and the unnormalised Ginibre density.  The zero set of the
latter is proved to be exactly the collision locus.
-/

open scoped BigOperators NNReal

namespace GinibrePoincare

noncomputable section

/-- Euclidean squared norm on `ℂ^n`. -/
def configurationNormSq {n : ℕ} (z : Configuration n) : ℝ :=
  ∑ i : Fin n, Complex.normSq (z i)

/-- The Gaussian factor `exp (-n |z|²)`. -/
def gaussianWeight (n : ℕ) (z : Configuration n) : ℝ :=
  Real.exp (-(n : ℝ) * configurationNormSq z)

/-- The nonnegative squared modulus of the Vandermonde determinant. -/
def vandermondeWeight {n : ℕ} (z : Configuration n) : ℝ :=
  Complex.normSq (vandermonde z)

/-- The unnormalised Ginibre density with respect to Lebesgue measure. -/
def ginibreWeight (n : ℕ) (z : Configuration n) : ℝ :=
  gaussianWeight n z * vandermondeWeight z

/-- The Euclidean squared norm is nonnegative. -/
theorem configurationNormSq_nonneg {n : ℕ} (z : Configuration n) :
    0 ≤ configurationNormSq z := by
  unfold configurationNormSq
  exact Finset.sum_nonneg fun i _ => Complex.normSq_nonneg (z i)

/-- The Gaussian factor is strictly positive. -/
theorem gaussianWeight_pos (n : ℕ) (z : Configuration n) :
    0 < gaussianWeight n z := by
  unfold gaussianWeight
  exact Real.exp_pos _

/-- The Gaussian factor is nonnegative. -/
theorem gaussianWeight_nonneg (n : ℕ) (z : Configuration n) :
    0 ≤ gaussianWeight n z :=
  le_of_lt (gaussianWeight_pos n z)

/-- The Vandermonde squared modulus is nonnegative. -/
theorem vandermondeWeight_nonneg {n : ℕ} (z : Configuration n) :
    0 ≤ vandermondeWeight z := by
  exact Complex.normSq_nonneg _

/-- The Ginibre density is nonnegative. -/
theorem ginibreWeight_nonneg (n : ℕ) (z : Configuration n) :
    0 ≤ ginibreWeight n z := by
  exact mul_nonneg (gaussianWeight_nonneg n z)
    (vandermondeWeight_nonneg z)

/-- The Gaussian weight as a nonnegative real number. -/
def gaussianWeightNN (n : ℕ) (z : Configuration n) : ℝ≥0 :=
  ⟨gaussianWeight n z, gaussianWeight_nonneg n z⟩

/-- The Vandermonde square as a nonnegative real number. -/
def vandermondeWeightNN {n : ℕ} (z : Configuration n) : ℝ≥0 :=
  ⟨vandermondeWeight z, vandermondeWeight_nonneg z⟩

/-- The Ginibre weight as a nonnegative real number. -/
def ginibreWeightNN (n : ℕ) (z : Configuration n) : ℝ≥0 :=
  ⟨ginibreWeight n z, ginibreWeight_nonneg n z⟩

@[simp]
theorem coe_gaussianWeightNN (n : ℕ) (z : Configuration n) :
    (gaussianWeightNN n z : ℝ) = gaussianWeight n z :=
  rfl

@[simp]
theorem coe_vandermondeWeightNN {n : ℕ} (z : Configuration n) :
    (vandermondeWeightNN z : ℝ) = vandermondeWeight z :=
  rfl

@[simp]
theorem coe_ginibreWeightNN (n : ℕ) (z : Configuration n) :
    (ginibreWeightNN n z : ℝ) = ginibreWeight n z :=
  rfl

/-- The Vandermonde square vanishes precisely at collisions. -/
theorem vandermondeWeight_eq_zero_iff {n : ℕ} (z : Configuration n) :
    vandermondeWeight z = 0 ↔ z ∈ collisionSet n := by
  rw [vandermondeWeight, Complex.normSq_eq_zero]
  exact vandermonde_eq_zero_iff z

/-- The Ginibre density vanishes precisely at collisions. -/
theorem ginibreWeight_eq_zero_iff (n : ℕ) (z : Configuration n) :
    ginibreWeight n z = 0 ↔ z ∈ collisionSet n := by
  unfold ginibreWeight
  rw [mul_eq_zero]
  constructor
  · intro h
    rcases h with hgauss | hvdm
    · exact False.elim ((ne_of_gt (gaussianWeight_pos n z)) hgauss)
    · exact (vandermondeWeight_eq_zero_iff z).mp hvdm
  · intro h
    exact Or.inr ((vandermondeWeight_eq_zero_iff z).mpr h)

/-- The Euclidean square norm is invariant under particle relabelling. -/
theorem configurationNormSq_permute {n : ℕ}
    (σ : ParticlePermutation n) (z : Configuration n) :
    configurationNormSq (permute σ z) = configurationNormSq z := by
  unfold configurationNormSq
  simpa [permute] using (Equiv.sum_comp σ (fun i => Complex.normSq (z i)))

/-- The Gaussian factor is invariant under particle relabelling. -/
theorem gaussianWeight_permute {n : ℕ}
    (σ : ParticlePermutation n) (z : Configuration n) :
    gaussianWeight n (permute σ z) = gaussianWeight n z := by
  simp [gaussianWeight, configurationNormSq_permute]

end

end GinibrePoincare
Concrete GinibrePoincare/Concrete/Wirtinger.lean #
import Mathlib.Analysis.Calculus.ContDiff.Defs
import GinibrePoincare.Concrete.MeasureModel
import Mathlib.Analysis.Calculus.FDeriv.Basic
import Mathlib.MeasureTheory.Integral.Bochner.Basic
import Mathlib.Order.ConditionallyCompleteLattice.Basic

/-!
# Concrete Wirtinger derivatives and Gaussian holomorphic distance

The coordinate operators
`∂̄_k = (∂_{x_k} + i ∂_{y_k}) / 2` are defined directly from the real
Fréchet derivative on `Configuration n`.
-/

open MeasureTheory
open scoped BigOperators ContDiff

namespace GinibrePoincare

noncomputable section

/-- A vector supported in one complex coordinate. -/
def coordinateDirection {n : ℕ} (k : Fin n) (w : ℂ) :
    Configuration n :=
  fun j => if j = k then w else 0

/-- Unit direction in the real part of coordinate `k`. -/
def realCoordinateDirection {n : ℕ} (k : Fin n) :
    Configuration n :=
  coordinateDirection k 1

/-- Unit direction in the imaginary part of coordinate `k`. -/
def imaginaryCoordinateDirection {n : ℕ} (k : Fin n) :
    Configuration n :=
  coordinateDirection k Complex.I

/-- Coordinate `∂̄` derivative defined from the real Fréchet derivative. -/
def dbarComponent {n : ℕ} (g : Configuration n → ℂ)
    (k : Fin n) (z : Configuration n) : ℂ :=
  (1 / 2 : ℂ) *
    (fderiv ℝ g z (realCoordinateDirection k) +
      Complex.I * fderiv ℝ g z (imaginaryCoordinateDirection k))

/-- Sum of the squared coordinate `∂̄` derivatives at a point. -/
def dbarNormSq {n : ℕ} (g : Configuration n → ℂ)
    (z : Configuration n) : ℝ :=
  ∑ k : Fin n, Complex.normSq (dbarComponent g k z)

/-- Normalized Gaussian `∂̄` energy. -/
def gaussianDbarEnergy (n : ℕ) (g : Configuration n → ℂ) : ℝ :=
  (1 / (n : ℝ)) *
    ∫ z, dbarNormSq g z ∂complexGaussianMeasure n

/-- Entire functions on the finite-dimensional complex configuration space. -/
def IsEntire {n : ℕ} (h : Configuration n → ℂ) : Prop :=
  Differentiable ℂ h

/-- Square-integrability of a complex function for the Gaussian measure. -/
def IsGaussianL2 (n : ℕ) (g : Configuration n → ℂ) : Prop :=
  Integrable (fun z => Complex.normSq (g z))
    (complexGaussianMeasure n)

/-- Form-domain conditions used by the representative-level `∂̄` estimate. -/
def IsGaussianDbarAdmissible (n : ℕ)
    (g : Configuration n → ℂ) : Prop :=
  ContDiff ℝ ∞ g ∧ IsGaussianL2 n g ∧
    ∀ k : Fin n,
      Integrable (fun z => Complex.normSq (dbarComponent g k z))
        (complexGaussianMeasure n)

/-- Squared Gaussian `L²` error between two complex functions. -/
def gaussianComplexError (n : ℕ) (g h : Configuration n → ℂ) : ℝ :=
  ∫ z, Complex.normSq (g z - h z) ∂complexGaussianMeasure n

/-- Set of errors of entire square-integrable Gaussian approximants. -/
def gaussianHolomorphicErrors (n : ℕ)
    (g : Configuration n → ℂ) : Set ℝ :=
  {r | ∃ h : Configuration n → ℂ,
    IsEntire h ∧ IsGaussianL2 n h ∧
      r = gaussianComplexError n g h}

/-- Squared distance to the Gaussian holomorphic subspace, on representatives. -/
def gaussianHolomorphicDistanceSq (n : ℕ)
    (g : Configuration n → ℂ) : ℝ :=
  sInf (gaussianHolomorphicErrors n g)

/-- Exact target for the Gaussian `∂̄` estimate. -/
def GaussianDbarEstimateStatement : Prop :=
  ∀ n : ℕ, 0 < n →
    ∀ g : Configuration n → ℂ,
      IsGaussianDbarAdmissible n g →
      gaussianHolomorphicDistanceSq n g ≤ gaussianDbarEnergy n g

end

end GinibrePoincare
Endgame GinibrePoincare/Endgame/ConcreteTheoremOneNine.lean #
import GinibrePoincare.Analysis.GinibreGeneratorL2
import GinibrePoincare.Analysis.GinibreConjugationGeometry
import GinibrePoincare.Analysis.HermiteWeightedEnergy
import GinibrePoincare.Analysis.WeightedSeriesTruncation
import GinibrePoincare.Analysis.VandermondeGroundStateZeroMode
import GinibrePoincare.Endgame.SeriesDeficit
import GinibrePoincare.Endgame.FiniteTheoremOneNine

/-! # Concrete assembly of the two identities in Theorem 1.9 -/

namespace GinibrePoincare

noncomputable section
open scoped Topology
open MeasureTheory
open ComplexHermite
open Filter

local instance concrete_completeSpace_gaussianAlternatingL2 (n : ℕ) :
    CompleteSpace (gaussianAlternatingL2 n) :=
  (isClosed_gaussianAlternatingL2 n).completeSpace_coe

local instance concrete_completeSpace_ginibreSymmetricL2 (n : ℕ) :
    CompleteSpace (ginibreSymmetricL2 n) :=
  (isClosed_ginibreSymmetricL2 n).completeSpace_coe

/-- Positive antiholomorphic masses of the transformed centered observable,
indexed so that entry `k` is the mode of degree `k + 1`. -/
def concretePositiveHermiteModeMass {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) : ℕ → ℝ :=
  positiveHermiteModeMass hn (transformedCenteredObservableL2 hn f hf)

def uncenteredGroundStateTransform {n : ℕ} (f : Configuration n → ℝ) :
    Configuration n → ℂ :=
  normalizedVandermondeTransform n (fun z => (f z : ℂ))

def uncenteredGroundStateL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    Lp ℂ 2 (complexGaussianMeasure n) := by
  have hF : ContDiff ℝ 1 (uncenteredGroundStateTransform f) :=
    (contDiff_normalizedVandermonde_ofReal hf.1).of_le (by simp)
  exact smoothCompactL2 (uncenteredGroundStateTransform f) hF
    (hasCompactSupport_normalizedVandermonde_ofReal hf.2.1)

theorem uncenteredGroundStateL2_coeFn {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    uncenteredGroundStateL2 hn f hf =ᵐ[complexGaussianMeasure n]
      uncenteredGroundStateTransform f := by
  unfold uncenteredGroundStateL2 smoothCompactL2
  exact MemLp.coeFn_toLp _

theorem uncenteredGroundStateL2_eq_centered_add_groundState
    {n : ℕ} (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) :
    uncenteredGroundStateL2 hn f hf =
      transformedCenteredObservableL2 hn f hf +
        (smoothGinibreMean n f : ℂ) • normalizedVandermondeGroundStateL2 n hn := by
  apply Lp.ext
  filter_upwards [uncenteredGroundStateL2_coeFn hn f hf,
    transformedCenteredObservableL2_coeFn hn f hf,
    normalizedVandermondeGroundStateL2_coeFn n hn,
    Lp.coeFn_add (transformedCenteredObservableL2 hn f hf)
      ((smoothGinibreMean n f : ℂ) • normalizedVandermondeGroundStateL2 n hn),
    Lp.coeFn_smul (smoothGinibreMean n f : ℂ)
      (normalizedVandermondeGroundStateL2 n hn)] with z hunc hcent hground hadd hsmul
  rw [hunc, hadd, Pi.add_apply, hsmul, hcent, Pi.smul_apply, hground]
  unfold uncenteredGroundStateTransform centeredObservable
  rw [normalizedVandermondeTransform_apply,
    normalizedVandermondeTransform_apply]
  unfold normalizedVandermondeMultiplier
  simp only [Pi.add_apply, Pi.smul_apply, smul_eq_mul]
  push_cast
  ring

theorem positiveHermiteMode_uncentered_eq_centered {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) (k : ℕ) :
    gaussianHermiteMode hn (k + 1) (uncenteredGroundStateL2 hn f hf) =
      gaussianHermiteMode hn (k + 1)
        (transformedCenteredObservableL2 hn f hf) := by
  let v := normalizedVandermondeGroundStateL2 n hn
  have hv0 : gaussianHermiteMode hn 0 v = v := by
    rw [gaussianHermiteMode_eq_antiDegreeProjection]
    exact Submodule.starProjection_eq_self_iff.mpr
      (normalizedVandermondeGroundStateL2_mem_hermiteAntiDegreeClosedSpan n hn)
  have hvpos : gaussianHermiteMode hn (k + 1) v = 0 := by
    rw [← hv0]
    exact gaussianHermiteMode_cross_eq_zero hn (by omega) v
  rw [uncenteredGroundStateL2_eq_centered_add_groundState hn f hf,
    gaussianHermiteMode_eq_antiDegreeProjection, map_add, map_smul,
    ← gaussianHermiteMode_eq_antiDegreeProjection,
    ← gaussianHermiteMode_eq_antiDegreeProjection, hvpos, smul_zero, add_zero]

theorem positiveHermiteModeMass_uncentered_eq_concrete {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) (k : ℕ) :
    positiveHermiteModeMass hn (uncenteredGroundStateL2 hn f hf) k =
      concretePositiveHermiteModeMass hn f hf k := by
  unfold positiveHermiteModeMass concretePositiveHermiteModeMass
  change ‖gaussianHermiteMode hn (k + 1) (uncenteredGroundStateL2 hn f hf)‖ ^ 2 =
    ‖gaussianHermiteMode hn (k + 1) (transformedCenteredObservableL2 hn f hf)‖ ^ 2
  rw [positiveHermiteMode_uncentered_eq_centered hn f hf k]

theorem uncenteredGroundState_weightedModeEnergy {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    HasSum (fun k : ℕ => (k + 1) * positiveHermiteModeMass hn
      (uncenteredGroundStateL2 hn f hf) k)
      (smoothGinibreEnergy n f / 4) := by
  have hF : ContDiff ℝ 1 (uncenteredGroundStateTransform f) :=
    (contDiff_normalizedVandermonde_ofReal hf.1).of_le (by simp)
  let hFc : HasCompactSupport (uncenteredGroundStateTransform f) :=
    hasCompactSupport_normalizedVandermonde_ofReal hf.2.1
  have hs := hasSum_weighted_positiveHermiteModeMass_smoothCompact hn
    (uncenteredGroundStateTransform f) hF hFc
  change HasSum _ (gaussianDbarEnergy n (uncenteredGroundStateTransform f)) at hs
  have hcenter := gaussianDbarEnergy_normalizedVandermonde_centered_eq_uncentered
    (hf.1.differentiable (by simp))
  have hground := groundStateEnergyIdentity n hn
    (ginibreMeasure_isProbabilityMeasure hn) f hf.isSmoothCompactSymmetric
  change smoothGinibreEnergy n f = 4 * gaussianDbarEnergy n
    (normalizedVandermondeTransform n
      (fun z => (centeredObservable n f z : ℂ))) at hground
  convert hs using 1
  · simp only [uncenteredGroundStateL2]
  · change smoothGinibreEnergy n f / 4 = gaussianDbarEnergy n
      (normalizedVandermondeTransform n (fun z => (f z : ℂ)))
    rw [← hcenter, hground]
    ring

theorem concrete_weightedModeEnergy {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    HasSum (fun k : ℕ => ((k + 1 : ℕ) : ℝ) *
      concretePositiveHermiteModeMass hn f hf k)
      (smoothGinibreEnergy n f / 4) := by
  apply (uncenteredGroundState_weightedModeEnergy hn f hf).congr_fun
  intro k
  rw [positiveHermiteModeMass_uncentered_eq_concrete hn f hf k]
  push_cast
  rfl

theorem transformedCenteredObservable_mem_hermiteWeightedDomain
    {n : ℕ} (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) :
    transformedCenteredObservableL2 hn f hf ∈ HermiteWeightedDomain hn := by
  change Summable (fun k : ℕ => ((k + 1 : ℕ) : ℝ) *
    positiveHermiteModeMass hn (transformedCenteredObservableL2 hn f hf) k)
  exact (concrete_weightedModeEnergy hn f hf).summable

/-- Concrete form-domain approximation by finite antiholomorphic Hermite
modes, including both `L²` convergence and convergence of the weighted
energy tails. -/
theorem transformedCenteredObservable_finiteMode_formCore
    {n : ℕ} (hn : 0 < n) (f : Configuration n → ℝ)
    (hf : IsTheoremOneNineCore f) :
    Tendsto (fun N ↦ gaussianHermiteModePartialSum hn N
        (transformedCenteredObservableL2 hn f hf)) atTop
        (𝓝 (transformedCenteredObservableL2 hn f hf)) ∧
      Tendsto
        (fun N ↦
          (∑' k : ℕ, ((k + 1 : ℕ) : ℝ) *
              concretePositiveHermiteModeMass hn f hf k) -
            ∑ k ∈ Finset.range N, ((k + 1 : ℕ) : ℝ) *
              concretePositiveHermiteModeMass hn f hf k)
        atTop (𝓝 0) := by
  exact HermiteWeightedDomain.finiteMode_formCore
    (transformedCenteredObservable_mem_hermiteWeightedDomain hn f hf)

def centeredObservableSymmetricL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    ginibreSymmetricL2 n := by
  refine ⟨centeredObservableL2 hn f hf, ?_⟩
  intro σ
  apply Lp.ext
  have hc := centeredObservableL2_coeFn hn f hf
  filter_upwards [Lp.coeFn_compMeasurePreserving (centeredObservableL2 hn f hf)
      (ginibre_measurePreserving_permute σ),
    (ginibre_measurePreserving_permute σ).quasiMeasurePreserving.ae_eq_comp hc,
    hc] with z hperm hcomp hz
  change (Lp.compMeasurePreserving (permute σ)
    (ginibre_measurePreserving_permute σ) (centeredObservableL2 hn f hf)) z = _
  rw [hperm, hcomp, hz]
  simp only [Function.comp_apply, Complex.ofReal_inj]
  unfold centeredObservable
  rw [hf.2.2.2 σ z]

theorem coe_starProjection_centeredObservableSymmetricL2 {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    (ComplexHermite.ginibreSymmetricHolomorphicProjection n hn
      (centeredObservableSymmetricL2 hn f hf)).1 =
      (ginibreHolomorphicAmbientClosedSpan n hn).starProjection
        (centeredObservableL2 hn f hf) := by
  let u := centeredObservableSymmetricL2 hn f hf
  symm
  apply Submodule.eq_starProjection_of_mem_of_inner_eq_zero
  · exact ⟨ComplexHermite.ginibreSymmetricHolomorphicProjection n hn u,
      Submodule.starProjection_apply_mem
        (ComplexHermite.ginibreSymmetricHolomorphicPolynomialClosedSpan n hn).toSubmodule u,
      rfl⟩
  · intro w hw
    rcases hw with ⟨v, hv, rfl⟩
    change inner ℂ (u.1 - (ComplexHermite.ginibreSymmetricHolomorphicProjection n hn u).1) v.1 = 0
    exact Submodule.starProjection_inner_eq_zero u v hv

theorem coe_gaussianAlternatingZeroModeProjection {n : ℕ} (hn : 0 < n)
    (v : gaussianAlternatingL2 n) :
    (ComplexHermite.gaussianAlternatingZeroModeProjection n hn v).1 =
      ComplexHermite.hermiteAntiDegreeProjection n hn 0 v.1 := by
  let p : gaussianAlternatingL2 n :=
    ⟨ComplexHermite.hermiteAntiDegreeProjection n hn 0 v.1, by
      intro σ
      rw [gaussianPermutationL2_comm_antiDegreeProjection hn,
        v.2 σ, map_smul]⟩
  have hp : p ∈ ComplexHermite.gaussianAlternatingZeroModeClosedSpan n hn := by
    change p ∈ (ComplexHermite.gaussianAlternatingZeroModeClosedSpan n hn).toSubmodule
    rw [ComplexHermite.gaussianAlternatingZeroModeClosedSpan_eq_hermiteZeroMode_comap]
    exact Submodule.starProjection_apply_mem
      (ComplexHermite.hermiteAntiDegreeClosedSpan n hn 0).toSubmodule v.1
  have hort : ∀ w ∈ ComplexHermite.gaussianAlternatingZeroModeClosedSpan n hn,
      inner ℂ (v - p) w = 0 := by
    intro w hw
    change inner ℂ (v.1 - ComplexHermite.hermiteAntiDegreeProjection n hn 0 v.1) w.1 = 0
    apply Submodule.starProjection_inner_eq_zero
    have heq := ComplexHermite.gaussianAlternatingZeroModeClosedSpan_eq_hermiteZeroMode_comap n hn
    have hw' : w ∈ (ComplexHermite.gaussianAlternatingZeroModeClosedSpan n hn).toSubmodule := hw
    rw [heq] at hw'
    exact hw'
  change (ComplexHermite.gaussianAlternatingZeroModeProjection n hn v).1 = p.1
  apply congrArg Subtype.val
  unfold ComplexHermite.gaussianAlternatingZeroModeProjection
  apply Submodule.eq_starProjection_of_mem_of_inner_eq_zero
  · rw [ComplexHermite.map_ginibreSymmetricHolomorphicPolynomialClosedSpan]
    exact hp
  · intro w hw
    apply hort w
    have hmap := ComplexHermite.map_ginibreSymmetricHolomorphicPolynomialClosedSpan n hn
    have hw' := hw
    rw [hmap] at hw'
    exact hw'

theorem concreteZeroMode_norm_sq_eq_holomorphicProjection {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    ‖gaussianHermiteMode hn 0 (transformedCenteredObservableL2 hn f hf)‖ ^ 2 =
      ‖(ginibreHolomorphicAmbientClosedSpan n hn).starProjection
        (centeredObservableL2 hn f hf)‖ ^ 2 := by
  let u := centeredObservableSymmetricL2 hn f hf
  let v := vandermondeSymmetricAlternatingEquiv n hn u
  have hv : v.1 = transformedCenteredObservableL2 hn f hf := rfl
  have hproj := ComplexHermite.transform_ginibreSymmetricHolomorphicPart_eq_gaussianZeroMode
    n hn u
  have hambient := coe_starProjection_centeredObservableSymmetricL2 hn f hf
  rw [gaussianHermiteMode_eq_antiDegreeProjection]
  rw [← hv, ← coe_gaussianAlternatingZeroModeProjection hn v]
  change ‖ComplexHermite.gaussianZeroModeOfGinibre n hn u‖ ^ 2 = _
  rw [← hproj]
  rw [(vandermondeSymmetricAlternatingEquiv n hn).norm_map]
  change ‖(ComplexHermite.ginibreSymmetricHolomorphicPart n hn u).1‖ ^ 2 = _
  dsimp [u, ComplexHermite.ginibreSymmetricHolomorphicPart]
  rw [hambient]

/-- Internal concrete assembly lemma. Its sole analytic hypothesis is the
weighted mode-energy series identity, stated as `HasSum` so convergence is
part of the identity rather than a separate assumption. -/
theorem concrete_theoremOneNine_of_modeEnergy {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f)
    (henergy : HasSum (fun k : ℕ => ((k + 1 : ℕ) : ℝ) *
      concretePositiveHermiteModeMass hn f hf k)
        (smoothGinibreEnergy n f / 4)) :
    let h := (ginibreHolomorphicAmbientClosedSpan n hn).starProjection
      (centeredObservableL2 hn f hf)
    let r := centeredObservableL2 hn f hf - h - star h
    (smoothGinibreEnergy n f - 2 * smoothGinibreVariance n f =
      2 * ‖r‖ ^ 2 +
        4 * modeTail (concretePositiveHermiteModeMass hn f hf)) ∧
    (ginibreGeneratorNormSq n f - 2 * smoothGinibreEnergy n f =
      shiftedGinibreGeneratorNormSq n (centeredObservable n f) +
        4 * ‖r‖ ^ 2 +
        8 * modeTail (concretePositiveHermiteModeMass hn f hf)) := by
  dsimp only
  let h := (ginibreHolomorphicAmbientClosedSpan n hn).starProjection
    (centeredObservableL2 hn f hf)
  let r := centeredObservableL2 hn f hf - h - star h
  let a := concretePositiveHermiteModeMass hn f hf
  have ha : Summable a := summable_transformedCentered_positiveModeMass hn f hf
  have ht : Summable fun k : ℕ => (k : ℝ) * a k := by
    have hs := henergy.summable.sub ha
    apply hs.congr
    intro k
    dsimp [a]
    push_cast
    ring

  have henergy' : smoothGinibreEnergy n f = 4 * modeEnergy a := by
    unfold modeEnergy
    rw [henergy.tsum_eq]
    ring
  have hparseval : smoothGinibreVariance n f = ‖h‖ ^ 2 + modeMass a := by
    rw [smoothGinibreVariance_eq_zeroMode_add_positiveModeMass hn f hf,
      concreteZeroMode_norm_sq_eq_holomorphicProjection hn f hf]
    rfl
  have hgeometry : smoothGinibreVariance n f = 2 * ‖h‖ ^ 2 + ‖r‖ ^ 2 := by
    exact (centeredHolomorphicRemainderGeometry hn f hf).2.2.2
  have hfirst : smoothGinibreEnergy n f - 2 * smoothGinibreVariance n f =
      2 * ‖r‖ ^ 2 + 4 * modeTail a :=
    infinite_deficit_identity a ha ht _ _ _ _ hparseval hgeometry henergy'
  constructor
  · exact hfirst
  · rw [ginibreGenerator_squareCompletion hn f hf, hfirst]
    ring

/-- The two exact sum-of-squares identities of Theorem 1.9 for the concrete
Ginibre measure and generator, with all Hermite-series convergence included. -/
theorem concrete_theoremOneNine {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    let h := (ginibreHolomorphicAmbientClosedSpan n hn).starProjection
      (centeredObservableL2 hn f hf)
    let r := centeredObservableL2 hn f hf - h - star h
    (smoothGinibreEnergy n f - 2 * smoothGinibreVariance n f =
      2 * ‖r‖ ^ 2 +
        4 * modeTail (concretePositiveHermiteModeMass hn f hf)) ∧
    (ginibreGeneratorNormSq n f - 2 * smoothGinibreEnergy n f =
      shiftedGinibreGeneratorNormSq n (centeredObservable n f) +
        4 * ‖r‖ ^ 2 +
        8 * modeTail (concretePositiveHermiteModeMass hn f hf)) :=
  concrete_theoremOneNine_of_modeEnergy hn f hf
    (concrete_weightedModeEnergy hn f hf)

end

end GinibrePoincare
Endgame GinibrePoincare/Endgame/FiniteTheoremOneNine.lean #
import GinibrePoincare.Analysis.L2RepresentativeBridges

/-! # Realizing finite Hermite expansions in the Ginibre ground-state transform -/

open MeasureTheory
open scoped BigOperators ComplexConjugate

namespace GinibrePoincare
namespace ComplexHermite

noncomputable section

theorem transformedCenteredObservableL2_coeFn {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f) :
    transformedCenteredObservableL2 hn f hf =ᵐ[complexGaussianMeasure n]
      normalizedVandermondeTransform n
        (fun z => (centeredObservable n f z : ℂ)) := by
  let u := centeredObservableL2 hn f hf
  have hmul : normalizedVandermondeL2 n hn u =ᵐ[complexGaussianMeasure n]
      fun z => normalizedVandermondeMultiplier n z * u z := by
    unfold normalizedVandermondeL2
    dsimp only
    generalize_proofs h1 h2 h3 h4 h5
    exact (h5 u).coeFn_toLp
  have hu := (complexGaussianMeasure_absolutelyContinuous_ginibreMeasure
    (ginibreMassEvaluation n hn)).ae_eq (centeredObservableL2_coeFn hn f hf)
  filter_upwards [hmul, hu] with z hz hzu
  rw [transformedCenteredObservableL2, hz, hzu]
  unfold normalizedVandermondeMultiplier
  exact (normalizedVandermondeTransform_apply n
    (fun z => (centeredObservable n f z : ℂ)) z).symm

private theorem continuous_finiteHermiteFunction (n : ℕ) (hn : 0 < n)
    (c : HermiteMultiIndex n →₀ ℂ) :
    Continuous (finiteHermiteFunction n hn c) := by
  classical
  rw [show finiteHermiteFunction n hn c = fun z =>
      ∑ pq ∈ c.support, c pq * multivariateNormalized n hn pq.1 pq.2 z by
    funext z
    simp [finiteHermiteFunction, Finsupp.linearCombination_apply,
      Finsupp.sum, smul_eq_mul]]
  apply continuous_finset_sum
  intro pq hpq
  exact continuous_const.mul (continuous_multivariateNormalized n hn pq.1 pq.2)

/-- An equality of the Gaussian `L²` classes upgrades to literal equality of
the smooth ground-state representative and its finite Hermite polynomial. -/
theorem transformedCentered_eq_finiteHermiteFunction {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f)
    (c : HermiteMultiIndex n →₀ ℂ)
    (hL2 : transformedCenteredObservableL2 hn f hf =
      finiteHermiteCombination n hn c) :
    normalizedVandermondeTransform n
        (fun z => (centeredObservable n f z : ℂ)) =
      finiteHermiteFunction n hn c := by
  apply continuous_eq_of_ae_eq_complexGaussian hn
  · exact (contDiff_normalizedVandermonde_centered hf.1).continuous
  · exact continuous_finiteHermiteFunction n hn c
  · calc
      _ =ᵐ[complexGaussianMeasure n] transformedCenteredObservableL2 hn f hf :=
        (transformedCenteredObservableL2_coeFn hn f hf).symm
      _ =ᵐ[complexGaussianMeasure n] finiteHermiteCombination n hn c := by
        rw [hL2]
      _ =ᵐ[complexGaussianMeasure n] finiteHermiteFunction n hn c :=
        finiteHermiteCombination_coeFn n hn c

/-- Parseval realizes the concrete Ginibre variance as the coefficient mass
of any finite Hermite expansion of the transformed centered observable. -/
theorem finiteHermite_variance_identity {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f)
    (c : HermiteMultiIndex n →₀ ℂ)
    (hL2 : transformedCenteredObservableL2 hn f hf =
      finiteHermiteCombination n hn c) :
    smoothGinibreVariance n f = c.sum fun _ a => Complex.normSq a := by
  rw [← norm_sq_transformedCenteredObservableL2 hn f hf, hL2,
    norm_sq_finiteHermiteCombination]

/-- The Gaussian antiholomorphic energy of a realized finite expansion is
the exact Hermite diagonal energy divided by `n`. -/
theorem finiteHermite_gaussianDbarEnergy_identity {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f)
    (c : HermiteMultiIndex n →₀ ℂ)
    (hL2 : transformedCenteredObservableL2 hn f hf =
      finiteHermiteCombination n hn c) :
    gaussianDbarEnergy n
        (normalizedVandermondeTransform n
          (fun z => (centeredObservable n f z : ℂ))) =
      (1 / (n : ℝ)) * finiteDbarEnergy c := by
  rw [transformedCentered_eq_finiteHermiteFunction hn f hf c hL2]
  unfold gaussianDbarEnergy dbarNormSq
  congr 1
  rw [integral_finset_sum]
  have h := finiteGaussianDbarIntegralEnergy n hn c
  have hre := congrArg Complex.re h
  calc
    _ = ∑ j : Fin n,
        (∫ z, conj (dbarComponent (finiteHermiteFunction n hn c) j z) *
          dbarComponent (finiteHermiteFunction n hn c) j z
          ∂complexGaussianMeasure n).re := by
      apply Finset.sum_congr rfl
      intro j hj
      let u := finiteHermiteCombination n hn (loweredCoefficients n c j)
      have hcint : Integrable (fun z =>
          conj (dbarComponent (finiteHermiteFunction n hn c) j z) *
            dbarComponent (finiteHermiteFunction n hn c) j z)
          (complexGaussianMeasure n) := by
        have hu := MeasureTheory.L2.integrable_inner (𝕜 := ℂ) u u
        apply hu.congr
        filter_upwards [finiteHermiteCombination_coeFn n hn
          (loweredCoefficients n c j)] with z hz
        rw [hz, ← dbarComponent_finiteHermiteFunction n hn c j z]
        rw [RCLike.inner_apply]
        ring
      calc
        _ = ∫ z, (conj (dbarComponent (finiteHermiteFunction n hn c) j z) *
            dbarComponent (finiteHermiteFunction n hn c) j z).re
            ∂complexGaussianMeasure n := by
          apply integral_congr_ae
          filter_upwards with z
          simp [Complex.normSq_apply]
        _ = _ := integral_re hcint
    _ = finiteDbarEnergy c := by simpa [map_sum] using hre
  intro j hj
  let u := finiteHermiteCombination n hn (loweredCoefficients n c j)
  have hcint : Integrable (fun z =>
      conj (dbarComponent (finiteHermiteFunction n hn c) j z) *
        dbarComponent (finiteHermiteFunction n hn c) j z)
      (complexGaussianMeasure n) := by
    have hu := MeasureTheory.L2.integrable_inner (𝕜 := ℂ) u u
    apply hu.congr
    filter_upwards [finiteHermiteCombination_coeFn n hn
      (loweredCoefficients n c j)] with z hz
    rw [hz, ← dbarComponent_finiteHermiteFunction n hn c j z]
    rw [RCLike.inner_apply]
    ring
  apply hcint.re.congr
  filter_upwards [finiteHermiteCombination_coeFn n hn
    (loweredCoefficients n c j)] with z hz
  simp [Complex.normSq_apply]

/-- Exact finite-mode realization of the first (Dirichlet/variance) energy
data: the Ginibre energy is four times the Hermite diagonal energy divided
by `n`. -/
theorem finiteHermite_smoothEnergy_identity {n : ℕ} (hn : 0 < n)
    (f : Configuration n → ℝ) (hf : IsTheoremOneNineCore f)
    (c : HermiteMultiIndex n →₀ ℂ)
    (hL2 : transformedCenteredObservableL2 hn f hf =
      finiteHermiteCombination n hn c) :
    smoothGinibreEnergy n f =
      4 * ((1 / (n : ℝ)) * finiteDbarEnergy c) := by
  rw [groundStateEnergyIdentity n hn (ginibreMeasure_isProbabilityMeasure hn)
    f hf.isSmoothCompactSymmetric,
    finiteHermite_gaussianDbarEnergy_identity hn f hf c hL2]

end
end ComplexHermite
end GinibrePoincare
Endgame GinibrePoincare/Endgame/GeneratorCompletion.lean #
import Mathlib.Analysis.InnerProductSpace.Basic
import Mathlib.Analysis.InnerProductSpace.LinearMap
import Mathlib.Tactic.Linarith
import Mathlib.Tactic.Ring

/-!
# Universal Hilbert-space square completion

Equation (6.6) of the paper is independent of the Ginibre realization.  This
file proves it directly for a real-linear operator on a real inner-product
space.  There is no certificate, no measure-theoretic hypothesis, and no
Ginibre-specific theorem hidden in the declarations.
-/

namespace GinibrePoincare

noncomputable section

namespace OperatorSquareCompletion

variable {E : Type*}
variable [SeminormedAddCommGroup E]
variable [InnerProductSpace ℝ E]

/-- Squared norm, written as a real inner product. -/
def normSq (f : E) : ℝ :=
  inner ℝ f f

/-- Variance of a centered vector in the abstract Hilbert calculation. -/
def variance (f : E) : ℝ :=
  normSq f

/-- Dirichlet energy associated with a real-linear generator. -/
def energy (A : E →ₗ[ℝ] E) (f : E) : ℝ :=
  -inner ℝ (A f) f

/-- Squared norm of the generator image. -/
def generatorSq (A : E →ₗ[ℝ] E) (f : E) : ℝ :=
  normSq (A f)

/-- Squared norm of `(A + 2 I)f`. -/
def shiftedGeneratorSq (A : E →ₗ[ℝ] E) (f : E) : ℝ :=
  normSq (A f + (2 : ℝ) • f)

/-- A squared norm is nonnegative. -/
theorem normSq_nonneg (f : E) :
    0 ≤ normSq f := by
  exact real_inner_self_nonneg

/-- The shifted-generator square is nonnegative. -/
theorem shiftedGeneratorSq_nonneg (A : E →ₗ[ℝ] E) (f : E) :
    0 ≤ shiftedGeneratorSq A f := by
  exact normSq_nonneg (A f + (2 : ℝ) • f)

/-- Direct expansion of the shifted square. -/
theorem shiftedGeneratorSq_expand (A : E →ₗ[ℝ] E) (f : E) :
    shiftedGeneratorSq A f =
      generatorSq A f - 4 * energy A f + 4 * variance f := by
  unfold shiftedGeneratorSq generatorSq energy variance normSq
  have hcomm : inner ℝ f (A f) = inner ℝ (A f) f :=
    real_inner_comm (A f) f
  simp only [inner_add_left, inner_add_right, real_inner_smul_left,
    real_inner_smul_right, hcomm]
  ring

/-- Equation (6.6), proved by expanding the square. -/
theorem completionSquare (A : E →ₗ[ℝ] E) (f : E) :
    generatorSq A f - 2 * energy A f =
      shiftedGeneratorSq A f +
        2 * (energy A f - 2 * variance f) := by
  rw [shiftedGeneratorSq_expand]
  ring

/-- Poincaré implies the integrated `Gamma_2` inequality by square completion. -/
theorem integratedGammaTwo_of_poincare
    (A : E →ₗ[ℝ] E)
    (f : E)
    (hPoincare : 2 * variance f ≤ energy A f) :
    2 * energy A f ≤ generatorSq A f := by
  have hSquare := completionSquare A f
  have hShifted := shiftedGeneratorSq_nonneg A f
  linarith

end OperatorSquareCompletion

end

end GinibrePoincare
Endgame GinibrePoincare/Endgame/HilbertGeometry.lean #
import Mathlib.Analysis.InnerProductSpace.Basic
import Mathlib.Analysis.InnerProductSpace.LinearMap

/-!
# Hilbert-space geometry used by the Ginibre deficit proof

This file isolates the Pythagorean part of the proof.  It proves the norm
identity obtained from three pairwise orthogonal vectors, and the particular
zero-mode geometry

`‖f‖² = 2 ‖h‖² + ‖r‖²`

when `f = h + hbar + r`, the three summands are pairwise orthogonal, and
`‖hbar‖ = ‖h‖`.
-/

namespace GinibrePoincare

noncomputable section

/-- The square of the norm, written without using a power. -/
def normSq {E : Type*} [Norm E] (x : E) : ℝ :=
  ‖x‖ * ‖x‖

@[simp]
theorem normSq_zero {E : Type*} [SeminormedAddCommGroup E] :
    normSq (0 : E) = 0 := by
  simp [normSq]

/-- A squared norm is nonnegative. -/
theorem normSq_nonneg {E : Type*} [SeminormedAddCommGroup E] (x : E) :
    0 ≤ normSq x := by
  exact mul_self_nonneg ‖x‖

/-- Pythagoras in the notation `normSq`. -/
theorem normSq_add_of_inner_eq_zero
    {𝕜 E : Type*}
    [RCLike 𝕜]
    [SeminormedAddCommGroup E]
    [InnerProductSpace 𝕜 E]
    (x y : E)
    (hxy : inner 𝕜 x y = 0) :
    normSq (x + y) = normSq x + normSq y := by
  simpa only [normSq] using
    norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero x y hxy

/-- Pythagoras for three pairwise orthogonal vectors in a real inner-product space. -/
theorem normSq_three_of_pairwise_orthogonal
    {E : Type*}
    [SeminormedAddCommGroup E]
    [InnerProductSpace ℝ E]
    (x y z : E)
    (hxy : inner ℝ x y = 0)
    (hxz : inner ℝ x z = 0)
    (hyz : inner ℝ y z = 0) :
    normSq (x + y + z) = normSq x + normSq y + normSq z := by
  have hsumz : inner ℝ (x + y) z = 0 := by
    simp only [inner_add_left, hxz, hyz, add_zero]
  calc
    normSq (x + y + z) = normSq (x + y) + normSq z :=
      normSq_add_of_inner_eq_zero (x + y) z hsumz
    _ = normSq x + normSq y + normSq z := by
      rw [normSq_add_of_inner_eq_zero x y hxy]

/--
The abstract Hilbert-space form of the holomorphic--antiholomorphic
projection geometry used in the paper.
-/
theorem zero_mode_projection_geometry
    {E : Type*}
    [SeminormedAddCommGroup E]
    [InnerProductSpace ℝ E]
    (f h hbar r : E)
    (hf : f = h + hbar + r)
    (hh_hbar : inner ℝ h hbar = 0)
    (hh_r : inner ℝ h r = 0)
    (hhbar_r : inner ℝ hbar r = 0)
    (hNorm : ‖hbar‖ = ‖h‖) :
    normSq f = 2 * normSq h + normSq r := by
  rw [hf, normSq_three_of_pairwise_orthogonal h hbar r hh_hbar hh_r hhbar_r]
  unfold normSq
  rw [hNorm]
  ring

/-- A linear isometric equivalence preserves squared norms. -/
@[simp]
theorem normSq_map_linearIsometryEquiv
    {𝕜 E F : Type*}
    [RCLike 𝕜]
    [SeminormedAddCommGroup E]
    [SeminormedAddCommGroup F]
    [NormedSpace 𝕜 E]
    [NormedSpace 𝕜 F]
    (U : E ≃ₗᵢ[𝕜] F)
    (x : E) :
    normSq (U x) = normSq x := by
  simp [normSq]

end

end GinibrePoincare
Endgame GinibrePoincare/Endgame/SeriesDeficit.lean #
import Mathlib.Topology.Algebra.InfiniteSum.Real
import Mathlib.Tactic.Linarith
import Mathlib.Tactic.Ring

/-!
# The series arithmetic in the proof of Theorem 1.9

This file formalizes the exact algebraic endgame of the Hermite proof of the
Poincaré deficit formula in arXiv:2608.19358.

The sequence `a` is deliberately shifted by one index:

* `a k` represents `‖g_{k+1}‖²`;
* `modeMass a = ∑ k, ‖g_{k+1}‖²`;
* `modeTail a = ∑ k, k ‖g_{k+1}‖²`, which is
  `∑_{m ≥ 2} (m - 1) ‖g_m‖²`;
* `modeEnergy a = ∑ k, (k + 1) ‖g_{k+1}‖²`, which is
  `∑_{m ≥ 1} m ‖g_m‖²`.

Every theorem in this file has an explicit proof term.
-/

open scoped BigOperators

namespace GinibrePoincare

noncomputable section

/-- The unweighted mass of the strictly positive Hermite modes. -/
def modeMass (a : ℕ → ℝ) : ℝ :=
  ∑' k : ℕ, a k

/-- The shifted Poincaré-deficit tail. -/
def modeTail (a : ℕ → ℝ) : ℝ :=
  ∑' k : ℕ, (k : ℝ) * a k

/-- The weighted Hermite energy, with `a k = ‖g_{k+1}‖²`. -/
def modeEnergy (a : ℕ → ℝ) : ℝ :=
  ∑' k : ℕ, ((k + 1 : ℕ) : ℝ) * a k

/-- The elementary decomposition `(k + 1) a_k = a_k + k a_k`, summed over `k`. -/
theorem modeEnergy_eq_modeMass_add_modeTail
    (a : ℕ → ℝ)
    (ha : Summable a)
    (ht : Summable fun k : ℕ => (k : ℝ) * a k) :
    modeEnergy a = modeMass a + modeTail a := by
  unfold modeEnergy modeMass modeTail
  calc
    (∑' k : ℕ, ((k + 1 : ℕ) : ℝ) * a k)
        = ∑' k : ℕ, (a k + (k : ℝ) * a k) := by
            apply tsum_congr
            intro k
            simp only [Nat.cast_add, Nat.cast_one]
            ring
    _ = (∑' k : ℕ, a k) + ∑' k : ℕ, (k : ℝ) * a k :=
      ha.tsum_add ht

/-- Nonnegativity of the shifted tail. -/
theorem modeTail_nonneg
    (a : ℕ → ℝ)
    (ha : ∀ k : ℕ, 0 ≤ a k) :
    0 ≤ modeTail a := by
  unfold modeTail
  exact tsum_nonneg fun k : ℕ => mul_nonneg (Nat.cast_nonneg k) (ha k)

/--
The exact infinite-series deficit identity.

The hypotheses encode, respectively, Parseval, the three-term zero-mode
geometry, and the Hermite energy expansion.
-/
theorem infinite_deficit_identity
    (a : ℕ → ℝ)
    (ha : Summable a)
    (ht : Summable fun k : ℕ => (k : ℝ) * a k)
    (variance holomorphicSq remainderSq energy : ℝ)
    (hParseval : variance = holomorphicSq + modeMass a)
    (hGeometry : variance = 2 * holomorphicSq + remainderSq)
    (hEnergy : energy = 4 * modeEnergy a) :
    energy - 2 * variance = 2 * remainderSq + 4 * modeTail a := by
  rw [hEnergy, modeEnergy_eq_modeMass_add_modeTail a ha ht]
  linarith [hParseval, hGeometry]

/-- The Poincaré inequality obtained from the exact deficit identity. -/
theorem infinite_poincare_from_deficit
    (a : ℕ → ℝ)
    (ha : Summable a)
    (ht : Summable fun k : ℕ => (k : ℝ) * a k)
    (variance holomorphicSq remainderSq energy : ℝ)
    (hParseval : variance = holomorphicSq + modeMass a)
    (hGeometry : variance = 2 * holomorphicSq + remainderSq)
    (hEnergy : energy = 4 * modeEnergy a)
    (hRemainder : 0 ≤ remainderSq)
    (hMode : ∀ k : ℕ, 0 ≤ a k) :
    2 * variance ≤ energy := by
  have hDeficit := infinite_deficit_identity a ha ht variance holomorphicSq
    remainderSq energy hParseval hGeometry hEnergy
  have hTail := modeTail_nonneg a hMode
  linarith

/-- The conventional form `variance ≤ energy / 2`. -/
theorem infinite_poincare_half
    (a : ℕ → ℝ)
    (ha : Summable a)
    (ht : Summable fun k : ℕ => (k : ℝ) * a k)
    (variance holomorphicSq remainderSq energy : ℝ)
    (hParseval : variance = holomorphicSq + modeMass a)
    (hGeometry : variance = 2 * holomorphicSq + remainderSq)
    (hEnergy : energy = 4 * modeEnergy a)
    (hRemainder : 0 ≤ remainderSq)
    (hMode : ∀ k : ℕ, 0 ≤ a k) :
    variance ≤ energy / 2 := by
  have h := infinite_poincare_from_deficit a ha ht variance holomorphicSq
    remainderSq energy hParseval hGeometry hEnergy hRemainder hMode
  linarith

/-- Equality forces both nonnegative pieces of the Poincaré deficit to vanish. -/
theorem infinite_equality_forces_remainder_and_tail_zero
    (a : ℕ → ℝ)
    (ha : Summable a)
    (ht : Summable fun k : ℕ => (k : ℝ) * a k)
    (variance holomorphicSq remainderSq energy : ℝ)
    (hParseval : variance = holomorphicSq + modeMass a)
    (hGeometry : variance = 2 * holomorphicSq + remainderSq)
    (hEnergy : energy = 4 * modeEnergy a)
    (hRemainder : 0 ≤ remainderSq)
    (hMode : ∀ k : ℕ, 0 ≤ a k)
    (hEquality : energy = 2 * variance) :
    remainderSq = 0 ∧ modeTail a = 0 := by
  have hDeficit := infinite_deficit_identity a ha ht variance holomorphicSq
    remainderSq energy hParseval hGeometry hEnergy
  have hTail := modeTail_nonneg a hMode
  constructor <;> linarith

/-- Vanishing of the two pieces is sufficient for equality. -/
theorem infinite_equality_of_remainder_and_tail_zero
    (a : ℕ → ℝ)
    (ha : Summable a)
    (ht : Summable fun k : ℕ => (k : ℝ) * a k)
    (variance holomorphicSq remainderSq energy : ℝ)
    (hParseval : variance = holomorphicSq + modeMass a)
    (hGeometry : variance = 2 * holomorphicSq + remainderSq)
    (hEnergy : energy = 4 * modeEnergy a)
    (hRemainderZero : remainderSq = 0)
    (hTailZero : modeTail a = 0) :
    energy = 2 * variance := by
  have hDeficit := infinite_deficit_identity a ha ht variance holomorphicSq
    remainderSq energy hParseval hGeometry hEnergy
  linarith

section Finite

/-- Finite-mode analogue of `modeMass`. -/
def finiteModeMass (N : ℕ) (a : ℕ → ℝ) : ℝ :=
  (Finset.range N).sum a

/-- Finite-mode analogue of `modeTail`. -/
def finiteModeTail (N : ℕ) (a : ℕ → ℝ) : ℝ :=
  (Finset.range N).sum (fun k : ℕ => (k : ℝ) * a k)

/-- Finite-mode analogue of `modeEnergy`. -/
def finiteModeEnergy (N : ℕ) (a : ℕ → ℝ) : ℝ :=
  (Finset.range N).sum (fun k : ℕ => ((k + 1 : ℕ) : ℝ) * a k)

/-- Finite-sum version of `(k + 1) a_k = a_k + k a_k`. -/
theorem finiteModeEnergy_eq_finiteModeMass_add_finiteModeTail
    (N : ℕ) (a : ℕ → ℝ) :
    finiteModeEnergy N a = finiteModeMass N a + finiteModeTail N a := by
  unfold finiteModeEnergy finiteModeMass finiteModeTail
  rw [← Finset.sum_add_distrib]
  apply Finset.sum_congr rfl
  intro k hk
  simp only [Nat.cast_add, Nat.cast_one]
  ring

/-- Nonnegativity of the finite shifted tail. -/
theorem finiteModeTail_nonneg
    (N : ℕ) (a : ℕ → ℝ)
    (ha : ∀ k : ℕ, 0 ≤ a k) :
    0 ≤ finiteModeTail N a := by
  unfold finiteModeTail
  refine Finset.sum_nonneg ?_
  intro k hk
  exact mul_nonneg (Nat.cast_nonneg k) (ha k)

/-- Exact finite-Hermite-expansion deficit identity. -/
theorem finite_deficit_identity
    (N : ℕ) (a : ℕ → ℝ)
    (variance holomorphicSq remainderSq energy : ℝ)
    (hParseval : variance = holomorphicSq + finiteModeMass N a)
    (hGeometry : variance = 2 * holomorphicSq + remainderSq)
    (hEnergy : energy = 4 * finiteModeEnergy N a) :
    energy - 2 * variance = 2 * remainderSq + 4 * finiteModeTail N a := by
  rw [hEnergy, finiteModeEnergy_eq_finiteModeMass_add_finiteModeTail N a]
  linarith [hParseval, hGeometry]

/-- Poincaré inequality for a finite Hermite expansion. -/
theorem finite_poincare_from_deficit
    (N : ℕ) (a : ℕ → ℝ)
    (variance holomorphicSq remainderSq energy : ℝ)
    (hParseval : variance = holomorphicSq + finiteModeMass N a)
    (hGeometry : variance = 2 * holomorphicSq + remainderSq)
    (hEnergy : energy = 4 * finiteModeEnergy N a)
    (hRemainder : 0 ≤ remainderSq)
    (hMode : ∀ k : ℕ, 0 ≤ a k) :
    2 * variance ≤ energy := by
  have hDeficit := finite_deficit_identity N a variance holomorphicSq
    remainderSq energy hParseval hGeometry hEnergy
  have hTail := finiteModeTail_nonneg N a hMode
  linarith

end Finite

end

end GinibrePoincare
Endgame GinibrePoincare/Endgame/TheoremOneNine.lean #
import GinibrePoincare.Endgame.SeriesDeficit
import GinibrePoincare.Endgame.GeneratorCompletion

/-!
# The two sum-of-squares identities of Theorem 1.9

This file joins the Hermite-series deficit calculation to the universal
generator square-completion.  Unlike the former `ModeReduction` result, the
theorem below proves both displayed identities of Theorem 1.9 simultaneously.
The hypotheses are precisely the analytic realization data still needed from
the Ginibre/Hermite construction: Parseval, zero-mode geometry, and the mode
energy formula.
-/

namespace GinibrePoincare

noncomputable section

namespace TheoremOneNine

open OperatorSquareCompletion

variable {E : Type*}
variable [SeminormedAddCommGroup E]
variable [InnerProductSpace ℝ E]

/-- Abstract, fully checked form of both identities in Theorem 1.9 of
arXiv:2608.19358v2. -/
theorem sum_of_squares
    (A : E →ₗ[ℝ] E) (f : E)
    (a : ℕ → ℝ) (holomorphicSq remainderSq : ℝ)
    (ha : Summable a)
    (ht : Summable fun k : ℕ => (k : ℝ) * a k)
    (hParseval :
      variance f = holomorphicSq + modeMass a)
    (hGeometry :
      variance f = 2 * holomorphicSq + remainderSq)
    (hEnergy :
      energy A f = 4 * modeEnergy a) :
    (energy A f - 2 * variance f =
      2 * remainderSq + 4 * modeTail a) ∧
    (generatorSq A f - 2 * energy A f =
      shiftedGeneratorSq A f +
        4 * remainderSq + 8 * modeTail a) := by
  have hDeficit :
      energy A f - 2 * variance f =
        2 * remainderSq + 4 * modeTail a :=
    infinite_deficit_identity a ha ht
      (variance f) holomorphicSq remainderSq (energy A f)
      hParseval hGeometry hEnergy
  constructor
  · exact hDeficit
  · rw [completionSquare A f, hDeficit]
    ring

end TheoremOneNine

end

end GinibrePoincare
Project GinibrePoincare.lean #
import GinibrePoincare.Concrete.Configuration
import GinibrePoincare.Concrete.Vandermonde
import GinibrePoincare.Concrete.Weights
import GinibrePoincare.Concrete.GroundState
import GinibrePoincare.Concrete.CenterOfMass
import GinibrePoincare.Concrete.GaussianProbability
import GinibrePoincare.Concrete.MeasureModel
import GinibrePoincare.Concrete.NormalizedGroundState
import GinibrePoincare.Concrete.SmoothTarget
import GinibrePoincare.Concrete.Wirtinger
import GinibrePoincare.Concrete.HolomorphicDistance
import GinibrePoincare.Concrete.AnalyticStatements
import GinibrePoincare.Concrete.MainProofReduction
import GinibrePoincare.Concrete.ModeReduction
import GinibrePoincare.Concrete.Generator
import GinibrePoincare.Analysis.GaussianDensity
import GinibrePoincare.Analysis.ComplexHermite
import GinibrePoincare.Analysis.ComplexHermiteLowering
import GinibrePoincare.Analysis.NormalizedComplexHermite
import GinibrePoincare.Analysis.MultivariateComplexHermite
import GinibrePoincare.Analysis.HermiteWirtinger
import GinibrePoincare.Analysis.ComplexHermiteOrthogonality
import GinibrePoincare.Analysis.MultivariateHermiteIntegrability
import GinibrePoincare.Analysis.HermiteOrthogonalityCombinatorics
import GinibrePoincare.Analysis.HermiteBinomialIdentity
import GinibrePoincare.Analysis.GaussianPolynomialDensity
import GinibrePoincare.Analysis.GaussianPolynomialCompleteness
import GinibrePoincare.Analysis.HermiteMonomialSpan
import GinibrePoincare.Analysis.MultivariateHermiteMonomialSpan
import GinibrePoincare.Analysis.GaussianHermiteMoments
import GinibrePoincare.Analysis.GaussianFourierCoordinates
import GinibrePoincare.Analysis.GaussianFourierUniqueness
import GinibrePoincare.Analysis.HermiteL2Family
import GinibrePoincare.Analysis.HermiteParsevalModes
import GinibrePoincare.Analysis.HermiteWeightedEnergy
import GinibrePoincare.Analysis.VandermondeGroundStateZeroMode
import GinibrePoincare.Analysis.WeightedSeriesTruncation
import GinibrePoincare.Analysis.GaussianDbarParseval
import GinibrePoincare.Analysis.RealGaussianIntegrationByParts
import GinibrePoincare.Analysis.ComplexGaussianIntegrationByParts
import GinibrePoincare.Analysis.ComplexGaussianProductIntegral
import GinibrePoincare.Analysis.PolynomialCompactApproximation
import GinibrePoincare.Analysis.HermiteEnergy
import GinibrePoincare.Analysis.FiniteHermiteDeficit
import GinibrePoincare.Analysis.L2RepresentativeBridges
import GinibrePoincare.Analysis.GroundStateDbar
import GinibrePoincare.Analysis.HolomorphicVandermondeDivision
import GinibrePoincare.Analysis.HolomorphicVandermondeL2Closure
import GinibrePoincare.Analysis.GinibreConjugationGeometry
import GinibrePoincare.Analysis.GlobalPhaseAction
import GinibrePoincare.Analysis.GinibreIntegrationByParts
import GinibrePoincare.Analysis.GinibreGeneratorL2
import GinibrePoincare.Analysis.FinitePiDensity
import GinibrePoincare.Analysis.MeasureTransport
import GinibrePoincare.Analysis.ComplexGaussianDensity
import GinibrePoincare.Analysis.GinibreMassPositivity
import GinibrePoincare.Analysis.GaussianPolynomialIntegrability
import GinibrePoincare.Analysis.ComplexGaussianMoments
import GinibrePoincare.Analysis.AngularMoments
import GinibrePoincare.Analysis.RadialMoments
import GinibrePoincare.Analysis.PolarGaussianMoments
import GinibrePoincare.Analysis.GinibreMassFiniteness
import GinibrePoincare.Analysis.CollisionNull
import GinibrePoincare.Analysis.VandermondeL2
import GinibrePoincare.Analysis.PermutationLp
import GinibrePoincare.Analysis.VandermondeSymmetryL2
import GinibrePoincare.Analysis.VandermondeL2Inverse
import GinibrePoincare.Endgame.SeriesDeficit
import GinibrePoincare.Endgame.HilbertGeometry
import GinibrePoincare.Endgame.GeneratorCompletion
import GinibrePoincare.Endgame.TheoremOneNine
import GinibrePoincare.Endgame.FiniteTheoremOneNine
import GinibrePoincare.Endgame.ConcreteTheoremOneNine
Project AxiomAudit.lean #
import GinibrePoincare

#print axioms GinibrePoincare.collisionFree_iff_not_mem_collisionSet
#print axioms GinibrePoincare.vandermonde_eq_zero_iff
#print axioms GinibrePoincare.vandermonde_ne_zero_iff
#print axioms GinibrePoincare.vandermonde_permute
#print axioms GinibrePoincare.ginibreWeight_eq_zero_iff
#print axioms GinibrePoincare.vandermondeTransform_isAlternating
#print axioms GinibrePoincare.coordinateSum_permute
#print axioms GinibrePoincare.complexGaussianMeasure_univ
#print axioms GinibrePoincare.complexGaussianIsProbability
#print axioms GinibrePoincare.complexGaussianDensityMeasure_univ_of_identification
#print axioms GinibrePoincare.ginibreMeasure_univ_of_mass_valid
#print axioms GinibrePoincare.ginibreMeasure_isProbabilityMeasure_of_mass_valid
#print axioms GinibrePoincare.ginibreMeasureIsProbability_of_mass_evaluation
#print axioms GinibrePoincare.ginibreMeasure_isProbabilityMeasure_of_mass_evaluation
#print axioms GinibrePoincare.mainProof_scalar_endgame
#print axioms GinibrePoincare.smoothGinibrePoincare_of_main_analytic_statements
#print axioms GinibrePoincare.smoothGinibre_deficit_of_mode_identities
#print axioms GinibrePoincare.smoothGinibre_poincare_of_mode_identities
#print axioms GinibrePoincare.OperatorSquareCompletion.completionSquare
#print axioms GinibrePoincare.TheoremOneNine.sum_of_squares
#print axioms GinibrePoincare.ComplexHermite.finiteHermite_variance_identity
#print axioms GinibrePoincare.ComplexHermite.finiteHermite_smoothEnergy_identity
#print axioms GinibrePoincare.realCoordinateGaussianMeasure_eq_withDensity
#print axioms GinibrePoincare.ComplexHermite.raw_one_one
#print axioms GinibrePoincare.ComplexHermite.pderiv_Z_raw_zero_right
#print axioms GinibrePoincare.ComplexHermite.pderiv_Z_raw
#print axioms GinibrePoincare.ComplexHermite.pderiv_W_raw
#print axioms GinibrePoincare.ComplexHermite.pderiv_Z_normalized
#print axioms GinibrePoincare.ComplexHermite.pderiv_W_normalized
#print axioms GinibrePoincare.ComplexHermite.multivariateNormalized_zero_right
#print axioms GinibrePoincare.ComplexHermite.continuous_multivariateNormalized
#print axioms GinibrePoincare.ComplexHermite.dbarComponent_multivariateNormalized
#print axioms GinibrePoincare.ComplexHermite.normalizedEval_eq_sum
#print axioms GinibrePoincare.ComplexHermite.integrable_normalizedEval
#print axioms GinibrePoincare.ComplexHermite.normalizedEval_zero_zero_inner
#print axioms GinibrePoincare.ComplexHermite.integrable_normSq_multivariateNormalized
#print axioms GinibrePoincare.ComplexHermite.integral_conj_multivariateNormalized_mul_eq_prod
#print axioms GinibrePoincare.ComplexHermite.normalizedEval_inner_eq_momentSum_of_mixedMoments
#print axioms GinibrePoincare.ComplexHermite.multivariate_orthogonality_of_oneCoordinate
#print axioms GinibrePoincare.ComplexHermite.alternating_vandermonde
#print axioms GinibrePoincare.ComplexHermite.hermiteInnerMomentSum_eq
#print axioms GinibrePoincare.ComplexHermite.normalizedEval_orthogonal_of_mixedMoments
#print axioms GinibrePoincare.ComplexHermite.multivariate_orthogonality_of_mixedMoments
#print axioms GinibrePoincare.gaussian_boundedContinuous_toLp_denseRange
#print axioms GinibrePoincare.integrable_mul_configurationFourierCharacter
#print axioms GinibrePoincare.ComplexHermite.mixedMonomial_mem_normalizedEvalRectangleSpan
#print axioms GinibrePoincare.ComplexHermite.multivariateNormalizedRectangleSpan_eq_mixedMonomialRectangleSpan
#print axioms GinibrePoincare.gaussianL2LineMoment_eq_zero_of_orthogonal_hermites
#print axioms GinibrePoincare.gaussianL2FourierTest_eq_zero_of_orthogonal_hermites
#print axioms GinibrePoincare.configurationEuclideanEquiv
#print axioms GinibrePoincare.isFiniteMeasure_gaussianRealPartPositiveMeasure
#print axioms GinibrePoincare.eq_zero_of_gaussianL2FourierTest_eq_zero
#print axioms GinibrePoincare.eq_zero_of_orthogonal_hermites
#print axioms GinibrePoincare.gaussianHermiteSpan_topologicalClosure_eq_top
#print axioms GinibrePoincare.gaussianHermiteHilbertBasis
#print axioms GinibrePoincare.ComplexHermite.orthonormal_hermiteL2Family_gaussian
#print axioms GinibrePoincare.ComplexHermite.hermiteAntiDegreeProjection_apply_family
#print axioms GinibrePoincare.tsum_gaussianHermiteMode
#print axioms GinibrePoincare.tsum_norm_sq_gaussianHermiteMode
#print axioms GinibrePoincare.gaussianHermiteMode_eq_antiDegreeProjection
#print axioms GinibrePoincare.gaussianPermutationL2_comm_gaussianHermiteMode
#print axioms GinibrePoincare.gaussianHermiteMode_mem_alternating
#print axioms GinibrePoincare.gaussianHermiteCoefficient_finiteDbarComponentL2
#print axioms GinibrePoincare.hasDerivAt_realCoordinateDensity
#print axioms GinibrePoincare.realGaussianIntegrationByParts
#print axioms GinibrePoincare.complexRealSlice_gaussianIntegrationByParts
#print axioms GinibrePoincare.configurationPolynomialStarAlgebra_topologicalClosure
#print axioms GinibrePoincare.exists_configurationPolynomial_uniform_approximation
#print axioms GinibrePoincare.ComplexHermite.norm_sq_finiteHermiteCombination
#print axioms GinibrePoincare.ComplexHermite.antiDegreePieces_inner_eq_zero
#print axioms GinibrePoincare.ComplexHermite.finiteDbarEnergy_eq_sum_coordinates
#print axioms GinibrePoincare.ComplexHermite.dbarComponent_finiteHermiteFunction
#print axioms GinibrePoincare.ComplexHermite.loweredCoefficients_normSq_sum
#print axioms GinibrePoincare.ComplexHermite.sum_norm_sq_lowered_eq_finiteDbarEnergy
#print axioms GinibrePoincare.ComplexHermite.finiteHermiteCombination_coeFn
#print axioms GinibrePoincare.ComplexHermite.finiteGaussianDbarIntegralEnergy
#print axioms GinibrePoincare.ComplexHermite.norm_sq_zero_add_positive
#print axioms GinibrePoincare.ComplexHermite.finiteHermiteDeficit_eq_sum
#print axioms GinibrePoincare.ComplexHermite.finiteHermiteDeficit_eq_sum_degreeMass
#print axioms GinibrePoincare.ComplexHermite.starProjection_finiteHermiteCombination_eq_zeroPiece
#print axioms GinibrePoincare.ComplexHermite.norm_sub_degreeZeroProjection_eq_positive
#print axioms GinibrePoincare.continuous_eq_of_ae_eq_complexGaussian
#print axioms GinibrePoincare.norm_sq_centeredObservableL2
#print axioms GinibrePoincare.norm_sq_transformedCenteredObservableL2
#print axioms GinibrePoincare.dbarComponent_vandermonde
#print axioms GinibrePoincare.dbarNormSq_normalizedVandermondeTransform_mass
#print axioms GinibrePoincare.dbarNormSq_normalizedVandermondeTransform_ofReal
#print axioms GinibrePoincare.dbarNormSq_ofReal_eq_realGradientNormSq
#print axioms GinibrePoincare.integral_ginibreMeasure
#print axioms GinibrePoincare.groundStateEnergyIdentity
#print axioms GinibrePoincare.groundStateAdmissibility
#print axioms GinibrePoincare.isAlternating_polynomialVandermonde
#print axioms GinibrePoincare.alternating_polynomial_division_of_dvd
#print axioms GinibrePoincare.X_sub_X_dvd_of_alternating
#print axioms GinibrePoincare.pairwise_isRelPrime_orderedPairFactor
#print axioms GinibrePoincare.polynomialVandermonde_dvd_of_alternating
#print axioms GinibrePoincare.alternating_polynomial_vandermonde_division
#print axioms GinibrePoincare.alternating_finiteZeroAntiholomorphicHermiteSpan
#print axioms GinibrePoincare.finiteZeroAntiholomorphicHermiteSum_normalizedInverse
#print axioms GinibrePoincare.ComplexHermite.map_ginibreSymmetricHolomorphicPolynomialClosedSpan
#print axioms GinibrePoincare.ComplexHermite.gaussianAlternatingZeroModeClosedSpan_le_hermiteZeroMode
#print axioms GinibrePoincare.ComplexHermite.gaussianPermutationL2_gaussianAlternationOperator
#print axioms GinibrePoincare.ComplexHermite.gaussianAlternatingZeroModeClosedSpan_eq_hermiteZeroMode_comap
#print axioms GinibrePoincare.ComplexHermite.vandermondeEquiv_intertwines_holomorphicProjection
#print axioms GinibrePoincare.ComplexHermite.transform_ginibreSymmetricHolomorphicPart_eq_gaussianZeroMode
#print axioms GinibrePoincare.ginibreSymmetricConjugationEquiv
#print axioms GinibrePoincare.ginibreGlobalPhaseL2_symmetricConjugation
#print axioms GinibrePoincare.inner_star_eq_zero_of_positive_ginibre_phase_degree
#print axioms GinibrePoincare.vandermonde_globalPhase
#print axioms GinibrePoincare.measurePreserving_globalPhase_complexGaussianMeasure
#print axioms GinibrePoincare.measurePreserving_globalPhase_ginibreMeasure
#print axioms GinibrePoincare.gaussianGlobalPhaseL2
#print axioms GinibrePoincare.ginibreGlobalPhaseL2_finiteHomogeneousQuotient
#print axioms GinibrePoincare.integrable_realGradientNormSq_core_ginibre
#print axioms GinibrePoincare.Measure.pi_withDensity
#print axioms MeasureTheory.MeasurePreserving.map_withDensity_comp
#print axioms GinibrePoincare.complexCoordinateGaussianMeasure_eq_withDensity
#print axioms GinibrePoincare.complexGaussianDensityIdentification
#print axioms GinibrePoincare.ginibreNormalizingMass_pos
#print axioms GinibrePoincare.integrable_prod_norm_pow_complexGaussianMeasure
#print axioms GinibrePoincare.complexGaussianMixedMoment_zero_zero
#print axioms GinibrePoincare.complexGaussianMixedMoment_comm_conj
#print axioms GinibrePoincare.complexGaussianMixedMoment_formula
#print axioms GinibrePoincare.integral_angularMode_Ioc
#print axioms GinibrePoincare.integral_pow_mul_exp_neg_mul_sq_Ioi
#print axioms GinibrePoincare.mixedMonomial_polar
#print axioms GinibrePoincare.gaussianMixedIntegrand_polar
#print axioms GinibrePoincare.integral_gaussianMixedIntegrand_polar
#print axioms GinibrePoincare.integral_gaussianMixedIntegrand_polar_eq
#print axioms GinibrePoincare.integrable_prod_one_add_norm_pow_complexGaussianMeasure
#print axioms GinibrePoincare.vandermondeWeight_le_prod_one_add_norm_pow
#print axioms GinibrePoincare.ginibreNormalizingMass_lt_top
#print axioms GinibrePoincare.ginibreMassEvaluation
#print axioms GinibrePoincare.ginibreMeasureIsProbability
#print axioms GinibrePoincare.ginibreMeasure_isProbabilityMeasure
#print axioms GinibrePoincare.complexGaussianMeasure_collisionSet
#print axioms GinibrePoincare.complexGaussianMeasure_absolutelyContinuous_ginibreMeasure
#print axioms GinibrePoincare.normalizedVandermondeL2
#print axioms GinibrePoincare.normalizedVandermondeL2EquivRange
#print axioms GinibrePoincare.gaussian_measurePreserving_permute
#print axioms GinibrePoincare.ginibre_measurePreserving_permute
#print axioms GinibrePoincare.isClosed_gaussianSymmetricL2
#print axioms GinibrePoincare.isClosed_gaussianAlternatingL2
#print axioms GinibrePoincare.normalizedVandermondeL2_intertwines
#print axioms GinibrePoincare.normalizedVandermondeSymmetricL2
#print axioms GinibrePoincare.normalized_inverse_cancel_ae
#print axioms GinibrePoincare.inverseMultiplier_permute
#print axioms GinibrePoincare.inverseVandermonde_lintegral
#print axioms GinibrePoincare.inverseVandermondeL2
#print axioms GinibrePoincare.vandermondeSymmetricAlternatingEquiv
#print axioms GinibrePoincare.ginibrePregenerator_sub_const
#print axioms GinibrePoincare.norm_sq_ginibrePregeneratorL2
#print axioms GinibrePoincare.norm_sq_shiftedGinibrePregeneratorL2
#print axioms GinibrePoincare.inner_centeredObservableL2_ginibrePregeneratorL2
#print axioms GinibrePoincare.ginibreGenerator_squareCompletion
#print axioms GinibrePoincare.ginibre_second_deficit_identity_of_first
#print axioms GinibrePoincare.concrete_theoremOneNine_of_modeEnergy
#print axioms GinibrePoincare.concreteZeroMode_norm_sq_eq_holomorphicProjection
#print axioms GinibrePoincare.centeredObservableSymmetricL2
#print axioms GinibrePoincare.coe_starProjection_centeredObservableSymmetricL2
#print axioms GinibrePoincare.coe_gaussianAlternatingZeroModeProjection
#print axioms GinibrePoincare.centeredHolomorphicRemainderGeometry
#print axioms GinibrePoincare.tendsto_weighted_partialSums
#print axioms GinibrePoincare.hasSum_weighted_gaussianHermiteMode_of_coefficient_raise
#print axioms GinibrePoincare.hasSum_weighted_positiveHermiteModeMass_of_coefficient_raise
#print axioms GinibrePoincare.gaussianHermiteCoefficient_smoothDbarComponentL2_raise
#print axioms GinibrePoincare.hasSum_weighted_positiveHermiteModeMass_smoothCompact
#print axioms GinibrePoincare.concrete_weightedModeEnergy
#print axioms GinibrePoincare.transformedCenteredObservable_finiteMode_formCore
#print axioms GinibrePoincare.concrete_theoremOneNine
#print axioms GinibrePoincare.normalizedVandermondeGroundStateL2_mem_hermiteAntiDegreeClosedSpan
#print axioms GinibrePoincare.realGaussianIntegrationByParts_of_integrable

#check GinibrePoincare.SmoothGinibrePoincareStatement
#check GinibrePoincare.GaussianDbarEstimateStatement
#check GinibrePoincare.GroundStateEnergyIdentityStatement
#check GinibrePoincare.GroundStateDistanceIdentityStatement
#check GinibrePoincare.GinibreHalfDistanceStatement

#check GinibrePoincare.ComplexGaussianDensityIdentificationStatement