Skip to content

Commit dd2550d

Browse files
jjaassoonnriccardobrascaeric-wieser
authored andcommitted
feat(LinearAlgebra/PiTensorProduct): arbitrary tensor product of algebras (#9395)
Let $R$ be a commutative ring and $(A_i)$ a bunch of $R$-algebras, then $\bigotimes_{R} A$ is an $R$-algebra as well. In particular, taking $R$ to be $\mathbb{Z}$, we get tensor product of rings Co-authored-by: Riccardo Brasca <riccardo.brasca@gmail.com> Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
1 parent ddc619b commit dd2550d

4 files changed

Lines changed: 325 additions & 0 deletions

File tree

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3328,6 +3328,7 @@ import Mathlib.RingTheory.Nullstellensatz
33283328
import Mathlib.RingTheory.OreLocalization.Basic
33293329
import Mathlib.RingTheory.OreLocalization.OreSet
33303330
import Mathlib.RingTheory.Perfection
3331+
import Mathlib.RingTheory.PiTensorProduct
33313332
import Mathlib.RingTheory.Polynomial.Basic
33323333
import Mathlib.RingTheory.Polynomial.Bernstein
33333334
import Mathlib.RingTheory.Polynomial.Chebyshev

Mathlib/LinearAlgebra/Multilinear/Basic.lean

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,19 @@ sending a multilinear map `g` to `g (f₁ ⬝ , ..., fₙ ⬝ )` is linear in `g
10401040
· exact Function.apply_update c f i (a • f₀) j
10411041
· exact Function.apply_update c f i f₀ j
10421042

1043+
/--
1044+
Let `M₁ᵢ` and `M₁ᵢ'` be two families of `R`-modules and `M₂` an `R`-module.
1045+
Let us denote `Π i, M₁ᵢ` and `Π i, M₁ᵢ'` by `M` and `M'` respectively.
1046+
If `g` is a multilinear map `M' → M₂`, then `g` can be reinterpreted as a multilinear
1047+
map from `Π i, M₁ᵢ ⟶ M₁ᵢ'` to `M ⟶ M₂` via `(fᵢ) ↦ v ↦ g(fᵢ vᵢ)`.
1048+
-/
1049+
@[simps!] def piLinearMap :
1050+
MultilinearMap R M₁' M₂ →ₗ[R]
1051+
MultilinearMap R (fun i ↦ M₁ i →ₗ[R] M₁' i) (MultilinearMap R M₁ M₂) where
1052+
toFun g := (LinearMap.applyₗ g).compMultilinearMap compLinearMapMultilinear
1053+
map_add' := by aesop
1054+
map_smul' := by aesop
1055+
10431056
end
10441057

10451058
/-- If one multiplies by `c i` the coordinates in a finset `s`, then the image under a multilinear

Mathlib/LinearAlgebra/PiTensorProduct.lean

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ open MultilinearMap
357357

358358
variable {s}
359359

360+
section lift
361+
360362
/-- Auxiliary function to constructing a linear map `(⨂[R] i, s i) → E` given a
361363
`MultilinearMap R s E` with the property that its composition with the canonical
362364
`MultilinearMap R s (⨂[R] i, s i)` is the given multilinear map. -/
@@ -446,6 +448,84 @@ theorem lift_tprod : lift (tprod R : MultilinearMap R s _) = LinearMap.id :=
446448
Eq.symm <| lift.unique' rfl
447449
#align pi_tensor_product.lift_tprod PiTensorProduct.lift_tprod
448450

451+
end lift
452+
453+
section map
454+
455+
variable {t t' : ι → Type*}
456+
variable [∀ i, AddCommMonoid (t i)] [∀ i, Module R (t i)]
457+
variable [∀ i, AddCommMonoid (t' i)] [∀ i, Module R (t' i)]
458+
459+
/--
460+
Let `sᵢ` and `tᵢ` be two families of `R`-modules.
461+
Let `f` be a family of `R`-linear maps between `sᵢ` and `tᵢ`, i.e. `f : Πᵢ sᵢ → tᵢ`,
462+
then there is an induced map `⨂ᵢ sᵢ → ⨂ᵢ tᵢ` by `⨂ aᵢ ↦ ⨂ fᵢ aᵢ`.
463+
464+
This is `TensorProduct.map` for an arbitrary family of modules.
465+
-/
466+
def map (f : Π i, s i →ₗ[R] t i) : (⨂[R] i, s i) →ₗ[R] ⨂[R] i, t i :=
467+
lift <| (tprod R).compLinearMap f
468+
469+
@[simp] lemma map_tprod (f : Π i, s i →ₗ[R] t i) (x : Π i, s i) :
470+
map f (tprod R x) = tprod R fun i ↦ f i (x i) :=
471+
lift.tprod _
472+
473+
/--
474+
Let `sᵢ` and `tᵢ` be families of `R`-modules.
475+
Then there is an `R`-linear map between `⨂ᵢ Hom(sᵢ, tᵢ)` and `Hom(⨂ᵢ sᵢ, ⨂ tᵢ)` defined by
476+
`⨂ᵢ fᵢ ↦ ⨂ᵢ aᵢ ↦ ⨂ᵢ fᵢ aᵢ`.
477+
478+
This is `TensorProduct.homTensorHomMap` for an arbitrary family of modules.
479+
480+
Note that `PiTensorProduct.piTensorHomMap (tprod R f)` is equal to `PiTensorProduct.map f`.
481+
-/
482+
def piTensorHomMap : (⨂[R] i, s i →ₗ[R] t i) →ₗ[R] (⨂[R] i, s i) →ₗ[R] ⨂[R] i, t i :=
483+
lift.toLinearMap ∘ₗ lift (MultilinearMap.piLinearMap <| tprod R)
484+
485+
@[simp] lemma piTensorHomMap_tprod_tprod (f : Π i, s i →ₗ[R] t i) (x : Π i, s i) :
486+
piTensorHomMap (tprod R f) (tprod R x) = tprod R fun i ↦ f i (x i) := by
487+
simp [piTensorHomMap]
488+
489+
lemma piTensorHomMap_tprod_eq_map (f : Π i, s i →ₗ[R] t i) :
490+
piTensorHomMap (tprod R f) = map f := by
491+
ext; simp
492+
493+
/--
494+
Let `sᵢ`, `tᵢ` and `t'ᵢ` be families of `R`-modules, then `f : Πᵢ sᵢ → tᵢ → t'ᵢ` induces an
495+
element of `Hom(⨂ᵢ sᵢ, Hom(⨂ tᵢ, ⨂ᵢ t'ᵢ))` defined by `⨂ᵢ aᵢ ↦ ⨂ᵢ bᵢ ↦ ⨂ᵢ fᵢ aᵢ bᵢ`.
496+
497+
This is `PiTensorProduct.map` for two arbitrary families of modules.
498+
This is `TensorProduct.map₂` for families of modules.
499+
-/
500+
def map₂ (f : Π i, s i →ₗ[R] t i →ₗ[R] t' i) :
501+
(⨂[R] i, s i) →ₗ[R] (⨂[R] i, t i) →ₗ[R] ⨂[R] i, t' i:=
502+
lift <| LinearMap.compMultilinearMap piTensorHomMap <| (tprod R).compLinearMap f
503+
504+
lemma map₂_tprod_tprod (f : Π i, s i →ₗ[R] t i →ₗ[R] t' i) (x : Π i, s i) (y : Π i, t i) :
505+
map₂ f (tprod R x) (tprod R y) = tprod R fun i ↦ f i (x i) (y i) := by
506+
simp [map₂]
507+
508+
/--
509+
Let `sᵢ`, `tᵢ` and `t'ᵢ` be families of `R`-modules.
510+
Then there is an linear map from `⨂ᵢ Hom(sᵢ, Hom(tᵢ, t'ᵢ))` to `Hom(⨂ᵢ sᵢ, Hom(⨂ tᵢ, ⨂ᵢ t'ᵢ))`
511+
defined by `⨂ᵢ fᵢ ↦ ⨂ᵢ aᵢ ↦ ⨂ᵢ bᵢ ↦ ⨂ᵢ fᵢ aᵢ bᵢ`.
512+
513+
This is `TensorProduct.homTensorHomMap` for two arbitrary families of modules.
514+
-/
515+
def piTensorHomMap₂ : (⨂[R] i, s i →ₗ[R] t i →ₗ[R] t' i) →ₗ[R]
516+
(⨂[R] i, s i) →ₗ[R] (⨂[R] i, t i) →ₗ[R] (⨂[R] i, t' i) where
517+
toFun φ := lift <| LinearMap.compMultilinearMap piTensorHomMap <|
518+
(lift <| MultilinearMap.piLinearMap <| tprod R) φ
519+
map_add' x y := by dsimp; ext; simp
520+
map_smul' r x := by dsimp; ext; simp
521+
522+
@[simp] lemma piTensorHomMap₂_tprod_tprod_tprod
523+
(f : ∀ i, s i →ₗ[R] t i →ₗ[R] t' i) (a : ∀ i, s i) (b : ∀ i, t i) :
524+
piTensorHomMap₂ (tprod R f) (tprod R a) (tprod R b) = tprod R (fun i ↦ f i (a i) (b i)) := by
525+
simp [piTensorHomMap₂]
526+
527+
end map
528+
449529
section
450530

451531
variable (R M)
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
/-
2+
Copyright (c) 2024 Jujian Zhang. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Jujian Zhang
5+
-/
6+
7+
import Mathlib.LinearAlgebra.PiTensorProduct
8+
import Mathlib.Algebra.Algebra.Bilinear
9+
10+
/-!
11+
# Tensor product of `R`-algebras and rings
12+
13+
If `(Aᵢ)` is a family of `R`-algebras then the `R`-tensor product `⨂ᵢ Aᵢ` is an `R`-algebra as well
14+
with structure map defined by `r ↦ r • 1`.
15+
16+
In particular if we take `R` to be `ℤ`, then this collapses into the tensor product of rings.
17+
-/
18+
19+
open TensorProduct Function
20+
21+
variable {ι R' R : Type*} {A : ι → Type*}
22+
23+
namespace PiTensorProduct
24+
25+
noncomputable section AddCommMonoidWithOne
26+
27+
variable [CommSemiring R] [∀ i, AddCommMonoidWithOne (A i)] [∀ i, Module R (A i)]
28+
29+
instance instOne : One (⨂[R] i, A i) where
30+
one := tprod R 1
31+
32+
lemma one_def : 1 = tprod R (1 : Π i, A i) := rfl
33+
34+
instance instAddCommMonoidWithOne : AddCommMonoidWithOne (⨂[R] i, A i) where
35+
__ := inferInstanceAs (AddCommMonoid (⨂[R] i, A i))
36+
__ := instOne
37+
38+
end AddCommMonoidWithOne
39+
40+
noncomputable section NonUnitalNonAssocSemiring
41+
42+
variable [CommSemiring R] [∀ i, NonUnitalNonAssocSemiring (A i)]
43+
variable [∀ i, Module R (A i)] [∀ i, SMulCommClass R (A i) (A i)] [∀ i, IsScalarTower R (A i) (A i)]
44+
45+
attribute [aesop safe] mul_add mul_smul_comm smul_mul_assoc add_mul in
46+
/--
47+
The multiplication in tensor product of rings is induced by `(xᵢ) * (yᵢ) = (xᵢ * yᵢ)`
48+
-/
49+
def mul : (⨂[R] i, A i) →ₗ[R] (⨂[R] i, A i) →ₗ[R] (⨂[R] i, A i) :=
50+
PiTensorProduct.piTensorHomMap₂ <| tprod R fun _ ↦ LinearMap.mul _ _
51+
52+
@[simp] lemma mul_tprod_tprod (x y : (i : ι) → A i) :
53+
mul (tprod R x) (tprod R y) = tprod R (x * y) := by
54+
simp only [mul, piTensorHomMap₂_tprod_tprod_tprod, LinearMap.mul_apply']
55+
rfl
56+
57+
instance instMul : Mul (⨂[R] i, A i) where
58+
mul x y := mul x y
59+
60+
lemma mul_def (x y : ⨂[R] i, A i) : x * y = mul x y := rfl
61+
62+
@[simp] lemma tprod_mul_tprod (x y : (i : ι) → A i) :
63+
tprod R x * tprod R y = tprod R (x * y) :=
64+
mul_tprod_tprod x y
65+
66+
lemma smul_tprod_mul_smul_tprod (r s : R) (x y : Π i, A i) :
67+
(r • tprod R x) * (s • tprod R y) = (r * s) • tprod R (x * y) := by
68+
change mul _ _ = _
69+
rw [map_smul, map_smul, mul_comm r s, mul_smul]
70+
simp only [LinearMap.smul_apply, mul_tprod_tprod]
71+
72+
instance instNonUnitalNonAssocSemiring : NonUnitalNonAssocSemiring (⨂[R] i, A i) where
73+
__ := instMul
74+
__ := inferInstanceAs (AddCommMonoid (⨂[R] i, A i))
75+
left_distrib _ _ _ := (mul _).map_add _ _
76+
right_distrib _ _ _ := mul.map_add₂ _ _ _
77+
zero_mul _ := mul.map_zero₂ _
78+
mul_zero _ := map_zero (mul _)
79+
80+
end NonUnitalNonAssocSemiring
81+
82+
noncomputable section NonAssocSemiring
83+
84+
variable [CommSemiring R] [∀ i, NonAssocSemiring (A i)]
85+
variable [∀ i, Module R (A i)] [∀ i, SMulCommClass R (A i) (A i)] [∀ i, IsScalarTower R (A i) (A i)]
86+
87+
protected lemma one_mul (x : ⨂[R] i, A i) : mul (tprod R 1) x = x := by
88+
induction x using PiTensorProduct.induction_on with
89+
| smul_tprod => simp
90+
| add _ _ h1 h2 => simp [map_add, h1, h2]
91+
92+
protected lemma mul_one (x : ⨂[R] i, A i) : mul x (tprod R 1) = x := by
93+
induction x using PiTensorProduct.induction_on with
94+
| smul_tprod => simp
95+
| add _ _ h1 h2 => simp [h1, h2]
96+
97+
instance instNonAssocSemiring : NonAssocSemiring (⨂[R] i, A i) where
98+
__ := instNonUnitalNonAssocSemiring
99+
one_mul := PiTensorProduct.one_mul
100+
mul_one := PiTensorProduct.mul_one
101+
102+
end NonAssocSemiring
103+
104+
noncomputable section NonUnitalSemiring
105+
106+
variable [CommSemiring R] [∀ i, NonUnitalSemiring (A i)]
107+
variable [∀ i, Module R (A i)] [∀ i, SMulCommClass R (A i) (A i)] [∀ i, IsScalarTower R (A i) (A i)]
108+
109+
protected lemma mul_assoc (x y z : ⨂[R] i, A i) : mul (mul x y) z = mul x (mul y z) := by
110+
-- restate as an equality of morphisms so that we can use `ext`
111+
suffices LinearMap.llcomp R _ _ _ mul ∘ₗ mul =
112+
(LinearMap.llcomp R _ _ _ LinearMap.lflip <| LinearMap.llcomp R _ _ _ mul.flip ∘ₗ mul).flip by
113+
exact DFunLike.congr_fun (DFunLike.congr_fun (DFunLike.congr_fun this x) y) z
114+
ext x y z
115+
dsimp [← mul_def]
116+
simpa only [tprod_mul_tprod] using congr_arg (tprod R) (mul_assoc x y z)
117+
118+
instance instNonUnitalSemiring : NonUnitalSemiring (⨂[R] i, A i) where
119+
__ := instNonUnitalNonAssocSemiring
120+
mul_assoc := PiTensorProduct.mul_assoc
121+
122+
end NonUnitalSemiring
123+
124+
noncomputable section Semiring
125+
126+
variable [CommSemiring R'] [CommSemiring R] [∀ i, Semiring (A i)]
127+
variable [Algebra R' R] [∀ i, Algebra R (A i)] [∀ i, Algebra R' (A i)]
128+
variable [∀ i, IsScalarTower R' R (A i)]
129+
130+
instance instSemiring : Semiring (⨂[R] i, A i) where
131+
__ := instNonUnitalSemiring
132+
__ := instNonAssocSemiring
133+
134+
instance instAlgebra : Algebra R' (⨂[R] i, A i) where
135+
__ := hasSMul'
136+
toFun := (· • 1)
137+
map_one' := by simp
138+
map_mul' r s := show (r * s) • 1 = mul (r • 1) (s • 1) by
139+
rw [LinearMap.map_smul_of_tower, LinearMap.map_smul_of_tower, LinearMap.smul_apply, mul_comm,
140+
mul_smul]
141+
congr
142+
show (1 : ⨂[R] i, A i) = 1 * 1
143+
rw [mul_one]
144+
map_zero' := by simp
145+
map_add' := by simp [add_smul]
146+
commutes' r x := by
147+
simp only [RingHom.coe_mk, MonoidHom.coe_mk, OneHom.coe_mk]
148+
change mul _ _ = mul _ _
149+
rw [LinearMap.map_smul_of_tower, LinearMap.map_smul_of_tower, LinearMap.smul_apply]
150+
change r • (1 * x) = r • (x * 1)
151+
rw [mul_one, one_mul]
152+
smul_def' r x := by
153+
simp only [RingHom.coe_mk, MonoidHom.coe_mk, OneHom.coe_mk]
154+
change _ = mul _ _
155+
rw [LinearMap.map_smul_of_tower, LinearMap.smul_apply]
156+
change _ = r • (1 * x)
157+
rw [one_mul]
158+
159+
lemma algebraMap_apply (r : R') (i : ι) [DecidableEq ι] :
160+
algebraMap R' (⨂[R] i, A i) r = tprod R (Pi.mulSingle i (algebraMap R' (A i) r)) := by
161+
change r • tprod R 1 = _
162+
have : Pi.mulSingle i (algebraMap R' (A i) r) = update (fun i ↦ 1) i (r • 1) := by
163+
rw [Algebra.algebraMap_eq_smul_one]; rfl
164+
rw [this, ← smul_one_smul R r (1 : A i), MultilinearMap.map_smul, update_eq_self, smul_one_smul]
165+
congr
166+
167+
/--
168+
The map `Aᵢ ⟶ ⨂ᵢ Aᵢ` given by `a ↦ 1 ⊗ ... ⊗ a ⊗ 1 ⊗ ...`
169+
-/
170+
@[simps]
171+
def singleAlgHom [DecidableEq ι] (i : ι) : A i →ₐ[R] ⨂[R] i, A i where
172+
toFun a := tprod R (MonoidHom.single _ i a)
173+
map_one' := by simp only [_root_.map_one]; rfl
174+
map_mul' a a' := by simp
175+
map_zero' := MultilinearMap.map_update_zero _ _ _
176+
map_add' _ _ := MultilinearMap.map_add _ _ _ _ _
177+
commutes' r := show tprodCoeff R _ _ = r • tprodCoeff R _ _ by
178+
rw [Algebra.algebraMap_eq_smul_one]
179+
erw [smul_tprodCoeff]
180+
rfl
181+
182+
/--
183+
Lifting a multilinear map to an algebra homomorphism from tensor product
184+
-/
185+
@[simps!]
186+
def liftAlgHom {S : Type*} [Semiring S] [Algebra R S]
187+
(f : MultilinearMap R A S)
188+
(one : f 1 = 1) (mul : ∀ x y, f (x * y) = f x * f y) : (⨂[R] i, A i) →ₐ[R] S :=
189+
AlgHom.ofLinearMap (lift f) (show lift f (tprod R 1) = 1 by simp [one]) <|
190+
LinearMap.map_mul_iff _ |>.mpr <| by aesop
191+
192+
end Semiring
193+
194+
noncomputable section Ring
195+
196+
variable [CommRing R] [∀ i, Ring (A i)] [∀ i, Algebra R (A i)]
197+
198+
instance instRing : Ring (⨂[R] i, A i) where
199+
__ := instSemiring
200+
__ := inferInstanceAs <| AddCommGroup (⨂[R] i, A i)
201+
202+
end Ring
203+
204+
noncomputable section CommSemiring
205+
206+
variable [CommSemiring R] [∀ i, CommSemiring (A i)] [∀ i, Algebra R (A i)]
207+
208+
protected lemma mul_comm (x y : ⨂[R] i, A i) : mul x y = mul y x := by
209+
suffices mul (R := R) (A := A) = mul.flip from
210+
DFunLike.congr_fun (DFunLike.congr_fun this x) y
211+
ext x y
212+
dsimp
213+
simp only [mul_tprod_tprod, mul_tprod_tprod, mul_comm x y]
214+
215+
instance instCommSemiring : CommSemiring (⨂[R] i, A i) where
216+
__ := instSemiring
217+
__ := inferInstanceAs <| AddCommMonoid (⨂[R] i, A i)
218+
mul_comm := PiTensorProduct.mul_comm
219+
220+
end CommSemiring
221+
222+
noncomputable section CommRing
223+
224+
variable [CommRing R] [∀ i, CommRing (A i)] [∀ i, Algebra R (A i)]
225+
instance instCommRing : CommRing (⨂[R] i, A i) where
226+
__ := instCommSemiring
227+
__ := inferInstanceAs <| AddCommGroup (⨂[R] i, A i)
228+
229+
end CommRing
230+
231+
end PiTensorProduct

0 commit comments

Comments
 (0)