forked from leanprover-community/mathlib4
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIsTerminal.lean
More file actions
448 lines (370 loc) · 18.1 KB
/
IsTerminal.lean
File metadata and controls
448 lines (370 loc) · 18.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
/-
Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison, Bhavik Mehta
-/
module
public import Mathlib.CategoryTheory.PEmpty
public import Mathlib.CategoryTheory.Limits.IsLimit
public import Mathlib.CategoryTheory.EpiMono
public import Mathlib.CategoryTheory.Category.Preorder
/-!
# Initial and terminal objects in a category.
In this file we define the predicates `IsTerminal` and `IsInitial` as well as the class
`InitialMonoClass`.
The classes `HasTerminal` and `HasInitial` and the associated notations for terminal and initial
objects are defined in `Terminal.lean`.
## References
* [Stacks: Initial and final objects](https://stacks.math.columbia.edu/tag/002B)
-/
@[expose] public section
assert_not_exists CategoryTheory.Limits.HasLimit
noncomputable section
universe w w' v v₁ v₂ u u₁ u₂
open CategoryTheory
namespace CategoryTheory.Limits
variable {C : Type u₁} [Category.{v₁} C]
/-- Construct a cone for the empty diagram given an object. -/
@[simps]
def asEmptyCone (X : C) : Cone (Functor.empty.{0} C) :=
{ pt := X
π :=
{ app := by cat_disch } }
/-- Construct a cocone for the empty diagram given an object. -/
@[simps]
def asEmptyCocone (X : C) : Cocone (Functor.empty.{0} C) :=
{ pt := X
ι :=
{ app := by cat_disch } }
/-- `X` is terminal if the cone it induces on the empty diagram is limiting. -/
abbrev IsTerminal (X : C) :=
IsLimit (asEmptyCone X)
/-- `X` is initial if the cocone it induces on the empty diagram is colimiting. -/
abbrev IsInitial (X : C) :=
IsColimit (asEmptyCocone X)
/-- An object `Y` is terminal iff for every `X` there is a unique morphism `X ⟶ Y`. -/
def isTerminalEquivUnique (F : Discrete.{0} PEmpty.{1} ⥤ C) (Y : C) :
IsLimit (⟨Y, by cat_disch, by simp⟩ : Cone F) ≃ ∀ X : C, Unique (X ⟶ Y) where
toFun t X :=
{ default := t.lift ⟨X, ⟨by cat_disch, by simp⟩⟩
uniq := fun f =>
t.uniq ⟨X, ⟨by cat_disch, by simp⟩⟩ f (by simp) }
invFun u :=
{ lift := fun s => (u s.pt).default
uniq := fun s _ _ => (u s.pt).2 _ }
left_inv := by dsimp [Function.LeftInverse]; intro x; simp only [eq_iff_true_of_subsingleton]
right_inv := by
dsimp [Function.RightInverse, Function.LeftInverse]
subsingleton
/-- An object `Y` is terminal if for every `X` there is a unique morphism `X ⟶ Y`
(as an instance). -/
def IsTerminal.ofUnique (Y : C) [h : ∀ X : C, Unique (X ⟶ Y)] : IsTerminal Y where
lift s := (h s.pt).default
fac := fun _ ⟨j⟩ => j.elim
/-- An object `Y` is terminal if for every `X` there is a unique morphism `X ⟶ Y`
(as explicit arguments). -/
def IsTerminal.ofUniqueHom {Y : C} (h : ∀ X : C, X ⟶ Y) (uniq : ∀ (X : C) (m : X ⟶ Y), m = h X) :
IsTerminal Y :=
have : ∀ X : C, Unique (X ⟶ Y) := fun X ↦ ⟨⟨h X⟩, uniq X⟩
IsTerminal.ofUnique Y
/-- If `α` is a preorder with top, then `⊤` is a terminal object. -/
def isTerminalTop {α : Type*} [Preorder α] [OrderTop α] : IsTerminal (⊤ : α) :=
IsTerminal.ofUnique _
/-- Transport a term of type `IsTerminal` across an isomorphism. -/
def IsTerminal.ofIso {Y Z : C} (hY : IsTerminal Y) (i : Y ≅ Z) : IsTerminal Z :=
IsLimit.ofIsoLimit hY
{ hom := { hom := i.hom }
inv := { hom := i.inv } }
/-- If `X` and `Y` are isomorphic, then `X` is terminal iff `Y` is. -/
def IsTerminal.equivOfIso {X Y : C} (e : X ≅ Y) :
IsTerminal X ≃ IsTerminal Y where
toFun h := IsTerminal.ofIso h e
invFun h := IsTerminal.ofIso h e.symm
left_inv _ := Subsingleton.elim _ _
right_inv _ := Subsingleton.elim _ _
/-- An object `X` is initial iff for every `Y` there is a unique morphism `X ⟶ Y`. -/
def isInitialEquivUnique (F : Discrete.{0} PEmpty.{1} ⥤ C) (X : C) :
IsColimit (⟨X, ⟨by cat_disch, by simp⟩⟩ : Cocone F) ≃ ∀ Y : C, Unique (X ⟶ Y) where
toFun t X :=
{ default := t.desc ⟨X, ⟨by cat_disch, by simp⟩⟩
uniq := fun f => t.uniq ⟨X, ⟨by cat_disch, by simp⟩⟩ f (by simp) }
invFun u :=
{ desc := fun s => (u s.pt).default
uniq := fun s _ _ => (u s.pt).2 _ }
left_inv := by dsimp [Function.LeftInverse]; intro; simp only [eq_iff_true_of_subsingleton]
right_inv := by
#adaptation_note /-- 19-07-2025 grind stopped working -/
intro x; dsimp
/-- An object `X` is initial if for every `Y` there is a unique morphism `X ⟶ Y`
(as an instance). -/
def IsInitial.ofUnique (X : C) [h : ∀ Y : C, Unique (X ⟶ Y)] : IsInitial X where
desc s := (h s.pt).default
fac := fun _ ⟨j⟩ => j.elim
/-- An object `X` is initial if for every `Y` there is a unique morphism `X ⟶ Y`
(as explicit arguments). -/
def IsInitial.ofUniqueHom {X : C} (h : ∀ Y : C, X ⟶ Y) (uniq : ∀ (Y : C) (m : X ⟶ Y), m = h Y) :
IsInitial X :=
have : ∀ Y : C, Unique (X ⟶ Y) := fun Y ↦ ⟨⟨h Y⟩, uniq Y⟩
IsInitial.ofUnique X
/-- If `α` is a preorder with bot, then `⊥` is an initial object. -/
def isInitialBot {α : Type*} [Preorder α] [OrderBot α] : IsInitial (⊥ : α) :=
IsInitial.ofUnique _
/-- Transport a term of type `IsInitial` across an isomorphism. -/
def IsInitial.ofIso {X Y : C} (hX : IsInitial X) (i : X ≅ Y) : IsInitial Y :=
IsColimit.ofIsoColimit hX
{ hom := { hom := i.hom }
inv := { hom := i.inv } }
/-- If `X` and `Y` are isomorphic, then `X` is initial iff `Y` is. -/
def IsInitial.equivOfIso {X Y : C} (e : X ≅ Y) :
IsInitial X ≃ IsInitial Y where
toFun h := IsInitial.ofIso h e
invFun h := IsInitial.ofIso h e.symm
left_inv _ := Subsingleton.elim _ _
right_inv _ := Subsingleton.elim _ _
/-- Give the morphism to a terminal object from any other. -/
def IsTerminal.from {X : C} (t : IsTerminal X) (Y : C) : Y ⟶ X :=
t.lift (asEmptyCone Y)
/-- Any two morphisms to a terminal object are equal. -/
theorem IsTerminal.hom_ext {X Y : C} (t : IsTerminal X) (f g : Y ⟶ X) : f = g :=
IsLimit.hom_ext t (by simp)
@[simp]
theorem IsTerminal.comp_from {Z : C} (t : IsTerminal Z) {X Y : C} (f : X ⟶ Y) :
f ≫ t.from Y = t.from X :=
t.hom_ext _ _
@[simp]
theorem IsTerminal.from_self {X : C} (t : IsTerminal X) : t.from X = 𝟙 X :=
t.hom_ext _ _
/-- Give the morphism from an initial object to any other. -/
def IsInitial.to {X : C} (t : IsInitial X) (Y : C) : X ⟶ Y :=
t.desc (asEmptyCocone Y)
/-- Any two morphisms from an initial object are equal. -/
theorem IsInitial.hom_ext {X Y : C} (t : IsInitial X) (f g : X ⟶ Y) : f = g :=
IsColimit.hom_ext t (by simp)
@[simp]
theorem IsInitial.to_comp {X : C} (t : IsInitial X) {Y Z : C} (f : Y ⟶ Z) : t.to Y ≫ f = t.to Z :=
t.hom_ext _ _
@[simp]
theorem IsInitial.to_self {X : C} (t : IsInitial X) : t.to X = 𝟙 X :=
t.hom_ext _ _
/-- Any morphism from a terminal object is split mono. -/
theorem IsTerminal.isSplitMono_from {X Y : C} (t : IsTerminal X) (f : X ⟶ Y) : IsSplitMono f :=
IsSplitMono.mk' ⟨t.from _, t.hom_ext _ _⟩
/-- Any morphism to an initial object is split epi. -/
theorem IsInitial.isSplitEpi_to {X Y : C} (t : IsInitial X) (f : Y ⟶ X) : IsSplitEpi f :=
IsSplitEpi.mk' ⟨t.to _, t.hom_ext _ _⟩
/-- Any morphism from a terminal object is mono. -/
theorem IsTerminal.mono_from {X Y : C} (t : IsTerminal X) (f : X ⟶ Y) : Mono f := by
haveI := t.isSplitMono_from f; infer_instance
/-- Any morphism to an initial object is epi. -/
theorem IsInitial.epi_to {X Y : C} (t : IsInitial X) (f : Y ⟶ X) : Epi f := by
haveI := t.isSplitEpi_to f; infer_instance
/-- If `T` and `T'` are terminal, they are isomorphic. -/
@[simps]
def IsTerminal.uniqueUpToIso {T T' : C} (hT : IsTerminal T) (hT' : IsTerminal T') : T ≅ T' where
hom := hT'.from _
inv := hT.from _
/-- If `I` and `I'` are initial, they are isomorphic. -/
@[simps]
def IsInitial.uniqueUpToIso {I I' : C} (hI : IsInitial I) (hI' : IsInitial I') : I ≅ I' where
hom := hI.to _
inv := hI'.to _
variable (C)
section Univ
variable (X : C) {F₁ : Discrete.{w} PEmpty ⥤ C} {F₂ : Discrete.{w'} PEmpty ⥤ C}
/-- Being terminal is independent of the empty diagram, its universe, and the cone over it,
as long as the cone points are isomorphic. -/
def isLimitChangeEmptyCone {c₁ : Cone F₁} (hl : IsLimit c₁) (c₂ : Cone F₂) (hi : c₁.pt ≅ c₂.pt) :
IsLimit c₂ where
lift c := hl.lift ⟨c.pt, by cat_disch, by simp⟩ ≫ hi.hom
uniq c f _ := by
dsimp
rw [← hl.uniq _ (f ≫ hi.inv) _]
· simp only [Category.assoc, Iso.inv_hom_id, Category.comp_id]
· simp
/-- Replacing an empty cone in `IsLimit` by another with the same cone point
is an equivalence. -/
def isLimitEmptyConeEquiv (c₁ : Cone F₁) (c₂ : Cone F₂) (h : c₁.pt ≅ c₂.pt) :
IsLimit c₁ ≃ IsLimit c₂ where
toFun hl := isLimitChangeEmptyCone C hl c₂ h
invFun hl := isLimitChangeEmptyCone C hl c₁ h.symm
left_inv := by dsimp [Function.LeftInverse]; intro; simp only [eq_iff_true_of_subsingleton]
right_inv := by
dsimp [Function.LeftInverse, Function.RightInverse]; intro
simp only [eq_iff_true_of_subsingleton]
/-- If `F` is an empty diagram, then a cone over `F` is limiting iff the cone point is terminal. -/
noncomputable
def isLimitEquivIsTerminalOfIsEmpty {J : Type*} [Category* J] [IsEmpty J] {F : J ⥤ C} (c : Cone F) :
IsLimit c ≃ IsTerminal c.pt :=
(IsLimit.whiskerEquivalenceEquiv (equivalenceOfIsEmpty (Discrete PEmpty.{1}) _)).trans
(isLimitEmptyConeEquiv _ _ _ (.refl _))
/-- Being initial is independent of the empty diagram, its universe, and the cocone over it,
as long as the cocone points are isomorphic. -/
def isColimitChangeEmptyCocone {c₁ : Cocone F₁} (hl : IsColimit c₁) (c₂ : Cocone F₂)
(hi : c₁.pt ≅ c₂.pt) : IsColimit c₂ where
desc c := hi.inv ≫ hl.desc ⟨c.pt, by cat_disch, by simp⟩
uniq c f _ := by
dsimp
rw [← hl.uniq _ (hi.hom ≫ f) _]
· simp only [Iso.inv_hom_id_assoc]
· simp
/-- Replacing an empty cocone in `IsColimit` by another with the same cocone point
is an equivalence. -/
def isColimitEmptyCoconeEquiv (c₁ : Cocone F₁) (c₂ : Cocone F₂) (h : c₁.pt ≅ c₂.pt) :
IsColimit c₁ ≃ IsColimit c₂ where
toFun hl := isColimitChangeEmptyCocone C hl c₂ h
invFun hl := isColimitChangeEmptyCocone C hl c₁ h.symm
left_inv := by dsimp [Function.LeftInverse]; intro; simp only [eq_iff_true_of_subsingleton]
right_inv := by
dsimp [Function.LeftInverse, Function.RightInverse]; intro
simp only [eq_iff_true_of_subsingleton]
/-- If `F` is an empty diagram,
then a cocone over `F` is colimiting iff the cocone point is initial. -/
noncomputable
def isColimitEquivIsInitialOfIsEmpty {J : Type*} [Category* J] [IsEmpty J]
{F : J ⥤ C} (c : Cocone F) : IsColimit c ≃ IsInitial c.pt :=
(IsColimit.whiskerEquivalenceEquiv (equivalenceOfIsEmpty (Discrete PEmpty.{1}) _)).trans
(isColimitEmptyCoconeEquiv _ _ _ (.refl _))
end Univ
section
variable {C}
/-- An initial object is terminal in the opposite category. -/
def terminalOpOfInitial {X : C} (t : IsInitial X) : IsTerminal (Opposite.op X) where
lift s := (t.to s.pt.unop).op
uniq _ _ _ := Quiver.Hom.unop_inj (t.hom_ext _ _)
/-- An initial object in the opposite category is terminal in the original category. -/
def terminalUnopOfInitial {X : Cᵒᵖ} (t : IsInitial X) : IsTerminal X.unop where
lift s := (t.to (Opposite.op s.pt)).unop
uniq _ _ _ := Quiver.Hom.op_inj (t.hom_ext _ _)
/-- A terminal object is initial in the opposite category. -/
def initialOpOfTerminal {X : C} (t : IsTerminal X) : IsInitial (Opposite.op X) where
desc s := (t.from s.pt.unop).op
uniq _ _ _ := Quiver.Hom.unop_inj (t.hom_ext _ _)
/-- A terminal object in the opposite category is initial in the original category. -/
def initialUnopOfTerminal {X : Cᵒᵖ} (t : IsTerminal X) : IsInitial X.unop where
desc s := (t.from (Opposite.op s.pt)).unop
uniq _ _ _ := Quiver.Hom.op_inj (t.hom_ext _ _)
/-- A category is an `InitialMonoClass` if the canonical morphism of an initial object is a
monomorphism. In practice, this is most useful when given an arbitrary morphism out of the chosen
initial object, see `initial.mono_from`.
Given a terminal object, this is equivalent to the assumption that the unique morphism from initial
to terminal is a monomorphism, which is the second of Freyd's axioms for an AT category.
TODO: This is a condition satisfied by categories with zero objects and morphisms.
-/
class InitialMonoClass (C : Type u₁) [Category.{v₁} C] : Prop where
/-- The map from the (any as stated) initial object to any other object is a
monomorphism -/
isInitial_mono_from : ∀ {I} (X : C) (hI : IsInitial I), Mono (hI.to X)
theorem IsInitial.mono_from [InitialMonoClass C] {I} {X : C} (hI : IsInitial I) (f : I ⟶ X) :
Mono f := by
rw [hI.hom_ext f (hI.to X)]
apply InitialMonoClass.isInitial_mono_from
/-- To show a category is an `InitialMonoClass` it suffices to give an initial object such that
every morphism out of it is a monomorphism. -/
theorem InitialMonoClass.of_isInitial {I : C} (hI : IsInitial I) (h : ∀ X, Mono (hI.to X)) :
InitialMonoClass C where
isInitial_mono_from {I'} X hI' := by
rw [hI'.hom_ext (hI'.to X) ((hI'.uniqueUpToIso hI).hom ≫ hI.to X)]
apply mono_comp
/-- To show a category is an `InitialMonoClass` it suffices to show the unique morphism from an
initial object to a terminal object is a monomorphism. -/
theorem InitialMonoClass.of_isTerminal {I T : C} (hI : IsInitial I) (hT : IsTerminal T)
(_ : Mono (hI.to T)) : InitialMonoClass C :=
InitialMonoClass.of_isInitial hI fun X => mono_of_mono_fac (hI.hom_ext (_ ≫ hT.from X) (hI.to T))
variable {J : Type u} [Category.{v} J]
/-- From a functor `F : J ⥤ C`, given an initial object of `J`, construct a cone for `J`.
In `limitOfDiagramInitial` we show it is a limit cone. -/
@[simps]
def coneOfDiagramInitial {X : J} (tX : IsInitial X) (F : J ⥤ C) : Cone F where
pt := F.obj X
π :=
{ app := fun j => F.map (tX.to j)
naturality := fun j j' k => by
dsimp
rw [← F.map_comp, Category.id_comp, tX.hom_ext (tX.to j ≫ k) (tX.to j')] }
/-- From a functor `F : J ⥤ C`, given an initial object of `J`, show the cone
`coneOfDiagramInitial` is a limit. -/
def limitOfDiagramInitial {X : J} (tX : IsInitial X) (F : J ⥤ C) :
IsLimit (coneOfDiagramInitial tX F) where
lift s := s.π.app X
uniq s m w := by
conv_lhs => dsimp
simp_rw [← w X, coneOfDiagramInitial_π_app, tX.hom_ext (tX.to X) (𝟙 _)]
simp
/-- From a functor `F : J ⥤ C`, given a terminal object of `J`, construct a cone for `J`,
provided that the morphisms in the diagram are isomorphisms.
In `limitOfDiagramTerminal` we show it is a limit cone. -/
@[simps]
def coneOfDiagramTerminal {X : J} (hX : IsTerminal X) (F : J ⥤ C)
[∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : Cone F where
pt := F.obj X
π :=
{ app := fun _ => inv (F.map (hX.from _))
naturality := by
intro i j f
dsimp
simp only [IsIso.eq_inv_comp, IsIso.comp_inv_eq, Category.id_comp, ← F.map_comp,
hX.hom_ext (hX.from i) (f ≫ hX.from j)] }
/-- From a functor `F : J ⥤ C`, given a terminal object of `J` and that the morphisms in the
diagram are isomorphisms, show the cone `coneOfDiagramTerminal` is a limit. -/
def limitOfDiagramTerminal {X : J} (hX : IsTerminal X) (F : J ⥤ C)
[∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : IsLimit (coneOfDiagramTerminal hX F) where
lift S := S.π.app _
/-- From a functor `F : J ⥤ C`, given a terminal object of `J`, construct a cocone for `J`.
In `colimitOfDiagramTerminal` we show it is a colimit cocone. -/
@[simps]
def coconeOfDiagramTerminal {X : J} (tX : IsTerminal X) (F : J ⥤ C) : Cocone F where
pt := F.obj X
ι :=
{ app := fun j => F.map (tX.from j)
naturality := fun j j' k => by
dsimp
rw [← F.map_comp, Category.comp_id, tX.hom_ext (k ≫ tX.from j') (tX.from j)] }
/-- From a functor `F : J ⥤ C`, given a terminal object of `J`, show the cocone
`coconeOfDiagramTerminal` is a colimit. -/
def colimitOfDiagramTerminal {X : J} (tX : IsTerminal X) (F : J ⥤ C) :
IsColimit (coconeOfDiagramTerminal tX F) where
desc s := s.ι.app X
uniq s m w := by simp [← w X]
lemma IsColimit.isIso_ι_app_of_isTerminal {F : J ⥤ C} {c : Cocone F} (hc : IsColimit c)
(X : J) (hX : IsTerminal X) :
IsIso (c.ι.app X) := by
change IsIso (coconePointUniqueUpToIso (colimitOfDiagramTerminal hX F) hc).hom
infer_instance
/-- From a functor `F : J ⥤ C`, given an initial object of `J`, construct a cocone for `J`,
provided that the morphisms in the diagram are isomorphisms.
In `colimitOfDiagramInitial` we show it is a colimit cocone. -/
@[simps]
def coconeOfDiagramInitial {X : J} (hX : IsInitial X) (F : J ⥤ C)
[∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : Cocone F where
pt := F.obj X
ι :=
{ app := fun _ => inv (F.map (hX.to _))
naturality := by
intro i j f
dsimp
simp only [IsIso.eq_inv_comp, IsIso.comp_inv_eq, Category.comp_id, ← F.map_comp,
hX.hom_ext (hX.to i ≫ f) (hX.to j)] }
/-- From a functor `F : J ⥤ C`, given an initial object of `J` and that the morphisms in the
diagram are isomorphisms, show the cone `coconeOfDiagramInitial` is a colimit. -/
def colimitOfDiagramInitial {X : J} (hX : IsInitial X) (F : J ⥤ C)
[∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : IsColimit (coconeOfDiagramInitial hX F) where
desc S := S.ι.app _
lemma IsLimit.isIso_π_app_of_isInitial {F : J ⥤ C} {c : Cone F} (hc : IsLimit c)
(X : J) (hX : IsInitial X) :
IsIso (c.π.app X) := by
change IsIso (conePointUniqueUpToIso hc (limitOfDiagramInitial hX F)).hom
infer_instance
/-- Any morphism between terminal objects is an isomorphism. -/
lemma isIso_of_isTerminal {X Y : C} (hX : IsTerminal X) (hY : IsTerminal Y) (f : X ⟶ Y) :
IsIso f := by
refine ⟨⟨IsTerminal.from hX Y, ?_⟩⟩
simp only [IsTerminal.comp_from, IsTerminal.from_self, true_and]
apply IsTerminal.hom_ext hY
/-- Any morphism between initial objects is an isomorphism. -/
lemma isIso_of_isInitial {X Y : C} (hX : IsInitial X) (hY : IsInitial Y) (f : X ⟶ Y) :
IsIso f := by
refine ⟨⟨IsInitial.to hY X, ?_⟩⟩
simp only [IsInitial.to_comp, IsInitial.to_self, and_true]
apply IsInitial.hom_ext hX
end
end CategoryTheory.Limits