|
| 1 | +/- |
| 2 | +Copyright (c) 2021 Justus Springer. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Justus Springer |
| 5 | +
|
| 6 | +! This file was ported from Lean 3 source module algebra.category.Module.filtered_colimits |
| 7 | +! leanprover-community/mathlib commit 806bbb0132ba63b93d5edbe4789ea226f8329979 |
| 8 | +! Please do not edit these lines, except to modify the commit id |
| 9 | +! if you have ported upstream changes. |
| 10 | +-/ |
| 11 | +import Mathlib.Algebra.Category.GroupCat.FilteredColimits |
| 12 | +import Mathlib.Algebra.Category.ModuleCat.Basic |
| 13 | + |
| 14 | +/-! |
| 15 | +# The forgetful functor from `R`-modules preserves filtered colimits. |
| 16 | +
|
| 17 | +Forgetful functors from algebraic categories usually don't preserve colimits. However, they tend |
| 18 | +to preserve _filtered_ colimits. |
| 19 | +
|
| 20 | +In this file, we start with a ring `R`, a small filtered category `J` and a functor |
| 21 | +`F : J ⥤ Module R`. We show that the colimit of `F ⋙ forget₂ (Module R) AddCommGroup` |
| 22 | +(in `AddCommGroup`) carries the structure of an `R`-module, thereby showing that the forgetful |
| 23 | +functor `forget₂ (Module R) AddCommGroup` preserves filtered colimits. In particular, this implies |
| 24 | +that `forget (Module R)` preserves filtered colimits. |
| 25 | +
|
| 26 | +-/ |
| 27 | + |
| 28 | + |
| 29 | +universe v u |
| 30 | + |
| 31 | +noncomputable section |
| 32 | + |
| 33 | +open scoped Classical |
| 34 | + |
| 35 | +open CategoryTheory CategoryTheory.Limits |
| 36 | + |
| 37 | +-- avoid name collision with `_root_.max`. |
| 38 | +open CategoryTheory.IsFiltered renaming max → max' |
| 39 | + |
| 40 | +open AddMonCat.FilteredColimits (colimit_zero_eq colimit_add_mk_eq) |
| 41 | + |
| 42 | +namespace ModuleCat.FilteredColimits |
| 43 | + |
| 44 | +section |
| 45 | + |
| 46 | +variable {R : Type u} [Ring R] {J : Type v} [SmallCategory J] [IsFiltered J] |
| 47 | + |
| 48 | +variable (F : J ⥤ ModuleCatMax.{v, u, u} R) |
| 49 | + |
| 50 | +/-- The colimit of `F ⋙ forget₂ (Module R) AddCommGroup` in the category `AddCommGroup`. |
| 51 | +In the following, we will show that this has the structure of an `R`-module. |
| 52 | +-/ |
| 53 | +abbrev M : AddCommGroupCat := |
| 54 | + AddCommGroupCat.FilteredColimits.colimit.{v, u} |
| 55 | + (F ⋙ forget₂ (ModuleCat R) AddCommGroupCat.{max v u}) |
| 56 | +set_option linter.uppercaseLean3 false in |
| 57 | +#align Module.filtered_colimits.M ModuleCat.FilteredColimits.M |
| 58 | + |
| 59 | +/-- The canonical projection into the colimit, as a quotient type. -/ |
| 60 | +abbrev M.mk : (Σ j, F.obj j) → M F := |
| 61 | + Quot.mk (Types.Quot.Rel (F ⋙ forget (ModuleCat R))) |
| 62 | +set_option linter.uppercaseLean3 false in |
| 63 | +#align Module.filtered_colimits.M.mk ModuleCat.FilteredColimits.M.mk |
| 64 | + |
| 65 | +theorem M.mk_eq (x y : Σ j, F.obj j) |
| 66 | + (h : ∃ (k : J) (f : x.1 ⟶ k) (g : y.1 ⟶ k), F.map f x.2 = F.map g y.2) : M.mk F x = M.mk F y := |
| 67 | + Quot.EqvGen_sound (Types.FilteredColimit.eqvGen_quot_rel_of_rel (F ⋙ forget (ModuleCat R)) x y h) |
| 68 | +set_option linter.uppercaseLean3 false in |
| 69 | +#align Module.filtered_colimits.M.mk_eq ModuleCat.FilteredColimits.M.mk_eq |
| 70 | + |
| 71 | +/-- The "unlifted" version of scalar multiplication in the colimit. -/ |
| 72 | +def colimitSmulAux (r : R) (x : Σ j, F.obj j) : M F := |
| 73 | + M.mk F ⟨x.1, r • x.2⟩ |
| 74 | +set_option linter.uppercaseLean3 false in |
| 75 | +#align Module.filtered_colimits.colimit_smul_aux ModuleCat.FilteredColimits.colimitSmulAux |
| 76 | + |
| 77 | +theorem colimitSmulAux_eq_of_rel (r : R) (x y : Σ j, F.obj j) |
| 78 | + (h : Types.FilteredColimit.Rel.{v, u} (F ⋙ forget (ModuleCat R)) x y) : |
| 79 | + colimitSmulAux F r x = colimitSmulAux F r y := by |
| 80 | + apply M.mk_eq |
| 81 | + obtain ⟨k, f, g, hfg⟩ := h |
| 82 | + use k, f, g |
| 83 | + simp only [Functor.comp_obj, Functor.comp_map, forget_map] at hfg |
| 84 | + simp [hfg] |
| 85 | +set_option linter.uppercaseLean3 false in |
| 86 | +#align Module.filtered_colimits.colimit_smul_aux_eq_of_rel ModuleCat.FilteredColimits.colimitSmulAux_eq_of_rel |
| 87 | + |
| 88 | +/-- Scalar multiplication in the colimit. See also `colimitSmulAux`. -/ |
| 89 | +instance colimitHasSmul : SMul R (M F) where |
| 90 | + smul r x := by |
| 91 | + refine' Quot.lift (colimitSmulAux F r) _ x |
| 92 | + intro x y h |
| 93 | + apply colimitSmulAux_eq_of_rel |
| 94 | + apply Types.FilteredColimit.rel_of_quot_rel |
| 95 | + exact h |
| 96 | +set_option linter.uppercaseLean3 false in |
| 97 | +#align Module.filtered_colimits.colimit_has_smul ModuleCat.FilteredColimits.colimitHasSmul |
| 98 | + |
| 99 | +@[simp] |
| 100 | +theorem colimit_smul_mk_eq (r : R) (x : Σ j, F.obj j) : r • M.mk F x = M.mk F ⟨x.1, r • x.2⟩ := |
| 101 | + rfl |
| 102 | +set_option linter.uppercaseLean3 false in |
| 103 | +#align Module.filtered_colimits.colimit_smul_mk_eq ModuleCat.FilteredColimits.colimit_smul_mk_eq |
| 104 | + |
| 105 | +private theorem colimitModule.one_smul (x : (M F)) : (1 : R) • x = x := by |
| 106 | + refine' Quot.inductionOn x _; clear x; intro x; cases' x with j x |
| 107 | + erw [colimit_smul_mk_eq F 1 ⟨j, x⟩] |
| 108 | + simp |
| 109 | + rfl |
| 110 | + |
| 111 | +-- Porting note: writing directly the `Module` instance makes things very slow. |
| 112 | +instance colimitMulAction : MulAction R (M F) where |
| 113 | + one_smul x := by |
| 114 | + refine' Quot.inductionOn x _; clear x; intro x; cases' x with j x |
| 115 | + erw [colimit_smul_mk_eq F 1 ⟨j, x⟩, one_smul] |
| 116 | + rfl |
| 117 | + mul_smul r s x := by |
| 118 | + refine' Quot.inductionOn x _; clear x; intro x; cases' x with j x |
| 119 | + erw [colimit_smul_mk_eq F (r * s) ⟨j, x⟩, colimit_smul_mk_eq F s ⟨j, x⟩, |
| 120 | + colimit_smul_mk_eq F r ⟨j, _⟩, mul_smul] |
| 121 | + |
| 122 | +instance colimitSMulWithZero : SMulWithZero R (M F) := |
| 123 | +{ colimitMulAction F with |
| 124 | + smul_zero := fun r => by |
| 125 | + erw [colimit_zero_eq _ (IsFiltered.Nonempty.some : J), colimit_smul_mk_eq, smul_zero] |
| 126 | + rfl |
| 127 | + zero_smul := fun x => by |
| 128 | + refine' Quot.inductionOn x _; clear x; intro x; cases' x with j x |
| 129 | + erw [colimit_smul_mk_eq, zero_smul, colimit_zero_eq _ j] |
| 130 | + rfl } |
| 131 | + |
| 132 | +private theorem colimitModule.add_smul (r s : R) (x : (M F)) : (r + s) • x = r • x + s • x := by |
| 133 | + refine' Quot.inductionOn x _; clear x; intro x; cases' x with j x |
| 134 | + erw [colimit_smul_mk_eq, _root_.add_smul, colimit_smul_mk_eq, colimit_smul_mk_eq, |
| 135 | + colimit_add_mk_eq _ ⟨j, _⟩ ⟨j, _⟩ j (𝟙 j) (𝟙 j), CategoryTheory.Functor.map_id, id_apply, |
| 136 | + id_apply] |
| 137 | + rfl |
| 138 | + |
| 139 | +instance colimitModule : Module R (M F) := |
| 140 | +{ colimitMulAction F, |
| 141 | + colimitSMulWithZero F with |
| 142 | + smul_add := fun r x y => by |
| 143 | + refine' Quot.induction_on₂ x y _; clear x y; intro x y; cases' x with i x; cases' y with j y |
| 144 | + erw [colimit_add_mk_eq _ ⟨i, _⟩ ⟨j, _⟩ (max' i j) (IsFiltered.leftToMax i j) |
| 145 | + (IsFiltered.rightToMax i j), colimit_smul_mk_eq, smul_add, colimit_smul_mk_eq, |
| 146 | + colimit_smul_mk_eq, colimit_add_mk_eq _ ⟨i, _⟩ ⟨j, _⟩ (max' i j) (IsFiltered.leftToMax i j) |
| 147 | + (IsFiltered.rightToMax i j), LinearMap.map_smul, LinearMap.map_smul] |
| 148 | + rfl |
| 149 | + add_smul := colimitModule.add_smul F } |
| 150 | + |
| 151 | +set_option linter.uppercaseLean3 false in |
| 152 | +#align Module.filtered_colimits.colimit_module ModuleCat.FilteredColimits.colimitModule |
| 153 | + |
| 154 | +/-- The bundled `R`-module giving the filtered colimit of a diagram. -/ |
| 155 | +def colimit : ModuleCatMax.{v, u, u} R := |
| 156 | + ModuleCat.of R (M F) |
| 157 | +set_option linter.uppercaseLean3 false in |
| 158 | +#align Module.filtered_colimits.colimit ModuleCat.FilteredColimits.colimit |
| 159 | + |
| 160 | +/-- The linear map from a given `R`-module in the diagram to the colimit module. -/ |
| 161 | +def coconeMorphism (j : J) : F.obj j ⟶ colimit F := |
| 162 | + { (AddCommGroupCat.FilteredColimits.colimitCocone |
| 163 | + (F ⋙ forget₂ (ModuleCat R) AddCommGroupCat.{max v u})).ι.app j with |
| 164 | + map_smul' := fun r x => by erw [colimit_smul_mk_eq F r ⟨j, x⟩]; rfl } |
| 165 | +set_option linter.uppercaseLean3 false in |
| 166 | +#align Module.filtered_colimits.cocone_morphism ModuleCat.FilteredColimits.coconeMorphism |
| 167 | + |
| 168 | +/-- The cocone over the proposed colimit module. -/ |
| 169 | +def colimitCocone : Cocone F where |
| 170 | + pt := colimit F |
| 171 | + ι := |
| 172 | + { app := coconeMorphism F |
| 173 | + naturality := fun _ _' f => |
| 174 | + LinearMap.coe_injective ((Types.colimitCocone (F ⋙ forget (ModuleCat R))).ι.naturality f) } |
| 175 | +set_option linter.uppercaseLean3 false in |
| 176 | +#align Module.filtered_colimits.colimit_cocone ModuleCat.FilteredColimits.colimitCocone |
| 177 | + |
| 178 | +/-- Given a cocone `t` of `F`, the induced monoid linear map from the colimit to the cocone point. |
| 179 | +We already know that this is a morphism between additive groups. The only thing left to see is that |
| 180 | +it is a linear map, i.e. preserves scalar multiplication. |
| 181 | +-/ |
| 182 | +def colimitDesc (t : Cocone F) : colimit F ⟶ t.pt := |
| 183 | + { (AddCommGroupCat.FilteredColimits.colimitCoconeIsColimit |
| 184 | + (F ⋙ forget₂ (ModuleCatMax.{v, u} R) AddCommGroupCat.{max v u})).desc |
| 185 | + ((forget₂ (ModuleCat R) AddCommGroupCat.{max v u}).mapCocone t) with |
| 186 | + map_smul' := fun r x => by |
| 187 | + refine' Quot.inductionOn x _; clear x; intro x; cases' x with j x |
| 188 | + erw [colimit_smul_mk_eq] |
| 189 | + exact LinearMap.map_smul (t.ι.app j) r x } |
| 190 | +set_option linter.uppercaseLean3 false in |
| 191 | +#align Module.filtered_colimits.colimit_desc ModuleCat.FilteredColimits.colimitDesc |
| 192 | + |
| 193 | +/-- The proposed colimit cocone is a colimit in `Module R`. -/ |
| 194 | +def colimitCoconeIsColimit : IsColimit (colimitCocone F) where |
| 195 | + desc := colimitDesc F |
| 196 | + fac t j := |
| 197 | + LinearMap.coe_injective <| |
| 198 | + (Types.colimitCoconeIsColimit.{v, u} (F ⋙ forget (ModuleCat R))).fac |
| 199 | + ((forget (ModuleCat R)).mapCocone t) j |
| 200 | + uniq t _ h := |
| 201 | + LinearMap.coe_injective <| |
| 202 | + (Types.colimitCoconeIsColimit (F ⋙ forget (ModuleCat R))).uniq |
| 203 | + ((forget (ModuleCat R)).mapCocone t) _ fun j => funext fun x => LinearMap.congr_fun (h j) x |
| 204 | +set_option linter.uppercaseLean3 false in |
| 205 | +#align Module.filtered_colimits.colimit_cocone_is_colimit ModuleCat.FilteredColimits.colimitCoconeIsColimit |
| 206 | + |
| 207 | +instance forget₂AddCommGroupPreservesFilteredColimits : |
| 208 | + PreservesFilteredColimits (forget₂ (ModuleCat.{u} R) AddCommGroupCat.{u}) where |
| 209 | + preserves_filtered_colimits J _ _ := |
| 210 | + { -- Porting note: without the curly braces for `F` |
| 211 | + -- here we get a confusing error message about universes. |
| 212 | + preservesColimit := fun {F : J ⥤ ModuleCat.{u} R} => |
| 213 | + preservesColimitOfPreservesColimitCocone (colimitCoconeIsColimit F) |
| 214 | + (AddCommGroupCat.FilteredColimits.colimitCoconeIsColimit |
| 215 | + (F ⋙ forget₂ (ModuleCat.{u} R) AddCommGroupCat.{u})) } |
| 216 | +set_option linter.uppercaseLean3 false in |
| 217 | +#align Module.filtered_colimits.forget₂_AddCommGroup_preserves_filtered_colimits ModuleCat.FilteredColimits.forget₂AddCommGroupPreservesFilteredColimits |
| 218 | + |
| 219 | +instance forgetPreservesFilteredColimits : PreservesFilteredColimits (forget (ModuleCat.{u} R)) := |
| 220 | + Limits.compPreservesFilteredColimits (forget₂ (ModuleCat R) AddCommGroupCat) |
| 221 | + (forget AddCommGroupCat) |
| 222 | +set_option linter.uppercaseLean3 false in |
| 223 | +#align Module.filtered_colimits.forget_preserves_filtered_colimits ModuleCat.FilteredColimits.forgetPreservesFilteredColimits |
| 224 | + |
| 225 | +end |
| 226 | + |
| 227 | +end ModuleCat.FilteredColimits |
0 commit comments