summaryrefslogtreecommitdiff
path: root/abgroup.v
diff options
context:
space:
mode:
authoritamar <itbaf@proton.me>2026-03-09 22:39:37 +0200
committeritamar <itbaf@proton.me>2026-03-09 22:39:37 +0200
commit9f5c228d068d5da86db5fb1532ea3ca1b9c11c41 (patch)
treeef23f95caa80a4503b00cd9db9c8735975e1a413 /abgroup.v
push pushHEADmaster
Diffstat (limited to 'abgroup.v')
-rw-r--r--abgroup.v719
1 files changed, 719 insertions, 0 deletions
diff --git a/abgroup.v b/abgroup.v
new file mode 100644
index 0000000..8825e33
--- /dev/null
+++ b/abgroup.v
@@ -0,0 +1,719 @@
+(* Abelian groups and Homomorphisms *)
+
+Require Import Utf8.
+Require Import Setoid Morphisms.
+
+Reserved Notation "x '∈' S" (at level 60).
+Reserved Notation "x '≡' y" (at level 70).
+
+(* Abelian Groups.
+
+ Notes:
+
+ -sets in groups are predicates (naive theory of sets); a value of type
+ gr_set is not necessarily in the group set. To be in the group set, it
+ must satisfy the predicate gr_mem, which is later syntaxified by the
+ usual symbol ∈. This allows to create subgroups by changing gr_mem.
+
+ -group sets are setoids: there is a specific equality (gr_eq) which is
+ compatible with membership (gr_mem_compat), addition (gr_add_compat),
+ and opposite (gr_opp_compat). This allows to define quotient groups,
+ for example in cokernets, by changing this equality.
+*)
+
+Record AbGroup :=
+ { (* data *)
+ gr_set : Type;
+ gr_mem : gr_set → Prop where "x ∈ G" := (gr_mem x);
+ gr_eq : gr_set → gr_set → Prop where "x ≡ y" := (gr_eq x y);
+ gr_zero : gr_set where "0" := (gr_zero);
+ gr_add : gr_set → gr_set → gr_set where "x + y" := (gr_add x y);
+ gr_opp : gr_set → gr_set where "- x" := (gr_opp x);
+ (* properties *)
+ gr_zero_mem : 0 ∈ G;
+ gr_add_mem : ∀ x y, x ∈ G → y ∈ G → x + y ∈ G;
+ gr_add_0_l : ∀ x, 0 + x ≡ x;
+ gr_add_assoc : ∀ x y z, (x + y) + z ≡ x + (y + z);
+ gr_opp_mem : ∀ x, x ∈ G → - x ∈ G;
+ gr_add_opp_r : ∀ x, x + (- x) ≡ 0;
+ gr_add_comm : ∀ x y, x + y ≡ y + x;
+ gr_equiv : Equivalence gr_eq;
+ gr_mem_compat : ∀ x y, x ≡ y → x ∈ G → y ∈ G;
+ gr_add_compat : ∀ x y x' y', x ≡ y → x' ≡ y' → x + x' ≡ y + y';
+ gr_opp_compat : ∀ x y, x ≡ y → - x ≡ - y }.
+
+(* coq stuff: implicit and renamed arguments *)
+
+Arguments gr_eq [_].
+Arguments gr_zero [_].
+Arguments gr_add [_].
+Arguments gr_opp [_].
+Arguments gr_zero_mem G : rename.
+Arguments gr_add_mem G : rename.
+Arguments gr_add_0_l G : rename.
+Arguments gr_add_assoc G : rename.
+Arguments gr_opp_mem G : rename.
+Arguments gr_add_opp_r G : rename.
+Arguments gr_add_comm G : rename.
+Arguments gr_equiv G : rename.
+Arguments gr_mem_compat G : rename.
+Arguments gr_add_compat G : rename.
+Arguments gr_opp_compat G : rename.
+
+(* syntaxes for expressions for groups elements and sets *)
+
+Delimit Scope group_scope with G.
+
+Notation "0" := (gr_zero) : group_scope.
+Notation "a = b" := (gr_eq a b) : group_scope.
+Notation "a ≠ b" := (¬ gr_eq a b) : group_scope.
+Notation "a + b" := (gr_add a b) : group_scope.
+Notation "a - b" := (gr_add a (gr_opp b)) : group_scope.
+Notation "- a" := (gr_opp a) : group_scope.
+
+Notation "x '∈' S" := (gr_mem S x) (at level 60).
+Notation "x '∉' S" := (¬ gr_mem S x) (at level 60).
+
+Open Scope group_scope.
+
+(* Homomorphism between groups *)
+
+Record HomGr (A B : AbGroup) :=
+ { Happ : gr_set A → gr_set B;
+ Hmem_compat : ∀ x, x ∈ A → Happ x ∈ B;
+ Happ_compat : ∀ x y, x ∈ A → (x = y)%G → (Happ x = Happ y)%G;
+ Hadditive : ∀ x y,
+ x ∈ A → y ∈ A → (Happ (x + y) = Happ x + Happ y)%G }.
+
+(* coq stuff: implicit and renamed arguments *)
+
+Arguments Happ [A] [B].
+Arguments Hmem_compat _ _ f : rename.
+Arguments Happ_compat _ _ f : rename.
+Arguments Hadditive _ _ f : rename.
+
+(* Equality (gr_eq) of groups elements is an equivalence relation *)
+
+Instance gr_eq_rel {G} : Equivalence (@gr_eq G).
+Proof. apply gr_equiv. Qed.
+
+(* Coq "Morphisms": they allow to use "rewrite" in expressions containing
+ opposites (-), additions (+) and memberships (∈) *)
+
+Instance gr_opp_morph {G} : Proper (@gr_eq G ==> @gr_eq G) (@gr_opp G).
+Proof.
+intros x y Hxy.
+now apply gr_opp_compat.
+Qed.
+
+Instance gr_add_morph {G} :
+ Proper (@gr_eq G ==> @gr_eq G ==> @gr_eq G) (@gr_add G).
+Proof.
+intros x y Hxy x' y' Hxy'.
+now apply gr_add_compat.
+Qed.
+
+Instance gr_mem_morph {G} : Proper (@gr_eq G ==> iff) (@gr_mem G).
+Proof.
+intros x y Hxy.
+split; intros H.
+-eapply gr_mem_compat; [ apply Hxy | easy ].
+-eapply gr_mem_compat; [ symmetry; apply Hxy | easy ].
+Qed.
+
+(*
+Instance gr_app_morph {G H f} : Proper (@gr_eq G ==> @gr_eq H) (Happ f).
+Proof.
+intros x y Hxy.
+apply Happ_compat; [ | easy ].
+...
+blocked: we have to prove x ∈ G but it is not possible to
+have this hypothesis in Proper
+*)
+
+(* Miscellaneous theorems in groups *)
+
+Theorem gr_add_0_r : ∀ G (x : gr_set G), (x + 0 = x)%G.
+Proof.
+intros.
+rewrite gr_add_comm.
+apply gr_add_0_l.
+Qed.
+
+Theorem gr_add_opp_l : ∀ G (x : gr_set G), (- x + x = 0)%G.
+Proof.
+intros.
+rewrite gr_add_comm.
+apply gr_add_opp_r.
+Qed.
+
+Theorem gr_opp_zero : ∀ G, (- 0 = @gr_zero G)%G.
+Proof.
+intros.
+rewrite <- gr_add_0_l.
+apply gr_add_opp_r.
+Qed.
+
+Theorem gr_sub_0_r : ∀ G (x : gr_set G), (x - 0 = x)%G.
+Proof.
+intros.
+symmetry; rewrite <- gr_add_0_r at 1.
+apply gr_add_compat; [ easy | now rewrite gr_opp_zero ].
+Qed.
+
+Theorem gr_sub_move_r : ∀ G (x y z : gr_set G),
+ (x - y = z)%G ↔ (x = z + y)%G.
+Proof.
+intros.
+split; intros Hxyz.
+-now rewrite <- Hxyz, gr_add_assoc, gr_add_opp_l, gr_add_0_r.
+-now rewrite Hxyz, gr_add_assoc, gr_add_opp_r, gr_add_0_r.
+Qed.
+
+Theorem gr_sub_move_l : ∀ G (x y z : gr_set G),
+ (x - y = z)%G ↔ (x = y + z)%G.
+Proof.
+intros.
+split; intros Hxyz.
+-now rewrite <- Hxyz, gr_add_comm, gr_add_assoc, gr_add_opp_l, gr_add_0_r.
+-now rewrite Hxyz, gr_add_comm, <- gr_add_assoc, gr_add_opp_l, gr_add_0_l.
+Qed.
+
+Theorem gr_opp_add_distr : ∀ G (x y : gr_set G), (- (x + y) = - x - y)%G.
+Proof.
+intros *.
+symmetry.
+apply gr_sub_move_r.
+rewrite <- gr_add_0_l.
+apply gr_sub_move_r.
+symmetry; rewrite gr_add_assoc.
+symmetry.
+apply gr_sub_move_r.
+rewrite gr_add_0_l.
+apply gr_opp_compat, gr_add_comm.
+Qed.
+
+Theorem gr_opp_involutive : ∀ G (x : gr_set G), (- - x = x)%G.
+Proof.
+intros.
+transitivity (- - x + (- x + x))%G.
+-rewrite <- gr_add_0_r at 1.
+ apply gr_add_compat; [ easy | ].
+ now rewrite gr_add_opp_l.
+-now rewrite <- gr_add_assoc, gr_add_opp_l, gr_add_0_l.
+Qed.
+
+Theorem gr_eq_opp_l : ∀ G (x y : gr_set G), (- x = y)%G ↔ (x = - y)%G.
+Proof.
+intros.
+split; intros Hxy.
+-rewrite <- Hxy; symmetry; apply gr_opp_involutive.
+-rewrite Hxy; apply gr_opp_involutive.
+Qed.
+
+(* Theorems on homomorphisms *)
+
+Theorem Hzero : ∀ A B (f : HomGr A B), (Happ f 0 = 0)%G.
+Proof.
+intros.
+assert (H1 : (@gr_zero A + 0 = 0)%G) by apply A.
+assert (H2 : (Happ f 0 + Happ f 0 = Happ f 0)%G). {
+ rewrite <- Hadditive; [ | apply A | apply A ].
+ apply f; [ apply A; apply A | apply A ].
+}
+assert (H3 : (Happ f 0 + Happ f 0 - Happ f 0 = Happ f 0 - Happ f 0)%G). {
+ apply gr_add_compat; [ apply H2 | easy ].
+}
+assert (H4 : (Happ f 0 + Happ f 0 - Happ f 0 = 0)%G). {
+ rewrite H3; apply gr_add_opp_r.
+}
+rewrite <- H4.
+now rewrite gr_add_assoc, gr_add_opp_r, gr_add_0_r.
+Qed.
+
+Theorem Hopp : ∀ A B (f : HomGr A B) x,
+ x ∈ A → (Happ f (- x) = - Happ f x)%G.
+Proof.
+intros * Hx.
+assert (H2 : (Happ f (x - x) = Happ f 0)%G). {
+ apply Happ_compat; [ now apply A, A | apply A ].
+}
+assert (H3 : (Happ f x + Happ f (- x) = Happ f 0)%G). {
+ rewrite <- H2.
+ symmetry; apply Hadditive; [ easy | now apply A ].
+}
+assert (H4 : (Happ f x + Happ f (- x) = 0)%G). {
+ rewrite H3; apply Hzero.
+}
+symmetry; rewrite <- gr_add_0_l.
+apply gr_sub_move_l.
+now symmetry.
+Qed.
+
+(* Images *)
+
+Theorem Im_zero_mem {G H} : ∀ (f : HomGr G H),
+ ∃ a : gr_set G, a ∈ G ∧ (Happ f a = 0)%G.
+Proof.
+intros.
+exists 0%G.
+split; [ apply gr_zero_mem | apply Hzero ].
+Qed.
+
+Theorem Im_add_mem {G H} : ∀ f (x y : gr_set H),
+ (∃ a : gr_set G, a ∈ G ∧ (Happ f a = x)%G)
+ → (∃ a : gr_set G, a ∈ G ∧ (Happ f a = y)%G)
+ → ∃ a : gr_set G, a ∈ G ∧ (Happ f a = x + y)%G.
+Proof.
+intros f y y' (x & Hxg & Hx) (x' & Hx'g & Hx').
+exists (gr_add x x').
+split; [ now apply G | ].
+rewrite Hadditive; [ | easy | easy ].
+now apply gr_add_compat.
+Qed.
+
+Theorem Im_opp_mem {G H} : ∀ (f : HomGr G H) (x : gr_set H),
+ (∃ a : gr_set G, a ∈ G ∧ (Happ f a = x)%G)
+ → ∃ a : gr_set G, a ∈ G ∧ (Happ f a = - x)%G.
+Proof.
+intros f x (y & Hy & Hyx).
+exists (gr_opp y).
+split; [ now apply gr_opp_mem | ].
+rewrite <- Hyx.
+now apply Hopp.
+Qed.
+
+Theorem Im_mem_compat {G H} : ∀ f (x y : gr_set H),
+ (x = y)%G
+ → (∃ a, a ∈ G ∧ (Happ f a = x)%G)
+ → ∃ a, a ∈ G ∧ (Happ f a = y)%G.
+intros * Hxy (z & Hz & Hfz).
+exists z.
+split; [ easy | now rewrite Hfz ].
+Qed.
+
+Definition Im {G H : AbGroup} (f : HomGr G H) :=
+ {| gr_set := gr_set H;
+ gr_zero := gr_zero;
+ gr_eq := @gr_eq H;
+ gr_mem := λ b, ∃ a, a ∈ G ∧ (Happ f a = b)%G;
+ gr_add := @gr_add H;
+ gr_opp := @gr_opp H;
+ gr_zero_mem := Im_zero_mem f;
+ gr_add_mem := Im_add_mem f;
+ gr_add_0_l := gr_add_0_l H;
+ gr_add_assoc := gr_add_assoc H;
+ gr_opp_mem := Im_opp_mem f;
+ gr_add_opp_r := gr_add_opp_r H;
+ gr_add_comm := gr_add_comm H;
+ gr_equiv := gr_equiv H;
+ gr_mem_compat := Im_mem_compat f;
+ gr_add_compat := gr_add_compat H;
+ gr_opp_compat := gr_opp_compat H |}.
+
+(* Kernels *)
+
+Theorem Ker_zero_mem {G H} : ∀ (f : HomGr G H), 0%G ∈ G ∧ (Happ f 0 = 0)%G.
+Proof.
+intros f.
+split; [ apply gr_zero_mem | apply Hzero ].
+Qed.
+
+Theorem Ker_add_mem {G H} : ∀ (f : HomGr G H) (x y : gr_set G),
+ x ∈ G ∧ (Happ f x = 0)%G
+ → y ∈ G ∧ (Happ f y = 0)%G → (x + y)%G ∈ G ∧ (Happ f (x + y) = 0)%G.
+Proof.
+intros f x x' (Hx, Hfx) (Hx', Hfx').
+split; [ now apply gr_add_mem | ].
+rewrite Hadditive; [ | easy | easy ].
+rewrite Hfx, Hfx'.
+apply gr_add_0_r.
+Qed.
+
+Theorem Ker_opp_mem {G H} : ∀ (f : HomGr G H) (x : gr_set G),
+ x ∈ G ∧ (Happ f x = 0)%G → (- x)%G ∈ G ∧ (Happ f (- x) = 0)%G.
+Proof.
+intros f x (Hx & Hfx).
+split; [ now apply gr_opp_mem | ].
+rewrite Hopp; [ | easy ].
+rewrite Hfx.
+apply gr_opp_zero.
+Qed.
+
+Theorem Ker_mem_compat {G H} : ∀ (f : HomGr G H) x y,
+ (x = y)%G → x ∈ G ∧ (Happ f x = 0)%G → y ∈ G ∧ (Happ f y = 0)%G.
+Proof.
+intros * Hxy (ax, Hx).
+split.
+-eapply gr_mem_compat; [ apply Hxy | easy ].
+-rewrite <- Hx.
+ apply f; [ | easy ].
+ now rewrite <- Hxy.
+Qed.
+
+Definition Ker {G H : AbGroup} (f : HomGr G H) :=
+ {| gr_set := gr_set G;
+ gr_zero := gr_zero;
+ gr_eq := @gr_eq G;
+ gr_mem := λ a, a ∈ G ∧ (Happ f a = gr_zero)%G;
+ gr_add := @gr_add G;
+ gr_opp := @gr_opp G;
+ gr_zero_mem := Ker_zero_mem f;
+ gr_add_mem := Ker_add_mem f;
+ gr_add_0_l := gr_add_0_l G;
+ gr_add_assoc := gr_add_assoc G;
+ gr_opp_mem := Ker_opp_mem f;
+ gr_add_opp_r := gr_add_opp_r G;
+ gr_add_comm := gr_add_comm G;
+ gr_equiv := gr_equiv G;
+ gr_mem_compat := Ker_mem_compat f;
+ gr_add_compat := gr_add_compat G;
+ gr_opp_compat := gr_opp_compat G |}.
+
+(* Cokernels
+
+ x ∈ Coker f ↔ x ∈ H/Im f
+ quotient group is H with setoid, i.e. set with its own equality *)
+
+Definition Coker_eq {G H} (f : HomGr G H) x y := (x - y)%G ∈ Im f.
+
+Theorem Coker_add_0_l {G H} : ∀ (f : HomGr G H) x, Coker_eq f (0 + x)%G x.
+Proof.
+intros.
+unfold Coker_eq.
+exists 0%G.
+split; [ apply gr_zero_mem | ].
+rewrite gr_add_0_l, gr_add_opp_r.
+simpl; apply Hzero.
+Qed.
+
+Theorem Coker_add_assoc {G H} : ∀ (f : HomGr G H) x y z,
+ Coker_eq f (x + y + z)%G (x + (y + z))%G.
+Proof.
+intros.
+unfold Coker_eq.
+exists 0%G.
+split; [ apply gr_zero_mem | ].
+rewrite Hzero.
+symmetry; simpl.
+apply gr_sub_move_r.
+rewrite gr_add_0_l.
+apply gr_add_assoc.
+Qed.
+
+Theorem Coker_add_opp_r {G H} : ∀ (f : HomGr G H) x, Coker_eq f (x - x)%G 0%G.
+Proof.
+intros.
+exists 0%G.
+split; [ apply gr_zero_mem | ].
+now rewrite Hzero, gr_add_opp_r, gr_sub_0_r.
+Qed.
+
+Theorem Coker_add_comm {G H} : ∀ (f : HomGr G H) x y,
+ Coker_eq f (x + y)%G (y + x)%G.
+Proof.
+intros.
+exists 0%G.
+split; [ apply gr_zero_mem | ].
+rewrite Hzero.
+symmetry.
+simpl; apply gr_sub_move_l.
+now rewrite gr_add_0_r, gr_add_comm.
+Qed.
+
+Theorem Coker_eq_refl {G H} (f : HomGr G H) : Reflexive (Coker_eq f).
+Proof.
+intros x.
+exists 0%G.
+split; [ apply gr_zero_mem | ].
+rewrite gr_add_opp_r.
+simpl; apply Hzero.
+Qed.
+
+Theorem Coker_eq_symm {G H} (f : HomGr G H) : Symmetric (Coker_eq f).
+Proof.
+intros x y Hxy.
+destruct Hxy as (z & Hz & Hfz).
+exists (- z)%G.
+split; [ now apply gr_opp_mem | ].
+rewrite Hopp; [ | easy ].
+rewrite Hfz.
+simpl; rewrite gr_opp_add_distr, gr_add_comm.
+apply gr_add_compat; [ | easy ].
+apply gr_opp_involutive.
+Qed.
+
+Theorem Coker_eq_trans {G H} (f : HomGr G H) : Transitive (Coker_eq f).
+Proof.
+intros x y z Hxy Hyz.
+simpl in Hxy, Hyz.
+destruct Hxy as (t & Ht & Hft).
+destruct Hyz as (u & Hu & Hfu).
+exists (t + u)%G.
+split; [ now apply gr_add_mem | ].
+rewrite Hadditive; [ | easy | easy ].
+rewrite Hft, Hfu.
+simpl; rewrite gr_add_assoc.
+apply gr_add_compat; [ easy | ].
+now rewrite <- gr_add_assoc, gr_add_opp_l, gr_add_0_l.
+Qed.
+
+Theorem Coker_equiv {G H} : ∀ (f : HomGr G H), Equivalence (Coker_eq f).
+Proof.
+intros.
+unfold Coker_eq; split.
+-apply Coker_eq_refl.
+-apply Coker_eq_symm.
+-apply Coker_eq_trans.
+Qed.
+
+Add Parametric Relation {G H} {f : HomGr G H} : (gr_set (Im f)) (Coker_eq f)
+ reflexivity proved by (Coker_eq_refl f)
+ symmetry proved by (Coker_eq_symm f)
+ transitivity proved by (Coker_eq_trans f)
+ as gr_cokereq_rel.
+
+Theorem Coker_mem_compat {G H} : ∀ (f : HomGr G H) x y,
+ Coker_eq f x y → x ∈ H → y ∈ H.
+Proof.
+intros * Heq Hx.
+destruct Heq as (z & Hz & Hfz).
+apply gr_mem_compat with (x := (x - Happ f z)%G).
+-rewrite Hfz.
+ simpl; apply gr_sub_move_r.
+ now rewrite gr_add_comm, gr_add_assoc, gr_add_opp_l, gr_add_0_r.
+-simpl; apply gr_add_mem; [ easy | ].
+ apply gr_opp_mem.
+ now apply f.
+Qed.
+
+Theorem Coker_add_compat {G H} : ∀ (f : HomGr G H) x y x' y',
+ Coker_eq f x y → Coker_eq f x' y' → Coker_eq f (x + x')%G (y + y')%G.
+Proof.
+intros f x y x' y' (z & Hz & Hfz) (z' & Hz' & Hfz').
+exists (z + z')%G.
+split.
+-now apply gr_add_mem.
+-rewrite Hadditive; [ | easy | easy ].
+ rewrite Hfz, Hfz'; simpl.
+ rewrite gr_add_assoc; symmetry.
+ rewrite gr_add_assoc; symmetry.
+ apply gr_add_compat; [ easy | ].
+ rewrite gr_add_comm, gr_add_assoc.
+ apply gr_add_compat; [ easy | ].
+ rewrite gr_add_comm; symmetry.
+ apply gr_opp_add_distr.
+Qed.
+
+Theorem Coker_opp_compat {G H} :∀ (f : HomGr G H) x y,
+ Coker_eq f x y → Coker_eq f (- x)%G (- y)%G.
+Proof.
+intros * (z & Hz & Hfz).
+unfold Coker_eq; simpl.
+exists (- z)%G.
+split; [ now apply gr_opp_mem | ].
+rewrite Hopp; [ | easy ].
+rewrite Hfz.
+simpl; apply gr_opp_add_distr.
+Qed.
+
+Definition Coker {G H : AbGroup} (f : HomGr G H) :=
+ {| gr_set := gr_set H;
+ gr_zero := gr_zero;
+ gr_eq := Coker_eq f;
+ gr_mem := gr_mem H;
+ gr_add := @gr_add H;
+ gr_opp := @gr_opp H;
+ gr_zero_mem := @gr_zero_mem H;
+ gr_add_mem := @gr_add_mem H;
+ gr_add_0_l := Coker_add_0_l f;
+ gr_add_assoc := Coker_add_assoc f;
+ gr_opp_mem := gr_opp_mem H;
+ gr_add_opp_r := Coker_add_opp_r f;
+ gr_add_comm := Coker_add_comm f;
+ gr_equiv := Coker_equiv f;
+ gr_mem_compat := Coker_mem_compat f;
+ gr_add_compat := Coker_add_compat f;
+ gr_opp_compat := Coker_opp_compat f |}.
+
+(* Exact sequences *)
+
+Inductive sequence {A : AbGroup} :=
+ | SeqEnd : sequence
+ | Seq : ∀ {B} (f : HomGr A B), @sequence B → sequence.
+
+Notation "A ⊂ B" := (∀ a, a ∈ A → a ∈ B) (at level 60).
+Notation "A == B" := (A ⊂ B ∧ B ⊂ A) (at level 60).
+
+Fixpoint exact_sequence {A : AbGroup} (S : sequence) :=
+ match S with
+ | SeqEnd => True
+ | Seq f S' =>
+ match S' with
+ | SeqEnd => True
+ | Seq g S'' => Im f == Ker g ∧ exact_sequence S'
+ end
+ end.
+
+Delimit Scope seq_scope with S.
+
+Notation "[ ]" := SeqEnd (format "[ ]") : seq_scope.
+Notation "[ x ]" := (Seq x SeqEnd) : seq_scope.
+Notation "[ x ; y ; .. ; z ]" := (Seq x (Seq y .. (Seq z SeqEnd) ..)) : seq_scope.
+
+Arguments exact_sequence _ S%S.
+
+(*
+ f
+ A------>B
+ | |
+ g| |h
+ | |
+ v v
+ C------>D
+ k
+*)
+
+Definition diagram_commutes {A B C D}
+ (f : HomGr A B) (g : HomGr A C) (h : HomGr B D) (k : HomGr C D) :=
+ ∀ x, (Happ h (Happ f x) = Happ k (Happ g x))%G.
+
+(* The trivial group *)
+
+Theorem Gr1_add_0_l : ∀ x : True, I = x.
+Proof. now destruct x. Qed.
+
+Definition Gr1 :=
+ {| gr_set := True;
+ gr_mem _ := True;
+ gr_eq := eq;
+ gr_zero := I;
+ gr_add _ _ := I;
+ gr_opp x := x;
+ gr_zero_mem := I;
+ gr_add_mem _ _ _ _ := I;
+ gr_add_0_l := Gr1_add_0_l;
+ gr_add_assoc _ _ _ := eq_refl;
+ gr_opp_mem _ H := H;
+ gr_add_opp_r _ := eq_refl;
+ gr_add_comm _ _ := eq_refl;
+ gr_equiv := eq_equivalence;
+ gr_mem_compat _ _ _ _ := I;
+ gr_add_compat _ _ _ _ _ _ := eq_refl;
+ gr_opp_compat _ _ H := H |}.
+
+(* *)
+
+Definition is_mono {A B} (f : HomGr A B) :=
+ ∀ C (g₁ g₂ : HomGr C A),
+ (∀ z, z ∈ C → (Happ f (Happ g₁ z) = Happ f (Happ g₂ z))%G)
+ → (∀ z, z ∈ C → (Happ g₁ z = Happ g₂ z)%G).
+
+Definition is_epi {A B} (f : HomGr A B) :=
+ ∀ C (g₁ g₂ : HomGr B C),
+ (∀ x, x ∈ A → (Happ g₁ (Happ f x) = Happ g₂ (Happ f x))%G)
+ → (∀ y, y ∈ B → (Happ g₁ y = Happ g₂ y)%G).
+
+Definition is_iso {A B} (f : HomGr A B) :=
+ ∃ g : HomGr B A,
+ (∀ x, x ∈ A → (Happ g (Happ f x) = x)%G) ∧
+ (∀ y, y ∈ B → (Happ f (Happ g y) = y)%G).
+
+(* epimorphism is surjective and monomorphism is injective *)
+
+Theorem epi_is_surj : ∀ {A B} {f : HomGr A B},
+ is_epi f
+ → ∀ y, y ∈ B → ∃ t, t ∈ A ∧ (Happ f t = y)%G.
+Proof.
+intros * Hed y Hy.
+(* type gr_set B → gr_set (Coker f) *)
+set (v y1 := let _ : gr_set B := y1 in y1 : gr_set (Coker f)).
+assert (Hmc : ∀ y1, y1 ∈ B → v y1 ∈ B) by easy.
+assert (Hac : ∀ y1 y2, y1 ∈ B → (y1 = y2)%G → (v y1 = v y2)%G). {
+ intros * Hy1 Hyy.
+ exists 0; split; [ apply A | ].
+ now unfold v; simpl; rewrite Hzero, Hyy, gr_add_opp_r.
+}
+assert (Had : ∀ y1 y2, y1 ∈ B → y2 ∈ B → (v (y1 + y2) = v y1 + v y2)%G). {
+ intros * Hy1 Hy2.
+ exists 0; split; [ apply A | now unfold v; rewrite Hzero, gr_add_opp_r ].
+}
+set (hv :=
+ {| Happ := v;
+ Hmem_compat := Hmc;
+ Happ_compat := Hac;
+ Hadditive := Had |}).
+assert (Hmc₀ : ∀ y1, y1 ∈ B → 0 ∈ Coker f) by (intros; apply B).
+assert (Hac₀ : ∀ y1 y2, y1 ∈ B → (y1 = y2)%G → (@gr_zero (Coker f) = 0)%G). {
+ intros * Hy1 Hyy.
+ simpl; unfold Coker_eq; simpl.
+ exists 0; split; [ apply A | now rewrite Hzero, gr_add_opp_r ].
+}
+assert (Had₀ : ∀ y1 y2, y1 ∈ B → y2 ∈ B → (@gr_zero (Coker f) = 0 + 0)%G). {
+ intros * Hy1 Hy2.
+ simpl; unfold Coker_eq; simpl.
+ exists 0; split; [ apply A | now rewrite Hzero, gr_add_0_r, gr_sub_0_r ].
+}
+set (hw :=
+ {| Happ _ := 0;
+ Hmem_compat := Hmc₀;
+ Happ_compat := Hac₀;
+ Hadditive := Had₀ |}).
+specialize (Hed (Coker f) hv hw) as H1.
+assert (H : ∀ x, x ∈ A → (Happ hv (Happ f x) = Happ hw (Happ f x))%G). {
+ intros x Hx.
+ simpl; unfold v; unfold Coker_eq; simpl.
+ exists x; split; [ easy | now rewrite gr_sub_0_r ].
+}
+specialize (H1 H y Hy); clear H.
+simpl in H1; unfold Coker_eq in H1; simpl in H1.
+destruct H1 as (x & Hx).
+rewrite gr_sub_0_r in Hx.
+now exists x.
+Qed.
+
+Theorem mono_is_inj : ∀ {A B} {f : HomGr A B},
+ is_mono f
+ → ∀ x1 x2, x1 ∈ A → x2 ∈ A → (Happ f x1 = Happ f x2)%G → (x1 = x2)%G.
+Proof.
+intros * Hf * Hx1 Hx2 Hxx.
+(* morphism identity from Ker f to A *)
+set (v x := let _ : gr_set (Ker f) := x in x : gr_set A).
+assert (Hmc : ∀ x, x ∈ Ker f → v x ∈ A) by (intros x Hx; apply Hx).
+set (hv :=
+ {| Happ := v;
+ Hmem_compat := Hmc;
+ Happ_compat _ _ _ H := H;
+ Hadditive _ _ _ _ := reflexivity _ |}).
+(* morphism null from Ker f to A *)
+set (hw :=
+ {| Happ x := let _ : gr_set (Ker f) := x in 0 : gr_set A;
+ Hmem_compat _ _ := gr_zero_mem A;
+ Happ_compat _ _ _ _ := reflexivity _;
+ Hadditive _ _ _ _ := symmetry (gr_add_0_r _ _) |}).
+specialize (Hf (Ker f) hv hw) as H1.
+assert (H : ∀ z, z ∈ Ker f → (Happ f (Happ hv z) = Happ f (Happ hw z))%G). {
+ intros z (Hz, Hfz).
+ unfold hv, hw, v; simpl.
+ now rewrite Hfz, Hzero.
+}
+specialize (H1 H (x1 - x2)); clear H.
+assert (H : x1 - x2 ∈ Ker f). {
+ split.
+ -apply A; [ easy | now apply A ].
+ -rewrite Hadditive; [ | easy | now apply A ].
+ rewrite Hopp; [ | easy ].
+ now rewrite Hxx, gr_add_opp_r.
+}
+specialize (H1 H); clear H.
+unfold hv, hw, v in H1; simpl in H1.
+apply gr_sub_move_r in H1.
+now rewrite gr_add_0_l in H1.
+Qed.
+
+(* We sometimes need these axioms *)
+
+Definition Choice := ∀ {A B} {R : A → B → Prop},
+ (∀ x : A, ∃ y : B, R x y) → ∃ f : A → B, ∀ x : A, R x (f x).
+Definition Decidable_Membership := ∀ G x, {x ∈ G} + {x ∉ G}.
+