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 x ⇒ conc_nu (fun y ⇒ C1 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 x ⇒ C1 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 x ⇒ appr (F0 b) (C1 x b)) a)
                                  ((fun x ⇒ appr (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 x ⇒ appr (F0 x) (C1 c x)) b)
                                  ((fun x ⇒ appr (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 x ⇒ appr (F1 x b) (C0 b)) a)
                                  ((fun x ⇒ appr (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 x ⇒ appr (F1 c x) (C0 x)) b)
                                  ((fun x ⇒ appr (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:V→W),
    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 x ⇒ s 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 v ⇒ s'' v c a).
  change (Rel ((fun x ⇒ (bind (fun v : V ⇒ s'' v c x) (P x))) a)
       ((fun x ⇒ (bind (fun v : V ⇒ s'' 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 x ⇒ s'' 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 x ⇒ s'' 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 x ⇒ s'' 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 x ⇒ s'' v x b0) c)).
    eapply notin_rename; eauto; auto with hopi.
  simpl in H10. change (Rel ((fun c ⇒ (bind (fun v : V ⇒ s'' v c b) (P b))) c)
       ((fun c ⇒ (bind (fun v : V ⇒ s'' 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 b0 ⇒ s'' 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 b0 ⇒ s'' 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 x ⇒ s'' 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 x ⇒ s'' v x b) b0)).
    eapply notin_rename; eauto; auto with hopi.
  simpl in H11. asserts_rewrite (s = (fun v ⇒ s'' v a b)).
    extens. intros. forwards*: H5 x1. forwards*: H6 x1.
    destruct_hyps. rewrite H17. rewrite× H16.
  auto.
Qed.