Zulip Chat Archive

Stream: FLT

Topic: Task 239 help


Madison Crim (Feb 27 2025 at 20:11):

For task 239, I'm able to prove in general that I can commute a direct product with a tensor product when I have a finite free module M. The issue I'm running into is it's difficult to show then that this sends pure tensors to what'd we expect.

import Mathlib.Algebra.DirectSum.Module
import Mathlib.LinearAlgebra.FreeModule.Finite.Basic

section
variable {ι' : Type*} {R ι: Type*} {M N : ι  ι'  Type*} [CommRing R] [i i', AddCommGroup (M i i')]
[i i', AddCommGroup (N i i')] [i i', Module R (M i i')] [i i', Module R (N i i')] [Fintype ι'][DecidableEq ι']

open DirectSum

def proddirectsum' : ( (i' : ι'), ( i, N i i')) ≃ₗ[R] ( i, ( i', N i i')) where
  toFun nm i := i', DirectSum.of (fun i'  N i i') i' (nm i' i)
  map_add' x y := sorry --proved
  map_smul' := sorry --proved
  invFun nm :=  i', DirectSum.of (fun j   i, N i j) i' (fun i  nm i i')
  left_inv nm := sorry --proved
  right_inv nm := sorry --proved

end

open TensorProduct

variable (R M : Type*) [CommRing R] [AddCommGroup M] [Module R M] {ι : Type*}
(N : ι  Type*) [ i, AddCommGroup (N i)] [ i, Module R (N i)]

noncomputable def moduleTensorProdEquiv [Module.Free R M] [Module.Finite R M] :
    M [R] ( i, N i) ≃ₗ[R] (Module.Free.ChooseBasisIndex R M →₀ R) [R] (i, N i) :=
  TensorProduct.congr (Module.Free.repr R M) (LinearEquiv.refl R ((i : ι)  N i))

noncomputable def TensorProdEquivProdTensor [Module.Free R M] [Module.Finite R M] :
    (Module.Free.ChooseBasisIndex R M →₀ R) [R] (i, N i) ≃ₗ[R]
      i, ( Module.Free.ChooseBasisIndex R M →₀ R) [R] (N i) :=
  finsuppScalarLeft R (i, N i) (Module.Free.ChooseBasisIndex R M) ≪≫ₗ
    (finsuppLEquivDirectSum R (i, N i) (Module.Free.ChooseBasisIndex R M)) ≪≫ₗ
    proddirectsum' ≪≫ₗ
    LinearEquiv.piCongrRight (fun i (finsuppLEquivDirectSum R (N i)
    (Module.Free.ChooseBasisIndex R M)).symm)
    ≪≫ₗ LinearEquiv.piCongrRight (fun i 
      (finsuppScalarLeft R (N i) (Module.Free.ChooseBasisIndex R M)).symm)

noncomputable def prodTensorEquiv [Module.Free R M] [Module.Finite R M] :
  (i, (Module.Free.ChooseBasisIndex R M →₀ R) [R] N i) ≃ₗ[R] i, (M [R] N i) :=
  LinearEquiv.piCongrRight (fun i  (LinearEquiv.rTensor (N i) (Module.Free.repr R M).symm))

noncomputable def tensorProdbilinear_map [Module.Free R M] [Module.Finite R M]  :
  M [R] ( i, N i) ≃ₗ[R]  i, (M [R] N i) :=
  (moduleTensorProdEquiv R M N) ≪≫ₗ (TensorProdEquivProdTensor R M N) ≪≫ₗ (prodTensorEquiv R M N)

noncomputable def tensorProdbilinear_map_apply [Module.Free R M] [Module.Finite R M]
  (m : M) (n :  i, N i) :
  tensorProdbilinear_map R M N (m ⊗ₜ n) =
  fun i  (m ⊗ₜ n i) := sorry

This is where I'm struggling to show the map is the same as if I constructed the map tensorProdbilinear_map using TensorProduct.lift which wouldn't have given me the desired bijection.

Kevin Buzzard (Feb 27 2025 at 23:14):

Nice question! I agree that this needs some thought. This is FLT-free so you could even ask in #mathlib ;-)

Madison Crim (Feb 27 2025 at 23:18):

I can certainly ask there. I do plan to use these ideas for the FLT task. This is the generalization of the task I'm working on.

Kevin Buzzard (Feb 27 2025 at 23:35):

I've got no idea whether I'm going the right way, somehow the goal feels simpler but that doesn't mean I'm for sure going in the right direction (I made no attempt to tidy up but I need to sleep)

noncomputable def tensorProdbilinear_map_apply [Module.Free R M] [Module.Finite R M]
    (m : M) (n :  i, N i) :
    tensorProdbilinear_map R M N (m ⊗ₜ n) =
    fun i  (m ⊗ₜ n i) := by
  -- unfold some of your definitions (but not all)
  unfold tensorProdbilinear_map
  simp [moduleTensorProdEquiv]
  -- the goal now mentions `(Module.Free.repr R M) m` which has type `(some set) →₀ R`
  -- i.e. `Finsupp`, so we can (rather inelegantly) change the goal so that it
  -- doesn't mention m at all and only mentions `m'`, this finitely-supported function.
  let m' := (Module.Free.repr R M) m
  have hm' : (Module.Free.repr R M).symm m' = m := by simp [m']
  rw [ hm']
  simp
  -- Now the goal only has m' not m so we can apply an induction principle
  induction m' using Finsupp.induction_linear
  · -- goal true for zero function
    ext
    simp
  · -- goal preserved under addition
    ext i
    simp_all [add_tmul]
  · -- what's left: goal is true for functions supported at one place
    rename_i j r
    -- STP for m' the function sending j to r and everything else to 0
    -- randomly move an equiv to the other side out of hope more
    -- than anything else
    rw [ LinearEquiv.eq_symm_apply]
    simp [prodTensorEquiv]
    ext i
    simp
    -- we are surely close!
    -- ⊢ (TensorProdEquivProdTensor R M N) (Finsupp.single j r ⊗ₜ[R] n) i = Finsupp.single j r ⊗ₜ[R] n i
    sorry

Aaron Liu (Feb 28 2025 at 01:34):

I don't know much about linear algebra, but building off what @Kevin Buzzard has I was able to prove the goal.

import Mathlib.Algebra.DirectSum.Module
import Mathlib.LinearAlgebra.FreeModule.Finite.Basic

section
variable {ι' : Type*} {R ι: Type*} {M N : ι  ι'  Type*} [CommRing R] [i i', AddCommGroup (M i i')]
[i i', AddCommGroup (N i i')] [i i', Module R (M i i')] [i i', Module R (N i i')] [Fintype ι'][DecidableEq ι']

open DirectSum

def proddirectsum' : ( (i' : ι'), ( i, N i i')) ≃ₗ[R] ( i, ( i', N i i')) where
  toFun nm i := i', DirectSum.of (fun i'  N i i') i' (nm i' i)
  map_add' x y := sorry --proved
  map_smul' := sorry --proved
  invFun nm :=  i', DirectSum.of (fun j   i, N i j) i' (fun i  nm i i')
  left_inv nm := sorry --proved
  right_inv nm := sorry --proved

end

open TensorProduct

variable (R M : Type*) [CommRing R] [AddCommGroup M] [Module R M] {ι : Type*}
(N : ι  Type*) [ i, AddCommGroup (N i)] [ i, Module R (N i)]

noncomputable def moduleTensorProdEquiv [Module.Free R M] [Module.Finite R M] :
    M [R] ( i, N i) ≃ₗ[R] (Module.Free.ChooseBasisIndex R M →₀ R) [R] (i, N i) :=
  TensorProduct.congr (Module.Free.repr R M) (LinearEquiv.refl R ((i : ι)  N i))

noncomputable def TensorProdEquivProdTensor [Module.Free R M] [Module.Finite R M] :
    (Module.Free.ChooseBasisIndex R M →₀ R) [R] (i, N i) ≃ₗ[R]
      i, ( Module.Free.ChooseBasisIndex R M →₀ R) [R] (N i) :=
  finsuppScalarLeft R (i, N i) (Module.Free.ChooseBasisIndex R M) ≪≫ₗ
    (finsuppLEquivDirectSum R (i, N i) (Module.Free.ChooseBasisIndex R M)) ≪≫ₗ
    proddirectsum' ≪≫ₗ
    LinearEquiv.piCongrRight (fun i (finsuppLEquivDirectSum R (N i)
    (Module.Free.ChooseBasisIndex R M)).symm)
    ≪≫ₗ LinearEquiv.piCongrRight (fun i 
      (finsuppScalarLeft R (N i) (Module.Free.ChooseBasisIndex R M)).symm)

noncomputable def prodTensorEquiv [Module.Free R M] [Module.Finite R M] :
  (i, (Module.Free.ChooseBasisIndex R M →₀ R) [R] N i) ≃ₗ[R] i, (M [R] N i) :=
  LinearEquiv.piCongrRight (fun i  (LinearEquiv.rTensor (N i) (Module.Free.repr R M).symm))

noncomputable def tensorProdbilinear_map [Module.Free R M] [Module.Finite R M]  :
  M [R] ( i, N i) ≃ₗ[R]  i, (M [R] N i) :=
  (moduleTensorProdEquiv R M N) ≪≫ₗ (TensorProdEquivProdTensor R M N) ≪≫ₗ (prodTensorEquiv R M N)

noncomputable def tensorProdbilinear_map_apply [Module.Free R M] [Module.Finite R M]
    (m : M) (n :  i, N i) :
    tensorProdbilinear_map R M N (m ⊗ₜ n) =
    fun i  (m ⊗ₜ n i) := by
  -- unfold some of your definitions (but not all)
  unfold tensorProdbilinear_map
  simp [moduleTensorProdEquiv]
  -- the goal now mentions `(Module.Free.repr R M) m` which has type `(some set) →₀ R`
  -- i.e. `Finsupp`, so we can (rather inelegantly) change the goal so that it
  -- doesn't mention m at all and only mentions `m'`, this finitely-supported function.
  let m' := (Module.Free.repr R M) m
  have hm' : (Module.Free.repr R M).symm m' = m := by simp [m']
  rw [ hm']
  simp
  -- Now the goal only has m' not m so we can apply an induction principle
  induction m' using Finsupp.induction_linear
  · -- goal true for zero function
    ext
    simp
  · -- goal preserved under addition
    ext i
    simp_all [add_tmul]
  · -- what's left: goal is true for functions supported at one place
    rename_i j r
    -- STP for m' the function sending j to r and everything else to 0
    -- randomly move an equiv to the other side out of hope more
    -- than anything else
    rw [ LinearEquiv.eq_symm_apply]
    simp [prodTensorEquiv]
    ext i
    simp
    -- we are surely close!
    -- ⊢ (TensorProdEquivProdTensor R M N) (Finsupp.single j r ⊗ₜ[R] n) i = Finsupp.single j r ⊗ₜ[R] n i
    -- Kevin got here
    rw [TensorProdEquivProdTensor]
    simp only [LinearEquiv.trans_apply, LinearEquiv.piCongrRight_apply]
    rw [LinearEquiv.symm_apply_eq]
    ext k
    rw [finsuppScalarLeft_apply, LinearMap.rTensor_tmul, Finsupp.lapply_apply, TensorProduct.lid_tmul]
    rw [Finsupp.single_apply, ite_smul, zero_smul,  Finsupp.single_apply]
    apply congrFun
    apply congrArg
    clear k hm' m' m
    rw [LinearEquiv.symm_apply_eq]
    rw [finsuppLEquivDirectSum_single]
    rw [finsuppScalarLeft_apply_tmul, Finsupp.sum_single_index (by simp)]
    rw [finsuppLEquivDirectSum_single]
    rw [DirectSum.lof_eq_of, DirectSum.lof_eq_of]
    rw [proddirectsum']
    simp_rw [ LinearEquiv.toFun_eq_coe]
    conv_lhs =>
      enter [2, x]
      rw [DirectSum.of_apply]
      simp only [Eq.recOn.eq_def, eq_rec_constant, dif_eq_if]
      rw [ite_apply, Pi.zero_apply, Pi.smul_apply, apply_ite (DFunLike.coe _), AddMonoidHom.map_zero]
    apply Fintype.sum_dite_eq
    done

Madison Crim (Feb 28 2025 at 04:48):

Thank you both so much! Using this I was able to prove my task. My issue now is I have this additional file containing the work above including the proofs of the sorries. To create my PR for this task, should I include this file, or should I try to PR these results to mathlib before creating a PR for FLT?

Ruben Van de Velde (Feb 28 2025 at 06:58):

Perhaps submit it to flt first

Kevin Buzzard (Feb 28 2025 at 07:38):

I guess there might be better ways to define those maps, that's probably the first thing to think about


Last updated: May 02 2025 at 03:31 UTC