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

Commit c49e89d

Browse files
jcommelinjohoelzl
authored andcommitted
feat(category_theory/adjunction): definitions, basic proofs, and examples (#619)
1 parent 0e6c358 commit c49e89d

File tree

9 files changed

+583
-41
lines changed

9 files changed

+583
-41
lines changed

src/category_theory/adjunction.lean

Lines changed: 393 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,393 @@
1+
/-
2+
Copyright (c) 2019 Reid Barton. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Reid Barton, Johan Commelin
5+
-/
6+
7+
import category_theory.limits.preserves
8+
import category_theory.whiskering
9+
import category_theory.equivalence
10+
11+
namespace category_theory
12+
open category
13+
open category_theory.limits
14+
15+
universes v₁ v₂ v₃ u₁ u₂ u₃ -- declare the `v`'s first; see `category_theory.category` for an explanation
16+
17+
local attribute [elab_simple] whisker_left whisker_right
18+
19+
variables {C : Type u₁} [𝒞 : category.{v₁} C] {D : Type u₂} [𝒟 : category.{v₂} D]
20+
include 𝒞 𝒟
21+
22+
/--
23+
`adjunction F G` represents the data of an adjunction between two functors
24+
`F : C ⥤ D` and `G : D ⥤ C`. `F` is the left adjoint and `G` is the right adjoint.
25+
-/
26+
structure adjunction (F : C ⥤ D) (G : D ⥤ C) :=
27+
(hom_equiv : Π (X Y), (F.obj X ⟶ Y) ≃ (X ⟶ G.obj Y))
28+
(unit : functor.id C ⟶ F.comp G)
29+
(counit : G.comp F ⟶ functor.id D)
30+
(hom_equiv_unit' : Π {X Y f}, (hom_equiv X Y) f = (unit : _ ⟹ _).app X ≫ G.map f . obviously)
31+
(hom_equiv_counit' : Π {X Y g}, (hom_equiv X Y).symm g = F.map g ≫ counit.app Y . obviously)
32+
33+
namespace adjunction
34+
35+
restate_axiom hom_equiv_unit'
36+
restate_axiom hom_equiv_counit'
37+
attribute [simp, priority 1] hom_equiv_unit hom_equiv_counit
38+
39+
section
40+
41+
variables {F : C ⥤ D} {G : D ⥤ C} (adj : adjunction F G) {X' X : C} {Y Y' : D}
42+
43+
@[simp, priority 1] lemma hom_equiv_naturality_left_symm (f : X' ⟶ X) (g : X ⟶ G.obj Y) :
44+
(adj.hom_equiv X' Y).symm (f ≫ g) = F.map f ≫ (adj.hom_equiv X Y).symm g :=
45+
by rw [hom_equiv_counit, F.map_comp, assoc, adj.hom_equiv_counit.symm]
46+
47+
@[simp] lemma hom_equiv_naturality_left (f : X' ⟶ X) (g : F.obj X ⟶ Y) :
48+
(adj.hom_equiv X' Y) (F.map f ≫ g) = f ≫ (adj.hom_equiv X Y) g :=
49+
by rw [← equiv.eq_symm_apply]; simp [-hom_equiv_unit]
50+
51+
@[simp, priority 1] lemma hom_equiv_naturality_right (f : F.obj X ⟶ Y) (g : Y ⟶ Y') :
52+
(adj.hom_equiv X Y') (f ≫ g) = (adj.hom_equiv X Y) f ≫ G.map g :=
53+
by rw [hom_equiv_unit, G.map_comp, ← assoc, ←hom_equiv_unit]
54+
55+
@[simp] lemma hom_equiv_naturality_right_symm (f : X ⟶ G.obj Y) (g : Y ⟶ Y') :
56+
(adj.hom_equiv X Y').symm (f ≫ G.map g) = (adj.hom_equiv X Y).symm f ≫ g :=
57+
by rw [equiv.symm_apply_eq]; simp [-hom_equiv_counit]
58+
59+
@[simp] lemma left_triangle :
60+
(whisker_right adj.unit F).vcomp (whisker_left F adj.counit) = nat_trans.id _ :=
61+
begin
62+
ext1 X, dsimp,
63+
erw [← adj.hom_equiv_counit, equiv.symm_apply_eq, adj.hom_equiv_unit],
64+
simp
65+
end
66+
67+
@[simp] lemma right_triangle :
68+
(whisker_left G adj.unit).vcomp (whisker_right adj.counit G) = nat_trans.id _ :=
69+
begin
70+
ext1 Y, dsimp,
71+
erw [← adj.hom_equiv_unit, ← equiv.eq_symm_apply, adj.hom_equiv_counit],
72+
simp
73+
end
74+
75+
@[simp] lemma left_triangle_components :
76+
F.map (adj.unit.app X) ≫ adj.counit.app (F.obj X) = 𝟙 _ :=
77+
congr_arg (λ (t : _ ⟹ functor.id C ⋙ F), t.app X) adj.left_triangle
78+
79+
@[simp] lemma right_triangle_components {Y : D} :
80+
adj.unit.app (G.obj Y) ≫ G.map (adj.counit.app Y) = 𝟙 _ :=
81+
congr_arg (λ (t : _ ⟹ G ⋙ functor.id C), t.app Y) adj.right_triangle
82+
83+
end
84+
85+
structure core_hom_equiv (F : C ⥤ D) (G : D ⥤ C) :=
86+
(hom_equiv : Π (X Y), (F.obj X ⟶ Y) ≃ (X ⟶ G.obj Y))
87+
(hom_equiv_naturality_left_symm' : Π {X' X Y} (f : X' ⟶ X) (g : X ⟶ G.obj Y),
88+
(hom_equiv X' Y).symm (f ≫ g) = F.map f ≫ (hom_equiv X Y).symm g . obviously)
89+
(hom_equiv_naturality_right' : Π {X Y Y'} (f : F.obj X ⟶ Y) (g : Y ⟶ Y'),
90+
(hom_equiv X Y') (f ≫ g) = (hom_equiv X Y) f ≫ G.map g . obviously)
91+
92+
namespace core_hom_equiv
93+
94+
restate_axiom hom_equiv_naturality_left_symm'
95+
restate_axiom hom_equiv_naturality_right'
96+
attribute [simp, priority 1] hom_equiv_naturality_left_symm hom_equiv_naturality_right
97+
98+
variables {F : C ⥤ D} {G : D ⥤ C} (adj : core_hom_equiv F G) {X' X : C} {Y Y' : D}
99+
100+
@[simp] lemma hom_equiv_naturality_left (f : X' ⟶ X) (g : F.obj X ⟶ Y) :
101+
(adj.hom_equiv X' Y) (F.map f ≫ g) = f ≫ (adj.hom_equiv X Y) g :=
102+
by rw [← equiv.eq_symm_apply]; simp
103+
104+
@[simp] lemma hom_equiv_naturality_right_symm (f : X ⟶ G.obj Y) (g : Y ⟶ Y') :
105+
(adj.hom_equiv X Y').symm (f ≫ G.map g) = (adj.hom_equiv X Y).symm f ≫ g :=
106+
by rw [equiv.symm_apply_eq]; simp
107+
108+
end core_hom_equiv
109+
110+
structure core_unit_counit (F : C ⥤ D) (G : D ⥤ C) :=
111+
(unit : functor.id C ⟶ F.comp G)
112+
(counit : G.comp F ⟶ functor.id D)
113+
(left_triangle' : (whisker_right unit F).vcomp (whisker_left F counit) = nat_trans.id _ . obviously)
114+
(right_triangle' : (whisker_left G unit).vcomp (whisker_right counit G) = nat_trans.id _ . obviously)
115+
116+
namespace core_unit_counit
117+
118+
restate_axiom left_triangle'
119+
restate_axiom right_triangle'
120+
attribute [simp] left_triangle right_triangle
121+
122+
end core_unit_counit
123+
124+
variables (F : C ⥤ D) (G : D ⥤ C)
125+
126+
def mk_of_hom_equiv (adj : core_hom_equiv F G) : adjunction F G :=
127+
{ unit :=
128+
{ app := λ X, (adj.hom_equiv X (F.obj X)) (𝟙 (F.obj X)),
129+
naturality' :=
130+
begin
131+
intros,
132+
erw [← adj.hom_equiv_naturality_left, ← adj.hom_equiv_naturality_right],
133+
dsimp, simp
134+
end },
135+
counit :=
136+
{ app := λ Y, (adj.hom_equiv _ _).inv_fun (𝟙 (G.obj Y)),
137+
naturality' :=
138+
begin
139+
intros,
140+
erw [← adj.hom_equiv_naturality_left_symm, ← adj.hom_equiv_naturality_right_symm],
141+
dsimp, simp
142+
end },
143+
hom_equiv_unit' := λ X Y f, by erw [← adj.hom_equiv_naturality_right]; simp,
144+
hom_equiv_counit' := λ X Y f, by erw [← adj.hom_equiv_naturality_left_symm]; simp,
145+
.. adj }
146+
147+
def mk_of_unit_counit (adj : core_unit_counit F G) : adjunction F G :=
148+
{ hom_equiv := λ X Y,
149+
{ to_fun := λ f, adj.unit.app X ≫ G.map f,
150+
inv_fun := λ g, F.map g ≫ adj.counit.app Y,
151+
left_inv := λ f, begin
152+
change F.map (_ ≫ _) ≫ _ = _,
153+
rw [F.map_comp, assoc, ←functor.comp_map, adj.counit.naturality, ←assoc],
154+
convert id_comp _ f,
155+
exact congr_arg (λ t : _ ⟹ _, t.app _) adj.left_triangle
156+
end,
157+
right_inv := λ g, begin
158+
change _ ≫ G.map (_ ≫ _) = _,
159+
rw [G.map_comp, ←assoc, ←functor.comp_map, ←adj.unit.naturality, assoc],
160+
convert comp_id _ g,
161+
exact congr_arg (λ t : _ ⟹ _, t.app _) adj.right_triangle
162+
end },
163+
.. adj }
164+
165+
section
166+
omit 𝒟
167+
168+
def id : adjunction (functor.id C) (functor.id C) :=
169+
{ hom_equiv := λ X Y, equiv.refl _,
170+
unit := 𝟙 _,
171+
counit := 𝟙 _ }
172+
173+
end
174+
175+
/-
176+
TODO
177+
* define adjoint equivalences
178+
* show that every equivalence can be improved into an adjoint equivalence
179+
-/
180+
181+
section
182+
variables {E : Type u₃} [ℰ : category.{v₃} E] (H : D ⥤ E) (I : E ⥤ D)
183+
184+
def comp (adj₁ : adjunction F G) (adj₂ : adjunction H I) : adjunction (F ⋙ H) (I ⋙ G) :=
185+
{ hom_equiv := λ X Z, equiv.trans (adj₂.hom_equiv _ _) (adj₁.hom_equiv _ _),
186+
unit := adj₁.unit ≫
187+
(whisker_left F $ whisker_right adj₂.unit G) ≫ (functor.associator _ _ _).inv,
188+
counit := (functor.associator _ _ _).hom ≫
189+
(whisker_left I $ whisker_right adj₁.counit H) ≫ adj₂.counit }
190+
191+
end
192+
193+
structure is_left_adjoint (left : C ⥤ D) :=
194+
(right : D ⥤ C)
195+
(adj : adjunction left right)
196+
197+
structure is_right_adjoint (right : D ⥤ C) :=
198+
(left : C ⥤ D)
199+
(adj : adjunction left right)
200+
201+
section construct_left
202+
-- Construction of a left adjoint. In order to construct a left
203+
-- adjoint to a functor G : D → C, it suffices to give the object part
204+
-- of a functor F : C → D together with isomorphisms Hom(FX, Y) ≃
205+
-- Hom(X, GY) natural in Y. The action of F on morphisms can be
206+
-- constructed from this data.
207+
variables {F_obj : C → D} {G}
208+
variables (e : Π X Y, (F_obj X ⟶ Y) ≃ (X ⟶ G.obj Y))
209+
variables (he : Π X Y Y' g h, e X Y' (h ≫ g) = e X Y h ≫ G.map g)
210+
include he
211+
212+
private lemma he' {X Y Y'} (f g) : (e X Y').symm (f ≫ G.map g) = (e X Y).symm f ≫ g :=
213+
by intros; rw [equiv.symm_apply_eq, he]; simp
214+
215+
def left_adjoint_of_equiv : C ⥤ D :=
216+
{ obj := F_obj,
217+
map := λ X X' f, (e X (F_obj X')).symm (f ≫ e X' (F_obj X') (𝟙 _)),
218+
map_comp' := λ X X' X'' f f', begin
219+
rw [equiv.symm_apply_eq, he, equiv.apply_inverse_apply],
220+
conv { to_rhs, rw [assoc, ←he, id_comp, equiv.apply_inverse_apply] },
221+
simp
222+
end }
223+
224+
def adjunction_of_equiv_left : adjunction (left_adjoint_of_equiv e he) G :=
225+
mk_of_hom_equiv (left_adjoint_of_equiv e he) G
226+
{ hom_equiv := e,
227+
hom_equiv_naturality_left_symm' :=
228+
begin
229+
intros,
230+
erw [← he' e he, ← equiv.apply_eq_iff_eq],
231+
simp [(he _ _ _ _ _).symm]
232+
end }
233+
234+
end construct_left
235+
236+
section construct_right
237+
-- Construction of a right adjoint, analogous to the above.
238+
variables {F} {G_obj : D → C}
239+
variables (e : Π X Y, (F.obj X ⟶ Y) ≃ (X ⟶ G_obj Y))
240+
variables (he : Π X' X Y f g, e X' Y (F.map f ≫ g) = f ≫ e X Y g)
241+
include he
242+
243+
private lemma he' {X' X Y} (f g) : F.map f ≫ (e X Y).symm g = (e X' Y).symm (f ≫ g) :=
244+
by intros; rw [equiv.eq_symm_apply, he]; simp
245+
246+
def right_adjoint_of_equiv : D ⥤ C :=
247+
{ obj := G_obj,
248+
map := λ Y Y' g, (e (G_obj Y) Y') ((e (G_obj Y) Y).symm (𝟙 _) ≫ g),
249+
map_comp' := λ Y Y' Y'' g g', begin
250+
rw [← equiv.eq_symm_apply, ← he' e he, equiv.inverse_apply_apply],
251+
conv { to_rhs, rw [← assoc, he' e he, comp_id, equiv.inverse_apply_apply] },
252+
simp
253+
end }
254+
255+
def adjunction_of_equiv_right : adjunction F (right_adjoint_of_equiv e he) :=
256+
mk_of_hom_equiv F (right_adjoint_of_equiv e he)
257+
{ hom_equiv := e,
258+
hom_equiv_naturality_left_symm' := by intros; rw [equiv.symm_apply_eq, he]; simp,
259+
hom_equiv_naturality_right' :=
260+
begin
261+
intros X Y Y' g h,
262+
erw [←he, equiv.apply_eq_iff_eq, ←assoc, he' e he, comp_id, equiv.inverse_apply_apply]
263+
end }
264+
265+
end construct_right
266+
267+
end adjunction
268+
269+
end category_theory
270+
271+
namespace category_theory.adjunction
272+
open category_theory
273+
open category_theory.functor
274+
open category_theory.limits
275+
276+
universes u₁ u₂ v
277+
278+
variables {C : Type u₁} [𝒞 : category.{v} C] {D : Type u₂} [𝒟 : category.{v} D]
279+
include 𝒞 𝒟
280+
281+
variables {F : C ⥤ D} {G : D ⥤ C} (adj : adjunction F G)
282+
include adj
283+
284+
section preservation_colimits
285+
variables {J : Type v} [small_category J] (K : J ⥤ C)
286+
287+
def functoriality_is_left_adjoint :
288+
is_left_adjoint (@cocones.functoriality _ _ _ _ K _ _ F) :=
289+
{ right := (cocones.functoriality G) ⋙ (cocones.precompose
290+
(K.right_unitor.inv ≫ (whisker_left K adj.unit) ≫ (associator _ _ _).inv)),
291+
adj := mk_of_unit_counit _ _
292+
{ unit :=
293+
{ app := λ c,
294+
{ hom := adj.unit.app c.X,
295+
w' := λ j, by have := adj.unit.naturality (c.ι.app j); tidy },
296+
naturality' := λ _ _ f, by have := adj.unit.naturality (f.hom); tidy },
297+
counit :=
298+
{ app := λ c,
299+
{ hom := adj.counit.app c.X,
300+
w' :=
301+
begin
302+
intro j,
303+
dsimp,
304+
erw [category.comp_id, category.id_comp, F.map_comp, category.assoc,
305+
adj.counit.naturality (c.ι.app j), ← category.assoc,
306+
adj.left_triangle_components, category.id_comp],
307+
refl,
308+
end },
309+
naturality' := λ _ _ f, by have := adj.counit.naturality (f.hom); tidy } } }
310+
311+
/-- A left adjoint preserves colimits. -/
312+
def left_adjoint_preserves_colimits : preserves_colimits F :=
313+
λ J 𝒥 K, by resetI; exact
314+
{ preserves := λ c hc, is_colimit_iso_unique_cocone_morphism.inv
315+
(λ s, (((adj.functoriality_is_left_adjoint _).adj).hom_equiv _ _).unique_of_equiv $
316+
is_colimit_iso_unique_cocone_morphism.hom hc _ ) }
317+
318+
end preservation_colimits
319+
320+
section preservation_limits
321+
variables {J : Type v} [small_category J] (K : J ⥤ D)
322+
323+
def functoriality_is_right_adjoint :
324+
is_right_adjoint (@cones.functoriality _ _ _ _ K _ _ G) :=
325+
{ left := (cones.functoriality F) ⋙ (cones.postcompose
326+
((associator _ _ _).hom ≫ (whisker_left K adj.counit) ≫ K.right_unitor.hom)),
327+
adj := mk_of_unit_counit _ _
328+
{ unit :=
329+
{ app := λ c,
330+
{ hom := adj.unit.app c.X,
331+
w' :=
332+
begin
333+
intro j,
334+
dsimp,
335+
erw [category.comp_id, category.id_comp, G.map_comp, ← category.assoc,
336+
← adj.unit.naturality (c.π.app j), category.assoc,
337+
adj.right_triangle_components, category.comp_id],
338+
refl,
339+
end },
340+
naturality' := λ _ _ f, by have := adj.unit.naturality (f.hom); tidy },
341+
counit :=
342+
{ app := λ c,
343+
{ hom := adj.counit.app c.X,
344+
w' := λ j, by have := adj.counit.naturality (c.π.app j); tidy },
345+
naturality' := λ _ _ f, by have := adj.counit.naturality (f.hom); tidy } } }
346+
347+
/-- A right adjoint preserves limits. -/
348+
def right_adjoint_preserves_limits : preserves_limits G :=
349+
λ J 𝒥 K, by resetI; exact
350+
{ preserves := λ c hc, is_limit_iso_unique_cone_morphism.inv
351+
(λ s, (((adj.functoriality_is_right_adjoint _).adj).hom_equiv _ _).symm.unique_of_equiv $
352+
is_limit_iso_unique_cone_morphism.hom hc _) }
353+
354+
end preservation_limits
355+
356+
-- Note: this is natural in K, but we do not yet have the tools to formulate that.
357+
def cocones_iso {J : Type v} [small_category J] {K : J ⥤ C} :
358+
(cocones J D).obj (K ⋙ F) ≅ G ⋙ ((cocones J C).obj K) :=
359+
nat_iso.of_components (λ Y,
360+
{ hom := λ t,
361+
{ app := λ j, (adj.hom_equiv (K.obj j) Y) (t.app j),
362+
naturality' := λ j j' f, by erw [← adj.hom_equiv_naturality_left, t.naturality]; dsimp; simp },
363+
inv := λ t,
364+
{ app := λ j, (adj.hom_equiv (K.obj j) Y).symm (t.app j),
365+
naturality' := λ j j' f, begin
366+
erw [← adj.hom_equiv_naturality_left_symm, ← adj.hom_equiv_naturality_right_symm, t.naturality],
367+
dsimp, simp
368+
end } } )
369+
begin
370+
intros Y₁ Y₂ f,
371+
ext1 t,
372+
ext1 j,
373+
apply adj.hom_equiv_naturality_right
374+
end
375+
376+
-- Note: this is natural in K, but we do not yet have the tools to formulate that.
377+
def cones_iso {J : Type v} [small_category J] {K : J ⥤ D} :
378+
F.op ⋙ ((cones J D).obj K) ≅ (cones J C).obj (K ⋙ G) :=
379+
nat_iso.of_components (λ X,
380+
{ hom := λ t,
381+
{ app := λ j, (adj.hom_equiv X (K.obj j)) (t.app j),
382+
naturality' := λ j j' f, begin
383+
erw [← adj.hom_equiv_naturality_right, ← t.naturality, category.id_comp, category.id_comp],
384+
refl
385+
end },
386+
inv := λ t,
387+
{ app := λ j, (adj.hom_equiv X (K.obj j)).symm (t.app j),
388+
naturality' := λ j j' f, begin
389+
erw [← adj.hom_equiv_naturality_right_symm, ← t.naturality, category.id_comp, category.id_comp]
390+
end } } )
391+
(by tidy)
392+
393+
end category_theory.adjunction

0 commit comments

Comments
 (0)