Skip to content

Commit 433c275

Browse files
committed
feat(LinearAlgebra/BilinearForm/TensorProduct): base change of bilinear forms (#6306)
This generalizes the existing `BilinForm.tensorDistrib` to be heterogenous in the rings it uses, such that a base change, ```lean protected def baseChange (B : BilinForm R M₂) : BilinForm A (A ⊗[R] M₂) := ``` falls out as a special case. I do not attempt to generalize `BilinForm.tensorDistribEquiv`. Unfortunately, this changes the defeq as ```diff -(B₁.tmul B₂) (m₁ ⊗ₜ m₂) (m₁' ⊗ₜ m₂') = B₁ m₁ m₁' * B₂ m₂ m₂' +(B₁.tmul B₂) (m₁ ⊗ₜ m₂) (m₁' ⊗ₜ m₂') = B₂ m₂ m₂' • B₁ m₁ m₁' ``` We could fix this by using the right action instead, but that's a lot of work for a very minorly annoying defeq. This also breaks the defeq of `tensorDistribEquiv B = tensorDistrib B`; though the reason is more complicated than the scalar action issue above. It would be fixed if we defined all the homogenous operations on tensor products as special cases of the heterogenous ones, but that's also a lot of work for a very small win. This is a port of work from pygae/lean-ga#31, and almost at the end of the path to a base change of quadratic forms and clifford algebras. This was independently developed at the Leiden workshop as [`BilinForm.baseChange`](https://github.com/alexjbest/ant-lorentz/blob/1f97add294b2d50f99537c15583666d78b0d7e24/AntLorentz/BaseChange.lean#L75-L85), though the results there are not sorry-free.
1 parent 41e3e2b commit 433c275

2 files changed

Lines changed: 89 additions & 26 deletions

File tree

Mathlib/LinearAlgebra/BilinearForm/TensorProduct.lean

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Authors: Eric Wieser
55
-/
66
import Mathlib.LinearAlgebra.BilinearForm
77
import Mathlib.LinearAlgebra.TensorProduct
8+
import Mathlib.LinearAlgebra.TensorProduct.Tower
89

910
#align_import linear_algebra.bilinear_form.tensor_product from "leanprover-community/mathlib"@"f0c8bf9245297a541f468be517f1bde6195105e9"
1011

@@ -21,52 +22,76 @@ import Mathlib.LinearAlgebra.TensorProduct
2122
-/
2223

2324

24-
universe u v w
25+
universe u v w uι uR uA uM₁ uM₂
2526

26-
variable {ι : Type*} {R : Type*} {M₁ M₂ : Type*}
27+
variable {ι : Type} {R : Type uR} {A : Type uA} {M₁ : Type uM₁} {M₂ : Type uM₂}
2728

2829
open TensorProduct
2930

3031
namespace BilinForm
3132

3233
section CommSemiring
33-
34-
variable [CommSemiring R]
35-
34+
variable [CommSemiring R] [CommSemiring A]
3635
variable [AddCommMonoid M₁] [AddCommMonoid M₂]
37-
38-
variable [Module R M₁] [Module R M₂]
39-
40-
/-- The tensor product of two bilinear forms injects into bilinear forms on tensor products. -/
41-
def tensorDistrib : BilinForm R M₁ ⊗[R] BilinForm R M₂ →ₗ[R] BilinForm R (M₁ ⊗[R] M₂) :=
42-
((TensorProduct.tensorTensorTensorComm R _ _ _ _).dualMap ≪≫ₗ
43-
(TensorProduct.lift.equiv R _ _ _).symm ≪≫ₗ LinearMap.toBilin).toLinearMap ∘ₗ
44-
TensorProduct.dualDistrib R _ _ ∘ₗ
45-
(TensorProduct.congr (BilinForm.toLin ≪≫ₗ TensorProduct.lift.equiv R _ _ _)
36+
variable [Algebra R A] [Module R M₁] [Module A M₁]
37+
variable [SMulCommClass R A M₁] [SMulCommClass A R M₁] [IsScalarTower R A M₁]
38+
variable [Module R M₂]
39+
40+
variable (R A) in
41+
/-- The tensor product of two bilinear forms injects into bilinear forms on tensor products.
42+
43+
Note this is heterobasic; the bilinear form on the left can take values in an (commutative) algebra
44+
over the ring in which the right bilinear form is valued. -/
45+
def tensorDistrib : BilinForm A M₁ ⊗[R] BilinForm R M₂ →ₗ[A] BilinForm A (M₁ ⊗[R] M₂) :=
46+
((TensorProduct.AlgebraTensorModule.tensorTensorTensorComm R A M₁ M₂ M₁ M₂).dualMap
47+
≪≫ₗ (TensorProduct.lift.equiv A (M₁ ⊗[R] M₂) (M₁ ⊗[R] M₂) A).symm
48+
≪≫ₗ LinearMap.toBilin).toLinearMap
49+
∘ₗ TensorProduct.AlgebraTensorModule.dualDistrib R _ _ _
50+
∘ₗ (TensorProduct.AlgebraTensorModule.congr
51+
(BilinForm.toLin ≪≫ₗ TensorProduct.lift.equiv A _ _ _)
4652
(BilinForm.toLin ≪≫ₗ TensorProduct.lift.equiv R _ _ _)).toLinearMap
4753
#align bilin_form.tensor_distrib BilinForm.tensorDistrib
4854

55+
-- TODO: make the RHS `MulOpposite.op (B₂ m₂ m₂') • B₁ m₁ m₁'` so that this has a nicer defeq for
56+
-- `R = A` of `B₁ m₁ m₁' * B₂ m₂ m₂'`, as it did before the generalization in #6306.
4957
@[simp]
50-
theorem tensorDistrib_tmul (B₁ : BilinForm R M₁) (B₂ : BilinForm R M₂) (m₁ : M₁) (m₂ : M₂)
58+
theorem tensorDistrib_tmul (B₁ : BilinForm A M₁) (B₂ : BilinForm R M₂) (m₁ : M₁) (m₂ : M₂)
5159
(m₁' : M₁) (m₂' : M₂) :
52-
tensorDistrib (R := R) (B₁ ⊗ₜ B₂) (m₁ ⊗ₜ m₂) (m₁' ⊗ₜ m₂') = B₁ m₁ m₁' * B₂ m₂ m₂' :=
60+
tensorDistrib R A (B₁ ⊗ₜ B₂) (m₁ ⊗ₜ m₂) (m₁' ⊗ₜ m₂')
61+
= B₂ m₂ m₂' • B₁ m₁ m₁' :=
5362
rfl
54-
#align bilin_form.tensor_distrib_tmul BilinForm.tensorDistrib_tmul
63+
#align bilin_form.tensor_distrib_tmul BilinForm.tensorDistrib_tmulₓ
5564

5665
/-- The tensor product of two bilinear forms, a shorthand for dot notation. -/
5766
@[reducible]
58-
protected def tmul (B₁ : BilinForm R M₁) (B₂ : BilinForm R M₂) : BilinForm R (M₁ ⊗[R] M₂) :=
59-
tensorDistrib (R := R) (B₁ ⊗ₜ[R] B₂)
67+
protected def tmul (B₁ : BilinForm A M₁) (B₂ : BilinForm R M₂) : BilinForm A (M₁ ⊗[R] M₂) :=
68+
tensorDistrib R A (B₁ ⊗ₜ[R] B₂)
6069
#align bilin_form.tmul BilinForm.tmul
6170

6271
attribute [ext] TensorProduct.ext in
6372
/-- A tensor product of symmetric bilinear forms is symmetric. -/
64-
lemma IsSymm.tmul {B₁ : BilinForm R M₁} {B₂ : BilinForm R M₂}
73+
lemma IsSymm.tmul {B₁ : BilinForm A M₁} {B₂ : BilinForm R M₂}
6574
(hB₁ : B₁.IsSymm) (hB₂ : B₂.IsSymm) : (B₁.tmul B₂).IsSymm := by
6675
rw [isSymm_iff_flip R]
6776
apply toLin.injective
6877
ext x₁ x₂ y₁ y₂
69-
exact (congr_arg₂ (HMul.hMul) (hB₁ x₁ y₁) (hB₂ x₂ y₂)).symm
78+
exact (congr_arg₂ (HSMul.hSMul) (hB₂ x₂ y₂) (hB₁ x₁ y₁)).symm
79+
80+
variable (A) in
81+
/-- The base change of a bilinear form. -/
82+
protected def baseChange (B : BilinForm R M₂) : BilinForm A (A ⊗[R] M₂) :=
83+
BilinForm.tmul (R := R) (A := A) (M₁ := A) (M₂ := M₂) (LinearMap.toBilin <| LinearMap.mul A A) B
84+
85+
@[simp]
86+
theorem baseChange_tmul (B₂ : BilinForm R M₂) (a : A) (m₂ : M₂)
87+
(a' : A) (m₂' : M₂) :
88+
B₂.baseChange A (a ⊗ₜ m₂) (a' ⊗ₜ m₂') = (B₂ m₂ m₂') • (a * a') :=
89+
rfl
90+
91+
variable (A) in
92+
/-- The base change of a symmetric bilinear form is symmetric. -/
93+
lemma IsSymm.baseChange {B₂ : BilinForm R M₂} (hB₂ : B₂.IsSymm) : (B₂.baseChange A).IsSymm :=
94+
IsSymm.tmul mul_comm hB₂
7095

7196
end CommSemiring
7297

@@ -84,6 +109,7 @@ variable [Module.Free R M₂] [Module.Finite R M₂]
84109

85110
variable [Nontrivial R]
86111

112+
variable (R) in
87113
/-- `tensorDistrib` as an equivalence. -/
88114
noncomputable def tensorDistribEquiv :
89115
BilinForm R M₁ ⊗[R] BilinForm R M₂ ≃ₗ[R] BilinForm R (M₁ ⊗[R] M₂) :=
@@ -96,10 +122,28 @@ noncomputable def tensorDistribEquiv :
96122
(TensorProduct.lift.equiv R _ _ _).symm ≪≫ₗ LinearMap.toBilin
97123
#align bilin_form.tensor_distrib_equiv BilinForm.tensorDistribEquiv
98124

125+
-- this is a dsimp lemma
126+
@[simp, nolint simpNF]
127+
theorem tensorDistribEquiv_tmul (B₁ : BilinForm R M₁) (B₂ : BilinForm R M₂) (m₁ : M₁) (m₂ : M₂)
128+
(m₁' : M₁) (m₂' : M₂) :
129+
tensorDistribEquiv R (M₁ := M₁) (M₂ := M₂) (B₁ ⊗ₜ[R] B₂) (m₁ ⊗ₜ m₂) (m₁' ⊗ₜ m₂')
130+
= B₁ m₁ m₁' * B₂ m₂ m₂' :=
131+
rfl
132+
133+
variable (R M₁ M₂) in
134+
-- TODO: make this `rfl`
135+
@[simp]
136+
theorem tensorDistribEquiv_toLinearMap :
137+
(tensorDistribEquiv R (M₁ := M₁) (M₂ := M₂)).toLinearMap = tensorDistrib R R := by
138+
ext B₁ B₂ : 3
139+
apply toLin.injective
140+
ext
141+
exact mul_comm _ _
142+
99143
@[simp]
100144
theorem tensorDistribEquiv_apply (B : BilinForm R M₁ ⊗ BilinForm R M₂) :
101-
tensorDistribEquiv (R := R) (M₁ := M₁) (M₂ := M₂) B = tensorDistrib (R := R) B :=
102-
rfl
145+
tensorDistribEquiv R (M₁ := M₁) (M₂ := M₂) B = tensorDistrib R R B :=
146+
FunLike.congr_fun (tensorDistribEquiv_toLinearMap R M₁ M₂) B
103147
#align bilin_form.tensor_distrib_equiv_apply BilinForm.tensorDistribEquiv_apply
104148

105149
end CommRing

Mathlib/LinearAlgebra/Dual.lean

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Mathlib.LinearAlgebra.Projection
88
import Mathlib.LinearAlgebra.SesquilinearForm
99
import Mathlib.RingTheory.Finiteness
1010
import Mathlib.LinearAlgebra.FreeModule.Finite.Basic
11+
import Mathlib.RingTheory.TensorProduct
1112

1213
#align_import linear_algebra.dual from "leanprover-community/mathlib"@"b1c017582e9f18d8494e5c18602a8cb4a6f843ac"
1314

@@ -96,9 +97,9 @@ noncomputable section
9697
namespace Module
9798

9899
-- Porting note: max u v universe issues so name and specific below
99-
universe u v v' v'' w u₁ u₂
100+
universe u uA v v' v'' w u₁ u₂
100101

101-
variable (R : Type u) (M : Type v)
102+
variable (R : Type u) (A : Type uA) (M : Type v)
102103

103104
variable [CommSemiring R] [AddCommMonoid M] [Module R M]
104105

@@ -1566,7 +1567,7 @@ end VectorSpace
15661567

15671568
namespace TensorProduct
15681569

1569-
variable (R : Type*) (M : Type*) (N : Type*)
1570+
variable (R A : Type*) (M : Type*) (N : Type*)
15701571

15711572
variable {ι κ : Type*}
15721573

@@ -1608,6 +1609,24 @@ theorem dualDistrib_apply (f : Dual R M) (g : Dual R N) (m : M) (n : N) :
16081609

16091610
end
16101611

1612+
namespace AlgebraTensorModule
1613+
variable [CommSemiring R] [CommSemiring A] [Algebra R A] [AddCommMonoid M] [AddCommMonoid N]
1614+
1615+
variable [Module R M] [Module A M] [Module R N] [IsScalarTower R A M]
1616+
1617+
/-- Heterobasic version of `TensorProduct.dualDistrib` -/
1618+
def dualDistrib : Dual A M ⊗[R] Dual R N →ₗ[A] Dual A (M ⊗[R] N) :=
1619+
compRight (Algebra.TensorProduct.rid R A A) ∘ₗ homTensorHomMap R A A M N A R
1620+
1621+
variable {R M N}
1622+
1623+
@[simp]
1624+
theorem dualDistrib_apply (f : Dual A M) (g : Dual R N) (m : M) (n : N) :
1625+
dualDistrib R A M N (f ⊗ₜ g) (m ⊗ₜ n) = g n • f m :=
1626+
rfl
1627+
1628+
end AlgebraTensorModule
1629+
16111630
variable {R M N}
16121631

16131632
variable [CommRing R] [AddCommGroup M] [AddCommGroup N]

0 commit comments

Comments
 (0)