Skip to content

Commit d8c00d3

Browse files
joelrioueric-wieser
andcommitted
feat(LinearAlgebra/PiTensorProduct): dependent version of tmulEquiv (#18534)
Given a family of `R`-modules `N` indexed by `ι ⊕ ι'`, we obtain a linear equivalence `tmulEquivDep : (⨂[R] i₁, N (.inl i₁)) ⊗[R] (⨂[R] i₂, N (.inr i₂)) ≃ₗ[R] ⨂[R] i, N i`, which generalizes `tmulEquiv` (which is the case all `N i` are the same module). Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com> Co-authored-by: Eric Wieser <efw@google.com> Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
1 parent d31099d commit d8c00d3

File tree

6 files changed

+210
-134
lines changed

6 files changed

+210
-134
lines changed

Mathlib/Data/Sum/Basic.lean

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ theorem update_inr_apply_inr [DecidableEq β] [DecidableEq (α ⊕ β)] {f : α
111111
{x : γ} : update f (inr i) x (inr j) = update (f ∘ inr) i x j := by
112112
rw [← update_inr_comp_inr, Function.comp_apply]
113113

114+
@[simp]
115+
theorem update_inl_apply_inl' {γ : α ⊕ β → Type*} [DecidableEq α] [DecidableEq (α ⊕ β)]
116+
{f : (i : α ⊕ β) → γ i} {i : α} {x : γ (.inl i)} (j : α) :
117+
update f (.inl i) x (Sum.inl j) = update (fun j ↦ f (.inl j)) i x j :=
118+
Function.update_apply_of_injective f Sum.inl_injective i x j
119+
120+
@[simp]
121+
theorem update_inr_apply_inr' {γ : α ⊕ β → Type*} [DecidableEq β] [DecidableEq (α ⊕ β)]
122+
{f : (i : α ⊕ β) → γ i} {i : β} {x : γ (.inr i)} (j : β) :
123+
update f (.inr i) x (Sum.inr j) = update (fun j ↦ f (.inr j)) i x j :=
124+
Function.update_apply_of_injective f Sum.inr_injective i x j
125+
114126
@[simp]
115127
lemma rec_update_left {γ : α ⊕ β → Sort*} [DecidableEq α] [DecidableEq β]
116128
(f : ∀ a, γ (.inl a)) (g : ∀ b, γ (.inr b)) (a : α) (x : γ (.inl a)) :

Mathlib/LinearAlgebra/Multilinear/Basic.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,7 @@ protected def piRingEquiv [Fintype ι] : M₂ ≃ₗ[R] MultilinearMap R (fun _
13651365
right_inv f := f.mkPiRing_apply_one_eq_self
13661366

13671367
end CommSemiring
1368+
13681369
section Submodule
13691370

13701371
variable [Ring R] [∀ i, AddCommMonoid (M₁ i)] [AddCommMonoid M'] [AddCommMonoid M₂]

Mathlib/LinearAlgebra/Multilinear/Curry.lean

Lines changed: 97 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ in linear functions), called respectively `multilinearCurryLeftEquiv` and
2222

2323
open Fin Function Finset Set
2424

25-
universe uR uS uι v v' v₁ v₂ v₃
25+
universe uR uS uι uι' v v' v₁ v₂ v₃
2626

27-
variable {R : Type uR} {S : Type uS} {ι : Type uι} {n : ℕ}
27+
variable {R : Type uR} {S : Type uS} {ι : Type uι} {ι' : Type uι'} {n : ℕ}
2828
{M : Fin n.succ → Type v} {M₁ : ι → Type v₁} {M₂ : Type v₂} {M₃ : Type v₃} {M' : Type v'}
2929

3030
/-!
@@ -223,87 +223,119 @@ def multilinearCurryRightEquiv :
223223

224224
namespace MultilinearMap
225225

226-
variable {ι' : Type*} {R M₂}
227226

228-
/-- A multilinear map on `∀ i : ι ⊕ ι', M'` defines a multilinear map on `∀ i : ι, M'`
229-
taking values in the space of multilinear maps on `∀ i : ι', M'`. -/
230-
def currySum (f : MultilinearMap R (fun _ : ι ⊕ ι' => M') M₂) :
231-
MultilinearMap R (fun _ : ι => M') (MultilinearMap R (fun _ : ι' => M') M₂) where
227+
variable {R M₂} {N : (ι ⊕ ι') → Type*}
228+
[∀ i, AddCommMonoid (N i)] [∀ i, Module R (N i)]
229+
230+
/-- Given a family of modules `N : (ι ⊕ ι') → Type*`, a multilinear map
231+
on `(fun _ : ι ⊕ ι' => M')` induces a multilinear map on
232+
`(fun (i : ι) ↦ N (.inl i))` taking values in the space of
233+
linear maps on `(fun (i : ι') ↦ N (.inr i))`. -/
234+
def currySum (f : MultilinearMap R N M₂) :
235+
MultilinearMap R (fun i : ι ↦ N (.inl i)) (MultilinearMap R (fun i : ι' ↦ N (.inr i)) M₂) where
232236
toFun u :=
233-
{ toFun := fun v => f (Sum.elim u v)
234-
map_update_add' := fun v i x y => by
235-
letI := Classical.decEq ι
236-
simp only [← Sum.update_elim_inr, f.map_update_add]
237-
map_update_smul' := fun v i c x => by
238-
letI := Classical.decEq ι
239-
simp only [← Sum.update_elim_inr, f.map_update_smul] }
237+
{ toFun v := f (Sum.rec u v)
238+
map_update_add' := by letI := Classical.decEq ι; aesop
239+
map_update_smul' := by letI := Classical.decEq ι; aesop }
240240
map_update_add' u i x y :=
241-
ext fun v => by
242-
letI := Classical.decEq ι'
243-
simp only [MultilinearMap.coe_mk, add_apply, ← Sum.update_elim_inl, f.map_update_add]
241+
ext fun _ ↦ by letI := Classical.decEq ι'; simp
244242
map_update_smul' u i c x :=
245-
ext fun v => by
246-
letI := Classical.decEq ι'
247-
simp only [MultilinearMap.coe_mk, smul_apply, ← Sum.update_elim_inl, f.map_update_smul]
243+
ext fun _ ↦ by letI := Classical.decEq ι'; simp
244+
245+
@[simp low]
246+
theorem currySum_apply (f : MultilinearMap R N M₂)
247+
(u : (i : ι) → N (Sum.inl i)) (v : (i : ι') → N (Sum.inr i)) :
248+
currySum f u v = f (Sum.rec u v) := rfl
248249

249250
@[simp]
250-
theorem currySum_apply (f : MultilinearMap R (fun _ : ι ⊕ ι' => M') M₂) (u : ι → M')
251-
(v : ι' → M') : f.currySum u v = f (Sum.elim u v) :=
252-
rfl
251+
theorem currySum_apply' {N : Type*} [AddCommMonoid N] [Module R N]
252+
(f : MultilinearMap R (fun _ : ι ⊕ ι' ↦ N) M₂)
253+
(u : ι → N) (v : ι' → N) :
254+
currySum f u v = f (Sum.elim u v) := rfl
253255

254-
/-- A multilinear map on `∀ i : ι, M'` taking values in the space of multilinear maps
255-
on `∀ i : ι', M'` defines a multilinear map on `∀ i : ι ⊕ ι', M'`. -/
256-
def uncurrySum (f : MultilinearMap R (fun _ : ι => M') (MultilinearMap R (fun _ : ι' => M') M₂)) :
257-
MultilinearMap R (fun _ : ι ⊕ ι' => M') M₂ where
258-
toFun u := f (u ∘ Sum.inl) (u ∘ Sum.inr)
259-
map_update_add' u i x y := by
260-
letI := (@Sum.inl_injective ι ι').decidableEq
261-
letI := (@Sum.inr_injective ι ι').decidableEq
262-
cases i <;>
263-
simp only [MultilinearMap.map_update_add, add_apply, Sum.update_inl_comp_inl,
264-
Sum.update_inl_comp_inr, Sum.update_inr_comp_inl, Sum.update_inr_comp_inr]
265-
map_update_smul' u i c x := by
266-
letI := (@Sum.inl_injective ι ι').decidableEq
267-
letI := (@Sum.inr_injective ι ι').decidableEq
268-
cases i <;>
269-
simp only [MultilinearMap.map_update_smul, smul_apply, Sum.update_inl_comp_inl,
270-
Sum.update_inl_comp_inr, Sum.update_inr_comp_inl, Sum.update_inr_comp_inr]
256+
@[simp]
257+
lemma currySum_add (f₁ f₂ : MultilinearMap R N M₂):
258+
currySum (f₁ + f₂) = currySum f₁ + currySum f₂ := rfl
271259

272260
@[simp]
273-
theorem uncurrySum_aux_apply
274-
(f : MultilinearMap R (fun _ : ι => M') (MultilinearMap R (fun _ : ι' => M') M₂))
275-
(u : ι ⊕ ι' → M') : f.uncurrySum u = f (u ∘ Sum.inl) (u ∘ Sum.inr) :=
261+
lemma currySum_smul (r : R) (f : MultilinearMap R N M₂):
262+
currySum (r • f) = r • currySum f := rfl
263+
264+
/-- Given a family of modules `N : (ι ⊕ ι') → Type*`, a multilinear map on
265+
`(fun (i : ι) ↦ N (.inl i))` taking values in the space of
266+
linear maps on `(fun (i : ι') ↦ N (.inr i))` induces a multilinear map
267+
on `(fun _ : ι ⊕ ι' => M')` induces. -/
268+
def uncurrySum
269+
(g : MultilinearMap R (fun i : ι ↦ N (.inl i))
270+
(MultilinearMap R (fun i : ι' ↦ N (.inr i)) M₂)) :
271+
MultilinearMap R N M₂ where
272+
toFun u := g (fun i ↦ u (.inl i)) (fun i' ↦ u (.inr i'))
273+
map_update_add' := by
274+
letI := Classical.decEq ι
275+
letI := Classical.decEq ι'
276+
rintro _ _ (_ | _) _ _ <;> simp
277+
map_update_smul' := by
278+
letI := Classical.decEq ι
279+
letI := Classical.decEq ι'
280+
rintro _ _ (_ | _) _ _ <;> simp
281+
282+
@[simp]
283+
theorem uncurrySum_apply
284+
(g : MultilinearMap R (fun i : ι ↦ N (.inl i))
285+
(MultilinearMap R (fun i : ι' ↦ N (.inr i)) M₂)) (u) :
286+
g.uncurrySum u =
287+
g (fun i ↦ u (.inl i)) (fun i' ↦ u (.inr i')) := rfl
288+
289+
@[simp]
290+
lemma uncurrySum_add
291+
(g₁ g₂ : MultilinearMap R (fun i : ι ↦ N (.inl i))
292+
(MultilinearMap R (fun i : ι' ↦ N (.inr i)) M₂)) :
293+
uncurrySum (g₁ + g₂) = uncurrySum g₁ + uncurrySum g₂ :=
294+
rfl
295+
296+
lemma uncurrySum_smul
297+
(r : R) (g : MultilinearMap R (fun i : ι ↦ N (.inl i))
298+
(MultilinearMap R (fun i : ι' ↦ N (.inr i)) M₂)) :
299+
uncurrySum (r • g) = r • uncurrySum g :=
276300
rfl
277301

278-
variable (ι ι' R M₂ M')
302+
@[deprecated (since := "2025-04-23")] alias uncurrySum_aux_apply := uncurrySum_apply
279303

280-
/-- Linear equivalence between the space of multilinear maps on `∀ i : ι ⊕ ι', M'` and the space
281-
of multilinear maps on `∀ i : ι, M'` taking values in the space of multilinear maps
282-
on `∀ i : ι', M'`. -/
283-
def currySumEquiv :
284-
MultilinearMap R (fun _ : ι ⊕ ι' => M') M₂ ≃ₗ[R]
285-
MultilinearMap R (fun _ : ι => M') (MultilinearMap R (fun _ : ι' => M') M₂) where
286-
toFun := currySum
287-
invFun := uncurrySum
288-
left_inv f := ext fun u => by simp
289-
right_inv f := by
290-
ext
291-
simp
292-
map_add' f g := by
293-
ext
294-
rfl
295-
map_smul' c f := by
296-
ext
304+
@[simp]
305+
lemma uncurrySum_currySum (f : MultilinearMap R N M₂) :
306+
uncurrySum (currySum f) = f := by
307+
ext
308+
simp only [uncurrySum_apply, currySum_apply]
309+
congr
310+
ext (_ | _) <;> simp
311+
312+
@[simp]
313+
lemma currySum_uncurrySum
314+
(g : MultilinearMap R (fun i : ι ↦ N (.inl i))
315+
(MultilinearMap R (fun i : ι' ↦ N (.inr i)) M₂)) :
316+
currySum (uncurrySum g) = g :=
297317
rfl
298318

299-
variable {ι ι' R M₂ M'}
319+
/-- Multilinear maps on `N : (ι ⊕ ι') → Type*` identify to multilinear maps
320+
from `(fun (i : ι) ↦ N (.inl i))` taking values in the space of
321+
linear maps on `(fun (i : ι') ↦ N (.inr i))`. -/
322+
@[simps]
323+
def currySumEquiv : MultilinearMap R N M₂ ≃ₗ[R]
324+
MultilinearMap R (fun i : ι ↦ N (.inl i))
325+
(MultilinearMap R (fun i : ι' ↦ N (.inr i)) M₂) where
326+
toFun := currySum
327+
invFun := uncurrySum
328+
left_inv _ := by simp
329+
right_inv _ := rfl
330+
map_add' := by aesop
331+
map_smul' := by aesop
300332

301333
@[simp]
302-
theorem coe_currySumEquiv : ⇑(currySumEquiv R ι M₂ M' ι') = currySum :=
334+
theorem coe_currySumEquiv : ⇑(currySumEquiv (R := R) (N := N) (M₂ := M₂)) = currySum :=
303335
rfl
304336

305337
@[simp]
306-
theorem coe_currySumEquiv_symm : ⇑(currySumEquiv R ι M₂ M' ι').symm = uncurrySum :=
338+
theorem coe_currySumEquiv_symm : ⇑(currySumEquiv (R := R) (N := N) (M₂ := M₂)).symm = uncurrySum :=
307339
rfl
308340

309341
variable (R M₂ M')
@@ -316,7 +348,7 @@ def curryFinFinset {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) (hl : #sᶜ
316348
MultilinearMap R (fun _ : Fin n => M') M₂ ≃ₗ[R]
317349
MultilinearMap R (fun _ : Fin k => M') (MultilinearMap R (fun _ : Fin l => M') M₂) :=
318350
(domDomCongrLinearEquiv R R M' M₂ (finSumEquivOfFinset hk hl).symm).trans
319-
(currySumEquiv R (Fin k) M₂ M' (Fin l))
351+
currySumEquiv
320352

321353
variable {R M₂ M'}
322354

Mathlib/LinearAlgebra/Multilinear/TensorProduct.lean

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,47 @@ variable {R ι₁ ι₂ ι₃ ι₄ : Type*}
2222
variable [CommSemiring R]
2323
variable {N₁ : Type*} [AddCommMonoid N₁] [Module R N₁]
2424
variable {N₂ : Type*} [AddCommMonoid N₂] [Module R N₂]
25+
26+
attribute [local simp] add_tmul tmul_add smul_tmul
27+
28+
section
29+
30+
variable {N : ι₁ ⊕ ι₂ → Type*} [∀ i, AddCommMonoid (N i)] [∀ i, Module R (N i)]
31+
32+
/-- Given a family of modules `N` indexed by a type `ι₁ ⊕ ι₂`,
33+
a multilinear map from the modules `N (.inl i₁)` to `N₁` and
34+
a multilinear map from the modules `N (.inr i₁)` to `N₂`, this
35+
is the induced multilinear map from all the modules `N i` to `N₁ ⊗ N₂`. -/
36+
@[simps apply]
37+
def domCoprodDep (a : MultilinearMap R (fun i₁ ↦ N (.inl i₁)) N₁)
38+
(b : MultilinearMap R (fun i₂ ↦ N (.inr i₂)) N₂) :
39+
MultilinearMap R N (N₁ ⊗[R] N₂) where
40+
toFun v := a (fun i₁ ↦ v (.inl i₁)) ⊗ₜ b (fun i₂ ↦ v (.inr i₂))
41+
map_update_add' := by
42+
rintro _ _ (_ | _) _ _
43+
· letI := Classical.decEq ι₁; simp
44+
· letI := Classical.decEq ι₂; simp
45+
map_update_smul' := by
46+
rintro _ m (i₁ | i₂) p q
47+
· letI := Classical.decEq ι₁; simp
48+
· letI := Classical.decEq ι₂; simp
49+
50+
/-- A more bundled version of `MultilinearMap.domCoprodDep`, as a linear map
51+
from the tensor product of spaces of multilinear maps. -/
52+
def domCoprodDep' :
53+
MultilinearMap R (fun i₁ ↦ N (.inl i₁)) N₁ ⊗[R] MultilinearMap R (fun i₂ ↦ N (.inr i₂)) N₂ →ₗ[R]
54+
MultilinearMap R N (N₁ ⊗[R] N₂) :=
55+
TensorProduct.lift (LinearMap.mk₂ R domCoprodDep
56+
(by aesop) (by aesop) (by aesop) (by aesop))
57+
58+
@[simp]
59+
theorem domCoprodDep'_apply (a : MultilinearMap R (fun i₁ ↦ N (.inl i₁)) N₁)
60+
(b : MultilinearMap R (fun i₂ ↦ N (.inr i₂)) N₂) :
61+
domCoprodDep' (a ⊗ₜ b) = domCoprodDep a b := by
62+
rfl
63+
64+
end
65+
2566
variable {N : Type*} [AddCommMonoid N] [Module R N]
2667

2768
/-- Given two multilinear maps `(ι₁ → N) → N₁` and `(ι₂ → N) → N₂`, this produces the map
@@ -37,39 +78,18 @@ introduces `Sum.elim N'₁ N'₂` types in the result which are difficult to wor
3778
to the simple case defined here. See [this zulip thread](
3879
https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there.20code.20for.20X.3F/topic/Instances.20on.20.60sum.2Eelim.20A.20B.20i.60/near/218484619).
3980
-/
40-
@[simps apply]
81+
@[simps! apply]
4182
def domCoprod (a : MultilinearMap R (fun _ : ι₁ => N) N₁)
4283
(b : MultilinearMap R (fun _ : ι₂ => N) N₂) :
43-
MultilinearMap R (fun _ : ι₁ ⊕ ι₂ => N) (N₁ ⊗[R] N₂) where
44-
toFun v := (a fun i => v (Sum.inl i)) ⊗ₜ b fun i => v (Sum.inr i)
45-
map_update_add' _ i p q := by
46-
letI := (@Sum.inl_injective ι₁ ι₂).decidableEq
47-
letI := (@Sum.inr_injective ι₁ ι₂).decidableEq
48-
cases i <;> simp [TensorProduct.add_tmul, TensorProduct.tmul_add]
49-
map_update_smul' _ i c p := by
50-
letI := (@Sum.inl_injective ι₁ ι₂).decidableEq
51-
letI := (@Sum.inr_injective ι₁ ι₂).decidableEq
52-
cases i <;> simp [TensorProduct.smul_tmul', TensorProduct.tmul_smul]
84+
MultilinearMap R (fun _ : ι₁ ⊕ ι₂ => N) (N₁ ⊗[R] N₂) :=
85+
domCoprodDep a b
5386

5487
/-- A more bundled version of `MultilinearMap.domCoprod` that maps
5588
`((ι₁ → N) → N₁) ⊗ ((ι₂ → N) → N₂)` to `(ι₁ ⊕ ι₂ → N) → N₁ ⊗ N₂`. -/
5689
def domCoprod' :
5790
MultilinearMap R (fun _ : ι₁ => N) N₁ ⊗[R] MultilinearMap R (fun _ : ι₂ => N) N₂ →ₗ[R]
5891
MultilinearMap R (fun _ : ι₁ ⊕ ι₂ => N) (N₁ ⊗[R] N₂) :=
59-
TensorProduct.lift <|
60-
LinearMap.mk₂ R domCoprod
61-
(fun m₁ m₂ n => by
62-
ext
63-
simp only [domCoprod_apply, TensorProduct.add_tmul, add_apply])
64-
(fun c m n => by
65-
ext
66-
simp only [domCoprod_apply, TensorProduct.smul_tmul', smul_apply])
67-
(fun m n₁ n₂ => by
68-
ext
69-
simp only [domCoprod_apply, TensorProduct.tmul_add, add_apply])
70-
fun c m n => by
71-
ext
72-
simp only [domCoprod_apply, TensorProduct.tmul_smul, smul_apply]
92+
domCoprodDep' (R := R) (N := fun (_ : ι₁ ⊕ ι₂) ↦ N)
7393

7494
@[simp]
7595
theorem domCoprod'_apply (a : MultilinearMap R (fun _ : ι₁ => N) N₁)

0 commit comments

Comments
 (0)