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

Commit abfddbf

Browse files
feat(ring_theory): define left_mul_matrix and algebra.trace (#6653)
This PR defines the algebra trace, and the bilinear trace form, for an algebra `S` over a ring `R`, for example a field extension `L / K`. Follow-up PRs will prove that `algebra.trace K L x` is the sum of the conjugate roots of `x` in `L`, that `trace_form` is nondegenerate and that `trace K L x` is integral over `K`. Then we'll use this to find an integral basis for field extensions, and then we can prove that the integral closure of a Dedekind domain is again a Dedekind domain. Co-authored-by: Anne Baanen <Vierkantor@users.noreply.github.com> Co-authored-by: Bryan Gin-ge Chen <bryangingechen@gmail.com>
1 parent b75ec5c commit abfddbf

File tree

5 files changed

+276
-9
lines changed

5 files changed

+276
-9
lines changed

src/algebra/algebra/tower.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ def lsmul : A →ₐ[R] module.End R M :=
4545

4646
@[simp] lemma lsmul_coe (a : A) : (lsmul R M a : M → M) = (•) a := rfl
4747

48+
@[simp] lemma lmul_algebra_map (x : R) :
49+
lmul R A (algebra_map R A x) = algebra.lsmul R A x :=
50+
eq.symm $ linear_map.ext $ smul_def'' x
51+
4852
end algebra
4953

5054
namespace is_scalar_tower

src/algebra/lie/matrix.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def lie_equiv_matrix' : module.End R (n → R) ≃ₗ⁅R⁆ matrix n n R :=
5353
/-- An invertible matrix induces a Lie algebra equivalence from the space of matrices to itself. -/
5454
noncomputable def matrix.lie_conj (P : matrix n n R) (h : is_unit P) :
5555
matrix n n R ≃ₗ⁅R⁆ matrix n n R :=
56-
((@lie_equiv_matrix' R _ n _ _).symm.trans (P.to_linear_equiv h).lie_conj).trans lie_equiv_matrix'
56+
((@lie_equiv_matrix' R _ n _ _).symm.trans (P.to_linear_equiv' h).lie_conj).trans lie_equiv_matrix'
5757

5858
@[simp] lemma matrix.lie_conj_apply (P A : matrix n n R) (h : is_unit P) :
5959
P.lie_conj h A = P ⬝ A ⬝ P⁻¹ :=

src/linear_algebra/finite_dimensional.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,10 @@ begin
541541
rw h, norm_cast
542542
end
543543

544+
lemma findim_eq_zero_of_not_exists_basis
545+
(h : ¬ ∃ s : finset V, is_basis K (λ x, x : (↑s : set V) → V)) : findim K V = 0 :=
546+
dif_neg (mt (λ h, @exists_is_basis_finset K V _ _ _ (finite_dimensional_iff_dim_lt_omega.mpr h)) h)
547+
544548
variables (K V)
545549

546550
lemma finite_dimensional_bot : finite_dimensional K (⊥ : submodule K V) :=

src/linear_algebra/matrix.lean

Lines changed: 142 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import linear_algebra.finite_dimensional
77
import linear_algebra.nonsingular_inverse
88
import linear_algebra.multilinear
99
import linear_algebra.dual
10+
import ring_theory.algebra_tower
11+
import ring_theory.matrix_algebra
1012

1113
/-!
1214
# Linear maps and matrices
@@ -299,6 +301,9 @@ begin
299301
simp [linear_map.to_matrix_apply, is_basis.equiv_fun, matrix.one_apply, finsupp.single, eq_comm]
300302
end
301303

304+
lemma linear_map.to_matrix_one : linear_map.to_matrix hv₁ hv₁ 1 = 1 :=
305+
linear_map.to_matrix_id hv₁
306+
302307
@[simp]
303308
lemma matrix.to_lin_one : matrix.to_lin hv₁ hv₁ 1 = id :=
304309
by rw [← linear_map.to_matrix_id hv₁, matrix.to_lin_to_matrix]
@@ -323,6 +328,14 @@ lemma linear_map.to_matrix_mul (f g : M₁ →ₗ[R] M₁) :
323328
by { rw [show (@has_mul.mul (M₁ →ₗ[R] M₁) _) = linear_map.comp, from rfl,
324329
linear_map.to_matrix_comp hv₁ hv₁ hv₁ f g] }
325330

331+
lemma linear_map.to_matrix_mul_vec_repr (f : M₁ →ₗ[R] M₂) (x : M₁) :
332+
(linear_map.to_matrix hv₁ hv₂ f).mul_vec (hv₁.repr x) = hv₂.repr (f x) :=
333+
by { ext i,
334+
rw [← matrix.to_lin'_apply, linear_map.to_matrix, linear_equiv.trans_apply,
335+
matrix.to_lin'_to_matrix', linear_equiv.arrow_congr_apply, hv₂.equiv_fun_apply],
336+
congr,
337+
exact hv₁.equiv_fun.symm_apply_apply x }
338+
326339
lemma matrix.to_lin_mul [decidable_eq m] (A : matrix l m R) (B : matrix m n R) :
327340
matrix.to_lin hv₁ hv₃ (A ⬝ B) =
328341
(matrix.to_lin hv₂ hv₃ A).comp (matrix.to_lin hv₁ hv₂ B) :=
@@ -704,6 +717,8 @@ variables {n} {R} {M}
704717

705718
@[simp] lemma trace_diag (A : matrix n n M) : trace n R M A = ∑ i, diag n R M A i := rfl
706719

720+
lemma trace_apply (A : matrix n n M) : trace n R M A = ∑ i, A i i := rfl
721+
707722
@[simp] lemma trace_one [decidable_eq n] :
708723
trace n R R 1 = fintype.card n :=
709724
have h : trace n R R 1 = ∑ i, diag n R R 1 i := rfl,
@@ -744,8 +759,11 @@ lemma diagonal_to_lin' (w : n → R) :
744759
(diagonal w).to_lin' = linear_map.pi (λi, w i • linear_map.proj i) :=
745760
by ext v j; simp [mul_vec_diagonal]
746761

747-
/-- An invertible matrix yields a linear equivalence from the free module to itself. -/
748-
def to_linear_equiv (P : matrix n n R) (h : is_unit P) : (n → R) ≃ₗ[R] (n → R) :=
762+
/-- An invertible matrix yields a linear equivalence from the free module to itself.
763+
764+
See `matrix.to_linear_equiv` for the same map on arbitrary modules.
765+
-/
766+
def to_linear_equiv' (P : matrix n n R) (h : is_unit P) : (n → R) ≃ₗ[R] (n → R) :=
749767
have h' : is_unit P.det := P.is_unit_iff_is_unit_det.mp h,
750768
{ inv_fun := P⁻¹.to_lin',
751769
left_inv := λ v,
@@ -756,11 +774,11 @@ have h' : is_unit P.det := P.is_unit_iff_is_unit_det.mp h,
756774
by rw [← matrix.to_lin'_mul, P.mul_nonsing_inv h', matrix.to_lin'_one, linear_map.id_apply],
757775
..P.to_lin' }
758776

759-
@[simp] lemma to_linear_equiv_apply (P : matrix n n R) (h : is_unit P) :
760-
(↑(P.to_linear_equiv h) : module.End R (n → R)) = P.to_lin' := rfl
777+
@[simp] lemma to_linear_equiv'_apply (P : matrix n n R) (h : is_unit P) :
778+
(↑(P.to_linear_equiv' h) : module.End R (n → R)) = P.to_lin' := rfl
761779

762-
@[simp] lemma to_linear_equiv_symm_apply (P : matrix n n R) (h : is_unit P) :
763-
(↑(P.to_linear_equiv h).symm : module.End R (n → R)) = P⁻¹.to_lin' := rfl
780+
@[simp] lemma to_linear_equiv'_symm_apply (P : matrix n n R) (h : is_unit P) :
781+
(↑(P.to_linear_equiv' h).symm : module.End R (n → R)) = P⁻¹.to_lin' := rfl
764782

765783
end ring
766784

@@ -813,6 +831,34 @@ begin
813831
apply h₂,
814832
end
815833

834+
variables {R M : Type*} [comm_ring R] [add_comm_group M] [module R M]
835+
variables {b : n → M} (hb : is_basis R b)
836+
837+
include hb
838+
839+
/-- Given `hA : is_unit A.det` and `hb : is_basis R b`, `A.to_linear_equiv hb hA` is
840+
the `linear_equiv` arising from `to_lin hb hb A`.
841+
842+
See `matrix.to_linear_equiv'` for this result on `n → R`.
843+
-/
844+
@[simps apply]
845+
def to_linear_equiv [decidable_eq n] (A : matrix n n R) (hA : is_unit A.det) :
846+
M ≃ₗ[R] M :=
847+
begin
848+
refine ⟨to_lin hb hb A, linear_map.map_add _, linear_map.map_smul _, to_lin hb hb A⁻¹,
849+
λ x, _, λ x, _⟩;
850+
simp only [← linear_map.comp_apply, ← to_lin_mul,
851+
matrix.nonsing_inv_mul _ hA, matrix.mul_nonsing_inv _ hA,
852+
to_lin_one, linear_map.id_apply]
853+
end
854+
lemma ker_to_lin_eq_bot [decidable_eq n] (A : matrix n n R) (hA : is_unit A.det) :
855+
(to_lin hb hb A).ker = ⊥ :=
856+
ker_eq_bot.mpr (to_linear_equiv hb A hA).injective
857+
858+
lemma range_to_lin_eq_top [decidable_eq n] (A : matrix n n R) (hA : is_unit A.det) :
859+
(to_lin hb hb A).range = ⊤ :=
860+
range_eq_top.mpr (to_linear_equiv hb A hA).surjective
861+
816862
end vector_space
817863

818864
section finite_dimensional
@@ -998,6 +1044,92 @@ end reindexing
9981044

9991045
end matrix
10001046

1047+
namespace algebra
1048+
1049+
section lmul
1050+
1051+
variables {R S T : Type*} [comm_ring R] [comm_ring S] [comm_ring T]
1052+
variables [algebra R S] [algebra S T] [algebra R T] [is_scalar_tower R S T]
1053+
variables {m n : Type*} [fintype m] [decidable_eq m] [fintype n] [decidable_eq n]
1054+
variables {b : m → S} (hb : is_basis R b) {c : n → T} (hc : is_basis S c)
1055+
1056+
open algebra
1057+
1058+
lemma to_matrix_lmul' (x : S) (i j) :
1059+
linear_map.to_matrix hb hb (lmul R S x) i j = hb.repr (x * b j) i :=
1060+
by rw [linear_map.to_matrix_apply', lmul_apply]
1061+
1062+
@[simp] lemma to_matrix_lsmul (x : R) (i j) :
1063+
linear_map.to_matrix hb hb (algebra.lsmul R S x) i j = if i = j then x else 0 :=
1064+
by { rw [linear_map.to_matrix_apply', algebra.lsmul_coe, linear_map.map_smul, finsupp.smul_apply,
1065+
hb.repr_self_apply, smul_eq_mul, mul_boole],
1066+
congr' 1; simp only [eq_comm] }
1067+
1068+
/-- `left_mul_matrix hb x` is the matrix corresponding to the linear map `λ y, x * y`.
1069+
1070+
`left_mul_matrix_eq_repr_mul` gives a formula for the entries of `left_mul_matrix`.
1071+
1072+
This definition is useful for doing (more) explicit computations with `algebra.lmul`,
1073+
such as the trace form or norm map for algebras.
1074+
-/
1075+
noncomputable def left_mul_matrix : S →ₐ[R] matrix m m R :=
1076+
{ to_fun := λ x, linear_map.to_matrix hb hb (algebra.lmul R S x),
1077+
map_zero' := by rw [alg_hom.map_zero, linear_equiv.map_zero],
1078+
map_one' := by rw [alg_hom.map_one, linear_map.to_matrix_one],
1079+
map_add' := λ x y, by rw [alg_hom.map_add, linear_equiv.map_add],
1080+
map_mul' := λ x y, by rw [alg_hom.map_mul, linear_map.to_matrix_mul, matrix.mul_eq_mul],
1081+
commutes' := λ r, by { ext, rw [lmul_algebra_map, to_matrix_lsmul,
1082+
algebra_map_matrix_apply, id.map_eq_self] } }
1083+
1084+
lemma left_mul_matrix_apply (x : S) :
1085+
left_mul_matrix hb x = linear_map.to_matrix hb hb (lmul R S x) := rfl
1086+
1087+
lemma left_mul_matrix_eq_repr_mul (x : S) (i j) :
1088+
left_mul_matrix hb x i j = hb.repr (x * b j) i :=
1089+
-- This is defeq to just `to_matrix_lmul' hb x i j`,
1090+
-- but the unfolding goes a lot faster with this explicit `rw`.
1091+
by rw [left_mul_matrix_apply, to_matrix_lmul' hb x i j]
1092+
1093+
lemma left_mul_matrix_mul_vec_repr (x y : S) :
1094+
(left_mul_matrix hb x).mul_vec (hb.repr y) = hb.repr (x * y) :=
1095+
linear_map.to_matrix_mul_vec_repr hb hb (algebra.lmul R S x) y
1096+
1097+
@[simp] lemma to_matrix_lmul_eq (x : S) :
1098+
linear_map.to_matrix hb hb (lmul R S x) = left_mul_matrix hb x :=
1099+
rfl
1100+
1101+
lemma left_mul_matrix_injective : function.injective (left_mul_matrix hb) :=
1102+
λ x x' h, calc x = algebra.lmul R S x 1 : (mul_one x).symm
1103+
... = algebra.lmul R S x' 1 : by rw (linear_map.to_matrix hb hb).injective h
1104+
... = x' : mul_one x'
1105+
1106+
lemma smul_left_mul_matrix (x) (i j) (k k') :
1107+
left_mul_matrix (hb.smul hc) x (i, k) (j, k') =
1108+
left_mul_matrix hb (left_mul_matrix hc x k k') i j :=
1109+
by simp only [left_mul_matrix_apply, linear_map.to_matrix_apply, is_basis.equiv_fun_apply, mul_comm,
1110+
is_basis.smul_repr, finsupp.smul_apply, algebra.lmul_apply, id.smul_eq_mul,
1111+
linear_map.map_smul, mul_smul_comm]
1112+
1113+
lemma smul_left_mul_matrix_algebra_map (x : S) :
1114+
left_mul_matrix (hb.smul hc) (algebra_map _ _ x) = block_diagonal (λ k, left_mul_matrix hb x) :=
1115+
begin
1116+
ext ⟨i, k⟩ ⟨j, k'⟩,
1117+
rw [smul_left_mul_matrix, alg_hom.commutes, block_diagonal_apply, algebra_map_matrix_apply],
1118+
split_ifs with h; simp [h],
1119+
end
1120+
1121+
lemma smul_left_mul_matrix_algebra_map_eq (x : S) (i j k) :
1122+
left_mul_matrix (hb.smul hc) (algebra_map _ _ x) (i, k) (j, k) = left_mul_matrix hb x i j :=
1123+
by rw [smul_left_mul_matrix_algebra_map, block_diagonal_apply_eq]
1124+
1125+
lemma smul_left_mul_matrix_algebra_map_ne (x : S) (i j) {k k'}
1126+
(h : k ≠ k') : left_mul_matrix (hb.smul hc) (algebra_map _ _ x) (i, k) (j, k') = 0 :=
1127+
by rw [smul_left_mul_matrix_algebra_map, block_diagonal_apply_ne _ _ _ h]
1128+
1129+
end lmul
1130+
1131+
end algebra
1132+
10011133
namespace linear_map
10021134

10031135
open_locale matrix
@@ -1008,7 +1140,8 @@ def trace_aux (R : Type u) [comm_ring R] {M : Type v} [add_comm_group M] [module
10081140
(M →ₗ[R] M) →ₗ[R] R :=
10091141
(matrix.trace ι R R).comp $ linear_map.to_matrix hb hb
10101142

1011-
@[simp] lemma trace_aux_def (R : Type u) [comm_ring R] {M : Type v} [add_comm_group M] [module R M]
1143+
-- Can't be `simp` because it would cause a loop.
1144+
lemma trace_aux_def (R : Type u) [comm_ring R] {M : Type v} [add_comm_group M] [module R M]
10121145
{ι : Type w} [decidable_eq ι] [fintype ι] {b : ι → M} (hb : is_basis R b) (f : M →ₗ[R] M) :
10131146
trace_aux R hb f = matrix.trace ι R R (linear_map.to_matrix hb hb f) :=
10141147
rfl
@@ -1066,7 +1199,8 @@ else 0
10661199

10671200
theorem trace_eq_matrix_trace (R : Type u) [comm_ring R] {M : Type v} [add_comm_group M]
10681201
[module R M] {ι : Type w} [fintype ι] [decidable_eq ι] {b : ι → M} (hb : is_basis R b)
1069-
(f : M →ₗ[R] M) : trace R M f = matrix.trace ι R R (linear_map.to_matrix hb hb f) :=
1202+
(f : M →ₗ[R] M) :
1203+
trace R M f = matrix.trace ι R R (linear_map.to_matrix hb hb f) :=
10701204
have ∃ s : finset M, is_basis R (λ x, x : (↑s : set M) → M),
10711205
from ⟨finset.univ.image b,
10721206
by { rw [finset.coe_image, finset.coe_univ, set.image_univ], exact hb.range }⟩,

src/ring_theory/trace.lean

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/-
2+
Copyright (c) 2020 Anne Baanen. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Anne Baanen
5+
-/
6+
7+
import linear_algebra.bilinear_form
8+
import ring_theory.power_basis
9+
10+
/-!
11+
# Trace for (finite) ring extensions.
12+
13+
Suppose we have an `R`-algebra `S` with a finite basis. For each `s : S`,
14+
the trace of the linear map given by multiplying by `s` gives information about
15+
the roots of the minimal polynomial of `s` over `R`.
16+
17+
## Implementation notes
18+
19+
Typically, the trace is defined specifically for finite field extensions.
20+
The definition is as general as possible and the assumption that we have
21+
fields or that the extension is finite is added to the lemmas as needed.
22+
23+
We only define the trace for left multiplication (`algebra.left_mul_matrix`,
24+
i.e. `algebra.lmul_left`).
25+
For now, the definitions assume `S` is commutative, so the choice doesn't matter anyway.
26+
27+
## References
28+
29+
* https://en.wikipedia.org/wiki/Field_trace
30+
31+
-/
32+
33+
universes u v w
34+
35+
variables {R S T : Type*} [comm_ring R] [comm_ring S] [comm_ring T]
36+
variables [algebra R S] [algebra R T]
37+
variables {K L : Type*} [field K] [field L] [algebra K L]
38+
variables {ι : Type w} [fintype ι]
39+
40+
open finite_dimensional
41+
open linear_map
42+
open matrix
43+
44+
open_locale big_operators
45+
open_locale matrix
46+
47+
namespace algebra
48+
49+
variables {b : ι → S} (hb : is_basis R b)
50+
51+
variables (R S)
52+
53+
/-- The trace of an element `s` of an `R`-algebra is the trace of `(*) s`,
54+
as an `R`-linear map. -/
55+
@[simps]
56+
noncomputable def trace : S →ₗ[R] R :=
57+
(linear_map.trace R S).comp (lmul R S).to_linear_map
58+
59+
variables {S}
60+
61+
lemma trace_eq_zero_of_not_exists_basis
62+
(h : ¬ ∃ s : finset S, is_basis R (λ x, x : (↑s : set S) → S)) : trace R S = 0 :=
63+
by { ext s, simp [linear_map.trace, h] }
64+
65+
include hb
66+
67+
variables {R}
68+
69+
-- Can't be a `simp` lemma because it depends on a choice of basis
70+
lemma trace_eq_matrix_trace [decidable_eq ι] (hb : is_basis R b) (s : S) :
71+
trace R S s = matrix.trace _ R _ (algebra.left_mul_matrix hb s) :=
72+
by rw [trace_apply, linear_map.trace_eq_matrix_trace _ hb, to_matrix_lmul_eq]
73+
74+
/-- If `x` is in the base field `K`, then the trace is `[L : K] * x`. -/
75+
lemma trace_algebra_map_of_basis (x : R) :
76+
trace R S (algebra_map R S x) = fintype.card ι • x :=
77+
begin
78+
haveI := classical.dec_eq ι,
79+
rw [trace_apply, linear_map.trace_eq_matrix_trace R hb, trace_diag],
80+
convert finset.sum_const _,
81+
ext i,
82+
simp,
83+
end
84+
omit hb
85+
86+
/-- If `x` is in the base field `K`, then the trace is `[L : K] * x`.
87+
88+
(If `L` is not finite-dimensional over `K`, then `trace` and `findim` return `0`.)
89+
-/
90+
@[simp]
91+
lemma trace_algebra_map (x : K) : trace K L (algebra_map K L x) = findim K L • x :=
92+
begin
93+
by_cases H : ∃ s : finset L, is_basis K (λ x, x : (↑s : set L) → L),
94+
{ rw [trace_algebra_map_of_basis H.some_spec, findim_eq_card_basis H.some_spec] },
95+
{ simp [trace_eq_zero_of_not_exists_basis K H, findim_eq_zero_of_not_exists_basis H] },
96+
end
97+
98+
section trace_form
99+
100+
variables (R S)
101+
102+
/-- The `trace_form` maps `x y : S` to the trace of `x * y`.
103+
It is a symmetric bilinear form and is nondegenerate if the extension is separable. -/
104+
noncomputable def trace_form : bilin_form R S :=
105+
(linear_map.compr₂ (lmul R S).to_linear_map (trace R S)).to_bilin
106+
107+
variables {S}
108+
109+
-- This is a nicer lemma than the one produced by `@[simps] def trace_form`.
110+
@[simp] lemma trace_form_apply (x y : S) : trace_form R S x y = trace R S (x * y) := rfl
111+
112+
lemma trace_form_is_sym : sym_bilin_form.is_sym (trace_form R S) :=
113+
λ x y, congr_arg (trace R S) (mul_comm _ _)
114+
115+
lemma trace_form_to_matrix [decidable_eq ι] (i j) :
116+
bilin_form.to_matrix hb (trace_form R S) i j = trace R S (b i * b j) :=
117+
by rw [bilin_form.to_matrix_apply, trace_form_apply]
118+
119+
lemma trace_form_to_matrix_power_basis (h : power_basis R S) :
120+
bilin_form.to_matrix h.is_basis (trace_form R S) = λ i j, (trace R S (h.gen ^ (i + j : ℕ))) :=
121+
by { ext, rw [trace_form_to_matrix, pow_add] }
122+
123+
end trace_form
124+
125+
end algebra

0 commit comments

Comments
 (0)