|
| 1 | +/- |
| 2 | +Copyright (c) 2024 Joël Riou. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Joël Riou |
| 5 | +-/ |
| 6 | +import Mathlib.CategoryTheory.Filtered.Basic |
| 7 | +import Mathlib.CategoryTheory.Limits.HasLimits |
| 8 | + |
| 9 | +/-! |
| 10 | +# Limits of eventually constant functors |
| 11 | +
|
| 12 | +If `F : J ⥤ C` is a functor from a cofiltered category, and `j : J`, |
| 13 | +we introduce a property `F.IsEventuallyConstantTo j` which says |
| 14 | +that for any `f : i ⟶ j`, the induced morphism `F.map f` is an isomorphism. |
| 15 | +Under this assumption, it is shown that `F` admits `F.obj j` as a limit |
| 16 | +(`Functor.IsEventuallyConstantTo.isLimitCone`). |
| 17 | +
|
| 18 | +A typeclass `Cofiltered.IsEventuallyConstant` is also introduced, and |
| 19 | +the dual results for filtered categories and colimits are also obtained. |
| 20 | +
|
| 21 | +-/ |
| 22 | + |
| 23 | +namespace CategoryTheory |
| 24 | + |
| 25 | +open Category Limits |
| 26 | + |
| 27 | +variable {J C : Type*} [Category J] [Category C] (F : J ⥤ C) |
| 28 | + |
| 29 | +namespace Functor |
| 30 | + |
| 31 | +/-- A functor `F : J ⥤ C` is eventually constant to `j : J` if |
| 32 | +for any map `f : i ⟶ j`, the induced morphism `F.map f` is an isomorphism. |
| 33 | +If `J` is cofiltered, this implies `F` has a limit. -/ |
| 34 | +def IsEventuallyConstantTo (j : J) : Prop := |
| 35 | + ∀ ⦃i : J⦄ (f : i ⟶ j), IsIso (F.map f) |
| 36 | + |
| 37 | +/-- A functor `F : J ⥤ C` is eventually constant from `i : J` if |
| 38 | +for any map `f : i ⟶ j`, the induced morphism `F.map f` is an isomorphism. |
| 39 | +If `J` is filtered, this implies `F` has a colimit. -/ |
| 40 | +def IsEventuallyConstantFrom (i : J) : Prop := |
| 41 | + ∀ ⦃j : J⦄ (f : i ⟶ j), IsIso (F.map f) |
| 42 | + |
| 43 | +namespace IsEventuallyConstantTo |
| 44 | + |
| 45 | +variable {F} {i₀ : J} (h : F.IsEventuallyConstantTo i₀) |
| 46 | + |
| 47 | +include h |
| 48 | + |
| 49 | +lemma isIso_map {i j : J} (φ : i ⟶ j) (π : j ⟶ i₀) : IsIso (F.map φ) := by |
| 50 | + have := h π |
| 51 | + have := h (φ ≫ π) |
| 52 | + exact IsIso.of_isIso_fac_right (F.map_comp φ π).symm |
| 53 | + |
| 54 | +lemma precomp {j : J} (f : j ⟶ i₀) : F.IsEventuallyConstantTo j := |
| 55 | + fun _ φ ↦ h.isIso_map φ f |
| 56 | + |
| 57 | +section |
| 58 | + |
| 59 | +variable {i j : J} (φ : i ⟶ j) (hφ : Nonempty (j ⟶ i₀)) |
| 60 | + |
| 61 | +/-- The isomorphism `F.obj i ≅ F.obj j` induced by `φ : i ⟶ j`, |
| 62 | +when `h : F.IsEventuallyConstantTo i₀` and there exists a map `j ⟶ i₀`. -/ |
| 63 | +@[simps! hom] |
| 64 | +noncomputable def isoMap : F.obj i ≅ F.obj j := |
| 65 | + have := h.isIso_map φ hφ.some |
| 66 | + asIso (F.map φ) |
| 67 | + |
| 68 | +@[reassoc (attr := simp)] |
| 69 | +lemma isoMap_hom_inv_id : F.map φ ≫ (h.isoMap φ hφ).inv = 𝟙 _ := |
| 70 | + (h.isoMap φ hφ).hom_inv_id |
| 71 | + |
| 72 | +@[reassoc (attr := simp)] |
| 73 | +lemma isoMap_inv_hom_id : (h.isoMap φ hφ).inv ≫ F.map φ = 𝟙 _ := |
| 74 | + (h.isoMap φ hφ).inv_hom_id |
| 75 | + |
| 76 | +end |
| 77 | + |
| 78 | +variable [IsCofiltered J] |
| 79 | +open IsCofiltered |
| 80 | + |
| 81 | +/-- Auxiliary definition for `IsEventuallyConstantTo.cone`. -/ |
| 82 | +noncomputable def coneπApp (j : J) : F.obj i₀ ⟶ F.obj j := |
| 83 | + (h.isoMap (minToLeft i₀ j) ⟨𝟙 _⟩).inv ≫ F.map (minToRight i₀ j) |
| 84 | + |
| 85 | +lemma coneπApp_eq (j j' : J) (α : j' ⟶ i₀) (β : j' ⟶ j) : |
| 86 | + h.coneπApp j = (h.isoMap α ⟨𝟙 _⟩).inv ≫ F.map β := by |
| 87 | + obtain ⟨s, γ, δ, h₁, h₂⟩ := IsCofiltered.bowtie |
| 88 | + (IsCofiltered.minToRight i₀ j) β (IsCofiltered.minToLeft i₀ j) α |
| 89 | + dsimp [coneπApp] |
| 90 | + rw [← cancel_epi ((h.isoMap α ⟨𝟙 _⟩).hom), isoMap_hom, isoMap_hom_inv_id_assoc, |
| 91 | + ← cancel_epi (h.isoMap δ ⟨α⟩).hom, isoMap_hom, |
| 92 | + ← F.map_comp δ β, ← h₁, F.map_comp, ← F.map_comp_assoc, ← h₂, F.map_comp_assoc, |
| 93 | + isoMap_hom_inv_id_assoc] |
| 94 | + |
| 95 | +@[simp] |
| 96 | +lemma coneπApp_eq_id : h.coneπApp i₀ = 𝟙 _ := by |
| 97 | + rw [h.coneπApp_eq i₀ i₀ (𝟙 _) (𝟙 _), h.isoMap_inv_hom_id] |
| 98 | + |
| 99 | +/-- Given `h : F.IsEventuallyConstantTo i₀`, this is the (limit) cone for `F` whose |
| 100 | +point is `F.obj i₀`. -/ |
| 101 | +@[simps] |
| 102 | +noncomputable def cone : Cone F where |
| 103 | + pt := F.obj i₀ |
| 104 | + π := |
| 105 | + { app := h.coneπApp |
| 106 | + naturality := fun j j' φ ↦ by |
| 107 | + dsimp |
| 108 | + rw [id_comp] |
| 109 | + let i := IsCofiltered.min i₀ j |
| 110 | + let α : i ⟶ i₀ := IsCofiltered.minToLeft _ _ |
| 111 | + let β : i ⟶ j := IsCofiltered.minToRight _ _ |
| 112 | + rw [h.coneπApp_eq j _ α β, assoc, h.coneπApp_eq j' _ α (β ≫ φ), map_comp] } |
| 113 | + |
| 114 | +/-- When `h : F.IsEventuallyConstantTo i₀`, the limit of `F` exists and is `F.obj i₀`. -/ |
| 115 | +def isLimitCone : IsLimit h.cone where |
| 116 | + lift s := s.π.app i₀ |
| 117 | + fac s j := by |
| 118 | + dsimp [coneπApp] |
| 119 | + rw [← s.w (IsCofiltered.minToLeft i₀ j), ← s.w (IsCofiltered.minToRight i₀ j), assoc, |
| 120 | + isoMap_hom_inv_id_assoc] |
| 121 | + uniq s m hm := by simp only [← hm i₀, cone_π_app, coneπApp_eq_id, cone_pt, comp_id] |
| 122 | + |
| 123 | +lemma hasLimit : HasLimit F := ⟨_, h.isLimitCone⟩ |
| 124 | + |
| 125 | +lemma isIso_π_of_isLimit {c : Cone F} (hc : IsLimit c) : |
| 126 | + IsIso (c.π.app i₀) := by |
| 127 | + simp only [← IsLimit.conePointUniqueUpToIso_hom_comp hc h.isLimitCone i₀, |
| 128 | + cone_π_app, coneπApp_eq_id, cone_pt, comp_id] |
| 129 | + infer_instance |
| 130 | + |
| 131 | +/-- More general version of `isIso_π_of_isLimit`. -/ |
| 132 | +lemma isIso_π_of_isLimit' {c : Cone F} (hc : IsLimit c) (j : J) (π : j ⟶ i₀) : |
| 133 | + IsIso (c.π.app j) := |
| 134 | + (h.precomp π).isIso_π_of_isLimit hc |
| 135 | + |
| 136 | +end IsEventuallyConstantTo |
| 137 | + |
| 138 | +namespace IsEventuallyConstantFrom |
| 139 | + |
| 140 | +variable {F} {i₀ : J} (h : F.IsEventuallyConstantFrom i₀) |
| 141 | + |
| 142 | +include h |
| 143 | + |
| 144 | +lemma isIso_map {i j : J} (φ : i ⟶ j) (ι : i₀ ⟶ i) : IsIso (F.map φ) := by |
| 145 | + have := h ι |
| 146 | + have := h (ι ≫ φ) |
| 147 | + exact IsIso.of_isIso_fac_left (F.map_comp ι φ).symm |
| 148 | + |
| 149 | +lemma postcomp {j : J} (f : i₀ ⟶ j) : F.IsEventuallyConstantFrom j := |
| 150 | + fun _ φ ↦ h.isIso_map φ f |
| 151 | + |
| 152 | +section |
| 153 | + |
| 154 | +variable {i j : J} (φ : i ⟶ j) (hφ : Nonempty (i₀ ⟶ i)) |
| 155 | + |
| 156 | +/-- The isomorphism `F.obj i ≅ F.obj j` induced by `φ : i ⟶ j`, |
| 157 | +when `h : F.IsEventuallyConstantFrom i₀` and there exists a map `i₀ ⟶ i`. -/ |
| 158 | +@[simps! hom] |
| 159 | +noncomputable def isoMap : F.obj i ≅ F.obj j := |
| 160 | + have := h.isIso_map φ hφ.some |
| 161 | + asIso (F.map φ) |
| 162 | + |
| 163 | +@[reassoc (attr := simp)] |
| 164 | +lemma isoMap_hom_inv_id : F.map φ ≫ (h.isoMap φ hφ).inv = 𝟙 _ := |
| 165 | + (h.isoMap φ hφ).hom_inv_id |
| 166 | + |
| 167 | +@[reassoc (attr := simp)] |
| 168 | +lemma isoMap_inv_hom_id : (h.isoMap φ hφ).inv ≫ F.map φ = 𝟙 _ := |
| 169 | + (h.isoMap φ hφ).inv_hom_id |
| 170 | + |
| 171 | +end |
| 172 | + |
| 173 | +variable [IsFiltered J] |
| 174 | +open IsFiltered |
| 175 | + |
| 176 | +/-- Auxiliary definition for `IsEventuallyConstantFrom.cocone`. -/ |
| 177 | +noncomputable def coconeιApp (j : J) : F.obj j ⟶ F.obj i₀ := |
| 178 | + F.map (rightToMax i₀ j) ≫ (h.isoMap (leftToMax i₀ j) ⟨𝟙 _⟩).inv |
| 179 | + |
| 180 | +lemma coconeιApp_eq (j j' : J) (α : j ⟶ j') (β : i₀ ⟶ j') : |
| 181 | + h.coconeιApp j = F.map α ≫ (h.isoMap β ⟨𝟙 _⟩).inv := by |
| 182 | + obtain ⟨s, γ, δ, h₁, h₂⟩ := IsFiltered.bowtie |
| 183 | + (IsFiltered.leftToMax i₀ j) β (IsFiltered.rightToMax i₀ j) α |
| 184 | + dsimp [coconeιApp] |
| 185 | + rw [← cancel_mono ((h.isoMap β ⟨𝟙 _⟩).hom), assoc, assoc, isoMap_hom, isoMap_inv_hom_id, |
| 186 | + comp_id, ← cancel_mono (h.isoMap δ ⟨β⟩).hom, isoMap_hom, assoc, assoc, ← F.map_comp α δ, |
| 187 | + ← h₂, F.map_comp, ← F.map_comp β δ, ← h₁, F.map_comp, isoMap_inv_hom_id_assoc] |
| 188 | + |
| 189 | +@[simp] |
| 190 | +lemma coconeιApp_eq_id : h.coconeιApp i₀ = 𝟙 _ := by |
| 191 | + rw [h.coconeιApp_eq i₀ i₀ (𝟙 _) (𝟙 _), h.isoMap_hom_inv_id] |
| 192 | + |
| 193 | +/-- Given `h : F.IsEventuallyConstantFrom i₀`, this is the (limit) cocone for `F` whose |
| 194 | +point is `F.obj i₀`. -/ |
| 195 | +@[simps] |
| 196 | +noncomputable def cocone : Cocone F where |
| 197 | + pt := F.obj i₀ |
| 198 | + ι := |
| 199 | + { app := h.coconeιApp |
| 200 | + naturality := fun j j' φ ↦ by |
| 201 | + dsimp |
| 202 | + rw [comp_id] |
| 203 | + let i := IsFiltered.max i₀ j' |
| 204 | + let α : i₀ ⟶ i := IsFiltered.leftToMax _ _ |
| 205 | + let β : j' ⟶ i := IsFiltered.rightToMax _ _ |
| 206 | + rw [h.coconeιApp_eq j' _ β α, h.coconeιApp_eq j _ (φ ≫ β) α, map_comp, assoc] } |
| 207 | + |
| 208 | +/-- When `h : F.IsEventuallyConstantFrom i₀`, the colimit of `F` exists and is `F.obj i₀`. -/ |
| 209 | +def isColimitCocone : IsColimit h.cocone where |
| 210 | + desc s := s.ι.app i₀ |
| 211 | + fac s j := by |
| 212 | + dsimp [coconeιApp] |
| 213 | + rw [← s.w (IsFiltered.rightToMax i₀ j), ← s.w (IsFiltered.leftToMax i₀ j), assoc, |
| 214 | + isoMap_inv_hom_id_assoc] |
| 215 | + uniq s m hm := by simp only [← hm i₀, cocone_ι_app, coconeιApp_eq_id, id_comp] |
| 216 | + |
| 217 | +lemma hasColimit : HasColimit F := ⟨_, h.isColimitCocone⟩ |
| 218 | + |
| 219 | +lemma isIso_ι_of_isColimit {c : Cocone F} (hc : IsColimit c) : |
| 220 | + IsIso (c.ι.app i₀) := by |
| 221 | + simp only [← IsColimit.comp_coconePointUniqueUpToIso_inv hc h.isColimitCocone i₀, |
| 222 | + cocone_ι_app, coconeιApp_eq_id, id_comp] |
| 223 | + infer_instance |
| 224 | + |
| 225 | +/-- More general version of `isIso_ι_of_isColimit`. -/ |
| 226 | +lemma isIso_ι_of_isColimit' {c : Cocone F} (hc : IsColimit c) (j : J) (ι : i₀ ⟶ j) : |
| 227 | + IsIso (c.ι.app j) := |
| 228 | + (h.postcomp ι).isIso_ι_of_isColimit hc |
| 229 | + |
| 230 | +end IsEventuallyConstantFrom |
| 231 | + |
| 232 | +end Functor |
| 233 | + |
| 234 | +namespace IsCofiltered |
| 235 | + |
| 236 | +/-- A functor `F : J ⥤ C` from a cofiltered category is eventually constant if there |
| 237 | +exists `j : J`, such that for any `f : i ⟶ j`, the induced map `F.map f` is an isomorphism. -/ |
| 238 | +class IsEventuallyConstant : Prop where |
| 239 | + exists_isEventuallyConstantTo : ∃ (j : J), F.IsEventuallyConstantTo j |
| 240 | + |
| 241 | +instance [hF : IsEventuallyConstant F] [IsCofiltered J] : HasLimit F := by |
| 242 | + obtain ⟨j, h⟩ := hF.exists_isEventuallyConstantTo |
| 243 | + exact h.hasLimit |
| 244 | + |
| 245 | +end IsCofiltered |
| 246 | + |
| 247 | +namespace IsFiltered |
| 248 | + |
| 249 | +/-- A functor `F : J ⥤ C` from a filtered category is eventually constant if there |
| 250 | +exists `i : J`, such that for any `f : i ⟶ j`, the induced map `F.map f` is an isomorphism. -/ |
| 251 | +class IsEventuallyConstant : Prop where |
| 252 | + exists_isEventuallyConstantFrom : ∃ (i : J), F.IsEventuallyConstantFrom i |
| 253 | + |
| 254 | +instance [hF : IsEventuallyConstant F] [IsFiltered J] : HasColimit F := by |
| 255 | + obtain ⟨j, h⟩ := hF.exists_isEventuallyConstantFrom |
| 256 | + exact h.hasColimit |
| 257 | + |
| 258 | +end IsFiltered |
| 259 | + |
| 260 | +end CategoryTheory |
0 commit comments