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 xbind f (P x))) // (a ? (nu F)) //
      (nu (fun xbind 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 bbind f (Q b)) F2' x b.
    apply howe_nu with L; intros; fold @bind in ×.
    forwards*: @howe_rename (fun xsubst (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 xappr 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 xappr F1 (c x))
    (fun xappr 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 xbind g (P x))) // (a ? F1) // bind f Q1 //
      nu (fun xbind 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 bbind g (Q b)) C'0 x b.
    apply sc_trans with (nu (fun xappr F1 (C x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (P'0 a0) ((fun a0appr F1 (C a0)) a0)).
    eapply sc_rename; eauto with hopi.
    apply sc_trans with (nu (fun xappr F'2 (C'0 x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (Q'0 a0) ((fun a0appr 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 xbind f (P x))) // (a ? P2) // (a ? Q2) //
      nu (fun xbind 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 bbind f (Q b)) C2'0 x b.
    apply sc_trans with (nu (fun xappr P2 (C x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (P'0 a0) ((fun a0appr P2 (C a0)) a0)).
    eapply sc_rename; eauto with hopi.
    apply sc_trans with (nu (fun xappr Q2 (C2'0 x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (Q'0 a0) ((fun a0appr 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 xbind f (P x))) // (a ? (nu F)) // bind g Q2 //
      nu (fun xbind 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 bbind f (Q b)) F'0 x b.
    apply sc_trans with (nu (fun xappr (F x) C1)); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (P'0 a0) ((fun a0appr (F a0) C1) a0)).
    eapply sc_rename; eauto with hopi.
    apply sc_trans with (nu (fun xappr (F'0 x) C'2)); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (Q'0 a0) ((fun a0appr (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 xbind g (P x))) // (a ? P1) // (a ? Q1) //
      nu (fun xbind 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 bbind g (Q b)) C2'0 x b.
    apply sc_trans with (nu (fun xappr P1 (C x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (P'0 a0) ((fun a0appr P1 (C a0)) a0)).
    eapply sc_rename; eauto with hopi.
    apply sc_trans with (nu (fun xappr F2 (C2'0 x))); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (Q'0 a0) ((fun a0appr 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 xbind f (P x))) // (a ? (nu F)) // bind g Q2 //
      nu (fun xbind 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 bbind f (Q b)) F'0 x b.
    apply sc_trans with (nu (fun xappr (F x) C1)); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (P'0 a0) ((fun a0appr (F a0) C1) a0)).
    eapply sc_rename; eauto with hopi.
    apply sc_trans with (nu (fun xappr (F'0 x) C'2)); auto with sc.
    apply sc_nu with L; intros.
    change (sc0 (Q'0 a0) ((fun a0appr (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 xbind f (Q x))) //
      (nu (fun xbind 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 bbind 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 xconc_def (P x)(Q x)))
      (fun xconc_def (P x)(Q x))
| pull_nunu : C C' L, ( a, ¬In a L
    conc_notin_ho a (fun xconc_nu (C x))
    conc_notin_ho a (fun xconc_nu (C' x))
    pull (conc_nu (C a))(C' a))
    pull (conc_nu (fun xconc_nu (C x)))
         (fun yconc_nu (fun xC' 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 xconc_nu (C1 x))). fn(conc_nu(fun xconc_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 xconc_nu (fun yC' x y))).
  fresh_lc (a::L++L0)(conc_nu (fun xconc_nu (C x))).
  forwards*: H1. simpl_notin.
  destruct n. forwards*: H4 x. inverts H3.
  forwards*: H x. forwards*: H0. constructor; intros.
  change (sizec ((fun a0C' 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 xconc_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 xconc_def (P0 a x)(Q0 a x)) = conc_nu (C' a)).
     rewrite HeqC'a. auto.
    change ((fun aconc_nu (fun xconc_def (P0 a x) (Q0 a x))) a
      = (fun aconc_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 yconc_nu (fun xC''' a x y)) = conc_nu (C'0 a)).
     rewrite× HeqC'a.
    change ((fun aconc_nu (fun yconc_nu (fun xC''' a x y))) a
      = (fun aconc_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 bconc_nu (C'' b a0)) b) ((fun bC''' 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 aC'' 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 aC''' 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 yconc_nu (fun xC'0 x y)).
  apply pull_nunu with (a::nil); intros.
  change (pull ((fun a0conc_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 xconc_def (P x) (Q x)) b)).
      apply cwf_aux_change with x; auto with hopi.
    - inverts H0. fn (conc_nu (fun xconc_nu (fun y ⇒ (C'0 x y)))).
      fn (conc_nu (fun xconc_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.