(** This module defines the Ring record type which can be used to represent algebraic rings and provides a collection of axioms and theorems describing them.  Copyright (C) 2018 Larry D. Lee Jr. <llee454@gmail.com>  This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.  You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. *)
Module Ring.
Close Scope nat_scope.
(** 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
}.
(** Enable implicit arguments for ring properties. *)
Arguments E_0 {r}.
Arguments E_1 {r}.
Arguments sum {r} x y.
Arguments prod {r} x y.
Arguments distinct_0_1 {r} _.
Arguments sum_is_assoc {r} x y z.
Arguments sum_is_comm {r} x y.
Arguments sum_id_l {r} x.
Arguments sum_inv_l_ex {r} x.
Arguments prod_is_assoc {r} x y z.
Arguments prod_id_l {r} x.
Arguments prod_id_r {r} x.
Arguments prod_sum_distrib_l {r} x y z.
Arguments prod_sum_distrib_r {r} x y z.
(** Define notations for ring properties. *)
Notation "0" := E_0 : ring_scope.
Notation "1" := E_1 : ring_scope.
Notation "x + y" := (sum x y) (at level 50, left associativity) : ring_scope.
Notation "{+}" := sum : ring_scope.
Notation "x # y" := (prod x y) (at level 50, left associativity) : ring_scope.
Notation "{#}" := prod : ring_scope.
Open Scope ring_scope.
Section Theorems.
(** Represents an arbitrary ring.  Note: we use Variable rather than Parameter to ensure that the following theorems are generalized w.r.t r. *)
Variable r : Ring.
(** Represents the set of group elements.  Note: We use Let to define E as a local abbreviation. *)
Let E := E r.
(** 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: *)
(** Proves that 0 is the right identity element. *)
Theorem sum_id_r
:  sum_is_id_r 0.