Zulip Chat Archive

Stream: maths

Topic: Matrix diagonalizability criterion- Proofs


Pranav Shankar (Feb 25 2026 at 20:24):

I'm looking to add the criterion for matrix diagonalizability to mathlib. The criterion has 2 directions: EigenbasisExistsIfDiagonalizable and DiagonalizableIfBasisOfEigenvectorsExists. Are these proofs valid? Can they be added to mathlib?

The first proof is:

import Mathlib
theorem EigenbasisExistsIfDiagonalizable
  {F V : Type*} [Field F] [AddCommGroup V] [Module F V] [FiniteDimensional F V]
  (f : V →ₗ[F] V)
  (defaultBasis : Module.Basis (Fin (Module.finrank F V)) F V)
  (diagonalizable :  (μ : Fin (Module.finrank F V)  F),
             (P : Matrix (Fin (Module.finrank F V)) (Fin (Module.finrank F V)) F),
            P.det  0 
            LinearMap.toMatrix defaultBasis defaultBasis f = P * (Matrix.diagonal μ) * P⁻¹) :
             (b : Module.Basis (Fin (Module.finrank F V)) F V),
             i,  L : F, f (b i) = L  (b i) := by


  rcases diagonalizable with μ, P, h_det, h_A_eq

  let A := LinearMap.toMatrix defaultBasis defaultBasis f
  have AP_eq_PD : A * P = P * (Matrix.diagonal μ) := by
    dsimp [A]
    rw [h_A_eq]


    rw [Matrix.mul_assoc, Matrix.mul_assoc]


    rw [Matrix.nonsing_inv_mul P (isUnit_iff_ne_zero.mpr h_det)]


    simp only [Matrix.mul_one]
  have AP_col :  j, (A * P).col j = Matrix.mulVec A (P.col j) := by
    intro j
    ext i
    simp [Matrix.col, Matrix.mulVec, Matrix.mul_apply, dotProduct]
  have PD_col :  j, (P * (Matrix.diagonal μ)).col j = μ j  (P.col j) := by
    intro j
    ext i
    simp [Matrix.col]
    rw [mul_comm]
  have P_inv : IsUnit P.det := isUnit_iff_ne_zero.mpr h_det
  let n := Fin (Module.finrank F V)
  let b_basis : Module.Basis n F V := defaultBasis
  let f_lin := Matrix.toLin b_basis b_basis P
  let g_lin := Matrix.toLin b_basis b_basis P⁻¹
  have h_right : f_lin * g_lin = 1 := by
      apply (LinearMap.toMatrix b_basis b_basis).injective

      simp only [f_lin, g_lin, LinearMap.toMatrix_mul, LinearMap.toMatrix_toLin, LinearMap.toMatrix_one]

      exact Matrix.mul_nonsing_inv P (isUnit_iff_ne_zero.mpr h_det)


  have h_left : g_lin * f_lin = 1 := by
      apply (LinearMap.toMatrix b_basis b_basis).injective
      simp only [f_lin, g_lin, LinearMap.toMatrix_mul, LinearMap.toMatrix_toLin, LinearMap.toMatrix_one]
      -- Apply the identity P⁻¹ * P = 1
      exact Matrix.nonsing_inv_mul P (isUnit_iff_ne_zero.mpr h_det)

  have f_inv : IsUnit f_lin := by
   refine {
      val := f_lin
      inv := g_lin
      val_inv := h_right
      inv_val := h_left
    }, rfl
  let f_P : V ≃ₗ[F] V := LinearEquiv.ofLinear f_lin g_lin h_right h_left
  let b := b_basis.map f_P
  exists b
  intro i
  exists μ i
  have f_eq_A : f = Matrix.toLin b_basis b_basis A := by
    apply (LinearMap.toMatrix b_basis b_basis).injective
    simp only [LinearMap.toMatrix_toLin]
    dsimp [A]
  rw [f_eq_A]
  apply_fun (Matrix.toLin b_basis b_basis) at AP_eq_PD
  rw [Matrix.toLin_mul b_basis b_basis b_basis] at AP_eq_PD
  rw [Matrix.toLin_mul b_basis b_basis b_basis] at AP_eq_PD
  dsimp [b, f_P]
  rw [ LinearMap.comp_apply]
  dsimp [f_lin]
  rw [ LinearMap.comp_apply]
  rw [AP_eq_PD]
  rw [LinearMap.comp_apply]
  suffices eigen : (Matrix.toLin b_basis b_basis (Matrix.diagonal μ)) (b_basis i) = μ i  b_basis i by
    rw [eigen]
    rw [LinearMap.map_smul]
  apply b_basis.repr.injective
  simp [Matrix.toLin_apply, b_basis.repr_self]
  ext k
  simp [Matrix.mulVec_diagonal]
  simp only [Finsupp.single_apply]
  split_ifs with h_eq
  · subst h_eq
    simp
  · simp [h_eq]

and the second proof is

import Mathlib
theorem DiagonalizableIfBasisOfEigenvectorsExists
  {F V : Type*} [Field F] [AddCommGroup V] [Module F V] [FiniteDimensional F V]
  (f : V →ₗ[F] V) -- Linear operator on V
  (eigenBasis : Module.Basis (Fin (Module.finrank F V)) F V)
  (eigenvector_property :  i,  L : F, f (eigenBasis i) = L  (eigenBasis i)) :
   D : Matrix (Fin (Module.finrank F V)) (Fin (Module.finrank F V)) F,
     P : Matrix (Fin (Module.finrank F V)) (Fin (Module.finrank F V)) F,
      (P.det  0) 
      (LinearMap.toMatrix eigenBasis eigenBasis f = P * D * P⁻¹) := by
      have matrix_wrt_eigenbasis_is_diagonal
        (μ : Fin (Module.finrank F V)  F)
        (eigen :  i, f (eigenBasis i) = μ i  eigenBasis i) :
        LinearMap.toMatrix eigenBasis eigenBasis f = Matrix.diagonal μ := by
          ext i j
          simp [LinearMap.toMatrix_apply, eigen, Matrix.diagonal, Finsupp.single_apply]
          by_cases diagOrNot: i = j
          · subst diagOrNot
            simp
          rw [if_neg diagOrNot]
          rw [if_neg (Ne.symm diagOrNot)]

      let μ := fun i => Classical.choose (eigenvector_property i)

      have  :  i, f (eigenBasis i) = μ i  eigenBasis i := by
        intro i
        rw [Classical.choose_spec (eigenvector_property i)]

      let D := Matrix.diagonal μ
      let P := (1 : Matrix (Fin (Module.finrank F V)) (Fin (Module.finrank F V)) F)

      use D, P
      constructor

        dsimp [P]

        rw [Matrix.det_one]

        exact one_ne_zero

        dsimp [P]
        simp only [Matrix.one_mul, Matrix.mul_one, inv_one]


        apply matrix_wrt_eigenbasis_is_diagonal
        exact 

Eric Wieser (Feb 25 2026 at 20:57):

Please apply #backticks

J. J. Issai (project started by GRP) (Feb 25 2026 at 21:12):

Also, "Diagonalization Proofs" means something different in logic and set theory and recursion theory. Please change title to "Matrix Diagonalization proofs".


Last updated: Feb 28 2026 at 14:05 UTC