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

Commit 60ba478

Browse files
committed
feat(algebra/category/Module): the category of R-modules is abelian (#3606)
1 parent fb883ea commit 60ba478

File tree

4 files changed

+211
-35
lines changed

4 files changed

+211
-35
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/-
2+
Copyright (c) 2020 Markus Himmel. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Markus Himmel
5+
-/
6+
import algebra.category.Module.kernels
7+
import algebra.category.Module.limits
8+
import category_theory.abelian.basic
9+
10+
/-!
11+
# The category of left R-modules is abelian.
12+
-/
13+
14+
open category_theory
15+
open category_theory.limits
16+
17+
noncomputable theory
18+
19+
universe u
20+
21+
namespace Module
22+
variables {R : Type u} [ring R] {M N : Module R} (f : M ⟶ N)
23+
24+
/-- In the category of modules, every monomorphism is normal. -/
25+
def normal_mono [mono f] : normal_mono f :=
26+
{ Z := of R f.range.quotient,
27+
g := f.range.mkq,
28+
w := linear_map.range_mkq_comp _,
29+
is_limit :=
30+
is_kernel.iso_kernel _ _ (kernel_is_limit _)
31+
/- The following [invalid Lean code](https://github.com/leanprover-community/lean/issues/341)
32+
might help you understand what's going on here:
33+
```
34+
calc
35+
M ≃ₗ[R] f.ker.quotient : (submodule.quot_equiv_of_eq_bot _ (ker_eq_bot_of_mono _)).symm
36+
... ≃ₗ[R] f.range : linear_map.quot_ker_equiv_range f
37+
... ≃ₗ[R] r.range.mkq.ker : linear_equiv.of_eq _ _ (submodule.ker_mkq _).symm
38+
```
39+
-/
40+
(linear_equiv.to_Module_iso'
41+
(linear_equiv.trans (submodule.quot_equiv_of_eq_bot _ (ker_eq_bot_of_mono _)).symm
42+
(linear_equiv.trans (linear_map.quot_ker_equiv_range f)
43+
(linear_equiv.of_eq _ _ (submodule.ker_mkq _).symm)))) $
44+
by { ext, refl } }
45+
46+
/-- In the category of modules, every epimorphism is normal. -/
47+
def normal_epi [epi f] : normal_epi f :=
48+
{ W := of R f.ker,
49+
g := f.ker.subtype,
50+
w := linear_map.comp_ker_subtype _,
51+
is_colimit :=
52+
is_cokernel.cokernel_iso _ _ (cokernel_is_colimit _)
53+
(linear_equiv.to_Module_iso'
54+
/- The following invalid Lean code might help you understand what's going on here:
55+
```
56+
calc f.ker.subtype.range.quotient
57+
≃ₗ[R] f.ker.quotient : submodule.quot_equiv_of_eq _ _ (submodule.range_subtype _)
58+
... ≃ₗ[R] f.range : linear_map.quot_ker_equiv_range f
59+
... ≃ₗ[R] N : linear_equiv.of_top _ (range_eq_top_of_epi _)
60+
```
61+
-/
62+
(linear_equiv.trans
63+
(linear_equiv.trans (submodule.quot_equiv_of_eq _ _ (submodule.range_subtype _))
64+
(linear_map.quot_ker_equiv_range f)) (linear_equiv.of_top _ (range_eq_top_of_epi _)))) $
65+
by { ext, refl } }
66+
67+
local attribute [instance] has_equalizers_of_has_finite_limits
68+
69+
/-- The category of R-modules is abelian. -/
70+
instance : abelian (Module R) :=
71+
{ has_finite_products := by apply_instance,
72+
has_kernels := by apply_instance,
73+
has_cokernels := has_cokernels_Module,
74+
normal_mono := λ X Y f m, by exactI normal_mono f,
75+
normal_epi := λ X Y f e, by exactI normal_epi f }
76+
77+
end Module

src/algebra/category/Module/basic.lean

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ end Module
8686
variables {R}
8787
variables {X₁ X₂ : Type u}
8888

89+
/-- Reinterpreting a linear map in the category of `R`-modules. -/
90+
def Module.as_hom [add_comm_group X₁] [module R X₁] [add_comm_group X₂] [module R X₂] :
91+
(X₁ →ₗ[R] X₂) → (Module.of R X₁ ⟶ Module.of R X₂) := id
92+
8993
/-- Build an isomorphism in the category `Module R` from a `linear_equiv` between `module`s. -/
9094
@[simps]
9195
def linear_equiv.to_Module_iso
@@ -96,6 +100,18 @@ def linear_equiv.to_Module_iso
96100
hom_inv_id' := begin ext, exact e.left_inv x, end,
97101
inv_hom_id' := begin ext, exact e.right_inv x, end, }
98102

103+
/--
104+
Build an isomorphism in the category `Module R` from a `linear_equiv` between `module`s.
105+
106+
This version is better than `linear_equiv_to_Module_iso` when applicable, because Lean can't see `Module.of R M` is defeq to `M` when `M : Module R`.
107+
-/
108+
@[simps]
109+
def linear_equiv.to_Module_iso' {M N : Module R} (i : M ≃ₗ[R] N) : M ≅ N :=
110+
{ hom := i,
111+
inv := i.symm,
112+
hom_inv_id' := linear_map.ext $ λ x, by simp,
113+
inv_hom_id' := linear_map.ext $ λ x, by simp }
114+
99115
namespace category_theory.iso
100116

101117
/-- Build a `linear_equiv` from an isomorphism in the category `Module R`. -/
@@ -129,41 +145,22 @@ instance : preadditive (Module R) :=
129145

130146
end preadditive
131147

132-
section kernel
133-
variables {R} {M N : Module R} (f : M ⟶ N)
134-
135-
/-- The cone on the equalizer diagram of f and 0 induced by the kernel of f -/
136-
def kernel_cone : cone (parallel_pair f 0) :=
137-
{ X := of R f.ker,
138-
π :=
139-
{ app := λ j,
140-
match j with
141-
| zero := f.ker.subtype
142-
| one := 0
143-
end,
144-
naturality' := λ j j' g, by { cases j; cases j'; cases g; tidy } } }
145-
146-
/-- The kernel of a linear map is a kernel in the categorical sense -/
147-
def kernel_is_limit : is_limit (kernel_cone f) :=
148-
{ lift := λ s, linear_map.cod_restrict f.ker (fork.ι s) (λ c, linear_map.mem_ker.2 $
149-
by { erw [←@function.comp_apply _ _ _ f (fork.ι s) c, ←coe_comp, fork.condition,
150-
has_zero_morphisms.comp_zero (fork.ι s) N], refl }),
151-
fac' := λ s j, linear_map.ext $ λ x,
152-
begin
153-
rw [coe_comp, function.comp_app, ←linear_map.comp_apply],
154-
cases j,
155-
{ erw @linear_map.subtype_comp_cod_restrict _ _ _ _ _ _ _ _ (fork.ι s) f.ker _ },
156-
{ rw [←fork.app_zero_left, ←fork.app_zero_left], refl }
157-
end,
158-
uniq' := λ s m h, linear_map.ext $ λ x, subtype.ext_iff_val.2 $
159-
have h₁ : (m ≫ (kernel_cone f).π.app zero).to_fun = (s.π.app zero).to_fun,
160-
by { congr, exact h zero },
161-
by convert @congr_fun _ _ _ _ h₁ x }
162-
163-
end kernel
164-
165-
instance : has_kernels (Module R) :=
166-
⟨λ _ _ f, ⟨kernel_cone f, kernel_is_limit f⟩⟩
148+
section epi_mono
149+
variables {M N : Module R} (f : M ⟶ N)
150+
151+
lemma ker_eq_bot_of_mono [mono f] : f.ker = ⊥ :=
152+
linear_map.ker_eq_bot_of_cancel $ λ u v, (@cancel_mono _ _ _ _ _ f _ (as_hom u) (as_hom v)).1
153+
154+
lemma range_eq_top_of_epi [epi f] : f.range = ⊤ :=
155+
linear_map.range_eq_top_of_cancel $ λ u v, (@cancel_epi _ _ _ _ _ f _ (as_hom u) (as_hom v)).1
156+
157+
lemma mono_of_ker_eq_bot (hf : f.ker = ⊥) : mono f :=
158+
concrete_category.mono_of_injective _ $ linear_map.ker_eq_bot.1 hf
159+
160+
lemma epi_of_range_eq_top (hf : f.range = ⊤) : epi f :=
161+
concrete_category.epi_of_surjective _ $ linear_map.range_eq_top.1 hf
162+
163+
end epi_mono
167164

168165
end Module
169166

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/-
2+
Copyright (c) 2020 Markus Himmel. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Markus Himmel
5+
-/
6+
import algebra.category.Module.basic
7+
8+
/-!
9+
# The concrete (co)kernels in the category of modules are (co)kernels in the categorical sense.
10+
-/
11+
12+
open category_theory
13+
open category_theory.limits
14+
open category_theory.limits.walking_parallel_pair
15+
16+
universe u
17+
18+
namespace Module
19+
variables {R : Type u} [ring R]
20+
21+
section
22+
variables {M N : Module R} (f : M ⟶ N)
23+
24+
/-- The kernel cone induced by the concrete kernel. -/
25+
def kernel_cone : kernel_fork f :=
26+
kernel_fork.of_ι (as_hom f.ker.subtype) $ by tidy
27+
28+
/-- The kernel of a linear map is a kernel in the categorical sense. -/
29+
def kernel_is_limit : is_limit (kernel_cone f) :=
30+
fork.is_limit.mk _
31+
(λ s, linear_map.cod_restrict f.ker (fork.ι s) (λ c, linear_map.mem_ker.2 $
32+
by { rw [←@function.comp_apply _ _ _ f (fork.ι s) c, ←coe_comp, fork.condition,
33+
has_zero_morphisms.comp_zero (fork.ι s) N], refl }))
34+
(λ s, linear_map.subtype_comp_cod_restrict _ _ _)
35+
(λ s m h, linear_map.ext $ λ x, subtype.ext_iff_val.2 $
36+
have h₁ : (m ≫ (kernel_cone f).π.app zero).to_fun = (s.π.app zero).to_fun,
37+
by { congr, exact h zero },
38+
by convert @congr_fun _ _ _ _ h₁ x )
39+
40+
/-- The cokernel cocone induced by the projection onto the quotient. -/
41+
def cokernel_cocone : cokernel_cofork f :=
42+
cokernel_cofork.of_π (as_hom f.range.mkq) $ linear_map.range_mkq_comp _
43+
44+
/-- The projection onto the quotient is a cokernel in the categorical sense. -/
45+
def cokernel_is_colimit : is_colimit (cokernel_cocone f) :=
46+
cofork.is_colimit.mk _
47+
(λ s, f.range.liftq (cofork.π s) $ linear_map.range_le_ker_iff.2 $ cokernel_cofork.condition s)
48+
(λ s, f.range.liftq_mkq (cofork.π s) _)
49+
(λ s m h,
50+
begin
51+
haveI : epi (as_hom f.range.mkq) := epi_of_range_eq_top _ (submodule.range_mkq _),
52+
apply (cancel_epi (as_hom f.range.mkq)).1,
53+
convert h walking_parallel_pair.one,
54+
exact submodule.liftq_mkq _ _ _
55+
end)
56+
end
57+
58+
/-- The category of R-modules has kernels, given by the inclusion of the kernel submodule. -/
59+
def has_kernels_Module : has_kernels (Module R) :=
60+
⟨λ X Y f, ⟨_, kernel_is_limit f⟩⟩
61+
62+
/-- The category or R-modules has cokernels, given by the projection onto the quotient. -/
63+
def has_cokernels_Module : has_cokernels (Module R) :=
64+
⟨λ X Y f, ⟨_, cokernel_is_colimit f⟩⟩
65+
66+
end Module

src/linear_algebra/basic.lean

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,9 @@ def ker (f : M →ₗ[R] M₂) : submodule R M := comap f ⊥
10831083

10841084
@[simp] theorem map_coe_ker (f : M →ₗ[R] M₂) (x : ker f) : f x = 0 := mem_ker.1 x.2
10851085

1086+
lemma comp_ker_subtype (f : M →ₗ[R] M₂) : f.comp f.ker.subtype = 0 :=
1087+
linear_map.ext $ λ x, suffices f x = 0, by simp [this], mem_ker.1 x.2
1088+
10861089
theorem ker_comp (f : M →ₗ[R] M₂) (g : M₂ →ₗ[R] M₃) : ker (g.comp f) = comap f (ker g) := rfl
10871090

10881091
theorem ker_le_ker_comp (f : M →ₗ[R] M₂) (g : M₂ →ₗ[R] M₃) : ker f ≤ ker (g.comp f) :=
@@ -1534,6 +1537,32 @@ end ring
15341537

15351538
end submodule
15361539

1540+
namespace linear_map
1541+
variables [ring R] [add_comm_group M] [add_comm_group M₂] [module R M] [module R M₂]
1542+
1543+
lemma range_mkq_comp (f : M →ₗ[R] M₂) : f.range.mkq.comp f = 0 :=
1544+
linear_map.ext $ λ x, by { simp, use x }
1545+
1546+
/-- A monomorphism is injective. -/
1547+
lemma ker_eq_bot_of_cancel {f : M →ₗ[R] M₂}
1548+
(h : ∀ (u v : f.ker →ₗ[R] M), f.comp u = f.comp v → u = v) : f.ker = ⊥ :=
1549+
begin
1550+
have h₁ : f.comp (0 : f.ker →ₗ[R] M) = 0 := comp_zero _,
1551+
rw [←submodule.range_subtype f.ker, ←h 0 f.ker.subtype (eq.trans h₁ (comp_ker_subtype f).symm)],
1552+
exact range_zero
1553+
end
1554+
1555+
/-- An epimorphism is surjective. -/
1556+
lemma range_eq_top_of_cancel {f : M →ₗ[R] M₂}
1557+
(h : ∀ (u v : M₂ →ₗ[R] f.range.quotient), u.comp f = v.comp f → u = v) : f.range = ⊤ :=
1558+
begin
1559+
have h₁ : (0 : M₂ →ₗ[R] f.range.quotient).comp f = 0 := zero_comp _,
1560+
rw [←submodule.ker_mkq f.range, ←h 0 f.range.mkq (eq.trans h₁ (range_mkq_comp _).symm)],
1561+
exact ker_zero
1562+
end
1563+
1564+
end linear_map
1565+
15371566
@[simp] lemma linear_map.range_range_restrict [semiring R] [add_comm_monoid M] [add_comm_monoid M₂]
15381567
[semimodule R M] [semimodule R M₂] (f : M →ₗ[R] M₂) :
15391568
f.range_restrict.range = ⊤ :=
@@ -1993,6 +2022,13 @@ linear_equiv.of_linear (p.liftq id $ hp.symm ▸ bot_le) p.mkq (liftq_mkq _ _ _)
19932022
@[simp] lemma coe_quot_equiv_of_eq_bot_symm (hp : p = ⊥) :
19942023
((p.quot_equiv_of_eq_bot hp).symm : M →ₗ[R] p.quotient) = p.mkq := rfl
19952024

2025+
variables (q : submodule R M)
2026+
2027+
/-- Quotienting by equal submodules gives linearly equivalent quotients. -/
2028+
def quot_equiv_of_eq (h : p = q) : p.quotient ≃ₗ[R] q.quotient :=
2029+
{ map_add' := by { rintros ⟨x⟩ ⟨y⟩, refl }, map_smul' := by { rintros x ⟨y⟩, refl },
2030+
..@quotient.congr _ _ (quotient_rel p) (quotient_rel q) (equiv.refl _) $ λ a b, by { subst h, refl } }
2031+
19962032
end submodule
19972033

19982034
namespace submodule

0 commit comments

Comments
 (0)