/- Copyright (c) 2026 Michael R. Douglas. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. # Discrete Laplacian with Lattice Spacing Defines the discrete Laplacian on both finite (periodic) and infinite lattices, parametrized by lattice spacing `a : ℝ`. Also defines the massive operator `-Δ_a + m²` and its eigenvalues on the finite lattice. ## Main definitions - `finiteLaplacian d N a` — discrete Laplacian on the finite torus - `infiniteLaplacian d a` — discrete Laplacian on ℤ^d - `massOperator d N a mass` — the massive operator `-Δ_a + m²` - `latticeEigenvalue d N a mass m` — eigenvalues of the mass operator ## Mathematical background The discrete Laplacian with spacing `a` is: `(Δ_a f)(x) = (1/a²) Σ_{i=1}^d [f(x + eᵢ) + f(x - eᵢ) - 2f(x)]` On the finite torus with periodic BC, it has eigenvalues: `λ_k = -(4/a²) Σᵢ sin²(πkᵢ/N)` The mass operator `-Δ_a + m²` is positive definite when `m > 0`. -/ import Lattice.Sites import Lattice.FiniteField import Lattice.RapidDecayLattice import Mathlib.Analysis.SpecialFunctions.Trigonometric.Basic import Mathlib.Topology.Algebra.Module.Basic noncomputable section namespace GaussianField open Real /-! ## Finite Laplacian -/ /-- The discrete Laplacian on the finite torus (ℤ/Nℤ)^d with spacing `a`. `(Δ_a f)(x) = (1/a²) Σᵢ [f(x + eᵢ) + f(x - eᵢ) - 2f(x)]` where addition is modulo N (periodic boundary conditions). -/ def finiteLaplacianFun (d N : ℕ) [NeZero N] (a : ℝ) (f : FinLatticeField d N) (x : FinLatticeSites d N) : ℝ := a⁻¹ ^ 2 * ∑ i : Fin d, (f (fun j => if j = i then x j + 1 else x j) + f (fun j => if j = i then x j - 1 else x j) - 2 * f x) /-- The finite Laplacian as a continuous linear map. Continuity is automatic since FinLatticeField d N is finite-dimensional. -/ def finiteLaplacianLM (d N : ℕ) [NeZero N] (a : ℝ) : FinLatticeField d N →ₗ[ℝ] FinLatticeField d N where toFun := finiteLaplacianFun d N a map_add' := fun f g => by funext x; simp only [finiteLaplacianFun, Pi.add_apply] rw [← mul_add, ← Finset.sum_add_distrib] congr 1; apply Finset.sum_congr rfl; intro i _; ring map_smul' := fun r f => by funext x; simp only [finiteLaplacianFun, Pi.smul_apply, smul_eq_mul, RingHom.id_apply] -- Factor r out of each summand, then pull through sum and a⁻¹² have : ∀ i : Fin d, (r * (f fun j => if j = i then x j + 1 else x j)) + (r * (f fun j => if j = i then x j - 1 else x j)) - 2 * (r * f x) = r * (((f fun j => if j = i then x j + 1 else x j) + (f fun j => if j = i then x j - 1 else x j)) - 2 * f x) := fun i => by ring simp_rw [this, ← Finset.mul_sum, ← mul_assoc, mul_comm (a⁻¹ ^ 2) r] /-- The finite Laplacian as a continuous linear map. Continuity is automatic since FinLatticeField d N is finite-dimensional. -/ noncomputable def finiteLaplacian (d N : ℕ) [NeZero N] (a : ℝ) : FinLatticeField d N →L[ℝ] FinLatticeField d N := { finiteLaplacianLM d N a with cont := (finiteLaplacianLM d N a).continuous_of_finiteDimensional } /-! ## Properties of the finite Laplacian -/ /-- The finite Laplacian is self-adjoint (symmetric matrix). Proof: exchange of summation indices using periodicity. -/ private lemma update_add_eq {d N : ℕ} [NeZero N] (x : FinLatticeSites d N) (i : Fin d) (c : ZMod N) : (fun j => if j = i then x j + c else x j) = x + Pi.single i c := by ext j; simp only [Pi.add_apply, Pi.single_apply] split_ifs with h <;> simp [h] private lemma update_sub_eq {d N : ℕ} [NeZero N] (x : FinLatticeSites d N) (i : Fin d) (c : ZMod N) : (fun j => if j = i then x j - c else x j) = x - Pi.single i c := by ext j; simp only [Pi.sub_apply, Pi.single_apply] split_ifs with h <;> simp [h] private lemma sum_mul_shift_fwd {d N : ℕ} [NeZero N] (h k : FinLatticeField d N) (v : FinLatticeSites d N) : ∑ x, h x * k (x + v) = ∑ x, h (x - v) * k x := by symm; exact Fintype.sum_equiv (Equiv.addRight (-v)) (fun x => h (x - v) * k x) (fun x => h x * k (x + v)) (fun x => by simp [sub_eq_add_neg]) private lemma sum_mul_shift_bwd {d N : ℕ} [NeZero N] (h k : FinLatticeField d N) (v : FinLatticeSites d N) : ∑ x, h x * k (x - v) = ∑ x, h (x + v) * k x := by symm; exact Fintype.sum_equiv (Equiv.addRight v) (fun x => h (x + v) * k x) (fun x => h x * k (x - v)) (fun x => by simp [add_sub_cancel_right]) /-- Helper: The Laplacian inner product for a single direction, after expanding. -/ private lemma laplacian_direction_eq {d N : ℕ} [NeZero N] (f g : FinLatticeField d N) (i : Fin d) (a : ℝ) : ∑ x, f x * (a⁻¹ ^ 2 * ((g (x + Pi.single i (1 : ZMod N)) + g (x - Pi.single i (1 : ZMod N))) - 2 * g x)) = ∑ x, a⁻¹ ^ 2 * ((f (x + Pi.single i (1 : ZMod N)) + f (x - Pi.single i (1 : ZMod N))) - 2 * f x) * g x := by -- Expand both sides into three terms have lhs_expand : ∀ x : FinLatticeSites d N, f x * (a⁻¹ ^ 2 * ((g (x + Pi.single i (1 : ZMod N)) + g (x - Pi.single i (1 : ZMod N))) - 2 * g x)) = a⁻¹ ^ 2 * (f x * g (x + Pi.single i 1)) + a⁻¹ ^ 2 * (f x * g (x - Pi.single i 1)) + a⁻¹ ^ 2 * (-(2 : ℝ) * (f x * g x)) := by intro; ring have rhs_expand : ∀ x : FinLatticeSites d N, a⁻¹ ^ 2 * ((f (x + Pi.single i (1 : ZMod N)) + f (x - Pi.single i (1 : ZMod N))) - 2 * f x) * g x = a⁻¹ ^ 2 * (f (x + Pi.single i 1) * g x) + a⁻¹ ^ 2 * (f (x - Pi.single i 1) * g x) + a⁻¹ ^ 2 * (-(2 : ℝ) * (f x * g x)) := by intro; ring simp_rw [lhs_expand, rhs_expand, Finset.sum_add_distrib, ← Finset.mul_sum] -- Diagonal terms match. Reindex the shift terms. have h1 : ∑ x, f x * g (x + Pi.single i (1 : ZMod N)) = ∑ x, f (x - Pi.single i (1 : ZMod N)) * g x := sum_mul_shift_fwd f g _ have h2 : ∑ x, f x * g (x - Pi.single i (1 : ZMod N)) = ∑ x, f (x + Pi.single i (1 : ZMod N)) * g x := sum_mul_shift_bwd f g _ rw [h1, h2]; ring /-- The finite Laplacian is self-adjoint: ⟨f, Δg⟩ = ⟨Δf, g⟩. -/ theorem finiteLaplacian_selfAdjoint (d N : ℕ) [NeZero N] (a : ℝ) (f g : FinLatticeField d N) : ∑ x, f x * (finiteLaplacian d N a g) x = ∑ x, (finiteLaplacian d N a f) x * g x := by -- Unfold to the raw function definition change ∑ x, f x * finiteLaplacianFun d N a g x = ∑ x, finiteLaplacianFun d N a f x * g x simp only [finiteLaplacianFun] simp_rw [update_add_eq, update_sub_eq] -- Pull the direction sum outside and swap with the site sum simp_rw [Finset.mul_sum, Finset.sum_mul] rw [Finset.sum_comm (s := Finset.univ) (t := Finset.univ)] conv_rhs => rw [Finset.sum_comm (s := Finset.univ) (t := Finset.univ)] congr 1; ext i exact laplacian_direction_eq f g i a /-- For each lattice direction, the inner product ∑ₓ f(x)·Δᵢf(x) equals minus a sum of squares: -(∑ₓ (f(x+eᵢ) - f(x))²). -/ private lemma direction_sum_eq_neg_sq {d N : ℕ} [NeZero N] (f : FinLatticeField d N) (i : Fin d) : ∑ x : FinLatticeSites d N, f x * (f (x + Pi.single i 1) + f (x - Pi.single i 1) - 2 * f x) = -(∑ x : FinLatticeSites d N, (f (x + Pi.single i 1) - f x) ^ 2) := by have reindex_sq : ∑ x : FinLatticeSites d N, f (x + Pi.single i 1) ^ 2 = ∑ x : FinLatticeSites d N, f x ^ 2 := Fintype.sum_equiv (Equiv.addRight (Pi.single i (1 : ZMod N))) (fun x => f (x + Pi.single i 1) ^ 2) (fun x => f x ^ 2) (fun x => by simp) have shift_bwd : ∑ x : FinLatticeSites d N, f x * f (x - Pi.single i 1) = ∑ x : FinLatticeSites d N, f (x + Pi.single i 1) * f x := sum_mul_shift_bwd f f _ have comm_sum : ∑ x : FinLatticeSites d N, f (x + Pi.single i 1) * f x = ∑ x : FinLatticeSites d N, f x * f (x + Pi.single i 1) := Finset.sum_congr rfl (fun x _ => mul_comm _ _) have lhs_eq : ∑ x : FinLatticeSites d N, f x * (f (x + Pi.single i 1) + f (x - Pi.single i 1) - 2 * f x) = (∑ x : FinLatticeSites d N, f x * f (x + Pi.single i 1)) + (∑ x : FinLatticeSites d N, f x * f (x - Pi.single i 1)) + (-2) * (∑ x : FinLatticeSites d N, f x ^ 2) := by have h1 : ∀ x : FinLatticeSites d N, f x * (f (x + Pi.single i 1) + f (x - Pi.single i 1) - 2 * f x) = f x * f (x + Pi.single i 1) + f x * f (x - Pi.single i 1) + (-2) * (f x ^ 2) := by intro; ring simp_rw [h1, Finset.sum_add_distrib, ← Finset.mul_sum] rw [lhs_eq, shift_bwd, comm_sum] have rhs_eq : -(∑ x : FinLatticeSites d N, (f (x + Pi.single i 1) - f x) ^ 2) = -(∑ x : FinLatticeSites d N, f (x + Pi.single i 1) ^ 2) + 2 * (∑ x : FinLatticeSites d N, f x * f (x + Pi.single i 1)) + (-1) * (∑ x : FinLatticeSites d N, f x ^ 2) := by have h2 : ∀ x : FinLatticeSites d N, (f (x + Pi.single i 1) - f x) ^ 2 = f (x + Pi.single i 1) ^ 2 + (-2) * (f x * f (x + Pi.single i 1)) + f x ^ 2 := by intro; ring simp_rw [h2, Finset.sum_add_distrib, ← Finset.mul_sum] ring rw [rhs_eq, reindex_sq] ring /-- The finite Laplacian is negative semidefinite: ⟨f, Δf⟩ ≤ 0. Proof: summation by parts gives -a⁻² Σᵢ Σₓ (f(x+eᵢ) - f(x))² ≤ 0. -/ theorem finiteLaplacian_neg_semidefinite (d N : ℕ) [NeZero N] (a : ℝ) (ha : 0 < a) (f : FinLatticeField d N) : ∑ x, f x * (finiteLaplacian d N a f) x ≤ 0 := by let _ha := ha change ∑ x, f x * finiteLaplacianFun d N a f x ≤ 0 simp only [finiteLaplacianFun] simp_rw [update_add_eq, update_sub_eq] -- Rewrite to a⁻¹² * ∑_i ∑_x f(x)·(D_i f)(x) and swap sums have step1 : (∑ x : FinLatticeSites d N, f x * (a⁻¹ ^ 2 * ∑ i : Fin d, (f (x + Pi.single i 1) + f (x - Pi.single i 1) - 2 * f x))) = a⁻¹ ^ 2 * ∑ i : Fin d, ∑ x : FinLatticeSites d N, (f x * (f (x + Pi.single i 1) + f (x - Pi.single i 1) - 2 * f x)) := by conv_lhs => arg 2; ext x rw [mul_comm (f x) (a⁻¹ ^ 2 * _), mul_assoc, Finset.sum_mul] rw [← Finset.mul_sum, Finset.sum_comm] congr 1; apply Finset.sum_congr rfl intro i _; apply Finset.sum_congr rfl intro x _; ring rw [step1] simp_rw [direction_sum_eq_neg_sq] apply mul_nonpos_of_nonneg_of_nonpos · exact sq_nonneg _ · exact Finset.sum_nonpos (fun i _ => neg_nonpos_of_nonneg (Finset.sum_nonneg (fun x _ => sq_nonneg _))) /-! ## Infinite Laplacian -/ /-- The ℓ¹ norm is invariant under negation. -/ private lemma latticeNorm_neg {d : ℕ} (v : Fin d → ℤ) : latticeNorm (-v) = latticeNorm v := by simp only [latticeNorm, Pi.neg_apply, Int.cast_neg, abs_neg] /-- Shifting a rapidly decaying function by a bounded vector preserves rapid decay. -/ private lemma shift_rapid_decay {d : ℕ} (f : RapidDecayLattice d) (v : Fin d → ℤ) (hv : latticeNorm v ≤ 1) (k : ℕ) : Summable (fun x => |f.val (x + v)| * (1 + latticeNorm x) ^ k) := by -- Bound: (1+‖x‖) ≤ 2(1+‖x+v‖) because ‖x‖ ≤ ‖x+v‖ + ‖v‖ ≤ ‖x+v‖ + 1 apply Summable.of_nonneg_of_le (fun x => mul_nonneg (abs_nonneg _) (RapidDecayLattice.weight_nonneg x k)) · intro x have h_norm : latticeNorm x ≤ latticeNorm (x + v) + 1 := by have h1 : latticeNorm x = latticeNorm (fun i => (x + v) i + (-v) i) := by congr 1; ext j; simp have h2 := latticeNorm_triangle (x + v) (-v) have h3 : latticeNorm (-v) = latticeNorm v := latticeNorm_neg v linarith have h_le : 1 + latticeNorm x ≤ 2 * (1 + latticeNorm (x + v)) := by have := latticeNorm_nonneg (x + v) linarith calc |f.val (x + v)| * (1 + latticeNorm x) ^ k ≤ |f.val (x + v)| * (2 * (1 + latticeNorm (x + v))) ^ k := by apply mul_le_mul_of_nonneg_left _ (abs_nonneg _) exact pow_le_pow_left₀ (by linarith [latticeNorm_nonneg x]) h_le k _ = 2 ^ k * (|f.val (x + v)| * (1 + latticeNorm (x + v)) ^ k) := by rw [mul_pow]; ring · -- The upper bound is summable: reindex y = x + v have h_sum : Summable (fun x => |f.val (x + v)| * (1 + latticeNorm (x + v)) ^ k) := by show Summable ((fun y => |f.val y| * (1 + latticeNorm y) ^ k) ∘ (· + v)) exact (Equiv.summable_iff (Equiv.addRight v)).mpr (f.rapid_decay k) exact h_sum.const_smul (2 ^ k : ℝ) /-- The raw function for the infinite Laplacian. -/ private def infiniteLaplacianFun (d : ℕ) (a : ℝ) (f : RapidDecayLattice d) (x : Fin d → ℤ) : ℝ := a⁻¹ ^ 2 * ∑ i : Fin d, (f.val (fun j => x j + stdBasisInt d i j) + f.val (fun j => x j - stdBasisInt d i j) - 2 * f.val x) /-- Tsum bound for shifted rapid decay: the weighted tsum of a shift is bounded by 2^k times the original weighted tsum. -/ private lemma shift_rapid_decay_tsum_le {d : ℕ} (f : RapidDecayLattice d) (v : Fin d → ℤ) (hv : latticeNorm v ≤ 1) (k : ℕ) : ∑' x, |f.val (x + v)| * (1 + latticeNorm x) ^ k ≤ 2 ^ k * ∑' x, |f.val x| * (1 + latticeNorm x) ^ k := by have h_pw : ∀ x : Fin d → ℤ, |f.val (x + v)| * (1 + latticeNorm x) ^ k ≤ 2 ^ k * (|f.val (x + v)| * (1 + latticeNorm (x + v)) ^ k) := by intro x have h_norm : latticeNorm x ≤ latticeNorm (x + v) + 1 := by have h1 : latticeNorm x = latticeNorm (fun i => (x + v) i + (-v) i) := by congr 1; ext j; simp have h2 := latticeNorm_triangle (x + v) (-v) have h3 : latticeNorm (-v) = latticeNorm v := latticeNorm_neg v linarith have h_le : 1 + latticeNorm x ≤ 2 * (1 + latticeNorm (x + v)) := by have := latticeNorm_nonneg (x + v) linarith calc |f.val (x + v)| * (1 + latticeNorm x) ^ k ≤ |f.val (x + v)| * (2 * (1 + latticeNorm (x + v))) ^ k := by apply mul_le_mul_of_nonneg_left _ (abs_nonneg _) exact pow_le_pow_left₀ (by linarith [latticeNorm_nonneg x]) h_le k _ = 2 ^ k * (|f.val (x + v)| * (1 + latticeNorm (x + v)) ^ k) := by rw [mul_pow]; ring -- Reindex the upper bound sum: y = x + v have h_reindex : ∑' x, |f.val (x + v)| * (1 + latticeNorm (x + v)) ^ k = ∑' y, |f.val y| * (1 + latticeNorm y) ^ k := by show ∑' x, ((fun y => |f.val y| * (1 + latticeNorm y) ^ k) (x + v)) = ∑' y, |f.val y| * (1 + latticeNorm y) ^ k exact Equiv.tsum_eq (Equiv.addRight v) (fun y => |f.val y| * (1 + latticeNorm y) ^ k) calc ∑' x, |f.val (x + v)| * (1 + latticeNorm x) ^ k ≤ ∑' x, 2 ^ k * (|f.val (x + v)| * (1 + latticeNorm (x + v)) ^ k) := (shift_rapid_decay f v hv k).tsum_le_tsum h_pw ((f.rapid_decay k).comp_injective (Equiv.addRight v).injective |>.const_smul (2 ^ k : ℝ)) _ = 2 ^ k * ∑' x, |f.val (x + v)| * (1 + latticeNorm (x + v)) ^ k := tsum_mul_left _ = 2 ^ k * ∑' y, |f.val y| * (1 + latticeNorm y) ^ k := by rw [h_reindex] /-- Summability of shifted terms for the negative basis direction. -/ private lemma shift_neg_rapid_decay {d : ℕ} (f : RapidDecayLattice d) (i : Fin d) (k : ℕ) : Summable (fun x => |f.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k) := by have hv : latticeNorm (fun j => -stdBasisInt d i j) ≤ 1 := by rw [show (fun j => -stdBasisInt d i j) = -(stdBasisInt d i) from by ext j; simp] rw [latticeNorm_neg]; exact le_of_eq (latticeNorm_stdBasis i) have h_eq : ∀ x : Fin d → ℤ, (fun j => x j - stdBasisInt d i j) = (x + fun j => -stdBasisInt d i j) := by intro x; ext j; simp [Pi.add_apply, sub_eq_add_neg] simp_rw [h_eq] exact shift_rapid_decay f _ hv k /-- Tsum bound for negative shifted rapid decay. -/ private lemma shift_neg_rapid_decay_tsum_le {d : ℕ} (f : RapidDecayLattice d) (i : Fin d) (k : ℕ) : ∑' x, |f.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k ≤ 2 ^ k * ∑' x, |f.val x| * (1 + latticeNorm x) ^ k := by have hv : latticeNorm (fun j => -stdBasisInt d i j) ≤ 1 := by rw [show (fun j => -stdBasisInt d i j) = -(stdBasisInt d i) from by ext j; simp] rw [latticeNorm_neg]; exact le_of_eq (latticeNorm_stdBasis i) show ∑' x, |f.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k ≤ 2 ^ k * ∑' x, |f.val x| * (1 + latticeNorm x) ^ k have : (fun x : Fin d → ℤ => |f.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k) = (fun x => |f.val (x + fun j => -stdBasisInt d i j)| * (1 + latticeNorm x) ^ k) := by ext x; congr 1 rw [this] exact shift_rapid_decay_tsum_le f _ hv k /-- The infinite Laplacian preserves rapid decay. -/ private lemma infiniteLaplacian_rapid_decay (d : ℕ) (a : ℝ) (f : RapidDecayLattice d) (k : ℕ) : Summable (fun x => |infiniteLaplacianFun d a f x| * (1 + latticeNorm x) ^ k) := by -- Strategy: bound |Δf(x)| * w(x) ≤ sum of shifted terms, each summable. -- Build the summable upper bound as a sum over directions have h_shift_plus : ∀ i : Fin d, Summable (fun x => |f.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k) := fun i => shift_rapid_decay f (stdBasisInt d i) (le_of_eq (latticeNorm_stdBasis i)) k have h_shift_minus : ∀ i : Fin d, Summable (fun x => |f.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k) := fun i => shift_neg_rapid_decay f i k have h_diag : Summable (fun x => |f.val x| * (1 + latticeNorm x) ^ k) := f.rapid_decay k -- The summable upper bound per direction have h_dir_summable : ∀ i : Fin d, Summable (fun x => |f.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + |f.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + 2 * (|f.val x| * (1 + latticeNorm x) ^ k)) := by intro i apply Summable.add · exact (h_shift_plus i).add (h_shift_minus i) · show Summable (fun x => (2 : ℝ) • (|f.val x| * (1 + latticeNorm x) ^ k)) exact h_diag.const_smul 2 -- Sum over all d directions is summable have h_all_summable : Summable (fun x => ∑ i : Fin d, (|f.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + |f.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + 2 * (|f.val x| * (1 + latticeNorm x) ^ k))) := summable_sum (fun i _ => h_dir_summable i) -- Scale by |a⁻¹|² have h_ub_summable : Summable (fun x => |a⁻¹| ^ 2 * ∑ i : Fin d, (|f.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + |f.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + 2 * (|f.val x| * (1 + latticeNorm x) ^ k))) := h_all_summable.const_smul (|a⁻¹| ^ 2) -- Pointwise bound for each x have h_pw : ∀ x, |infiniteLaplacianFun d a f x| * (1 + latticeNorm x) ^ k ≤ |a⁻¹| ^ 2 * ∑ i : Fin d, (|f.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + |f.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + 2 * (|f.val x| * (1 + latticeNorm x) ^ k)) := by intro x simp only [infiniteLaplacianFun] rw [abs_mul, abs_pow] have hw := RapidDecayLattice.weight_nonneg x k -- Bound |∑ ...| ≤ ∑ (|f(x+eᵢ)| + |f(x-eᵢ)| + 2|f(x)|) have h_abs_sum : |∑ i : Fin d, (f.val (fun j => x j + stdBasisInt d i j) + f.val (fun j => x j - stdBasisInt d i j) - 2 * f.val x)| ≤ ∑ i : Fin d, (|f.val (fun j => x j + stdBasisInt d i j)| + |f.val (fun j => x j - stdBasisInt d i j)| + 2 * |f.val x|) := by calc |∑ i : Fin d, _| ≤ ∑ i : Fin d, |f.val (fun j => x j + stdBasisInt d i j) + f.val (fun j => x j - stdBasisInt d i j) - 2 * f.val x| := Finset.abs_sum_le_sum_abs _ _ _ ≤ _ := by apply Finset.sum_le_sum; intro i _ set a₁ := f.val (fun j => x j + stdBasisInt d i j) set a₂ := f.val (fun j => x j - stdBasisInt d i j) calc |a₁ + a₂ - 2 * f.val x| ≤ |a₁ + a₂| + |2 * f.val x| := by have := abs_add_le (a₁ + a₂) (-(2 * f.val x)) rwa [abs_neg, ← sub_eq_add_neg] at this _ ≤ (|a₁| + |a₂|) + 2 * |f.val x| := by have := abs_add_le a₁ a₂ rw [abs_mul, abs_of_nonneg (by norm_num : (2 : ℝ) ≥ 0)] linarith -- Combine: |a⁻¹|² * |∑...| * w ≤ |a⁻¹|² * ∑(abs terms) * w = |a⁻¹|² * ∑(abs*w terms) calc |a⁻¹| ^ 2 * |∑ i : Fin d, _| * (1 + latticeNorm x) ^ k ≤ |a⁻¹| ^ 2 * (∑ i : Fin d, (|f.val (fun j => x j + stdBasisInt d i j)| + |f.val (fun j => x j - stdBasisInt d i j)| + 2 * |f.val x|)) * (1 + latticeNorm x) ^ k := by gcongr _ = |a⁻¹| ^ 2 * ∑ i : Fin d, (|f.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + |f.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + 2 * (|f.val x| * (1 + latticeNorm x) ^ k)) := by rw [mul_assoc, Finset.sum_mul] congr 1; apply Finset.sum_congr rfl; intro i _; ring exact h_ub_summable.of_nonneg_of_le (fun x => mul_nonneg (abs_nonneg _) (RapidDecayLattice.weight_nonneg x k)) h_pw /-- The infinite Laplacian as a linear map on rapid decay functions. -/ private def infiniteLaplacianLM (d : ℕ) (a : ℝ) : RapidDecayLattice d →ₗ[ℝ] RapidDecayLattice d where toFun f := ⟨infiniteLaplacianFun d a f, infiniteLaplacian_rapid_decay d a f⟩ map_add' f g := by ext x; simp only [infiniteLaplacianFun, RapidDecayLattice.add_val] rw [← mul_add, ← Finset.sum_add_distrib] congr 1; apply Finset.sum_congr rfl; intro i _; ring map_smul' r f := by ext x; simp only [infiniteLaplacianFun, RapidDecayLattice.smul_val, RingHom.id_apply] -- Factor r out of sum, commute with a⁻¹² have h_sum_eq : ∀ i : Fin d, r * f.val (fun j => x j + stdBasisInt d i j) + r * f.val (fun j => x j - stdBasisInt d i j) - 2 * (r * f.val x) = r * (f.val (fun j => x j + stdBasisInt d i j) + f.val (fun j => x j - stdBasisInt d i j) - 2 * f.val x) := fun i => by ring simp_rw [h_sum_eq, ← Finset.mul_sum, ← mul_assoc, mul_comm (a⁻¹ ^ 2) r] /-- The discrete Laplacian on ℤ^d with spacing `a`. Preserves rapid decay since it's a finite difference operator. -/ noncomputable def infiniteLaplacian (d : ℕ) (a : ℝ) : RapidDecayLattice d →L[ℝ] RapidDecayLattice d where toLinearMap := infiniteLaplacianLM d a cont := by apply WithSeminorms.continuous_of_isBounded RapidDecayLattice.lattice_withSeminorms RapidDecayLattice.lattice_withSeminorms intro k -- For each output seminorm k, bound by input seminorm k with constant -- C = |a⁻¹|² * d * (2^(k+1) + 2). Each shifted tsum ≤ 2^k * seminorm_k(f). set C_val : ℝ := |a⁻¹| ^ 2 * (↑d * (2 * 2 ^ k + 2)) have hC_nonneg : 0 ≤ C_val := by positivity refine ⟨{k}, ⟨⟨C_val, hC_nonneg⟩, fun g => ?_⟩⟩ simp only [Seminorm.comp_apply, Finset.sup_singleton] -- Goal: seminorm_k(Δg) ≤ C * seminorm_k(g) show ∑' x, |(infiniteLaplacianLM d a g).val x| * (1 + latticeNorm x) ^ k ≤ C_val * (∑' x, |g.val x| * (1 + latticeNorm x) ^ k) -- The LM value is just infiniteLaplacianFun change ∑' x, |infiniteLaplacianFun d a g x| * (1 + latticeNorm x) ^ k ≤ C_val * (∑' x, |g.val x| * (1 + latticeNorm x) ^ k) set S := ∑' x, |g.val x| * (1 + latticeNorm x) ^ k -- Pointwise bound: |Δg(x)| * w ≤ |a⁻¹|² * ∑_i (|g(x+eᵢ)|*w + |g(x-eᵢ)|*w + 2*|g(x)|*w) -- (Same as in the rapid decay proof) have h_pw : ∀ x, |infiniteLaplacianFun d a g x| * (1 + latticeNorm x) ^ k ≤ |a⁻¹| ^ 2 * ∑ i : Fin d, (|g.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + |g.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + 2 * (|g.val x| * (1 + latticeNorm x) ^ k)) := by intro x simp only [infiniteLaplacianFun] rw [abs_mul, abs_pow] have hw := RapidDecayLattice.weight_nonneg x k have h_abs_sum : |∑ i : Fin d, (g.val (fun j => x j + stdBasisInt d i j) + g.val (fun j => x j - stdBasisInt d i j) - 2 * g.val x)| ≤ ∑ i : Fin d, (|g.val (fun j => x j + stdBasisInt d i j)| + |g.val (fun j => x j - stdBasisInt d i j)| + 2 * |g.val x|) := by calc |∑ i : Fin d, _| ≤ ∑ i : Fin d, |g.val (fun j => x j + stdBasisInt d i j) + g.val (fun j => x j - stdBasisInt d i j) - 2 * g.val x| := Finset.abs_sum_le_sum_abs _ _ _ ≤ _ := by apply Finset.sum_le_sum; intro i _ set a₁ := g.val (fun j => x j + stdBasisInt d i j) set a₂ := g.val (fun j => x j - stdBasisInt d i j) calc |a₁ + a₂ - 2 * g.val x| ≤ |a₁ + a₂| + |2 * g.val x| := by have := abs_add_le (a₁ + a₂) (-(2 * g.val x)) rwa [abs_neg, ← sub_eq_add_neg] at this _ ≤ (|a₁| + |a₂|) + 2 * |g.val x| := by have := abs_add_le a₁ a₂ rw [abs_mul, abs_of_nonneg (by norm_num : (2 : ℝ) ≥ 0)] linarith calc |a⁻¹| ^ 2 * |∑ i : Fin d, _| * (1 + latticeNorm x) ^ k ≤ |a⁻¹| ^ 2 * (∑ i : Fin d, (|g.val (fun j => x j + stdBasisInt d i j)| + |g.val (fun j => x j - stdBasisInt d i j)| + 2 * |g.val x|)) * (1 + latticeNorm x) ^ k := by gcongr _ = |a⁻¹| ^ 2 * ∑ i : Fin d, (|g.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + |g.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + 2 * (|g.val x| * (1 + latticeNorm x) ^ k)) := by rw [mul_assoc, Finset.sum_mul] congr 1; apply Finset.sum_congr rfl; intro i _; ring -- Take the tsum of both sides have h_ub_summable : Summable (fun x => |a⁻¹| ^ 2 * ∑ i : Fin d, (|g.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + |g.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + 2 * (|g.val x| * (1 + latticeNorm x) ^ k))) := by apply Summable.const_smul (b := |a⁻¹| ^ 2) apply summable_sum; intro i _ apply Summable.add · exact (shift_rapid_decay g (stdBasisInt d i) (le_of_eq (latticeNorm_stdBasis i)) k).add (shift_neg_rapid_decay g i k) · show Summable (fun x => (2 : ℝ) • (|g.val x| * (1 + latticeNorm x) ^ k)) exact (g.rapid_decay k).const_smul 2 -- Step 1: tsum bound using pointwise inequality calc ∑' x, |infiniteLaplacianFun d a g x| * (1 + latticeNorm x) ^ k ≤ ∑' x, |a⁻¹| ^ 2 * ∑ i : Fin d, (|g.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + |g.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + 2 * (|g.val x| * (1 + latticeNorm x) ^ k)) := (infiniteLaplacian_rapid_decay d a g k).tsum_le_tsum h_pw h_ub_summable -- Step 2: Pull constant out and swap sum/tsum _ = |a⁻¹| ^ 2 * ∑ i : Fin d, ∑' x, (|g.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + |g.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k + 2 * (|g.val x| * (1 + latticeNorm x) ^ k)) := by rw [tsum_mul_left] congr 1 exact Summable.tsum_finsetSum (fun i _ => by apply Summable.add · exact (shift_rapid_decay g (stdBasisInt d i) (le_of_eq (latticeNorm_stdBasis i)) k).add (shift_neg_rapid_decay g i k) · show Summable (fun x => (2 : ℝ) • (|g.val x| * (1 + latticeNorm x) ^ k)) exact (g.rapid_decay k).const_smul 2) -- Step 3: Bound each direction's tsum _ ≤ |a⁻¹| ^ 2 * ∑ i : Fin d, (2 ^ k * S + 2 ^ k * S + 2 * S) := by apply mul_le_mul_of_nonneg_left _ (pow_nonneg (abs_nonneg _) 2) apply Finset.sum_le_sum; intro i _ -- Split tsum(A + B + C) ≤ tsum A + tsum B + tsum C then bound each set T_plus := fun x : Fin d → ℤ => |g.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k set T_minus := fun x : Fin d → ℤ => |g.val (fun j => x j - stdBasisInt d i j)| * (1 + latticeNorm x) ^ k set T_diag := fun x : Fin d → ℤ => 2 * (|g.val x| * (1 + latticeNorm x) ^ k) have hS_plus : Summable T_plus := by show Summable (fun x => |g.val (fun j => x j + stdBasisInt d i j)| * (1 + latticeNorm x) ^ k) exact shift_rapid_decay g (stdBasisInt d i) (le_of_eq (latticeNorm_stdBasis i)) k have hS_minus : Summable T_minus := shift_neg_rapid_decay g i k have hS_diag : Summable T_diag := by show Summable (fun x => (2 : ℝ) • (|g.val x| * (1 + latticeNorm x) ^ k)) exact (g.rapid_decay k).const_smul 2 have h_split : ∑' x, (T_plus x + T_minus x + T_diag x) = ∑' x, T_plus x + ∑' x, T_minus x + ∑' x, T_diag x := by rw [show (fun x => T_plus x + T_minus x + T_diag x) = (fun x => (T_plus x + T_minus x) + T_diag x) from by ext; ring] rw [(hS_plus.add hS_minus).tsum_add hS_diag, hS_plus.tsum_add hS_minus] rw [h_split] have h1 : ∑' x, T_plus x ≤ 2 ^ k * S := shift_rapid_decay_tsum_le g (stdBasisInt d i) (le_of_eq (latticeNorm_stdBasis i)) k have h2 : ∑' x, T_minus x ≤ 2 ^ k * S := shift_neg_rapid_decay_tsum_le g i k have h3 : ∑' x, T_diag x = 2 * S := tsum_mul_left linarith -- Step 4: Simplify constant sum _ = C_val * S := by simp only [C_val, Finset.sum_const, Finset.card_univ, nsmul_eq_mul, Fintype.card_fin] ring /-- The infinite Laplacian acts as the expected finite difference formula. -/ theorem infiniteLaplacian_apply (d : ℕ) (a : ℝ) (f : RapidDecayLattice d) (x : Fin d → ℤ) : (infiniteLaplacian d a f).val x = a⁻¹ ^ 2 * ∑ i : Fin d, (f.val (fun j => x j + stdBasisInt d i j) + f.val (fun j => x j - stdBasisInt d i j) - 2 * f.val x) := rfl /-! ## Mass operator -/ /-- The mass operator `-Δ_a + m²` on the finite lattice. This is the covariance operator's inverse in the lattice Gaussian measure. -/ def massOperator (d N : ℕ) [NeZero N] (a mass : ℝ) : FinLatticeField d N →L[ℝ] FinLatticeField d N := -finiteLaplacian d N a + mass ^ 2 • ContinuousLinearMap.id ℝ _ /-- The mass operator is positive definite when mass > 0. Proof: ⟨f, (-Δ+m²)f⟩ = -⟨f,Δf⟩ + m²‖f‖² ≥ m²‖f‖² > 0 for f ≠ 0. -/ theorem massOperator_pos_def (d N : ℕ) [NeZero N] (a mass : ℝ) (ha : 0 < a) (hmass : 0 < mass) (f : FinLatticeField d N) (hf : f ≠ 0) : 0 < ∑ x, f x * (massOperator d N a mass f) x := by simp only [massOperator, add_apply, neg_apply, smul_apply, ContinuousLinearMap.id_apply, Pi.add_apply, Pi.neg_apply, Pi.smul_apply, smul_eq_mul] have split : ∀ x : FinLatticeSites d N, f x * (-(finiteLaplacian d N a f) x + mass ^ 2 * f x) = -(f x * (finiteLaplacian d N a f) x) + mass ^ 2 * f x ^ 2 := by intro x; ring simp_rw [split, Finset.sum_add_distrib, ← Finset.mul_sum, Finset.sum_neg_distrib] have h_neg : 0 ≤ -(∑ x : FinLatticeSites d N, f x * (finiteLaplacian d N a f) x) := neg_nonneg.mpr (finiteLaplacian_neg_semidefinite d N a ha f) have h_sq_pos : 0 < ∑ x : FinLatticeSites d N, f x ^ 2 := by obtain ⟨x, hx⟩ : ∃ x, f x ≠ 0 := by by_contra h; push Not at h; exact hf (funext h) exact Finset.sum_pos' (fun x _ => sq_nonneg (f x)) ⟨x, Finset.mem_univ _, by positivity⟩ linarith [mul_pos (sq_pos_of_pos hmass) h_sq_pos] /-! ## Eigenvalues -/ /-- Eigenvalue of `-Δ_a` alone (no mass) on the finite torus. Mode index `m : ℕ` decodes to multi-index `k ∈ (ZMod N)^d` via Fintype enumeration. The eigenvalue is: `(4/a²) Σᵢ sin²(πkᵢ/N)` These are nonneg (the zero mode has eigenvalue 0). Mass is NOT included — it enters only through the mass operator and Green's function. This follows the mass-separation convention from `HeatKernel/Bilinear.lean`, ensuring correct tensor product factorization: `μ_{E₁⊗E₂} = μ_{E₁} + μ_{E₂}`. -/ def latticeLaplacianEigenvalue (d N : ℕ) [NeZero N] (a : ℝ) (m : ℕ) : ℝ := if h : m < Fintype.card (FinLatticeSites d N) then let k := (Fintype.equivFin (FinLatticeSites d N)).symm ⟨m, h⟩ (4 / a ^ 2) * ∑ i : Fin d, sin (π * (ZMod.val (k i) : ℝ) / N) ^ 2 else 0 -- default for out-of-range indices /-- Laplacian eigenvalues are nonneg. -/ theorem latticeLaplacianEigenvalue_nonneg (d N : ℕ) [NeZero N] (a : ℝ) (m : ℕ) : 0 ≤ latticeLaplacianEigenvalue d N a m := by unfold latticeLaplacianEigenvalue split_ifs with h · apply mul_nonneg (div_nonneg (by norm_num) (sq_nonneg _)) exact Finset.sum_nonneg fun _ _ => sq_nonneg _ · exact le_refl _ /-- Eigenvalue of `-Δ_a + m²` on the finite torus. Defined as `latticeLaplacianEigenvalue + mass²`. -/ def latticeEigenvalue (d N : ℕ) [NeZero N] (a mass : ℝ) (m : ℕ) : ℝ := latticeLaplacianEigenvalue d N a m + mass ^ 2 /-- `latticeEigenvalue` unfolds to the explicit formula with mass. -/ theorem latticeEigenvalue_eq (d N : ℕ) [NeZero N] (a mass : ℝ) (m : ℕ) : latticeEigenvalue d N a mass m = latticeLaplacianEigenvalue d N a m + mass ^ 2 := rfl /-- Eigenvalues are strictly positive when mass > 0. -/ theorem latticeEigenvalue_pos (d N : ℕ) [NeZero N] (a mass : ℝ) (_ha : 0 < a) (hmass : 0 < mass) (m : ℕ) : 0 < latticeEigenvalue d N a mass m := by rw [latticeEigenvalue_eq] linarith [latticeLaplacianEigenvalue_nonneg d N a m, sq_pos_of_pos hmass] end GaussianField