HyPre.pred.MonoidHomomorphism


From Coq Require Import
  Program.Equality.

From HyPre Require Export
  ListExtra
  NatExtra
  VectorExtra.

Import ListNotations.
Set Implicit Arguments.
Set Maximal Implicit Insertion.
Set Universe Polymorphism.

Section Monoid.
  Universe u.
  Variable S : Type@{u}.

  Class Monoid@{} : Type :=
    {
      monoid_plus : S -> S -> S;
      monoid_unit : S;
    }.

  Class MonoidLaws@{} (M : Monoid) : Type :=
    {
      monoid_assoc : forall m1 m2 m3, monoid_plus (monoid_plus m1 m2) m3 = monoid_plus m1 (monoid_plus m2 m3);
      monoid_lunit : forall m, monoid_plus monoid_unit m = m;
      monoid_runit : forall m, monoid_plus m monoid_unit = m;
    }.

End Monoid.

Require Vector.

Generalizable All Variables.
(*Existing Class Monoid.*)

Global Instance Monoid_nat : Monoid nat
  := {| monoid_plus := Nat.add; monoid_unit := 0 |}.

Global Program Instance MonoidLaws_nat : MonoidLaws (Monoid_nat).
Next Obligation.
  lia.
Qed.

(*Existing Instance Monoid_nat_plus.*)

Class MonoidHomomorphism {M N : Type} {MMon : Monoid M} {NMon : Monoid N} (hom : M -> N)
  := {
      homomorph : forall m1 m2, hom (monoid_plus m1 m2) = monoid_plus (hom m1) (hom m2);
      homomorph_unit : hom monoid_unit = monoid_unit;
    }.

Class MonoidIsomorphism {M N : Type} {MMon : Monoid M} {NMon : Monoid N} (hom : M -> N)
  := {
      MonoidIsomorphism_homomorph :> MonoidHomomorphism hom;
      injective : forall m1 m2, hom m1 = hom m2 -> m1 = m2;
      surjective : forall m, {m' | hom m' = m};
    }.

(*Definition len_vec `{MM : MonoidHomomorphism} {k : nat} : Vector.t M k -> Vector.t N k
  := Vector.map hom.*)


Definition vm_plus `{MMon : Monoid M} {k : nat} : Vector.t M k -> Vector.t M k -> Vector.t M k
  := Vector.map2 (monoid_plus).

Module MonoidHomomorphismNotations.

  Infix "+m+" := (monoid_plus) (at level 69).

  Infix "+vm+" := vm_plus (at level 69).

End MonoidHomomorphismNotations.

Import MonoidHomomorphismNotations.

Lemma Monoid_unit_lunique `{M : Monoid} {ML : @MonoidLaws _ M}
  : forall m, (forall m', m +m+ m' = m') -> m = monoid_unit.
Proof.
  intros.
  specialize (H monoid_unit).
  setoid_rewrite monoid_runit in H.
  assumption.
Qed.

Lemma Monoid_unit_runique `{M : Monoid} `{ML : MonoidLaws}
  : forall m, (forall m', m' +m+ m = m') -> m = monoid_unit.
Proof.
  intros.
  specialize (H monoid_unit).
  setoid_rewrite monoid_lunit in H.
  assumption.
Qed.

Generalizable No Variables.

Global Instance MonList X : Monoid (list X)
  := {|
      monoid_plus := (@app X);
      monoid_unit := [];
    |}.
Global Program Instance MonLawsList X : MonoidLaws (MonList X).
Next Obligation.
  rewrite app_assoc.
  reflexivity.
Qed.
Next Obligation.
  rewrite app_nil_r.
  reflexivity.
Qed.

Global Instance MonPair M M' {MM : Monoid M} {MM' : Monoid M'}
  : Monoid (M*M')
  := {|
      monoid_plus := fun (x y : M*M') => let (x1,x2) := x in
                                      let (y1,y2) := y in
                                      (x1 +m+ y1, x2 +m+ y2);
      monoid_unit := (monoid_unit,monoid_unit)
    |}.
Global Program Instance MonLawsPair M M' {MM : Monoid M} {MM' : Monoid M'} {MLM : MonoidLaws MM} {MLM' : MonoidLaws MM'}
  : MonoidLaws (@MonPair M M' _ _).
Next Obligation.
  setoid_rewrite monoid_assoc.
  reflexivity.
Qed.
Next Obligation.
  setoid_rewrite monoid_lunit.
  reflexivity.
Qed.
Next Obligation.
  setoid_rewrite monoid_runit.
  reflexivity.
Qed.

Global Instance MonVecMon M {MM : Monoid M} (k : nat) : Monoid (Vector.t M k).
Proof.
  econstructor.
  - eapply (@Vector.map2 M M M (@monoid_plus M _)).
  - eapply (Vector.const (@monoid_unit M _)).
Defined.
Global Program Instance MonLawsVecMon M {MM : Monoid M} {MLM : MonoidLaws MM} (k : nat)
  : MonoidLaws (@MonVecMon M _ k).
Next Obligation.
  intros.
  rewrite vec_map2_map2_assoc;eauto.
  setoid_rewrite monoid_assoc.
  reflexivity.
Qed.
Next Obligation.
  intros.
  rewrite vec_map2_const1.
  setoid_rewrite Vector.map_ext with (g:=fun x => x).
  + eapply Vector.map_id.
  + setoid_rewrite monoid_lunit.
    reflexivity.
Qed.
Next Obligation.
  intros.
  rewrite vec_map2_const2.
  setoid_rewrite Vector.map_ext with (g:=fun x => x).
  + eapply Vector.map_id.
  + setoid_rewrite monoid_runit.
    reflexivity.
Qed.

Global Instance MonVecNat : forall (k : nat), Monoid@{Type} (Vector.t nat k).
Proof.
  intros. exact _.
Defined.
Global Instance MonLawsVecNat (k : nat) : MonoidLaws (MonVecNat k).
Proof.
  eapply MonLawsVecMon.
Qed.

Section with_MN12.
  Context {M1 M2 N1 N2 : Type}.
  Context (hom1 : M1 -> N1) (hom2 : M2 -> N2).

  Definition pair_hom (m : M1 * M2)
    := let (m1,m2) := m in (hom1 m1, hom2 m2).

  Global Instance pair_hom_inst `(MH1 : MonoidHomomorphism _ _ hom1) `(MH2 : MonoidHomomorphism _ _ hom2)
    : MonoidHomomorphism pair_hom.
  Proof.
    econstructor.
    - intros.
      unfold pair_hom.
      destruct m1 as [m11 m12]. destruct m2 as [m21 m22].
      cbn.
      setoid_rewrite homomorph.
      reflexivity.
    - cbn.
      setoid_rewrite homomorph_unit.
      reflexivity.
  Defined.

  Global Lemma pair_iso_inst `{MI1 : MonoidIsomorphism _ _ hom1} `{MI2 : MonoidIsomorphism _ _ hom2}
    (*{MonM1 : Monoid M1} {MonM2 : Monoid M2} {MonN1 : Monoid N1} {MonN2 : Monoid N2}*)
    : MonoidIsomorphism pair_hom.
  Proof.
    econstructor.
    - eapply pair_hom_inst.
      1,2:eapply MonoidIsomorphism_homomorph.
    - intros.
      destruct m1,m2.
      cbn in H.
      inversion H.
      f_equal.
      all:eapply injective;eauto.
    - intros.
      destruct m.
      specialize (surjective n) as Q1.
      specialize (surjective n0) as Q2.
      destruct Q1, Q2.
      exists (x,x0).
      cbn.
      f_equal;eauto.
  Defined.
End with_MN12.

Section with_X.
  Context {X : Type}.

  Global Instance len_hom
    : MonoidHomomorphism (@length X).
  Proof.
    constructor.
    - setoid_rewrite app_length.
      reflexivity.
    - cbn.
      reflexivity.
  Qed.
End with_X.