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.
Proof Monoid.op_inv_0_uniq op_monoid.
(** Represents strongly-specified negation. *)
Definition op_neg_strong
:  forall x : E, { y | op_is_inv x y }
:= fun x => Monoid.op_neg_strong op_monoid x (op_inv_ex x).
(** Represents negation. *)
Definition op_neg
:  E -> E
:= fun x => Monoid.op_neg op_monoid x (op_inv_ex x).
Notation "{-}" := (op_neg) : group_scope.
Notation "- x" := (op_neg x) : group_scope.
Proof
fun x
=> Monoid.op_neg_def op_monoid x (op_inv_ex x).

(** Proves that negation is one-to-one *)
(** 0 = 0 x + -x = 0 x + -x = y + -y x + -x = y + -x x = y *)
Theorem op_neg_inj
:  is_injective E E op_neg.