(**
  Accepts one argument: f, a binary function;
  and asserts that f is commutative.
*)
Definition is_comm (T : Type) (f : T -> T -> T)
  :  Prop
  := forall x y : T, f x y = f y x.(** Represents algebraic abelian groups. *)
Structure Abelian_Group : Type := abelian_group {

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

  (** Represents the identity element. *)
  E_0 : E;

  (** Represents the group operation. *)
  op : E -> E -> E;

  (** Asserts that the group operator is associative. *)
  op_is_assoc : Monoid.is_assoc E op;

  (** Asserts that the group operator is commutative. *)
  op_is_comm : is_comm E op;

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

  (**
    Asserts that every element has a left inverse.

    Strictly speaking, this axiom should be:

      forall x : E, exists y : E,
        Monoid.is_inv_l E op E_0 op_id x y

    which asserts and verifies that op y x equals
    the identity element. Technically, we haven't
    shown that E_0 is the identity element yet, so
    we're being a bit presumptuous defining inverses
    in this way. While we could prove op_id in this
    structure definition, we prefer not to to improve
    readability and instead use the form given below,
    which Monoid.is_inv_l reduces to anyway.
  *)
  op_inv_l_ex : forall x : E, exists y : E, op y x = E_0
}.(** Represents algebraic abelian groups. *)
Structure Abelian_Group : Type := abelian_group {

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

  (** Represents the identity element. *)
  E_0 : E;

  (** Represents the group operation. *)
  op : E -> E -> E;

  (** Asserts that the group operator is associative. *)
  op_is_assoc : Monoid.is_assoc E op;

  (** Asserts that the group operator is commutative. *)
  op_is_comm : is_comm E op;

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

  (**
    Asserts that every element has a left inverse.

    Strictly speaking, this axiom should be:

      forall x : E, exists y : E,
        Monoid.is_inv_l E op E_0 op_id x y

    which asserts and verifies that op y x equals
    the identity element. Technically, we haven't
    shown that E_0 is the identity element yet, so
    we're being a bit presumptuous defining inverses
    in this way. While we could prove op_id in this
    structure definition, we prefer not to to improve
    readability and instead use the form given below,
    which Monoid.is_inv_l reduces to anyway.
  *)
  op_inv_l_ex : forall x : E, exists y : E, op y x = E_0
}.(** Represents algebraic abelian groups. *)
Structure Abelian_Group : Type := abelian_group {

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

  (** Represents the identity element. *)
  E_0 : E;

  (** Represents the group operation. *)
  op : E -> E -> E;

  (** Asserts that the group operator is associative. *)
  op_is_assoc : Monoid.is_assoc E op;

  (** Asserts that the group operator is commutative. *)
  op_is_comm : is_comm E op;

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

  (**
    Asserts that every element has a left inverse.

    Strictly speaking, this axiom should be:

      forall x : E, exists y : E,
        Monoid.is_inv_l E op E_0 op_id x y

    which asserts and verifies that op y x equals
    the identity element. Technically, we haven't
    shown that E_0 is the identity element yet, so
    we're being a bit presumptuous defining inverses
    in this way. While we could prove op_id in this
    structure definition, we prefer not to to improve
    readability and instead use the form given below,
    which Monoid.is_inv_l reduces to anyway.
  *)
  op_inv_l_ex : forall x : E, exists y : E, op y x = E_0
}.(** Represents algebraic abelian groups. *)
Structure Abelian_Group : Type := abelian_group {

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

  (** Represents the identity element. *)
  E_0 : E;

  (** Represents the group operation. *)
  op : E -> E -> E;

  (** Asserts that the group operator is associative. *)
  op_is_assoc : Monoid.is_assoc E op;

  (** Asserts that the group operator is commutative. *)
  op_is_comm : is_comm E op;

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

  (**
    Asserts that every element has a left inverse.

    Strictly speaking, this axiom should be:

      forall x : E, exists y : E,
        Monoid.is_inv_l E op E_0 op_id x y

    which asserts and verifies that op y x equals
    the identity element. Technically, we haven't
    shown that E_0 is the identity element yet, so
    we're being a bit presumptuous defining inverses
    in this way. While we could prove op_id in this
    structure definition, we prefer not to to improve
    readability and instead use the form given below,
    which Monoid.is_inv_l reduces to anyway.
  *)
  op_inv_l_ex : forall x : E, exists y : E, op y x = E_0
}.(** Represents algebraic abelian groups. *)
Structure Abelian_Group : Type := abelian_group {

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

  (** Represents the identity element. *)
  E_0 : E;

  (** Represents the group operation. *)
  op : E -> E -> E;

  (** Asserts that the group operator is associative. *)
  op_is_assoc : Monoid.is_assoc E op;

  (** Asserts that the group operator is commutative. *)
  op_is_comm : is_comm E op;

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

  (**
    Asserts that every element has a left inverse.

    Strictly speaking, this axiom should be:

      forall x : E, exists y : E,
        Monoid.is_inv_l E op E_0 op_id x y

    which asserts and verifies that op y x equals
    the identity element. Technically, we haven't
    shown that E_0 is the identity element yet, so
    we're being a bit presumptuous defining inverses
    in this way. While we could prove op_id in this
    structure definition, we prefer not to to improve
    readability and instead use the form given below,
    which Monoid.is_inv_l reduces to anyway.
  *)
  op_inv_l_ex : forall x : E, exists y : E, op y x = E_0
}.(** Represents algebraic abelian groups. *)
Structure Abelian_Group : Type := abelian_group {

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

  (** Represents the identity element. *)
  E_0 : E;

  (** Represents the group operation. *)
  op : E -> E -> E;

  (** Asserts that the group operator is associative. *)
  op_is_assoc : Monoid.is_assoc E op;

  (** Asserts that the group operator is commutative. *)
  op_is_comm : is_comm E op;

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

  (**
    Asserts that every element has a left inverse.

    Strictly speaking, this axiom should be:

      forall x : E, exists y : E,
        Monoid.is_inv_l E op E_0 op_id x y

    which asserts and verifies that op y x equals
    the identity element. Technically, we haven't
    shown that E_0 is the identity element yet, so
    we're being a bit presumptuous defining inverses
    in this way. While we could prove op_id in this
    structure definition, we prefer not to to improve
    readability and instead use the form given below,
    which Monoid.is_inv_l reduces to anyway.
  *)
  op_inv_l_ex : forall x : E, exists y : E, op y x = E_0
}.(** Represents algebraic abelian groups. *)
Structure Abelian_Group : Type := abelian_group {

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

  (** Represents the identity element. *)
  E_0 : E;

  (** Represents the group operation. *)
  op : E -> E -> E;

  (** Asserts that the group operator is associative. *)
  op_is_assoc : Monoid.is_assoc E op;

  (** Asserts that the group operator is commutative. *)
  op_is_comm : is_comm E op;

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

  (**
    Asserts that every element has a left inverse.

    Strictly speaking, this axiom should be:

      forall x : E, exists y : E,
        Monoid.is_inv_l E op E_0 op_id x y

    which asserts and verifies that op y x equals
    the identity element. Technically, we haven't
    shown that E_0 is the identity element yet, so
    we're being a bit presumptuous defining inverses
    in this way. While we could prove op_id in this
    structure definition, we prefer not to to improve
    readability and instead use the form given below,
    which Monoid.is_inv_l reduces to anyway.
  *)
  op_inv_l_ex : forall x : E, exists y : E, op y x = E_0
}.(** Represents algebraic abelian groups. *)
Structure Abelian_Group : Type := abelian_group {

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

  (** Represents the identity element. *)
  E_0 : E;

  (** Represents the group operation. *)
  op : E -> E -> E;

  (** Asserts that the group operator is associative. *)
  op_is_assoc : Monoid.is_assoc E op;

  (** Asserts that the group operator is commutative. *)
  op_is_comm : is_comm E op;

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

  (**
    Asserts that every element has a left inverse.

    Strictly speaking, this axiom should be:

      forall x : E, exists y : E,
        Monoid.is_inv_l E op E_0 op_id x y

    which asserts and verifies that op y x equals
    the identity element. Technically, we haven't
    shown that E_0 is the identity element yet, so
    we're being a bit presumptuous defining inverses
    in this way. While we could prove op_id in this
    structure definition, we prefer not to to improve
    readability and instead use the form given below,
    which Monoid.is_inv_l reduces to anyway.
  *)
  op_inv_l_ex : forall x : E, exists y : E, op y x = E_0
}.(** Represents algebraic abelian groups. *)
Structure Abelian_Group : Type := abelian_group {

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

  (** Represents the identity element. *)
  E_0 : E;

  (** Represents the group operation. *)
  op : E -> E -> E;

  (** Asserts that the group operator is associative. *)
  op_is_assoc : Monoid.is_assoc E op;

  (** Asserts that the group operator is commutative. *)
  op_is_comm : is_comm E op;

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

  (**
    Asserts that every element has a left inverse.

    Strictly speaking, this axiom should be:

      forall x : E, exists y : E,
        Monoid.is_inv_l E op E_0 op_id x y

    which asserts and verifies that op y x equals
    the identity element. Technically, we haven't
    shown that E_0 is the identity element yet, so
    we're being a bit presumptuous defining inverses
    in this way. While we could prove op_id in this
    structure definition, we prefer not to to improve
    readability and instead use the form given below,
    which Monoid.is_inv_l reduces to anyway.
  *)
  op_inv_l_ex : forall x : E, exists y : E, op y x = E_0
}.Notation "0" := (Abelian_Group.E_0) : abelian_group_scope.Notation "x + y" := (Abelian_Group.op x y) (at level 50, left associativity) : abelian_group_scope.Notation "{+}" := (Abelian_Group.op) : abelian_group_scope.

(* Specifications: *)
Theorem op_is_id_lr : forall x : E, op_is_id_l x -> op_is_id_r x.
Theorem op_is_id_lid : forall x : E, op_is_id_l x -> op_is_id x.
Theorem op_id_r : op_is_id_r 0.
Theorem op_id : op_is_id 0.
Theorem op_inv_r_ex : forall x : E, exists y : E, op_is_inv_r x y.