@@ -11,6 +11,14 @@ import Mathlib.CategoryTheory.Limits.Shapes.Pullback.CommSq
11
11
Shows that products in the over category can be derived from wide pullbacks in the base category.
12
12
The main result is `over_product_of_widePullback`, which says that if `C` has `J`-indexed wide
13
13
pullbacks, then `Over B` has `J`-indexed products.
14
+
15
+ Note that the binary case is done separately to ensure defeqs with the pullback in the base
16
+ category.
17
+
18
+ ## TODO
19
+
20
+ * Generalise from arbitrary products to arbitrary limits. This is done in Toric.
21
+ * Dualise to get the `Under X` results.
14
22
-/
15
23
16
24
@@ -20,9 +28,196 @@ open CategoryTheory CategoryTheory.Limits
20
28
21
29
variable {J : Type w}
22
30
variable {C : Type u} [Category.{v} C]
23
- variable {X : C}
31
+ variable {X Y Z : C}
32
+
33
+ /-!
34
+ ### Binary products
35
+
36
+ In this section we construct binary products in `Over X` and binary coproducts in `Under X`
37
+ explicitly as the pullbacks and pushouts of binary (co)fans in the base category.
38
+
39
+ For `Over X`, one could construct these binary products from the general theory of arbitrary
40
+ products from the next section, ie
41
+ ```
42
+ (Cones.postcomposeEquivalence (diagramIsoCospan _).symm).trans
43
+ (Over.ConstructProducts.conesEquiv _ (pair (Over.mk f) (Over.mk g)))
44
+ ```
45
+ but this gives worse defeqs.
46
+
47
+ For `Under X`, there is currently no general theory of arbitrary coproducts.
48
+ -/
49
+
50
+ namespace CategoryTheory.Limits
51
+ section Over
52
+ variable {f : Y ⟶ X} {g : Z ⟶ X}
53
+
54
+ /-- Pullback cones to `X` are the same thing as binary fans in `Over X`. -/
55
+ @[simps]
56
+ def pullbackConeEquivBinaryFan : PullbackCone f g ≌ BinaryFan (Over.mk f) (.mk g) where
57
+ functor.obj c := .mk (Over.homMk (U := .mk (c.fst ≫ f)) (V := .mk f) c.fst rfl)
58
+ (Over.homMk (U := .mk (c.fst ≫ f)) (V := .mk g) c.snd c.condition.symm)
59
+ functor.map {c₁ c₂} a := { hom := Over.homMk a.hom, w := by rintro (_|_) <;> aesop_cat }
60
+ inverse.obj c := PullbackCone.mk c.fst.left c.snd.left (c.fst.w.trans c.snd.w.symm)
61
+ inverse.map {c₁ c₂} a := {
62
+ hom := a.hom.left
63
+ w := by rintro (_|_|_) <;> simp [← Over.comp_left_assoc, ← Over.comp_left]
64
+ }
65
+ unitIso := NatIso.ofComponents (fun c ↦ c.eta) (by intros; ext; dsimp; simp)
66
+ counitIso := NatIso.ofComponents (fun X ↦ BinaryFan.ext (Over.isoMk (Iso.refl _)
67
+ (by simpa using X.fst.w.symm)) (by ext; dsimp; simp) (by ext; dsimp; simp))
68
+ (by intros; ext; dsimp; simp [BinaryFan.ext])
69
+ functor_unitIso_comp c := by ext; dsimp; simp [BinaryFan.ext]
70
+
71
+ /-- A binary fan in `Over X` is a limit if its corresponding pullback cone to `X` is a limit. -/
72
+ -- `IsLimit.ofConeEquiv` isn't used here because the lift it defines is `𝟙 _ ≫ pullback.lift`.
73
+ -- TODO: Define `IsLimit.copy`?
74
+ @[simps!]
75
+ def IsLimit.pullbackConeEquivBinaryFanFunctor {c : PullbackCone f g} (hc : IsLimit c) :
76
+ IsLimit <| pullbackConeEquivBinaryFan.functor.obj c :=
77
+ BinaryFan.isLimitMk
78
+ -- TODO: Drop `BinaryFan.IsLimit.lift'`. Instead provide the lemmas it bundles separately.
79
+ -- TODO: Define `abbrev BinaryFan.IsLimit (c : BinaryFan X Y) := IsLimit c` for dot notation?
80
+ (fun s ↦ Over.homMk (hc.lift <| pullbackConeEquivBinaryFan.inverse.obj s) <| by
81
+ simpa using s.fst.w)
82
+ (fun s ↦ Over.OverMorphism.ext (hc.fac _ _)) (fun s ↦ Over.OverMorphism.ext (hc.fac _ _))
83
+ fun s m e₁ e₂ ↦ by
84
+ ext1
85
+ apply PullbackCone.IsLimit.hom_ext hc
86
+ · simpa using congr(($e₁).left)
87
+ · simpa using congr(($e₂).left)
88
+
89
+ /-- A pullback cone to `X` is a limit if its corresponding binary fan in `Over X` is a limit. -/
90
+ -- This could also be `(IsLimit.ofConeEquiv pullbackConeEquivBinaryFan.symm).symm hc`, but possibly
91
+ -- bad defeqs?
92
+ def IsLimit.pullbackConeEquivBinaryFanInverse {c : BinaryFan (Over.mk f) (.mk g)} (hc : IsLimit c) :
93
+ IsLimit <| pullbackConeEquivBinaryFan.inverse.obj c :=
94
+ PullbackCone.IsLimit.mk
95
+ (c.fst.w.trans c.snd.w.symm)
96
+ (fun s ↦ (hc.lift <| pullbackConeEquivBinaryFan.functor.obj s).left)
97
+ (fun s ↦ by simpa only using congr($(hc.fac _ _).left))
98
+ (fun s ↦ by simpa only using congr($(hc.fac _ _).left))
99
+ <| fun s m hm₁ hm₂ ↦ by
100
+ change PullbackCone f g at s
101
+ have := hc.uniq (pullbackConeEquivBinaryFan.functor.obj s) (Over.homMk m <| by
102
+ have := c.fst.w
103
+ simp only [pair_obj_left, Over.mk_left, Functor.id_obj, pair_obj_right,
104
+ Functor.const_obj_obj, Over.mk_hom, Functor.id_map, CostructuredArrow.right_eq_id,
105
+ Discrete.functor_map_id, Category.comp_id] at hm₁ this
106
+ simp [← hm₁, this])
107
+ (by rintro (_ | _) <;> ext <;> simpa)
108
+ exact congr(($this).left)
109
+
110
+ end Over
111
+
112
+ section Under
113
+ variable {f : X ⟶ Y} {g : X ⟶ Z}
114
+
115
+ /-- Pushout cocones from `X` are the same thing as binary cofans in `Under X`. -/
116
+ @[simps]
117
+ def pushoutCoconeEquivBinaryCofan : PushoutCocone f g ≌ BinaryCofan (Under.mk f) (.mk g) where
118
+ functor.obj c := .mk (Under.homMk (U := .mk f) (V := .mk (f ≫ c.inl)) c.inl rfl)
119
+ (Under.homMk (U := .mk g) (V := .mk (f ≫ c.inl)) c.inr c.condition.symm)
120
+ functor.map {c₁ c₂} a := { hom := Under.homMk a.hom, w := by rintro (_|_) <;> aesop_cat }
121
+ inverse.obj c := .mk c.inl.right c.inr.right (c.inl.w.symm.trans c.inr.w)
122
+ inverse.map {c₁ c₂} a := {
123
+ hom := a.hom.right
124
+ w := by rintro (_|_|_) <;> dsimp <;> simp [← Under.comp_right]
125
+ }
126
+ unitIso := NatIso.ofComponents (fun c ↦ c.eta) (fun f ↦ by ext; dsimp; simp)
127
+ counitIso := NatIso.ofComponents (fun X ↦ BinaryCofan.ext (Under.isoMk (.refl _)
128
+ (by dsimp; simpa using X.inl.w.symm)) (by ext; dsimp; simp) (by ext; dsimp; simp))
129
+ (by intros; ext; dsimp; simp)
130
+ functor_unitIso_comp c := by ext; dsimp; simp
131
+
132
+ /-- A binary cofan in `Under X` is a colimit if its corresponding pushout cocone from `X` is a
133
+ colimit. -/
134
+ -- `IsColimit.ofCoconeEquiv` isn't used here because the lift it defines is `pushout.desc ≫ 𝟙 _`.
135
+ -- TODO: Define `IsColimit.copy`?
136
+ @[simps!]
137
+ def IsColimit.pushoutCoconeEquivBinaryCofanFunctor {c : PushoutCocone f g} (hc : IsColimit c) :
138
+ IsColimit <| pushoutCoconeEquivBinaryCofan.functor.obj c :=
139
+ BinaryCofan.isColimitMk
140
+ (fun s ↦ Under.homMk
141
+ (hc.desc (PushoutCocone.mk s.inl.right s.inr.right (s.inl.w.symm.trans s.inr.w))) <| by
142
+ simpa using s.inl.w.symm)
143
+ (fun s ↦ Under.UnderMorphism.ext (hc.fac _ _)) (fun s ↦ Under.UnderMorphism.ext (hc.fac _ _))
144
+ fun s m e₁ e₂ ↦ by
145
+ ext1
146
+ refine PushoutCocone.IsColimit.hom_ext hc ?_ ?_
147
+ · simpa using congr(($e₁).right)
148
+ · simpa using congr(($e₂).right)
149
+
150
+ /-- A pushout cocone from `X` is a colimit if its corresponding binary cofan in `Under X` is a
151
+ colimit. -/
152
+ -- This could also be `(IsColimit.ofCoconeEquiv pushoutCoconeEquivBinaryCofan.symm).symm hc`,
153
+ -- but possibly bad defeqs?
154
+ def IsColimit.pushoutCoconeEquivBinaryCofanInverse {c : BinaryCofan (Under.mk f) (.mk g)}
155
+ (hc : IsColimit c) : IsColimit <| pushoutCoconeEquivBinaryCofan.inverse.obj c :=
156
+ PushoutCocone.IsColimit.mk
157
+ (c.inl.w.symm.trans c.inr.w)
158
+ (fun s ↦ (hc.desc <| pushoutCoconeEquivBinaryCofan.functor.obj s).right)
159
+ (fun s ↦ by simpa only using congr($(hc.fac _ _).right))
160
+ (fun s ↦ by simpa only using congr($(hc.fac _ _).right))
161
+ <| fun s m hm₁ hm₂ ↦ by
162
+ change PushoutCocone f g at s
163
+ have := hc.uniq (pushoutCoconeEquivBinaryCofan.functor.obj s) (Under.homMk m <| by
164
+ have := c.inl.w
165
+ simp only [pair_obj_left, Functor.const_obj_obj, Functor.id_obj, StructuredArrow.left_eq_id,
166
+ Discrete.functor_map_id, Category.id_comp, Under.mk_right, Under.mk_hom, Functor.id_map,
167
+ pair_obj_right] at this hm₁
168
+ simp [← hm₁, ← Category.assoc, ← this])
169
+ (by rintro (_ | _) <;> ext <;> simpa)
170
+ exact congr(($this).right)
171
+
172
+ end Under
173
+ end Limits
174
+
175
+ namespace Over
176
+ section BinaryProduct
177
+ variable {X : C} {Y Z : Over X}
178
+
179
+ open Limits
180
+
181
+ lemma isPullback_of_binaryFan_isLimit (c : BinaryFan Y Z) (hc : IsLimit c) :
182
+ IsPullback c.fst.left c.snd.left Y.hom Z.hom :=
183
+ ⟨by simp, ⟨hc.pullbackConeEquivBinaryFanInverse⟩⟩
184
+
185
+ variable (Y Z) [HasPullback Y.hom Z.hom] [HasBinaryProduct Y Z]
24
186
25
- namespace CategoryTheory.Over
187
+ /-- The product of `Y` and `Z` in `Over X` is isomorpic to `Y ×ₓ Z`. -/
188
+ noncomputable
189
+ def prodLeftIsoPullback :
190
+ (Y ⨯ Z).left ≅ pullback Y.hom Z.hom :=
191
+ (Over.isPullback_of_binaryFan_isLimit _ (prodIsProd Y Z)).isoPullback
192
+
193
+ @[reassoc (attr := simp)]
194
+ lemma prodLeftIsoPullback_hom_fst :
195
+ (prodLeftIsoPullback Y Z).hom ≫ pullback.fst _ _ = (prod.fst (X := Y)).left :=
196
+ IsPullback.isoPullback_hom_fst _
197
+
198
+ @[reassoc (attr := simp)]
199
+ lemma prodLeftIsoPullback_hom_snd :
200
+ (prodLeftIsoPullback Y Z).hom ≫ pullback.snd _ _ = (prod.snd (X := Y)).left :=
201
+ IsPullback.isoPullback_hom_snd _
202
+
203
+ @[reassoc (attr := simp)]
204
+ lemma prodLeftIsoPullback_inv_fst :
205
+ (prodLeftIsoPullback Y Z).inv ≫ (prod.fst (X := Y)).left = pullback.fst _ _ :=
206
+ IsPullback.isoPullback_inv_fst _
207
+
208
+ @[reassoc (attr := simp)]
209
+ lemma prodLeftIsoPullback_inv_snd :
210
+ (prodLeftIsoPullback Y Z).inv ≫ (prod.snd (X := Y)).left = pullback.snd _ _ :=
211
+ IsPullback.isoPullback_inv_snd _
212
+
213
+ end BinaryProduct
214
+
215
+ /-!
216
+ ### Arbitrary products
217
+
218
+ In this section, we prove that `J`-indexed products in `Over X` correspond to `J`-indexed pullbacks
219
+ in `C`.
220
+ -/
26
221
27
222
namespace ConstructProducts
28
223
@@ -164,46 +359,4 @@ theorem over_hasTerminal (B : C) : HasTerminal (Over B) where
164
359
dsimp at this
165
360
rwa [Category.comp_id, Category.comp_id] at this } }
166
361
167
- section BinaryProduct
168
-
169
- variable {X : C} {Y Z : Over X}
170
-
171
- open Limits
172
-
173
- lemma isPullback_of_binaryFan_isLimit (c : BinaryFan Y Z) (hc : IsLimit c) :
174
- IsPullback c.fst.left c.snd.left Y.hom Z.hom :=
175
- ⟨by simp, ⟨((IsLimit.postcomposeHomEquiv (diagramIsoCospan _) _).symm
176
- ((IsLimit.ofConeEquiv (ConstructProducts.conesEquiv X _).symm).symm hc)).ofIsoLimit
177
- (PullbackCone.isoMk _)⟩⟩
178
-
179
- variable (Y Z) [HasPullback Y.hom Z.hom] [HasBinaryProduct Y Z]
180
-
181
- /-- The product of `Y` and `Z` in `Over X` is isomorpic to `Y ×ₓ Z`. -/
182
- noncomputable
183
- def prodLeftIsoPullback :
184
- (Y ⨯ Z).left ≅ pullback Y.hom Z.hom :=
185
- (Over.isPullback_of_binaryFan_isLimit _ (prodIsProd Y Z)).isoPullback
186
-
187
- @[reassoc (attr := simp)]
188
- lemma prodLeftIsoPullback_hom_fst :
189
- (prodLeftIsoPullback Y Z).hom ≫ pullback.fst _ _ = (prod.fst (X := Y)).left :=
190
- IsPullback.isoPullback_hom_fst _
191
-
192
- @[reassoc (attr := simp)]
193
- lemma prodLeftIsoPullback_hom_snd :
194
- (prodLeftIsoPullback Y Z).hom ≫ pullback.snd _ _ = (prod.snd (X := Y)).left :=
195
- IsPullback.isoPullback_hom_snd _
196
-
197
- @[reassoc (attr := simp)]
198
- lemma prodLeftIsoPullback_inv_fst :
199
- (prodLeftIsoPullback Y Z).inv ≫ (prod.fst (X := Y)).left = pullback.fst _ _ :=
200
- IsPullback.isoPullback_inv_fst _
201
-
202
- @[reassoc (attr := simp)]
203
- lemma prodLeftIsoPullback_inv_snd :
204
- (prodLeftIsoPullback Y Z).inv ≫ (prod.snd (X := Y)).left = pullback.snd _ _ :=
205
- IsPullback.isoPullback_inv_snd _
206
-
207
- end BinaryProduct
208
-
209
362
end CategoryTheory.Over
0 commit comments