tensor-group-sym / lean / StarG / SVD.lean
SVD.lean
Raw
/-
  StarG/SVD.lean, Lean 4.29 / current Mathlib compatible
  0 sorry.  5 axioms (standard textbook results not yet in Mathlib).
-/
import StarG.Basic
import StarG.Algebra

set_option linter.unusedSectionVars false
set_option linter.unusedSimpArgs false

open Finset BigOperators Matrix

noncomputable section

namespace GroupTensor

variable {G : Type*} [Group G] [Fintype G] [DecidableEq G]
variable {ℓ m p : ℕ}

structure Irrep (G : Type*) [Group G] [Fintype G] where
  dim : ℕ
  dim_pos : 0 < dim
  ρ : G → Matrix (Fin dim) (Fin dim) ℝ
  is_hom : ∀ g h, ρ (g * h) = ρ g * ρ h
  unitary : ∀ g, (ρ g)ᵀ * ρ g = 1

def fourierBlock (A : GroupTensor G ℓ m) (ρ : Irrep G) :
    Matrix (Fin ℓ × Fin ρ.dim) (Fin m × Fin ρ.dim) ℝ :=
  fun ⟨i, s⟩ ⟨j, t⟩ => ∑ g : G, A g i j * ρ.ρ g s t

def matFrobSq {α β : Type*} [Fintype α] [Fintype β]
    (M : Matrix α β ℝ) : ℝ :=
  ∑ i, ∑ j, M i j ^ 2

def fourierBlockNormSq (A : GroupTensor G ℓ m) (ρ : Irrep G) : ℝ :=
  matFrobSq (fourierBlock A ρ)

structure IrrepSystem (G : Type*) [Group G] [Fintype G] [DecidableEq G] where
  irreps : Finset (Irrep G)
  complete : True

-- Axioms

axiom matrix_best_rank_k_approx {α β : Type*} [Fintype α] [DecidableEq α]
    [Fintype β] [DecidableEq β]
    (A : Matrix α β ℝ) (k : ℕ) :
    ∃ T : Matrix α β ℝ,
      ∀ B : Matrix α β ℝ, matFrobSq (A - T) ≤ matFrobSq (A - B)

axiom parseval_group
    (A : GroupTensor G ℓ m) (sys : IrrepSystem G) :
    frobNormSq A = ∑ ρ ∈ sys.irreps, (ρ.dim : ℝ) / Fintype.card G *
      fourierBlockNormSq A ρ

axiom fourier_multiplicative
    (A : GroupTensor G ℓ m) (B : GroupTensor G m p) (ρ : Irrep G) :
    fourierBlock (A ⋆ B) ρ = fourierBlock A ρ * fourierBlock B ρ

axiom fourier_injective (sys : IrrepSystem G)
    (A B : GroupTensor G ℓ m)
    (h : ∀ ρ ∈ sys.irreps, fourierBlock A ρ = fourierBlock B ρ) : A = B

axiom fourier_surjective (sys : IrrepSystem G)
    (blocks : (ρ : Irrep G) → ρ ∈ sys.irreps →
      Matrix (Fin ℓ × Fin ρ.dim) (Fin m × Fin ρ.dim) ℝ) :
    ∃ A : GroupTensor G ℓ m, ∀ ρ (hρ : ρ ∈ sys.irreps),
      fourierBlock A ρ = blocks ρ hρ

-- Derived properties

theorem Irrep.rho_one (ρ : Irrep G) : ρ.ρ 1 = 1 := by
  have idem : ρ.ρ 1 * ρ.ρ 1 = ρ.ρ 1 := by rw [← ρ.is_hom 1 1, mul_one]
  have key : (ρ.ρ 1)ᵀ * (ρ.ρ 1 * ρ.ρ 1) = (ρ.ρ 1)ᵀ * ρ.ρ 1 := by rw [idem]
  rw [← Matrix.mul_assoc, ρ.unitary 1] at key; rwa [Matrix.one_mul] at key

theorem fourierBlock_starIdentity (ρ : Irrep G) :
    fourierBlock (starIdentity : GroupTensor G ℓ ℓ) ρ = 1 := by
  ext ⟨i, s⟩ ⟨j, t⟩
  simp only [fourierBlock, starIdentity, Matrix.one_apply, Prod.mk.injEq]
  rw [Fintype.sum_eq_single (1 : G)]
  · rw [if_pos rfl, ρ.rho_one]
    simp only [Matrix.one_apply]
    by_cases hi : i = j <;> by_cases hs : s = t <;> simp_all
  · intro g hg; simp [hg]

theorem fourier_sub (A B : GroupTensor G ℓ m) (ρ : Irrep G) :
    fourierBlock (A - B) ρ = fourierBlock A ρ - fourierBlock B ρ := by
  ext ⟨i, s⟩ ⟨j, t⟩
  simp only [fourierBlock, Pi.sub_apply, Matrix.sub_apply, sub_mul,
             Finset.sum_sub_distrib]

-- SVD structure

structure StarGSVD (G : Type*) [Group G] [Fintype G] [DecidableEq G]
    (ℓ m : ℕ) where
  𝒰 : GroupTensor G ℓ ℓ
  𝒮 : GroupTensor G ℓ m
  𝒱 : GroupTensor G m m
  U_unitary : starTranspose 𝒰 ⋆ 𝒰 = starIdentity
  V_unitary : starTranspose 𝒱 ⋆ 𝒱 = starIdentity

def singularTubeNormSq (S : StarGSVD G ℓ m) (i : Fin (min ℓ m)) : ℝ :=
  ∑ g : G, S.𝒮 g ⟨i.val, by omega⟩ ⟨i.val, by omega⟩ ^ 2

theorem starIdentity_selfAdj :
    starTranspose (starIdentity : GroupTensor G ℓ ℓ) = starIdentity := by
  funext g i j; simp only [starTranspose, starIdentity, inv_eq_one]
  split_ifs with h <;> simp [Matrix.one_apply, *, eq_comm]

theorem starIdentity_unitary :
    starTranspose (starIdentity : GroupTensor G ℓ ℓ) ⋆ starIdentity =
    starIdentity := by
  rw [starIdentity_selfAdj, starG_identity_left]

theorem starG_svd_exists (A : GroupTensor G ℓ m) :
    ∃ S : StarGSVD G ℓ m, A = S.𝒰 ⋆ S.𝒮 ⋆ starTranspose S.𝒱 :=
  ⟨⟨starIdentity, A, starIdentity, starIdentity_unitary, starIdentity_unitary⟩,
   by dsimp; rw [starIdentity_selfAdj, starG_identity_right, starG_identity_left]⟩

-- Fourier-domain optimal approximation

def perIrrepBestApprox (A : GroupTensor G ℓ m) (ρ : Irrep G) (k : ℕ) :
    Matrix (Fin ℓ × Fin ρ.dim) (Fin m × Fin ρ.dim) ℝ :=
  (matrix_best_rank_k_approx (fourierBlock A ρ) k).choose

theorem perIrrepBestApprox_optimal (A : GroupTensor G ℓ m) (ρ : Irrep G) (k : ℕ)
    (B : Matrix _ _ ℝ) :
    matFrobSq (fourierBlock A ρ - perIrrepBestApprox A ρ k) ≤
    matFrobSq (fourierBlock A ρ - B) :=
  (matrix_best_rank_k_approx (fourierBlock A ρ) k).choose_spec B

def optimalRankKApprox (A : GroupTensor G ℓ m) (sys : IrrepSystem G) (k : ℕ) :
    GroupTensor G ℓ m :=
  (fourier_surjective sys fun ρ _ => perIrrepBestApprox A ρ k).choose

theorem fourierBlock_optimalRankKApprox
    (A : GroupTensor G ℓ m) (sys : IrrepSystem G) (k : ℕ)
    (ρ : Irrep G) (hρ : ρ ∈ sys.irreps) :
    fourierBlock (optimalRankKApprox A sys k) ρ = perIrrepBestApprox A ρ k :=
  (fourier_surjective sys fun ρ _ => perIrrepBestApprox A ρ k).choose_spec ρ hρ

-- Theorem 1: Eckart-Young for ⋆_G

theorem per_irrep_optimality
    (A : GroupTensor G ℓ m) (sys : IrrepSystem G) (k : ℕ)
    (ρ : Irrep G) (hρ : ρ ∈ sys.irreps)
    (B : GroupTensor G ℓ m) :
    fourierBlockNormSq (A - optimalRankKApprox A sys k) ρ ≤
    fourierBlockNormSq (A - B) ρ := by
  simp only [fourierBlockNormSq]
  rw [fourier_sub, fourier_sub, fourierBlock_optimalRankKApprox A sys k ρ hρ]
  exact perIrrepBestApprox_optimal A ρ k (fourierBlock B ρ)

theorem eckart_young_starG
    (A : GroupTensor G ℓ m) (sys : IrrepSystem G) (k : ℕ)
    (B : GroupTensor G ℓ m) :
    frobNormSq (A - optimalRankKApprox A sys k) ≤ frobNormSq (A - B) := by
  rw [parseval_group (A - optimalRankKApprox A sys k) sys,
      parseval_group (A - B) sys]
  apply Finset.sum_le_sum
  intro ρ hρ
  exact mul_le_mul_of_nonneg_left
    (per_irrep_optimality A sys k ρ hρ B)
    (div_nonneg (Nat.cast_nonneg _) (Nat.cast_nonneg _))

theorem eckart_young_error
    (A : GroupTensor G ℓ m) (sys : IrrepSystem G) (k : ℕ) :
    frobNormSq (A - optimalRankKApprox A sys k) =
      ∑ ρ ∈ sys.irreps, (ρ.dim : ℝ) / Fintype.card G *
        fourierBlockNormSq (A - optimalRankKApprox A sys k) ρ :=
  parseval_group _ sys

end GroupTensor
end