Library CatSem.COMP.type_arities


Require Import Coq.Bool.Bvector.
Require Export CatSem.CAT.cat_TYPE.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Transparent Obligations.
Unset Automatic Introduction.

Ltac app_any := match goal with [H:_|-_]=>apply H end.

this should be in std lib -- wtf

Section Vmap.

Variables A B : Type.
Variable f : A -> B.

Fixpoint Vmap n (X : vector A n) : vector B n :=
  match X in vector _ n return vector B n with
  | Vnil => Vnil _
  | Vcons a _ al => Vcons _ (f a) _ (Vmap al) end.

End Vmap.

Ltac simpind x := induction x; simpl; auto; rew_all; auto.

Lemma Vmap_id A l x: Vmap (A:=A) (fun x => x) (n:=l) x = x.
Proof.
  simpind x.
Qed.

Lemma Vmap_comp A B C (f : A -> B) (g : B -> C) l (x : vector A l):
     Vmap (fun x => g (f x)) x = Vmap g (Vmap f x).
Proof.
  simpind x.
Qed.

Hint Rewrite Vmap_id : vec.
Hint Resolve Vmap_id : vec.

Ltac vec := simpl; intros; autorewrite with vec;
               auto with vec.

Record type_sig : Type := {
  ts_ind : Type ;
  ts_dom : ts_ind -> nat }.

Section type_arity_reps.

Variable T : type_sig.

Class ts_rep_struct (X : Type) := {
  ts_rep_s : forall a : ts_ind T, vector X (ts_dom a) -> X }.

Record ts_rep := {
  ta_c :> Type ;
  ta_rep_s :> ts_rep_struct ta_c }.

Existing Instance ta_rep_s.

Section homs.

Variable A B : ts_rep.

Class ts_rep_hom_s (f : A -> B) : Prop := {
   ts_rep_hom_com :
       forall (a : ts_ind T) (x : vector A (ts_dom a)),
                   f (ts_rep_s x) = ts_rep_s (Vmap f x) }.

Record ts_rep_hom : Type := {
  ts_rep_hom_c :> A -> B ;
  ts_rep_hom_struct :> ts_rep_hom_s ts_rep_hom_c }.

End homs.

Existing Instance ts_rep_hom_struct.

Obligation Tactic := vec.

Program Instance ts_rep_id_s A : ts_rep_hom_s (fun x : _ A => x).
Definition ts_rep_id A := Build_ts_rep_hom (ts_rep_id_s A).

Obligation Tactic := simpl; intros; auto;
          repeat (rewrite Vmap_comp || rewrite ts_rep_hom_com ; app_any || auto).

Program Instance ts_rep_comp_s A B C (f : ts_rep_hom A B) (g : ts_rep_hom B C) :
                 ts_rep_hom_s (fun x : _ A => g (f x)).
Definition ts_rep_comp A B C f g := Build_ts_rep_hom (ts_rep_comp_s A B C f g).

Obligation Tactic := vec ; unfold Transitive; simpl; intros; etransitivity; auto.

Program Instance ts_eq A B : Equivalence (fun f g : ts_rep_hom A B => forall x, f x = g x).
Definition ts_oid A B := Build_Setoid (ts_eq A B).

Obligation Tactic := unfold Proper, respectful; simpl; intros;
        repeat rew_all; auto.

Program Instance TS_rep_s : Cat_struct ts_rep_hom := {
  mor_oid a b := ts_oid a b ;
  id := ts_rep_id ;
  comp := ts_rep_comp }.

Definition TS_rep := Build_Cat TS_rep_s.

Inductive ts_in : Type :=
  ts_build : forall i : ts_ind T, ts_in_list (ts_dom i) -> ts_in
with
  ts_in_list : nat -> Type :=
   | vnil : ts_in_list 0
   | vcons : forall n, ts_in -> ts_in_list n -> ts_in_list (S n).

Scheme ts_induct := Induction for ts_in Sort Prop with
      ts_list_induct := Induction for ts_in_list Sort Prop.

Fixpoint vec_f_ts_list n (x : ts_in_list n) : vector ts_in n :=
    match x in ts_in_list n return vector ts_in n with
        | vnil => Vnil
        | vcons _ a l => Vcons a (vec_f_ts_list l) end.

Fixpoint ts_list_f_vec n (x : vector ts_in n) : ts_in_list n :=
    match x in vector _ n return ts_in_list n with
        | Vnil => vnil
        | Vcons a _ l => vcons a (ts_list_f_vec l) end.

Lemma one_way n (x : ts_in_list n) :
         ts_list_f_vec (vec_f_ts_list x) = x.
Proof.
  simpind x.
Qed.

Lemma or_another n (x : vector ts_in n) :
         vec_f_ts_list (ts_list_f_vec x) = x.
Proof.
  simpind x.
Qed.

Program Instance ts_init_rep_s : ts_rep_struct ts_in := {
   ts_rep_s := fun a x => ts_build (ts_list_f_vec x) }.
Definition ts_init : TS_rep := Build_ts_rep ts_init_rep_s.

Section init.

Variable R : TS_rep.

Fixpoint init (x : ts_in) : R :=
  match x with ts_build i l => ts_rep_s (init_list l) end
with
  init_list i (x : ts_in_list i) : vector R i :=
  match x in ts_in_list i return vector R i with
    vnil => Vnil
    | vcons _ a al => Vcons (init a) (init_list al) end.

Lemma init_list_vmap (a : ts_ind T) (x : vector ts_in (ts_dom (t:=T) a)) :
    init_list (ts_list_f_vec x) = Vmap init x.
Proof.
  induction x; simpl;
  repeat (reflexivity || rew_all).
Qed.

Hint Rewrite init_list_vmap : vec.

Obligation Tactic := vec.

Program Instance init_hom_s : ts_rep_hom_s (A:=ts_init) (B:=R) init.

Definition init_hom := Build_ts_rep_hom init_hom_s.

Lemma unique : forall f : ts_init ---> R, f == init_hom.
Proof.
  simpl.
  intro f.
  apply (@ts_induct
              (fun t => f t = init t)
              (fun n lk => Vmap f (vec_f_ts_list lk) = init_list lk));
  simpl; intros; auto.
  assert (H2:= @ts_rep_hom_com _ _ f).
  simpl in H2.
  rewrite <- H.
  rewrite <- (H2 f).
  apply f_equal.
  apply f_equal.
  rew one_way.
  repeat rew_all.
  auto.
Qed.

End init.

Program Instance ts_INIT : Initial TS_rep := {
  Init := ts_init ;
  InitMor := init_hom ;
  InitMorUnique := unique
}.

End type_arity_reps.