/- Copyright (c) 2025 Michael R. Douglas, Sarah Hoback, Anna Mei, Ron Nissim. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Michael R. Douglas, Sarah Hoback, Anna Mei, Ron Nissim -/ import Mathlib.Tactic import Mathlib.Analysis.Calculus.BumpFunction.Convolution import Mathlib.MeasureTheory.Measure.ProbabilityMeasure import Mathlib.MeasureTheory.Function.LocallyIntegrable import Mathlib.Order.Filter.Basic import OSforGFF.Spacetime.Basic import OSforGFF.Schwinger.Defs /-! ## Schwinger Two-Point Function This file defines the two-point Schwinger function S₂(x) = ⟨φ(x)φ(0)⟩ as the limit of smeared correlations as the smearing functions approach Dirac deltas. For mollifiers φ_ε (smooth, nonnegative, integral 1, support shrinking to 0): S₂(x) := lim_{ε→0} SchwingerFunction₂ dμ (φ_ε(·-x)) (φ_ε) = lim_{ε→0} ∫∫ φ_ε(u-x) ⟨φ(u)φ(v)⟩ φ_ε(v) du dv For the GFF with covariance kernel C, this equals C(x) by `double_mollifier_convergence`. -/ open MeasureTheory open scoped MeasureTheory noncomputable section /-- If f(n+1) → L, then f(n) → L. This is because atTop is shift-invariant. -/ private lemma tendsto_of_tendsto_succ {α : Type*} {f : ℕ → α} {L : Filter α} (h : Filter.Tendsto (fun n => f (n + 1)) Filter.atTop L) : Filter.Tendsto f Filter.atTop L := (Filter.tendsto_add_atTop_iff_nat 1).mp h /-! ### Two-Point Schwinger Function Infrastructure -/ /-- Convert a ContDiffBump centered at 0 to a normalized Schwartz function. This produces the L¹-normalized version φ.normed volume, which integrates to 1. Bump functions have compact support and are smooth, so they are Schwartz. -/ noncomputable def bumpToSchwartz (φ : ContDiffBump (0 : SpaceTime)) : TestFunction := -- The normed bump has compact support and is C^∞, hence Schwartz (φ.hasCompactSupport_normed (μ := volume)).toSchwartzMap φ.contDiff_normed /-- bumpToSchwartz produces the L¹-normalized bump function. -/ @[simp] theorem bumpToSchwartz_apply (φ : ContDiffBump (0 : SpaceTime)) (x : SpaceTime) : bumpToSchwartz φ x = φ.normed volume x := rfl /-- Translate a Schwartz function by a vector. This is an alias for `SchwartzMap.translate` specialized to SpaceTime. Translation preserves smoothness and decay properties. See `SchwartzMap.translate` in FunctionalAnalysis.lean for the general version. -/ noncomputable def translateSchwartz (f : TestFunction) (a : SpaceTime) : TestFunction := f.translate a /-- The smeared two-point function using a bump function. This is well-defined (modulo bumpToSchwartz) and converges to the pointwise value as the bump width → 0. SmearedTwoPointFunction dμ φ x = ∫∫ φ(u-x) ⟨φ(u)φ(v)⟩ φ(v) du dv -/ noncomputable def SmearedTwoPointFunction (dμ_config : ProbabilityMeasure FieldConfiguration) (φ : ContDiffBump (0 : SpaceTime)) (x : SpaceTime) : ℝ := SchwingerFunction₂ dμ_config (translateSchwartz (bumpToSchwartz φ) x) (bumpToSchwartz φ) /-- A canonical sequence of bump functions with rOut → 0. We use rOut = 1/n for n ∈ ℕ⁺. -/ noncomputable def standardBumpSequence (n : ℕ) (hn : n ≠ 0) : ContDiffBump (0 : SpaceTime) := -- Create a bump with rOut = 1/n and rIn = 1/(2n) { rIn := 1 / (2 * n) rOut := 1 / n rIn_pos := by positivity rIn_lt_rOut := by have hn' : (0 : ℝ) < n := Nat.cast_pos.mpr (Nat.pos_of_ne_zero hn) have h2n : (0 : ℝ) < 2 * n := by positivity have : (2 * (n : ℝ))⁻¹ < (n : ℝ)⁻¹ := inv_strictAnti₀ hn' (by linarith) simp only [one_div] exact this } /-- Two-point correlation function defined as the limit of smeared correlations. **Definition**: S₂(x) := lim_{n→∞} SmearedTwoPointFunction dμ (φ_{1/n}) x where φ_ε is a standard bump function with outer radius ε. This replaces the old DiracDelta-based definition, which was conceptually correct but used sorry since delta functions are distributions, not test functions. **Regularization at coincident points**: At x = 0, the two-point function is mathematically undefined (it would be infinite for most QFTs). We regularize by setting S₂(0) = 0, which is consistent with the convention used in freeCovarianceKernel and makes the decay bounds hold trivially at x = 0. For the GFF, this limit equals freeCovarianceKernel(x) by `double_mollifier_convergence`. -/ noncomputable def SchwingerTwoPointFunction (dμ_config : ProbabilityMeasure FieldConfiguration) (x : SpaceTime) : ℝ := -- Regularize at coincident points: S₂(0) = 0 if x = 0 then 0 else -- Use the filter limit along the sequence of bump functions -- The limit exists for "good" measures (those with continuous covariance kernels away from 0) Filter.limUnder Filter.atTop (fun n : ℕ => if hn : n = 0 then 0 else SmearedTwoPointFunction dμ_config (standardBumpSequence n hn) x) /-- SchwingerTwoPointFunction vanishes at coincident points by definition. -/ @[simp] theorem schwingerTwoPointFunction_zero (dμ_config : ProbabilityMeasure FieldConfiguration) : SchwingerTwoPointFunction dμ_config 0 = 0 := by unfold SchwingerTwoPointFunction simp only [ite_true] /-- The smeared two-point function converges to SchwingerTwoPointFunction as bump width → 0. This justifies the limit-based definition of SchwingerTwoPointFunction. For measures with continuous covariance kernels (like the GFF), the limit exists and equals the kernel value. **Key hypothesis**: We assume there exists a continuous (away from 0) kernel C such that SchwingerFunction₂ computes the double integral against C. This holds for Gaussian measures where C is the covariance kernel. The proof uses `double_mollifier_convergence` from FunctionalAnalysis.lean. -/ theorem smearedTwoPoint_tendsto_schwingerTwoPoint (dμ_config : ProbabilityMeasure FieldConfiguration) (x : SpaceTime) (hx : x ≠ 0) {ι : Type*} {l : Filter ι} [l.NeBot] (φ : ι → ContDiffBump (0 : SpaceTime)) (hφ : Filter.Tendsto (fun i => (φ i).rOut) l (nhds 0)) -- Key hypothesis: there exists an underlying continuous kernel (C : SpaceTime → ℝ) (hC : ContinuousOn C {y | y ≠ 0}) -- The SchwingerFunction₂ computes the double integral against C (hS₂ : ∀ (f g : TestFunction), SchwingerFunction₂ dμ_config f g = ∫ u, ∫ v, f u * C (u - v) * g v) : Filter.Tendsto (fun i => SmearedTwoPointFunction dμ_config (φ i) x) l (nhds (C x)) := by -- The SmearedTwoPointFunction is SchwingerFunction₂ with mollifiers -- By hS₂, this equals ∫∫ φ(u-x) C(u-v) φ(v) du dv -- By double_mollifier_convergence, this → C(x) simp only [SmearedTwoPointFunction] -- Rewrite using hS₂ have h_eq : ∀ i, SchwingerFunction₂ dμ_config (translateSchwartz (bumpToSchwartz (φ i)) x) (bumpToSchwartz (φ i)) = ∫ u, ∫ v, (translateSchwartz (bumpToSchwartz (φ i)) x) u * C (u - v) * (bumpToSchwartz (φ i)) v := by intro i exact hS₂ _ _ simp_rw [h_eq] -- bumpToSchwartz produces the normed bump, so we can directly apply double_mollifier_convergence -- translateSchwartz is SchwartzMap.translate, which shifts by x simp only [translateSchwartz, SchwartzMap.translate_apply, bumpToSchwartz_apply] -- Now apply double_mollifier_convergence with the Schwartz functions exact double_mollifier_convergence C hC x hx φ hφ /-- For measures with a continuous kernel C, the SchwingerTwoPointFunction equals C(x). This is the key result: if the measure has an underlying continuous covariance kernel, then the limit-based definition of SchwingerTwoPointFunction evaluates to that kernel. Note: For x = 0, the SchwingerTwoPointFunction is defined to be 0 by regularization, so this theorem requires x ≠ 0. -/ theorem schwingerTwoPointFunction_eq_kernel (dμ_config : ProbabilityMeasure FieldConfiguration) (x : SpaceTime) (hx : x ≠ 0) (C : SpaceTime → ℝ) (hC : ContinuousOn C {y | y ≠ 0}) (hS₂ : ∀ (f g : TestFunction), SchwingerFunction₂ dμ_config f g = ∫ u, ∫ v, f u * C (u - v) * g v) : SchwingerTwoPointFunction dμ_config x = C x := by unfold SchwingerTwoPointFunction simp only [hx, ↓reduceIte] -- unfold the if x = 0 case -- By smearedTwoPoint_tendsto_schwingerTwoPoint, the sequence converges to C x have h_tendsto : Filter.Tendsto (fun n : ℕ => if hn : n = 0 then 0 else SmearedTwoPointFunction dμ_config (standardBumpSequence n hn) x) Filter.atTop (nhds (C x)) := by -- For n ≥ 1, apply smearedTwoPoint_tendsto_schwingerTwoPoint -- standardBumpSequence n has rOut = 1/n → 0 -- Define φ indexed by ℕ+ using (n+1) to avoid the n=0 issue -- φ n = standardBumpSequence (n+1) _, so φ n has rOut = 1/(n+1) let φ : ℕ → ContDiffBump (0 : SpaceTime) := fun n => standardBumpSequence (n + 1) (Nat.succ_ne_zero n) -- The rOut of this sequence tends to 0: 1/(n+1) → 0 have hφ_rOut : Filter.Tendsto (fun n => (φ n).rOut) Filter.atTop (nhds 0) := by simp only [φ, standardBumpSequence] have h1 : ∀ n : ℕ, (1 : ℝ) / ↑(n + 1) = 1 / (↑n + 1) := fun n => by norm_cast simp_rw [h1] exact tendsto_one_div_add_atTop_nhds_zero_nat -- Apply smearedTwoPoint_tendsto_schwingerTwoPoint to φ have h_smeared : Filter.Tendsto (fun n => SmearedTwoPointFunction dμ_config (φ n) x) Filter.atTop (nhds (C x)) := smearedTwoPoint_tendsto_schwingerTwoPoint dμ_config x hx φ hφ_rOut C hC hS₂ -- Key observation: for n ≥ 1, the original sequence at n equals φ(n-1) -- original(n) = SmearedTwo (standardBumpSequence n) = SmearedTwo (φ (n-1)) when n ≥ 1 -- Since φ(n-1) = standardBumpSequence n for n ≥ 1 -- We use Filter.tendsto_atTop_add_const_nat: -- If Tendsto f atTop L, then Tendsto (f ∘ (· + k)) atTop L -- Equivalently: Tendsto (fun n => f (n + k)) atTop L -- We have h_smeared: Tendsto (fun n => SmearedTwo (φ n)) atTop (nhds (C x)) -- This means: Tendsto (fun n => SmearedTwo (standardBumpSequence (n+1))) atTop (nhds (C x)) -- The original sequence for n ≥ 1 is: SmearedTwo (standardBumpSequence n) -- Let f(n) = original(n+1) = SmearedTwo (standardBumpSequence (n+1)) = SmearedTwo (φ n) -- So h_smeared says f → C(x) -- Now original = f ∘ pred (for n ≥ 1), i.e., original(n) = f(n-1) for n ≥ 1 -- Since atTop is cofinal under (·-1) for n ≥ 1, original → C(x) -- Use tendsto_of_tendsto_succ: if f(n+1) → L then f(n) → L -- We show that original(n+1) = (SmearedTwo ∘ φ)(n), so original(n+1) → C(x) -- Then by tendsto_of_tendsto_succ, original(n) → C(x) apply tendsto_of_tendsto_succ -- Goal: Tendsto (fun n => original(n+1)) atTop (nhds (C x)) -- original(n+1) = if (n+1)=0 then 0 else SmearedTwo (standardBumpSequence (n+1)) -- = SmearedTwo (standardBumpSequence (n+1)) [since n+1 ≠ 0] -- = SmearedTwo (φ n) simp only [Nat.succ_ne_zero, dite_false] exact h_smeared -- In Hausdorff spaces, limUnder equals the limit when it exists exact Filter.Tendsto.limUnder_eq h_tendsto end