Rec.Framework.graded

Graded and Bigraded Domains

In this file we provide canonical structures and standard instances for graded and bigraded domains. This corresponds to definitions 3.2 and 5.2 from the paper.
While the paper only requires compositional graded domains, we provide additional instances for completeness.
From mathcomp Require Import ssreflect.all_ssreflect.
Require Import Base.axioms Base.fintype.
Set Implicit Arguments.
Unset Strict Implicit.

Canonical Structures


Module Graded1.
  Definition mixin_of (p : nat -> Type) :=
    forall m n, iren m n -> p m -> p n.
  Notation class_of := mixin_of (only parsing).

  Section Defs.
    Structure type := Pack
      { sort : nat -> Type
      ; _ : class_of sort
      ; _ : nat -> Type
      }.
    Local Coercion sort : type >-> Funclass.

    Variable (p : nat -> Type) (cT : type).
    Definition class :=
      let: Pack _ c _ := cT return class_of cT in c.

    Definition pack th := @Pack p th p.
    Definition clone c of phant_id class c := @Pack p c p.
  End Defs.

  Module Exports.
    Coercion sort : type >-> Funclass.
    Notation graded1 := type.
    Notation Graded1 p th := (@pack p th).

    Notation "[ 'graded1' 'of' p 'for' C ]" := (@clone p C _ idfun)
      (at level 0, format "[ 'graded1' 'of' p 'for' C ]") : form_scope.
    Notation "[ 'graded1' 'of' p ]" := (@clone p _ _ id)
      (at level 0, format "[ 'graded1' 'of' p ]") : form_scope.
  End Exports.
End Graded1.
Export Graded1.Exports.

Module Graded2.
  Definition mixin_of (p : nat -> nat -> Type) :=
    forall m1 n1 m2 n2, iren m1 m2 -> iren n1 n2 -> p m1 n1 -> p m2 n2.
  Notation class_of := mixin_of (only parsing).

  Section Defs.
    Structure type := Pack
      { sort : nat -> nat ->Type
      ; _ : class_of sort
      ; _ : nat -> nat -> Type
      }.
    Local Coercion sort : type >-> Funclass.

    Variable (p : nat -> nat -> Type) (cT : type).
    Definition class :=
      let: Pack _ c _ := cT return class_of cT in c.

    Definition pack th := @Pack p th p.
    Definition clone c of phant_id class c := @Pack p c p.
  End Defs.

  Module Exports.
    Coercion sort : type >-> Funclass.
    Notation graded2 := type.
    Notation Graded2 p th := (@pack p th).

    Notation "[ 'graded2' 'of' p 'for' C ]" := (@clone p C _ idfun)
      (at level 0, format "[ 'graded2' 'of' p 'for' C ]") : form_scope.
    Notation "[ 'graded2' 'of' p ]" := (@clone p _ _ id)
      (at level 0, format "[ 'graded2' 'of' p ]") : form_scope.
  End Exports.
End Graded2.
Export Graded2.Exports.

Definition th1 {T : graded1} {m n : nat} : iren m n -> T m -> T n := @Graded1.class T m n.
Arguments th1 {T m n} f x : simpl never.

Definition th2 {T : graded2} {m1 n1 m2 n2 : nat} : iren m1 m2 -> iren n1 n2 -> T m1 n1 -> T m2 n2 := @Graded2.class T m1 n1 m2 n2.
Arguments th2 {T m1 n1 m2 n2} f g x : simpl never.

Notation "x ⋅ f" := (@th1 _ _ _ f x)
  (at level 2, left associativity, format "x ⋅ f") : graded_scope.
Notation "x ⋅ ( f )" := (@th1 _ _ _ f x)
  (at level 2, left associativity, only parsing) : graded_scope.
Notation "x ⋅ ( f , g )" := (@th2 _ _ _ _ _ f g x)
  (at level 2, left associativity, format "x ⋅ ( f , g )") : graded_scope.
Open Scope graded_scope.

Module CGraded1.
  Definition mixin_of (T : graded1) :=
    forall m n k (f : iren m n) (g : iren n k) (x : T m), x f g = x (f >>> g).

  Section ClassDef.
    Record class_of (p : nat -> Type) := Class {
      base : Graded1.class_of p;
      mixin : mixin_of (Graded1.Pack base p)
    }.
    Local Coercion base : class_of >-> Graded1.class_of.

    Structure type := Pack {sort; _ : class_of sort; _ : nat -> Type }.
    Local Coercion sort : type >-> Funclass.

    Variable (T : nat -> Type) (cT : type).
    Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
    Definition clone c of phant_id class c := @Pack T c T.
    Let xT := let: Pack T _ _ := cT in T.
    Notation xclass := (class : class_of xT).

    Definition pack b0 (m0 : mixin_of (@Graded1.Pack T b0 T)) :=
      fun bT b & phant_id (@Graded1.class bT) b =>
      fun m & phant_id m0 m => Pack (@Class T b m) T.

    Definition graded1 := @Graded1.Pack cT xclass xT.
  End ClassDef.

  Module Exports.
    Coercion base : class_of >-> Graded1.class_of.
    Coercion mixin : class_of >-> mixin_of.
    Coercion sort : type >-> Funclass.

    Coercion graded1 : type >-> Graded1.type.
    Canonical graded1.

    Notation cgraded1 := type.
    Notation CGraded1 T m := (@pack T _ m _ _ id _ id).

    Notation "[ 'cgraded1' 'of' T 'for' C ]" := (@clone T C _ idfun)
      (at level 0, format "[ 'cgraded1' 'of' T 'for' C ]") : form_scope.
    Notation "[ 'cgraded1' 'of' T ]" := (@clone T _ _ id)
      (at level 0, format "[ 'cgraded1' 'of' T ]") : form_scope.
  End Exports.
End CGraded1.
Export CGraded1.Exports.

Module IGraded1.
  Definition mixin_of (T : graded1) :=
    forall n (x : T n), x idren = x.

  Section ClassDef.
    Record class_of (p : nat -> Type) := Class {
      base : Graded1.class_of p;
      mixin : mixin_of (Graded1.Pack base p)
    }.
    Local Coercion base : class_of >-> Graded1.class_of.

    Structure type := Pack {sort; _ : class_of sort; _ : nat -> Type }.
    Local Coercion sort : type >-> Funclass.

    Variable (T : nat -> Type) (cT : type).
    Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
    Definition clone c of phant_id class c := @Pack T c T.
    Let xT := let: Pack T _ _ := cT in T.
    Notation xclass := (class : class_of xT).

    Definition pack b0 (m0 : mixin_of (@Graded1.Pack T b0 T)) :=
      fun bT b & phant_id (@Graded1.class bT) b =>
      fun m & phant_id m0 m => Pack (@Class T b m) T.

    Definition graded1 := @Graded1.Pack cT xclass xT.
  End ClassDef.

  Module Exports.
    Coercion base : class_of >-> Graded1.class_of.
    Coercion mixin : class_of >-> mixin_of.
    Coercion sort : type >-> Funclass.

    Coercion graded1 : type >-> Graded1.type.
    Canonical graded1.

    Notation igraded1 := type.
    Notation IGraded1 T m := (@pack T _ m _ _ id _ id).

    Notation "[ 'igraded1' 'of' T 'for' C ]" := (@clone T C _ idfun)
      (at level 0, format "[ 'igraded1' 'of' T 'for' C ]") : form_scope.
    Notation "[ 'igraded1' 'of' T ]" := (@clone T _ _ id)
      (at level 0, format "[ 'igraded1' 'of' T ]") : form_scope.
  End Exports.
End IGraded1.
Export IGraded1.Exports.

Module PGraded1.
  Definition mixin_of (T : graded1) :=
    forall m n (f : iren m n), injective (@th1 T m n f).

  Section ClassDef.
    Record class_of (p : nat -> Type) := Class {
      base : Graded1.class_of p;
      mixin : mixin_of (Graded1.Pack base p)
    }.
    Local Coercion base : class_of >-> Graded1.class_of.

    Structure type := Pack {sort; _ : class_of sort; _ : nat -> Type }.
    Local Coercion sort : type >-> Funclass.

    Variable (T : nat -> Type) (cT : type).
    Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
    Definition clone c of phant_id class c := @Pack T c T.
    Let xT := let: Pack T _ _ := cT in T.
    Notation xclass := (class : class_of xT).

    Definition pack b0 (m0 : mixin_of (@Graded1.Pack T b0 T)) :=
      fun bT b & phant_id (@Graded1.class bT) b =>
      fun m & phant_id m0 m => Pack (@Class T b m) T.

    Definition graded1 := @Graded1.Pack cT xclass xT.
  End ClassDef.

  Module Exports.
    Coercion base : class_of >-> Graded1.class_of.
    Coercion mixin : class_of >-> mixin_of.
    Coercion sort : type >-> Funclass.

    Coercion graded1 : type >-> Graded1.type.
    Canonical graded1.

    Notation pgraded1 := type.
    Notation PGraded1 T m := (@pack T _ m _ _ id _ id).

    Notation "[ 'pgraded1' 'of' T 'for' C ]" := (@clone T C _ idfun)
      (at level 0, format "[ 'pgraded1' 'of' T 'for' C ]") : form_scope.
    Notation "[ 'pgraded1' 'of' T ]" := (@clone T _ _ id)
      (at level 0, format "[ 'pgraded1' 'of' T ]") : form_scope.
  End Exports.
End PGraded1.
Export PGraded1.Exports.

Module CGraded2.
  Definition mixin_of (T : graded2) :=
    forall m1 m2 m3 n1 n2 n3 (f1 : iren m1 m2) (f2 : iren m2 m3) (g1 : iren n1 n2) (g2 : iren n2 n3) (x : T m1 n1), x (f1,g1) (f2,g2) = x (f1 >>> f2, g1 >>> g2).

  Section ClassDef.
    Record class_of (p : nat -> nat -> Type) := Class {
      base : Graded2.class_of p;
      mixin : mixin_of (Graded2.Pack base p)
    }.
    Local Coercion base : class_of >-> Graded2.class_of.

    Structure type := Pack {sort; _ : class_of sort; _ : nat -> nat -> Type }.
    Local Coercion sort : type >-> Funclass.

    Variable (T : nat -> nat -> Type) (cT : type).
    Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
    Definition clone c of phant_id class c := @Pack T c T.
    Let xT := let: Pack T _ _ := cT in T.
    Notation xclass := (class : class_of xT).

    Definition pack b0 (m0 : mixin_of (@Graded2.Pack T b0 T)) :=
      fun bT b & phant_id (@Graded2.class bT) b =>
      fun m & phant_id m0 m => Pack (@Class T b m) T.

    Definition graded2 := @Graded2.Pack cT xclass xT.
  End ClassDef.

  Module Exports.
    Coercion base : class_of >-> Graded2.class_of.
    Coercion mixin : class_of >-> mixin_of.
    Coercion sort : type >-> Funclass.

    Coercion graded2 : type >-> Graded2.type.
    Canonical graded2.

    Notation cgraded2 := type.
    Notation CGraded2 T m := (@pack T _ m _ _ id _ id).

    Notation "[ 'cgraded2' 'of' T 'for' C ]" := (@clone T C _ idfun)
      (at level 0, format "[ 'cgraded2' 'of' T 'for' C ]") : form_scope.
    Notation "[ 'cgraded2' 'of' T ]" := (@clone T _ _ id)
      (at level 0, format "[ 'cgraded2' 'of' T ]") : form_scope.
  End Exports.
End CGraded2.
Export CGraded2.Exports.

Module IGraded2.
  Definition mixin_of (T : graded2) :=
    forall m n (x : T m n), x (idren,idren) = x.

  Section ClassDef.
    Record class_of (p : nat -> nat -> Type) := Class {
      base : Graded2.class_of p;
      mixin : mixin_of (Graded2.Pack base p)
    }.
    Local Coercion base : class_of >-> Graded2.class_of.

    Structure type := Pack {sort; _ : class_of sort; _ : nat -> nat -> Type }.
    Local Coercion sort : type >-> Funclass.

    Variable (T : nat -> nat -> Type) (cT : type).
    Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
    Definition clone c of phant_id class c := @Pack T c T.
    Let xT := let: Pack T _ _ := cT in T.
    Notation xclass := (class : class_of xT).

    Definition pack b0 (m0 : mixin_of (@Graded2.Pack T b0 T)) :=
      fun bT b & phant_id (@Graded2.class bT) b =>
      fun m & phant_id m0 m => Pack (@Class T b m) T.

    Definition graded2 := @Graded2.Pack cT xclass xT.
  End ClassDef.

  Module Exports.
    Coercion base : class_of >-> Graded2.class_of.
    Coercion mixin : class_of >-> mixin_of.
    Coercion sort : type >-> Funclass.

    Coercion graded2 : type >-> Graded2.type.
    Canonical graded2.

    Notation igraded2 := type.
    Notation IGraded2 T m := (@pack T _ m _ _ id _ id).

    Notation "[ 'igraded2' 'of' T 'for' C ]" := (@clone T C _ idfun)
      (at level 0, format "[ 'igraded2' 'of' T 'for' C ]") : form_scope.
    Notation "[ 'igraded2' 'of' T ]" := (@clone T _ _ id)
      (at level 0, format "[ 'igraded2' 'of' T ]") : form_scope.
  End Exports.
End IGraded2.
Export IGraded2.Exports.

Module PGraded2.
  Definition mixin_of (T : graded2) :=
    forall m1 m2 n1 n2 (f : iren m1 m2) (g : iren n1 n2), injective (@th2 T _ _ _ _ f g).

  Section ClassDef.
    Record class_of (p : nat -> nat -> Type) := Class {
      base : Graded2.class_of p;
      mixin : mixin_of (Graded2.Pack base p)
    }.
    Local Coercion base : class_of >-> Graded2.class_of.

    Structure type := Pack {sort; _ : class_of sort; _ : nat -> nat -> Type }.
    Local Coercion sort : type >-> Funclass.

    Variable (T : nat -> nat -> Type) (cT : type).
    Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c.
    Definition clone c of phant_id class c := @Pack T c T.
    Let xT := let: Pack T _ _ := cT in T.
    Notation xclass := (class : class_of xT).

    Definition pack b0 (m0 : mixin_of (@Graded2.Pack T b0 T)) :=
      fun bT b & phant_id (@Graded2.class bT) b =>
      fun m & phant_id m0 m => Pack (@Class T b m) T.

    Definition graded2 := @Graded2.Pack cT xclass xT.
  End ClassDef.

  Module Exports.
    Coercion base : class_of >-> Graded2.class_of.
    Coercion mixin : class_of >-> mixin_of.
    Coercion sort : type >-> Funclass.

    Coercion graded2 : type >-> Graded2.type.
    Canonical graded2.

    Notation pgraded2 := type.
    Notation PGraded2 T m := (@pack T _ m _ _ id _ id).

    Notation "[ 'pgraded2' 'of' T 'for' C ]" := (@clone T C _ idfun)
      (at level 0, format "[ 'pgraded2' 'of' T 'for' C ]") : form_scope.
    Notation "[ 'pgraded2' 'of' T ]" := (@clone T _ _ id)
      (at level 0, format "[ 'pgraded2' 'of' T ]") : form_scope.
  End Exports.
End PGraded2.
Export PGraded2.Exports.

Lemmas


Lemma th_comp1 {T : cgraded1} {m n k : nat} (f : iren m n) (g : iren n k) (x : T m) :
  x f g = x (f >>> g).
Proof. exact: CGraded1.mixin. Qed.

Lemma th_id1 {T : igraded1} {n : nat} (x : T n) :
  x idren = x.
Proof. exact: IGraded1.mixin. Qed.

Lemma th_inj1 {T : pgraded1} {m n : nat} (f : iren m n) (x y : T m) :
  x f = y f -> x = y.
Proof. exact: PGraded1.mixin. Qed.

Lemma th_comp2 {T : cgraded2} {m1 m2 m3 n1 n2 n3 : nat} (f1 : iren m1 m2) (f2 : iren m2 m3) (g1 : iren n1 n2) (g2 : iren n2 n3) (x : T m1 n1) :
  x (f1,g1) (f2,g2) = x (f1 >>> f2, g1 >>> g2).
Proof. exact: CGraded2.mixin. Qed.

Lemma th_id2 {T : igraded2} {m n : nat} (x : T m n) :
  x (idren, idren) = x.
Proof. exact: IGraded2.mixin. Qed.

Lemma th_inj2 {T : pgraded2} {m1 m2 n1 n2} (f : iren m1 m2) (g : iren n1 n2) (x y : T m1 n1) :
  x (f,g) = y (f,g) -> x = y.
Proof. exact: PGraded2.mixin. Qed.

Instances

Fin grading


Section TrivialGraded1.
  Definition fin_th1 {m n : nat} (xi : ren m n) (x : fin m) : fin n := xi x.

  Canonical fin_graded1 := Eval hnf in Graded1 fin (@fin_th1).

  Lemma fin_cgraded1_mixin : CGraded1.mixin_of fin_graded1.
  Proof. by []. Qed.

  Canonical fin_cgraded1 := Eval hnf in CGraded1 fin fin_cgraded1_mixin.

  Lemma fin_igraded1_mixin : IGraded1.mixin_of fin_graded1.
  Proof. by []. Qed.

  Canonical fin_igraded1 := Eval hnf in IGraded1 fin fin_igraded1_mixin.

  Lemma fin_pgraded1_mixin : PGraded1.mixin_of fin_graded1.
  Proof. move=> m n f x y. exact: iren_inj. Qed.

  Canonical fin_pgraded1 := Eval hnf in PGraded1 fin fin_pgraded1_mixin.

  Lemma th1_finE {m n} (f : iren m n) : @th1 fin_graded1 m n f = f.
  Proof. by []. Qed.
End TrivialGraded1.

Constant grading


Definition const1 (V : Type) : nat -> Type := fun=> V.

Section ConstGraded1.
  Variable (T : Type).

  Canonical const_graded1 : graded1 :=
    Eval hnf in Graded1 (const1 T) (fun _ _ _ => id).

  Lemma const_cgraded1_mixin : CGraded1.mixin_of const_graded1.
  Proof. by []. Qed.

  Canonical const_cgraded1 :=
    Eval hnf in CGraded1 (const1 T) const_cgraded1_mixin.

  Lemma const_igraded1_mixin : IGraded1.mixin_of const_graded1.
  Proof. by []. Qed.

  Canonical const_igraded1 := Eval hnf in IGraded1 (const1 T) const_igraded1_mixin.

  Lemma const_pgraded1_mixin : PGraded1.mixin_of const_graded1.
  Proof. move=> m n f x y. exact. Qed.

  Canonical const_pgraded1 := Eval hnf in PGraded1 (const1 T) const_pgraded1_mixin.

  Lemma th1_constE {m n} (f : iren m n) : @th1 const_graded1 m n f = id.
  Proof. by []. Qed.
End ConstGraded1.

Monotone grading


Definition box (V : nat -> Type) (m : nat) : Type :=
  forall n, iren m n -> V n.

Section BoxGraded1.
  Variable (V : nat -> Type).

  Canonical box_graded1 : graded1 :=
    Eval hnf in Graded1 (box V) (fun m n f bv k g => bv k (f >>> g)).

  Lemma box_cgraded1_mixin : CGraded1.mixin_of box_graded1.
  Proof. by []. Qed.

  Canonical box_cgraded1 :=
    Eval hnf in CGraded1 (box V) box_cgraded1_mixin.

  Lemma box_igraded1_mixin : IGraded1.mixin_of box_graded1.
  Proof. by []. Qed.

  Canonical box_igraded1 :=
    Eval hnf in IGraded1 (box V) box_igraded1_mixin.

  Lemma th1_boxE {m n k} (f : iren m n) (g : iren n k) (b : box V m) : (b f) k g = b k (f >>> g).
  Proof. by []. Qed.
End BoxGraded1.

Notation "☐ V" := (box V) (at level 2).

Set grading


Definition pred1 (A : nat -> Type) (n : nat) := A n -> Prop.

Definition im {X Y} (f : X -> Y) (P : X -> Prop) (y : Y) : Prop :=
  exists2 x, P x & f x = y.

Lemma im_inj {X Y} (f : X -> Y) (P : X -> Prop) (x : X) :
  injective f -> im f P (f x) = P x.
Proof.
  move=> fP. apply: pext; split=> [[x' px' /fP <-//]|px]. by exists x.
Qed.

Lemma im_injective {X Y} (f : X -> Y) :
  injective f -> injective (im f).
Proof.
  move=> fP P Q E. fext=> x. by rewrite -(im_inj P x fP) E im_inj.
Qed.

Lemma im_id {X} (P : X -> Prop) : im id P = P.
Proof. fext=> x. apply: pext; split=> [[y py <-//]|px]. by exists x. Qed.

Lemma im_comp {X Y Z} (f : X -> Y) (g : Y -> Z) (P : X -> Prop) :
  im g (im f P) = im (f >> g) P.
Proof.
  fext=> x. apply: pext; split=>[[y[z pz <-]<-]|[z pz <-]].
    by exists z. exists (f z) => //. by exists z.
Qed.

Section PredGrading.
  Variable (A : graded1).

  Definition pred_th1 {m n} (f : iren m n) (P : pred1 A m) : pred1 A n := im (th1 f) P.

  Canonical pred_graded1 := Eval hnf in Graded1 (pred1 A) (@pred_th1).

  Lemma th1_predE {m n} (f : iren m n) (P : pred1 A m) : P f = im (th1 f) P.
  Proof. by []. Qed.
End PredGrading.

Section PredCGrading.
  Variable (A : cgraded1).

  Lemma pred_cgraded1_mixin : CGraded1.mixin_of (pred_graded1 A).
  Proof.
    move=>/=m n k f g P. rewrite !th1_predE im_comp. f_equal.
    fext=> x /=. by rewrite th_comp1.
  Qed.

  Canonical pred_cgraded1 := Eval hnf in CGraded1 (pred1 A) pred_cgraded1_mixin.
End PredCGrading.

Section PredIGrading.
  Variable (A : igraded1).

  Lemma pred_igraded1_mixin : IGraded1.mixin_of (pred_graded1 A).
  Proof.
    hnf; intros. fext=> H. apply: pext; split. move=> [H' P]. by rewrite th_id1 => <-.
    move=> H'. hnf. exists H => //. by rewrite th_id1.
  Qed.

  Canonical pred_igraded1 := Eval hnf in IGraded1 (pred1 A) pred_igraded1_mixin.
End PredIGrading.

Section PredPGrading.
  Variable (A : pgraded1).

  Lemma pred_pgraded1_mixin : PGraded1.mixin_of (pred_graded1 A).
  Proof.
    move=> m n f /=. apply: im_injective. exact: th_inj1.
  Qed.

  Canonical pred_pgraded1 := Eval hnf in PGraded1 (pred1 A) pred_pgraded1_mixin.
End PredPGrading.

Left/Right bigrading


Definition constl (F : nat -> Type) (m n : nat) : Type := F m.
Definition constr (F : nat -> Type) (m n : nat) : Type := F n.

Section LiftGrading.
  Variable (F : graded1).

  Definition constl_th2 {m1 n1 m2 n2 : nat} (f : iren m1 m2) (g : iren n1 n2)
    (x : constl F m1 n1) : constl F m2 n2 := x f.
  Definition constr_th2 {m1 n1 m2 n2 : nat} (f : iren m1 m2) (g : iren n1 n2)
    (x : constr F m1 n1) : constr F m2 n2 := x g.

  Canonical constl_graded2 := Eval hnf in Graded2 (constl F) (@constl_th2).
  Canonical constr_graded2 := Eval hnf in Graded2 (constr F) (@constr_th2).

  Lemma th2_constlE {m1 n1 m2 n2} (f : iren m1 m2) (g : iren n1 n2) :
    @th2 constl_graded2 m1 n1 m2 n2 f g = @th1 F m1 m2 f.
  Proof. by []. Qed.

  Lemma th2_constrE {m1 n1 m2 n2} (f : iren m1 m2) (g : iren n1 n2) :
    @th2 constr_graded2 m1 n1 m2 n2 f g = @th1 F n1 n2 g.
  Proof. by []. Qed.
End LiftGrading.

Section LiftCGrading.
  Variable (F : cgraded1).

  Lemma constl_cgraded2_mixin : CGraded2.mixin_of (constl_graded2 F).
  Proof. hnf;intros. exact: th_comp1. Qed.

  Lemma constr_cgraded2_mixin : CGraded2.mixin_of (constr_graded2 F).
  Proof. hnf;intros. exact: th_comp1. Qed.

  Canonical contl_cgraded2 := Eval hnf in CGraded2 (constl F) constl_cgraded2_mixin.
  Canonical contr_cgraded2 := Eval hnf in CGraded2 (constr F) constr_cgraded2_mixin.
End LiftCGrading.

Section LiftIGrading.
  Variable (F : igraded1).

  Lemma constl_igraded2_mixin : IGraded2.mixin_of (constl_graded2 F).
  Proof. hnf;intros. exact: th_id1. Qed.

  Lemma constr_igraded2_mixin : IGraded2.mixin_of (constr_graded2 F).
  Proof. hnf;intros. exact: th_id1. Qed.

  Canonical constl_igraded2 := Eval hnf in IGraded2 (constl F) constl_igraded2_mixin.
  Canonical constr_igraded2 := Eval hnf in IGraded2 (constr F) constr_igraded2_mixin.
End LiftIGrading.

Section LiftPGrading.
  Variable (F : pgraded1).

  Lemma constl_pgraded2_mixin : PGraded2.mixin_of (constl_graded2 F).
  Proof. hnf;intros. exact: th_inj1. Qed.

  Lemma constr_pgraded2_mixin : PGraded2.mixin_of (constr_graded2 F).
  Proof. hnf;intros. exact: th_inj1. Qed.

  Canonical constl_pgraded2 := Eval hnf in PGraded2 (constl F) constl_pgraded2_mixin.
  Canonical constr_pgraded2 := Eval hnf in PGraded2 (constr F) constr_pgraded2_mixin.
End LiftPGrading.

Fin right bigrading


Definition fin2 : nat -> nat -> Type := constr fin.

Constant bigrading


Definition const2 (V : Type) : nat -> nat -> Type := fun _ _ => V.

Section ConstGraded2.
  Variable (T : Type).

  Canonical const_graded2 : graded2 :=
    Eval hnf in Graded2 (const2 T) (fun _ _ _ _ _ _ => id).

  Lemma const_cgraded2_mixin : CGraded2.mixin_of const_graded2.
  Proof. by []. Qed.

  Canonical const_cgraded2 :=
    Eval hnf in CGraded2 (const2 T) const_cgraded2_mixin.

  Lemma const_igraded2_mixin : IGraded2.mixin_of const_graded2.
  Proof. by []. Qed.

  Canonical const_igraded2 := Eval hnf in IGraded2 (const2 T) const_igraded2_mixin.

  Lemma const_pgraded2_mixin : PGraded2.mixin_of const_graded2.
  Proof. move=> m1 m2 n1 n2 f g x y. exact. Qed.

  Canonical const_pgraded2 := Eval hnf in PGraded2 (const2 T) const_pgraded2_mixin.

  Lemma th2_constE {m1 n1 m2 n2} (f : iren m1 m2) (g : iren n1 n2) :
    @th2 const_graded2 m1 n1 m2 n2 f g = id.
  Proof. by []. Qed.
End ConstGraded2.

Monotone bigrading


Definition box2 (V : nat -> nat -> Type) (m1 n1 : nat) : Type :=
  forall m2 n2, iren m1 m2 -> iren n1 n2 -> V m2 n2.

Section BoxGraded2.
  Variable (V : nat -> nat -> Type).

  Canonical box_graded2 : graded2 :=
    Eval hnf in Graded2 (box2 V)
      (fun m1 n1 m2 n2 f1 g1 bv m3 n3 f2 g2 => bv m3 n3 (f1 >>> f2) (g1 >>> g2)).

  Lemma box_cgraded2_mixin : CGraded2.mixin_of box_graded2.
  Proof. by []. Qed.

  Canonical box_cgraded2 :=
    Eval hnf in CGraded2 (box2 V) box_cgraded2_mixin.

  Lemma box_igraded2_mixin : IGraded2.mixin_of box_graded2.
  Proof. by []. Qed.

  Canonical box_igraded2 :=
    Eval hnf in IGraded2 (box2 V) box_igraded2_mixin.

  Lemma th2_boxE {m1 n1 m2 n2 m3 n3} (f1 : iren m1 m2) (f2 : iren m2 m3) (g1 : iren n1 n2) (g2 : iren n2 n3) (b : box2 V m1 n1) :
    @th2 box_graded2 m1 n1 m2 n2 f1 g1 b m3 n3 f2 g2 = b m3 n3 (f1 >>> f2) (g1 >>> g2).
  Proof. by []. Qed.
End BoxGraded2.

Notation "☐₂ V" := (box2 V) (at level 2).

Left grading


Definition left1 (n : nat) (F : nat -> nat -> Type) (m : nat) := F m n.

Section LeftGraded1.
  Variable (F : graded2) (n : nat).

  Definition left_th1 {m1 m2} (f : iren m1 m2) (x : left1 n F m1) : left1 n F m2 :=
    x (f,idren).

  Canonical left_graded1 := Eval hnf in Graded1 (left1 n F) (@left_th1).

  Lemma th1_leftE {m1 m2} (f : iren m1 m2) (x : left1 n F m1) :
    x f = x (f,idren).
  Proof. by []. Qed.
End LeftGraded1.

Section LeftCGraded1.
  Variable (F : cgraded2) (n : nat).

  Lemma left_cgraded1_mixin : CGraded1.mixin_of (left_graded1 F n).
  Proof.
    move=> /= m1 m2 m3 f1 f2 x. by rewrite !th1_leftE th_comp2.
  Qed.

  Canonical left_cgraded1 := Eval hnf in CGraded1 (left1 n F) left_cgraded1_mixin.
End LeftCGraded1.

Section LeftIGraded1.
  Variable (F : igraded2) (n : nat).

  Lemma left_igraded1_mixin : IGraded1.mixin_of (left_graded1 F n).
  Proof.
    move=> /= m x. by rewrite th1_leftE th_id2.
  Qed.

  Canonical left_igraded1 := Eval hnf in IGraded1 (left1 n F) left_igraded1_mixin.
End LeftIGraded1.

Section LeftPGraded1.
  Variable (F : pgraded2) (n : nat).

  Lemma left_pgraded1_mixin : PGraded1.mixin_of (left_graded1 F n).
  Proof.
    move=> /= m1 m2 f x y. rewrite !th1_leftE. exact: th_inj2.
  Qed.

  Canonical left_pgraded1 := Eval hnf in PGraded1 (left1 n F) left_pgraded1_mixin.
End LeftPGraded1.

Automation


Lemma th1_idX {T : igraded1} {n : nat} : @th1 T n n idren = id.
Proof. fext=> i. exact: th_id1. Qed.

Lemma th1_compX {T : cgraded1} {m n k : nat} (f : iren m n) (g : iren n k) :
  @th1 T m n f >> @th1 T n k g = @th1 T m k (f >>> g).
Proof. fext=> i /=. exact: th_comp1. Qed.

Lemma th1_compR {I : Type} {T : cgraded1} {m n k} (f : iren m n) (g : iren n k) (h : _ -> I) :
  @th1 T m n f >> (@th1 T n k g >> h) = @th1 T m k (f >>> g) >> h.
Proof. fext=> i /=. by rewrite th_comp1. Qed.

Lemma th2_idX {T : igraded2} {m n : nat} : @th2 T m n m n idren idren = id.
Proof. fext=> i. exact: th_id2. Qed.

Lemma th2_compX {T : cgraded2} {m1 m2 m3 n1 n2 n3} (f1 : iren m1 m2) (f2 : iren m2 m3) (g1 : iren n1 n2) (g2 : iren n2 n3) :
  @th2 T m1 n1 m2 n2 f1 g1 >> @th2 T m2 n2 m3 n3 f2 g2 = @th2 T m1 n1 m3 n3 (f1 >>> f2) (g1 >>> g2).
Proof. fext=> i /=. exact: th_comp2. Qed.

Lemma th2_compR {I : Type} {T : cgraded2} {m1 m2 m3 n1 n2 n3} (f1 : iren m1 m2) (f2 : iren m2 m3) (g1 : iren n1 n2) (g2 : iren n2 n3) (h : _ -> I) :
  @th2 T m1 n1 m2 n2 f1 g1 >> (@th2 T m2 n2 m3 n3 f2 g2 >> h) = @th2 T m1 n1 m3 n3 (f1 >>> f2) (g1 >>> g2) >> h.
Proof. fext=> i /=. by rewrite th_comp2. Qed.

Ltac gsimpl :=
  rewrite ?th1_idX ?th1_compX ?th1_compR
          ?th2_idX ?th2_compX ?th2_compR
          ?th_id1 ?th_comp1
          ?th_id2 ?th_comp2
          ?th1_finE
          ?th1_constE
          ?th1_boxE
          ?th1_predE
          ?th2_constlE
          ?th2_constrE
          ?th2_constE
          ?th2_boxE.