Library Bisimulation

Require Export Semantics.

Notation Rincl := LibRelation.rel_incl.

Definition comp_rel {A:Type} (R S :binary A) x y := z, R x z S z y.

Notation "R ° S" := (@comp_rel _ R S) (at level 42, right associativity).

Lemma comp_trans{A}: (R S:binary A), inverse (R°S) = (inverse S ° inverse R).
Proof.
  intros. apply binary_ext.
    split; intros H; destruct H as [ z [ H1 H2 ]]; eexists; eauto.
Qed.

Lemma comp_assoc {A} : (R S T:binary A), R ° S ° T = (R ° S) ° T.
Proof.
  intros. apply binary_ext. intros.
    split; introv H; inverts H as [H1 H2].
    inverts H2; repeat (eexists; intuition eauto).
    inverts H1; repeat (eexists; intuition eauto).
Qed.

Ltac destruct_comp :=
  repeat match goal with
    | H: (_ ° _) _ _ |- _unfold comp_rel in H; destruct_hyps
  end.


Early bisimulation


Notation test_proc Rel P Q :=
    ( P', ltsproc P P' Q', ltsproc Q Q' Rel P' Q').

Notation test_abs Rel P Q :=
  ( a (F:abs), ltsabs P a F (C:conc),
   conc_wf C (F':abs), ltsabs Q a F' Rel (appr F C) (appr F' C)).

Notation test_conc Rel P Q :=
  ( a (C:conc), ltsconc P a C (F:abs),
    (C':conc), ltsconc Q a C' Rel (appr F C) (appr F C')).

Definition simulation (Rel: binary proc0) : Prop :=
   P Q, Rel P Q test_proc Rel P Q test_abs Rel P Q test_conc Rel P Q.

Definition bisimulation (Rel : binary proc0) : Prop :=
  (simulation Rel) (simulation (inverse Rel)).

Ltac forwards_test Rel := try (match goal with
  | H1: P Q, Rel P Q _,
    H2: Rel ?P ?Q |- _specialize (H1 P Q H2)
  end); intuition auto; match goal with
  | H1: test_proc Rel ?P ?Q, H2: ltsproc ?P _ |- _
      let H' := fresh "H" in
      let Q' := fresh "Q'" in forwards H': H1 H2; destruct H' as [Q' []]
| H1: test_abs Rel ?P ?Q, H2: ltsabs ?P _ _, C:conc |- _
      let H' := fresh "H" in
      let F' := fresh "F'" in forwards× H': H1 H2 C; destruct H' as [F' []]
| H1: test_conc Rel ?P ?Q, H2: ltsconc ?P _ _, F:abs |- _
      let H' := fresh "H" in
      let F' := fresh "C'" in forwards× H': H1 H2 F; destruct H' as [F' []]
end.

Lemma transp_bisim_is_bisim: Rel, bisimulation (inverse Rel) bisimulation Rel.
Proof.
  unfold bisimulation; intuition.
Qed.

Lemma sim_sym_imply_bisim : Rel, simulation Rel sym Rel bisimulation Rel.
Proof.
  intros Rel Hsim Hsym.
  split; intuition.
  rewrite inverse_sym; auto.
Qed.

Lemma comp_sim_is_sim : R S, simulation R simulation S simulation (R°S).
Proof.
  intros_all. destruct_comp. unfold simulation in ×.
  forwards_test R; forwards_test S; eexists;
       intuition; try solve [eassumption]; eexists; intuition eassumption.
Qed.

Lemma comp_bisim_is_bisim : R S, bisimulation R bisimulation S bisimulation (R°S).
Proof.
  unfold bisimulation. intros; split; intuition auto using comp_sim_is_sim.
  rewrite× @comp_trans. auto using comp_sim_is_sim.
Qed.

Lemma union_sim_is_sim : Rel Rel', simulation Rel simulation Rel'
     simulation (LibRelation.union Rel Rel').
Proof.
  intros_all. unfold simulation in ×. inverts H1;
      [forwards_test Rel; eexists; intuition eauto; left× |
       forwards_test Rel'; eexists; intuition eauto; right*].
Qed.


Bisimilarity


Definition bisimilarity (P Q:proc0) := Rel, bisimulation Rel Rel P Q.

Lemma bisim_sym: sym bisimilarity.
Proof.
  intros_all. destruct H as [ Rel ]. (inverse Rel); intuition.
  apply transp_bisim_is_bisim; auto.
Qed.

Lemma bisim_trans: trans bisimilarity.
Proof.
  intros_all. inversion H as [ Rel ]. inversion H0 as [ Rel' ].
   (Rel ° Rel'). intuition. apply comp_bisim_is_bisim; auto.
   y; auto.
Qed.

Definition id_bisim (P Q:proc0) := P=Q.

Hint Unfold id_bisim bisimulation bisimilarity:bisim.

Lemma id_bisim_bisim: bisimulation id_bisim.
Proof.
  unfold id_bisim. apply sim_sym_imply_bisim.
  intros_all. subst. eexists; intuition eauto with hopi.
  intros_all; subst; intuition.
Qed.

Lemma bisim_refl: P, bisimilarity P P.
Proof.
  intros P. id_bisim. split. apply id_bisim_bisim. auto with bisim.
Qed.

Lemma bisim_is_bisimulation : bisimulation bisimilarity.
Proof.
  apply sim_sym_imply_bisim.
  + intros_all. inverts H. destruct H0. assert (Hbisim:=H).
      destruct H as [Hr Hrconv]. unfold simulation in ×.
      forwards_test x; eexists; intuition; try eassumption; x; intuition.
  + apply bisim_sym.
Qed.

two bisimilar terms are related by a symetric bisimulation
Lemma bisim_exists_sym_rel : P Q, bisimilarity P Q
     Rel, sym Rel simulation Rel Rel P Q.
Proof.
  intros.
  destruct H as [Rel [Hbis Hpq]].
   (LibRelation.union Rel (inverse Rel)).
  destruct Hbis as [ Hsim Hsimsym ].
  splits.
  - intros_all. destruct H. right. auto. left. auto.
  - apply union_sim_is_sim; auto.
  - left. auto.
Qed.

Definition rename_compatible {V:Set} Rel := (P Q:name proc V) a,
  notin_ho a P notin_ho a Q Rel (P a)(Q a)
   b, notin_ho b P notin_ho b Q Rel (P b)(Q b).

Inductive rel_renamed (Rel: binary proc0) : binary proc0 :=
| rrenamed_base : (P Q:proc0), Rel P Q rel_renamed Rel P Q
| rrenamed_def : (P Q:proc0), rel_renamed Rel P Q
     a P' Q', notin_ho a P' notin_ho a Q'
    P = P' a Q = Q' a b,
    notin_ho b P' notin_ho b Q' rel_renamed Rel (P' b)(Q' b).

Lemma simulation_rel_renamed: Rel, simulation Rel simulation (rel_renamed Rel).
Proof.
    intros_all. unfold simulation in ×. induction H0; intros.
      + forwards_test Rel; eauto using rrenamed_base.
      + splits; intros; subst.
        - all_exp b. forwards*: ltsproc_rename H5 a.
          forwards*: ltsproc_notin_ho H5 a.
          forwards_test (rel_renamed Rel). all_exp a.
          forwards*: ltsproc_rename H10 b.
          forwards*: ltsproc_notin_ho H10 b.
          eexists; split; try eassumption.
          apply rrenamed_def with (P'1 a)(Q'1 a) a; auto with hopi.
        - all_exp b. destruct (exists_sname a0 b a) as [d].
          forwards*: ltsabs_rename H7 a.
          forwards*: ltsabs_notin_ho H7 a.
          destruct (dec_name a b); subst.
          forwards_test (rel_renamed Rel).
          conc_exp b C. ho_conc_exp a C0.
          fresh_lpc (a::b::d::nil) ((nu P') // (a0 ? (nu F0)) // nu Q')
                    (conc_nu (fun xconc_nu (fun yC1 x y))).
          rename x into c. destruct IHrel_renamed as [Hp []].
          forwards*: H15 H9 (C1 c a).
            unfold conc_wf. assert (cwf_aux nil (C1 c b)).
            change (cwf_aux nil ((fun xC1 x b) c)).
            eapply cwf_aux_rename; eauto; auto with hopi.
            eapply cwf_aux_rename; eauto; auto with hopi.
          destruct_hyps. rename x into F'. all_exp a.
          assert (subst_name a b d a0).
            inverts H4; constructor.
            destruct (dec_name a b); subst; auto.
            forwards*: ltsabs_notin_label H7.
          forwards*: ltsabs_rename H22 b.
          forwards*: ltsabs_notin_ho H22 b.
          eexists; split; try eassumption.
          change (rel_renamed Rel ((fun xappr (F0 b) (C1 x b)) a)
                                  ((fun xappr (F'0 b) (C1 x b)) a)).
          apply rrenamed_def with (appr (F0 b)(C1 c b)) (appr (F'0 b)(C1 c b))
          c; eauto; auto with hopi.
          change (rel_renamed Rel ((fun xappr (F0 x) (C1 c x)) b)
                                  ((fun xappr (F'0 x) (C1 c x)) b)).
          eapply rrenamed_def; eauto; auto with hopi.
          intros_all. solve_notin'; auto with hopi.
          eapply ltsabs_notin; eauto; auto with hopi.
        - conc_exp b C. destruct (exists_sname a0 b a) as [d].
          forwards*: ltsconc_rename H7 a.
          forwards*: ltsconc_notin_ho H7 a.
          destruct (dec_name a b); subst.
          forwards_test (rel_renamed Rel).
          all_exp b. ho_exp a F0.
          fresh_lpc (a::b::d::nil) ((nu P') //
                    (a0 ? (nu (fun x ⇒ (nu fun y =>(F1 x y))))) // nu Q')
                    (conc_nu C0).
          rename x into c. destruct IHrel_renamed as [Hp []].
          forwards*: H17 H8 (F1 c a).
          destruct_hyps. rename x into C'. conc_exp a C'.
          assert (subst_name a b d a0).
            inverts H4; constructor.
            destruct (dec_name a b); subst; auto.
            forwards*: ltsconc_notin_label H7.
          forwards*: ltsconc_rename H21 b.
          forwards*: ltsconc_notin_ho H21 b.
          eexists; split; try eassumption.
          change (rel_renamed Rel ((fun xappr (F1 x b) (C0 b)) a)
                                  ((fun xappr (F1 x b) (C'0 b)) a)).
          apply rrenamed_def with (appr (F1 c b)(C0 b)) (appr (F1 c b)(C'0 b))
          c; eauto; auto with hopi.
          change (rel_renamed Rel ((fun xappr (F1 c x) (C0 x)) b)
                                  ((fun xappr (F1 c x) (C'0 x)) b)).
          eapply rrenamed_def; eauto; auto with hopi.
          intros_all. solve_notin'; auto with hopi.
          eapply ltsconc_notin; eauto; auto with hopi.
Qed.

Lemma bisim_rename_compatible : rename_compatible bisimilarity.
Proof.
  intros_all.
  forwards: bisim_exists_sym_rel H1.
  destruct H4 as [Rel [Hsym [Hsim Hpq]]].
   (rel_renamed Rel).
  split.
  - apply sim_sym_imply_bisim.
    apply× simulation_rel_renamed.
    intros_all. induction H4. apply rrenamed_base; auto.
    subst. apply rrenamed_def with (Q' a0) (P' a0) a0; eauto.
  - apply rrenamed_def with (P a)(Q a) a; eauto. apply rrenamed_base; auto.
Qed.


Open extension


Definition open_extension {V:Set} (Rel:binary proc0) (P Q:proc V) :=
    (s: V proc0), Rel (bind s P) (bind s Q).

Lemma oe_refl {V:Set} : Rel, refl Rel refl (@open_extension V Rel).
Proof.
  intros_all. apply H.
Qed.

Lemma oe_sym {V:Set} : Rel, sym Rel sym (@open_extension V Rel).
Proof.
  intros_all. apply H; auto.
Qed.

Lemma oe_trans {V:Set} : Rel, trans Rel trans (@open_extension V Rel).
Proof.
  intros_all. eauto.
Qed.

Lemma oe_mapV {V W:Set}: Rel (P Q:proc V) (f:VW),
    open_extension Rel P Q open_extension Rel (mapV f P)(mapV f Q).
Proof.
   intros_all. repeat(rewrite bind_mapV_comp); auto.
Qed.

Lemma oe_bind{V W:Set}: Rel (P Q:proc V) (f:V proc W),
    open_extension Rel P Q open_extension Rel (bind f P)(bind f Q).
Proof.
  unfold open_extension. intros. repeat (rewrite bind_bind). apply H.
Qed.

Lemma oe_proc0 : (Rel:binary proc0) (P Q:proc0), Rel P Q open_extension Rel P Q.
Proof.
  intros_all. repeat (rewrite bind_proc0); auto.
Qed.

Axiom fun_beta_exp : {V:Set} a (s: V proc0), s',
   v, notin_ho a (s' v) s v = s' v a.

Axiom fun_ho_beta_exp : {V:Set} a (s: V name proc0), s',
   v, notin_ho a (fun xs v x) s v = s' v a.

Lemma oe_rename: (Rel:binary proc0), (rename_compatible Rel)
    V, (@rename_compatible V (open_extension Rel)).
Proof.
  intros_all.
  destruct (dec_name a b); subst; auto.
  destruct (fun_beta_exp b s) as [s'].
  destruct (fun_ho_beta_exp a s') as [s''].
  fresh_lp (a::b::nil) (bind s (P a) // bind s (Q a)).
  rename x into c. forwards*: H1 (fun vs'' v c a).
  change (Rel ((fun x ⇒ (bind (fun v : Vs'' v c x) (P x))) a)
       ((fun x ⇒ (bind (fun v : Vs'' v c x) (Q x))) a)) in H8.
  forwards*: X a b.
    intros_all. apply× @notin_bind. intros.
    forwards*: H6 v. forwards*: H5 v. destruct_hyps.
    forwards*: H14 b0. rewrite H17 in H18.
    change (notin a ((fun xs'' v x b0) c)).
    eapply notin_rename; eauto; auto with hopi.
    intros_all. apply× @notin_bind. intros.
    forwards*: H6 v. forwards*: H5 v. destruct_hyps.
    forwards*: H14 b0. rewrite H17 in H18.
    change (notin a ((fun xs'' v x b0) c)).
    eapply notin_rename; eauto; auto with hopi.
    intros_all. apply× @notin_bind. intros.
    forwards*: H6 v. forwards*: H5 v. destruct_hyps.
    forwards*: H15 b0. rewrite H17 in H18.
    change (notin b ((fun xs'' v x b0) c)).
    eapply notin_rename; eauto; auto with hopi.
    intros_all. apply× @notin_bind. intros.
    forwards*: H6 v. forwards*: H5 v. destruct_hyps.
    forwards*: H15 b0. rewrite H17 in H18.
    change (notin b ((fun xs'' v x b0) c)).
    eapply notin_rename; eauto; auto with hopi.
  simpl in H10. change (Rel ((fun c ⇒ (bind (fun v : Vs'' v c b) (P b))) c)
       ((fun c ⇒ (bind (fun v : Vs'' v c b) (Q b))) c)) in H10.
  forwards*: X c a.
    intros_all. apply notin_bind_rev in H12.
    apply× @notin_bind. intros.
    forwards*: H6 v. forwards*: H5 v. destruct_hyps.
    assert (isinV v (P a)) by (eapply isinV_rename; eauto).
    forwards*: H12. rewrite H17 in H21. rewrite H18 in H21.
    change (notin c ((fun b0s'' v b0 b) b0)).
    eapply notin_rename; eauto; auto with hopi.
    destruct_hyps. eapply notin_rename; eauto.
    intros_all. apply notin_bind_rev in H13.
    apply× @notin_bind. intros.
    forwards*: H6 v. forwards*: H5 v. destruct_hyps.
    assert (isinV v (Q a)) by (eapply isinV_rename; eauto).
    forwards*: H13. rewrite H17 in H21. rewrite H18 in H21.
    change (notin c ((fun b0s'' v b0 b) b0)).
    eapply notin_rename; eauto; auto with hopi.
    destruct_hyps. eapply notin_rename; eauto.
    intros_all. apply× @notin_bind. intros.
    forwards*: H6 v. forwards*: H5 v. destruct_hyps.
    forwards*: H15 b. rewrite H18 in H19.
    change (notin a ((fun xs'' v x b) b0)).
    eapply notin_rename; eauto; auto with hopi.
    intros_all. apply× @notin_bind. intros.
    forwards*: H6 v. forwards*: H5 v. destruct_hyps.
    forwards*: H15 b. rewrite H18 in H19.
    change (notin a ((fun xs'' v x b) b0)).
    eapply notin_rename; eauto; auto with hopi.
  simpl in H11. asserts_rewrite (s = (fun vs'' v a b)).
    extens. intros. forwards*: H5 x1. forwards*: H6 x1.
    destruct_hyps. rewrite H17. rewrite× H16.
  auto.
Qed.