CoRN.algebra.OperationClasses


Require Import Setoid Morphisms.
Notation " x === y " := (Equivalence.equiv x y) (at level 70, no associativity).

Set Implicit Arguments.
Unset Strict Implicit.

Section Definitions.

Definition unop (R : Type) := RR.
Definition binop (R : Type) := RRR.
Context {R : Type}.
Class unop_intern (P : RType) (op : unop R) :=
  unop_int : x : R, P xP (op x).
Class binop_intern (P : RType) (op : binop R) :=
  binop_int : x y : R, P xP yP (op x y).
Context `{r_st : Equivalence R}.

Class associative (op : binop R) :=
  assoc : x y z, op x (op y z) === op (op x y) z.
Class commutative (op : binop R) :=
  commut : x y, op x y === op y x.
Class left_commutative (op : binop R) :=
  left_commut : x y z, op x (op y z) === op y (op x z).
Class right_commutative (op : binop R) :=
  right_commut : x y z, op (op x y) z === op (op x z) y.

Class left_unit (op : binop R) (idm : R) :=
  left_id : x, op idm x === x.
Class right_unit (op : binop R) (idm : R) :=
  right_id : x, op x idm === x.
Class left_absorbing (op : binop R) (idm : R) :=
  left_zero : x, op idm x === idm.
Class right_absorbing (op : binop R) (idm : R) :=
  right_zero : x, op x idm === idm.

Class left_distributive (op mul : binop R) :=
  left_dist : x y z, mul (op x y) z === op (mul x z) (mul y z).
Class right_distributive (op mul : binop R) :=
  right_dist : x y z, mul x (op y z) === op (mul x y) (mul x z).

Class left_inverse (op : binop R) (idm : R) (inv : unop R) :=
  left_inv : x, op x (inv x) === idm.
Class right_inverse (op : binop R) (idm : R) (inv : unop R) :=
  right_inv : x, op (inv x) x === idm.

End Definitions.

Section Commutative.
Context `{r_st : Equivalence}.
Context {mul : binop A} {mulC : commutative mul}.
Global Instance mulC_id_l {idm : A} {H : left_unit mul idm} : right_unit mul idm.
Proof. reduce; rewrite commut; apply left_id. Qed.
Global Instance mulC_id_r {idm : A} {H : right_unit mul idm} : left_unit mul idm.
Proof. reduce; rewrite commut; apply right_id. Qed.
Global Instance mulC_zero_l {zero : A} {H : left_absorbing mul zero} : right_absorbing mul zero.
Proof. reduce; rewrite commut; apply left_zero. Qed.
Global Instance mulC_zero_r {zero : A} {H : right_absorbing mul zero} : left_absorbing mul zero.
Proof. reduce; rewrite commut; apply right_zero. Qed.
Global Instance mulC_inv_l {idm : A} {inv : unop A} {H : left_inverse mul idm inv} : right_inverse mul idm inv.
Proof. reduce; rewrite commut; apply left_inv. Qed.
Global Instance mulC_inv_r {idm : A} {inv : unop A} {H : right_inverse mul idm inv} : left_inverse mul idm inv.
Proof. reduce; rewrite commut; apply right_inv. Qed.

Section distributivity.
Context {op : binop A}.
Context {op_morph : Proper (Equivalence.equiv==>Equivalence.equiv==>Equivalence.equiv) op}.
Global Instance mulC_distr_l {H : left_distributive op mul} : right_distributive op mul.
Proof. intros x y z; rewrite → (commut x (op _ _)), → (commut x y), → (commut x z); apply left_dist. Qed.
Global Instance mulC_distr_r {H : right_distributive op mul} : left_distributive op mul.
Proof. intros x y z; rewrite → (commut (op _ _) z), → (commut x z), → (commut y z); apply right_dist. Qed.
End distributivity.

Section Associativity.
Context {mul_morph : Proper (Equivalence.equiv==>Equivalence.equiv==>Equivalence.equiv) mul}.
Context {mulA : associative mul}.
Global Instance mulAC_comm_l : left_commutative mul.
Proof. intros x y z; rewriteassoc, assoc, (commut x y); reflexivity. Qed.
Global Instance mulAC_comm_r : right_commutative mul.
Proof. intros x y z; rewrite <- assoc, <- assoc, (commut y z); reflexivity. Qed.
End Associativity.

End Commutative.

Section AssociativeCommutative.
Context `{r_st : Equivalence}.
Context {add mul : binop A} {opp : unop A} {zero : A}.
Context {add_morph : Proper (Equivalence.equiv==>Equivalence.equiv==>Equivalence.equiv) add}.
Context {mul_morph : Proper (Equivalence.equiv==>Equivalence.equiv==>Equivalence.equiv) mul}.
Context {opA : associative add}.
Context {opC : commutative add}.
Section Left.
Context {l_inv : left_inverse add zero opp}.
Context {op_id : left_unit add zero}.
Context {l_d : left_distributive add mul}.

Existing Instance mulC_id_l.

Global Instance opA_zero_l : left_absorbing mul zero.
Proof.
 intro; rewrite <- (left_id (mul _ _)); rewrite <- (left_id zero) at 3.
 set (e := left_inv (mul zero x)); rewrite <- e at 1 3; clear e.
 rewrite → (commut (mul _ _)), <- assoc, <-assoc; apply add_morph; try reflexivity.
 rewrite <- left_dist, (left_id zero), (right_id (mul _ _)); reflexivity.
Qed.
End Left.
Section Right.
Context {r_inv : right_inverse add zero opp}.
Context {op_id : right_unit add zero}.
Context {r_d : right_distributive add mul}.

Existing Instance mulC_id_r.

Global Instance opA_zero_r : right_absorbing mul zero.
Proof.
 intro; rewrite <- (right_id (mul _ _)); rewrite <- (right_id zero) at 3.
 set (e := right_inv (mul x zero)); rewrite <- e at 2 4; clear e.
 rewrite → (commut (opp _)), assoc, assoc; apply add_morph; try reflexivity.
 rewrite <- right_dist, (right_id zero), (left_id (mul _ _)); reflexivity.
Qed.
End Right.
End AssociativeCommutative.