Section Theorems.
(** Represents an arbitrary group.  Note: we use Variable rather than Parameter to ensure that the following theorems are generalized w.r.t g. *)
Variable g : Group.
(** Represents the set of group elements. *)
Let E := E g.
(** Represents the monoid structure formed by op over E. *)
Definition op_monoid := Monoid.monoid E 0 {+} op_is_assoc op_id_l op_id_r.
(** Accepts one group element, x, and asserts that x is the left identity element. *)
Definition op_is_id_l := Monoid.op_is_id_l op_monoid.
(** Accepts one group element, x, and asserts that x is the right identity element. *)
Definition op_is_id_r := Monoid.op_is_id_r op_monoid.
(** Accepts one group element, x, and asserts that x is the identity element. *)
Definition op_is_id := Monoid.op_is_id op_monoid.
Proof Monoid.op_id op_monoid.
(** Accepts two group elements, x and y, and asserts that y is x's left inverse. *)
Definition op_is_inv_l := Monoid.op_is_inv_l op_monoid.
(** Accepts two group elements, x and y, and asserts that y is x's right inverse. *)
Definition op_is_inv_r := Monoid.op_is_inv_r op_monoid.
Proof Monoid.op_id_l_uniq op_monoid.
Proof Monoid.op_id_r_uniq op_monoid.
Proof Monoid.op_id_uniq op_monoid.
Proof Monoid.op_intro_l op_monoid.
Proof Monoid.op_intro_r op_monoid.
(** Accepts two group elements, x and y, and asserts that y is x's inverse. *)
Definition op_is_inv := Monoid.op_is_inv op_monoid.
(** Accepts one argument, x, and asserts that x has a left inverse. *)
Definition has_inv_l := Monoid.has_inv_l op_monoid.
(** Accepts one argument, x, and asserts that x has a right inverse. *)
Definition has_inv_r := Monoid.has_inv_r op_monoid.
(** Accepts one argument, x, and asserts that x has an inverse. *)
Definition has_inv := Monoid.has_inv op_monoid.
Proof Monoid.op_inv_l_r_eq op_monoid.
Proof Monoid.op_inv_sym op_monoid.
Proof
fun x : E
=> ex_ind
(fun y H
=> ex_ind
(fun z H0
=> let H1
:  op_is_inv_r x y
:=  H0
|| op_is_inv_r x a @a
by op_inv_l_r_eq x y H z H0 in
ex_intro
(fun a => op_is_inv x a)
y
(conj H H1))
(op_inv_r_ex x))
(op_inv_l_ex x).
Proof
fun x y z H
=> Monoid.op_cancel_l op_monoid x y z (op_inv_l_ex z) H.
Proof
fun x y z
=> Monoid.op_cancel_r op_monoid x y z (op_inv_r_ex z).
Proof
fun x
=> Monoid.op_inv_l_uniq op_monoid x (op_inv_r_ex x).
Proof
fun x
=> Monoid.op_inv_r_uniq op_monoid x (op_inv_l_ex x).
Proof Monoid.op_inv_uniq op_monoid.
Proof
fun x
=> ex_ind
(fun y (H : op_is_inv x y)
=> ex_intro
(fun y => op_is_inv x y /\ forall z, op_is_inv x z -> y = z)
y
(conj H (fun z H0 => eq_sym (op_inv_uniq x y z H H0))))
(op_inv_ex x).
Proof Monoid.op_inv_0_l op_monoid.
Proof Monoid.op_inv_0_r op_monoid.
Proof Monoid.op_inv_0 op_monoid.
Proof Monoid.op_has_inv_l_0 op_monoid.
Proof Monoid.op_has_inv_r_0 op_monoid.
Proof Monoid.op_has_inv_0 op_monoid.
Proof Monoid.op_inv_0_eq_0 op_monoid.

(** Proves that 0 is the only element whose inverse is 0. *)
Theorem op_inv_0_uniq
:  unique (fun x => op_is_inv x 0) 0.