Skip to content

Commit a5a0f4c

Browse files
feat: base change properties, direct sums, bases, modules of linear maps (#31240)
Establish various `IsBaseChange` properties: * direct sums commute with base change * when the source module is finite free, modules of linear maps commute with base change (on the right, on both sides, and for endomorphisms). * a base change of a free module is free, with compatible bases. Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent 7cc87f6 commit a5a0f4c

File tree

9 files changed

+437
-11
lines changed

9 files changed

+437
-11
lines changed

Mathlib.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6130,6 +6130,8 @@ public import Mathlib.RingTheory.TensorProduct.Basic
61306130
public import Mathlib.RingTheory.TensorProduct.DirectLimitFG
61316131
public import Mathlib.RingTheory.TensorProduct.Finite
61326132
public import Mathlib.RingTheory.TensorProduct.Free
6133+
public import Mathlib.RingTheory.TensorProduct.IsBaseChangeFree
6134+
public import Mathlib.RingTheory.TensorProduct.IsBaseChangeHom
61336135
public import Mathlib.RingTheory.TensorProduct.IsBaseChangePi
61346136
public import Mathlib.RingTheory.TensorProduct.Maps
61356137
public import Mathlib.RingTheory.TensorProduct.MonoidAlgebra

Mathlib/Algebra/DirectSum/Finsupp.lean

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,22 @@ theorem finsuppLEquivDirectSum_single (i : ι) (m : M) :
4343
finsuppLEquivDirectSum R M ι (Finsupp.single i m) = DirectSum.lof R ι _ i m :=
4444
Finsupp.toDFinsupp_single i m
4545

46+
@[simp]
47+
theorem finsuppLEquivDirectSum_apply (m : ι →₀ M) (i : ι) :
48+
finsuppLEquivDirectSum R M ι m i = m i := by
49+
rfl
50+
4651
@[simp]
4752
theorem finsuppLEquivDirectSum_symm_lof (i : ι) (m : M) :
4853
(finsuppLEquivDirectSum R M ι).symm (DirectSum.lof R ι _ i m) = Finsupp.single i m :=
4954
letI : ∀ m : M, Decidable (m ≠ 0) := Classical.decPred _
5055
DFinsupp.toFinsupp_single i m
5156

57+
theorem lmap_finsuppLEquivDirectSum_eq {N : Type*} [AddCommMonoid N] [Module R N]
58+
(ε : M →ₗ[R] N) (m : ι →₀ M) :
59+
(lmap fun _ ↦ ε) ((finsuppLEquivDirectSum R M ι) m) =
60+
(finsuppLEquivDirectSum R N ι) (m.mapRange ⇑ε ε.map_zero) := by
61+
ext i
62+
rfl
63+
5264
end finsuppLequivDirectSum

Mathlib/Algebra/DirectSum/Module.lean

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,4 +545,44 @@ end Ring
545545

546546
end Submodule
547547

548+
section Congr
549+
550+
variable {R : Type*} [Semiring R]
551+
{ι : Type*}
552+
{N : ι → Type*} [(i : ι) → AddCommMonoid (N i)] [(i : ι) → Module R (N i)]
553+
{P : ι → Type*} [∀ i, AddCommMonoid (P i)] [∀ i, Module R (P i)]
554+
555+
/-- Direct sums of isomorphic additive groups are isomorphic. -/
556+
def congr_addEquiv (u : (i : ι) → N i ≃+ P i) :
557+
(⨁ i, N i) ≃+ ⨁ i, P i where
558+
toAddHom := DirectSum.map fun i ↦ (u i).toAddMonoidHom
559+
invFun := DirectSum.map fun i ↦ (u i).symm.toAddMonoidHom
560+
left_inv x := by aesop
561+
right_inv y := by aesop
562+
563+
theorem coe_congr_addEquiv (u : (i : ι) → N i ≃+ P i) :
564+
⇑(congr_addEquiv u).toAddMonoidHom = ⇑(DirectSum.map fun i ↦ (u i).toAddMonoidHom) :=
565+
rfl
566+
567+
/-- Direct sums of isomorphic modules are isomorphic. -/
568+
def congr_linearEquiv (u : (i : ι) → N i ≃ₗ[R] P i) :
569+
(⨁ i, N i) ≃ₗ[R] ⨁ i, P i where
570+
toAddEquiv := congr_addEquiv (fun i ↦ (u i).toAddEquiv)
571+
map_smul' r x := by
572+
exact (DirectSum.lmap (fun i ↦ (u i).toLinearMap)).map_smul r x
573+
574+
theorem coe_congr_linearEquiv (u : (i : ι) → N i ≃ₗ[R] P i) :
575+
⇑(congr_linearEquiv u) = ⇑(DirectSum.lmap (fun i ↦ (u i).toLinearMap)) :=
576+
rfl
577+
578+
theorem congr_linearEquiv_toAddEquiv (u : (i : ι) → N i ≃ₗ[R] P i) :
579+
(congr_linearEquiv u).toAddEquiv = congr_addEquiv (fun i ↦ (u i).toAddEquiv) :=
580+
rfl
581+
582+
theorem congr_linearEquiv_toLinearMap (u : (i : ι) → N i ≃ₗ[R] P i) :
583+
(congr_linearEquiv u).toLinearMap = DirectSum.lmap (fun i ↦ (u i).toLinearMap) :=
584+
rfl
585+
586+
end Congr
587+
548588
end DirectSum

Mathlib/LinearAlgebra/DirectSum/TensorProduct.lean

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ theorem directSumLeft_symm_lof_tmul (i : ι₁) (x : M₁ i) (y : M₂') :
116116
DirectSum.lof R _ _ i x ⊗ₜ[R] y := by
117117
rw [LinearEquiv.symm_apply_eq, directSumLeft_tmul_lof]
118118

119+
@[simp]
120+
lemma directSumLeft_tmul (m : ⨁ i, M₁ i) (n : M₂') (i : ι₁) :
121+
directSumLeft R M₁ M₂' (m ⊗ₜ[R] n) i = (m i) ⊗ₜ[R] n := by
122+
suffices (DirectSum.component R ι₁ _ i) ∘ₗ(directSumLeft R M₁ M₂').toLinearMap ∘ₗ
123+
((TensorProduct.mk R (⨁ i, M₁ i) M₂').flip n) =
124+
((TensorProduct.mk R (M₁ i) M₂').flip n) ∘ₗ (DirectSum.component R ι₁ M₁ i) by
125+
simpa using LinearMap.congr_fun this m
126+
ext j n
127+
by_cases hj : j = i
128+
· subst hj; simp
129+
· simp [DirectSum.component.of, hj]
130+
119131
@[simp]
120132
theorem directSumRight_tmul_lof (x : M₁') (i : ι₂) (y : M₂ i) :
121133
directSumRight R M₁' M₂ (x ⊗ₜ[R] DirectSum.lof R _ _ i y) =
@@ -135,6 +147,49 @@ lemma directSumRight_comp_rTensor (f : M₁' →ₗ[R] M₂') :
135147
(lmap fun _ ↦ f.rTensor _) ∘ₗ directSumRight R M₁' M₁ := by
136148
ext; simp
137149

150+
@[simp]
151+
lemma directSumRight_tmul (m : M₁') (n : ⨁ i, M₂ i) (i : ι₂) :
152+
directSumRight R M₁' M₂ (m ⊗ₜ[R] n) i = m ⊗ₜ[R] (n i) := by
153+
suffices (DirectSum.component R ι₂ _ i) ∘ₗ(directSumRight R M₁' M₂).toLinearMap ∘ₗ
154+
(TensorProduct.mk R M₁' (⨁ i, M₂ i) m) =
155+
(TensorProduct.mk R M₁' (M₂ i) m) ∘ₗ (DirectSum.component R ι₂ M₂ i) by
156+
simpa using LinearMap.congr_fun this n
157+
ext j n
158+
by_cases hj : j = i
159+
· subst hj; simp
160+
· simp [DirectSum.component.of, hj]
161+
162+
variable [Module S M₁'] [IsScalarTower R S M₁']
163+
164+
-- NB. Why not giving `TensorProduct.directSumRight` the adequate linearity?
165+
variable (M₁' M₂) in
166+
/-- Tensor products distribute over a direct sum on the right.
167+
168+
This version has more linearity than `TensorProduct.directSumRight`. -/
169+
def directSumRight' : (M₁' ⊗[R] ⨁ i, M₂ i) ≃ₗ[S] ⨁ i, M₁' ⊗[R] M₂ i where
170+
toAddEquiv := (directSumRight ..).toAddEquiv
171+
map_smul' s t := by
172+
induction t using TensorProduct.induction_on with
173+
| zero => simp
174+
| add x y hx hy =>
175+
simp only [AddHom.toFun_eq_coe, coe_toAddHom,
176+
LinearEquiv.coe_coe, RingHom.id_apply] at hx hy ⊢
177+
simp only [smul_add, map_add, hx, hy]
178+
| tmul m n =>
179+
simp
180+
rw [TensorProduct.smul_tmul']
181+
ext i
182+
rw [DirectSum.smul_apply, directSumRight_tmul,
183+
directSumRight_tmul, TensorProduct.smul_tmul']
184+
185+
lemma directSumRight'_restrict :
186+
(directSumRight' R S M₁' M₂).restrictScalars R = directSumRight R M₁' M₂ :=
187+
rfl
188+
189+
lemma coe_directSumRight' :
190+
⇑(directSumRight' R S M₁' M₂) = directSumRight R M₁' M₂ :=
191+
rfl
192+
138193
end TensorProduct
139194

140195
end Ring

Mathlib/LinearAlgebra/TensorProduct/Tower.lean

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,14 @@ lemma baseChange_mul (f g : Module.End R M) :
643643

644644
variable (R A M N)
645645

646+
/-- `baseChange A e` for `e : M ≃ₗ[R] N` is the `A`-linear map `A ⊗[R] M ≃ₗ[A] A ⊗[R] N`. -/
647+
def _root_.LinearEquiv.baseChange (e : M ≃ₗ[R] N) : A ⊗[R] M ≃ₗ[A] A ⊗[R] N :=
648+
AlgebraTensorModule.congr (.refl _ _) e
649+
650+
theorem _root_.LinearEquiv.baseChange_tmul (e : M ≃ₗ[R] N) (a : A) (m : M) :
651+
LinearEquiv.baseChange R A M N e (a ⊗ₜ[R] m) = a ⊗ₜ e m :=
652+
rfl
653+
646654
/-- `baseChange` as a linear map.
647655
648656
When `M = N`, this is true more strongly as `Module.End.baseChangeHom`. -/
@@ -661,13 +669,9 @@ lemma baseChange_pow (f : Module.End R M) (n : ℕ) :
661669
(f ^ n).baseChange A = f.baseChange A ^ n :=
662670
map_pow (Module.End.baseChangeHom _ _ _) f n
663671

664-
/-- `baseChange A e` for `e : M ≃ₗ[R] N` is the `A`-linear map `A ⊗[R] M ≃ₗ[A] A ⊗[R] N`. -/
665-
def _root_.LinearEquiv.baseChange (e : M ≃ₗ[R] N) : A ⊗[R] M ≃ₗ[A] A ⊗[R] N :=
666-
AlgebraTensorModule.congr (.refl _ _) e
667-
668672
@[simp]
669673
theorem _root_.LinearEquiv.coe_baseChange (e : M ≃ₗ[R] N) :
670-
(e.baseChange R A M N : (A ⊗[R] M →ₗ[A] A ⊗[R] N)) = e.toLinearMap.baseChange A :=
674+
(e.baseChange R A M N : (A ⊗[R] M →ₗ[A] A ⊗[R] N)) = LinearMap.baseChange A e :=
671675
rfl
672676

673677
@[simp]

Mathlib/RingTheory/IsTensorProduct.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,9 +263,11 @@ noncomputable nonrec def IsBaseChange.equiv : S ⊗[R] M ≃ₗ[S] N :=
263263
· intro x y hx hy
264264
rw [map_add, smul_add, map_add, smul_add, hx, hy] }
265265

266+
@[simp]
266267
theorem IsBaseChange.equiv_tmul (s : S) (m : M) : h.equiv (s ⊗ₜ m) = s • f m :=
267268
rfl
268269

270+
@[simp]
269271
theorem IsBaseChange.equiv_symm_apply (m : M) : h.equiv.symm (f m) = 1 ⊗ₜ m := by
270272
rw [h.equiv.symm_apply_eq, h.equiv_tmul, one_smul]
271273

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/-
2+
Copyright (c) 2025 Antoine Chambert-Loir. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Antoine Chambert-Loir
5+
-/
6+
module
7+
8+
public import Mathlib.RingTheory.TensorProduct.IsBaseChangePi
9+
public import Mathlib.LinearAlgebra.FreeModule.Basic
10+
11+
/-! # Base change of a free module
12+
13+
* `IsBaseChange.basis` : the natural basis of the base change of a module with a basis
14+
15+
* `IsBaseChange.free` : a base change of a free module is free.
16+
17+
-/
18+
19+
@[expose] public section
20+
21+
namespace IsBaseChange
22+
23+
variable {R : Type*} [CommSemiring R]
24+
{S : Type*} [CommSemiring S] [Algebra R S]
25+
{V : Type*} [AddCommMonoid V] [Module R V]
26+
{W : Type*} [AddCommMonoid W] [Module R W] [Module S W] [IsScalarTower R S W]
27+
{ι : Type*} [DecidableEq ι]
28+
{ε : V →ₗ[R] W}
29+
30+
variable (b : Module.Basis ι R V) (ibc : IsBaseChange S ε)
31+
32+
/-- The basis of a module deduced by base change from a free module with a basis. -/
33+
noncomputable def basis :
34+
Module.Basis ι S W where
35+
repr := (ibc.equiv.symm.trans (b.repr.baseChange R S _ _)).trans
36+
(finsuppPow ι (linearMap R S)).equiv
37+
38+
theorem basis_apply (i) : ibc.basis b i = ε (b i) := by
39+
simp [basis]
40+
simp [LinearEquiv.baseChange]
41+
generalize_proofs _ _ _ _ ibcRA
42+
have : ibcRA.equiv.symm (Finsupp.single i 1) = 1 ⊗ₜ (Finsupp.single i 1) := by
43+
simp [LinearEquiv.symm_apply_eq, IsBaseChange.equiv_tmul]
44+
simp [this, IsBaseChange.equiv_tmul]
45+
46+
theorem basis_repr_comp_apply (v i) :
47+
(ibc.basis b).repr (ε v) i = algebraMap R S (b.repr v i):= by
48+
conv_lhs => rw [← b.linearCombination_repr v, Finsupp.linearCombination_apply,
49+
map_finsuppSum, map_finsuppSum]
50+
simp only [map_smul, Finsupp.sum_apply]
51+
rw [Finsupp.sum_eq_single i]
52+
· rw [← IsScalarTower.algebraMap_smul S (b.repr v i) (ε (b i)),
53+
map_smul, ← ibc.basis_apply]
54+
simp [Finsupp.single_eq_same, Algebra.algebraMap_eq_smul_one]
55+
· intro i' _ h
56+
rw [← IsScalarTower.algebraMap_smul S (b.repr v i') (ε (b i')), map_smul,
57+
← ibc.basis_apply]
58+
simp [Finsupp.single_eq_of_ne (Ne.symm h)]
59+
· simp
60+
61+
theorem basis_repr_comp (v : V) :
62+
(ibc.basis b).repr (ε v) =
63+
Finsupp.mapRange.linearMap (Algebra.linearMap R S) (b.repr v) := by
64+
ext i
65+
simp [basis_repr_comp_apply]
66+
67+
variable [Module.Free R V]
68+
69+
include ibc in
70+
theorem free : Module.Free S W :=
71+
Module.Free.of_basis (ibc.basis (Module.Free.chooseBasis R V))
72+
73+
end IsBaseChange

0 commit comments

Comments
 (0)