/- Copyright (c) 2026 Michael R. Douglas. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. # Lattice Heat Kernel Defines the heat kernel on the finite lattice as the matrix exponential of the negative Laplacian: `K_t = exp(-t · (-Δ_a))`. ## Main definitions - `negLaplacianMatrix` — the matrix `-Δ_a` (mass-free) - `latticeHeatKernelMatrix` — `K_t = exp(-t · (-Δ_a))` ## Main theorems - `latticeHeatKernelMatrix_semigroup` — `K_{s+t} = K_s · K_t` - `latticeHeatKernelMatrix_zero` — `K_0 = I` - `latticeHeatKernelMatrix_isHermitian` — `K_tᵀ = K_t` (symmetry) - `latticeHeatKernelMatrix_commute` — commutation with symmetries ## Design notes The heat kernel uses eigenvalues of `-Δ_a` alone (no mass). Mass enters only through the Green's function / propagator: `G_m = ∫₀^∞ e^{-tm²} K_t dt = (-Δ + m²)⁻¹` This follows the mass-separation convention from `HeatKernel/Bilinear.lean`, ensuring tensor product factorization: `K_t^{2D} = K_t^{1D} ⊗ K_t^{1D}`. ## References - Glimm-Jaffe, *Quantum Physics*, §6.1, §19 - Simon, *The P(φ)₂ Euclidean QFT*, Ch. I -/ import Lattice.SpectralCovariance import Mathlib.Analysis.Normed.Algebra.MatrixExponential noncomputable section -- Bridge instance: NormedSpace.exp derives NonUnitalNonAssocRing from Ring via -- Ring.toNonAssocRing.toNonUnitalNonAssocRing, but Matrix.topologicalRing uses -- Matrix.nonUnitalNonAssocRing (from NormedCommRing). They are rfl-equal, but -- Lean's TC synthesis can't unify them. This instance explicitly provides -- IsTopologicalRing with the NonUnitalNonAssocRing that NormedSpace.exp expects. instance matrix_isTopologicalRing_of_ring {n : Type*} [Fintype n] [DecidableEq n] : @IsTopologicalRing (Matrix n n ℝ) instTopologicalSpaceMatrix (@NonAssocRing.toNonUnitalNonAssocRing _ (@Ring.toNonAssocRing _ Matrix.instRing)) := Matrix.topologicalRing namespace GaussianField open Matrix -- `NormedSpace.exp` applied to matrices gives the matrix exponential -- (not `Real.exp` which is ℝ → ℝ) variable (d N : ℕ) [NeZero N] /-! ## Negative Laplacian matrix -/ /-- The matrix of `-Δ_a` (the negative Laplacian, without mass). Defined as `massOperatorMatrix` at mass = 0, which gives `(-Δ_a)(x,y) = ⟨δ_x, (-Δ_a)(δ_y)⟩`. -/ def negLaplacianMatrix (a : ℝ) : Matrix (FinLatticeSites d N) (FinLatticeSites d N) ℝ := massOperatorMatrix d N a 0 /-- `-Δ_a` is symmetric (Hermitian). -/ theorem negLaplacianMatrix_isHermitian (a : ℝ) : (negLaplacianMatrix d N a).IsHermitian := massOperatorMatrix_isHermitian d N a 0 /-! ## Heat kernel matrix -/ /-- **Lattice heat kernel matrix.** `K_t = exp(-t · (-Δ_a))` where `-Δ_a` is the negative Laplacian matrix (without mass). This is a positive semidefinite symmetric matrix for `t ≥ 0`. The matrix exponential is `exp(A) = Σ_{n=0}^∞ A^n / n!`, convergent for any matrix (finite-dimensional normed algebra). -/ def latticeHeatKernelMatrix (a t : ℝ) : Matrix (FinLatticeSites d N) (FinLatticeSites d N) ℝ := NormedSpace.exp (-t • negLaplacianMatrix d N a) /-! ## Semigroup and identity -/ /-- **Heat kernel semigroup property:** `K_{s+t} = K_s · K_t`. Proof: `exp(-(s+t)A) = exp(-sA + -tA) = exp(-sA) · exp(-tA)` since `-sA` and `-tA` commute (both are scalar multiples of `A`). -/ theorem latticeHeatKernelMatrix_semigroup (a s t : ℝ) : latticeHeatKernelMatrix d N a (s + t) = latticeHeatKernelMatrix d N a s * latticeHeatKernelMatrix d N a t := by simp only [latticeHeatKernelMatrix, neg_add, add_smul] exact Matrix.exp_add_of_commute _ _ ((Commute.refl (negLaplacianMatrix d N a)).smul_right (-t) |>.smul_left (-s)) /-- **Heat kernel at t = 0 is the identity:** `K_0 = I`. -/ theorem latticeHeatKernelMatrix_zero (a : ℝ) : latticeHeatKernelMatrix d N a 0 = 1 := by simp only [latticeHeatKernelMatrix, neg_zero, zero_smul, NormedSpace.exp_zero] /-! ## Symmetry -/ /-- **Heat kernel is symmetric:** `K_tᵀ = K_t`. Since `-Δ_a` is symmetric, so is `-t • (-Δ_a)`, and therefore so is `exp(-t · (-Δ_a))`. -/ theorem latticeHeatKernelMatrix_isHermitian (a t : ℝ) : (latticeHeatKernelMatrix d N a t).IsHermitian := by simp only [latticeHeatKernelMatrix] apply Matrix.IsHermitian.exp rw [Matrix.IsHermitian, conjTranspose_smul, star_trivial, (negLaplacianMatrix_isHermitian d N a).eq] /-! ## Commutation with symmetries -/ /-- Any matrix commuting with `-Δ_a` also commutes with the heat kernel `K_t`. This is the key structural result: proving `[U, Δ] = 0` gives heat kernel invariance for free, via Mathlib's `Commute.exp_right`. -/ theorem latticeHeatKernelMatrix_commute (a t : ℝ) (U : Matrix (FinLatticeSites d N) (FinLatticeSites d N) ℝ) (hU : Commute U (negLaplacianMatrix d N a)) : Commute U (latticeHeatKernelMatrix d N a t) := by simp only [latticeHeatKernelMatrix] exact (hU.smul_right (-t)).exp_right /-! ## Spectral expansion of the matrix exponential For a Hermitian matrix M with eigenvector basis ψ_k and eigenvalues μ_k, the matrix exponential satisfies: `exp(-t · M) ψ_j = exp(-t · μ_j) · ψ_j` and hence the bilinear form: `∑ x, f x · (exp(-tM) g) x = ∑ k, exp(-tμ_k) · c_k(f) · c_k(g)` These results use Mathlib's abstract eigenvector basis from the spectral theorem for Hermitian (real symmetric) matrices. -/ section MatrixExpSpectral variable {n : Type*} [Fintype n] [DecidableEq n] /-- Eigenvectors of a Hermitian matrix are eigenvectors of its matrix exponential. If `M ψ_j = μ_j · ψ_j`, then `exp(-t·M) ψ_j = exp(-t·μ_j) · ψ_j`. The proof uses: - Spectral theorem: `M = U · diagonal(μ) · U*` - `exp_units_conj`: `exp(U A U⁻¹) = U exp(A) U⁻¹` - `exp_diagonal`: `exp(diagonal v) = diagonal(exp v)` -/ theorem Matrix.IsHermitian.mulVec_exp_neg_smul {M : Matrix n n ℝ} (hM : M.IsHermitian) (t : ℝ) (j : n) : (NormedSpace.exp ((-t) • M)) *ᵥ ⇑(hM.eigenvectorBasis j) = Real.exp (-t * hM.eigenvalues j) • ⇑(hM.eigenvectorBasis j) := by set U := hM.eigenvectorUnitary have hspec := hM.spectral_theorem simp only [RCLike.ofReal_real_eq_id] at hspec -- -t • M = conjStarAlgAut U (-t • diagonal eigenvalues) have hsmul : (-t) • M = Unitary.conjStarAlgAut ℝ (Matrix n n ℝ) U ((-t) • diagonal (id ∘ hM.eigenvalues)) := by rw [map_smul, ← hspec] -- Key: eigenvector equation M *ᵥ ψ_j = λ_j • ψ_j -- implies (-t•M) *ᵥ ψ_j = (-t*λ_j) • ψ_j -- implies exp(-t•M) *ᵥ ψ_j = exp(-t*λ_j) • ψ_j -- We prove this via spectral decomposition: M = U * diag(λ) * U* set D := diagonal (id ∘ hM.eigenvalues) set y := Unitary.toUnits U -- exp(-t • diag(λ)) = diag(exp(-t * λ)) have hexp_diag : NormedSpace.exp ((-t) • D) = diagonal (fun i => NormedSpace.exp ((-t) * hM.eigenvalues i)) := by rw [← Matrix.diagonal_smul, Matrix.exp_diagonal]; congr 1; ext i; simp -- Connect star U with (y⁻¹).val have hinv_star : (y⁻¹ : (Matrix n n ℝ)ˣ).val = star (U : Matrix n n ℝ) := by simp [y, Unitary.toUnits] have hval_U : y.val = (U : Matrix n n ℝ) := rfl -- -t • M = y.val * (-t • D) * (y⁻¹).val have hsmul' : (-t) • M = y.val * ((-t) • D) * (y⁻¹ : (Matrix n n ℝ)ˣ).val := by rw [hsmul, Unitary.conjStarAlgAut_apply, hinv_star, hval_U] -- exp(-t•M) = y.val * exp(-t • D) * (y⁻¹).val have hexp : NormedSpace.exp ((-t) • M) = y.val * NormedSpace.exp ((-t) • D) * (y⁻¹ : (Matrix n n ℝ)ˣ).val := by rw [hsmul']; exact Matrix.exp_units_conj y _ -- Apply mulVec to eigenvector ψ_j rw [hexp, hexp_diag, hinv_star] -- (↑y * diag * star ↑U) *ᵥ ψ_j = ↑y *ᵥ (diag *ᵥ (star ↑U *ᵥ ψ_j)) rw [← Matrix.mulVec_mulVec, ← Matrix.mulVec_mulVec] rw [hM.star_eigenvectorUnitary_mulVec j] -- Keep as mulVec_mulVec; don't apply diagonal_mulVec_single -- Goal before simp: ↑y *ᵥ (diag *ᵥ Pi.single j 1) = exp(-t*λ_j) • ψ_j -- Instead: rewrite diag as scalar * I applied to Pi.single j -- Simpler: use mulVec_smul after converting Pi.single j c to c • Pi.single j 1 rw [Matrix.diagonal_mulVec_single, show (fun i => NormedSpace.exp ((-t) * hM.eigenvalues i)) j * (1 : ℝ) = NormedSpace.exp ((-t) * hM.eigenvalues j) from by simp] rw [show (Pi.single j (NormedSpace.exp ((-t) * hM.eigenvalues j)) : n → ℝ) = NormedSpace.exp ((-t) * hM.eigenvalues j) • (Pi.single j (1 : ℝ) : n → ℝ) from by funext i; simp [Pi.single_apply, smul_eq_mul]] rw [Matrix.mulVec_smul, hval_U, hM.eigenvectorUnitary_mulVec j] congr 1; exact congr_fun Real.exp_eq_exp_ℝ.symm _ /-- Inner product of eigenvector with exp(-tM)g extracts the eigenvalue factor. -/ theorem Matrix.IsHermitian.eigenCoeff_exp_neg_smul {M : Matrix n n ℝ} (hM : M.IsHermitian) (t : ℝ) (g : n → ℝ) (k : n) : (∑ x : n, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * ((NormedSpace.exp ((-t) • M)) *ᵥ g) x) = Real.exp (-t * hM.eigenvalues k) * (∑ x : n, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * g x) := by -- exp(-tM) is symmetric, so ψ_k^T exp(-tM) g = (exp(-tM) ψ_k)^T g have hHerm : (NormedSpace.exp ((-t) • M)).IsHermitian := by apply Matrix.IsHermitian.exp rw [Matrix.IsHermitian, conjTranspose_smul, star_trivial, hM.eq] -- Rewrite as dotProduct and use symmetry of exp(-tM) to swap change dotProduct (⇑(hM.eigenvectorBasis k)) ((NormedSpace.exp ((-t) • M)) *ᵥ g) = _ rw [Matrix.dotProduct_mulVec] -- ψ_k ᵥ* exp(-t•M) = exp(-t•M) *ᵥ ψ_k (using symmetry) rw [show (NormedSpace.exp ((-t) • M)) = (NormedSpace.exp ((-t) • M))ᵀ from by rw [← Matrix.conjTranspose_eq_transpose_of_trivial]; exact hHerm.eq.symm, Matrix.vecMul_transpose] -- dotProduct (exp(-t•M) *ᵥ ψ_k) g = exp(-t*λ_k) * dotProduct ψ_k g rw [Matrix.IsHermitian.mulVec_exp_neg_smul hM t k] simp [dotProduct, smul_eq_mul, Finset.mul_sum, mul_comm, mul_left_comm] /-- **Spectral expansion of the matrix exponential bilinear form.** For a Hermitian matrix M: `∑ x, f x * (exp(-tM) g) x = ∑ k, exp(-tμ_k) * c_k(f) * c_k(g)` where `c_k(f) = ∑ x, ψ_k(x) * f(x)` are the eigenvector coefficients. -/ theorem Matrix.IsHermitian.bilinear_exp_eq_spectral {M : Matrix n n ℝ} (hM : M.IsHermitian) (t : ℝ) (f g : n → ℝ) : (∑ x : n, f x * ((NormedSpace.exp ((-t) • M)) *ᵥ g) x) = ∑ k : n, Real.exp (-t * hM.eigenvalues k) * (∑ x : n, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * f x) * (∑ x : n, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * g x) := by set h := (NormedSpace.exp ((-t) • M)) *ᵥ g let uf : EuclideanSpace ℝ n := (EuclideanSpace.equiv n ℝ).symm f let uh : EuclideanSpace ℝ n := (EuclideanSpace.equiv n ℝ).symm h have hparseval := OrthonormalBasis.sum_inner_mul_inner (hM.eigenvectorBasis) uf uh have hinner_fh : @inner ℝ _ _ uf uh = ∑ x : n, f x * h x := by change uh.ofLp ⬝ᵥ star uf.ofLp = _ simp [uf, uh, dotProduct, star_trivial, mul_comm] have hcoeff_f : ∀ k, @inner ℝ _ _ uf (hM.eigenvectorBasis k) = ∑ x, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * f x := by intro k change (hM.eigenvectorBasis k).ofLp ⬝ᵥ star uf.ofLp = _ simp [uf, dotProduct, star_trivial, mul_comm] have hcoeff_h : ∀ k, @inner ℝ _ _ (hM.eigenvectorBasis k) uh = ∑ x, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * h x := by intro k change uh.ofLp ⬝ᵥ star (hM.eigenvectorBasis k).ofLp = _ simp [uh, dotProduct, star_trivial, mul_comm] have heigen : ∀ k, ∑ x, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * h x = Real.exp (-t * hM.eigenvalues k) * ∑ x, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * g x := fun k => Matrix.IsHermitian.eigenCoeff_exp_neg_smul hM t g k calc ∑ x, f x * h x = @inner ℝ _ _ uf uh := hinner_fh.symm _ = ∑ k, @inner ℝ _ _ uf (hM.eigenvectorBasis k) * @inner ℝ _ _ (hM.eigenvectorBasis k) uh := hparseval.symm _ = ∑ k, (∑ x, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * f x) * (∑ x, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * h x) := by refine Finset.sum_congr rfl ?_; intro k _; rw [hcoeff_f, hcoeff_h] _ = ∑ k, (∑ x, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * f x) * (Real.exp (-t * hM.eigenvalues k) * ∑ x, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * g x) := by refine Finset.sum_congr rfl ?_; intro k _; rw [heigen] _ = ∑ k, Real.exp (-t * hM.eigenvalues k) * (∑ x, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * f x) * (∑ x, (hM.eigenvectorBasis k : EuclideanSpace ℝ n) x * g x) := by refine Finset.sum_congr rfl ?_; intro k _; ring set_option linter.unusedSectionVars false in /-- **Symmetry of Hermitian matrix bilinear form.** For a real symmetric (Hermitian) matrix M: `(M *ᵥ u) ⬝ᵥ w = u ⬝ᵥ (M *ᵥ w)`. -/ theorem Matrix.IsHermitian.dotProduct_mulVec_comm {M : Matrix n n ℝ} (hM : M.IsHermitian) (u w : n → ℝ) : dotProduct (M.mulVec u) w = dotProduct u (M.mulVec w) := by rw [Matrix.dotProduct_mulVec] congr 1 have hMT : M = Mᵀ := by rw [← Matrix.conjTranspose_eq_transpose_of_trivial]; exact hM.eq.symm symm; conv_lhs => rw [hMT] exact Matrix.vecMul_transpose M u /-- **Eigenspace orthogonality for Hermitian matrices.** If M is Hermitian with eigenvectors v (eigenvalue μ) and w (eigenvalue λ ≠ μ), then `v ⬝ᵥ w = 0`. -/ theorem Matrix.IsHermitian.dotProduct_eigenvectors_eq_zero {M : Matrix n n ℝ} (hM : M.IsHermitian) {v w : n → ℝ} {μ ν : ℝ} (hv : M.mulVec v = μ • v) (hw : M.mulVec w = ν • w) (hne : μ ≠ ν) : dotProduct v w = 0 := by -- μ ⟨v, w⟩ = ⟨Mv, w⟩ = ⟨v, Mw⟩ = ν ⟨v, w⟩ have lhs : μ * dotProduct v w = dotProduct (M.mulVec v) w := by rw [hv]; simp [dotProduct, smul_eq_mul, Finset.mul_sum] refine Finset.sum_congr rfl fun i _ => ?_; ring have rhs : dotProduct (M.mulVec v) w = ν * dotProduct v w := by rw [Matrix.IsHermitian.dotProduct_mulVec_comm hM, hw] simp [dotProduct, smul_eq_mul, Finset.mul_sum] refine Finset.sum_congr rfl fun i _ => ?_; ring have : (μ - ν) * dotProduct v w = 0 := by linarith [lhs, rhs] exact (mul_eq_zero.mp this).resolve_left (sub_ne_zero.mpr hne) /-- **Matrix exponential maps any eigenvector of a Hermitian matrix.** If `M v = μ • v` and M is Hermitian, then `exp(-t·M) v = exp(-t·μ) • v`. The proof uses `bilinear_exp_eq_spectral` to compute `w ⬝ᵥ (exp(-tM) v)` for all w, and eigenspace orthogonality to identify all Mathlib eigenvector coefficients. -/ theorem Matrix.IsHermitian.mulVec_exp_of_eigenvector {M : Matrix n n ℝ} (hM : M.IsHermitian) (t : ℝ) {v : n → ℝ} {μ : ℝ} (hv : M.mulVec v = μ • v) : (NormedSpace.exp ((-t) • M)).mulVec v = Real.exp (-t * μ) • v := by set ψ := hM.eigenvectorBasis -- Strategy: show ∑_x w(x) · (exp(-tM) v)(x) = ∑_x w(x) · (exp(-tμ) · v)(x) -- for all w, then extract each component. suffices h_all : ∀ w : n → ℝ, (∑ x, w x * ((NormedSpace.exp ((-t) • M)).mulVec v) x) = (∑ x, w x * (Real.exp (-t * μ) * v x)) by ext i have := h_all (Pi.single i 1) simp only [Pi.single_apply, boole_mul] at this rw [Finset.sum_ite_eq', Finset.sum_ite_eq', if_pos (Finset.mem_univ i), if_pos (Finset.mem_univ i)] at this simp only [Pi.smul_apply, smul_eq_mul] exact this intro w -- LHS: use bilinear_exp_eq_spectral rw [Matrix.IsHermitian.bilinear_exp_eq_spectral hM t w v] -- Transform RHS: ∑ x, w x * (exp * v x) → exp * ∑ x, w x * v x → spectral simp_rw [show ∀ x, w x * (Real.exp (-t * μ) * v x) = Real.exp (-t * μ) * (w x * v x) from fun x => by ring] rw [← Finset.mul_sum] -- Use Parseval on ⟨w, v⟩ (obtained from bilinear_exp_eq_spectral at t = 0) have hparseval : (∑ x, w x * v x) = ∑ k, (∑ x, (ψ k : EuclideanSpace ℝ n) x * w x) * (∑ x, (ψ k : EuclideanSpace ℝ n) x * v x) := by have := Matrix.IsHermitian.bilinear_exp_eq_spectral hM 0 w v simp only [neg_zero, zero_smul, NormedSpace.exp_zero, Matrix.one_mulVec, zero_mul, Real.exp_zero, one_mul] at this exact this rw [hparseval, Finset.mul_sum] -- Goal: ∑ k, exp(-tμ_k) (ψ_k·w)(ψ_k·v) = ∑ k, exp(-tμ) ((ψ_k·w)(ψ_k·v)) refine Finset.sum_congr rfl fun k _ => ?_ by_cases hk : hM.eigenvalues k = μ · rw [hk]; ring · -- ψ_k·v = 0 by eigenspace orthogonality have h_ortho : dotProduct (⇑(ψ k)) v = 0 := Matrix.IsHermitian.dotProduct_eigenvectors_eq_zero hM (hM.mulVec_eigenvectorBasis k) hv hk rw [show (∑ x, (ψ k : EuclideanSpace ℝ n) x * v x) = dotProduct (⇑(ψ k)) v from rfl, h_ortho, mul_zero, mul_zero, mul_zero] end MatrixExpSpectral end GaussianField