Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit d04e3fc

Browse files
feat(linear_algebra/char_poly): relates the characteristic polynomial to trace, determinant, and dimension (#3536)
adds lemmas about the number of fixed points of a permutation adds lemmas connecting the trace, determinant, and dimension of a matrix to its characteristic polynomial Co-authored-by: Aaron Anderson <awainverse@gmail.com> Co-authored-by: Aaron Anderson <65780815+awainverse@users.noreply.github.com>
1 parent a9481d9 commit d04e3fc

File tree

4 files changed

+205
-1
lines changed

4 files changed

+205
-1
lines changed

src/data/matrix/basic.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,9 @@ begin
466466
simp,
467467
end
468468

469+
lemma scalar.commute [decidable_eq n] (r : α) (M : matrix n n α) : commute (scalar n r) M :=
470+
by simp [commute, semiconj_by]
471+
469472
end comm_semiring
470473

471474
section semiring

src/group_theory/perm/cycles.lean

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,27 @@ def cycle_factors [fintype α] [decidable_linear_order α] (f : perm α) :
144144
{l : list (perm α) // l.prod = f ∧ (∀ g ∈ l, is_cycle g) ∧ l.pairwise disjoint} :=
145145
cycle_factors_aux (univ.sort (≤)) f (λ _ _, (mem_sort _).2 (mem_univ _))
146146

147+
section fixed_points
148+
149+
lemma one_lt_nonfixed_point_card_of_ne_one [fintype α] {σ : perm α} (h : σ ≠ 1) :
150+
1 < (filter (λ x, σ x ≠ x) univ).card :=
151+
begin
152+
rw one_lt_card_iff,
153+
contrapose! h, ext, dsimp,
154+
have := h (σ x) x, contrapose! this, simpa,
155+
end
156+
157+
lemma fixed_point_card_lt_of_ne_one [fintype α] {σ : perm α} (h : σ ≠ 1) :
158+
(filter (λ x, σ x = x) univ).card < fintype.card α - 1 :=
159+
begin
160+
rw nat.lt_sub_left_iff_add_lt, apply nat.add_lt_of_lt_sub_right,
161+
convert one_lt_nonfixed_point_card_of_ne_one h,
162+
rw [nat.sub_eq_iff_eq_add, add_comm], swap, { apply card_le_of_subset, simp },
163+
rw ← card_disjoint_union, swap, { rw [disjoint_iff_inter_eq_empty, filter_inter_filter_neg_eq] },
164+
rw filter_union_filter_neg_eq, refl
165+
end
166+
167+
end fixed_points
168+
169+
147170
end equiv.perm
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/-
2+
Copyright (c) 2020 Aaron Anderson, Jalex Stark. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: Aaron Anderson, Jalex Stark.
5+
-/
6+
7+
import linear_algebra.char_poly
8+
import linear_algebra.matrix
9+
import ring_theory.polynomial.basic
10+
import algebra.polynomial.big_operators
11+
import group_theory.perm.cycles
12+
13+
/-!
14+
# Characteristic polynomials
15+
16+
We give methods for computing coefficients of the characteristic polynomial.
17+
18+
## Main definitions
19+
20+
- `char_poly_degree_eq_dim` proves that the degree of the characteristic polynomial
21+
over a nonzero ring is the dimension of the matrix
22+
- `det_eq_sign_char_poly_coeff` proves that the determinant is the constant term of the characteristic
23+
polynomial, up to sign.
24+
- `trace_eq_neg_char_poly_coeff` proves that the trace is the negative of the (d-1)th coefficient of the
25+
characteristic polynomial, where d is the dimension of the matrix.
26+
For a nonzero ring, this is the second-highest coefficient.
27+
28+
-/
29+
30+
noncomputable theory
31+
32+
universes u v w z
33+
34+
open polynomial matrix
35+
open_locale big_operators
36+
37+
variables {R : Type u} [comm_ring R]
38+
variables {n G : Type v} [fintype n] [decidable_eq n]
39+
variables {α β : Type v} [decidable_eq α]
40+
41+
42+
open finset
43+
open polynomial
44+
45+
variable {M : matrix n n R}
46+
47+
lemma char_matrix_apply_nat_degree [nontrivial R] (i j : n) :
48+
(char_matrix M i j).nat_degree = ite (i = j) 1 0 :=
49+
by { by_cases i = j; simp [h, ← degree_eq_iff_nat_degree_eq_of_pos (nat.succ_pos 0)], }
50+
51+
lemma char_matrix_apply_nat_degree_le (i j : n) :
52+
(char_matrix M i j).nat_degree ≤ ite (i = j) 1 0 :=
53+
by split_ifs; simp [h, nat_degree_X_sub_C_le]
54+
55+
variable (M)
56+
lemma char_poly_sub_diagonal_degree_lt :
57+
(char_poly M - ∏ (i : n), (X - C (M i i))).degree < ↑(fintype.card n - 1) :=
58+
begin
59+
rw [char_poly, det, ← insert_erase (mem_univ (equiv.refl n)),
60+
sum_insert (not_mem_erase (equiv.refl n) univ), add_comm],
61+
simp only [char_matrix_apply_eq, one_mul, equiv.perm.sign_refl, id.def, int.cast_one,
62+
units.coe_one, add_sub_cancel, equiv.coe_refl],
63+
rw ← mem_degree_lt, apply submodule.sum_mem (degree_lt R (fintype.card n - 1)),
64+
intros c hc, rw [← C_eq_int_cast, C_mul'],
65+
apply submodule.smul_mem (degree_lt R (fintype.card n - 1)) ↑↑(equiv.perm.sign c),
66+
rw mem_degree_lt, apply lt_of_le_of_lt degree_le_nat_degree _, rw with_bot.coe_lt_coe,
67+
apply lt_of_le_of_lt _ (equiv.perm.fixed_point_card_lt_of_ne_one (ne_of_mem_erase hc)),
68+
apply le_trans (polynomial.nat_degree_prod_le univ (λ i : n, (char_matrix M (c i) i))) _,
69+
rw card_eq_sum_ones, rw sum_filter, apply sum_le_sum,
70+
intros, apply char_matrix_apply_nat_degree_le,
71+
end
72+
73+
lemma char_poly_coeff_eq_prod_coeff_of_le {k : ℕ} (h : fintype.card n - 1 ≤ k) :
74+
(char_poly M).coeff k = (∏ i : n, (X - C (M i i))).coeff k :=
75+
begin
76+
apply eq_of_sub_eq_zero, rw ← coeff_sub, apply polynomial.coeff_eq_zero_of_degree_lt,
77+
apply lt_of_lt_of_le (char_poly_sub_diagonal_degree_lt M) _, rw with_bot.coe_le_coe, apply h,
78+
end
79+
80+
lemma det_of_card_zero (h : fintype.card n = 0) (M : matrix n n R) : M.det = 1 :=
81+
by { rw fintype.card_eq_zero_iff at h, suffices : M = 1, { simp [this] }, ext, tauto }
82+
83+
84+
theorem char_poly_degree_eq_dim [nontrivial R] (M : matrix n n R) :
85+
(char_poly M).degree = fintype.card n :=
86+
begin
87+
by_cases fintype.card n = 0, rw h, unfold char_poly, rw det_of_card_zero, simpa,
88+
rw ← sub_add_cancel (char_poly M) (∏ (i : n), (X - C (M i i))),
89+
have h1 : (∏ (i : n), (X - C (M i i))).degree = fintype.card n,
90+
{ rw degree_eq_iff_nat_degree_eq_of_pos, swap, apply nat.pos_of_ne_zero h,
91+
rw nat_degree_prod', simp_rw nat_degree_X_sub_C, unfold fintype.card, simp,
92+
simp_rw (monic_X_sub_C _).leading_coeff, simp, },
93+
rw degree_add_eq_of_degree_lt, exact h1, rw h1,
94+
apply lt_trans (char_poly_sub_diagonal_degree_lt M), rw with_bot.coe_lt_coe,
95+
rw ← nat.pred_eq_sub_one, apply nat.pred_lt, apply h,
96+
end
97+
98+
theorem char_poly_nat_degree_eq_dim [nontrivial R] (M : matrix n n R) :
99+
(char_poly M).nat_degree = fintype.card n :=
100+
nat_degree_eq_of_degree_eq_some (char_poly_degree_eq_dim M)
101+
102+
lemma char_poly_monic_of_nontrivial [nontrivial R] (M : matrix n n R) :
103+
monic (char_poly M) :=
104+
begin
105+
by_cases fintype.card n = 0, rw [char_poly, det_of_card_zero h], apply monic_one,
106+
have mon : (∏ (i : n), (X - C (M i i))).monic,
107+
{ apply monic_prod_of_monic univ (λ i : n, (X - C (M i i))), simp [monic_X_sub_C], },
108+
rw ← sub_add_cancel (∏ (i : n), (X - C (M i i))) (char_poly M) at mon,
109+
rw monic at *, rw leading_coeff_add_of_degree_lt at mon, rw ← mon,
110+
rw char_poly_degree_eq_dim, rw ← neg_sub, rw degree_neg,
111+
apply lt_trans (char_poly_sub_diagonal_degree_lt M), rw with_bot.coe_lt_coe,
112+
rw ← nat.pred_eq_sub_one, apply nat.pred_lt, apply h,
113+
end
114+
115+
lemma char_poly_monic (M : matrix n n R) :
116+
monic (char_poly M) :=
117+
begin
118+
classical, by_cases h : nontrivial R,
119+
{ letI := h, apply char_poly_monic_of_nontrivial, },
120+
{ rw nontrivial_iff at h, push_neg at h, apply h, }
121+
end
122+
123+
theorem trace_eq_neg_char_poly_coeff [nonempty n] (M : matrix n n R) :
124+
(matrix.trace n R R) M = -(char_poly M).coeff (fintype.card n - 1) :=
125+
begin
126+
by_cases nontrivial R; try { rw not_nontrivial_iff_subsingleton at h }; haveI := h, swap,
127+
{ apply subsingleton.elim },
128+
rw char_poly_coeff_eq_prod_coeff_of_le, swap, refl,
129+
rw [fintype.card, prod_X_sub_C_coeff_card_pred univ (λ i : n, M i i)], simp,
130+
rw [← fintype.card, fintype.card_pos_iff], apply_instance,
131+
end
132+
133+
-- I feel like this should use polynomial.alg_hom_eval₂_algebra_map
134+
lemma mat_poly_equiv_eval (M : matrix n n (polynomial R)) (r : R) (i j : n) :
135+
(mat_poly_equiv M).eval ((scalar n) r) i j = (M i j).eval r :=
136+
begin
137+
unfold polynomial.eval, unfold eval₂,
138+
transitivity finsupp.sum (mat_poly_equiv M) (λ (e : ℕ) (a : matrix n n R),
139+
(a * (scalar n) r ^ e) i j),
140+
{ unfold finsupp.sum, rw sum_apply, rw sum_apply, dsimp, refl, },
141+
{ simp_rw ← (scalar n).map_pow, simp_rw ← (matrix.scalar.commute _ _).eq,
142+
simp only [coe_scalar, matrix.one_mul, ring_hom.id_apply,
143+
smul_val, mul_eq_mul, algebra.smul_mul_assoc],
144+
have h : ∀ x : ℕ, (λ (e : ℕ) (a : R), r ^ e * a) x 0 = 0 := by simp,
145+
symmetry, rw ← finsupp.sum_map_range_index h, swap, refl,
146+
refine congr (congr rfl _) (by {ext, rw mul_comm}), ext, rw finsupp.map_range_apply,
147+
simp [apply_eq_coeff], }
148+
end
149+
150+
lemma eval_det (M : matrix n n (polynomial R)) (r : R) :
151+
polynomial.eval r M.det = (polynomial.eval (matrix.scalar n r) (mat_poly_equiv M)).det :=
152+
begin
153+
rw [polynomial.eval, ← coe_eval₂_ring_hom, ring_hom.map_det],
154+
apply congr_arg det, ext, symmetry, convert mat_poly_equiv_eval _ _ _ _,
155+
end
156+
157+
theorem det_eq_sign_char_poly_coeff (M : matrix n n R) :
158+
M.det = (-1)^(fintype.card n) * (char_poly M).coeff 0:=
159+
begin
160+
rw [coeff_zero_eq_eval_zero, char_poly, eval_det, mat_poly_equiv_char_matrix, ← det_smul],
161+
simp
162+
end

src/linear_algebra/determinant.lean

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ Authors: Kenny Lau, Chris Hughes, Tim Baanen
66
import data.matrix.pequiv
77
import data.fintype.card
88
import group_theory.perm.sign
9+
import ring_theory.algebra
910

10-
universes u v
11+
universes u v w z
1112
open equiv equiv.perm finset function
1213

1314
namespace matrix
@@ -144,6 +145,21 @@ calc det (c • A) = det (matrix.mul (diagonal (λ _, c)) A) : by rw [smul_eq_di
144145
... = det (diagonal (λ _, c)) * det A : det_mul _ _
145146
... = c ^ fintype.card n * det A : by simp [card_univ]
146147

148+
section hom_map
149+
150+
variables {S : Type w} [comm_ring S]
151+
152+
lemma ring_hom.map_det {M : matrix n n R} {f : R →+* S} :
153+
f M.det = matrix.det (f.map_matrix M) :=
154+
by simp [matrix.det, f.map_sum, f.map_prod]
155+
156+
lemma alg_hom.map_det [algebra R S] {T : Type z} [comm_ring T] [algebra R T]
157+
{M : matrix n n S} {f : S →ₐ[R] T} :
158+
f M.det = matrix.det ((f : S →+* T).map_matrix M) :=
159+
by rw [← alg_hom.coe_to_ring_hom, ring_hom.map_det]
160+
161+
end hom_map
162+
147163
section det_zero
148164
/-!
149165
### `det_zero` section

0 commit comments

Comments
 (0)