(**
  Accepts two monoid elements, x and y, and
  asserts  that y is x's left inverse.
*)
Definition op_is_inv_l := is_inv_l M {+} 0 op_id.(**
  Accepts two monoid elements, x and y, and
  asserts  that y is x's right inverse.
*)
Definition op_is_inv_r := is_inv_r M {+} 0 op_id.(**
  Accepts two monoid elements, x and y, and
  asserts  that y is x's inverse.
*)
Definition op_is_inv := is_inv M {+} 0 op_id.(**
  Accepts one argument, x, and asserts that
  x has a left inverse.
*)
Definition has_inv_l
  := fun x => exists y : M, op_is_inv_l x y.(**
  Accepts one argument, x, and asserts that
  x has a right inverse.
*)
Definition has_inv_r
  := fun x => exists y : M, op_is_inv_r x y.(**
  Accepts one argument, x, and asserts that
  x has an inverse.
*)
Definition has_inv
  := fun x => exists y : M, op_is_inv x y.

(* Specifications: *)
Theorem op_inv_l_r_eq : forall x y : M, op_is_inv_l x y -> forall z : M, op_is_inv_r x z -> y = z.
Theorem op_inv_sym : forall x y : M, op_is_inv x y <-> op_is_inv y x.
Theorem op_cancel_l : forall x y z : M, has_inv_l z -> z + x = z + y -> x = y.
Theorem op_cancel_r : forall x y z : M, has_inv_r z -> x + z = y + z -> x = y.
Theorem op_inv_l_uniq : forall x : M, has_inv_r x -> forall y z : M, op_is_inv_l x y -> op_is_inv_l x z -> z = y.
Theorem op_inv_r_uniq : forall x : M, has_inv_l x -> forall y z : M, op_is_inv_r x y -> op_is_inv_r x z -> z = y.
Theorem op_inv_uniq : forall x y z : M, op_is_inv x y -> op_is_inv x z -> z = y.
Theorem op_inv_0_l : op_is_inv_l 0 0.
Theorem op_inv_0_r : op_is_inv_r 0 0.
Theorem op_inv_0 : op_is_inv 0 0.
Theorem op_has_inv_l_0 : has_inv_l 0.
Theorem op_has_inv_r_0 : has_inv_r 0.
Theorem op_has_inv_0 : has_inv 0.
Theorem op_inv_0_eq_0 : forall x : M, op_is_inv x 0 -> x = 0.
Theorem op_inv_0_uniq : unique (fun x => op_is_inv x 0) 0.