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.
Proof Ring.sum_inv_l_r_eq ring.
Proof Ring.sum_inv_sym ring.
Proof Ring.sum_inv_uniq ring.
Proof Ring.sum_inv_ex ring.
Proof Ring.sum_inv_uniq_ex ring.
Proof Ring.sum_intro_l ring.
Proof Ring.sum_intro_r ring.
Proof Ring.sum_cancel_l ring.
Proof Ring.sum_cancel_r ring.
Proof Ring.sum_inv_l_uniq ring.
Proof Ring.sum_inv_r_uniq ring.
Proof Ring.sum_0_inv_l ring.
Proof Ring.sum_0_inv_r ring.
Proof Ring.sum_0_inv ring.
Proof Ring.sum_has_inv_l_0 ring.
Proof Ring.sum_has_inv_r_0 ring.
Proof Ring.sum_has_inv_0 ring.
Proof Ring.sum_inv_0_eq_0 ring.
Proof Ring.sum_inv_0_uniq ring.
(** Represents strongly-specified negation. *)
Definition sum_neg_strong
:  forall x : E, { y | sum_is_inv x y }
:= Ring.sum_neg_strong ring.
(** Represents negation. *)
Definition sum_neg
:  E -> E
:= Ring.sum_neg ring.
Notation "{-}" := (sum_neg) : commutative_ring_scope.
Notation "- x" := (sum_neg x) : commutative_ring_scope.
(** Asserts that the negation returns the inverse of its argument. *)
Definition sum_neg_def
:  forall x : E, sum_is_inv x (- x)
:= Ring.sum_neg_def ring.
Proof Ring.sum_neg_inj ring.
Proof Ring.sum_cancel_neg ring.
Proof Ring.sum_neg_onto ring.
Proof Ring.sum_neg_bijective ring.
Proof Ring.sum_neg_rev ring.
Proof Ring.sum_neg_distrib_inv_l ring.
Proof Ring.sum_neg_distrib_inv_r ring.
Proof Ring.sum_neg_distrib_inv ring.
Proof Ring.sum_neg_distrib ring.
Proof Ring.sum_0_neg ring.
Proof Ring.sum_neg_0 ring.
Proof Ring.sum_neg_0_uniq ring.
Proof Ring.prod_id ring.
Proof Ring.prod_id_l_uniq ring.
Proof Ring.prod_id_r_uniq ring.
Proof Ring.prod_id_uniq ring.
Proof Ring.prod_intro_l ring.
Proof Ring.prod_intro_r ring.
(** Accepts two elements, x and y, and asserts that y is x's left inverse. *)
Definition prod_is_inv_l := Ring.prod_is_inv_l ring.
(** Accepts two elements, x and y, and asserts that y is x's right inverse. *)
Definition prod_is_inv_r := Ring.prod_is_inv_r ring.
(** Accepts two elements, x and y, and asserts that y is x's inverse. *)
Definition prod_is_inv := Ring.prod_is_inv ring.
(** Accepts one argument, x, and asserts that x has a left inverse. *)
Definition prod_has_inv_l := Ring.prod_has_inv_l ring.
(** Accepts one argument, x, and asserts that x has a right inverse. *)
Definition prod_has_inv_r := Ring.prod_has_inv_r ring.
(** Accepts one argument, x, and asserts that x has an inverse. *)
Definition prod_has_inv := Ring.prod_has_inv ring.
Proof
fun x y H
=> H || a = 1 @a by prod_is_comm x y.

(** Proves that the left and right inverses of an element must be equal. *)
Theorem prod_inv_l_r_eq
:  forall x y : E, prod_is_inv_l x y -> forall z : E, prod_is_inv_r x z -> y = z.