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
    lts (bind f P1) (inp a) (ag_abs F1) lts (bind g P2) (out a) (ag_conc C1)
    F2 C2 P'2 Q'2, lts (bind f Q1) (inp a) (ag_abs F2)
                            lts (bind g Q2) (out a) (ag_conc 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
   lts (bind f P1) (inp a) (ag_abs F1)
   F2, lts (bind f Q1) (inp a) (ag_abs F2)
                howe Rel (asubst F1 P2) (asubst 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 0 Q2 PO) as C.
    assert (Hwf:conc_wf C). subst. intros_all. omega.
    unfold simulation in Hsim. forwards_test Rel.
    destruct F2 as [R']; destruct F'0 as [Q'1]; subst. simpl in H5.
    apply HpO in H5. repeat (rewrite mapN_id' in H5).
     (abs_def Q'1); intuition. simpl.
    apply howe_comp with (subst R' Q2); eauto with howe hopi.
      apply× oe_proc0.
  - simpl in ×. F1; intuition. destruct F1 as [P']; simpl.
    apply howe_subst; auto with howe.
  - inverts HltsP1.
    + forwards: lts_inp_abs H2. destruct H as [F'1]. subst. simpl in H3.
      forwards*: IHHp1q1_1 Hp2q2 H2. destruct H as [F'2 [Hltsf'2 Hhowe]].
       (abs_parl F'2 (bind f Q')). split.
      eapply lts_parl'; eauto.
      inverts H3. destruct F'1 as [P'1]. destruct F'2 as [Q'1]. simpl.
      simpl in Hhowe. apply howe_par; auto with howe.
    + forwards: lts_inp_abs H2. destruct H as [F'1]. subst. simpl in H3.
      forwards*: IHHp1q1_2 Hp2q2 H2. destruct H as [F'2 [Hltsf'2 Hhowe]].
       (abs_parr (bind f Q) F'2 ). split.
      eapply lts_parr'; eauto.
      inverts H3. destruct F'1 as [P'1]. destruct F'2 as [Q'1]. simpl.
      simpl in Hhowe. apply howe_par; auto with howe.
  - inverts HltsP1. (abs_def (bind (liftV f) Q)). split.
    simpl. auto with hopi.
    simpl. apply howe_subst; auto with howe.
  - simpl in ×. inverts HltsP1.
    destruct l0; inverts H0. destruct A as [ | F1' | ]; inverts H1.
    forwards*: @howe_mapN Hp2q2 S.
    forwards*: IHHp1q1 H H3. destruct H0 as [F2' [ HltsF2' Hrel ]].
     (abs_new F2'). split. eapply lts_new'; eauto. destruct F1'; destruct F2'. simpl in ×.
    apply howe_nu.
    asserts_rewrite (bind
     (fun x : incV Empty_setmapN (fun x0 : natS x0) (subst_func P2 x))
     p = subst p (mapN S P2)). fequals. extens. intros [ |]; simpl; auto.
    asserts_rewrite (bind
     (fun x : incV Empty_setmapN (fun x0 : natS x0) (subst_func Q2 x))
     p0 = subst p0 (mapN S Q2)). fequals. extens. intros [ |]; simpl; auto. auto.
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
   lts (bind f P1) (inp a) (ag_abs F1)
   F2, lts (bind f Q1) (inp a) (ag_abs F2) howe Rel (appr F1 C) (appr F2 C).
Proof.
  intros. destruct C. forwards: mapN_lts (fun xn+x) H3.
  rewrite bind_mapN in H4. forwards*: @howe_mapN H2 (fun xn+x).
  forwards: @pseudo_inp_first p p H5 H4; auto with hopi howe.
  destruct H6 as [F2 [HltsF2 Hhowe]].
  rewrite <- bind_mapN in HltsF2. apply mapN_lts_rev in HltsF2; auto using shiftN_injective.
  destruct HltsF2 as [A' [l' [HF2 [HltsA' Hl']]]]. destruct l'; inverts Hl'.
  assert (n0=a). apply plus_reg_l in H7. auto. subst. destruct A' as [ |F'| ]; inverts HF2.
   F'; intuition. destruct F1 as [P'1]; destruct F' as [P'2]; simpl in ×.
  apply howe_genNu. apply howe_par; auto with howe.
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: lts_out_conc H2. destruct H as [C'1]. subst. simpl in H3.
      forwards*: IHHp2q2_1 Hp1q1 HltsP1 H2.
      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; eauto with hopi howe.
      eapply lts_parl'; eauto.
      apply sc_trans with (appr F1 C'1 // bind g P'); auto with sc hopi howe.
      inverts H3. assert (struct_congr
        (appr F1 C'1 // bind g P') (appr F1 (conc_parl C'1 (bind g P')))).
        destruct F1, C'1; simpl. eauto with sc.
      eauto with sc.
      apply sc_trans with (appr F'2 C'2 // bind g Q'); auto with sc hopi howe.
      assert (struct_congr
        (appr F'2 C'2 // bind g Q') (appr F'2 (conc_parl C'2 (bind g Q')))).
        destruct F'2, C'2; simpl. eauto with sc.
      auto with sc.
    + forwards: lts_out_conc H2. destruct H as [C'1]. subst. simpl in H3.
      forwards*: IHHp2q2_2 Hp1q1 HltsP1 H2.
      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; eauto with hopi howe.
      eapply lts_parr'; eauto.
      apply sc_trans with (bind g P // appr F1 C'1); auto with sc hopi howe.
      inverts H3. assert (struct_congr
        (bind g P // appr F1 C'1) (appr F1 (conc_parr (bind g P) C'1))).
        destruct F1, C'1; simpl. apply sc_trans with
          (genNu n (shiftN n (bind g P) // (subst ((shiftN n) p) p0 // p1))); eauto with sc.
      auto with sc hopi howe.
      apply sc_trans with (bind g Q // appr F'2 C'2); auto with sc hopi howe.
      assert (struct_congr (bind g Q // appr F'2 C'2)
                            (appr F'2 (conc_parr (bind g Q) C'2))).
        destruct F'2, C'2; simpl. apply sc_trans with
          (genNu n (shiftN n (bind g Q) // (subst ((shiftN n) p) p0 // p1))); eauto with sc.
      auto with sc hopi howe.
  - 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]]. assert ( F, fshiftN 0 F = F).
      destruct F; simpl; rewrite× @mapN_id'.
     F2 (conc_def 0 (bind g Q) (bind g Q'))
        (appr F1 (conc_def 0 (bind g P) (bind g P')))
        (appr F2 (conc_def 0 (bind g Q) (bind g Q'))); intuition auto with hopi howe;
      simpl; repeat (rewrite H); auto with sc hopi howe.
  - simpl in ×. inverts HltsP2. destruct A as [ | | C1']; inverts H1. destruct l0; inverts H0.
    simpl in H2. destruct_notin. forwards*: mapN_lts S HltsP1. simpl in H. rewrite bind_mapN in H.
    asserts_rewrite (S (n-1) = n) in H. omega. forwards*: @howe_mapN Hp1q1 S.
    forwards*: IHHp2q2 H0 H H3. destruct H1 as [F'2 [ C'2 [P'2 [Q'2 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]].
    rewrite <- bind_mapN in HltsF'2. apply mapN_lts_rev in HltsF'2; try (intros_all; omega).
    destruct HltsF'2 as [A' [l' [Hf'2 [HltsQ1 Hl']]]]. destruct A'; inverts Hf'2. destruct l'; inverts Hl'.
    asserts_rewrite (S n0 -1 = n0). omega.
     a (conc_new C'2) (nu P'2)(nu Q'2). splits; auto with hopi howe.
    eapply lts_new'; eauto. simpl; fsetdec.
    eauto with sc. eauto with sc.
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
  lts (bind f P1) (out a) (ag_conc C1)
   C2 P'2 Q'2, lts (bind f Q1) (out a) (ag_conc C2)
     sc0 P'2 (appr (abs_def P2) C1)
     sc0 Q'2 (appr (abs_def 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 ×. remember (abs_def Q2) as F.
    forwards_test Rel. subst.
     C'0 P'2 (appr (abs_def Q2) C'0); intuition.
    apply howe_comp with Q'2; auto with hopi howe.
      apply oe_trans with (appr (abs_def Q2) C2); auto.
      apply× oe_sc0. apply× oe_proc0.
  - simpl in ×.
     C1 (appr (abs_def P2) C1)(appr (abs_def Q2) C1);
                                          intuition auto with sc.
    destruct C1 as [n P Q]; simpl.
    apply howe_genNu. apply howe_par; auto with howe. apply howe_subst; auto with howe.
    apply howe_mapN; auto using shiftN_injective.
  - inverts HltsP1.
    + forwards: lts_out_conc H2. destruct H as [C'1]. subst. simpl in H3.
      forwards*: IHHp1q1_1 Hp2q2 H2.
      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; eauto with hopi howe.
      eapply lts_parl'; eauto.
      apply sc_trans with (appr (abs_def P2) C'1 // bind f P');
                                                        auto with sc hopi howe.
      inverts H3. assert (struct_congr
        (appr (abs_def P2) C'1 // bind f P')
        (appr (abs_def P2) (conc_parl C'1 (bind f P')))).
        destruct C'1; simpl. eauto with sc.
      eauto with sc hopi howe.
      apply sc_trans with (appr (abs_def Q2) C'2 // bind f Q');
                                                        auto with sc hopi howe.
      assert (struct_congr
        (appr (abs_def Q2) C'2 // bind f Q')
        (appr (abs_def Q2) (conc_parl C'2 (bind f Q')))).
        destruct C'2; simpl. eauto with sc.
      eauto with sc hopi howe.
    + forwards: lts_out_conc H2. destruct H as [C'1]. subst. simpl in H3.
      forwards*: IHHp1q1_2 Hp2q2 H2.
      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; eauto with hopi howe.
      eapply lts_parr'; eauto.
      apply sc_trans with (bind f P // appr (abs_def P2) C'1);
                                                      auto with sc hopi howe.
      inverts H3. assert (struct_congr
        (bind f P // appr (abs_def P2) C'1)
        (appr (abs_def P2) (conc_parr (bind f P) C'1))).
        destruct C'1; simpl. apply sc_trans with
          (genNu n (shiftN n (bind f P) // (subst ((shiftN n) P2) p // p0))); eauto with sc.
      eauto with sc hopi howe.
      apply sc_trans with (bind f Q // appr (abs_def Q2) C'2); auto with sc hopi howe.
      assert (struct_congr (bind f Q // appr (abs_def Q2) C'2)
                   (appr (abs_def Q2) (conc_parr (bind f Q) C'2))).
        destruct C'2; simpl. apply sc_trans with
          (genNu n (shiftN n (bind f Q) // (subst ((shiftN n) Q2) p // p0))); eauto with sc.
      eauto with sc hopi howe.
  - inverts HltsP1. simpl.
     (conc_def 0 (bind f Q) (bind f Q'))
        (appr (abs_def P2) (conc_def 0 (bind f P) (bind f P')))
        (appr (abs_def Q2) (conc_def 0 (bind f Q) (bind f Q')));
    simpl; intuition auto with hopi sc.
    apply howe_par; auto with howe. apply howe_subst; auto with howe.
    apply howe_mapN; auto.
  - simpl in ×. inverts HltsP1. destruct l0; inverts H0. destruct A as [ | | C1' ]; inverts H1.
    forwards*: @howe_mapN Hp2q2 S.
    forwards*: IHHp1q1 H H3. destruct H0 as [C2' [P'2 [Q'2 [HltsC2' [Hp'2 [HQ'2 Hrel]]]]]].
     (conc_new C2') (nu P'2) (nu Q'2). splits. eapply lts_new'; eauto.
    remember (abs_def P2) as F1. asserts_rewrite (abs_def (mapN S P2) = fmapN S F1) in Hp'2. subst; reflexivity.
    eauto with sc.
    remember (abs_def Q2) as F2. asserts_rewrite (abs_def (mapN S Q2) = fmapN S F2) in HQ'2. subst; reflexivity.
    eauto with sc.
    auto with howe.
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 ×. destruct F1 as [P'1].
    forwards: @pseudo_out_first P2 Q2 P'1 P'1 C1; eauto with howe hopi.
    destruct H as [C2 [ P'2 [Q'2 [HltsC2 [Hp'2 [Hq'2 Hhowe]]]]]].
     (abs_def P'1) C2 P'2 Q'2; intuition.
  - inverts HltsP1.
    + forwards: lts_inp_abs H2. destruct H as [F'1]. subst. simpl in H3.
      forwards*: IHHp1q1_1 Hp2q2 H2 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; eauto with hopi howe.
      eapply lts_parl'; eauto.
      apply sc_trans with (appr F'1 C1 // bind f P'); auto with sc hopi howe.
      inverts H3. assert (struct_congr
        (appr F'1 C1 // bind f P') (appr (abs_parl F'1 (bind f P')) C1)).
        destruct F'1, C1; simpl. rewrite <- mapV_mapN. rewrite subst_shift.
        apply sc_trans with
          (genNu n (subst ((shiftN n) p) p0 // p1 // (shiftN n)(bind f P'))); eauto with sc.
      eauto with sc hopi howe.
      apply sc_trans with (appr F'2 C'2 // bind f Q'); auto with sc hopi howe.
      assert (struct_congr
        (appr F'2 C'2 // bind f Q') (appr (abs_parl F'2 (bind f Q')) C'2)).
        destruct F'2, C'2; simpl. rewrite <- mapV_mapN. rewrite subst_shift.
        apply sc_trans with
          (genNu n (subst ((shiftN n) p) p0 // p1 // (shiftN n)(bind f Q'))); eauto with sc.
      eauto with sc hopi howe.
    + forwards: lts_inp_abs H2. destruct H as [F'1]. subst. simpl in H3.
      forwards*: IHHp1q1_2 Hp2q2 H2 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; eauto with hopi howe.
      eapply lts_parr'; eauto.
      apply sc_trans with (bind f P // appr F'1 C1); auto with sc hopi howe.
      inverts H3. assert (struct_congr
        (bind f P // appr F'1 C1) (appr (abs_parr (bind f P) F'1) C1)).
        destruct F'1, C1; simpl. rewrite <- mapV_mapN. rewrite subst_shift.
      apply sc_trans with
          (genNu n (shiftN n (bind f P) // (subst ((shiftN n) p) p0 // p1))); eauto with sc.
      eauto with sc hopi howe.
      apply sc_trans with (bind f Q // appr F'2 C'2); auto with sc hopi howe.
      assert (struct_congr (bind f Q // appr F'2 C'2)
                            (appr (abs_parr (bind f Q) F'2) C'2)).
        destruct F'2, C'2; simpl. rewrite <- mapV_mapN. rewrite subst_shift.
      apply sc_trans with
          (genNu n (shiftN n (bind f Q) // (subst ((shiftN n) p) p0 // p1))); eauto with sc.
      eauto with sc hopi howe.
  - 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]]]]]].
     (abs_def (bind (liftV f) Q)) C'2 P'2 Q'2; intuition.
  - simpl in ×. inverts HltsP1. destruct A as [ | F1' | ]; inverts H1. destruct l0; inverts H0.
    simpl in H2. destruct_notin. forwards*: mapN_lts S HltsP2. simpl in H. rewrite bind_mapN in H.
    asserts_rewrite (S (n-1) = n) in H. omega. forwards*: @howe_mapN Hp2q2 S.
    forwards*: IHHp1q1 H0 H. destruct H1 as [F'2 [ C'2 [P'2 [Q'2 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]].
    rewrite <- bind_mapN in HltsC'2. apply mapN_lts_rev in HltsC'2; try (intros_all; omega).
    destruct HltsC'2 as [A' [l' [Hc'2 [HltsQ2 Hl']]]]. destruct A'; inverts Hc'2. destruct l'; inverts Hl'.
    asserts_rewrite (S n0 -1 = n0). omega.
     (abs_new F'2) c (nu P'2)(nu Q'2). splits; auto with hopi howe.
    eapply lts_new'; eauto. simpl; fsetdec. eauto with sc.
    eauto with sc.
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
    lts (bind f P1) (inp a) (ag_abs F1) lts (bind g P2) (out a) (ag_conc C1)
    F2 C2 P'2 Q'2 n3, lts (bind f Q1) (inp a) (ag_abs F2)
                               lts (bind g Q2) (out a) (ag_conc 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 lt lt)).
    rewrite <- LibNat.lt_peano.
    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),
              lts (bind g P2) (out a) C1
                  (C2:conc) P'2 Q'2 x3,
                     lts (bind g Q2) (out a) C2
                    sc0 P'2 (appr (abs_def P1) C1)
                    sc0 Q'2 (appr (abs_def 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 (abs_def Q1) C'0)(S x3); intuition.
        apply howe_comp' with x2; auto with hopi howe.
        apply oe_trans with (appr (abs_def Q1) x0); auto.
        apply× oe_sc0. apply× oe_proc0.
    - simpl in ×.
      assert ( n3, howe' Rel (appr (abs_def P1) C1) (appr (abs_def Q1) C1) n3).
        destruct C1 as [n P Q]; simpl. apply howe_implies_howe'.
        apply howe_genNu. apply howe_par; auto with howe. apply howe_subst; auto with howe.
        apply howe_mapN; auto with howe. eapply howe'_implies_howe; eauto.
      destruct H1. C1 (appr (abs_def P1) C1)(appr (abs_def Q1) C1) x0;
      intuition auto with sc.
  - inverts H2.
    + forwards: lts_out_conc H7. destruct H1 as [C'1].
      rewrite_all H1 in *; clear H1. simpl in H8.
      forwards*: IH f H3 H7; 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 (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. apply× @howe_par. apply× @howe_bind.
        intros; auto with howe hopi.
      destruct H1. (conc_parl C'2 (bind g Q')) (P'2// bind g P') (Q'2//bind g Q') x.
      splits; eauto with hopi howe.
      eapply lts_parl'; eauto.
      apply sc_trans with (appr (abs_def P1) C'1 // bind g P');
                                                        auto with sc hopi howe.
      inverts H8. assert (struct_congr
        (appr (abs_def P1) C'1 // bind g P')
        (appr (abs_def P1) (conc_parl C'1 (bind g P')))).
        destruct C'1; simpl. eauto with sc.
      eauto with sc hopi howe.
      apply sc_trans with (appr (abs_def Q1) C'2 // bind g Q');
                                                        auto with sc hopi howe.
      assert (struct_congr
        (appr (abs_def Q1) C'2 // bind g Q')
        (appr (abs_def Q1) (conc_parl C'2 (bind g Q')))).
        destruct C'2; simpl. eauto with sc.
      eauto with sc hopi howe.
    + forwards: lts_out_conc H7. destruct H1 as [C'1].
      rewrite_all H1 in *; clear H1. simpl in H8.
      forwards*: IH f H1_0 H7; 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. apply× @howe_par. apply× @howe_bind.
        intros; auto with howe hopi.
      destruct H1. (conc_parr (bind g Q) C'2) (bind g P // P'2) (bind g Q // Q'2) x.
      splits; eauto with hopi howe. eapply lts_parr'; eauto.
      apply sc_trans with (bind g P // appr (abs_def P1) C'1); auto with sc hopi howe.
      assert (struct_congr (bind g P // appr (abs_def P1) C'1)
                           (appr (abs_def P1) (conc_parr (bind g P) C'1))).
        destruct C'1; simpl. apply sc_trans with
          (genNu n (shiftN n (bind g P) // (subst ((shiftN n) P1) p // p0))); eauto with sc.
      inverts H8. eauto with sc hopi howe.
      apply sc_trans with (bind g Q // appr (abs_def Q1) C'2); auto with sc hopi howe.
      assert (struct_congr (bind g Q // appr (abs_def Q1) C'2)
                   (appr (abs_def Q1) (conc_parr (bind g Q) C'2))).
        destruct C'2; simpl. apply sc_trans with
          (genNu n (shiftN n (bind g Q) // (subst ((shiftN n) Q1) p // p0))); eauto with sc.
      eauto with sc hopi howe.
  - inverts H2. simpl.
    assert ( n, howe' Rel (appr (abs_def P1) (conc_def 0 (bind g P) (bind g P')))
        (appr (abs_def Q1) (conc_def 0 (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.
      apply howe_par; auto with howe. apply howe_subst; auto with howe.
       apply howe_mapN; auto with howe.
    destruct H1. (conc_def 0 (bind g Q) (bind g Q'))
        (appr (abs_def P1) (conc_def 0 (bind g P) (bind g P')))
        (appr (abs_def Q1) (conc_def 0 (bind g Q) (bind g Q'))) x;
    intuition auto with hopi sc.
  - simpl in ×. inverts H2. destruct l0; inverts H6. destruct A as [ | | C1' ]; inverts H7.
    forwards*: @howe'_mapN H3 S. simpl in H8. destruct_notin.
    simpl in H2. asserts_rewrite (S (n-1) = n) in H2. destruct n; omega.
    forwards*: IH f H1 H2.
      apply lexico2_1. omega.
      subst. rewrite bind_return'. apply lts_inp.
    destruct H5 as [F2 [C2' [P'2 [Q'2 [n3 [HltsF2 [HltsC2' [Hp'2 [HQ'2 Hrel]]]]]]]]].
     (conc_new C2') (nu P'2) (nu Q'2)(S n3). splits. eapply lts_new'; eauto. simpl; fsetdec.
    remember (abs_def P1) as F1. asserts_rewrite (abs_def (mapN S P1) = fmapN S F1) in Hp'2. subst; reflexivity.
    eauto with sc.
    remember (abs_def Q1) as F'2. inverts HltsF2. rewrite H4 in ×.
    asserts_rewrite (abs_def (mapN S Q1) = fmapN S F'2) in HQ'2. subst; reflexivity.
    eauto with sc. auto with howe.
    }
  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 ×. destruct F1 as [P1'].
    assert ( n1, howe' Rel P1' P1' 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: lts_inp_abs H7. destruct H2 as [F'1]. subst. simpl in H8.
      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; eauto with hopi howe.
      eapply lts_parl'; eauto.
      apply sc_trans with (appr F'1 C1 // bind f P'); auto with sc hopi howe.
      inverts H8. assert (struct_congr
        (appr F'1 C1 // bind f P') (appr (abs_parl F'1 (bind f P')) C1)).
        destruct F'1, C1; simpl. rewrite <- mapV_mapN. rewrite subst_shift.
        apply sc_trans with
          (genNu n (subst ((shiftN n) p) p0 // p1 // (shiftN n)(bind f P'))); eauto with sc.
      eauto with sc hopi howe.
      apply sc_trans with (appr F'2 C'2 // bind f Q'); auto with sc hopi howe.
      assert (struct_congr
        (appr F'2 C'2 // bind f Q') (appr (abs_parl F'2 (bind f Q')) C'2)).
        destruct F'2, C'2; simpl. rewrite <- mapV_mapN. rewrite subst_shift.
        apply sc_trans with
          (genNu n (subst ((shiftN n) p) p0 // p1 // (shiftN n)(bind f Q'))); eauto with sc.
      eauto with sc hopi howe.
    - forwards: lts_inp_abs H7. destruct H2 as [F'1]. subst. simpl in H8.
      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; eauto with hopi howe.
      eapply lts_parr'; eauto.
      apply sc_trans with (bind f P // appr F'1 C1); auto with sc hopi howe.
      inverts H8. assert (struct_congr
        (bind f P // appr F'1 C1) (appr (abs_parr (bind f P) F'1) C1)).
        destruct F'1, C1; simpl. rewrite <- mapV_mapN. rewrite subst_shift.
      apply sc_trans with
          (genNu n (shiftN n (bind f P) // (subst ((shiftN n) p) p0 // p1))); eauto with sc.
      eauto with sc hopi howe.
      apply sc_trans with (bind f Q // appr F'2 C'2); auto with sc hopi howe.
      assert (struct_congr (bind f Q // appr F'2 C'2)
                            (appr (abs_parr (bind f Q) F'2) C'2)).
        destruct F'2, C'2; simpl. rewrite <- mapV_mapN. rewrite subst_shift.
      apply sc_trans with
          (genNu n (shiftN n (bind f Q) // (subst ((shiftN n) p) p0 // p1))); eauto with sc.
      eauto with sc hopi howe.
  + 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. destruct A as [ | F1' | ]; inverts H7. destruct l0; inverts H6.
    simpl in H8. destruct_notin. forwards*: mapN_lts S H4. simpl in H3. rewrite bind_mapN in H3.
    asserts_rewrite (S (n-1) = n) in H3. omega. forwards*: @howe'_mapN H1 S.
    forwards*: IH H5 H9 H3. apply lexico2_2; omega.
    destruct H6 as [F'2 [ C'2 [P'2 [Q'2 [n3 [HltsF'2 [ HltsC'2 [Hp'2 [Hq'2 Hhowe]]]]]]]]].
    rewrite <- bind_mapN in HltsC'2. apply mapN_lts_rev in HltsC'2; try (intros_all; omega).
    destruct HltsC'2 as [A' [l' [Hc'2 [HltsQ2 Hl']]]]. destruct A'; inverts Hc'2. destruct l'; inverts Hl'.
    asserts_rewrite (S n0 -1 = n0). omega.
     (abs_new F'2) c (nu P'2)(nu Q'2)(S n3). splits; auto with hopi howe.
    eapply lts_new'; eauto. simpl; fsetdec. eauto with sc.
    eauto with sc.
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
  lts (bind f P) tau (ag_proc P')
   Q' P'' Q'', lts (bind f Q) tau (ag_proc 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: lts_tau_proc H2. destruct H as [P'1]. subst. simpl in H3.
      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')).
      inverts H3. splits; auto with sc howe hopi.
      eapply lts_parl'; eauto.
    + forwards: lts_tau_proc H2. destruct H as [P'1]. subst. simpl in H3.
      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).
      inverts H3. splits; auto with sc howe hopi.
      eapply lts_parr'; eauto.
    + forwards: lpseudo_sim H3 H2; 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.
      eapply lts_taul'; eauto.
      apply sc_trans with (appr F C); auto with sc.
      apply sc_trans with (appr F2 C2); auto with sc.
    + forwards: lpseudo_sim H2 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. destruct A as [ P'1 | [] | [] ]; inverts H1. destruct l0; inverts H0.
    forwards*: IHHp1q1 H3. destruct H as [Q'1 [P''1 [Q''1 [HltsQ' [Hp'1p''1 [Hq'1q''1 Hhowe]]]]]].
     (nu Q'1) (nu P''1) (nu Q''1); intuition eauto with hopi sc howe. simpl. eapply lts_new'; eauto.
Qed.

Lemma conc_to_proc : (C:conc) a, conc_wf C
     P, lts P (out a) C
        ( (C':conc), lts P (out a) C' C = C').
Proof.
  intros. destruct C as [n P1 P2]. gen a P1 P2. induction n; intros.
  + (a!(P1) P2); intuition; auto with hopi. inverts H0. auto.
  + forwards*:IHn (S a) P1 P2. destruct H0 as [P' [Hlts Hc']].
    assert (n \in fn P1). apply H. omega.
     (nu P'). splits.
    - eapply lts_new'; eauto. simpl; fsetdec.
      simpl. case_if; auto. simpl; auto with arith.
    - intros. inverts H1. destruct A as [ | | C'']; inverts H4. destruct l0; inverts H3.
      simpl in H5. destruct_notin. asserts_rewrite (S(n0-1) = n0) in ×. omega.
      forwards*: Hc' H6. rewrite <- H1; simpl. case_if; auto.
Qed.

Lemma abs_to_proc : (F:abs) a,
     P, lts P (inp a) F
        ( (F':abs), lts P (inp a) F' F = F').
Proof.
  intros. destruct F as [P]. (a? P); 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).
    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.