Skip to content

Commit 3e56ff8

Browse files
committed
feat(CategoryTheory): limits of eventually constant functors from cofiltered categories (#19021)
An eventually constant functor from a cofiltered category admits a limit. Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com>
1 parent 7113817 commit 3e56ff8

File tree

3 files changed

+281
-0
lines changed

3 files changed

+281
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,7 @@ import Mathlib.CategoryTheory.Limits.Connected
17701770
import Mathlib.CategoryTheory.Limits.Constructions.BinaryProducts
17711771
import Mathlib.CategoryTheory.Limits.Constructions.EpiMono
17721772
import Mathlib.CategoryTheory.Limits.Constructions.Equalizers
1773+
import Mathlib.CategoryTheory.Limits.Constructions.EventuallyConstant
17731774
import Mathlib.CategoryTheory.Limits.Constructions.Filtered
17741775
import Mathlib.CategoryTheory.Limits.Constructions.FiniteProductsOfBinaryProducts
17751776
import Mathlib.CategoryTheory.Limits.Constructions.LimitsOfProductsAndEqualizers

Mathlib/CategoryTheory/Filtered/Basic.lean

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,26 @@ theorem _root_.CategoryTheory.Functor.ranges_directed (F : C ⥤ Type*) (j : C)
616616
let ⟨l, li, lk, e⟩ := cospan ij kj
617617
refine ⟨⟨l, lk ≫ kj⟩, e ▸ ?_, ?_⟩ <;> simp_rw [F.map_comp] <;> apply Set.range_comp_subset_range
618618

619+
/-- Given a "bowtie" of morphisms
620+
```
621+
k₁ k₂
622+
|\ /|
623+
| \/ |
624+
| /\ |
625+
|/ \∣
626+
vv vv
627+
j₁ j₂
628+
```
629+
in a cofiltered category, we can construct an object `s` and two morphisms
630+
from `s` to `k₁` and `k₂`, making the resulting squares commute.
631+
-/
632+
theorem bowtie {j₁ j₂ k₁ k₂ : C} (f₁ : k₁ ⟶ j₁) (g₁ : k₂ ⟶ j₁) (f₂ : k₁ ⟶ j₂) (g₂ : k₂ ⟶ j₂) :
633+
∃ (s : C) (α : s ⟶ k₁) (β : s ⟶ k₂), α ≫ f₁ = β ≫ g₁ ∧ α ≫ f₂ = β ≫ g₂ := by
634+
obtain ⟨t, k₁t, k₂t, ht⟩ := cospan f₁ g₁
635+
obtain ⟨s, ts, hs⟩ := IsCofilteredOrEmpty.cone_maps (k₁t ≫ f₂) (k₂t ≫ g₂)
636+
exact ⟨s, ts ≫ k₁t, ts ≫ k₂t, by simp only [Category.assoc, ht],
637+
by simp only [Category.assoc, hs]⟩
638+
619639
end AllowEmpty
620640

621641
end IsCofiltered
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
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

Comments
 (0)