Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - feat(linear_algebra/cayley_hamilton): the Cayley-Hamilton theorem #3276

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4438ae0
feat(ring_theory/polynomial_algebra): polynomial A ≃ₐ[R] (A ⊗[R] poly…
semorrison Jul 3, 2020
7ddedc5
feat(linear_algebra/cayley_hamilton): the Cayley-Hamilton theorem
semorrison Jul 3, 2020
d3ff2bb
Apply suggestions from code review
semorrison Jul 3, 2020
0a3a028
Update src/ring_theory/polynomial_algebra.lean
semorrison Jul 5, 2020
e1e3571
shorter names
semorrison Jul 5, 2020
d121285
Merge branch 'polynomial_algebra' of github.com:leanprover-community/…
semorrison Jul 5, 2020
ef96e4d
Merge branch 'polynomial_algebra' into cayley_hamilton_squashed
semorrison Jul 5, 2020
5cc4b0f
Merge branch 'cayley_hamilton_squashed' of github.com:leanprover-comm…
semorrison Jul 5, 2020
84840ad
use short names
semorrison Jul 5, 2020
83f8759
merge origin/master
semorrison Jul 9, 2020
2b30176
fix
semorrison Jul 9, 2020
13bb96b
feat(data/matrix): add matrix.map and supporting lemmas
semorrison Jul 10, 2020
0796d5c
Merge branch 'matrix_map' into cayley_hamilton_squashed
semorrison Jul 10, 2020
aa54558
finish renaming
semorrison Jul 10, 2020
3353512
Merge branch 'matrix_map' into cayley_hamilton_squashed
semorrison Jul 10, 2020
f7a8682
finish renaming
semorrison Jul 10, 2020
a4528d3
Merge branch 'matrix_map' into cayley_hamilton_squashed
semorrison Jul 10, 2020
cafc6eb
use matrix.map
semorrison Jul 10, 2020
38699b2
Apply suggestions from code review
semorrison Jul 10, 2020
bff2461
Apply suggestions from code review
semorrison Jul 10, 2020
e3dab7b
Merge remote-tracking branch 'origin/matrix_map' into cayley_hamilton…
semorrison Jul 10, 2020
ba3cc97
Apply suggestions from code review
semorrison Jul 10, 2020
aae83b3
rename file
semorrison Jul 10, 2020
5fadd0a
chore(*): import tactic.basic as early as possible, and reduce import…
semorrison Jul 10, 2020
9830e2e
chore(logic/embedding): reuse proofs from `data.*` (#3341)
urkud Jul 10, 2020
6cdb107
feat(ring_theory/matrix_algebra): drop commutativity assumption (#3351)
semorrison Jul 10, 2020
dc1a0df
refactor(algebra/homology): handle co/homology uniformly (#3316)
semorrison Jul 10, 2020
972afa6
Merge branch 'master' into cayley_hamilton_squashed
jcommelin Jul 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
107 changes: 107 additions & 0 deletions src/linear_algebra/char_poly.lean
@@ -0,0 +1,107 @@
/-
Copyright (c) 2020 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison
-/
import tactic.apply_fun
import ring_theory.matrix_algebra
import ring_theory.polynomial_algebra
import linear_algebra.nonsingular_inverse
import tactic.squeeze

/-!
# Characteristic polynomials and the Cayley-Hamilton theorem

We define characteristic polynomials of matrices and
prove the Cayley–Hamilton theorem over arbitrary commutative rings.

## Main definitions

* `char_poly` is the characteristic polynomial of a matrix.

## Implementation details

We follow a nice proof from http://drorbn.net/AcademicPensieve/2015-12/CayleyHamilton.pdf
-/

noncomputable theory

universes u v w

open polynomial matrix
open_locale big_operators

variables {R : Type u} [comm_ring R]
variables {n : Type w} [fintype n] [decidable_eq n]

open finset

/--
The "characteristic matrix" of `M : matrix n n R` is the matrix of polynomials $t I - M$.
The determinant of this matrix is the characteristic polynomial.
-/
def char_matrix (M : matrix n n R) : matrix n n (polynomial R) :=
matrix.scalar n (X : polynomial R) - (C : R →+* polynomial R).map_matrix M

@[simp] lemma char_matrix_apply_eq (M : matrix n n R) (i : n) :
char_matrix M i i = (X : polynomial R) - C (M i i) :=
by simp only [char_matrix, sub_left_inj, pi.sub_apply, scalar_apply_eq,
ring_hom.map_matrix_apply, map_apply]

@[simp] lemma char_matrix_apply_ne (M : matrix n n R) (i j : n) (h : i ≠ j) :
char_matrix M i j = - C (M i j) :=
by simp only [char_matrix, pi.sub_apply, scalar_apply_ne _ _ _ h, zero_sub,
ring_hom.map_matrix_apply, map_apply]

lemma mat_poly_equiv_char_matrix (M : matrix n n R) :
mat_poly_equiv (char_matrix M) = X - C M :=
begin
ext k i j,
simp only [mat_poly_equiv_coeff_apply, coeff_sub, pi.sub_apply],
by_cases h : i = j,
{ subst h, rw [char_matrix_apply_eq, coeff_sub],
simp only [coeff_X, coeff_C],
split_ifs; simp, },
{ rw [char_matrix_apply_ne _ _ _ h, coeff_X, coeff_neg, coeff_C, coeff_C],
split_ifs; simp [h], }
end

/--
The characteristic polynomial of a matrix `M` is given by $\det (t I - M)$.
-/
def char_poly (M : matrix n n R) : polynomial R :=
(char_matrix M).det

/--
The Cayley-Hamilton theorem, that the characteristic polynomial of a matrix,
applied to the matrix itself, is zero.

This holds over any commutative ring.
-/
-- This proof follows http://drorbn.net/AcademicPensieve/2015-12/CayleyHamilton.pdf
theorem char_poly_map_eval_self (M : matrix n n R) :
((char_poly M).map (algebra_map R (matrix n n R))).eval M = 0 :=
begin
-- We begin with the fact $χ_M(t) I = adjugate (t I - M) * (t I - M)$,
-- as an identity in `matrix n n (polynomial R)`.
have h : (char_poly M) • (1 : matrix n n (polynomial R)) =
adjugate (char_matrix M) * (char_matrix M) :=
(adjugate_mul _).symm,
-- Using the algebra isomorphism `matrix n n (polynomial R) ≃ₐ[R] polynomial (matrix n n R)`,
-- we have the same identity in `polynomial (matrix n n R)`.
apply_fun mat_poly_equiv at h,
simp only [mat_poly_equiv.map_mul,
mat_poly_equiv_char_matrix] at h,
-- Because the coefficient ring `matrix n n R` is non-commutative,
-- evaluation at `M` is not multiplicative.
-- However, any polynomial which is a product of the form $N * (t I - M)$
-- is sent to zero, because the evaluation function puts the polynomial variable
-- to the right of any coefficients, so everything telescopes.
apply_fun (λ p, p.eval M) at h,
rw eval_mul_X_sub_C at h,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason not to write rwa [eval_mul_X_sub_C, mat_poly_equiv_smul_one] at h, instead of those three lines? Is that because of the narrative in the comments?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this proof was indeed un-golfed for readability reasons.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether we should care about the fact that mathcomp people always point out how their proof is only three lines long.

Maybe we can add a comment below our proof saying:

theorem char_poly_map_eval_self (M : matrix n n R) :
  ((char_poly M).map (algebra_map R (matrix n n R))).eval M = 0 :=
begin
  have h : (mat_poly_equiv ((char_poly M) • 1)).eval M = (mat_poly_equiv  (adjugate (char_matrix M) * (char_matrix M))).eval M := congr_arg _ (congr_arg _ (adjugate_mul _).symm),
  simpa only [mat_poly_equiv.map_mul, mat_poly_equiv_char_matrix, eval_mul_X_sub_C, mat_poly_equiv_smul_one] using h,
end

Copy link
Member

@jcommelin jcommelin Jul 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me.
How about by simpa ... using ...?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, on Scott's screen you could use

by simpa only [mat_poly_equiv.map_mul, mat_poly_equiv_char_matrix, eval_mul_X_sub_C, mat_poly_equiv_smul_one] using (congr_arg _ (congr_arg _ (adjugate_mul _).symm) : (mat_poly_equiv ((char_poly M) • 1)).eval M = (mat_poly_equiv  (adjugate (char_matrix M) * (char_matrix M))).eval M)

-- Now $χ_M (t) I$, when thought of as a polynomial of matrices
-- and evaluated at some `N` is exactly $χ_M (N)$.
rw mat_poly_equiv_smul_one at h,
-- Thus we have $χ_M(M) = 0$, which is the desired result.
exact h,
end
2 changes: 2 additions & 0 deletions src/ring_theory/polynomial_algebra.lean
Expand Up @@ -8,6 +8,8 @@ import ring_theory.matrix_algebra
import data.polynomial

/-!
semorrison marked this conversation as resolved.
Show resolved Hide resolved
# Algebra isomorphism between matrices of polynomials and polynomials of matrices

Given `[comm_ring R] [ring A] [algebra R A]`
we show `polynomial A ≃ₐ[R] (A ⊗[R] polynomial R)`.
Combining this with the isomorphism `matrix n n A ≃ₐ[R] (A ⊗[R] matrix n n R)` proved earlier
Expand Down