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

Commit 17296e9

Browse files
kim-emTwoFX
andcommitted
feat(category_theory/abelian): Schur's lemma (#2838)
I wrote this mostly to gain some familiarity with @TwoFX's work on abelian categories from #2817. That all looked great, and Schur's lemma was pleasantly straightforward. Co-authored-by: Markus Himmel <markus@himmel-villmar.de> Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
1 parent 2812cdc commit 17296e9

File tree

6 files changed

+274
-43
lines changed

6 files changed

+274
-43
lines changed

src/category_theory/limits/shapes/images.lean

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ begin
253253
... = 𝟙 (image f) ≫ h : by rw [←category.assoc, t]
254254
... = h : by rw [category.id_comp]
255255
end
256+
257+
lemma epi_of_epi_image {X Y : C} (f : X ⟶ Y) [has_image f]
258+
[epi (image.ι f)] [epi (factor_thru_image f)] : epi f :=
259+
by { rw [←image.fac f], apply epi_comp, }
260+
256261
end
257262

258263
section

src/category_theory/limits/shapes/kernels.lean

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,16 @@ open category_theory.limits.walking_parallel_pair
4747
namespace category_theory.limits
4848

4949
variables {C : Type u} [category.{v} C]
50+
variables [has_zero_morphisms.{v} C]
51+
52+
/-- A morphism `f` has a kernel if the functor `parallel_pair f 0` has a limit. -/
53+
abbreviation has_kernel {X Y : C} (f : X ⟶ Y) : Type (max u v) := has_limit (parallel_pair f 0)
54+
/-- A morphism `f` has a cokernel if the functor `parallel_pair f 0` has a colimit. -/
55+
abbreviation has_cokernel {X Y : C} (f : X ⟶ Y) : Type (max u v) := has_colimit (parallel_pair f 0)
5056

5157
variables {X Y : C} (f : X ⟶ Y)
5258

5359
section
54-
variables [has_zero_morphisms.{v} C]
5560

5661
/-- A kernel fork is just a fork where the second morphism is a zero morphism. -/
5762
abbreviation kernel_fork := fork f 0
@@ -77,7 +82,7 @@ def kernel_fork.is_limit.lift' {s : kernel_fork f} (hs : is_limit s) {W : C} (k
7782
end
7883

7984
section
80-
variables [has_zero_morphisms.{v} C] [has_limit (parallel_pair f 0)]
85+
variables [has_kernel f]
8186

8287
/-- The kernel of a morphism, expressed as the equalizer with the 0 morphism. -/
8388
abbreviation kernel : C := equalizer f 0
@@ -103,17 +108,27 @@ def kernel.lift' {W : C} (k : W ⟶ X) (h : k ≫ f = 0) : {l : W ⟶ kernel f /
103108
⟨kernel.lift f k h, kernel.lift_ι _ _ _⟩
104109

105110
/-- Every kernel of the zero morphism is an isomorphism -/
106-
def kernel.ι_zero_is_iso [has_limit (parallel_pair (0 : X ⟶ Y) 0)] :
111+
def kernel.ι_zero_is_iso [has_kernel (0 : X ⟶ Y)] :
107112
is_iso (kernel.ι (0 : X ⟶ Y)) :=
108113
equalizer.ι_of_self _
109114

115+
lemma eq_zero_of_epi_kernel [epi (kernel.ι f)] : f = 0 :=
116+
(cancel_epi (kernel.ι f)).1 (by simp)
117+
118+
variables {f}
119+
120+
lemma kernel_not_epi_of_nonzero (w : f ≠ 0) : ¬epi (kernel.ι f) :=
121+
λ I, by exactI w (eq_zero_of_epi_kernel f)
122+
123+
lemma kernel_not_iso_of_nonzero (w : f ≠ 0) : (is_iso (kernel.ι f)) → false :=
124+
λ I, kernel_not_epi_of_nonzero w $ by { resetI, apply_instance }
125+
110126
end
111127

112128
section has_zero_object
113129
variables [has_zero_object.{v} C]
114130

115131
local attribute [instance] has_zero_object.has_zero
116-
variables [has_zero_morphisms.{v} C]
117132

118133
/-- The morphism from the zero object determines a cone on a kernel diagram -/
119134
def kernel.zero_cone : cone (parallel_pair f 0) :=
@@ -129,19 +144,18 @@ fork.is_limit.mk _ (λ s, 0)
129144
(λ _ _ _, has_zero_object.zero_of_to_zero _)
130145

131146
/-- The kernel of a monomorphism is isomorphic to the zero object -/
132-
def kernel.of_mono [has_limit (parallel_pair f 0)] [mono f] : kernel f ≅ 0 :=
147+
def kernel.of_mono [has_kernel f] [mono f] : kernel f ≅ 0 :=
133148
functor.map_iso (cones.forget _) $ is_limit.unique_up_to_iso
134149
(limit.is_limit (parallel_pair f 0)) (kernel.is_limit_cone_zero_cone f)
135150

136151
/-- The kernel morphism of a monomorphism is a zero morphism -/
137-
lemma kernel.ι_of_mono [has_limit (parallel_pair f 0)] [mono f] : kernel.ι f = 0 :=
152+
lemma kernel.ι_of_mono [has_kernel f] [mono f] : kernel.ι f = 0 :=
138153
by rw [←category.id_comp (kernel.ι f), ←iso.hom_inv_id (kernel.of_mono f), category.assoc,
139154
has_zero_object.zero_of_to_zero (kernel.of_mono f).hom, has_zero_morphisms.zero_comp]
140155

141156
end has_zero_object
142157

143158
section transport
144-
variables [has_zero_morphisms.{v} C]
145159

146160
/-- If `i` is an isomorphism such that `l ≫ i.hom = f`, then any kernel of `f` is a kernel of `l`.-/
147161
def is_kernel.of_comp_iso {Z : C} (l : X ⟶ Z) (i : Z ≅ Y) (h : l ≫ i.hom = f)
@@ -153,7 +167,7 @@ fork.is_limit.mk _
153167
(λ s m h, by { apply fork.is_limit.hom_ext hs, simpa using h walking_parallel_pair.zero })
154168

155169
/-- If `i` is an isomorphism such that `l ≫ i.hom = f`, then the kernel of `f` is a kernel of `l`.-/
156-
def kernel.of_comp_iso [has_limit (parallel_pair f 0)]
170+
def kernel.of_comp_iso [has_kernel f]
157171
{Z : C} (l : X ⟶ Z) (i : Z ≅ Y) (h : l ≫ i.hom = f) :
158172
is_limit (kernel_fork.of_ι (kernel.ι f) $
159173
show kernel.ι f ≫ l = 0, by simp [←i.comp_inv_eq.2 h.symm]) :=
@@ -168,24 +182,23 @@ is_limit.of_iso_limit hs $ cones.ext i.symm $ λ j,
168182
by { cases j, { exact (iso.eq_inv_comp i).2 h }, { simp } }
169183

170184
/-- If `i` is an isomorphism such that `i.hom ≫ kernel.ι f = l`, then `l` is a kernel of `f`. -/
171-
def kernel.iso_kernel [has_limit (parallel_pair f 0)]
185+
def kernel.iso_kernel [has_kernel f]
172186
{Z : C} (l : Z ⟶ X) (i : Z ≅ kernel f) (h : i.hom ≫ kernel.ι f = l) :
173187
is_limit (kernel_fork.of_ι l $ by simp [←h]) :=
174188
is_kernel.iso_kernel f l (limit.is_limit _) i h
175189

176190
end transport
177191

178192
section
179-
variables (X) (Y) [has_zero_morphisms.{v} C]
193+
variables (X Y)
180194

181195
/-- The kernel morphism of a zero morphism is an isomorphism -/
182-
def kernel.ι_of_zero [has_limit (parallel_pair (0 : X ⟶ Y) 0)] : is_iso (kernel.ι (0 : X ⟶ Y)) :=
196+
def kernel.ι_of_zero [has_kernel (0 : X ⟶ Y)] : is_iso (kernel.ι (0 : X ⟶ Y)) :=
183197
equalizer.ι_of_self _
184198

185199
end
186200

187201
section
188-
variables [has_zero_morphisms.{v} C]
189202

190203
/-- A cokernel cofork is just a cofork where the second morphism is a zero morphism. -/
191204
abbreviation cokernel_cofork := cofork f 0
@@ -211,7 +224,7 @@ def cokernel_cofork.is_colimit.desc' {s : cokernel_cofork f} (hs : is_colimit s)
211224
end
212225

213226
section
214-
variables [has_zero_morphisms.{v} C] [has_colimit (parallel_pair f 0)]
227+
variables [has_cokernel f]
215228

216229
/-- The cokernel of a morphism, expressed as the coequalizer with the 0 morphism. -/
217230
abbreviation cokernel : C := coequalizer f 0
@@ -238,15 +251,29 @@ def cokernel.desc' {W : C} (k : Y ⟶ W) (h : f ≫ k = 0) :
238251
{l : cokernel f ⟶ W // cokernel.π f ≫ l = k} :=
239252
⟨cokernel.desc f k h, cokernel.π_desc _ _ _⟩
240253

254+
/-- The cokernel of the zero morphism is an isomorphism -/
255+
def cokernel.π_zero_is_iso [has_colimit (parallel_pair (0 : X ⟶ Y) 0)] :
256+
is_iso (cokernel.π (0 : X ⟶ Y)) :=
257+
coequalizer.π_of_self _
258+
259+
lemma eq_zero_of_mono_cokernel [mono (cokernel.π f)] : f = 0 :=
260+
(cancel_mono (cokernel.π f)).1 (by simp)
261+
262+
variables {f}
263+
264+
lemma cokernel_not_mono_of_nonzero (w : f ≠ 0) : ¬mono (cokernel.π f) :=
265+
λ I, by exactI w (eq_zero_of_mono_cokernel f)
266+
267+
lemma cokernel_not_iso_of_nonzero (w : f ≠ 0) : (is_iso (cokernel.π f)) → false :=
268+
λ I, cokernel_not_mono_of_nonzero w $ by { resetI, apply_instance }
269+
241270
end
242271

243272
section has_zero_object
244273
variables [has_zero_object.{v} C]
245274

246275
local attribute [instance] has_zero_object.has_zero
247276

248-
variable [has_zero_morphisms.{v} C]
249-
250277
/-- The morphism to the zero object determines a cocone on a cokernel diagram -/
251278
def cokernel.zero_cocone : cocone (parallel_pair f 0) :=
252279
{ X := 0,
@@ -261,22 +288,22 @@ cofork.is_colimit.mk _ (λ s, 0)
261288
(λ _ _ _, has_zero_object.zero_of_from_zero _)
262289

263290
/-- The cokernel of an epimorphism is isomorphic to the zero object -/
264-
def cokernel.of_epi [has_colimit (parallel_pair f 0)] [epi f] : cokernel f ≅ 0 :=
291+
def cokernel.of_epi [has_cokernel f] [epi f] : cokernel f ≅ 0 :=
265292
functor.map_iso (cocones.forget _) $ is_colimit.unique_up_to_iso
266293
(colimit.is_colimit (parallel_pair f 0)) (cokernel.is_colimit_cocone_zero_cocone f)
267294

268295
/-- The cokernel morphism if an epimorphism is a zero morphism -/
269-
lemma cokernel.π_of_epi [has_colimit (parallel_pair f 0)] [epi f] : cokernel.π f = 0 :=
296+
lemma cokernel.π_of_epi [has_cokernel f] [epi f] : cokernel.π f = 0 :=
270297
by rw [←category.comp_id (cokernel.π f), ←iso.hom_inv_id (cokernel.of_epi f), ←category.assoc,
271298
has_zero_object.zero_of_from_zero (cokernel.of_epi f).inv, has_zero_morphisms.comp_zero]
272299

273300
end has_zero_object
274301

275302
section
276-
variables (X) (Y) [has_zero_morphisms.{v} C]
303+
variables (X Y)
277304

278305
/-- The cokernel of a zero morphism is an isomorphism -/
279-
def cokernel.π_of_zero [has_colimit (parallel_pair (0 : X ⟶ Y) 0)] :
306+
def cokernel.π_of_zero [has_cokernel (0 : X ⟶ Y)] :
280307
is_iso (cokernel.π (0 : X ⟶ Y)) :=
281308
coequalizer.π_of_self _
282309

@@ -287,22 +314,20 @@ section has_zero_object
287314
variables [has_zero_object.{v} C]
288315

289316
local attribute [instance] has_zero_object.has_zero
290-
variables [has_zero_morphisms.{v} C]
291317

292318
/-- The kernel of the cokernel of an epimorphism is an isomorphism -/
293-
instance kernel.of_cokernel_of_epi [has_colimit (parallel_pair f 0)]
294-
[has_limit (parallel_pair (cokernel.π f) 0)] [epi f] : is_iso (kernel.ι (cokernel.π f)) :=
319+
instance kernel.of_cokernel_of_epi [has_cokernel f]
320+
[has_kernel (cokernel.π f)] [epi f] : is_iso (kernel.ι (cokernel.π f)) :=
295321
equalizer.ι_of_eq $ cokernel.π_of_epi f
296322

297323
/-- The cokernel of the kernel of a monomorphism is an isomorphism -/
298-
instance cokernel.of_kernel_of_mono [has_limit (parallel_pair f 0)]
299-
[has_colimit (parallel_pair (kernel.ι f) 0)] [mono f] : is_iso (cokernel.π (kernel.ι f)) :=
324+
instance cokernel.of_kernel_of_mono [has_kernel f]
325+
[has_cokernel (kernel.ι f)] [mono f] : is_iso (cokernel.π (kernel.ι f)) :=
300326
coequalizer.π_of_eq $ kernel.ι_of_mono f
301327

302328
end has_zero_object
303329

304330
section transport
305-
variables [has_zero_morphisms.{v} C]
306331

307332
/-- If `i` is an isomorphism such that `i.hom ≫ l = f`, then any cokernel of `f` is a cokernel of
308333
`l`. -/
@@ -316,7 +341,7 @@ cofork.is_colimit.mk _
316341

317342
/-- If `i` is an isomorphism such that `i.hom ≫ l = f`, then the cokernel of `f` is a cokernel of
318343
`l`. -/
319-
def cokernel.of_iso_comp [has_colimit (parallel_pair f 0)]
344+
def cokernel.of_iso_comp [has_cokernel f]
320345
{Z : C} (l : Z ⟶ Y) (i : X ≅ Z) (h : i.hom ≫ l = f) :
321346
is_colimit (cokernel_cofork.of_π (cokernel.π f) $
322347
show l ≫ cokernel.π f = 0, by simp [i.eq_inv_comp.2 h]) :=
@@ -330,28 +355,29 @@ def is_cokernel.cokernel_iso {Z : C} (l : Y ⟶ Z) {s : cokernel_cofork f} (hs :
330355
is_colimit.of_iso_colimit hs $ cocones.ext i $ λ j, by { cases j, { simp }, { exact h } }
331356

332357
/-- If `i` is an isomorphism such that `cokernel.π f ≫ i.hom = l`, then `l` is a cokernel of `f`. -/
333-
def cokernel.cokernel_iso [has_colimit (parallel_pair f 0)]
358+
def cokernel.cokernel_iso [has_cokernel f]
334359
{Z : C} (l : Y ⟶ Z) (i : cokernel f ≅ Z) (h : cokernel.π f ≫ i.hom = l) :
335360
is_colimit (cokernel_cofork.of_π l $ by simp [←h]) :=
336361
is_cokernel.cokernel_iso f l (colimit.is_colimit _) i h
337362

338363
end transport
339364

340365
end category_theory.limits
366+
341367
namespace category_theory.limits
342368
variables (C : Type u) [category.{v} C]
343369

344370
variables [has_zero_morphisms.{v} C]
345371

346372
/-- `has_kernels` represents a choice of kernel for every morphism -/
347373
class has_kernels :=
348-
(has_limit : Π {X Y : C} (f : X ⟶ Y), has_limit (parallel_pair f 0))
374+
(has_limit : Π {X Y : C} (f : X ⟶ Y), has_kernel f)
349375

350376
/-- `has_cokernels` represents a choice of cokernel for every morphism -/
351377
class has_cokernels :=
352-
(has_colimit : Π {X Y : C} (f : X ⟶ Y), has_colimit (parallel_pair f 0))
378+
(has_colimit : Π {X Y : C} (f : X ⟶ Y), has_cokernel f)
353379

354-
attribute [instance] has_kernels.has_limit has_cokernels.has_colimit
380+
attribute [instance, priority 100] has_kernels.has_limit has_cokernels.has_colimit
355381

356382
/-- Kernels are finite limits, so if `C` has all finite limits, it also has all kernels -/
357383
def has_kernels_of_has_finite_limits [has_finite_limits.{v} C] : has_kernels.{v} C :=

src/category_theory/limits/shapes/zero.lean

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Scott Morrison
55
-/
66
import category_theory.limits.shapes.binary_products
7+
import category_theory.limits.shapes.images
78
import category_theory.epi_mono
89
import category_theory.punit
910

@@ -97,6 +98,11 @@ by { rw [←zero_comp.{v} X g, cancel_mono] at h, exact h }
9798
lemma zero_of_epi_comp {X Y Z : C} (f : X ⟶ Y) {g : Y ⟶ Z} [epi f] (h : f ≫ g = 0) : g = 0 :=
9899
by { rw [←comp_zero.{v} f Z, cancel_epi] at h, exact h }
99100

101+
lemma eq_zero_of_image_eq_zero {X Y : C} {f : X ⟶ Y} [has_image f] (w : image.ι f = 0) : f = 0 :=
102+
by rw [←image.fac f, w, has_zero_morphisms.comp_zero]
103+
104+
lemma nonzero_image_of_nonzero {X Y : C} {f : X ⟶ Y} [has_image f] (w : f ≠ 0) : image.ι f ≠ 0 :=
105+
λ h, w (eq_zero_of_image_eq_zero h)
100106
end
101107

102108
section
@@ -145,6 +151,20 @@ protected def has_zero : has_zero C :=
145151
local attribute [instance] has_zero_object.has_zero
146152
local attribute [instance] has_zero_object.unique_to has_zero_object.unique_from
147153

154+
@[ext]
155+
lemma to_zero_ext {X : C} (f g : X ⟶ 0) : f = g :=
156+
by rw [(has_zero_object.unique_from.{v} X).uniq f, (has_zero_object.unique_from.{v} X).uniq g]
157+
158+
@[ext]
159+
lemma from_zero_ext {X : C} (f g : 0 ⟶ X) : f = g :=
160+
by rw [(has_zero_object.unique_to.{v} X).uniq f, (has_zero_object.unique_to.{v} X).uniq g]
161+
162+
instance {X : C} (f : 0 ⟶ X) : mono f :=
163+
{ right_cancellation := λ Z g h w, by ext, }
164+
165+
instance {X : C} (f : X ⟶ 0) : epi f :=
166+
{ left_cancellation := λ Z g h w, by ext, }
167+
148168
/-- A category with a zero object has zero morphisms.
149169
150170
It is rarely a good idea to use this. Many categories that have a zero object have zero
@@ -163,20 +183,13 @@ section
163183
variable [has_zero_morphisms.{v} C]
164184

165185
/-- An arrow ending in the zero object is zero -/
166-
@[ext]
186+
-- This can't be a `simp` lemma because the left hand side would be a metavariable.
167187
lemma zero_of_to_zero {X : C} (f : X ⟶ 0) : f = 0 :=
168-
begin
169-
rw (has_zero_object.unique_from.{v} X).uniq f,
170-
rw (has_zero_object.unique_from.{v} X).uniq (0 : X ⟶ 0)
171-
end
188+
by ext
172189

173190
/-- An arrow starting at the zero object is zero -/
174-
@[ext]
175191
lemma zero_of_from_zero {X : C} (f : 0 ⟶ X) : f = 0 :=
176-
begin
177-
rw (has_zero_object.unique_to.{v} X).uniq f,
178-
rw (has_zero_object.unique_to.{v} X).uniq (0 : 0 ⟶ X)
179-
end
192+
by ext
180193

181194
end
182195

src/category_theory/preadditive.lean

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ mk' (λ f, f ≫ g) $ λ f f', by simp
8383
(f - f') ≫ g = f ≫ g - f' ≫ g :=
8484
map_sub (right_comp P g) f f'
8585

86-
/- The redundant simp lemma linter says that simp can prove the reassoc version of this lemma. -/
86+
-- The redundant simp lemma linter says that simp can prove the reassoc version of this lemma.
8787
@[reassoc, simp] lemma comp_sub {P Q R : C} (f : P ⟶ Q) (g g' : Q ⟶ R) :
8888
f ≫ (g - g') = f ≫ g - f ≫ g' :=
8989
map_sub (left_comp R f) g g'
@@ -118,6 +118,10 @@ lemma mono_iff_cancel_zero {Q R : C} (f : Q ⟶ R) :
118118
mono f ↔ ∀ (P : C) (g : P ⟶ Q), g ≫ f = 0 → g = 0 :=
119119
⟨λ m P g, by exactI zero_of_comp_mono _, mono_of_cancel_zero f⟩
120120

121+
lemma mono_of_kernel_zero {X Y : C} {f : X ⟶ Y} [has_limit (parallel_pair f 0)]
122+
(w : kernel.ι f = 0) : mono f :=
123+
mono_of_cancel_zero f (λ P g h, by rw [←kernel.lift_ι f g h, w, has_zero_morphisms.comp_zero])
124+
121125
lemma epi_of_cancel_zero {P Q : C} (f : P ⟶ Q) (h : ∀ {R : C} (g : Q ⟶ R), f ≫ g = 0 → g = 0) :
122126
epi f :=
123127
⟨λ R g g' hg, sub_eq_zero.1 $ h _ $ (map_sub (left_comp R f) g g').trans $ sub_eq_zero.2 hg⟩
@@ -126,6 +130,10 @@ lemma epi_iff_cancel_zero {P Q : C} (f : P ⟶ Q) :
126130
epi f ↔ ∀ (R : C) (g : Q ⟶ R), f ≫ g = 0 → g = 0 :=
127131
⟨λ e R g, by exactI zero_of_epi_comp _, epi_of_cancel_zero f⟩
128132

133+
lemma epi_of_cokernel_zero {X Y : C} (f : X ⟶ Y) [has_colimit (parallel_pair f 0 )]
134+
(w : cokernel.π f = 0) : epi f :=
135+
epi_of_cancel_zero f (λ P g h, by rw [←cokernel.π_desc f g h, w, has_zero_morphisms.zero_comp])
136+
129137
end preadditive
130138

131139
section equalizers
@@ -135,7 +143,7 @@ section
135143
variables {X Y : C} (f : X ⟶ Y) (g : X ⟶ Y)
136144

137145
/-- A kernel of `f - g` is an equalizer of `f` and `g`. -/
138-
def has_limit_parallel_pair [has_limit (parallel_pair (f - g) 0)] :
146+
def has_limit_parallel_pair [has_kernel (f - g)] :
139147
has_limit (parallel_pair f g) :=
140148
{ cone := fork.of_ι (kernel.ι (f - g)) (sub_eq_zero.1 $
141149
by { rw ←comp_sub, exact kernel.condition _ }),
@@ -159,7 +167,7 @@ section
159167
variables {X Y : C} (f : X ⟶ Y) (g : X ⟶ Y)
160168

161169
/-- A cokernel of `f - g` is a coequalizer of `f` and `g`. -/
162-
def has_colimit_parallel_pair [has_colimit (parallel_pair (f - g) 0)] :
170+
def has_colimit_parallel_pair [has_cokernel (f - g)] :
163171
has_colimit (parallel_pair f g) :=
164172
{ cocone := cofork.of_π (cokernel.π (f - g)) (sub_eq_zero.1 $
165173
by { rw ←sub_comp, exact cokernel.condition _ }),

0 commit comments

Comments
 (0)