Section Theorems.
(** Represents an arbitrary commutative ring.  Note: we use Variable rather than Parameter to ensure that the following theorems are generalized w.r.t r. *)
Variable r : Commutative_Ring.
(** Represents the set of group elements.  Note: We use Let to define E as a local abbreviation. *)
Let E := E r.
(** Accepts one ring element, x, and asserts that x is the left identity element. *)
Definition sum_is_id_l := Monoid.is_id_l E {+}.
(** Accepts one ring element, x, and asserts that x is the right identity element. *)
Definition sum_is_id_r := Monoid.is_id_r E {+}.
(** Accepts one ring element, x, and asserts that x is the identity element. *)
Definition sum_is_id := Monoid.is_id E {+}.
(** Accepts one ring element, x, and asserts that x is the left identity element. *)
Definition prod_is_id_l := Monoid.is_id_l E {#}.
(** Accepts one ring element, x, and asserts that x is the right identity element. *)
Definition prod_is_id_r := Monoid.is_id_r E {#}.
(** Accepts one ring element, x, and asserts that x is the identity element. *)
Definition prod_is_id := Monoid.is_id E {#}.
Proof
fun x : E
=> eq_ind_r
(fun a => a = x)
(prod_id_l x)
(prod_is_comm x 1).
Proof
fun x y z : E
=>  prod_sum_distrib_l x y z
|| x # (y + z) = a + (x # z) @a by <- prod_is_comm x y
|| x # (y + z) = (y # x) + a @a by <- prod_is_comm x z
|| a = (y # x) + (z # x)     @a by <- prod_is_comm x (y + z).
(** Represents the non-commutative ring formed by addition and multiplication over E. *)
Definition ring := Ring.ring E 0 1 {+} {#} distinct_0_1 sum_is_assoc sum_is_comm sum_id_l sum_inv_l_ex prod_is_assoc prod_id_l prod_id_r prod_sum_distrib_l prod_sum_distrib_r.
(** Represents the abelian group formed by addition over E. *)
Definition sum_abelian_group := Ring.sum_abelian_group ring.
(** Represents the group formed by addition over E. *)
Definition sum_group := Ring.sum_group ring.
(** Represents the monoid formed by addition over E. *)
Definition sum_monoid := Ring.sum_monoid ring.
(** Represents the monoid formed by multiplication over E. *)
Definition prod_monoid := Ring.prod_monoid ring.
Proof
fun H : E_1 = E_0
=> distinct_0_1 (eq_sym H).
(** A predicate that accepts one element, x, and asserts that x is nonzero. *)
Definition nonzero
: E -> Prop
:= Ring.nonzero ring.
Proof Ring.sum_id_r ring.
Proof Ring.sum_id ring.
(** Accepts two elements, x and y, and asserts that y is x's left inverse. *)
Definition sum_is_inv_l
:= Ring.sum_is_inv_l ring.
(** Accepts two elements, x and y, and asserts that y is x's right inverse. *)
Definition sum_is_inv_r
:= Ring.sum_is_inv_r ring.
(** Accepts two elements, x and y, and asserts that y is x's inverse. *)
Definition sum_is_inv
:= Ring.sum_is_inv ring.
(** Accepts one argument, x, and asserts that x has a left inverse. *)
Definition sum_has_inv_l := Ring.sum_has_inv_l ring.
(** Accepts one argument, x, and asserts that x has a right inverse. *)
Definition sum_has_inv_r := Ring.sum_has_inv_r ring.
(** Accepts one argument, x, and asserts that x has an inverse. *)
Definition sum_has_inv := Ring.sum_has_inv ring.
Proof Ring.sum_inv_r_ex ring.
Proof Ring.sum_id_l_uniq ring.
Proof Ring.sum_id_r_uniq ring.
Proof Ring.sum_id_uniq ring.

(** Proves that for every group element, x, its left and right inverses are equal. *)
Theorem sum_inv_l_r_eq
:  forall x y : E, sum_is_inv_l x y -> forall z : E, sum_is_inv_r x z -> y = z.