Library HoweSound

Require Export Howe.

Notation pseudo_sim :=
  (∀ {V W:Set} Rel (P1 Q1:proc V)(P2 Q2:proc W) a F1 C1 (f:V → proc0)(g: W → proc0),
   simulation Rel → refl Rel → rename_compatible Rel → (Rincl sc0 Rel) → trans Rel
   → howe Rel P2 Q2 → howe Rel P1 Q1
   → ltsabs (bind f P1) a F1 → ltsconc (bind g P2) a C1
   → ∃ F2 C2 P'2 Q'2, ltsabs (bind f Q1) a F2 ∧
                            ltsconc (bind g Q2) a C2 ∧
                            sc0 P'2 (appr F1 C1) ∧
                            sc0 Q'2 (appr F2 C2) ∧
                            howe Rel P'2 Q'2).


Sequential proof, input then output


Lemma pseudo_inp_first {V:Set}:
  ∀ Rel (P1 Q1:proc V)(P2 Q2:proc0) a F1 (f:V → proc0),
    simulation Rel → refl Rel → rename_compatible Rel
  → (∀ P Q, Rel (P // PO) (Q // PO) → Rel P Q)
  → howe Rel P1 Q1 → howe Rel P2 Q2
  → ltsabs (bind f P1) a F1
  → ∃ F2, ltsabs (bind f Q1) a F2 ∧
                howe Rel (subst F1 P2) (subst F2 Q2).
Proof.
  introv Hsim Hrefl Hrename HpO Hp1q1. gen a f F1 P2 Q2.
  induction Hp1q1; introv Hp2q2 HltsP1; try solve [inverts HltsP1].
  - forwards*: IHHp1q1 Hp2q2 HltsP1. destruct H0 as [F2 [Hltsf2 Hhowe]].
    forwards*: H f. remember (conc_def Q2 PO) as C.
    assert (Hwf:conc_wf C). subst.
      unfold conc_wf. repeat constructor×.
    unfold simulation in Hsim. forwards_test Rel.
    subst. simpl in H5. apply HpO in H5.
    ∃ F'0; intuition.
    apply howe_comp with (subst F2 Q2); eauto with howe hopi.
      apply× oe_proc0.
  - simpl in ×. ∃ F1; intuition.
  - inverts HltsP1.
    + forwards*: IHHp1q1_1 Hp2q2 H3. destruct H as [F'2 [Hltsf'2 Hhowe]].
      ∃ (abs_parl F'2 (bind f Q')). split; simpl; eauto with hopi howe.
    + forwards*: IHHp1q1_2 Hp2q2 H3. destruct H as [F'2 [Hltsf'2 Hhowe]].
      ∃ (abs_parr (bind f Q) F'2 ). split; simpl; eauto with hopi howe.
  - inverts HltsP1. ∃ (bind (liftV f) Q). split; simpl; auto with hopi howe.
  - simpl in ×. inverts HltsP1.
    fresh_lp (a::L++L0) ((nu (fun x ⇒ bind f (P x))) // (a ? (nu F)) //
      (nu (fun x ⇒ bind f (Q x))) // P2 // Q2).
    forwards*: H2 x.
    forwards*: H0 x; auto with hopi.
    destruct H11 as [F2' [ HltsF2' Hrel ]]. exp x F2'. rename F2'0 into F2'.
    ∃ (nu F2'). split.
    apply ltsa_new with L0; intros; auto with hopi.
    assert (subst_name x b a a) by constructor×.
    forwards*: ltsabs_rename (fun b ⇒ bind f (Q b)) F2' x b.
    apply howe_nu with L; intros; fold @bind in ×.
    forwards*: @howe_rename (fun x⇒ subst (F x) P2)
          (fun x ⇒ (subst (F2' x) Q2)) x a0; auto with hopi;
      intros_all; apply× @notin_bind;
      intros [|]; simpl; auto with hopi.
Qed.

Lemma pseudo_inp_conc {V:Set}: ∀ Rel (P1 Q1:proc V) a F1 C (f:V → proc0),
    simulation Rel → refl Rel → rename_compatible Rel
  → (∀ P Q, Rel (P // PO) (Q // PO) → Rel P Q)
  → howe Rel P1 Q1
  → ltsabs (bind f P1) a F1
  → ∃ F2, ltsabs (bind f Q1) a F2 ∧ howe Rel (appr F1 C) (appr F2 C).
Proof.
  intros. induction C; simpl.
  forwards: @pseudo_inp_first p p H2 H3; auto with hopi howe.
  destruct H4 as [F2 []]. ∃ F2; split; auto with hopi howe.
  fresh_pc ((nu (fun x ⇒ appr F1 (c x)))// bind f Q1) (conc_nu c).
  forwards*: H4 x. destruct H5 as [F2 []]. ∃ F2; split; auto with hopi howe.
  apply howe_nu with (@nil name); intros.
  forwards*: @howe_rename (fun x ⇒ appr F1 (c x))
    (fun x ⇒ appr F2 (c x)) x a0.
    intros_all. solve_notin'. eapply ltsabs_notin; eauto.
Qed.

Lemma pseudo_sim_out : pseudo_sim.
Proof.
  introv Hsim Hrefl Hrename Hsc0 Htrans Hp2q2.
  assert (∀ P Q : proc0, Rel (P // PO) (Q // PO) → Rel P Q) as HpO.
    intros. eauto with sc.
  gen a f g F1 C1 P1 Q1.
  induction Hp2q2; introv Hp1q1 HltsP1 HltsP2; try solve [inverts HltsP2].
  - forwards*: IHHp2q2 a F1 C1 P1 Q1.
    destruct H0 as [F2 [C2 [ P'2 [R' [HltsQ1 [ HltsR [Hp'2 [Hr' HhoweP1R]]]]]]]].
    forwards*: H g. unfold simulation in ×.
    forwards_test Rel.
    ∃ F2 C'0 P'2 (appr F2 C'0); intuition.
    apply howe_comp with R'; auto with hopi howe.
      apply oe_trans with (appr F2 C2); auto.
      apply× oe_sc0. apply× oe_proc0.
  - forwards: @pseudo_inp_conc P1 Q1 F1 C1; eauto with hopi.
    destruct H as [F2 []]. ∃ F2 C1 (appr F1 C1) (appr F2 C1); intuition.
  - inverts HltsP2.
    + forwards*: IHHp2q2_1 Hp1q1 HltsP1 H3.
      destruct H as [F'2 [ C'2 [P'2 [Q'2 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]].
      ∃ F'2 (conc_parl C'2 (bind g Q')) (P'2// bind g P') (Q'2//bind g Q').
      splits; simpl; eauto with hopi howe sc.
    + forwards*: IHHp2q2_2 Hp1q1 HltsP1 H3.
      destruct H as [F'2 [ C'2 [P'2 [Q'2 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]].
      ∃ F'2 (conc_parr (bind g Q) C'2) (bind g P // P'2) (bind g Q // Q'2).
      splits; simpl; eauto with hopi howe sc.
  - inverts HltsP2. simpl.
    forwards*: @pseudo_inp_first Rel P1 Q1 (bind g P)(bind g Q).
      apply @howe_bind; auto with howe.
    destruct H as [F2 [HltsQ1 HhoweF1F2]].
    ∃ F2 (conc_def (bind g Q) (bind g Q'))
        (appr F1 (conc_def (bind g P) (bind g P')))
        (appr F2 (conc_def (bind g Q) (bind g Q'))); intuition auto with hopi howe;
      simpl; auto with sc hopi howe.
  - simpl in ×. inverts HltsP2.
    fresh_lpc (L0++L) ((nu (fun x ⇒ bind g (P x))) // (a ? F1) // bind f Q1 //
      nu (fun x ⇒ bind g (Q x))) (conc_nu C).
    forwards*: H2 x.
    forwards*: H0 x; auto with hopi.
    destruct H6 as [F'2 [ C'2 [P'2 [Q'2 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]].
    conc_exp x C'2. destruct (exists_cnew C'0) as [C'2].
    exp x P'2. exp x Q'2.
    ∃ F'2 C'2 (nu P'0) (nu Q'0); splits; auto.
    apply ltsc_new with C'0 L0; auto; intros.
    assert (subst_name x b a a) by constructor×.
    forwards*: ltsconc_rename (fun b ⇒ bind g (Q b)) C'0 x b.
    apply sc_trans with (nu (fun x ⇒ appr F1 (C x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (P'0 a0) ((fun a0 ⇒ appr F1 (C a0)) a0)).
    eapply sc_rename; eauto with hopi.
    apply sc_trans with (nu (fun x ⇒ appr F'2 (C'0 x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (Q'0 a0) ((fun a0 ⇒ appr F'2 (C'0 a0)) a0)).
    eapply sc_rename; eauto with hopi.
    intros_all. solve_notin'. eapply ltsabs_notin; eauto.
    apply howe_nu with L; intros.
    forwards*: @howe_rename P'0 Q'0 x a0.
Qed.


Sequential proof, output then input


Lemma pseudo_out_first {V:Set}: ∀ Rel (P1 Q1:proc V)(P2 Q2:proc1) a C1
  (f:V → proc0), simulation Rel → refl Rel →
  rename_compatible Rel → (Rincl sc0 Rel) → trans Rel →
  howe Rel P1 Q1 → howe Rel P2 Q2 →
  ltsconc (bind f P1) a C1 →
  ∃ C2 P'2 Q'2, ltsconc (bind f Q1) a C2 ∧
     sc0 P'2 (appr P2 C1) ∧
     sc0 Q'2 (appr Q2 C2) ∧ howe Rel P'2 Q'2.
Proof.
  introv Hsim Hrefl Hrename Hsc0 Htrans Hp1q1. gen a f C1 P2 Q2.
  induction Hp1q1; introv Hp2q2 HltsP1; try solve [inverts HltsP1].
  - forwards*: IHHp1q1 Hp2q2 HltsP1.
    destruct H0 as [C2 [P'2 [Q'2 [Hltsc2 [Hp'2 [Hq'2 Hhowe]]]]]].
    forwards: H f; auto. unfold simulation in ×.
    forwards_test Rel.
    ∃ C'0 P'2 (appr Q2 C'0); intuition.
    apply howe_comp with Q'2; auto with hopi howe.
      apply oe_trans with (appr Q2 C2); auto.
      apply× oe_sc0. apply× oe_proc0.
  - simpl in ×.
    ∃ C1 (appr P2 C1)(appr Q2 C1); intuition auto with howe sc.
    ind_conc; simpl; eauto with howe.
  - inverts HltsP1.
    + forwards*: IHHp1q1_1 Hp2q2 H3.
      destruct H as [ C'2 [P'2 [Q'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]].
      ∃ (conc_parl C'2 (bind f Q')) (P'2// bind f P') (Q'2//bind f Q').
      splits; simpl; eauto with hopi howe sc.
    + forwards*: IHHp1q1_2 Hp2q2 H3.
      destruct H as [ C'2 [P'2 [Q'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]].
      ∃ (conc_parr (bind f Q) C'2) (bind f P // P'2) (bind f Q // Q'2).
      splits; simpl; eauto with hopi howe sc.
  - inverts HltsP1. simpl.
    ∃ (conc_def (bind f Q) (bind f Q'))
        (appr P2 (conc_def (bind f P) (bind f P')))
        (appr Q2 (conc_def (bind f Q) (bind f Q')));
    simpl; intuition auto with hopi sc howe.
  - simpl in ×. inverts HltsP1.
    fresh_lpc (L0++L) ((nu (fun x ⇒ bind f (P x))) // (a ? P2) // (a ? Q2) //
      nu (fun x ⇒ bind f (Q x))) (conc_nu C).
    forwards*: H2 x.
    forwards*: H0 x; auto with hopi.
    destruct H6 as [C2' [P'2 [Q'2 [HltsC2' [Hp'2 [HQ'2 Hrel]]]]]].
    conc_exp x C2'. destruct (exists_cnew C2'0) as [C'2].
    exp x P'2. exp x Q'2.
    ∃ C'2 (nu P'0) (nu Q'0); splits; auto.
    apply ltsc_new with C2'0 L0; auto; intros.
    assert (subst_name x b a a) by constructor×.
    forwards*: ltsconc_rename (fun b ⇒ bind f (Q b)) C2'0 x b.
    apply sc_trans with (nu (fun x ⇒ appr P2 (C x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (P'0 a0) ((fun a0 ⇒ appr P2 (C a0)) a0)).
    eapply sc_rename; eauto with hopi.
    apply sc_trans with (nu (fun x ⇒ appr Q2 (C2'0 x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (Q'0 a0) ((fun a0 ⇒ appr Q2 (C2'0 a0)) a0)).
    eapply sc_rename; eauto with hopi.
    apply howe_nu with L; intros.
    forwards*: @howe_rename P'0 Q'0 x a0.
    Unshelve. exact (@nil name).
Qed.

Lemma pseudo_sim_in : pseudo_sim.
Proof.
  introv Hsim Hrefl Hrename Hsc0 Htrans Hp2q2 Hp1q1. gen a f g F1 C1 P2 Q2.
  induction Hp1q1; introv Hp2q2 HltsP1 HltsP2; try solve [inverts HltsP1].
  - forwards*: IHHp1q1 a F1 C1 P2 Q2.
    destruct H0 as [F2 [C2 [ P'2 [R' [HltsQ1 [ HltsR [Hp'2 [Hr' HhoweP1R]]]]]]]].
    forwards*: H f. unfold simulation in ×.
    assert (conc_wf C2). forwards*: lts_conc_wf HltsR.
    forwards_test Rel.
    ∃ F'0 C2 P'2 (appr F'0 C2); intuition.
    apply howe_comp with R'; auto with hopi howe.
      apply oe_trans with (appr F2 C2); auto.
      apply× oe_sc0. apply× oe_proc0.
  - simpl in ×.
    forwards: @pseudo_out_first P2 Q2 F1 F1 C1; eauto with howe hopi.
    destruct H as [C2 [ P'2 [Q'2 [HltsC2 [Hp'2 [Hq'2 Hhowe]]]]]].
    ∃ F1 C2 P'2 Q'2; intuition.
  - inverts HltsP1.
    + forwards*: IHHp1q1_1 Hp2q2 H3 HltsP2.
      destruct H as [F'2 [ C'2 [P'2 [Q'2 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]].
      ∃ (abs_parl F'2 (bind f Q')) C'2 (P'2// bind f P') (Q'2//bind f Q').
      splits; simpl; eauto with hopi howe sc.
    + forwards*: IHHp1q1_2 Hp2q2 H3 HltsP2.
      destruct H as [F'2 [ C'2 [P'2 [Q'2 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]].
      ∃ (abs_parr (bind f Q) F'2) C'2 (bind f P // P'2) (bind f Q // Q'2).
      splits; simpl; eauto with hopi howe sc.
  - inverts HltsP1. simpl. forwards*: @pseudo_out_first Rel P2 Q2 (bind (liftV f) P)(bind (liftV f) Q).
      apply× @howe_bind. intros [|]; simpl; auto with howe.
    destruct H as [ C'2 [P'2 [Q'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]].
    ∃ (bind (liftV f) Q) C'2 P'2 Q'2; intuition.
  - simpl in ×. inverts HltsP1.
    fresh_lpc (L0++L) ((nu (fun x ⇒ bind f (P x))) // (a ? (nu F)) // bind g Q2 //
      nu (fun x ⇒ bind f (Q x))) C1.
    forwards*: H2 x.
    forwards*: H0 x; auto with hopi.
    destruct H8 as [F'2 [ C'2 [P'2 [Q'2 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]].
    exp x F'2. exp x P'2. exp x Q'2.
    ∃ (nu F'0) C'2 (nu P'0)(nu Q'0); splits; auto.
    apply ltsa_new with L0; intros; auto with hopi.
    assert (subst_name x b a a) by constructor×.
    forwards*: ltsabs_rename (fun b ⇒ bind f (Q b)) F'0 x b.
    apply sc_trans with (nu (fun x ⇒ appr (F x) C1)); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (P'0 a0) ((fun a0 ⇒ appr (F a0) C1) a0)).
    eapply sc_rename; eauto with hopi.
    apply sc_trans with (nu (fun x ⇒ appr (F'0 x) C'2)); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (Q'0 a0) ((fun a0 ⇒ appr (F'0 a0) C'2) a0)).
    eapply sc_rename; eauto with hopi.
    intros_all. solve_notin'. eapply ltsconc_notin; eauto with hopi.
    apply howe_nu with L; intros.
    forwards*: @howe_rename P'0 Q'0 x a0.
Qed.


Simultaneous proof

the measure is lexico ordering of (size of output proof, size of input proof) see the variable case for input to see why. For a calculus with join patterns, the ordering should be lexico of (sum of size of outputs, size of input)

Lemma pseudo_sim_sim' :
  (∀ {V W:Set} Rel (P1 Q1:proc V)(P2 Q2:proc W) a F1 C1 (f:V → proc0)(g: W → proc0) n1 n2,
   simulation Rel → refl Rel → rename_compatible Rel → (Rincl sc0 Rel) → trans Rel
   → howe' Rel P2 Q2 n2 → howe' Rel P1 Q1 n1
   → ltsabs (bind f P1) a F1 → ltsconc (bind g P2) a C1
   → ∃ F2 C2 P'2 Q'2 n3, ltsabs (bind f Q1) a F2 ∧
                               ltsconc (bind g Q2) a C2 ∧
                               sc0 P'2 (appr F1 C1) ∧
                               sc0 Q'2 (appr F2 C2) ∧
                               howe' Rel P'2 Q'2 n3).
Proof.
  introv Hsim Hrefl Hrename Hsc0 Htrans.
  Require Import TLC.LibWf.
  assert (wf (lexico2 Peano.lt Peano.lt)).
    apply wf_lexico2; auto with wf.
  remember (n2, n1) as p. gen V W.
  gen n1 n2 a F1 C1.
  induction_wf IH: H p. intros n1 n2 Hp. subst.
  assert (∀ (V2 : Set) a (P1 Q1 : proc1) (n1 : nat) (P2 Q2 : proc V2),
     howe' Rel P1 Q1 n1
     → howe' Rel P2 Q2 n2
         → ∀ (g : V2 → proc0) (C1 : conc),
              ltsconc (bind g P2) a C1
                 → ∃ (C2:conc) P'2 Q'2 x3,
                     ltsconc (bind g Q2) a C2
                   ∧ sc0 P'2 (appr P1 C1)
                   ∧ sc0 Q'2 (appr Q1 C2) ∧ howe' Rel P'2 Q'2 x3).
  { intros.
    assert (howe' Rel (a? P1) (a? Q1)(S n0)) by auto with howe.
    remember (pr_var (V:=Empty_set)) as f.
    assert (∀ P, bind (liftV f) P = P).
      intros; rewrite× @bind_return. intros [|]; simpl; auto.
      intros. inverts e.
    destruct H1; try solve [inverts H2].
    - forwards*: IH (k, S n0) f; try solve [subst; simpl; eauto with hopi].
      destruct_hyps. specialize (H5 g). unfold simulation in ×.
      forwards_test Rel. inverts H6. rewrite H4 in ×.
      ∃ C'0 x1 (appr Q1 C'0)(S x3); intuition.
        apply howe_comp' with x2; auto with hopi howe.
        apply oe_trans with (appr Q1 x0); auto.
        apply× oe_sc0. apply× oe_proc0.
    - simpl in ×.
      assert (∃ n3, howe' Rel (appr P1 C1) (appr Q1 C1) n3).
        apply× @howe_implies_howe'. apply howe'_implies_howe in H0.
        ind_conc; simpl; eauto with howe.
      destruct H1. ∃ C1 (appr P1 C1)(appr Q1 C1) x0;
      intuition auto with sc.
  - inverts H2.
    + forwards*: IH f H3 H8; try solve [subst; simpl; eauto with hopi].
        apply lexico2_1. nat_math.
      destruct H1 as [ F2 [ C'2 [P'2 [Q'2 [ n3 [ HltsF2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]]].
      inverts HltsF2. rewrite H4 in ×.
      assert (∃ n4, howe' Rel (P'2// bind g P') (Q'2//bind g Q') n4).
        apply× @howe_implies_howe'. apply howe'_implies_howe in H1_0.
        apply howe'_implies_howe in Hhowe. auto with howe.
      destruct H2. ∃ (conc_parl C'2 (bind g Q')) (P'2// bind g P') (Q'2//bind g Q') x.
      splits; simpl; eauto with hopi howe sc.
    + forwards*: IH f H1_0 H8; try solve [subst; simpl; eauto with hopi].
        apply lexico2_1. omega.
      destruct H1 as [ F2 [ C'2 [P'2 [Q'2 [ n3 [ HltsF2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]]].
      inverts HltsF2. rewrite H4 in ×.
      assert (∃ n4, howe' Rel (bind g P // P'2) (bind g Q // Q'2) n4).
        apply× @howe_implies_howe'. apply howe'_implies_howe in H1_.
        apply howe'_implies_howe in Hhowe. auto with howe.
      destruct H2. ∃ (conc_parr (bind g Q) C'2) (bind g P // P'2) (bind g Q // Q'2) x.
      splits; simpl; eauto with hopi howe sc.
  - inverts H2. simpl.
    assert (∃ n, howe' Rel (appr P1 (conc_def (bind g P) (bind g P')))
        (appr Q1 (conc_def (bind g Q) (bind g Q'))) n).
      apply× @howe_implies_howe'. simpl. apply howe'_implies_howe in H1_.
      apply howe'_implies_howe in H1_0. apply howe'_implies_howe in H0.
      auto with howe.
    destruct H1. ∃ (conc_def (bind g Q) (bind g Q'))
        (appr P1 (conc_def (bind g P) (bind g P')))
        (appr Q1 (conc_def (bind g Q) (bind g Q'))) x;
    intuition auto with hopi sc.
  - simpl in ×. inverts H2.
    fresh_lpc (L0++L) ((nu (fun x ⇒ bind g (P x))) // (a ? P1) // (a ? Q1) //
      nu (fun x ⇒ bind g (Q x))) (conc_nu C).
    forwards*: H6 x.
    forwards*: H1 x; auto with hopi.
    forwards*: IH H9 H3; auto with hopi.
      apply lexico2_1. nat_math.
      rewrite bind_return'. apply ltsa_inp.
    destruct H14 as [F2 [C2' [P'2 [Q'2 [n3 [HltsF2 [HltsC2' [Hp'2 [HQ'2 Hrel]]]]]]]]].
    conc_exp x C2'. destruct (exists_cnew C2'0) as [C'2].
    exp x P'2. exp x Q'2. rewrite bind_return' in HltsF2. inverts HltsF2.
    ∃ C'2 (nu P'0) (nu Q'0) (S n3); splits; auto.
    apply ltsc_new with C2'0 L0; auto; intros.
    assert (subst_name x b a a) by constructor×.
    forwards*: ltsconc_rename (fun b ⇒ bind g (Q b)) C2'0 x b.
    apply sc_trans with (nu (fun x ⇒ appr P1 (C x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (P'0 a0) ((fun a0 ⇒ appr P1 (C a0)) a0)).
    eapply sc_rename; eauto with hopi.
    apply sc_trans with (nu (fun x ⇒ appr F2 (C2'0 x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (Q'0 a0) ((fun a0 ⇒ appr F2 (C2'0 a0)) a0)).
    eapply sc_rename; eauto with hopi.
    apply howe_nu' with L; intros.
    forwards*: @howe'_rename P'0 Q'0 x a0.
    }
  intros. destruct H2; try solve [inverts H3].
  + forwards*: IH H1 H3; try solve [simpl; eauto with hopi].
    destruct H6 as [F2 [C2 [ P'2 [R' [n3 [HltsQ1 [ HltsR [Hp'2 [Hr' HhoweP1R]]]]]]]]].
    forwards*: H5 f. unfold simulation in ×. assert (conc_wf C2). forwards*: lts_conc_wf HltsR.
    forwards_test Rel.
    assert (∃ n, howe' Rel P'2 (appr F'0 C2) n).
      apply× @howe_implies_howe'. apply howe'_implies_howe in HhoweP1R.
      apply howe_comp with R'; auto with hopi howe.
      apply oe_trans with (appr F2 C2); auto.
      apply× oe_sc0. apply× oe_proc0.
    destruct H13. ∃ F'0 C2 P'2 (appr F'0 C2) x; intuition.
  + simpl in ×. assert (∃ n1, howe' Rel F1 F1 n1).
      apply howe_implies_howe'; auto with howe hopi.
    destruct H2. forwards*: H0 H2 H1 H4. destruct_hyps.
    do 5 eexists; intuition (try eassumption).
  + inverts H3.
    - forwards*: IH H1 H2_; try solve [simpl; eauto with hopi].
        apply lexico2_2; omega.
      destruct H2 as [F'2 [ C'2 [P'2 [Q'2 [n3 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]]].
      assert (∃ n4, howe' Rel (P'2 // bind f P') (Q'2 // bind f Q') n4).
        apply× @howe_implies_howe'. apply howe'_implies_howe in H2_0.
        apply howe'_implies_howe in Hhowe. auto with hopi howe.
      destruct H2. ∃ (abs_parl F'2 (bind f Q')) C'2 (P'2// bind f P') (Q'2//bind f Q') x.
      splits; simpl; eauto with hopi sc howe.
    - forwards*: IH H1 H2_0; try solve [simpl; eauto with hopi].
        apply lexico2_2; omega.
      destruct H2 as [F'2 [ C'2 [P'2 [Q'2 [n3 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]]].
      assert (∃ n4, howe' Rel (bind f P // P'2) (bind f Q // Q'2) n4).
        apply× @howe_implies_howe'. apply howe'_implies_howe in H2_.
        apply howe'_implies_howe in Hhowe. auto with hopi howe.
      destruct H2. ∃ (abs_parr (bind f Q) F'2) C'2 (bind f P // P'2) (bind f Q // Q'2) x.
      splits; simpl; eauto with hopi howe sc.
  + inverts H3. assert (∃ n1, howe' Rel (bind (liftV f) P)(bind (liftV f) Q) n1).
      apply× @howe_implies_howe'. apply× @howe_bind. apply× @howe'_implies_howe.
      intros [|]; simpl; auto with howe.
    destruct H3. forwards*: H0 H3 H1. destruct_hyps.
    do 5 eexists; intuition (try eassumption).
    simpl. auto with hopi.
  + simpl in ×. inverts H3.
    fresh_lpc (L0++L) ((nu (fun x ⇒ bind f (P x))) // (a ? (nu F)) // bind g Q2 //
      nu (fun x ⇒ bind f (Q x))) C1.
    forwards*: H6 x.
    forwards*: H2 x; auto with hopi.
    forwards*: IH H1 H11 H5 ; auto with hopi.
      apply lexico2_2; nat_math.
    destruct H15 as [F'2 [ C'2 [P'2 [Q'2 [n3 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]]].
    exp x F'2. exp x P'2. exp x Q'2.
    ∃ (nu F'0) C'2 (nu P'0)(nu Q'0)(S n3); splits; auto.
    apply ltsa_new with L0; intros; auto with hopi.
    assert (subst_name x b a a) by constructor×.
    forwards*: ltsabs_rename (fun b ⇒ bind f (Q b)) F'0 x b.
    apply sc_trans with (nu (fun x ⇒ appr (F x) C1)); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (P'0 a0) ((fun a0 ⇒ appr (F a0) C1) a0)).
    eapply sc_rename; eauto with hopi.
    apply sc_trans with (nu (fun x ⇒ appr (F'0 x) C'2)); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (Q'0 a0) ((fun a0 ⇒ appr (F'0 a0) C'2) a0)).
    eapply sc_rename; eauto with hopi.
    intros_all. solve_notin'. eapply ltsconc_notin; eauto with hopi.
    apply howe_nu' with L; intros.
    forwards*: @howe'_rename P'0 Q'0 x a0.
    Unshelve. exact (@nil name).
Qed.

Lemma pseudo_sim_sim : pseudo_sim.
Proof.
  intros. apply howe_implies_howe' in H3; auto.
  apply howe_implies_howe' in H4; auto. destruct H3, H4.
  forwards*: @pseudo_sim_sim' H2 H3; try eassumption. destruct_hyps.
  apply howe'_implies_howe in H11. do 4 eexists; intuition eassumption.
Qed.


Part common to all proofs

to adapt the proof according to the chosen path
Notation lpseudo_sim := pseudo_sim_in .

Lemma pseudo_tau {V:Set}: ∀ Rel (P Q:proc V) P'
  (f:V → proc0), simulation Rel → refl Rel → rename_compatible Rel →
  (Rincl sc0 Rel) → trans Rel → howe Rel P Q →
  ltsproc (bind f P) P' →
  ∃ Q' P'' Q'', ltsproc (bind f Q) Q' ∧
                sc0 P' P'' ∧ sc0 Q' Q'' ∧ howe Rel P'' Q''.
Proof.
  introv Hsim Hrefl Hrename Hincl Htrans Hp1q1. gen f P'.
  induction Hp1q1; introv HltsP1; try solve [inverts HltsP1].
  - forwards*: IHHp1q1 P'.
    destruct H0 as [R' [P'' [R'' [HltsR [Hp'p'' [Hr'r'' HhoweP1R]]]]]].
    forwards: H f; auto. unfold simulation in ×. forwards_test Rel.
    ∃ Q'0 P'' Q'0; intuition.
    apply howe_comp with R''; auto with hopi howe.
      apply oe_trans with R'; auto. apply oe_sc0; auto with sc. apply× oe_proc0.
  - ∃ P' P' P'; intuition.
  - inverts HltsP1.
    + forwards: IHHp1q1_1 H2; auto.
      destruct H as [Q'1 [P''1 [Q''1 [HltsQ' [Hp'1p''1 [Hq'1q''1 Hhowe]]]]]].
      ∃ (Q'1 // (bind f Q')) (P''1 // (bind f P')) (Q''1 // (bind f Q')).
      splits; simpl; auto with sc howe hopi.
    + forwards: IHHp1q1_2 H2; auto.
      destruct H as [Q'1 [P''1 [Q''1 [HltsQ' [Hp'1p''1 [Hq'1q''1 Hhowe]]]]]].
      ∃ ((bind f Q) // Q'1) ((bind f P) // P''1) ((bind f Q) // Q''1).
      splits; simpl; auto with sc howe hopi.
    + forwards: lpseudo_sim H3 H1; eauto.
      destruct H as [F2 [C2 [P'2 [Q'2 [HltsQ' [HltsQ [Hp'2 [Hq'2 Hhowe]]]]]]]].
      ∃ (appl C2 F2) P'2 Q'2. splits; eauto with sc.
      eapply lts_taul'; eauto.
    + forwards: lpseudo_sim H1 H3; eauto.
      destruct H as [F2 [C2 [P'2 [Q'2 [HltsQ' [HltsQ [Hp'2 [Hq'2 Hhowe]]]]]]]].
      ∃ (appr F2 C2) P'2 Q'2. splits; eauto with sc.
      eapply lts_taur'; eauto.
  - inverts HltsP1.
    fresh_lp (L0++L) ((nu (fun x ⇒ bind f (Q x))) //
      (nu (fun x ⇒ bind f (P x))) // nu P'0).
    forwards*: H2 x.
    forwards*: H0 x; auto with hopi.
    destruct H8 as [Q'1 [P''1 [Q''1 [HltsQ' [Hp'1p''1 [Hq'1q''1 Hhowe]]]]]].
    all_exp x.
    ∃ (nu Q'0) (nu P''0) (nu Q''0); splits; eauto.
    apply ltsp_new with L; intros.
    forwards*: ltsproc_rename (fun b ⇒ bind f (Q b)) Q'0 x a.
    apply sc_nu with L; intros.
    eapply sc_rename; eauto with hopi.
    apply sc_nu with L; intros.
    eapply sc_rename; eauto with hopi.
    apply howe_nu with L; intros.
    forwards*: @howe_rename P''0 Q''0 x a.
Qed.



Inductive pull: conc → (name → conc) → Prop :=
| pull_nudef : ∀ P Q, pull (conc_nu (fun x ⇒ conc_def (P x)(Q x)))
      (fun x ⇒ conc_def (P x)(Q x))
| pull_nunu : ∀ C C' L, (∀ a, ¬In a L →
    conc_notin_ho a (fun x ⇒ conc_nu (C x)) →
    conc_notin_ho a (fun x ⇒ conc_nu (C' x)) →
    pull (conc_nu (C a))(C' a)) →
    pull (conc_nu (fun x ⇒ conc_nu (C x)))
         (fun y ⇒ conc_nu (fun x ⇒ C' x y)).


Lemma pull_conc_new : ∀ C, conc_wf (conc_nu C) →
             ∀ C', pull (conc_nu C) C' →
             conc_new C' (conc_nu C).
Proof.
  intros. gen C'. induction H; intros.
  + inverts H0.
  + inverts H1.
    × fresh_lpc (L'++L)((nu P) // nu Q) (conc_nu C). forwards*: H x.
        auto with hopi.
      inverts H2. constructor. inverts H9.
      intros. apply isin_arg with x; eauto.
    × fn(conc_nu (fun x ⇒ conc_nu (C1 x))). fn(conc_nu(fun x ⇒ conc_nu (C'0 x))).
      apply cnew_nu with (L++L'++L0++L1++L2); intros.
      simpl_notin. forwards*: H1. forwards*: H2. simpl_notin.
Qed.

Lemma pull_size : ∀ n C, sizec C (S n) →
    ∀ C', pull C C' → ∀ a, sizec (C' a) n.
Proof.
  intros. gen n. induction H0; auto; intros.
  inverts× H. inverts H1.
  fn(conc_nu (fun x⇒conc_nu (fun y ⇒ C' x y))).
  fresh_lc (a::L++L0)(conc_nu (fun x ⇒ conc_nu (C x))).
  forwards*: H1. simpl_notin.
  destruct n. forwards*: H4 x. inverts H3.
  forwards*: H x. forwards*: H0. constructor; intros.
  change (sizec ((fun a0 ⇒ C' a0 a) a0) n).
  eapply sizec_rename; eauto. auto with hopi.
Qed.

Lemma pull_rename : ∀ C C' a, conc_notin_ho a C →
  conc_notin_ho a (fun x ⇒ conc_nu (C' x)) → pull (C a)(C' a) →
  ∀ b, pull (C b)(C' b).
Proof.
  intros. remember (C a) as Ca. remember (C' a) as C'a.
  gen a b C C'. induction H1; intros.
  + ho_exp a P. ho_exp a Q. conc_change_ext.
    assert (conc_nu (fun x ⇒ conc_def (P0 a x)(Q0 a x)) = conc_nu (C' a)).
     rewrite HeqC'a. auto.
    change ((fun a ⇒ conc_nu (fun x ⇒ conc_def (P0 a x) (Q0 a x))) a
      = (fun a ⇒ conc_nu (C' a)) a) in H3.
    auto_conc_ext. apply equal_f with b in H4. inverts H4.
    constructor.
  + destruct (conc_ho_ho_beta_exp a C) as [C'' []].
    subst. conc_change_ext.
    destruct (conc_ho_ho_beta_exp a C') as [C''' []]. subst.
    assert (conc_nu (fun y ⇒ conc_nu (fun x ⇒ C''' a x y)) = conc_nu (C'0 a)).
     rewrite× HeqC'a.
    change ((fun a ⇒ conc_nu (fun y ⇒ conc_nu (fun x ⇒ C''' a x y))) a
      = (fun a ⇒ conc_nu (C'0 a)) a) in H5.
    auto_conc_ext.
    apply equal_f with b in H6. inverts H6.
    apply pull_nunu with (a::b::L); intros. simpl_notin.
    change (pull ((fun b ⇒ conc_nu (C'' b a0)) b) ((fun b ⇒ C''' b a0) b)).
    eapply H0; eauto; auto with hopi.
      intros_all. constructor; intros.
      forwards*: H6 b0. simpl_notin. forwards*: H16 b1.
      change (conc_notin a0 ((fun a ⇒ C'' a b0 b1) a)).
      eapply conc_notin_rename; eauto.
      intros_all. constructor; intros.
      forwards*: H8 b0. simpl_notin. forwards*: H16 b1.
      change (conc_notin a0 ((fun a ⇒ C''' a b0 b1) a)).
      eapply conc_notin_rename; eauto.
      intros_all. constructor; intros.
      forwards*: H3 a0. simpl_notin. forwards*: H16 b0. simpl_notin.
      intros_all. constructor; intros.
      forwards*: H4 a0. simpl_notin. forwards*: H16 b0. simpl_notin.
Qed.

Lemma exists_pull' : ∀ n C'', sizec C'' n →
  ∀ a C, conc_notin_ho a C → C'' = C a →
  ∃ C', pull (conc_nu C) C'.
Proof.
  induction n; intros; inverts H.
  conc_exp_ext a. eexists; econstructor.
  ho_conc_exp a C0. conc_change_ext.
  fresh_conc (conc_nu (C1 a)).
  forwards*: IHn x (C1 a). destruct H1 as [C'].
  ho_conc_exp a C'. ∃ (fun y ⇒ conc_nu (fun x ⇒ C'0 x y)).
  apply pull_nunu with (a::nil); intros.
  change (pull ((fun a0 ⇒ conc_nu (C1 a0)) a0)(C'0 a0)).
  apply pull_rename with a; auto with hopi.
Qed.

Lemma exists_pull : ∀ C, ∃ C', pull (conc_nu C) C'.
Proof.
  intros. fresh_conc (conc_nu C).
  destruct (exists_szc (C x)). forwards*: exists_pull'.
Qed.

Lemma pull_conc_wf : ∀ L C C',
   cwf_aux L C → pull C C' → ∀ b, cwf_aux (b::L)(C' b).
Proof.
  intros. gen L C'. induction C; intros.
  + inverts× H0.
  + inverts H1.
    - inverts H0. fresh_lp (b::L++L')((nu P) // nu Q).
      forwards*: H3 x. auto with hopi.
      rewrite <- (@app_nil_l name (b::L)).
      change (cwf_aux (nil ++ b :: L) ((fun x ⇒ conc_def (P x) (Q x)) b)).
      apply cwf_aux_change with x; auto with hopi.
    - inverts H0. fn (conc_nu (fun x ⇒ conc_nu (fun y ⇒ (C'0 x y)))).
      fn (conc_nu (fun x ⇒ conc_nu (C x))).
      apply cwf_nu with (b::L++L'++L0++L1++L2); intros.
      simpl_notin. forwards*: H1. forwards*: H0 a.
      simpl_notin. forwards*: H3 a.
      forwards*: H a (a::L).
      eapply cwf_include; eauto. intros_all.
      default_simp.
Qed.

Lemma conc_to_proc : ∀ n (C:conc), sizec C n →
   conc_wf C → ∀ a, ∃ P, ltsconc P a C ∧
        (∀ (C':conc), ltsconc P a C' → C = C').
Proof.
  induction n; intros; inverts H.
  + ∃ (a!(P) Q). split; auto with hopi.
    intros. inverts× H.
  +
    forwards*: exists_pull C0. destruct H as [C'].
    assert (Hnew: conc_new C' (conc_nu C0)) by apply× pull_conc_new.
    fresh_lc (a::nil)(conc_nu C0).
    forwards*: IHn (C' x) a.
      forwards*: pull_size H. constructor×.
      forwards*: pull_conc_wf x.
      eapply cwf_include; eauto. intros_all. default_simp.
    destruct H2 as [P []]. exp x P. ∃ (nu P0).
    split. apply ltsc_new with C' (a::nil); intros.
    assert (subst_name x b a a). constructor×.
    apply ltsconc_rename with a x; auto.
      forwards*: cnew_notin_rev; auto with hopi.
    auto.
    intros. assert (HxC'0:conc_notin x C'0).
      eapply ltsconc_notin; eauto with hopi.
    inverts H7. fresh_lpc (a::x::L) (nu P0) (conc_nu C).
    forwards*: H9 x0. assert (ltsconc (P0 x) a (C x)).
      apply ltsconc_rename with a x0; auto.
      constructor×.
    forwards*: H4. auto_conc_ext.
      forwards*: cnew_notin_rev Hnew x; auto with hopi.
      forwards*: cnew_notin_rev H10 x; auto with hopi.
    eapply cnew_unique; eauto.
Qed.

Lemma abs_to_proc : ∀ (F:abs) a,
    ∃ P, ltsabs P a F ∧
        (∀ (F':abs), ltsabs P a F' → F = F').
Proof.
  intros. ∃ (a? F); splits*; auto with hopi.
  intros. inverts× H.
Qed.

Lemma simulation_up_to_sc_howe : ∀ Rel, simulation Rel → refl Rel → rename_compatible Rel →
  (Rincl sc0 Rel) → trans Rel → simulation_up_to_sc (howe Rel).
Proof.
  intros_all. splits; intros.
  + replace P with (bind (pr_var (V:=Empty_set)) P) in H4 by (rewrite× bind_proc0).
    forwards: @pseudo_tau H3; eauto with hopi.
    destruct H5 as [Q' [P'' [Q'' [HltsQ' [Hpp'' [Hq'q'' Hhowe]]]]]].
    replace (bind (pr_var (V:=Empty_set)) Q) with Q in HltsQ' by (rewrite× bind_proc0).
    ∃ Q'. split×. do 2 (eexists; intuition eauto with sc).
  + replace P with (bind (pr_var (V:=Empty_set)) P) in H4 by (rewrite× bind_proc0).
    destruct (exists_szc C) as [n Hszc].
    forwards*: conc_to_proc C a. destruct H6 as [R [Hlts Hc']].
    assert (howe Rel R R) by apply× @howe_refl.
    replace R with (bind (pr_var (V:=Empty_set)) R) in Hlts by (rewrite× bind_proc0).
    forwards: lpseudo_sim H6 H3; eauto with hopi.
    destruct H7 as [F2 [C2 [P'2 [Q'2 [HltsQ [HltsR [Hpp'' [Hq'q'' Hhowe]]]]]]]].
    replace (bind (pr_var (V:=Empty_set)) Q) with Q in HltsQ by (rewrite× bind_proc0).
    replace (bind (pr_var (V:=Empty_set)) R) with R in HltsR by (rewrite× bind_proc0).
    forwards*: Hc' HltsR. subst. eexists; intuition eauto with sc.
    ∃ P'2; intuition eauto with sc. eexists; intuition eauto with sc.
  + replace P with (bind (pr_var (V:=Empty_set)) P) in H4 by (rewrite× bind_proc0).
    forwards*: abs_to_proc F a. destruct H5 as [R [Hlts Hf']].
    assert (howe Rel R R) by apply× @howe_refl.
    replace R with (bind (pr_var (V:=Empty_set)) R) in Hlts by (rewrite× bind_proc0).
    forwards: lpseudo_sim H3 H5; eauto with hopi.
    destruct H6 as [F2 [C2 [P'2 [Q'2 [HltsR [HltsQ [Hpp'' [Hq'q'' Hhowe]]]]]]]].
    replace (bind (pr_var (V:=Empty_set)) Q) with Q in HltsQ by (rewrite× bind_proc0).
    replace (bind (pr_var (V:=Empty_set)) R) with R in HltsR by (rewrite× bind_proc0).
    forwards*: Hf' HltsR. subst. eexists; intuition eauto with sc.
    ∃ P'2; intuition eauto with sc. eexists; intuition eauto with sc.
Qed.

Lemma Rincl_sc0_howe : ∀ Rel, (Rincl sc0 Rel) → Rincl sc0 (howe Rel).
Proof.
  intros_all. apply howe_comp with x; auto with sc howe.
  apply× oe_proc0.
Qed.

Lemma bisimulation_tclos_howe : ∀ Rel, simulation Rel → refl Rel
   → rename_compatible Rel → (Rincl sc0 Rel) → trans Rel → sym Rel
   → bisimulation (tclosure (howe Rel)).
Proof.
  intros. rename H3 into Hsym. apply sim_sym_imply_bisim.
  ×
    intros. assert (Rincl sc0 (tclosure (howe Rel))).
      intros_all. apply× tclosure_once. apply× Rincl_sc0_howe.
    intros_all. induction H4.
    + forwards*: simulation_up_to_sc_howe Rel.
      specialize (H5 x y H4).
      splits; intros; forwards_test (sc0° (howe Rel) ° sc0); destruct_comp;
      repeat (eexists; intuition (try eassumption)); intuition;
      repeat (match goal with
        | H1: Rincl sc0 (tclosure (howe Rel)),
          H2: sc0 _ _ |- _ ⇒ apply H1 in H2 end); eauto with howe.
    + splits; intros; forwards_test (tclosure (@howe Empty_set Rel)); clear H4_;
      forwards_test (tclosure (@howe Empty_set Rel)); destruct_comp;
        repeat (eexists; intuition (try eassumption)); intuition eauto with howe.
 × apply× @howe_sym.
Qed.

Theorem bisimilarity_howe : bisimilarity = howe bisimilarity.
Proof.
  apply binary_ext; split.
  - intros. assert (Hbisim:=H). unfold bisimilarity in H. destruct H. destruct H.
    apply howe_comp with x; auto with bisim. apply howe_refl; auto with bisim.
    apply× oe_proc0.
  - intros. ∃ (tclosure (@howe Empty_set bisimilarity)).
    split. apply bisimulation_tclos_howe; auto using bisim_sym, bisim_trans, bisim_refl,
      bisim_rename_compatible.
      forwards*: bisim_is_bisimulation; intuition.
      intros_all; apply bisim_refl.
      intros_all. ∃ sc0. intuition. apply struct_congr_bisim.
      apply× tclosure_once.
Qed.