ITree.Eq.Rutt

Relation up to tau

rutt ("relation up to tau") is a generalization of eutt that may relate trees indexed by different event type families E.
It corresponds roughly to the interpretation of "types as relations" from the relational parametricity model by Reynolds (Types, Abstraction and Parametric Polymorphism). Any polymorphic function f : E R, itree E R ... should respect this relation, in the sense that for any relations rE, rR, the implication rutt rE rR t t' (f t ~~ f t') should hold, where ~~ is some canonical relation on the codomain of f.
If we could actually quotient itrees "up to taus", and Coq could generate parametricity ("free") theorems on demand, the above might be a free theorem.
rutt is used to define the trace_refine relation in ITree.ITrace.ITraceDefinition.

From Coq Require Import
     Morphisms
.

From ExtLib Require Import
     Structures.Monad.

From ITree Require Import
     Basics.Tacs
     Axioms
     ITree
     Eq
     Basics
.

From Paco Require Import paco.

Import Monads.
Import MonadNotation.
Local Open Scope monad_scope.

Section RuttF.

  Context {E1 E2 : Type Type}.
  Context {R1 R2 : Type}.
  (* From the point of view of relational parametricity, it would be more fitting
  to replace (REv, RAns) with one REv : A1 A2, (A1 A2 Prop) (E1 A1 E2 A2 Prop).
  Contributions to that effect are welcome. *)

  Context (REv : (A B : Type), E1 A E2 B Prop ).
  Context (RAns : (A B : Type), E1 A A E2 B B Prop ).
  Context (RR : R1 R2 Prop).
  Arguments REv {A} {B}.
  Arguments RAns {A} {B}.

  Inductive ruttF (sim : itree E1 R1 itree E2 R2 Prop) : itree' E1 R1 itree' E2 R2 Prop :=
  | EqRet : (r1 : R1) (r2 : R2),
      RR r1 r2
      ruttF sim (RetF r1) (RetF r2)
  | EqTau : (m1 : itree E1 R1) (m2 : itree E2 R2),
      sim m1 m2
      ruttF sim (TauF m1) (TauF m2)
  | EqVis : (A B : Type) (e1 : E1 A) (e2 : E2 B ) (k1 : A itree E1 R1) (k2 : B itree E2 R2),
      REv e1 e2
      ( (a : A) (b : B), RAns e1 a e2 b sim (k1 a) (k2 b))
      ruttF sim (VisF e1 k1) (VisF e2 k2)
  | EqTauL : (t1 : itree E1 R1) (ot2 : itree' E2 R2),
      ruttF sim (observe t1) ot2
      ruttF sim (TauF t1) ot2
  | EqTauR : (ot1 : itree' E1 R1) (t2 : itree E2 R2),
      ruttF sim ot1 (observe t2)
      ruttF sim ot1 (TauF t2).
  Hint Constructors ruttF : itree.

  Definition rutt_ (sim : itree E1 R1 itree E2 R2 Prop)
             (t1 : itree E1 R1) (t2 : itree E2 R2) :=
    ruttF sim (observe t1) (observe t2).
  Hint Unfold rutt_ : itree.

  Lemma rutt_monot : monotone2 rutt_.
  Proof.
    red. intros. red; induction IN; eauto with itree.
  Qed.

  Definition rutt : itree E1 R1 itree E2 R2 Prop := paco2 rutt_ bot2.

End RuttF.

#[global] Hint Resolve rutt_monot : paco.

Lemma rutt_inv_Tau_l {E1 E2 R1 R2 REv RAns RR} t1 t2 :
  @rutt E1 E2 R1 R2 REv RAns RR (Tau t1) t2 rutt REv RAns RR t1 t2.
Proof.
  intros. punfold H. red in H. simpl in ×.
  remember (TauF t1) as tt1. genobs t2 ot2.
  hinduction H before t1; intros; try discriminate.
  - inv Heqtt1. pclearbot. pstep. red. simpobs. econstructor; eauto. pstep_reverse.
  - inv Heqtt1. punfold_reverse H.
  - red in IHruttF. pstep. red; simpobs. econstructor; eauto. pstep_reverse.
Qed.

Lemma rutt_add_Tau_l {E1 E2 R1 R2 REv RAns RR} t1 t2 :
  @rutt E1 E2 R1 R2 REv RAns RR t1 t2 rutt REv RAns RR (Tau t1) t2.
Proof.
  intros. pfold. red. cbn. constructor. pstep_reverse.
Qed.

Lemma rutt_inv_Tau_r {E1 E2 R1 R2 REv RAns RR} t1 t2 :
  @rutt E1 E2 R1 R2 REv RAns RR t1 (Tau t2) rutt REv RAns RR t1 t2.
Proof.
  intros. punfold H. red in H. simpl in ×.
  pstep. red. remember (TauF t2) as tt2 eqn:Ett2 in H.
  revert t2 Ett2; induction H; try discriminate; intros; inversion Ett2; subst; auto.
  - pclearbot. constructor. pstep_reverse.
  - constructor. eapply IHruttF; eauto.
Qed.

Lemma rutt_add_Tau_r {E1 E2 R1 R2 REv RAns RR} t1 t2 :
  @rutt E1 E2 R1 R2 REv RAns RR t1 t2 rutt REv RAns RR t1 (Tau t2).
Proof.
  intros. pfold. red. cbn. constructor. pstep_reverse.
Qed.

Lemma rutt_inv_Tau {E1 E2 R1 R2 REv RAns RR} t1 t2 :
  @rutt E1 E2 R1 R2 REv RAns RR (Tau t1) (Tau t2) rutt REv RAns RR t1 t2.
Proof.
  intros; apply rutt_inv_Tau_r, rutt_inv_Tau_l; assumption.
Qed.

Section euttge_trans_clo.

  Context {E1 E2 : Type Type} {R1 R2 : Type} (RR : R1 R2 Prop).

  (* Closing a relation over itrees under euttge.
     Essentially the same closure as eqit_trans_clo, but heterogeneous
     in the interface argument E.
     We only define the closure under euttge as opposed to eqit_trans_clo
     capturing closure under eq_itree and eutt at the same time, since it's
     the only one we need.
   *)


  (* A transitivity functor *)
  Variant euttge_trans_clo (r : itree E1 R1 itree E2 R2 Prop) :
    itree E1 R1 itree E2 R2 Prop :=
    eqit_trans_clo_intro t1 t2 t1' t2' RR1 RR2
                         (EQVl: euttge RR1 t1 t1')
                         (EQVr: euttge RR2 t2 t2')
                         (REL: r t1' t2')
                         (LERR1: x x' y, RR1 x x' RR x' y RR x y)
                         (LERR2: x y y', RR2 y y' RR x y' RR x y) :
      euttge_trans_clo r t1 t2.
  Hint Constructors euttge_trans_clo : itree.

  Lemma euttge_trans_clo_mon r1 r2 t1 t2
        (IN : euttge_trans_clo r1 t1 t2)
        (LE : r1 <2= r2) :
    euttge_trans_clo r2 t1 t2.
  Proof.
    destruct IN; econstructor; eauto.
  Qed.

  Hint Resolve euttge_trans_clo_mon : paco.

End euttge_trans_clo.

(*replicate this proof for the models functor*)
(* Validity of the up-to euttge principle *)
Lemma euttge_trans_clo_wcompat E1 E2 R1 R2 (REv : A B, E1 A E2 B Prop)
      (RAns : A B, E1 A A E2 B B Prop ) (RR : R1 R2 Prop) :
  wcompatible2 (rutt_ REv RAns RR) (euttge_trans_clo RR).
Proof.
  constructor; eauto with paco.
  { red. intros. eapply euttge_trans_clo_mon; eauto. }
  intros.
  destruct PR. punfold EQVl. punfold EQVr. unfold_eqit.
  hinduction REL before r; intros; clear t1' t2'.
  - remember (RetF r1) as x. red.
    hinduction EQVl before r; intros; subst; try inv Heqx; eauto; (try constructor; eauto).
    remember (RetF r3) as x. hinduction EQVr before r; intros; subst; try inv Heqx; (try constructor; eauto).
  - red. remember (TauF m1) as x.
    hinduction EQVl before r; intros; subst; try inv Heqx; try inv CHECK; ( try (constructor; eauto; fail )).
    remember (TauF m3) as y.
    hinduction EQVr before r; intros; subst; try inv Heqy; try inv CHECK; (try (constructor; eauto; fail)).
    pclearbot. constructor. gclo. econstructor; eauto with paco.
  - remember (VisF e1 k1) as x. red.
    hinduction EQVl before r; intros; subst; try discriminate; try (constructor; eauto; fail).
    remember (VisF e2 k3) as y.
    hinduction EQVr before r; intros; subst; try discriminate; try (constructor; eauto; fail).
    dependent destruction Heqx.
    dependent destruction Heqy.
    constructor; auto. intros. apply H0 in H1. pclearbot.
    apply gpaco2_clo.
    econstructor; eauto with itree.
  - remember (TauF t1) as x. red.
    hinduction EQVl before r; intros; subst; try inv Heqx; try inv CHECK; (try (constructor; eauto; fail)).
    pclearbot. punfold REL. constructor. eapply IHREL; eauto.
  - remember (TauF t2) as y. red.
    hinduction EQVr before r; intros; subst; try inv Heqy; try inv CHECK; (try (constructor; eauto; fail)).
    pclearbot. punfold REL. constructor. eapply IHREL; eauto.
Qed.

#[global] Hint Resolve euttge_trans_clo_wcompat : paco.

(* The validity of the up-to euttge entails we can rewrite under euttge
   and hence also eq_itree during coinductive proofs of rutt
*)

#[global] Instance grutt_cong_eqit {R1 R2 : Type} {E1 E2 : Type Type} {REv : A B, E1 A E2 B Prop}
       {RAns : A B, E1 A A E2 B B Prop} {RR1 RR2} {RS : R1 R2 Prop} r rg
       (LERR1: x x' y, (RR1 x x': Prop) (RS x' y: Prop) RS x y)
       (LERR2: x y y', (RR2 y y': Prop) RS x y' RS x y) :
  Proper (eq_itree RR1 ==> eq_itree RR2 ==> flip impl)
         (gpaco2 (rutt_ REv RAns RS) (euttge_trans_clo RS) r rg).
Proof.
  repeat intro. gclo. econstructor; eauto;
    try eapply eqit_mon; try apply H; try apply H0; auto.
Qed.

Global Instance grutt_cong_euttge {R1 R2 : Type} {E1 E2 : Type Type} {REv : A B, E1 A E2 B Prop}
       {RAns : A B, E1 A A E2 B B Prop} {RR1 RR2} {RS : R1 R2 Prop} r rg
       (LERR1: x x' y, (RR1 x x': Prop) (RS x' y: Prop) RS x y)
       (LERR2: x y y', (RR2 y y': Prop) RS x y' RS x y) :
  Proper (euttge RR1 ==> euttge RR2 ==> flip impl)
         (gpaco2 (rutt_ REv RAns RS) (euttge_trans_clo RS) r rg).
Proof.
  repeat intro. gclo. econstructor; eauto.
Qed.