Built with Alectryon, running Coq+SerAPI v8.19.0+0.19.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use ⌘ instead of Ctrl.
[Loading ML file number_string_notation_plugin.cmxs (using legacy method) ... done]
Require Import Homotopy.IdentitySystems.Require Import (notations) Classes.interfaces.canonical_names.Require Export (hints) Classes.interfaces.abstract_algebra.Require Export (hints) Classes.interfaces.canonical_names.(** We only export the parts of these that will be most useful to users of this file. *)Require Export Classes.interfaces.canonical_names (SgOp, sg_op, MonUnit, mon_unit,
LeftIdentity, left_identity, RightIdentity, right_identity,
Inverse, inv, Associative, simple_associativity, associativity, associative_flip,
LeftInverse, left_inverse, RightInverse, right_inverse, Commutative, commutativity).Export canonical_names.BinOpNotations.Require Export Classes.interfaces.abstract_algebra (IsGroup(..), group_monoid, inverse_l, inverse_r,
IsSemiGroup(..), sg_set, sg_ass,
IsMonoid(..), monoid_left_id, monoid_right_id, monoid_semigroup,
IsMonoidPreserving(..), monmor_unitmor, monmor_sgmor,
IsSemiGroupPreserving, preserves_sg_op, IsUnitPreserving, preserves_mon_unit).Require Export Classes.theory.groups.Require Import Pointed.Core.Require Import WildCat.Require Import Spaces.Nat.Core Spaces.Int.Require Import Truncations.Core.Local Set Polymorphic Inductive Cumulativity.Generalizable VariablesG H A B C f g.Declare Scope group_scope.(** * Groups *)(** A group is an abstraction of several common situations in mathematics. For example, consider the symmetries of an object. Two symmetries can be combined; there is a symmetry that does nothing; and any symmetry can be reversed. Such situations arise in geometry, algebra and, importantly for us, homotopy theory. *)LocalOpen Scope pointed_scope.LocalOpen Scope mc_mult_scope.LocalOpen Scope wc_iso_scope.(** ** Definition of a Group *)(** A group consists of a type, an operation on that type, a unit and an inverse that satisfy the group axioms in [IsGroup]. *)RecordGroup := Build_Group_internal {
group_type :> Type;
group_sgop :: SgOp group_type;
group_unit :: MonUnit group_type;
group_inverse :: Inverse group_type;
group_isgroup :: IsGroup group_type;
(** This axiom is redundant, but will allow the "opposite" group to be definitionally involutive. *)
group_assoc_opp : Associative (flip group_sgop);
}.Arguments group_sgop {_}.Arguments group_unit {_}.Arguments group_inverse {_}.Arguments group_isgroup {_}.Arguments group_assoc_opp {_}.(** We should never need to unfold the proof that something is a group. *)GlobalOpaque group_isgroup.Definitionissig_group : _ <~> Group
:= ltac:(issig).(** This is the main constructor that is used to build groups.It differs from [Build_Group_internal] by removing the redundant second proof of associativity. There is a technical reason for keeping the second axiom around, see the definition of [grp_op].Note that we could have given the fields of [IsGroup] in a completely unbundled manner, but this has a negative impact on performance since every time a [Group] term is unfolded, the axioms appear in the arguments.It is therefore advised to use this constructor in combination with a tactic like [repeat split] when building groups. *)
G: Type op: SgOp G unit: MonUnit G inv: Inverse G grp: IsGroup G
Group
G: Type op: SgOp G unit: MonUnit G inv: Inverse G grp: IsGroup G
Group
G: Type op: SgOp G unit: MonUnit G inv: Inverse G grp: IsGroup G
Associative (flip op)
rapply associative_flip.Defined.(** ** Proof automation *)(** Many times in group theoretic proofs we want some form of automation for obvious identities. Here we implement such a behavior. *)(** We create a database of hints for the group theory library *)Create HintDb group_db.(** Our group laws can be proven easily with tactics such as [rapply associativity]. However this requires a typeclass search on more general algebraic structures. Therefore we explicitly list many groups laws here so that Coq can use them. We also create hints for each law in our groups database. *)SectionGroupLaws.Context {G : Group} (xyz : G).Definitiongrp_assoc := associativity x y z.Definitiongrp_unit_l := left_identity x.Definitiongrp_unit_r := right_identity x.Definitiongrp_inv_l := left_inverse x.Definitiongrp_inv_r := right_inverse x.EndGroupLaws.#[export] Hint Immediate grp_assoc : group_db.#[export] Hint Immediate grp_unit_l : group_db.#[export] Hint Immediate grp_unit_r : group_db.#[export] Hint Immediate grp_inv_l : group_db.#[export] Hint Immediate grp_inv_r : group_db.(** Given path types in a product we may want to decompose. *)#[export] Hint Extern5 (@paths (_ * _) _ _) => (apply path_prod) : group_db.(** Given path types in a sigma type of a hprop family (i.e. a subset) we may want to decompose. *)#[export] Hint Extern6 (@paths (sig _) _ _) => (rapply path_sigma_hprop) : group_db.(** We also declare a tactic (notation) for automatically solving group laws *)(** TODO: improve this tactic so that it also rewrites and is able to solve basic group lemmas. *)Tactic Notation"grp_auto" := hnf; intros; eauto with group_db.(** ** Some basic properties of groups *)(** Groups are pointed sets with point the identity. *)Instanceispointed_group (G : Group)
: IsPointed G := @mon_unit G _.Definitionptype_group : Group -> pType
:= funG => [G, _].Coercionptype_group : Group >-> pType.(** An element acting like the identity is unique. *)Definitionidentity_unique {A : Type} {Aop : SgOp A}
(xy : A) {p : LeftIdentity Aop x} {q : RightIdentity Aop y}
: x = y := (q x)^ @ p y.Definitionidentity_unique' {A : Type} {Aop : SgOp A}
(xy : A) {p : LeftIdentity Aop x} {q : RightIdentity Aop y}
: y = x := (identity_unique x y)^.(** An element acting like an inverse is unique. *)
A: Type Aop: SgOp A Aunit: MonUnit A H: IsMonoid A a, x, y: A p: x * a = 1 q: a * y = 1
x = y
A: Type Aop: SgOp A Aunit: MonUnit A H: IsMonoid A a, x, y: A p: x * a = 1 q: a * y = 1
x = y
A: Type Aop: SgOp A Aunit: MonUnit A H: IsMonoid A a, x, y: A p: x * a = 1 q: a * y = 1
x * (a * y) = y
A: Type Aop: SgOp A Aunit: MonUnit A H: IsMonoid A a, x, y: A p: x * a = 1 q: a * y = 1
x * a * y = y
A: Type Aop: SgOp A Aunit: MonUnit A H: IsMonoid A a, x, y: A p: x * a = 1 q: a * y = 1
1 * y = y
apply left_identity.Defined.(** With other assumptions, the right inverse law follows from the left inverse law. *)
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1
RightInverse sg_op inv 1
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1
RightInverse sg_op inv 1
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
x * x^ = 1
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
1 * (x * x^) = 1
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
(x^)^ * x^ * (x * x^) = (x^)^ * x^
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
(x^)^ * (x^ * (x * x^)) = (x^)^ * x^
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
x^ * (x * x^) = x^
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
x^ * x * x^ = x^
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
x^ * x = ?Goal
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
?Goal * x^ = x^
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
1 * x^ = x^
apply left_identity.Defined.GlobalOpaque right_inverse_left_inverse.(** With other assumptions, the right identity law follows from the left identity law. *)
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1
RightIdentity sg_op 1
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1
RightIdentity sg_op 1
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
x * 1 = x
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
1 * (x * 1) = x
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
1 * (x * 1) = 1 * x
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
(x^)^ * x^ * (x * 1) = (x^)^ * x^ * x
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
(x^)^ * (x^ * (x * 1)) = (x^)^ * x^ * x
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
(x^)^ * (x^ * (x * 1)) = (x^)^ * (x^ * x)
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
x^ * (x * 1) = x^ * x
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
x^ * x * 1 = x^ * x
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
1 * 1 = x^ * x
G: Type IsHSet0: IsHSet G H: SgOp G H0: MonUnit G H1: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op inv 1 x: G
1 = x^ * x
symmetry; apply left_inverse.Defined.GlobalOpaque right_identity_left_identity.(** When building a group we can choose to omit the right inverse law and right identity law, since they follow from the left ones. Note that as before with [Build_Group], the extra associativity axiom is omitted. *)
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
Group
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
Group
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
IsHSet G
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
Associative sg_op
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
LeftIdentity sg_op 1
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
RightIdentity sg_op 1
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
LeftInverse sg_op canonical_names.inv 1
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
RightInverse sg_op canonical_names.inv 1
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
RightIdentity sg_op 1
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
RightInverse sg_op canonical_names.inv 1
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
RightIdentity sg_op 1
napply right_identity_left_identity; exact _.
G: Type IsHSet0: IsHSet G op: SgOp G unit: MonUnit G inv: Inverse G Associative0: Associative sg_op LeftIdentity0: LeftIdentity sg_op 1 LeftInverse0: LeftInverse sg_op canonical_names.inv 1
RightInverse sg_op canonical_names.inv 1
napply right_inverse_left_inverse; exact _.Defined.(** This is a variant of [issig_group] that drops the opposite axiom. *)
H: Funext
{G : Type &
{op : SgOp G &
{unit : MonUnit G & {inv : Inverse G & IsGroup G}}}} <~>
Group
H: Funext
{G : Type &
{op : SgOp G &
{unit : MonUnit G & {inv : Inverse G & IsGroup G}}}} <~>
Group
H: Funext
{H : Type &
{H0 : SgOp H &
{H1 : MonUnit H &
{H2 : Inverse H &
{_ : IsGroup H & Associative (flip H0)}}}}} <~>
{G : Type &
{op : SgOp G &
{unit : MonUnit G & {inv : Inverse G & IsGroup G}}}}
H: Funext G: Type
{H0 : SgOp G &
{H1 : MonUnit G &
{H2 : Inverse G &
{_ : IsGroup G & Associative (flip H0)}}}} <~>
{op : SgOp G &
{unit : MonUnit G & {inv : Inverse G & IsGroup G}}}
H: Funext G: Type op: SgOp G
{H1 : MonUnit G &
{H2 : Inverse G &
{_ : IsGroup G & Associative (flip op)}}} <~>
{unit : MonUnit G & {inv : Inverse G & IsGroup G}}
H: Funext G: Type op: SgOp G unit: MonUnit G
{H2 : Inverse G &
{_ : IsGroup G & Associative (flip op)}} <~>
{inv : Inverse G & IsGroup G}
H: Funext G: Type op: SgOp G unit: MonUnit G inv: Inverse G
{_ : IsGroup G & Associative (flip op)} <~> IsGroup G
H: Funext G: Type op: SgOp G unit: MonUnit G inv: Inverse G g: IsGroup G
Associative (flip op)
intros z y x; symmetry; rapply simple_associativity.Defined.(** ** Group homomorphisms *)(** Group homomorphisms are maps between groups that preserve the group operation. They allow us to compare groups and map their structure to one another. This is useful for determining if two groups are really the same, in which case we say they are "isomorphic". *)(** A group homomorphism consists of a map between groups and a proof that the map preserves the group operation. *)RecordGroupHomomorphism (GH : Group) := Build_GroupHomomorphism {
grp_homo_map :> group_type G -> group_type H;
issemigrouppreserving_grp_homo :: IsSemiGroupPreserving grp_homo_map;
}.Arguments grp_homo_map {G H}.Arguments Build_GroupHomomorphism {G H} _ _.Arguments issemigrouppreserving_grp_homo {G H} f _ : rename.(** ** Basic properties of group homomorphisms *)(** Group homomorphisms preserve group operations. This is an alias for [issemigrouppreserving_grp_homo] with the identity written explicitly. *)Definitiongrp_homo_op
: forall {GH : Group} (f : GroupHomomorphism G H) (xy : G), f (x * y) = f x * f y
:= @issemigrouppreserving_grp_homo.#[export] Hint Immediate grp_homo_op : group_db.(** Group homomorphisms are unit preserving. *)
G, H: Group f: GroupHomomorphism G H
IsUnitPreserving f
G, H: Group f: GroupHomomorphism G H
IsUnitPreserving f
G, H: Group f: GroupHomomorphism G H
f 1 = 1
G, H: Group f: GroupHomomorphism G H
f 1 * f 1 = f 1 * 1
G, H: Group f: GroupHomomorphism G H
f 1 * f 1 = f 1
G, H: Group f: GroupHomomorphism G H
f 1 * f 1 = f (1 * 1)
G, H: Group f: GroupHomomorphism G H
f (1 * 1) = f 1 * f 1
napply issemigrouppreserving_grp_homo.Defined.(** We usually don't need access to the proof, so we mark this as opaque for a very slight speedup. *)Opaque isunitpreserving_grp_homo.(** Group homomorphisms preserve identities. This is an alias for the previous statement. *)Definitiongrp_homo_unit
: forall {GH : Group} (f : GroupHomomorphism G H), f mon_unit = mon_unit
:= @isunitpreserving_grp_homo.#[export] Hint Immediate grp_homo_unit : group_db.(** Therefore, group homomorphisms are monoid homomorphisms. *)Instanceismonoidpreserving_grp_homo {GH : Group}
(f : GroupHomomorphism G H)
: IsMonoidPreserving f
:= {}.(** Group homomorphisms are pointed maps. *)Definitionpmap_GroupHomomorphism {GH : Group} (f : GroupHomomorphism G H) : G ->* H
:= Build_pMap f (isunitpreserving_grp_homo f).Coercionpmap_GroupHomomorphism : GroupHomomorphism >-> pForall.Definitionissig_GroupHomomorphism (GH : Group) : _ <~> GroupHomomorphism G H
:= ltac:(issig).(** Function extensionality for group homomorphisms. *)
F: Funext G, H: Group g, h: GroupHomomorphism G H
g == h <~> g = h
F: Funext G, H: Group g, h: GroupHomomorphism G H
g == h <~> g = h
F: Funext G, H: Group g, h: GroupHomomorphism G H
g == h <~>
(issig_GroupHomomorphism G H)^-1 g =
(issig_GroupHomomorphism G H)^-1 h
F: Funext G, H: Group g, h: GroupHomomorphism G H
g == h <~>
((issig_GroupHomomorphism G H)^-1 g).1 =
((issig_GroupHomomorphism G H)^-1 h).1
apply equiv_path_forall.Defined.(** Group homomorphisms are sets, in the presence of funext. *)
F: Funext G, H: Group
IsHSet (GroupHomomorphism G H)
F: Funext G, H: Group
IsHSet (GroupHomomorphism G H)
F: Funext G, H: Group
is_mere_relation (GroupHomomorphism G H) paths
intros f g; exact (istrunc_equiv_istrunc _ equiv_path_grouphomomorphism).Defined.(** Group homomorphisms preserve inverses. *)
G, H: Group f: GroupHomomorphism G H
forallx : G, f x^ = (f x)^
(* This can also be proved using [:= preserves_inverse.] from Classes/theory/groups.v. That uses [rewrite] and is marked [Qed]. *)
G, H: Group f: GroupHomomorphism G H
forallx : G, f x^ = (f x)^
G, H: Group f: GroupHomomorphism G H x: G
f x^ = (f x)^
G, H: Group f: GroupHomomorphism G H x: G
f x^ * f x = 1
G, H: Group f: GroupHomomorphism G H x: G
f x * (f x)^ = 1
G, H: Group f: GroupHomomorphism G H x: G
f x^ * f x = 1
G, H: Group f: GroupHomomorphism G H x: G
f x^ * f x = f 1
G, H: Group f: GroupHomomorphism G H x: G
f (x^ * x) = f 1
G, H: Group f: GroupHomomorphism G H x: G
x^ * x = 1
apply grp_inv_l.
G, H: Group f: GroupHomomorphism G H x: G
f x * (f x)^ = 1
apply grp_inv_r.Defined.#[export] Hint Immediate grp_homo_inv : group_db.(** The identity map is a group homomorphism. *)Definitiongrp_homo_id {G : Group} : GroupHomomorphism G G
:= Build_GroupHomomorphism idmap _.(** The composition of the underlying functions of two group homomorphisms is also a group homomorphism. *)
G, H, K: Group
GroupHomomorphism H K ->
GroupHomomorphism G H -> GroupHomomorphism G K
G, H, K: Group
GroupHomomorphism H K ->
GroupHomomorphism G H -> GroupHomomorphism G K
G, H, K: Group f: GroupHomomorphism H K g: GroupHomomorphism G H
GroupHomomorphism G K
srapply (Build_GroupHomomorphism (f o g)).Defined.(** ** Group Isomorphisms *)(** Group isomorphisms are group homomorphisms whose underlying map happens to be an equivalence. They allow us to consider two groups to be the "same". They can be inverted and composed just like equivalences. *)(** An isomorphism of groups is defined as group homomorphism that is an equivalence. *)RecordGroupIsomorphism (GH : Group) := Build_GroupIsomorphism {
grp_iso_homo :> GroupHomomorphism G H;
isequiv_group_iso :: IsEquiv grp_iso_homo;
}.(** We can build an isomorphism from an operation-preserving equivalence. *)
G, H: Group f: G <~> H h: IsSemiGroupPreserving f
GroupIsomorphism G H
G, H: Group f: G <~> H h: IsSemiGroupPreserving f
GroupIsomorphism G H
G, H: Group f: G <~> H h: IsSemiGroupPreserving f
GroupHomomorphism G H
G, H: Group f: G <~> H h: IsSemiGroupPreserving f
IsEquiv ?grp_iso_homo
G, H: Group f: G <~> H h: IsSemiGroupPreserving f
IsEquiv
{|
grp_homo_map := f;
issemigrouppreserving_grp_homo := h
|}
exact _.Defined.Definitionissig_GroupIsomorphism (GH : Group)
: _ <~> GroupIsomorphism G H := ltac:(issig).(** The underlying equivalence of a group isomorphism. *)Definitionequiv_groupisomorphism {GH : Group}
: GroupIsomorphism G H -> G <~> H
:= funf => Build_Equiv G H f _.Coercionequiv_groupisomorphism : GroupIsomorphism >-> Equiv.(** The underlying pointed equivalence of a group isomorphism. *)Definitionpequiv_groupisomorphism {AB : Group}
: GroupIsomorphism A B -> (A <~>* B)
:= funf => Build_pEquiv f _.Coercionpequiv_groupisomorphism : GroupIsomorphism >-> pEquiv.(** Funext for group isomorphisms. *)
F: Funext G, H: Group f, g: GroupIsomorphism G H
f == g <~> f = g
F: Funext G, H: Group f, g: GroupIsomorphism G H
f == g <~> f = g
F: Funext G, H: Group f, g: GroupIsomorphism G H
f == g <~>
(issig_GroupIsomorphism G H)^-1 f =
(issig_GroupIsomorphism G H)^-1 g
F: Funext G, H: Group f, g: GroupIsomorphism G H
f == g <~>
((issig_GroupIsomorphism G H)^-1 f).1 =
((issig_GroupIsomorphism G H)^-1 g).1
exact equiv_path_grouphomomorphism.Defined.(** Group isomorphisms form a set. *)
F: Funext G, H: Group
IsHSet (GroupIsomorphism G H)
F: Funext G, H: Group
IsHSet (GroupIsomorphism G H)
F: Funext G, H: Group
is_mere_relation (GroupIsomorphism G H) paths
intros f g; exact (istrunc_equiv_istrunc _ (equiv_path_groupisomorphism _ _)).Defined.(** The identity map is an equivalence and therefore a group isomorphism. *)Definitiongrp_iso_id {G : Group} : GroupIsomorphism G G
:= Build_GroupIsomorphism _ _ grp_homo_id _.(** Group isomorphisms can be composed by composing the underlying group homomorphism. *)Definitiongrp_iso_compose {GHK : Group}
(g : GroupIsomorphism H K) (f : GroupIsomorphism G H)
: GroupIsomorphism G K
:= Build_GroupIsomorphism _ _ (grp_homo_compose g f) _.(** Group isomorphisms can be inverted. The inverse map of the underlying equivalence also preserves the group operation and unit. *)
exact _.Defined.(** Group isomorphism is a reflexive relation. *)Instancereflexive_groupisomorphism
: Reflexive GroupIsomorphism
:= funG => grp_iso_id.(** Group isomorphism is a symmetric relation. *)Instancesymmetric_groupisomorphism
: Symmetric GroupIsomorphism
:= funGH => grp_iso_inverse.(** Group isomorphism is a transitive relation. *)Instancetransitive_groupisomorphism
: Transitive GroupIsomorphism
:= funGHKfg => grp_iso_compose g f.(** Under univalence, equality of groups is equivalent to isomorphism of groups. This is the structure identity principle for groups. *)
U: Univalence G, H: Group
GroupIsomorphism G H <~> G = H
U: Univalence G, H: Group
GroupIsomorphism G H <~> G = H
U: Univalence G, H: Group
GroupIsomorphism G H <~>
{f : G <~> H & IsSemiGroupPreserving f}
U: Univalence G, H: Group
{f : G <~> H & IsSemiGroupPreserving f} <~> G = H
U: Univalence G, H: Group
{f : G <~> H & IsSemiGroupPreserving f} <~> G = H
U: Univalence
forallb : {H : Type &
{H0 : SgOp H &
{H1 : MonUnit H &
{H2 : Inverse H &
{_ : IsGroup H & Associative (flip H0)}}}}},
{f : issig_group b <~> issig_group b &
IsSemiGroupPreserving f}
U: Univalence
forallb1 : {H : Type &
{H0 : SgOp H &
{H1 : MonUnit H &
{H2 : Inverse H &
{_ : IsGroup H & Associative (flip H0)}}}}},
Contr
{b2
: {H : Type &
{H0 : SgOp H &
{H1 : MonUnit H &
{H2 : Inverse H &
{_ : IsGroup H & Associative (flip H0)}}}}} &
{f : issig_group b1 <~> issig_group b2 &
IsSemiGroupPreserving f}}
U: Univalence
forallb : {H : Type &
{H0 : SgOp H &
{H1 : MonUnit H &
{H2 : Inverse H &
{_ : IsGroup H & Associative (flip H0)}}}}},
{f : issig_group b <~> issig_group b &
IsSemiGroupPreserving f}
U: Univalence G: Type proj1: SgOp G proj0: MonUnit G proj2: Inverse G proj3: {_ : IsGroup G & Associative (flip proj1)}
U: Univalence G: Type proj1: SgOp G proj0: MonUnit G proj2: Inverse G proj3: {_ : IsGroup G & Associative (flip proj1)}
IsSemiGroupPreserving 1%equiv
exact _.
U: Univalence
forallb1 : {H : Type &
{H0 : SgOp H &
{H1 : MonUnit H &
{H2 : Inverse H &
{_ : IsGroup H & Associative (flip H0)}}}}},
Contr
{b2
: {H : Type &
{H0 : SgOp H &
{H1 : MonUnit H &
{H2 : Inverse H &
{_ : IsGroup H & Associative (flip H0)}}}}} &
{f : issig_group b1 <~> issig_group b2 &
IsSemiGroupPreserving f}}
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op)
Contr
{b2
: {H : Type &
{H0 : SgOp H &
{H1 : MonUnit H &
{H2 : Inverse H &
{_ : IsGroup H & Associative (flip H0)}}}}} &
{f : G <~> b2.1 & IsSemiGroupPreserving f}}
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op)
Contr
{y
: {H0 : SgOp G &
{H1 : MonUnit G &
{H2 : Inverse G &
{_ : IsGroup G & Associative (flip H0)}}}} &
IsSemiGroupPreserving 1%equiv}
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op)
Associative (flip op)
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op)
IsSemiGroupPreserving idmap
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op)
forally : {y
: {H0 : SgOp G &
{H1 : MonUnit G &
{H2 : Inverse G &
{_ : IsGroup G & Associative (flip H0)}}}} &
IsSemiGroupPreserving idmap},
((op; unit; neg; ax; ?Goal); ?Goal0) = y
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op)
IsSemiGroupPreserving idmap
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op)
forally : {y
: {H0 : SgOp G &
{H1 : MonUnit G &
{H2 : Inverse G &
{_ : IsGroup G & Associative (flip H0)}}}} &
IsSemiGroupPreserving idmap},
((op; unit; neg; ax; assoc_op); ?Goal) = y
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op)
forally : {y
: {H0 : SgOp G &
{H1 : MonUnit G &
{H2 : Inverse G &
{_ : IsGroup G & Associative (flip H0)}}}} &
IsSemiGroupPreserving idmap},
((op; unit; neg; ax; assoc_op);
abstract_algebra.id_sg_morphism) = y
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap
(op; unit; neg) = (op'; unit'; neg')
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap
op = op'
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap
transport
(fun_ : SgOp G => {_ : MonUnit G & Inverse G})
?p (unit; neg) = (unit'; neg')
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap
transport
(fun_ : SgOp G => {_ : MonUnit G & Inverse G})
(path_forall op op'
((funx : G =>
path_forall (op x) (op' x)
((funy : G => eq x y) : op x == op' x))
:
op == op')) (unit; neg) = (unit'; neg')
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap
(unit; neg) = (unit'; neg')
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap f:= {|
grp_homo_map := idmap;
issemigrouppreserving_grp_homo := eq
|}: GroupHomomorphism
{|
group_type := G;
group_sgop := op;
group_unit := unit;
group_inverse := neg;
group_isgroup := ax;
group_assoc_opp := assoc_op
|}
{|
group_type := G;
group_sgop := op';
group_unit := unit';
group_inverse := neg';
group_isgroup := ax';
group_assoc_opp := assoc_op'
|}
(unit; neg) = (unit'; neg')
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap f:= {|
grp_homo_map := idmap;
issemigrouppreserving_grp_homo := eq
|}: GroupHomomorphism
{|
group_type := G;
group_sgop := op;
group_unit := unit;
group_inverse := neg;
group_isgroup := ax;
group_assoc_opp := assoc_op
|}
{|
group_type := G;
group_sgop := op';
group_unit := unit';
group_inverse := neg';
group_isgroup := ax';
group_assoc_opp := assoc_op'
|}
unit = unit'
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap f:= {|
grp_homo_map := idmap;
issemigrouppreserving_grp_homo := eq
|}: GroupHomomorphism
{|
group_type := G;
group_sgop := op;
group_unit := unit;
group_inverse := neg;
group_isgroup := ax;
group_assoc_opp := assoc_op
|}
{|
group_type := G;
group_sgop := op';
group_unit := unit';
group_inverse := neg';
group_isgroup := ax';
group_assoc_opp := assoc_op'
|}
transport (fun_ : MonUnit G => Inverse G) ?p neg =
neg'
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap f:= {|
grp_homo_map := idmap;
issemigrouppreserving_grp_homo := eq
|}: GroupHomomorphism
{|
group_type := G;
group_sgop := op;
group_unit := unit;
group_inverse := neg;
group_isgroup := ax;
group_assoc_opp := assoc_op
|}
{|
group_type := G;
group_sgop := op';
group_unit := unit';
group_inverse := neg';
group_isgroup := ax';
group_assoc_opp := assoc_op'
|}
transport (fun_ : MonUnit G => Inverse G)
(grp_homo_unit f) neg = neg'
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap f:= {|
grp_homo_map := idmap;
issemigrouppreserving_grp_homo := eq
|}: GroupHomomorphism
{|
group_type := G;
group_sgop := op;
group_unit := unit;
group_inverse := neg;
group_isgroup := ax;
group_assoc_opp := assoc_op
|}
{|
group_type := G;
group_sgop := op';
group_unit := unit';
group_inverse := neg';
group_isgroup := ax';
group_assoc_opp := assoc_op'
|}
neg = neg'
U: Univalence G: Type op: SgOp G unit: MonUnit G neg: Inverse G ax: IsGroup G assoc_op: Associative (flip op) op': SgOp G unit': MonUnit G neg': Inverse G ax': IsGroup G assoc_op': Associative (flip op') eq: IsSemiGroupPreserving idmap f:= {|
grp_homo_map := idmap;
issemigrouppreserving_grp_homo := eq
|}: GroupHomomorphism
{|
group_type := G;
group_sgop := op;
group_unit := unit;
group_inverse := neg;
group_isgroup := ax;
group_assoc_opp := assoc_op
|}
{|
group_type := G;
group_sgop := op';
group_unit := unit';
group_inverse := neg';
group_isgroup := ax';
group_assoc_opp := assoc_op'
|} x: G
neg x = neg' x
exact (grp_homo_inv f x).Defined.(** A version with nicer universe variables. *)Definitionequiv_path_group@{u v | u < v} {U : Univalence} {G H : Group@{u}}
: GroupIsomorphism G H <~> (paths@{v} G H)
:= equiv_path_group'.(** ** Simple group equivalences *)(** Left multiplication is an equivalence. *)
G: Group
forallx : G, IsEquiv (sg_op x)
G: Group
forallx : G, IsEquiv (sg_op x)
G: Group x: G
IsEquiv (sg_op x)
G: Group x: G
G -> G
G: Group x: G
sg_op x o ?g == idmap
G: Group x: G
?g o sg_op x == idmap
G: Group x: G
sg_op x o sg_op x^ == idmap
G: Group x: G
sg_op x^ o sg_op x == idmap
G: Group x, y: G
x * (x^ * y) = y
G: Group x, y: G
x^ * (x * y) = y
G: Group x, y: G
x * x^ * y = 1 * y
G: Group x, y: G
x^ * x * y = 1 * y
G: Group x, y: G
x * x^ = 1
G: Group x, y: G
x^ * x = 1
G: Group x, y: G
x^ * x = 1
apply grp_inv_l.Defined.(** Right multiplication is an equivalence. *)
G: Group
forallx : G, IsEquiv (funy : G => y * x)
G: Group
forallx : G, IsEquiv (funy : G => y * x)
G: Group x: G
IsEquiv (funy : G => y * x)
G: Group x: G
G -> G
G: Group x: G
(funy : G => y * x) o ?g == idmap
G: Group x: G
?g o (funy : G => y * x) == idmap
G: Group x: G
(funy : G => y * x) o (funy : G => y * x^) == idmap
G: Group x: G
(funy : G => y * x^) o (funy : G => y * x) == idmap
G: Group x, y: G
y * x^ * x = y
G: Group x, y: G
y * x * x^ = y
G: Group x, y: G
y * (x^ * x) = y * 1
G: Group x, y: G
y * (x * x^) = y * 1
G: Group x, y: G
x^ * x = 1
G: Group x, y: G
x * x^ = 1
G: Group x, y: G
x * x^ = 1
apply grp_inv_r.Defined.(** The operation inverting group elements is an equivalence. Note that, since the order of the operation will change after inversion, this isn't a group homomorphism. *)
G: Group
IsEquiv (inv : G -> G)
G: Group
IsEquiv (inv : G -> G)
G: Group
inv o inv == idmap
exact inverse_involutive.Defined.(** ** Reasoning with equations in groups. *)SectionGroupEquations.Context {G : Group} (xyz : G).(** Inverses are involutive. *)Definitiongrp_inv_inv : x^^ = x := inverse_involutive x.(** Inverses distribute over the group operation. *)Definitiongrp_inv_op : (x * y)^ = y^ * x^ := inverse_sg_op x y.(** The inverse of the unit is the unit. *)Definitiongrp_inv_unit : mon_unit^ = mon_unit := inverse_mon_unit (G :=G).Definitiongrp_inv_V_gg : x^ * (x * y) = y
:= grp_assoc _ _ _ @ ap (.* y) (grp_inv_l x) @ grp_unit_l y.Definitiongrp_inv_g_Vg : x * (x^ * y) = y
:= grp_assoc _ _ _ @ ap (.* y) (grp_inv_r x) @ grp_unit_l y.Definitiongrp_inv_gg_V : (x * y) * y^ = x
:= (grp_assoc _ _ _)^ @ ap (x *.) (grp_inv_r y) @ grp_unit_r x.Definitiongrp_inv_gV_g : (x * y^) * y = x
:= (grp_assoc _ _ _)^ @ ap (x *.) (grp_inv_l y) @ grp_unit_r x.Definitiongrp_1g_g1 : x = y <~> 1 * x = y * 1
:= equiv_concat_r (grp_unit_r _)^ _ oE equiv_concat_l (grp_unit_l _) _.Definitiongrp_g1_1g : x = y <~> x * 1 = 1 * y
:= equiv_concat_r (grp_unit_l _)^ _ oE equiv_concat_l (grp_unit_r _) _.EndGroupEquations.(** ** Cancellation lemmas *)(** Group elements can be cancelled both on the left and the right. *)Definitiongrp_cancelL {G : Group} {xy : G} z : x = y <~> z * x = z * y
:= equiv_ap (funx => z * x) _ _.Definitiongrp_cancelR {G : Group} {xy : G} z : x = y <~> x * z = y * z
:= equiv_ap (funx => x * z) _ _.(** ** Group movement lemmas *)SectionGroupMovement.(** Since left/right multiplication is an equivalence, we can use lemmas about moving equivalences around to prove group movement lemmas. *)Context {G : Group} {xyz : G}.(** *** Moving group elements *)Definitiongrp_moveL_gM : x * z^ = y <~> x = y * z
:= equiv_moveL_equiv_M (f := funt => t * z) _ _.Definitiongrp_moveL_Mg : y^ * x = z <~> x = y * z
:= equiv_moveL_equiv_M (f := funt => y * t) _ _.Definitiongrp_moveR_gM : x = z * y^ <~> x * y = z
:= equiv_moveR_equiv_M (f := funt => t * y) _ _.Definitiongrp_moveR_Mg : y = x^ * z <~> x * y = z
:= equiv_moveR_equiv_M (f := funt => x * t) _ _.(** *** Moving inverses.*)(** These are the inverses of the previous but are included here for completeness*)Definitiongrp_moveR_gV : x = y * z <~> x * z^ = y
:= equiv_moveR_equiv_V (f := funt => t * z) _ _.Definitiongrp_moveR_Vg : x = y * z <~> y^ * x = z
:= equiv_moveR_equiv_V (f := funt => y * t) _ _.Definitiongrp_moveL_gV : x * y = z <~> x = z * y^
:= equiv_moveL_equiv_V (f := funt => t * y) _ _.Definitiongrp_moveL_Vg : x * y = z <~> y = x^ * z
:= equiv_moveL_equiv_V (f := funt => x * t) _ _.(** We close the section here so the previous lemmas generalise their assumptions. *)EndGroupMovement.SectionGroupMovement.Context {G : Group} {xyz : G}.(** *** Moving elements equal to unit. *)Definitiongrp_moveL_1M : x * y^ = 1 <~> x = y
:= equiv_concat_r (grp_unit_l _) _ oE grp_moveL_gM.Definitiongrp_moveL_M1 : y^ * x = 1 <~> x = y
:= equiv_concat_r (grp_unit_r _) _ oE grp_moveL_Mg.Definitiongrp_moveL_1V : x * y = 1 <~> x = y^
:= equiv_concat_r (grp_unit_l _) _ oE grp_moveL_gV.Definitiongrp_moveL_V1 : y * x = 1 <~> x = y^
:= equiv_concat_r (grp_unit_r _) _ oE grp_moveL_Vg.Definitiongrp_moveR_1M : 1 = y * x^ <~> x = y
:= (equiv_concat_l (grp_unit_l _) _)^-1 oE grp_moveR_gM.Definitiongrp_moveR_M1 : 1 = x^ * y <~> x = y
:= (equiv_concat_l (grp_unit_r _) _)^-1 oE grp_moveR_Mg.Definitiongrp_moveR_1V : 1 = y * x <~> x^ = y
:= (equiv_concat_l (grp_unit_l _) _)^-1 oE grp_moveR_gV.Definitiongrp_moveR_V1 : mon_unit = x * y <~> x^ = y
:= (equiv_concat_l (grp_unit_r _) _)^-1 oE grp_moveR_Vg.(** *** Cancelling elements equal to unit. *)Definitiongrp_cancelL1 : x = mon_unit <~> z * x = z
:= (equiv_concat_r (grp_unit_r _) _ oE grp_cancelL z).Definitiongrp_cancelR1 : x = mon_unit <~> x * z = z
:= (equiv_concat_r (grp_unit_l _) _) oE grp_cancelR z.EndGroupMovement.(** ** Commutation *)(** If [g] commutes with [h], then [g] commutes with the inverse [-h]. *)
G: Group g, h: G p: g * h = h * g
g * h^ = h^ * g
G: Group g, h: G p: g * h = h * g
g * h^ = h^ * g
G: Group g, h: G p: g * h = h * g
g = h^ * g * h
G: Group g, h: G p: g * h = h * g
g = h^ * (g * h)
byapply grp_moveL_Vg.Defined.(** If [g] commutes with [h] and [h'], then [g] commutes with their product [h * h']. *)
G: Group g, h, h': G p: g * h = h * g p': g * h' = h' * g
g * (h * h') = h * h' * g
G: Group g, h, h': G p: g * h = h * g p': g * h' = h' * g
g * (h * h') = h * h' * g
G: Group g, h, h': G p: g * h = h * g p': g * h' = h' * g
g * h * h' = h * h' * g
G: Group g, h, h': G p: g * h = h * g p': g * h' = h' * g
h * g * h' = h * h' * g
G: Group g, h, h': G p: g * h = h * g p': g * h' = h' * g
h * (g * h') = h * h' * g
G: Group g, h, h': G p: g * h = h * g p': g * h' = h' * g
h * (h' * g) = h * h' * g
byapply simple_associativity.Defined.(** ** Power operation *)(** For a given [g : G] we can define the function [Int -> G] sending an integer to that power of [g]. *)Definitiongrp_pow {G : Group} (g : G) (n : Int) : G
:= int_iter (g *.) n mon_unit.(** Any homomorphism respects [grp_pow]. In other words, [fun g => grp_pow g n] is natural. *)
G, H: Group f: GroupHomomorphism G H n: Int g: G
f (grp_pow g n) = grp_pow (f g) n
G, H: Group f: GroupHomomorphism G H n: Int g: G
f (grp_pow g n) = grp_pow (f g) n
G, H: Group f: GroupHomomorphism G H n: Int g: G
(funx : G => f (g * x)) == (funx : G => f g * f x)
G, H: Group f: GroupHomomorphism G H n: Int g: G
int_iter (sg_op (f g)) n (f 1) = grp_pow (f g) n
G, H: Group f: GroupHomomorphism G H n: Int g: G
int_iter (sg_op (f g)) n (f 1) = grp_pow (f g) n
apply (ap (int_iter _ n)), grp_homo_unit.Defined.(** All powers of the unit are the unit. *)
G: Group n: Int
grp_pow 1 n = 1
G: Group n: Int
grp_pow 1 n = 1
G: Group n: Int
forallx : G, x = 1 -> 1 * x = 1
G: Group n: Int
forallx : G, x = 1 -> 1^ * x = 1
G: Group n: Int
1 = 1
G: Group n: Int
1 * 1 = 1
G: Group n: Int
1^ * 1 = 1
G: Group n: Int
1 = 1
G: Group n: Int
1 * 1 = 1
apply grp_unit_r.
G: Group n: Int
1^ * 1 = 1
G: Group n: Int
1^ = 1
exact grp_inv_unit.
G: Group n: Int
1 = 1
reflexivity.Defined.(** Note that powers don't preserve the group operation as it is not commutative. This does hold in an abelian group so such a result will appear later. *)(** The next two results tell us how [grp_pow] unfolds. *)Definitiongrp_pow_succ {G : Group} (n : Int) (g : G)
: grp_pow g (n.+1)%int = g * grp_pow g n
:= int_iter_succ_l _ _ _.Definitiongrp_pow_pred {G : Group} (n : Int) (g : G)
: grp_pow g (n.-1)%int = g^ * grp_pow g n
:= int_iter_pred_l _ _ _.(** [grp_pow] satisfies an additive law of exponents. *)
G: Group m, n: Int g: G
grp_pow g (n + m)%int = grp_pow g n * grp_pow g m
G: Group m, n: Int g: G
grp_pow g (n + m)%int = grp_pow g n * grp_pow g m
G: Group m, n: Int g: G
int_iter (sg_op g) n (int_iter (sg_op g) m 1) =
grp_pow g n * grp_pow g m
G: Group m: Int g: G
int_iter (sg_op g) m 1 = 1 * grp_pow g m
G: Group m: Int n: nat g: G IHn: int_iter (sg_op g) n (int_iter (sg_op g) m 1) = grp_pow g n * grp_pow g m
int_iter (sg_op g) n.+1%int (int_iter (sg_op g) m 1) =
grp_pow g n.+1%int * grp_pow g m
G: Group m: Int n: nat g: G IHn: int_iter (sg_op g) (- n)%int (int_iter (sg_op g) m 1) =
grp_pow g (- n)%int * grp_pow g m
int_iter (sg_op g) (- n).-1%int
(int_iter (sg_op g) m 1) =
grp_pow g (- n).-1%int * grp_pow g m
G: Group m: Int n: nat g: G IHn: int_iter (sg_op g) n (int_iter (sg_op g) m 1) = grp_pow g n * grp_pow g m
int_iter (sg_op g) n.+1%int (int_iter (sg_op g) m 1) =
grp_pow g n.+1%int * grp_pow g m
G: Group m: Int n: nat g: G IHn: int_iter (sg_op g) (- n)%int (int_iter (sg_op g) m 1) =
grp_pow g (- n)%int * grp_pow g m
int_iter (sg_op g) (- n).-1%int
(int_iter (sg_op g) m 1) =
grp_pow g (- n).-1%int * grp_pow g m
G: Group m: Int n: nat g: G IHn: int_iter (sg_op g) n (int_iter (sg_op g) m 1) = grp_pow g n * grp_pow g m
g * int_iter (sg_op g) n (int_iter (sg_op g) m 1) =
g * grp_pow g n * grp_pow g m
G: Group m: Int n: nat g: G IHn: int_iter (sg_op g) (- n)%int (int_iter (sg_op g) m 1) =
grp_pow g (- n)%int * grp_pow g m
int_iter (sg_op g) (- n).-1%int
(int_iter (sg_op g) m 1) =
grp_pow g (- n).-1%int * grp_pow g m
G: Group m: Int n: nat g: G IHn: int_iter (sg_op g) n (int_iter (sg_op g) m 1) = grp_pow g n * grp_pow g m
g * int_iter (sg_op g) n (int_iter (sg_op g) m 1) =
g * grp_pow g n * grp_pow g m
G: Group m: Int n: nat g: G IHn: int_iter (sg_op g) (- n)%int (int_iter (sg_op g) m 1) =
grp_pow g (- n)%int * grp_pow g m
g^ *
int_iter (sg_op g) (- n)%int (int_iter (sg_op g) m 1) =
g^ * grp_pow g (- n)%int * grp_pow g m
1,2 : rhs_V srapply associativity;
apply ap, IHn.Defined.(** [grp_pow] commutes negative exponents to powers of the inverse *)
G: Group n: Int g: G
grp_pow g (- n)%int = grp_pow g^ n
G: Group n: Int g: G
grp_pow g (- n)%int = grp_pow g^ n
G: Group n: Int g: G
int_iter (sg_op g)^-1 n 1 = grp_pow g^ n
G: Group n: Int g: G
int_iter (sg_op g^) n 1 = int_iter (sg_op g^) n 1
(* These agree, except for the proofs that [sg_op g^] is an equivalence. *)apply int_iter_agree.Defined.(** Using a negative power in [grp_pow] is the same as first using a positive power and then inverting the result. *)
G: Group m: Int g: G
grp_pow g (- m)%int = (grp_pow g m)^
G: Group m: Int g: G
grp_pow g (- m)%int = (grp_pow g m)^
G: Group m: Int g: G
grp_pow g (- m)%int * grp_pow g m = 1
G: Group m: Int g: G
grp_pow g (- m + m)%int = 1
byrewrite int_add_neg_l.Defined.(** Combining the two previous results gives that a power of an inverse is the inverse of the power. *)
G: Group n: Int g: G
grp_pow g^ n = (grp_pow g n)^
G: Group n: Int g: G
grp_pow g^ n = (grp_pow g n)^
G: Group n: Int g: G
grp_pow g (- n)%int = (grp_pow g n)^
apply grp_pow_neg_inv.Defined.(** [grp_pow] satisfies a multiplicative law of exponents. *)
G: Group m, n: Int g: G
grp_pow g (m * n)%int = grp_pow (grp_pow g m) n
G: Group m, n: Int g: G
grp_pow g (m * n)%int = grp_pow (grp_pow g m) n
G: Group m: Int g: G
grp_pow g (m * 0)%int = grp_pow (grp_pow g m) 0%int
G: Group m: Int n: nat g: G IHn: grp_pow g (m * n)%int = grp_pow (grp_pow g m) n
grp_pow g (m * n.+1)%int =
grp_pow (grp_pow g m) n.+1%int
G: Group m: Int n: nat g: G IHn: grp_pow g (m * - n)%int = grp_pow (grp_pow g m) (- n)%int
grp_pow g (m * (- n).-1)%int =
grp_pow (grp_pow g m) (- n).-1%int
G: Group m: Int g: G
grp_pow g (m * 0)%int = grp_pow (grp_pow g m) 0%int
G: Group m: Int g: G
grp_pow g (m * 0)%int = 1
byrewrite int_mul_0_r.
G: Group m: Int n: nat g: G IHn: grp_pow g (m * n)%int = grp_pow (grp_pow g m) n
grp_pow g (m * n.+1)%int =
grp_pow (grp_pow g m) n.+1%int
G: Group m: Int n: nat g: G IHn: grp_pow g (m * n)%int = grp_pow (grp_pow g m) n
grp_pow g (m + m * n)%int =
grp_pow (grp_pow g m) n.+1%int
G: Group m: Int n: nat g: G IHn: grp_pow g (m * n)%int = grp_pow (grp_pow g m) n
grp_pow g m * grp_pow g (m * n)%int =
grp_pow (grp_pow g m) n.+1%int
G: Group m: Int n: nat g: G IHn: grp_pow g (m * n)%int = grp_pow (grp_pow g m) n
grp_pow g m * grp_pow g (m * n)%int =
grp_pow g m * grp_pow (grp_pow g m) n
apply grp_cancelL, IHn.
G: Group m: Int n: nat g: G IHn: grp_pow g (m * - n)%int = grp_pow (grp_pow g m) (- n)%int
grp_pow g (m * (- n).-1)%int =
grp_pow (grp_pow g m) (- n).-1%int
G: Group m: Int n: nat g: G IHn: grp_pow g (m * - n)%int = grp_pow (grp_pow g m) (- n)%int
grp_pow g (- m + m * - n)%int =
grp_pow (grp_pow g m) (- n).-1%int
G: Group m: Int n: nat g: G IHn: grp_pow g (m * - n)%int = grp_pow (grp_pow g m) (- n)%int
grp_pow g (- m)%int * grp_pow g (m * - n)%int =
grp_pow (grp_pow g m) (- n).-1%int
G: Group m: Int n: nat g: G IHn: grp_pow g (m * - n)%int = grp_pow (grp_pow g m) (- n)%int
(grp_pow g m)^ * grp_pow g (m * - n)%int =
grp_pow (grp_pow g m) (- n).-1%int
G: Group m: Int n: nat g: G IHn: grp_pow g (m * - n)%int = grp_pow (grp_pow g m) (- n)%int
(grp_pow g m)^ * grp_pow g (m * - n)%int =
(grp_pow g m)^ * grp_pow (grp_pow g m) (- n)%int
apply grp_cancelL, IHn.Defined.(** If [h] commutes with [g], then [h] commutes with [grp_pow g n]. *)
G: Group n: Int g, h: G p: h * g = g * h
h * grp_pow g n = grp_pow g n * h
G: Group n: Int g, h: G p: h * g = g * h
h * grp_pow g n = grp_pow g n * h
G: Group g, h: G p: h * g = g * h
h * grp_pow g 0%int = grp_pow g 0%int * h
G: Group n: nat g, h: G p: h * g = g * h IHn: h * grp_pow g n = grp_pow g n * h
h * grp_pow g n.+1%int = grp_pow g n.+1%int * h
G: Group n: nat g, h: G p: h * g = g * h IHn: h * grp_pow g (- n)%int = grp_pow g (- n)%int * h
h * grp_pow g (- n).-1%int =
grp_pow g (- n).-1%int * h
G: Group g, h: G p: h * g = g * h
h * grp_pow g 0%int = grp_pow g 0%int * h
byapply grp_g1_1g.
G: Group n: nat g, h: G p: h * g = g * h IHn: h * grp_pow g n = grp_pow g n * h
h * grp_pow g n.+1%int = grp_pow g n.+1%int * h
G: Group n: nat g, h: G p: h * g = g * h IHn: h * grp_pow g n = grp_pow g n * h
h * (g * grp_pow g n) = g * grp_pow g n * h
napply grp_commutes_op; assumption.
G: Group n: nat g, h: G p: h * g = g * h IHn: h * grp_pow g (- n)%int = grp_pow g (- n)%int * h
h * grp_pow g (- n).-1%int =
grp_pow g (- n).-1%int * h
G: Group n: nat g, h: G p: h * g = g * h IHn: h * grp_pow g (- n)%int = grp_pow g (- n)%int * h
h * (g^ * grp_pow g (- n)%int) =
g^ * grp_pow g (- n)%int * h
G: Group n: nat g, h: G p: h * g = g * h IHn: h * grp_pow g (- n)%int = grp_pow g (- n)%int * h
h * g^ = g^ * h
G: Group n: nat g, h: G p: h * g = g * h IHn: h * grp_pow g (- n)%int = grp_pow g (- n)%int * h
h * grp_pow g (- n)%int = grp_pow g (- n)%int * h
G: Group n: nat g, h: G p: h * g = g * h IHn: h * grp_pow g (- n)%int = grp_pow g (- n)%int * h
h * g^ = g^ * h
apply grp_commutes_inv, p.Defined.(** [grp_pow g n] commutes with [g]. *)
G: Group n: Int g: G
g * grp_pow g n = grp_pow g n * g
G: Group n: Int g: G
g * grp_pow g n = grp_pow g n * g
byapply grp_pow_commutes.Defined.(** If [g] and [h] commute, then [grp_pow (g * h) n] = (grp_pow g n) * (grp_pow h n)]. *)
G: Group n: Int g, h: G c: g * h = h * g
grp_pow (g * h) n = grp_pow g n * grp_pow h n
G: Group n: Int g, h: G c: g * h = h * g
grp_pow (g * h) n = grp_pow g n * grp_pow h n
G: Group g, h: G c: g * h = h * g
grp_pow (g * h) 0%int =
grp_pow g 0%int * grp_pow h 0%int
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) n = grp_pow g n * grp_pow h n
grp_pow (g * h) n.+1%int =
grp_pow g n.+1%int * grp_pow h n.+1%int
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
grp_pow (g * h) (- n).-1%int =
grp_pow g (- n).-1%int * grp_pow h (- n).-1%int
G: Group g, h: G c: g * h = h * g
grp_pow (g * h) 0%int =
grp_pow g 0%int * grp_pow h 0%int
G: Group g, h: G c: g * h = h * g
1 = 1 * 1
symmetry; napply grp_unit_r.
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) n = grp_pow g n * grp_pow h n
grp_pow (g * h) n.+1%int =
grp_pow g n.+1%int * grp_pow h n.+1%int
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) n = grp_pow g n * grp_pow h n
g * h * grp_pow (g * h) n =
g * grp_pow g n * (h * grp_pow h n)
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) n = grp_pow g n * grp_pow h n
g * h * (grp_pow g n * grp_pow h n) =
g * grp_pow g n * (h * grp_pow h n)
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) n = grp_pow g n * grp_pow h n
g * h * grp_pow g n * grp_pow h n =
g * grp_pow g n * h * grp_pow h n
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) n = grp_pow g n * grp_pow h n
g * h * grp_pow g n = g * grp_pow g n * h
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) n = grp_pow g n * grp_pow h n
g * (h * grp_pow g n) = g * (grp_pow g n * h)
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) n = grp_pow g n * grp_pow h n
h * grp_pow g n = grp_pow g n * h
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) n = grp_pow g n * grp_pow h n
h * g = g * h
exact c^%path.
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
grp_pow (g * h) (- n).-1%int =
grp_pow g (- n).-1%int * grp_pow h (- n).-1%int
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
grp_pow (g * h) (- n).-1%int =
grp_pow g (- n).-1%int * grp_pow h (- n).-1%int
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
(g * h)^ * (grp_pow g (- n)%int * grp_pow h (- n)%int) =
g^ * grp_pow g (- n)%int * (h^ * grp_pow h (- n)%int)
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
(g * h)^ * grp_pow g (- n)%int * grp_pow h (- n)%int =
g^ * grp_pow g (- n)%int * h^ * grp_pow h (- n)%int
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
(g * h)^ * grp_pow g (- n)%int =
g^ * grp_pow g (- n)%int * h^
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
(h * g)^ * grp_pow g (- n)%int =
g^ * grp_pow g (- n)%int * h^
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
g^ * h^ * grp_pow g (- n)%int =
g^ * grp_pow g (- n)%int * h^
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
g^ * (h^ * grp_pow g (- n)%int) =
g^ * (grp_pow g (- n)%int * h^)
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
h^ * grp_pow g (- n)%int = grp_pow g (- n)%int * h^
G: Group n: nat g, h: G c: g * h = h * g IHn: grp_pow (g * h) (- n)%int = grp_pow g (- n)%int * grp_pow h (- n)%int
h^ * g = g * h^
symmetry; apply grp_commutes_inv, c.Defined.(** ** The category of Groups *)(** ** Groups together with homomorphisms form a 1-category whose equivalences are the group isomorphisms. *)Instanceisgraph_group : IsGraph Group
:= Build_IsGraph Group GroupHomomorphism.(** We add this coercion to make it easier to use a group isomorphism where Coq expects a category morphism. *)DefinitionisHom_GroupIsomorphism (GH : Group) : GroupIsomorphism G H -> Hom G H := idmap.CoercionisHom_GroupIsomorphism : GroupIsomorphism >-> Hom.Instanceis01cat_group : Is01Cat Group :=
Build_Is01Cat Group _ (@grp_homo_id) (@grp_homo_compose).(** Helper notation so that the wildcat instances can easily be inferred. *)Local Notationgrp_homo_map' A B := (@grp_homo_map A B : _ -> (group_type A $-> _)).Instanceis2graph_group : Is2Graph Group
:= funAB => isgraph_induced (grp_homo_map' A B).Instanceisgraph_grouphomomorphism {AB : Group} : IsGraph (A $-> B)
:= isgraph_induced (grp_homo_map' A B).Instanceis01cat_grouphomomorphism {AB : Group} : Is01Cat (A $-> B)
:= is01cat_induced (grp_homo_map' A B).Instanceis0gpd_grouphomomorphism {AB : Group}: Is0Gpd (A $-> B)
:= is0gpd_induced (grp_homo_map' A B).
A, B, C: Group h: B $-> C
Is0Functor (cat_postcomp A h)
A, B, C: Group h: B $-> C
Is0Functor (cat_postcomp A h)
A, B, C: Group h: B $-> C
forallab : A $-> B,
(a $-> b) -> cat_postcomp A h a $-> cat_postcomp A h b
intros f g p a ; exact (ap h (p a)).Defined.
A, B, C: Group h: A $-> B
Is0Functor (cat_precomp C h)
A, B, C: Group h: A $-> B
Is0Functor (cat_precomp C h)
A, B, C: Group h: A $-> B
forallab : B $-> C,
(a $-> b) -> cat_precomp C h a $-> cat_precomp C h b
intros [f ?] [g ?] p a ; exact (p (h a)).Defined.(** Group forms a 1Cat *)
Is1Cat Group
Is1Cat Group
by rapply Build_Is1Cat.Defined.(** Under [Funext], the category of groups has morphism extensionality. *)
intros []; reflexivity.Defined.(** Group isomorphisms become equivalences in the category of groups. *)
HasEquivs Group
HasEquivs Group
Group -> Group -> Type
forallab : Group, (a $-> b) -> Type
forallab : Group, ?CatEquiv' a b -> a $-> b
forall (ab : Group) (f : a $-> b),
?CatIsEquiv' a b f -> ?CatEquiv' a b
forallab : Group, ?CatEquiv' a b -> b $-> a
forall (ab : Group) (f : ?CatEquiv' a b),
?CatIsEquiv' a b (?cate_fun' a b f)
forall (ab : Group) (f : a $-> b)
(fe : ?CatIsEquiv' a b f),
?cate_fun' a b (?cate_buildequiv' a b f fe) $== f
forall (ab : Group) (f : ?CatEquiv' a b),
?cate_inv' a b f $o ?cate_fun' a b f $== Id a
forall (ab : Group) (f : ?CatEquiv' a b),
?cate_fun' a b f $o ?cate_inv' a b f $== Id b
forall (ab : Group) (f : a $-> b) (g : b $-> a),
f $o g $== Id b ->
g $o f $== Id a -> ?CatIsEquiv' a b f
Group -> Group -> Type
exact GroupIsomorphism.
forallab : Group, (a $-> b) -> Type
exact (funGHf => IsEquiv f).
forallab : Group, GroupIsomorphism a b -> a $-> b
intros G H f; exact f.
forall (ab : Group) (f : a $-> b),
(fun (GH : Group) (f0 : G $-> H) => IsEquiv f0) a b f ->
GroupIsomorphism a b
exact Build_GroupIsomorphism.
forallab : Group, GroupIsomorphism a b -> b $-> a
intros G H; exact grp_iso_inverse.
forall (ab : Group) (f : GroupIsomorphism a b),
(fun (GH : Group) (f0 : G $-> H) => IsEquiv f0) a b
((fun (GH : Group) (f0 : GroupIsomorphism G H) =>
isHom_GroupIsomorphism G H f0) a b f)
cbn; exact _.
forall (ab : Group) (f : a $-> b)
(fe : (fun (GH : Group) (f0 : G $-> H) => IsEquiv f0)
a b f),
(fun (GH : Group) (f0 : GroupIsomorphism G H) =>
isHom_GroupIsomorphism G H f0) a b
{| grp_iso_homo := f; isequiv_group_iso := fe |} $==
f
reflexivity.
forall (ab : Group) (f : GroupIsomorphism a b),
(fun (GH : Group) (x : GroupIsomorphism G H) =>
isHom_GroupIsomorphism H G (grp_iso_inverse x)) a b f $o
(fun (GH : Group) (f0 : GroupIsomorphism G H) =>
isHom_GroupIsomorphism G H f0) a b f $== Id a
intros ????; apply eissect.
forall (ab : Group) (f : GroupIsomorphism a b),
(fun (GH : Group) (f0 : GroupIsomorphism G H) =>
isHom_GroupIsomorphism G H f0) a b f $o
(fun (GH : Group) (x : GroupIsomorphism G H) =>
isHom_GroupIsomorphism H G (grp_iso_inverse x)) a b f $==
Id b
intros ????; apply eisretr.
forall (ab : Group) (f : a $-> b) (g : b $-> a),
f $o g $== Id b ->
g $o f $== Id a ->
(fun (GH : Group) (f0 : G $-> H) => IsEquiv f0) a b f
G, H: Group f: G $-> H g: H $-> G p: f $o g $== Id H q: g $o f $== Id G
(fun (GH : Group) (f : G $-> H) => IsEquiv f) G H f
exact (isequiv_adjointify f g p q).Defined.
H: Funext
Is1Cat_Strong Group
H: Funext
Is1Cat_Strong Group
H: Funext
forall (abcd : Group) (f : a $-> b) (g : b $-> c)
(h : c $-> d), h $o g $o f = h $o (g $o f)
H: Funext
forall (abcd : Group) (f : a $-> b) (g : b $-> c)
(h : c $-> d), h $o (g $o f) = h $o g $o f
H: Funext
forall (ab : Group) (f : a $-> b), Id b $o f = f
H: Funext
forall (ab : Group) (f : a $-> b), f $o Id a = f
all: intros; apply equiv_path_grouphomomorphism; intro; reflexivity.Defined.(** The [group_type] map is a 1-functor. *)
Is0Functor group_type
Is0Functor group_type
forallab : Group, (a $-> b) -> a $-> b
exact @grp_homo_map.Defined.
Is1Functor group_type
Is1Functor group_type
byapply Build_Is1Functor.Defined.(** The [ptype_group] map is a 1-functor. *)
Is0Functor ptype_group
Is0Functor ptype_group
forallab : Group, (a $-> b) -> a $-> b
rapply @pmap_GroupHomomorphism.Defined.
Is1Functor ptype_group
Is1Functor ptype_group
apply Build_Is1Functor; intros; byapply phomotopy_homotopy_hset.Defined.(** Given a group element [a0 : A] over [b : B], multiplication by [a] establishes an equivalence between the kernel and the fiber over [b]. *)
A, B: Group f: GroupHomomorphism A B b: B
hfiber f b -> hfiber f b <~> hfiber f 1
A, B: Group f: GroupHomomorphism A B b: B
hfiber f b -> hfiber f b <~> hfiber f 1
A, B: Group f: GroupHomomorphism A B b: B a0: A p: f a0 = b
hfiber f b <~> hfiber f 1
A, B: Group f: GroupHomomorphism A B b: B a0: A p: f a0 = b
hfiber f b <~> hfiber f (b * b^)
A, B: Group f: GroupHomomorphism A B b: B a0: A p: f a0 = b
hfiber f b -> hfiber f (b * b^)
A, B: Group f: GroupHomomorphism A B b: B a0: A p: f a0 = b
IsEquiv ?equiv_fun
A, B: Group f: GroupHomomorphism A B b: B a0: A p: f a0 = b
hfiber f b -> hfiber f (b * b^)
A, B: Group f: GroupHomomorphism A B b: B a0: A p: f a0 = b
(funy : B => y * b^) o f ==
f o (funy : A => y * a0^)
A, B: Group f: GroupHomomorphism A B b: B a0: A p: f a0 = b a: A
f (a * a0^) = f a * b^
A, B: Group f: GroupHomomorphism A B b: B a0: A p: f a0 = b a: A
f (a * a0^) = f a * (f a0)^
exact (grp_homo_op f _ _ @ ap (f a *.) (grp_homo_inv f a0)).
A, B: Group f: GroupHomomorphism A B b: B a0: A p: f a0 = b
IsEquiv
(functor_hfiber
((funa : A =>
((grp_homo_op f a (inv a0) @
ap (sg_op (f a)) (grp_homo_inv f a0)) @
ap (funx : B => f a * inv x) p)^%path
:
f a * b^ = f (a * a0^))
:
(funy : B => y * b^) o f ==
f o (funy : A => y * a0^)) b)
srapply isequiv_functor_hfiber.Defined.(** ** The trivial group *)
Group
Group
snapply (Build_Group' Unit (fun__ => tt) tt (fun_ => tt));
only1: exact _; byintros [].Defined.(** Map out of trivial group. *)
intros ??; symmetry; apply grp_unit_l.Defined.(** Map into trivial group. *)
G: Group
GroupHomomorphism G grp_trivial
G: Group
GroupHomomorphism G grp_trivial
G: Group
G -> grp_trivial
G: Group
IsSemiGroupPreserving ?grp_homo_map
G: Group
IsSemiGroupPreserving (fun_ : G => tt)
intros ??; symmetry; exact (grp_unit_l _).Defined.(** Group is a pointed category. *)
IsPointedCat Group
IsPointedCat Group
Group
IsInitial ?zero_object
IsTerminal ?zero_object
Group
exact grp_trivial.
IsInitial grp_trivial
G: Group
{f : grp_trivial $-> G &
forallg : grp_trivial $-> G, f $== g}
G: Group
forallg : grp_trivial $-> G, grp_trivial_rec G $== g
G: Group g: grp_trivial $-> G
group_unit = g tt
exact (grp_homo_unit g)^%path.
IsTerminal grp_trivial
G: Group
{f : G $-> grp_trivial &
forallg : G $-> grp_trivial, f $== g}
G: Group
forallg : G $-> grp_trivial,
grp_trivial_corec G $== g
G: Group g: G $-> grp_trivial x: G
tt = g x
apply path_unit.Defined.Definitiongrp_homo_const {GH : Group} : GroupHomomorphism G H
:= zero_morphism.(** ** Opposite Group *)(** The opposite group of a group is the group with the same elements but with the group operation reversed. Our technical choice for including a redundant associativity axiom in the definition of a group from before comes into play here. All we have to do to define the opposite group is to shuffle some data around. Since we are only shuffling, this operation becomes definitionally involutive. We make this choice because it is a great help in later proofs. *)
Group -> Group
Group -> Group
G: Group
Group
G: Group
Type
G: Group
SgOp ?group_type
G: Group
MonUnit ?group_type
G: Group
Inverse ?group_type
G: Group
IsHSet ?group_type
G: Group
Associative sg_op
G: Group
LeftIdentity sg_op 1
G: Group
RightIdentity sg_op 1
G: Group
LeftInverse sg_op inv 1
G: Group
RightInverse sg_op inv 1
G: Group
Associative (flip ?group_sgop)
G: Group
Type
exact G.
G: Group
SgOp G
exact (flip (.*.)).
G: Group
MonUnit G
exact1.
G: Group
Inverse G
exact (^).
G: Group
IsHSet G
exact _.
G: Group
Associative sg_op
exact group_assoc_opp.
G: Group
LeftIdentity sg_op 1
exact grp_unit_r.
G: Group
RightIdentity sg_op 1
exact grp_unit_l.
G: Group
LeftInverse sg_op inv 1
exact grp_inv_r.
G: Group
RightInverse sg_op inv 1
exact grp_inv_l.
G: Group
Associative (flip (flip sg_op))
exact grp_assoc.Defined.(** Taking the inverse is an isomorphism from the group to the opposite group. *)
G: Group
G ≅ grp_op G
G: Group
G ≅ grp_op G
G: Group
GroupHomomorphism G (grp_op G)
G: Group
IsEquiv ?grp_iso_homo
G: Group
GroupHomomorphism G (grp_op G)
G: Group
G -> grp_op G
G: Group
IsSemiGroupPreserving ?grp_homo_map
G: Group
G -> grp_op G
exact inv.
G: Group
IsSemiGroupPreserving inv
G: Group x, y: G
(x * y)^ = x^ * y^
rapply grp_inv_op.
G: Group
IsEquiv
{|
grp_homo_map := inv;
issemigrouppreserving_grp_homo :=
(funxy : G => grp_inv_op y x)
:
IsSemiGroupPreserving inv
|}
simpl; exact _.Defined.(** ** The direct product of groups *)(** The cartesian product of the underlying sets of two groups has a natural group structure. We call this the direct product of groups. *)
Group -> Group -> Group
Group -> Group -> Group
G, H: Group
Group
G, H: Group
SgOp (G * H)
G, H: Group
MonUnit (G * H)
G, H: Group
Inverse (G * H)
G, H: Group
IsGroup (G * H)
G, H: Group
SgOp (G * H)
G, H: Group
MonUnit (G * H)
G, H: Group
Inverse (G * H)
G, H: Group
IsHSet (G * H)
G, H: Group
Associative sg_op
G, H: Group
LeftIdentity sg_op 1
G, H: Group
RightIdentity sg_op 1
G, H: Group
LeftInverse sg_op inv 1
G, H: Group
RightInverse sg_op inv 1
G, H: Group
SgOp (G * H)
G, H: Group g1: G h1: H g2: G h2: H
(G * H)%type
exact (g1 * g2, h1 * h2).
G, H: Group
MonUnit (G * H)
exact (1, 1).
G, H: Group
Inverse (G * H)
exact (functor_prod inv inv).
G, H: Group
IsHSet (G * H)
exact _.
G, H: Group
Associative sg_op
intros x y z; apply path_prod'; apply simple_associativity.
G, H: Group
LeftIdentity sg_op 1
intros x; apply path_prod'; apply left_identity.
G, H: Group
RightIdentity sg_op 1
intros x; apply path_prod'; apply right_identity.
G, H: Group
LeftInverse sg_op inv 1
intros x; apply path_prod'; apply left_inverse.
G, H: Group
RightInverse sg_op inv 1
intros x; apply path_prod'; apply right_inverse.Defined.(** Maps into the direct product can be built by mapping separately into each factor. *)
G, H, K: Group f: K $-> G g: K $-> H
K $-> grp_prod G H
G, H, K: Group f: K $-> G g: K $-> H
K $-> grp_prod G H
G, H, K: Group f: K $-> G g: K $-> H
K -> grp_prod G H
G, H, K: Group f: K $-> G g: K $-> H
IsSemiGroupPreserving ?grp_homo_map
G, H, K: Group f: K $-> G g: K $-> H
K -> grp_prod G H
exact (funx : K => (f x, g x)).
G, H, K: Group f: K $-> G g: K $-> H
IsSemiGroupPreserving (funx : K => (f x, g x))
G, H, K: Group f: K $-> G g: K $-> H x, y: K
(f (x * y), g (x * y)) = (f x, g x) * (f y, g y)
apply path_prod'; apply grp_homo_op.Defined.(** [grp_prod_corec] satisfies a definitional naturality property. *)Definitiongrp_prod_corec_natural {XYAB : Group}
(f : X $-> Y) (g0 : Y $-> A) (g1 : Y $-> B)
: grp_prod_corec g0 g1 $o f $== grp_prod_corec (g0 $o f) (g1 $o f)
:= fun_ => idpath.(** The left factor injects into the direct product. *)Definitiongrp_prod_inl {HK : Group}
: H $-> grp_prod H K
:= grp_prod_corec grp_homo_id grp_homo_const.(** The left injection is an embedding. *)
H, K: Group
IsEmbedding grp_prod_inl
H, K: Group
IsEmbedding grp_prod_inl
H, K: Group
IsInjective grp_prod_inl
H, K: Group h0, h1: H p: (h0, group_unit) = (h1, group_unit)
h0 = h1
exact (fst ((equiv_path_prod _ _)^-1 p)).Defined.(** The right factor injects into the direct product. *)Definitiongrp_prod_inr {HK : Group}
: K $-> grp_prod H K
:= grp_prod_corec grp_homo_const grp_homo_id.(** The right injection is an embedding. *)
H, K: Group
IsEmbedding grp_prod_inr
H, K: Group
IsEmbedding grp_prod_inr
H, K: Group
IsInjective grp_prod_inr
H, K: Group k0, k1: K q: (group_unit, k0) = (group_unit, k1)
k0 = k1
exact (snd ((equiv_path_prod _ _)^-1 q)).Defined.(** Given two pairs of isomorphic groups, their pairwise direct products are isomorphic. *)
A, B, C, D: Group
A ≅ B -> C ≅ D -> grp_prod A C ≅ grp_prod B D
A, B, C, D: Group
A ≅ B -> C ≅ D -> grp_prod A C ≅ grp_prod B D
A, B, C, D: Group f: A ≅ B g: C ≅ D
grp_prod A C ≅ grp_prod B D
A, B, C, D: Group f: A ≅ B g: C ≅ D
grp_prod A C <~> grp_prod B D
A, B, C, D: Group f: A ≅ B g: C ≅ D
IsSemiGroupPreserving ?f
A, B, C, D: Group f: A ≅ B g: C ≅ D
IsSemiGroupPreserving equiv_functor_prod
A, B, C, D: Group f: A ≅ B g: C ≅ D
IsSemiGroupPreserving (functor_prod f g)
A, B, C, D: Group f: A ≅ B g: C ≅ D
IsSemiGroupPreserving
(funz : A * C => (f (fst z), g (snd z)))
A, B, C, D: Group f: A ≅ B g: C ≅ D x, y: (A * C)%type
(f (fst (x * y)), g (snd (x * y))) =
(f (fst x), g (snd x)) * (f (fst y), g (snd y))
A, B, C, D: Group f: A ≅ B g: C ≅ D x, y: (A * C)%type
fst (f (fst (x * y)), g (snd (x * y))) =
fst ((f (fst x), g (snd x)) * (f (fst y), g (snd y)))
A, B, C, D: Group f: A ≅ B g: C ≅ D x, y: (A * C)%type
snd (f (fst (x * y)), g (snd (x * y))) =
snd ((f (fst x), g (snd x)) * (f (fst y), g (snd y)))
1,2: apply grp_homo_op.Defined.(** The first projection of the direct product. *)
G, H: Group
GroupHomomorphism (grp_prod G H) G
G, H: Group
GroupHomomorphism (grp_prod G H) G
G, H: Group
grp_prod G H -> G
G, H: Group
IsSemiGroupPreserving ?grp_homo_map
G, H: Group
IsSemiGroupPreserving fst
intros ? ?; reflexivity.Defined.(** The first projection is a surjection. *)Instanceissurj_grp_prod_pr1 {GH : Group}
: IsSurjection (@grp_prod_pr1 G H)
:= issurj_retr grp_prod_inl (fun_ => idpath).(** The second projection of the direct product. *)
G, H: Group
GroupHomomorphism (grp_prod G H) H
G, H: Group
GroupHomomorphism (grp_prod G H) H
G, H: Group
grp_prod G H -> H
G, H: Group
IsSemiGroupPreserving ?grp_homo_map
G, H: Group
IsSemiGroupPreserving snd
intros ? ?; reflexivity.Defined.(** Pairs in direct products can be decomposed *)
snapply grp_unit_l.Defined.(** The second projection is a surjection. *)Instanceissurj_grp_prod_pr2 {GH : Group}
: IsSurjection (@grp_prod_pr2 G H)
:= issurj_retr grp_prod_inr (fun_ => idpath).(** [Group] is a category with binary products given by the direct product. *)
HasBinaryProducts Group
HasBinaryProducts Group
G, H: Group
BinaryProduct G H
G, H: Group
Group
G, H: Group
?cat_binprod' $-> G
G, H: Group
?cat_binprod' $-> H
G, H: Group
forallz : Group,
(z $-> G) -> (z $-> H) -> z $-> ?cat_binprod'
G, H: Group
forall (z : Group) (f : z $-> G) (g : z $-> H),
?cat_pr1 $o ?cat_binprod_corec z f g $== f
G, H: Group
forall (z : Group) (f : z $-> G) (g : z $-> H),
?cat_pr2 $o ?cat_binprod_corec z f g $== g
G, H: Group
forall (z : Group) (fg : z $-> ?cat_binprod'),
?cat_pr1 $o f $== ?cat_pr1 $o g ->
?cat_pr2 $o f $== ?cat_pr2 $o g -> f $== g
G, H: Group
Group
exact (grp_prod G H).
G, H: Group
grp_prod G H $-> G
exact grp_prod_pr1.
G, H: Group
grp_prod G H $-> H
exact grp_prod_pr2.
G, H: Group
forallz : Group,
(z $-> G) -> (z $-> H) -> z $-> grp_prod G H
G, H, K: Group
(K $-> G) -> (K $-> H) -> K $-> grp_prod G H
exact grp_prod_corec.
G, H: Group
forall (z : Group) (f : z $-> G) (g : z $-> H),
grp_prod_pr1 $o
(funK : Group => grp_prod_corec) z f g $== f
G, H, K: Group f: K $-> G g: K $-> H
grp_prod_pr1 $o
(funK : Group => grp_prod_corec) K f g $== f
exact (Id _).
G, H: Group
forall (z : Group) (f : z $-> G) (g : z $-> H),
grp_prod_pr2 $o
(funK : Group => grp_prod_corec) z f g $== g
G, H, K: Group f: K $-> G g: K $-> H
grp_prod_pr2 $o
(funK : Group => grp_prod_corec) K f g $== g
exact (Id _).
G, H: Group
forall (z : Group) (fg : z $-> grp_prod G H),
grp_prod_pr1 $o f $== grp_prod_pr1 $o g ->
grp_prod_pr2 $o f $== grp_prod_pr2 $o g -> f $== g
G, H, K: Group f, g: K $-> grp_prod G H p: grp_prod_pr1 $o f $== grp_prod_pr1 $o g q: grp_prod_pr2 $o f $== grp_prod_pr2 $o g a: K
f a = g a
exact (path_prod' (p a) (q a)).Defined.(** *** Properties of maps to and from the trivial group *)
IsInitial grp_trivial
IsInitial grp_trivial
G: Group
{f : grp_trivial $-> G &
forallg : grp_trivial $-> G, f $== g}
G: Group
forallg : grp_trivial $-> G, grp_trivial_rec G $== g
G: Group g: grp_trivial $-> G
grp_trivial_rec G tt = g tt
exact (grp_homo_unit g)^%path.Defined.
H: Funext G: Group
Contr (GroupHomomorphism grp_trivial G)
H: Funext G: Group
Contr (GroupHomomorphism grp_trivial G)
H: Funext G: Group
GroupHomomorphism grp_trivial G
H: Funext G: Group
forally : GroupHomomorphism grp_trivial G,
?center = y
H: Funext G: Group
forally : GroupHomomorphism grp_trivial G,
grp_trivial_rec G = y
H: Funext G: Group g: GroupHomomorphism grp_trivial G
grp_trivial_rec G = g
H: Funext G: Group g: GroupHomomorphism grp_trivial G
grp_trivial_rec G == g
H: Funext G: Group g: GroupHomomorphism grp_trivial G
grp_trivial_rec G tt = g tt
H: Funext G: Group g: GroupHomomorphism grp_trivial G
g tt = grp_trivial_rec G tt
rapply grp_homo_unit.Defined.
IsTerminal grp_trivial
IsTerminal grp_trivial
G: Group
{f : G $-> grp_trivial &
forallg : G $-> grp_trivial, f $== g}
G: Group
forallg : G $-> grp_trivial,
grp_trivial_corec G $== g
G: Group g: G $-> grp_trivial x: G
grp_trivial_corec G x = g x
apply path_contr.Defined.
H: Funext G: Group
Contr (GroupHomomorphism G grp_trivial)
H: Funext G: Group
Contr (GroupHomomorphism G grp_trivial)
H: Funext G: Group
GroupHomomorphism G grp_trivial
H: Funext G: Group
forally : GroupHomomorphism G grp_trivial,
?center = y
H: Funext G: Group
forally : GroupHomomorphism G grp_trivial,
(isterminal_grp_trivial G).1 = y
H: Funext G: Group g: GroupHomomorphism G grp_trivial
(isterminal_grp_trivial G).1 = g
H: Funext G: Group g: GroupHomomorphism G grp_trivial
(isterminal_grp_trivial G).1 == g
H: Funext G: Group g: GroupHomomorphism G grp_trivial x: G
(isterminal_grp_trivial G).1 x = g x
apply path_contr.Defined.
H: Funext G: Group
IsHProp (G ≅ grp_trivial)
H: Funext G: Group
IsHProp (G ≅ grp_trivial)
H: Funext G: Group
forallxy : G ≅ grp_trivial, x = y
H: Funext G: Group f, g: G ≅ grp_trivial
f = g
apply equiv_path_groupisomorphism; intro; apply path_ishprop.Defined.(** ** Free groups *)DefinitionFactorsThroughFreeGroup (S : Type) (F_S : Group)
(i : S -> F_S) (A : Group) (g : S -> A) : Type
:= {f : F_S $-> A & f o i == g}.(** Universal property of a free group on a set (type). *)ClassIsFreeGroupOn (S : Type) (F_S : Group) (i : S -> F_S)
:= contr_isfreegroupon :: forall (A : Group) (g : S -> A),
Contr (FactorsThroughFreeGroup S F_S i A g).(** A group is free if there exists a generating type on which it is a free group. *)ClassIsFreeGroup (F_S : Group)
:= isfreegroup : {S : _ & {i : _ & IsFreeGroupOn S F_S i}}.Instanceisfreegroup_isfreegroupon (S : Type) (F_S : Group) (i : S -> F_S)
{H : IsFreeGroupOn S F_S i}
: IsFreeGroup F_S
:= (S; i; H).(** ** Further properties of group homomorphisms. *)(** Commutativity can be transferred across isomorphisms. *)
G, H: Group C: Commutative group_sgop f: GroupIsomorphism G H
Commutative group_sgop
G, H: Group C: Commutative group_sgop f: GroupIsomorphism G H
Commutative group_sgop
G, H: Group C: Commutative group_sgop f: GroupIsomorphism G H
forallxy : H, group_sgop x y = group_sgop y x
G, H: Group C: Commutative group_sgop f: GroupIsomorphism G H g1: G
forally : H,
group_sgop (f g1) y = group_sgop y (f g1)
G, H: Group C: Commutative group_sgop f: GroupIsomorphism G H g1, g2: G
G, H: Group C: Commutative group_sgop f: GroupIsomorphism G H g1, g2: G
f (g1 * g2) = f (g2 * g1)
G, H: Group C: Commutative group_sgop f: GroupIsomorphism G H g1, g2: G
g1 * g2 = g2 * g1
apply C.Defined.(** If two group homomorphisms agree on two elements, then they agree on their product. *)
G, G', H: Group f: G $-> H f': G' $-> H x, y: G x', y': G' p: f x = f' x' q: f y = f' y'
f (x * y) = f' (x' * y')
G, G', H: Group f: G $-> H f': G' $-> H x, y: G x', y': G' p: f x = f' x' q: f y = f' y'
f (x * y) = f' (x' * y')
G, G', H: Group f: G $-> H f': G' $-> H x, y: G x', y': G' p: f x = f' x' q: f y = f' y'
f x * f y = f' (x' * y')
G, G', H: Group f: G $-> H f': G' $-> H x, y: G x', y': G' p: f x = f' x' q: f y = f' y'
f x * f y = f' x' * f' y'
exact (ap011 _ p q).Defined.(** The group movement lemmas can be extended to when there is a homomorphism involved. For now, we only include these two. *)Definitiongrp_homo_moveL_1V {AB : Group} (f : GroupHomomorphism A B) (xy : A)
: f (x * y) = group_unit <~> (f x = - f y)
:= grp_moveL_1V oE equiv_concat_l (grp_homo_op f x y)^ _.
A, B: Group f: GroupHomomorphism A B x, y: A
f (x * y^) = group_unit <~> f x = f y
A, B: Group f: GroupHomomorphism A B x, y: A
f (x * y^) = group_unit <~> f x = f y
A, B: Group f: GroupHomomorphism A B x, y: A
f (x * y^) = f x * (f y)^
A, B: Group f: GroupHomomorphism A B x, y: A
f x * f y^ = f x * (f y)^
apply ap, grp_homo_inv.Defined.(** ** Conjugation *)(** Conjugation by a group element is a homomorphism. Often we need to use properties about group homomorphisms in order to prove things about conjugation, so it is helpful to define it directly as a group homomorphism. *)
G: Group x: G
G $-> G
G: Group x: G
G $-> G
G: Group x: G
G -> G
G: Group x: G
IsSemiGroupPreserving ?grp_homo_map
G: Group x: G
G -> G
exact (funy => x * y * x^).
G: Group x: G
IsSemiGroupPreserving (funy : G => x * y * x^)
G: Group x, y, z: G
x * (y * z) * x^ = x * y * x^ * (x * z * x^)
G: Group x, y, z: G
x * (y * z) * x^ = x * y * x^ * (x * z) * x^
G: Group x, y, z: G
x * (y * z) = x * y * x^ * (x * z)
G: Group x, y, z: G
x * (y * z) = x * y * x^ * x * z
G: Group x, y, z: G
x * y * z = x * y * x^ * x * z
G: Group x, y, z: G
x * y = x * y * x^ * x
symmetry; apply grp_inv_gV_g.Defined.(** Conjugation by the unit element is the identity. *)
G: Group
grp_conj 1 $== Id G
G: Group
grp_conj 1 $== Id G
G: Group x: G
grp_conj 1 x = Id G x
G: Group x: G
1 * x = Id G x * 1
by napply grp_1g_g1.Defined.(** Conjugation commutes with group homomorphisms. *)