(**
  Accepts two binary functions, f and g, and
  asserts that f is left distributive over g.
*)
Definition is_distrib_l (T : Type) (f g : T -> T -> T)
  :  Prop
  := forall x y z : T, f x (g y z) = g (f x y) (f x z).(**
  Accepts two binary functions, f and g, and
  asserts that f is right distributive over g.
*)
Definition is_distrib_r (T : Type) (f g : T -> T -> T)
  :  Prop
  := forall x y z : T, f (g y z) x = g (f y x) (f z x).(**
  Accepts two binary functions, f and g, and
  asserts that f is distributive over g.
*)
Definition is_distrib (T : Type) (f g : T -> T -> T)
  :  Prop
  := is_distrib_l T f g /\ is_distrib_r T f g.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.(** Represents algebraic rings *)
Structure Ring : Type := ring {

  (** Represents the set of ring elements. *)
  E : Set;

  (** Represents 0 - the additive identity. *)
  E_0 : E;

  (** Represents 1 - the multiplicative identity. *)
  E_1 : E;

  (** Represents addition. *)
  sum : E -> E -> E;

  (** Represents multiplication. *)
  prod : E -> E -> E;

  (** Asserts that 0 /= 1. *)
  distinct_0_1 : E_0 <> E_1;

  (** Asserts that addition is associative. *)
  sum_is_assoc : Monoid.is_assoc E sum;

  (** Asserts that addition is commutative. *)
  sum_is_comm : Abelian_Group.is_comm E sum;

  (** Asserts that E_0 is the left identity element. *)
  sum_id_l : Monoid.is_id_l E sum E_0;

  (**
    Asserts that every element has an additive
    inverse.
  *)
  sum_inv_l_ex : forall x : E, exists y : E, sum y x = E_0;

  (** Asserts that multiplication is associative. *)
  prod_is_assoc : Monoid.is_assoc E prod;

  (**
    Asserts that 1 is the left identity
    element.
  *)
  prod_id_l : Monoid.is_id_l E prod E_1;

  (**
    Asserts that 1 is the right identity
    element.
  *)
  prod_id_r : Monoid.is_id_r E prod E_1;

  (**
    Asserts that multiplication is left
    distributive over addition.
  *)
  prod_sum_distrib_l : is_distrib_l E prod sum;
   
  (**
    Asserts that multiplication is right
    distributive over addition.
  *)
  prod_sum_distrib_r : is_distrib_r E prod sum
}.Notation "0" := (Ring.E_0) : ring_scope.Notation "1" := (Ring.E_1) : ring_scope.Notation "x + y" := (Ring.sum x y) (at level 50, left associativity) : ring_scope.Notation "{+}" := (Ring.sum) : ring_scope.Notation "x # y" := (Ring.prod x y) (at level 50, left associativity) : ring_scope.Notation "{#}" := (Ring.prod) : ring_scope.(**
  A predicate that accepts one element, x,
  and asserts that x is nonzero.
*)
Definition nonzero (x : E) : Prop := x <> 0.(**
  Accepts one ring element, x, and asserts
  that x is the left identity element.
*)
Definition sum_is_id_l := Monoid.is_id_l E sum.(**
  Accepts one ring element, x, and asserts
  that x is the right identity element.
*)
Definition sum_is_id_r := Monoid.is_id_r E sum.(**
  Accepts one ring element, x, and asserts
  that x is the identity element.
*)
Definition sum_is_id := Monoid.is_id E sum.(**
  Represents the abelian group formed by
  addition over E.
*)
Definition sum_abelian_group
  := Abelian_Group.abelian_group E 0 {+} sum_is_assoc sum_is_comm sum_id_l sum_inv_l_ex.(**
  Represents the group formed by addition
  over E.
*)
Definition sum_group
  := Abelian_Group.op_group sum_abelian_group.(**
  Represents the monoid formed by addition
  over E.
*)
Definition sum_monoid
  := Abelian_Group.op_monoid sum_abelian_group.

(* Specifications: *)
Theorem sum_id_r : sum_is_id_r 0.
Theorem sum_id : sum_is_id 0.