Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit a796008

Browse files
b-mehtakim-em
andcommitted
feat(category_theory): cartesian closed categories (#2894)
Cartesian closed categories, from my topos project. Co-authored-by: Scott Morrison <scott@tqft.net>
1 parent 25e414d commit a796008

File tree

6 files changed

+525
-0
lines changed

6 files changed

+525
-0
lines changed
Lines changed: 394 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,394 @@
1+
/-
2+
Copyright (c) 2020 Bhavik Mehta, Edward Ayers, Thomas Read. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Bhavik Mehta, Edward Ayers, Thomas Read
5+
-/
6+
7+
import category_theory.limits.shapes.binary_products
8+
import category_theory.limits.shapes.constructions.preserve_binary_products
9+
import category_theory.closed.monoidal
10+
import category_theory.monoidal.of_has_finite_products
11+
import category_theory.adjunction
12+
import category_theory.epi_mono
13+
14+
/-!
15+
# Cartesian closed categories
16+
17+
Given a category with finite products, the cartesian monoidal structure is provided by the local
18+
instance `monoidal_of_has_finite_products`.
19+
20+
We define exponentiable objects to be closed objects with respect to this monoidal structure,
21+
i.e. `(X × -)` is a left adjoint.
22+
23+
We say a category is cartesian closed if every object is exponentiable
24+
(equivalently, that the category equipped with the cartesian monoidal structure is closed monoidal).
25+
26+
Show that exponential forms a difunctor and define the exponential comparison morphisms.
27+
28+
## TODO
29+
Some of the results here are true more generally for closed objects and
30+
for closed monoidal categories, and these could be generalised.
31+
-/
32+
universes v u u₂
33+
34+
namespace category_theory
35+
36+
open category_theory category_theory.category category_theory.limits
37+
38+
local attribute [instance] monoidal_of_has_finite_products
39+
40+
/--
41+
An object `X` is *exponentiable* if `(X × -)` is a left adjoint.
42+
We define this as being `closed` in the cartesian monoidal structure.
43+
-/
44+
abbreviation exponentiable {C : Type u} [category.{v} C] [has_finite_products.{v} C] (X : C) :=
45+
closed X
46+
47+
/--
48+
If `X` and `Y` are exponentiable then `X ⨯ Y` is.
49+
This isn't an instance because it's not usually how we want to construct exponentials, we'll usually
50+
prove all objects are exponential uniformly.
51+
-/
52+
def binary_product_exponentiable {C : Type u} [category.{v} C] [has_finite_products.{v} C] {X Y : C}
53+
(hX : exponentiable X) (hY : exponentiable Y) : exponentiable (X ⨯ Y) :=
54+
{ is_adj :=
55+
begin
56+
haveI := hX.is_adj,
57+
haveI := hY.is_adj,
58+
exact adjunction.left_adjoint_of_nat_iso (monoidal_category.tensor_left_tensor _ _).symm
59+
end }
60+
61+
/--
62+
The terminal object is always exponentiable.
63+
This isn't an instance because most of the time we'll prove cartesian closed for all objects
64+
at once, rather than just for this one.
65+
-/
66+
def terminal_exponentiable {C : Type u} [category.{v} C] [has_finite_products.{v} C] : exponentiable ⊤_C :=
67+
{ is_adj :=
68+
{ right := 𝟭 C,
69+
adj := adjunction.mk_of_hom_equiv
70+
{ hom_equiv := λ X _, have unitor : _, from prod.left_unitor X,
71+
⟨λ a, unitor.inv ≫ a, λ a, unitor.hom ≫ a, by tidy, by tidy⟩ } } }
72+
73+
/--
74+
A category `C` is cartesian closed if it has finite products and every object is exponentiable.
75+
We define this as `monoidal_closed` with respect to the cartesian monoidal structure.
76+
-/
77+
abbreviation cartesian_closed (C : Type u) [category.{v} C] [has_finite_products.{v} C] :=
78+
monoidal_closed C
79+
80+
variables {C : Type u} [category.{v} C] (A B : C) {X X' Y Y' Z : C}
81+
82+
section exp
83+
variables [has_finite_products.{v} C] [exponentiable A]
84+
85+
/-- This is (-)^A. -/
86+
def exp : C ⥤ C :=
87+
(@closed.is_adj _ _ _ A _).right
88+
89+
/-- The adjunction between A ⨯ - and (-)^A. -/
90+
def exp.adjunction : prod_functor.obj A ⊣ exp A :=
91+
closed.is_adj.adj
92+
93+
/-- The evaluation natural transformation. -/
94+
def ev : exp A ⋙ prod_functor.obj A ⟶ 𝟭 C :=
95+
closed.is_adj.adj.counit
96+
97+
/-- The coevaluation natural transformation. -/
98+
def coev : 𝟭 C ⟶ prod_functor.obj A ⋙ exp A :=
99+
closed.is_adj.adj.unit
100+
101+
notation A ` ⟹ `:20 B:20 := (exp A).obj B
102+
notation A ` ^^ `:30 B:30 := (exp A).obj B
103+
104+
@[simp, reassoc] lemma ev_coev : limits.prod.map (𝟙 A) ((coev A).app B) ≫ (ev A).app (A ⨯ B) = 𝟙 (A ⨯ B) :=
105+
adjunction.left_triangle_components (exp.adjunction A)
106+
107+
@[simp, reassoc] lemma coev_ev : (coev A).app (A⟹B) ≫ (exp A).map ((ev A).app B) = 𝟙 (A⟹B) :=
108+
adjunction.right_triangle_components (exp.adjunction A)
109+
110+
end exp
111+
112+
variables {A}
113+
114+
-- Wrap these in a namespace so we don't clash with the core versions.
115+
namespace is_cartesian_closed
116+
117+
variables [has_finite_products.{v} C] [exponentiable A]
118+
119+
/-- Currying in a cartesian closed category. -/
120+
def curry : (A ⨯ Y ⟶ X) → (Y ⟶ A ⟹ X) :=
121+
(closed.is_adj.adj.hom_equiv _ _).to_fun
122+
/-- Uncurrying in a cartesian closed category. -/
123+
def uncurry : (Y ⟶ A ⟹ X) → (A ⨯ Y ⟶ X) :=
124+
(closed.is_adj.adj.hom_equiv _ _).inv_fun
125+
126+
end is_cartesian_closed
127+
128+
open is_cartesian_closed
129+
130+
variables [has_finite_products.{v} C] [exponentiable A]
131+
132+
@[reassoc]
133+
lemma curry_natural_left (f : X ⟶ X') (g : A ⨯ X' ⟶ Y) :
134+
curry (limits.prod.map (𝟙 _) f ≫ g) = f ≫ curry g :=
135+
adjunction.hom_equiv_naturality_left _ _ _
136+
137+
@[reassoc]
138+
lemma curry_natural_right (f : A ⨯ X ⟶ Y) (g : Y ⟶ Y') :
139+
curry (f ≫ g) = curry f ≫ (exp _).map g :=
140+
adjunction.hom_equiv_naturality_right _ _ _
141+
142+
@[reassoc]
143+
lemma uncurry_natural_right (f : X ⟶ A⟹Y) (g : Y ⟶ Y') :
144+
uncurry (f ≫ (exp _).map g) = uncurry f ≫ g :=
145+
adjunction.hom_equiv_naturality_right_symm _ _ _
146+
147+
@[reassoc]
148+
lemma uncurry_natural_left (f : X ⟶ X') (g : X' ⟶ A⟹Y) :
149+
uncurry (f ≫ g) = limits.prod.map (𝟙 _) f ≫ uncurry g :=
150+
adjunction.hom_equiv_naturality_left_symm _ _ _
151+
152+
@[simp]
153+
lemma uncurry_curry (f : A ⨯ X ⟶ Y) : uncurry (curry f) = f :=
154+
(closed.is_adj.adj.hom_equiv _ _).left_inv f
155+
156+
@[simp]
157+
lemma curry_uncurry (f : X ⟶ A⟹Y) : curry (uncurry f) = f :=
158+
(closed.is_adj.adj.hom_equiv _ _).right_inv f
159+
160+
lemma curry_eq_iff (f : A ⨯ Y ⟶ X) (g : Y ⟶ A ⟹ X) :
161+
curry f = g ↔ f = uncurry g :=
162+
adjunction.hom_equiv_apply_eq _ f g
163+
164+
lemma eq_curry_iff (f : A ⨯ Y ⟶ X) (g : Y ⟶ A ⟹ X) :
165+
g = curry f ↔ uncurry g = f :=
166+
adjunction.eq_hom_equiv_apply _ f g
167+
168+
-- I don't think these two should be simp.
169+
lemma uncurry_eq (g : Y ⟶ A ⟹ X) : uncurry g = limits.prod.map (𝟙 A) g ≫ (ev A).app X :=
170+
adjunction.hom_equiv_counit _
171+
172+
lemma curry_eq (g : A ⨯ Y ⟶ X) : curry g = (coev A).app Y ≫ (exp A).map g :=
173+
adjunction.hom_equiv_unit _
174+
175+
lemma uncurry_id_eq_ev (A X : C) [exponentiable A] : uncurry (𝟙 (A ⟹ X)) = (ev A).app X :=
176+
by rw [uncurry_eq, prod_map_id_id, id_comp]
177+
178+
lemma curry_id_eq_coev (A X : C) [exponentiable A] : curry (𝟙 _) = (coev A).app X :=
179+
by { rw [curry_eq, (exp A).map_id (A ⨯ _)], apply comp_id }
180+
181+
lemma curry_injective : function.injective (curry : (A ⨯ Y ⟶ X) → (Y ⟶ A ⟹ X)) :=
182+
(closed.is_adj.adj.hom_equiv _ _).injective
183+
184+
lemma uncurry_injective : function.injective (uncurry : (Y ⟶ A ⟹ X) → (A ⨯ Y ⟶ X)) :=
185+
(closed.is_adj.adj.hom_equiv _ _).symm.injective
186+
187+
/--
188+
Show that the exponential of the terminal object is isomorphic to itself, i.e. `X^1 ≅ X`.
189+
190+
The typeclass argument is explicit: any instance can be used.
191+
-/
192+
def exp_terminal_iso_self [exponentiable ⊤_C] : (⊤_C ⟹ X) ≅ X :=
193+
yoneda.ext (⊤_ C ⟹ X) X
194+
(λ Y f, (prod.left_unitor Y).inv ≫ uncurry f)
195+
(λ Y f, curry ((prod.left_unitor Y).hom ≫ f))
196+
(λ Z g, by rw [curry_eq_iff, iso.hom_inv_id_assoc] )
197+
(λ Z g, by simp)
198+
(λ Z W f g, by rw [uncurry_natural_left, prod_left_unitor_inv_naturality_assoc f] )
199+
200+
/-- The internal element which points at the given morphism. -/
201+
def internalize_hom (f : A ⟶ Y) : ⊤_C ⟶ (A ⟹ Y) :=
202+
curry (limits.prod.fst ≫ f)
203+
204+
section pre
205+
206+
variables {B}
207+
208+
/-- Pre-compose an internal hom with an external hom. -/
209+
def pre (X : C) (f : B ⟶ A) [exponentiable B] : (A⟹X) ⟶ B⟹X :=
210+
curry (limits.prod.map f (𝟙 _) ≫ (ev A).app X)
211+
212+
lemma pre_id (A X : C) [exponentiable A] : pre X (𝟙 A) = 𝟙 (A⟹X) :=
213+
by { rw [pre, prod_map_id_id, id_comp, ← uncurry_id_eq_ev], simp }
214+
215+
-- There's probably a better proof of this somehow
216+
/-- Precomposition is contrafunctorial. -/
217+
lemma pre_map [exponentiable B] {D : C} [exponentiable D] (f : A ⟶ B) (g : B ⟶ D) :
218+
pre X (f ≫ g) = pre X g ≫ pre X f :=
219+
begin
220+
rw [pre, curry_eq_iff, pre, pre, uncurry_natural_left, uncurry_curry, prod_map_map_assoc,
221+
prod_map_comp_id, assoc, ← uncurry_id_eq_ev, ← uncurry_id_eq_ev, ← uncurry_natural_left,
222+
curry_natural_right, comp_id, uncurry_natural_right, uncurry_curry],
223+
end
224+
225+
end pre
226+
227+
lemma pre_post_comm [cartesian_closed C] {A B : C} {X Y : Cᵒᵖ} (f : A ⟶ B) (g : X ⟶ Y) :
228+
pre A g.unop ≫ (exp Y.unop).map f = (exp X.unop).map f ≫ pre B g.unop :=
229+
begin
230+
erw [← curry_natural_left, eq_curry_iff, uncurry_natural_right, uncurry_curry, prod_map_map_assoc,
231+
(ev _).naturality, assoc], refl
232+
end
233+
234+
/-- The internal hom functor given by the cartesian closed structure. -/
235+
def internal_hom [cartesian_closed C] : C ⥤ Cᵒᵖ ⥤ C :=
236+
{ obj := λ X,
237+
{ obj := λ Y, Y.unop ⟹ X,
238+
map := λ Y Y' f, pre _ f.unop,
239+
map_id' := λ Y, pre_id _ _,
240+
map_comp' := λ Y Y' Y'' f g, pre_map _ _ },
241+
map := λ A B f, { app := λ X, (exp X.unop).map f, naturality' := λ X Y g, pre_post_comm _ _ },
242+
map_id' := λ X, by { ext, apply functor.map_id },
243+
map_comp' := λ X Y Z f g, by { ext, apply functor.map_comp } }
244+
245+
/-- If an initial object `0` exists in a CCC, then `A ⨯ 0 ≅ 0`. -/
246+
@[simps]
247+
def zero_mul [has_initial.{v} C] : A ⨯ ⊥_ C ≅ ⊥_ C :=
248+
{ hom := limits.prod.snd,
249+
inv := default (⊥_ C ⟶ A ⨯ ⊥_ C),
250+
hom_inv_id' :=
251+
begin
252+
have: (limits.prod.snd : A ⨯ ⊥_ C ⟶ ⊥_ C) = uncurry (default _),
253+
rw ← curry_eq_iff,
254+
apply subsingleton.elim,
255+
rw [this, ← uncurry_natural_right, ← eq_curry_iff],
256+
apply subsingleton.elim
257+
end,
258+
}
259+
260+
/-- If an initial object `0` exists in a CCC, then `0 ⨯ A ≅ 0`. -/
261+
def mul_zero [has_initial.{v} C] : ⊥_ C ⨯ A ≅ ⊥_ C :=
262+
limits.prod.braiding _ _ ≪≫ zero_mul
263+
264+
/-- If an initial object `0` exists in a CCC then `0^B ≅ 1` for any `B`. -/
265+
def pow_zero [has_initial.{v} C] [cartesian_closed C] : ⊥_C ⟹ B ≅ ⊤_ C :=
266+
{ hom := default _,
267+
inv := curry (mul_zero.hom ≫ default (⊥_ C ⟶ B)),
268+
hom_inv_id' :=
269+
begin
270+
rw [← curry_natural_left, curry_eq_iff, ← cancel_epi mul_zero.inv],
271+
{ apply subsingleton.elim },
272+
{ apply_instance },
273+
{ apply_instance }
274+
end }
275+
276+
-- TODO: Generalise the below to its commutated variants.
277+
-- TODO: Define a distributive category, so that zero_mul and friends can be derived from this.
278+
/-- In a CCC with binary coproducts, the distribution morphism is an isomorphism. -/
279+
def prod_coprod_distrib [has_binary_coproducts.{v} C] [cartesian_closed C] (X Y Z : C) :
280+
(Z ⨯ X) ⨿ (Z ⨯ Y) ≅ Z ⨯ (X ⨿ Y) :=
281+
{ hom := coprod.desc (limits.prod.map (𝟙 _) coprod.inl) (limits.prod.map (𝟙 _) coprod.inr),
282+
inv := uncurry (coprod.desc (curry coprod.inl) (curry coprod.inr)),
283+
hom_inv_id' :=
284+
begin
285+
apply coprod.hom_ext,
286+
rw [coprod.inl_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inl_desc, uncurry_curry],
287+
rw [coprod.inr_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inr_desc, uncurry_curry],
288+
end,
289+
inv_hom_id' :=
290+
begin
291+
rw [← uncurry_natural_right, ← eq_curry_iff],
292+
apply coprod.hom_ext,
293+
rw [coprod.inl_desc_assoc, ← curry_natural_right, coprod.inl_desc, ← curry_natural_left, comp_id],
294+
rw [coprod.inr_desc_assoc, ← curry_natural_right, coprod.inr_desc, ← curry_natural_left, comp_id],
295+
end }
296+
297+
/--
298+
If an initial object `0` exists in a CCC then it is a strict initial object,
299+
i.e. any morphism to `0` is an iso.
300+
-/
301+
instance strict_initial [has_initial.{v} C] {f : A ⟶ ⊥_ C} : is_iso f :=
302+
begin
303+
haveI : mono (limits.prod.lift (𝟙 A) f ≫ zero_mul.hom) := mono_comp _ _,
304+
rw [zero_mul_hom, prod.lift_snd] at _inst,
305+
haveI: split_epi f := ⟨default _, subsingleton.elim _ _⟩,
306+
apply is_iso_of_mono_of_split_epi
307+
end
308+
309+
/-- If an initial object `0` exists in a CCC then every morphism from it is monic. -/
310+
instance initial_mono (B : C) [has_initial.{v} C] [cartesian_closed C] : mono (initial.to B) :=
311+
⟨λ B g h _, eq_of_inv_eq_inv (subsingleton.elim (inv g) (inv h))⟩
312+
313+
variables {D : Type u₂} [category.{v} D]
314+
section functor
315+
316+
variables [has_finite_products.{v} D]
317+
318+
/--
319+
Transport the property of being cartesian closed across an equivalence of categories.
320+
321+
Note we didn't require any coherence between the choice of finite products here, since we transport
322+
along the `prod_comparison` isomorphism.
323+
-/
324+
def cartesian_closed_of_equiv (e : C ≌ D) [h : cartesian_closed C] : cartesian_closed D :=
325+
{ closed := λ X,
326+
{ is_adj :=
327+
begin
328+
haveI q : exponentiable (e.inverse.obj X) := infer_instance,
329+
have : is_left_adjoint (prod_functor.obj (e.inverse.obj X)) := q.is_adj,
330+
have: e.functor ⋙ prod_functor.obj X ⋙ e.inverse ≅ prod_functor.obj (e.inverse.obj X),
331+
apply nat_iso.of_components _ _,
332+
intro Y,
333+
apply as_iso (prod_comparison e.inverse X (e.functor.obj Y)) ≪≫ _,
334+
refine ⟨limits.prod.map (𝟙 _) (e.unit_inv.app _),
335+
limits.prod.map (𝟙 _) (e.unit.app _),
336+
by simpa [← prod_map_id_comp, prod_map_id_id],
337+
by simpa [← prod_map_id_comp, prod_map_id_id]⟩,
338+
intros Y Z g,
339+
simp only [prod_comparison, inv_prod_comparison_map_fst, inv_prod_comparison_map_snd,
340+
prod.lift_map, equivalence.unit_inv, functor.comp_map,
341+
prod_functor_obj_map, assoc, comp_id, iso.trans_hom, as_iso_hom],
342+
apply prod.hom_ext,
343+
rw [assoc, prod.lift_fst, prod.lift_fst, ← functor.map_comp, limits.prod.map_fst, comp_id],
344+
rw [assoc, prod.lift_snd, prod.lift_snd, ← functor.map_comp_assoc, limits.prod.map_snd],
345+
simp only [equivalence.unit, equivalence.unit_inv, nat_iso.hom_inv_id_app, assoc, equivalence.inv_fun_map, functor.map_comp, comp_id],
346+
erw comp_id,
347+
haveI : is_left_adjoint (e.functor ⋙ prod_functor.obj X ⋙ e.inverse) := adjunction.left_adjoint_of_nat_iso this.symm,
348+
haveI : is_left_adjoint (e.inverse ⋙ e.functor ⋙ prod_functor.obj X ⋙ e.inverse) := adjunction.left_adjoint_of_comp e.inverse _,
349+
have : (e.inverse ⋙ e.functor ⋙ prod_functor.obj X ⋙ e.inverse) ⋙ e.functor ≅ prod_functor.obj X,
350+
apply iso_whisker_right e.counit_iso (prod_functor.obj X ⋙ e.inverse ⋙ e.functor) ≪≫ _,
351+
change prod_functor.obj X ⋙ e.inverse ⋙ e.functor ≅ prod_functor.obj X,
352+
apply iso_whisker_left (prod_functor.obj X) e.counit_iso,
353+
apply adjunction.left_adjoint_of_nat_iso this,
354+
end } }
355+
356+
variables [cartesian_closed C] [cartesian_closed D]
357+
variables (F : C ⥤ D) [preserves_limits_of_shape (discrete walking_pair) F]
358+
359+
/--
360+
The exponential comparison map.
361+
`F` is a cartesian closed functor if this is an iso for all `A,B`.
362+
-/
363+
def exp_comparison (A B : C) :
364+
F.obj (A ⟹ B) ⟶ F.obj A ⟹ F.obj B :=
365+
curry (inv (prod_comparison F A _) ≫ F.map ((ev _).app _))
366+
367+
/-- The exponential comparison map is natural in its left argument. -/
368+
lemma exp_comparison_natural_left (A A' B : C) (f : A' ⟶ A) :
369+
exp_comparison F A B ≫ pre (F.obj B) (F.map f) = F.map (pre B f) ≫ exp_comparison F A' B :=
370+
begin
371+
rw [exp_comparison, exp_comparison, ← curry_natural_left, eq_curry_iff, uncurry_natural_left,
372+
pre, uncurry_curry, prod_map_map_assoc, curry_eq, prod_map_id_comp, assoc],
373+
erw [(ev _).naturality, ev_coev_assoc, ← F.map_id, ← prod_comparison_inv_natural_assoc,
374+
← F.map_id, ← prod_comparison_inv_natural_assoc, ← F.map_comp, ← F.map_comp, pre, curry_eq,
375+
prod_map_id_comp, assoc, (ev _).naturality, ev_coev_assoc], refl,
376+
end
377+
378+
/-- The exponential comparison map is natural in its right argument. -/
379+
lemma exp_comparison_natural_right (A B B' : C) (f : B ⟶ B') :
380+
exp_comparison F A B ≫ (exp (F.obj A)).map (F.map f) = F.map ((exp A).map f) ≫ exp_comparison F A B' :=
381+
by
382+
erw [exp_comparison, ← curry_natural_right, curry_eq_iff, exp_comparison, uncurry_natural_left,
383+
uncurry_curry, assoc, ← F.map_comp, ← (ev _).naturality, F.map_comp,
384+
prod_comparison_inv_natural_assoc, F.map_id]
385+
386+
-- TODO: If F has a left adjoint L, then F is cartesian closed if and only if
387+
-- L (B ⨯ F A) ⟶ L B ⨯ L F A ⟶ L B ⨯ A
388+
-- is an iso for all A ∈ D, B ∈ C.
389+
-- Corollary: If F has a left adjoint L which preserves finite products, F is cartesian closed iff
390+
-- F is full and faithful.
391+
392+
end functor
393+
394+
end category_theory

0 commit comments

Comments
 (0)