/-
Copyright (c) 2026 Michael R. Douglas. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

# Spectral Theorem for Compact Self-Adjoint Operators

Proves the spectral theorem for compact self-adjoint operators on
real Hilbert spaces with no custom axioms — all results are fully proved
using only Mathlib.

Key proved lemmas:
- `compact_selfAdjoint_hasEigenvector` (proved via maximizing sequence + T² approach)
- `compact_selfAdjoint_orthogonalComplement_iSup_eigenspaces_eq_bot` (proved via restrict-to-complement)

## Main result

`compact_selfAdjoint_spectral`: For any compact self-adjoint T on a real
Hilbert space, there exist a HilbertBasis of eigenvectors and eigenvalues
μ_ι → 0 such that T = ∑ μ_ι ⟨e_ι, ·⟩ e_ι.

## References

- Reed-Simon, "Methods of Modern Mathematical Physics" Vol. 1, Thm VI.11, VI.15, VI.16
- Conway, "A Course in Functional Analysis", Thm II.5.1, II.5.7
- Brezis, "Functional Analysis", Thm 6.11
-/

import Mathlib.Analysis.InnerProductSpace.Rayleigh
import Mathlib.Analysis.InnerProductSpace.Projection.Submodule
import Mathlib.Analysis.InnerProductSpace.Spectrum
import Mathlib.Analysis.InnerProductSpace.Adjoint
import Mathlib.Analysis.Normed.Operator.Compact.Basic
import Mathlib.Analysis.SpecificLimits.Basic
import Mathlib.Tactic.Module
import Mathlib.Topology.Algebra.InfiniteSum.Module
import Mathlib.Analysis.InnerProductSpace.l2Space

noncomputable section

namespace GaussianField

open scoped InnerProductSpace
open LinearMap Submodule Filter Metric

universe u
variable {E : Type u} [NormedAddCommGroup E] [InnerProductSpace ℝ E] [CompleteSpace E]

/-! ### Helper: Eigenvector existence (explicit form)

This helper proves existence of an eigenvector with the explicit form
needed by the eigenspace spanning proof. The eigenvalue is ±‖T‖.
Proof adapted from CompactEigenvector.lean in aqft2. -/

set_option maxHeartbeats 800000 in
private theorem hasEigenvector_aux
    [Nontrivial E]
    (T : E →L[ℝ] E) (hT : IsSelfAdjoint T) (hK : IsCompactOperator T) (hne : T ≠ 0) :
    ∃ (μ : ℝ) (x : E), x ≠ 0 ∧ (T : E →ₗ[ℝ] E) x = μ • x ∧ |μ| = ‖T‖ := by
  have hα_pos : (0 : ℝ) < ‖T‖ := norm_pos_iff.mpr hne
  have hα_ne : (‖T‖ : ℝ) ≠ 0 := ne_of_gt hα_pos
  have hα2_pos : (0 : ℝ) < ‖T‖ ^ 2 := by positivity
  have hα2_ne : (‖T‖ ^ 2 : ℝ) ≠ 0 := ne_of_gt hα2_pos
  set α := ‖T‖ with hα_def
  have hT_sym : (T : E →ₗ[ℝ] E).IsSymmetric :=
    ContinuousLinearMap.isSelfAdjoint_iff_isSymmetric.mp hT
  -- Step 1: Maximizing sequence for ‖Tx‖
  have hseq : ∀ n : ℕ, ∃ x : E, ‖x‖ < 1 ∧ α - 1 / ((n : ℝ) + 1) < ‖T x‖ := by
    intro n
    exact T.exists_lt_apply_of_lt_opNorm (by linarith [show (0:ℝ) < 1/((n:ℝ)+1) from by positivity])
  choose x hx_norm hx_lb using hseq
  -- Step 2: Extract convergent subsequence Tx(φ n) → y
  have hcpt : IsCompact (closure (T '' closedBall (0 : E) 1)) :=
    hK.isCompact_closure_image_closedBall 1
  have hTx_mem : ∀ n, T (x n) ∈ closure (T '' closedBall (0 : E) 1) := by
    intro n
    apply subset_closure
    exact Set.mem_image_of_mem T (mem_closedBall_zero_iff.mpr (hx_norm n).le)
  obtain ⟨y, _, φ, hφ, hTxφ⟩ := hcpt.isSeqCompact hTx_mem
  -- Key: ‖y‖ = α
  have hy_norm : ‖y‖ = α := by
    have hTxφ_norm := (continuous_norm.tendsto y).comp hTxφ
    have hle : ‖y‖ ≤ α := by
      apply le_of_tendsto hTxφ_norm
      apply Filter.Eventually.of_forall; intro n
      calc ‖T (x (φ n))‖ ≤ α * ‖x (φ n)‖ := T.le_opNorm _
        _ ≤ α * 1 := by gcongr; exact (hx_norm _).le
        _ = α := mul_one _
    have hge : α ≤ ‖y‖ := by
      have hf_lb : ∀ n : ℕ, α - 1 / ((n : ℝ) + 1) ≤ ‖T (x (φ n))‖ := by
        intro n
        have h1 := hx_lb (φ n)
        have hφn : (n : ℝ) ≤ (φ n : ℝ) := by exact_mod_cast hφ.id_le n
        have : 1 / ((φ n : ℝ) + 1) ≤ 1 / ((n : ℝ) + 1) :=
          div_le_div_of_nonneg_left (by positivity) (by linarith) (by linarith)
        linarith
      have h_lb_tendsto : Tendsto (fun n : ℕ => α - 1 / ((n : ℝ) + 1)) atTop (nhds α) := by
        have h1 : Tendsto (fun n : ℕ => (1 : ℝ) / ((n : ℝ) + 1)) atTop (nhds 0) := by
          have := @tendsto_one_div_add_atTop_nhds_zero_nat ℝ _ _ _ _
          exact this
        have := tendsto_const_nhds (x := α).sub h1
        simp only [sub_zero] at this; exact this
      have hTxφ_norm' : Tendsto (fun n => ‖T (x (φ n))‖) atTop (nhds ‖y‖) := by
        exact (continuous_norm.tendsto y).comp hTxφ
      exact le_of_tendsto_of_tendsto h_lb_tendsto hTxφ_norm'
        (Filter.Eventually.of_forall hf_lb)
    linarith
  -- Step 3: T(Tx(φ n)) → Ty
  have hTTxφ : Tendsto (fun n => T (T (x (φ n)))) atTop (nhds (T y)) :=
    (T.continuous.tendsto y).comp hTxφ
  -- Step 4: ‖T²x(φ n) - α²·x(φ n)‖ → 0
  have hTx_norm : Tendsto (fun n => ‖T (x (φ n))‖) atTop (nhds α) := by
    rw [← hy_norm]
    exact (continuous_norm.tendsto y).comp hTxφ
  have hkey : Tendsto (fun n => ‖T (T (x (φ n))) - α ^ 2 • x (φ n)‖) atTop (nhds 0) := by
    suffices hsq : Tendsto (fun n => ‖T (T (x (φ n))) - α ^ 2 • x (φ n)‖ ^ 2) atTop (nhds 0) by
      have := hsq.sqrt
      simp only [Real.sqrt_sq_eq_abs, abs_norm, Real.sqrt_zero] at this
      exact this
    have hpointwise : ∀ n, ‖T (T (x (φ n))) - α ^ 2 • x (φ n)‖ ^ 2 ≤
        α ^ 2 * (α ^ 2 - ‖T (x (φ n))‖ ^ 2) := by
      intro n
      set z := x (φ n)
      have hz_norm : ‖z‖ ≤ 1 := (hx_norm (φ n)).le
      have hTTz_norm : ‖T (T z)‖ ≤ α * ‖T z‖ := T.le_opNorm (T z)
      have hinner : ⟪T (T z), z⟫_ℝ = ‖T z‖ ^ 2 := by
        have h1 : @inner ℝ E _ ((T : E →ₗ[ℝ] E) (T z)) z =
            @inner ℝ E _ (T z) ((T : E →ₗ[ℝ] E) z) := hT_sym (T z) z
        simp only [ContinuousLinearMap.coe_coe] at h1
        rw [h1, real_inner_self_eq_norm_sq]
      have hexpand : ‖T (T z) - α ^ 2 • z‖ ^ 2 =
          ‖T (T z)‖ ^ 2 - 2 * (α ^ 2 * ⟪T (T z), z⟫_ℝ) + (α ^ 2) ^ 2 * ‖z‖ ^ 2 := by
        rw [norm_sub_sq_real, inner_smul_right, norm_smul,
            Real.norm_of_nonneg (sq_nonneg α)]
        ring
      rw [hexpand, hinner]
      have h1 : ‖T (T z)‖ ^ 2 ≤ α ^ 2 * ‖T z‖ ^ 2 := by
        calc ‖T (T z)‖ ^ 2 ≤ (α * ‖T z‖) ^ 2 :=
              pow_le_pow_left₀ (norm_nonneg _) hTTz_norm 2
          _ = α ^ 2 * ‖T z‖ ^ 2 := mul_pow α ‖T z‖ 2
      have h2 : ‖z‖ ^ 2 ≤ 1 := by nlinarith [sq_nonneg (1 - ‖z‖), norm_nonneg z]
      nlinarith
    have h_ub_tendsto : Tendsto (fun n => α ^ 2 * (α ^ 2 - ‖T (x (φ n))‖ ^ 2))
        atTop (nhds 0) := by
      have h1 : Tendsto (fun n => α ^ 2 - ‖T (x (φ n))‖ ^ 2) atTop (nhds 0) := by
        have := tendsto_const_nhds (x := α ^ 2).sub (hTx_norm.pow 2)
        simp only [sub_self] at this; exact this
      have := h1.const_mul (α ^ 2)
      simp only [mul_zero] at this; exact this
    exact squeeze_zero (fun n => sq_nonneg _) hpointwise h_ub_tendsto
  -- Step 5: x(φ n) → Ty/α²
  have hx_conv : Tendsto (fun n => x (φ n)) atTop (nhds ((α ^ 2)⁻¹ • T y)) := by
    have hα2_smul : Tendsto (fun n => α ^ 2 • x (φ n)) atTop (nhds (T y)) := by
      have h_diff : Tendsto (fun n => T (T (x (φ n))) - α ^ 2 • x (φ n)) atTop (nhds 0) := by
        rw [tendsto_zero_iff_norm_tendsto_zero]
        exact hkey
      have : Tendsto (fun n => T (T (x (φ n))) - (T (T (x (φ n))) - α ^ 2 • x (φ n)))
          atTop (nhds (T y - 0)) :=
        hTTxφ.sub h_diff
      simp only [sub_sub_cancel, sub_zero] at this
      exact this
    have hTy_eq : T y = α ^ 2 • ((α ^ 2)⁻¹ • T y) := by
      rw [smul_smul, mul_inv_cancel₀ hα2_ne, one_smul]
    rw [hTy_eq] at hα2_smul
    rwa [tendsto_const_smul_iff₀ hα2_ne] at hα2_smul
  set x₀ := (α ^ 2)⁻¹ • T y with hx₀_def
  -- Step 6: T²x₀ = α²·x₀
  have hT2x0 : T (T x₀) = α ^ 2 • x₀ := by
    have h_TTx0 : T (T x₀) = T y := by
      have h1 : Tendsto (fun n => T (T (x (φ n)))) atTop (nhds (T (T x₀))) :=
        (T.continuous.tendsto (T x₀)).comp ((T.continuous.tendsto x₀).comp hx_conv)
      exact tendsto_nhds_unique h1 hTTxφ
    have h_α2x0 : α ^ 2 • x₀ = T y := by
      simp [hx₀_def, smul_smul, mul_inv_cancel₀ hα2_ne]
    rw [h_TTx0, ← h_α2x0]
  -- Step 7: ‖x₀‖ = 1
  have hx0_norm : ‖x₀‖ = 1 := by
    have hx_norm_conv : Tendsto (fun n => ‖x (φ n)‖) atTop (nhds ‖x₀‖) :=
      (continuous_norm.tendsto x₀).comp hx_conv
    have hge : 1 ≤ ‖x₀‖ := by
      by_contra h
      push Not at h
      have hlt : α * ‖x₀‖ < α := by nlinarith
      have h_ub : Tendsto (fun n => α * ‖x (φ n)‖) atTop (nhds (α * ‖x₀‖)) :=
        hx_norm_conv.const_mul α
      have h_lb_le : ∀ n, ‖T (x (φ n))‖ ≤ α * ‖x (φ n)‖ := fun n => T.le_opNorm _
      have := le_of_tendsto_of_tendsto hTx_norm h_ub (Filter.Eventually.of_forall h_lb_le)
      linarith
    have hle : ‖x₀‖ ≤ 1 := by
      apply le_of_tendsto hx_norm_conv
      apply Filter.Eventually.of_forall
      intro n; exact (hx_norm _).le
    linarith
  have hx0_ne : x₀ ≠ 0 := by
    intro h; simp [h] at hx0_norm
  -- Step 8: Construct T-eigenvector from T²-eigenvector
  set ep := T x₀ + α • x₀ with hep_def
  set em := T x₀ - α • x₀ with hem_def
  have hTep : T ep = α • ep := by
    simp only [hep_def, map_add, map_smul]
    rw [hT2x0]; module
  have hTem : T em = (-α) • em := by
    simp only [hem_def, map_sub, map_smul]
    rw [hT2x0]; module
  have hne_ep_em : ep ≠ 0 ∨ em ≠ 0 := by
    by_contra h
    push Not at h
    have : ep - em = ((2 : ℝ) * α) • x₀ := by simp [hep_def, hem_def]; module
    rw [h.1, h.2, sub_zero] at this
    have := smul_eq_zero.mp this.symm
    rcases this with h2 | h2
    · linarith [show (0:ℝ) < 2 * α from by positivity]
    · exact hx0_ne h2
  have hα_abs : |α| = ‖T‖ := abs_of_nonneg (le_of_lt hα_pos)
  rcases hne_ep_em with hep_ne | hem_ne
  · exact ⟨α, ep, hep_ne, by exact_mod_cast hTep, hα_abs⟩
  · exact ⟨-α, em, hem_ne, by exact_mod_cast hTem,
      by rw [abs_neg]; exact hα_abs⟩

/-! ### Theorem 1: Eigenvector existence -/

/-- A compact self-adjoint operator on a nontrivial real Hilbert space
    has an eigenvector achieving ‖T‖. -/
theorem compact_selfAdjoint_hasEigenvector
    [Nontrivial E]
    {T : E →L[ℝ] E} (hT_sa : IsSelfAdjoint T) (hT_compact : IsCompactOperator T)
    (hT_ne : T ≠ 0) :
    ∃ μ : ℝ, Module.End.HasEigenvalue (T : E →ₗ[ℝ] E) μ ∧ |μ| = ‖T‖ := by
  obtain ⟨μ, x, hx_ne, hx_eig, hμ_abs⟩ := hasEigenvector_aux T hT_sa hT_compact hT_ne
  refine ⟨μ, ?_, hμ_abs⟩
  rw [Module.End.HasEigenvalue]
  intro h_bot
  rw [Submodule.eq_bot_iff] at h_bot
  exact hx_ne (h_bot x (Module.End.mem_eigenspace_iff.mpr hx_eig))

/-! ### Theorem 2: Eigenspaces span -/

/-- The orthogonal complement of the span of all eigenspaces is trivial.
    Proved via the "restrict to complement" argument. -/
theorem compact_selfAdjoint_orthogonalComplement_iSup_eigenspaces_eq_bot
    {T : E →L[ℝ] E} (hT_sa : IsSelfAdjoint T) (hT_compact : IsCompactOperator T) :
    (⨆ μ, Module.End.eigenspace (T : E →ₗ[ℝ] E) μ)ᗮ = ⊥ := by
  have hT_sym := ContinuousLinearMap.isSelfAdjoint_iff_isSymmetric.mp hT_sa
  set W := (⨆ μ, Module.End.eigenspace (T : E →ₗ[ℝ] E) μ)ᗮ with hW_def
  -- Step 1: T preserves W
  have hW_inv : ∀ w ∈ W, (T : E →ₗ[ℝ] E) w ∈ W :=
    fun w hw => hT_sym.orthogonalComplement_iSup_eigenspaces_invariant hw
  -- Step 2: Build CLM T_W : W →L[ℝ] W
  set T_W := (T.comp W.subtypeL).codRestrict W (fun ⟨u, hu⟩ => hW_inv u hu) with hT_W_def
  -- W is a complete space (orthogonal complement of a submodule in a complete space);
  -- we also need Star (↥W →L[ℝ] ↥W) for IsSelfAdjoint, which requires CompleteSpace ↥W.
  -- Instance search can't synthesize these through the set-binding, so we provide them
  -- explicitly via @.
  have instCS_W : CompleteSpace ↥W :=
    Submodule.instOrthogonalCompleteSpace (⨆ μ, Module.End.eigenspace (T : E →ₗ[ℝ] E) μ)
  -- Step 3: T_W is self-adjoint
  have hT_W_sym : (T_W : ↥W →ₗ[ℝ] ↥W).IsSymmetric := by
    intro ⟨x, _⟩ ⟨y, _⟩
    simp only [Submodule.coe_inner]
    change @inner ℝ E _ (T x) y = @inner ℝ E _ x (T y)
    exact hT_sym x y
  have hT_W_sa : @IsSelfAdjoint (↥W →L[ℝ] ↥W)
      (@ContinuousLinearMap.instStarId ℝ ↥W _ _ _ instCS_W) T_W :=
    (@ContinuousLinearMap.isSelfAdjoint_iff_isSymmetric ℝ ↥W _ _ _ instCS_W).mpr hT_W_sym
  -- Step 4: T_W is compact
  have hT_W_compact : IsCompactOperator T_W :=
    (hT_compact.comp_clm W.subtypeL).codRestrict _ (Submodule.isClosed_orthogonal _)
  -- Step 5: T_W = 0
  have hT_W_zero : T_W = 0 := by
    by_contra hT_W_ne
    obtain ⟨v, hv_ne⟩ : ∃ v : ↥W, T_W v ≠ 0 := by
      by_contra h
      push Not at h
      exact hT_W_ne (ContinuousLinearMap.ext (fun v => h v))
    haveI : Nontrivial W := by
      refine ⟨⟨v, 0, ?_⟩⟩
      intro heq
      exact hv_ne (by rw [heq]; simp)
    obtain ⟨μ, e_W, he_ne, he_eig, _⟩ :=
      @hasEigenvector_aux ↥W _ _ instCS_W _ T_W hT_W_sa hT_W_compact hT_W_ne
    have hT_W_eq : (T_W : ↥W →ₗ[ℝ] ↥W) = (T : E →ₗ[ℝ] E).restrict hW_inv := by
      ext ⟨x, hx⟩
      simp only [ContinuousLinearMap.coe_coe, LinearMap.restrict_apply]
      rfl
    have h_no_eig : Module.End.eigenspace ((T : E →ₗ[ℝ] E).restrict hW_inv) μ = ⊥ := by
      have : hW_inv = hT_sym.orthogonalComplement_iSup_eigenspaces_invariant := by
        ext x hx; rfl
      rw [this]
      exact hT_sym.orthogonalComplement_iSup_eigenspaces μ
    have he_mem : e_W ∈ Module.End.eigenspace ((T : E →ₗ[ℝ] E).restrict hW_inv) μ := by
      rw [Module.End.mem_eigenspace_iff]
      rw [← hT_W_eq]
      exact he_eig
    rw [h_no_eig] at he_mem
    exact he_ne ((Submodule.mem_bot ℝ).mp he_mem)
  -- Step 6: W = ⊥
  rw [Submodule.eq_bot_iff]
  intro w hw
  have hTw : (T : E →ₗ[ℝ] E) w = 0 := by
    have : T_W ⟨w, hw⟩ = 0 := by rw [hT_W_zero]; simp
    have h := congr_arg Subtype.val this
    simp only [ZeroMemClass.coe_zero] at h
    exact h
  have hw_eig : w ∈ Module.End.eigenspace (T : E →ₗ[ℝ] E) 0 := by
    rw [Module.End.mem_eigenspace_iff]
    simp [hTw]
  have hw_sup : w ∈ ⨆ μ, Module.End.eigenspace (T : E →ₗ[ℝ] E) μ :=
    le_iSup (fun μ => Module.End.eigenspace (T : E →ₗ[ℝ] E) μ) 0 hw_eig
  have hw_inner : @inner ℝ E _ w w = 0 :=
    Submodule.inner_right_of_mem_orthogonal hw_sup hw
  rwa [real_inner_self_eq_norm_sq, sq_eq_zero_iff, norm_eq_zero] at hw_inner

/-! ### Helper: Eigenvector Hilbert basis (Zorn construction) -/

private theorem eigenvector_basis
    (T : E →L[ℝ] E) (hT : IsSelfAdjoint T) (hK : IsCompactOperator T) :
    ∃ (ι : Type u) (b : HilbertBasis ι ℝ E) (eigenval : ι → ℝ),
      ∀ i, (T : E →ₗ[ℝ] E) (b i) = eigenval i • b i := by
  have hspan := compact_selfAdjoint_orthogonalComplement_iSup_eigenspaces_eq_bot
    (T := T) hT hK
  have hT_sym := ContinuousLinearMap.isSelfAdjoint_iff_isSymmetric.mp hT
  -- Step 1: Maximal orthonormal subset of eigenvectors via Zorn
  let eigset : Set E := ⋃ (μ : ℝ), ↑(Module.End.eigenspace (T : E →ₗ[ℝ] E) μ)
  have hZ : ∃ S ⊆ eigset, Orthonormal ℝ ((↑) : S → E) ∧
      ∀ u, S ⊆ u → u ⊆ eigset → Orthonormal ℝ ((↑) : u → E) → u = S := by
    have := zorn_subset_nonempty
      {b : Set E | b ⊆ eigset ∧ Orthonormal ℝ ((↑) : b → E)}
      (fun c hc cc _c0 => ⟨⋃₀ c,
        ⟨fun x ⟨s, hs, hx⟩ => (hc hs).1 hx,
         orthonormal_sUnion_of_directed cc.directedOn (fun s hs => (hc hs).2)⟩,
        fun s hs => Set.subset_sUnion_of_mem hs⟩)
      ∅ ⟨Set.empty_subset _, orthonormal_empty ℝ E⟩
    obtain ⟨S, _, hSmax⟩ := this
    have hSe := hSmax.1.1
    have hSo := hSmax.1.2
    exact ⟨S, hSe, hSo, fun u hSu hue huo =>
      (hSmax.2 ⟨hue, huo⟩ hSu).antisymm hSu⟩
  obtain ⟨S, hSe, hSo, hSmax⟩ := hZ
  -- Step 2: T maps span S into itself
  have hT_span_inv : Submodule.span ℝ S ≤ (Submodule.span ℝ S).comap (T : E →ₗ[ℝ] E) := by
    rw [Submodule.span_le]
    intro s hs
    show (T : E →ₗ[ℝ] E) s ∈ Submodule.span ℝ S
    have hse := hSe hs; rw [Set.mem_iUnion] at hse
    obtain ⟨μ, hμ⟩ := hse
    rw [Module.End.mem_eigenspace_iff.mp hμ]
    exact Submodule.smul_mem _ _ (Submodule.subset_span hs)
  -- Step 3: T maps (span S)ᗮ into itself
  have hT_orth_inv : ∀ w ∈ (Submodule.span ℝ S)ᗮ,
      (T : E →ₗ[ℝ] E) w ∈ (Submodule.span ℝ S)ᗮ := by
    intro w hw
    rw [Submodule.mem_orthogonal'] at hw ⊢
    intro u hu
    rw [real_inner_comm]
    rw [← hT_sym u w, real_inner_comm]
    exact hw _ (hT_span_inv hu)
  -- Step 4: (span ℝ S)ᗮ = ⊥
  have h_span_bot : (Submodule.span ℝ S)ᗮ = ⊥ := by
    by_contra h_ne
    obtain ⟨w, hw, hw_ne⟩ := (Submodule.ne_bot_iff _).mp h_ne
    set W := (Submodule.span ℝ S)ᗮ with hW_def
    have extend_S : ∀ e ∈ W, e ∈ eigset → ‖e‖ = 1 → False := by
      intro e he_W he_eig he_norm
      have he_orth : ∀ s ∈ Submodule.span ℝ S, @inner ℝ E _ e s = 0 := by
        rwa [Submodule.mem_orthogonal'] at he_W
      have he_notin : e ∉ S := by
        intro hmem
        have h_inner := he_orth e (Submodule.subset_span hmem)
        rw [real_inner_self_eq_norm_sq, he_norm, one_pow] at h_inner
        exact one_ne_zero h_inner
      have hSue_orth : Orthonormal ℝ ((↑) : ↥(S ∪ {e}) → E) := by
        refine ⟨fun ⟨x, hx⟩ => ?_, fun ⟨x, hx⟩ ⟨y, hy⟩ hne => ?_⟩
        · rcases hx with hx | hx
          · exact hSo.1 ⟨x, hx⟩
          · have := Set.mem_singleton_iff.mp hx; subst this; exact he_norm
        · have hne_val : x ≠ y := fun h => hne (Subtype.ext h)
          rcases hx with hx | hx <;> rcases hy with hy | hy
          · show @inner ℝ E _ x y = 0
            exact hSo.2 (show (⟨x, hx⟩ : ↥S) ≠ ⟨y, hy⟩ from
              fun h => hne_val (congr_arg Subtype.val h))
          · show @inner ℝ E _ x y = 0
            have hye : y = e := Set.mem_singleton_iff.mp hy; subst hye
            rw [real_inner_comm]; exact he_orth x (Submodule.subset_span hx)
          · show @inner ℝ E _ x y = 0
            have hxe : x = e := Set.mem_singleton_iff.mp hx; subst hxe
            exact he_orth y (Submodule.subset_span hy)
          · exfalso; apply hne_val
            rw [Set.mem_singleton_iff.mp hx, Set.mem_singleton_iff.mp hy]
      have hSue_sub : S ∪ {e} ⊆ eigset := by
        intro x hx; rcases hx with hx | hx
        · exact hSe hx
        · rw [Set.mem_singleton_iff.mp hx]; exact he_eig
      have hSue_eq := hSmax (S ∪ {e}) Set.subset_union_left hSue_sub hSue_orth
      exact he_notin (hSue_eq ▸ Set.mem_union_right S rfl)
    by_cases hTw_all : ∀ v ∈ W, (T : E →ₗ[ℝ] E) v = 0
    · have hw_norm_ne : ‖w‖ ≠ 0 := norm_ne_zero_iff.mpr hw_ne
      exact extend_S ((‖w‖⁻¹ : ℝ) • w) (W.smul_mem _ hw)
        (Set.mem_iUnion.mpr ⟨0, Module.End.mem_eigenspace_iff.mpr (by
          show (T : E →ₗ[ℝ] E) ((‖w‖⁻¹ : ℝ) • w) = 0 • ((‖w‖⁻¹ : ℝ) • w)
          rw [zero_smul, map_smul, hTw_all w hw, smul_zero])⟩)
        (by rw [norm_smul, norm_inv, norm_norm, inv_mul_cancel₀ hw_norm_ne])
    · push Not at hTw_all; obtain ⟨v, hv, hTv_ne⟩ := hTw_all
      set T_W := (T.comp W.subtypeL).codRestrict W (fun ⟨u, hu⟩ => hT_orth_inv u hu)
      have instCS_W : CompleteSpace ↥W :=
        Submodule.instOrthogonalCompleteSpace (Submodule.span ℝ S)
      have hT_W_sym : (T_W : ↥W →ₗ[ℝ] ↥W).IsSymmetric := by
        intro ⟨x, _⟩ ⟨y, _⟩
        rw [Submodule.coe_inner, Submodule.coe_inner]
        change @inner ℝ E _ (T x) y = @inner ℝ E _ x (T y)
        exact (ContinuousLinearMap.isSelfAdjoint_iff_isSymmetric.mp hT) x y
      have hT_W_sa : @IsSelfAdjoint (↥W →L[ℝ] ↥W)
          (@ContinuousLinearMap.instStarId ℝ ↥W _ _ _ instCS_W) T_W :=
        (@ContinuousLinearMap.isSelfAdjoint_iff_isSymmetric ℝ ↥W _ _ _ instCS_W).mpr hT_W_sym
      have hT_W_compact : IsCompactOperator T_W :=
        (hK.comp_clm W.subtypeL).codRestrict _ (Submodule.isClosed_orthogonal _)
      have hT_W_ne : T_W ≠ 0 := by
        intro h
        have : T_W ⟨v, hv⟩ = 0 := by rw [h]; simp
        have h2 : (T_W ⟨v, hv⟩ : E) = 0 := congr_arg Subtype.val this
        exact hTv_ne h2
      haveI : Nontrivial W := by
        refine ⟨⟨⟨v, hv⟩, 0, ?_⟩⟩
        intro h
        have := congr_arg Subtype.val h
        simp only [ZeroMemClass.coe_zero] at this
        exact hTv_ne (by rw [this]; simp)
      obtain ⟨μ, e_W, he_ne, he_eig, _⟩ :=
        @hasEigenvector_aux ↥W _ _ instCS_W _ T_W hT_W_sa hT_W_compact hT_W_ne
      have he_eig_E : (T : E →ₗ[ℝ] E) (e_W : E) = μ • (e_W : E) := by
        have h := congr_arg Subtype.val he_eig
        simp only [SetLike.val_smul] at h
        exact h
      have he_norm_ne : ‖(e_W : E)‖ ≠ 0 := by
        intro h; apply he_ne; ext; exact norm_eq_zero.mp h
      exact extend_S ((‖(e_W : E)‖⁻¹ : ℝ) • (e_W : E)) (W.smul_mem _ e_W.2)
        (Set.mem_iUnion.mpr ⟨μ, Module.End.mem_eigenspace_iff.mpr (by
          show (T : E →ₗ[ℝ] E) _ = μ • _
          rw [map_smul, he_eig_E, smul_comm])⟩)
        (by rw [norm_smul, norm_inv, norm_norm, inv_mul_cancel₀ he_norm_ne])
  -- Step 5: Build HilbertBasis
  have h_range : (Submodule.span ℝ (Set.range ((↑) : S → E)))ᗮ = ⊥ := by
    rwa [Subtype.range_coe_subtype, Set.setOf_mem_eq]
  let b := HilbertBasis.mkOfOrthogonalEqBot hSo h_range
  have h_eig : ∀ (x : S), ∃ μ : ℝ, (T : E →ₗ[ℝ] E) (x : E) = μ • (x : E) := by
    intro ⟨x, hx⟩
    have := hSe hx; rw [Set.mem_iUnion] at this
    obtain ⟨μ, hμ⟩ := this; exact ⟨μ, Module.End.mem_eigenspace_iff.mp hμ⟩
  refine ⟨↥S, b, fun i => (h_eig i).choose, fun i => ?_⟩
  have hbi : (b i : E) = (i : E) :=
    congr_fun (HilbertBasis.coe_mkOfOrthogonalEqBot hSo h_range) i
  rw [hbi]; exact (h_eig i).choose_spec

/-! ### Theorem 3: Spectral theorem (diagonal representation) -/

/-- **Spectral Theorem**: Every compact self-adjoint operator on a real Hilbert
    space admits a HilbertBasis of eigenvectors.

    Given T compact and self-adjoint, there exist:
    - A HilbertBasis {e_ι} (spanning ONB)
    - Eigenvalues μ_ι with T(e_ι) = μ_ι • e_ι
    - Representation: T(x) = ∑_ι μ_ι ⟨e_ι, x⟩ e_ι (norm-convergent) -/
theorem compact_selfAdjoint_spectral
    (T : E →L[ℝ] E)
    (hT_sa : IsSelfAdjoint T) (hT_compact : IsCompactOperator T) :
    ∃ (ι : Type u) (b : HilbertBasis ι ℝ E) (eigenval : ι → ℝ),
      (∀ i, (T : E →ₗ[ℝ] E) (b i) = eigenval i • b i) ∧
      (∀ x, HasSum (fun i => (eigenval i * @inner ℝ _ _ (b i) x) • b i) (T x)) := by
  obtain ⟨ι, b, μ, hev⟩ := eigenvector_basis T hT_sa hT_compact
  refine ⟨ι, b, μ, hev, fun x => ?_⟩
  have hrepr := b.hasSum_repr x
  have hT_sum : HasSum (fun i => T (b.repr x i • b i)) (T x) :=
    hrepr.mapL T
  have key : ∀ i, T (b.repr x i • b i) = (μ i * @inner ℝ _ _ (b i) x) • b i := fun i => by
    change (T : E →ₗ[ℝ] E) (b.repr x i • b i) = _
    rw [map_smul, hev i, smul_smul, HilbertBasis.repr_apply_apply, mul_comm]
  simp_rw [key] at hT_sum
  exact hT_sum

end GaussianField
