Library Semantics

Require Export HOASSyntax.

agents


Notation abs := proc1 (only parsing).

Inductive conc : Set :=
| conc_def : proc0 proc0 conc
| conc_nu : (name conc) conc
.

Inductive conc_notin : name conc Prop :=
| nc_def : a P Q, notin a P notin a Q
            conc_notin a (conc_def P Q)
| nc_nu : a C, ( b, ab conc_notin a (C b))
            conc_notin a (conc_nu C).

Hint Constructors conc_notin:hopi.

Definition conc_notin_ho a C :=
       b, ab conc_notin a (C b).

Ltac simpl_conc_notin :=
  repeat match goal with
  | [ H : conc_notin _ ?t |- _ ] ⇒ head_constructor t; inverts H
  | [ H : conc_notin _ _ _ |- _ ] ⇒ destruct H
  end.
Ltac simpl_notin ::=
  repeat (simpl_notin_list; simpl_notin_proc; simpl_conc_notin; simpl in *; auto).

Axiom conc_ext : a C C', conc_notin_ho a C
  conc_notin_ho a C' C a = C' a C = C'.

Ltac auto_conc_ext :=
  match goal with
  | [ H : ?P ?X = ?Q ?X |- _ ] ⇒
    (forwards*: @conc_ext X P Q; intros_all; auto with hopi);
    subst; simpl_notin; clear H; auto with hopi
  end.

Axiom conc_beta_exp : a C,
   C', conc_notin_ho a C' C = C' a.
Axiom conc_ho_beta_exp : a (C:name conc),
   C', conc_notin_ho a (fun xconc_nu (C' x)) C = C' a.
Axiom conc_ho_ho_beta_exp : a (C:name name conc),
   C', conc_notin_ho a
    (fun yconc_nu (fun xconc_nu (C' x y))) C = C' a.

Ltac conc_exp x C := let Cr := fresh C in
   destruct (conc_beta_exp x C) as [Cr []]; subst.
Ltac ho_conc_exp x C := let Cr := fresh C in
   destruct (conc_ho_beta_exp x C) as [Cr []]; subst.

Ltac all_conc_exp x := repeat match goal with
  | [ C : conc |- _ ] ⇒ conc_exp x C
  | [ P : proc _ |- _ ] ⇒ exp x P
  end.

Ltac conc_change_ext :=
  match goal with
  | [ H : ?C = ?C' ?x |- _ ] ⇒
    let C'' := (eval pattern x in C) in change (C'' = C' x) in H; auto_conc_ext
  end.
Ltac conc_exp_ext x := all_conc_exp x; repeat conc_change_ext.

Axiom conc_unsat : C, a, conc_notin a C.

Ltac fresh_conc C := destruct (conc_unsat C); simpl_notin.

Inductive list_in_proc {V:Set}: list name proc V Prop :=
| list_in_proc_nil : P, list_in_proc nil P
| list_in_proc_rec : a L P, list_in_proc L P
                  isin a P list_in_proc (a::L) P.

Inductive cwf_aux : list name conc Prop :=
| cwf_def : L P Q, list_in_proc L P
                cwf_aux L (conc_def P Q)
| cwf_nu : L C L', ( a, ¬In a L' conc_notin_ho a C
               cwf_aux (a::L) (C a) ) cwf_aux L (conc_nu C).

Definition conc_wf C := cwf_aux nil C.


LTS


Fixpoint conc_parl C P : conc :=
  match C with
  | conc_def P' Qconc_def P' (Q // P)
  | conc_nu C'conc_nu (fun x ⇒ (conc_parl (C' x) P))
  end.

Fixpoint conc_parr P C : conc :=
  match C with
  | conc_def P' Qconc_def P' (P // Q)
  | conc_nu C'conc_nu (fun x ⇒ (conc_parr P (C' x)))
  end.

Definition abs_parl (F:abs) P : abs := (F // (shiftV P)).

Definition abs_parr P (F:abs) : abs := ((shiftV P) // F).

Inductive conc_new : (name conc) conc Prop :=
| cnew_extr : P Q, ( a, notin_ho a P isin a (P a))
     conc_new (fun xconc_def (P x)(Q x)) (conc_nu (fun xconc_def (P x) (Q x)))
| cnew_no_extr : P Q, ( a, notin_ho a P notin a (P a))
      a, conc_new (fun xconc_def (P x)(Q x)) (conc_def (P a) (nu Q))
| cnew_nu : (C:namenameconc) C' L,
    ( a, ¬In a L conc_notin_ho a (fun xconc_nu (C x))
   conc_new (fun xC x a)(C' a))
    conc_new (fun xconc_nu (C x)) (conc_nu C')
.

Hint Constructors conc_new:hopi.


Lemma equal_f : {A B : Type} {f g : A B},
  f = g x, f x = g x.
Proof.
  intros; rewrite H; auto.
Qed.

Ltac fun_eq_solve := let x:= fresh "x" in
  extens; intro x; solve [ repeat match goal with
  | [ H : ?f = ?g |- _ ] ⇒ match type of f with
    | name _apply equal_f with x in H; inverts× H
     end
  end ].

Ltac fun_eq_absurd := match goal with
  [ x : name |- _ ] ⇒ solve [ repeat match goal with
  | [ H : ?f = ?g |- _ ] ⇒ match type of f with
    | name _apply equal_f with x in H;
      inverts× H
     end
  end ]
end.

Fixpoint appr F C : proc0 :=
  match C with
  | conc_def P Qsubst F P // Q
  | conc_nu C'nu (fun xappr F (C' x))
  end.

Fixpoint appl C F : proc0 :=
  match C with
  | conc_def P QQ // subst F P
  | conc_nu C'nu (fun xappl (C' x) F)
  end.

Lemma notin_appr : F C a, notin a F conc_notin a C
   notin a (appr F C).
Proof.
  intros; induction C; simpl_notin; auto with hopi.
  constructor×. apply× @notin_bind.
  intros [|]; simpl; auto with hopi.
Qed.

Lemma notin_appl : F C a, notin a F conc_notin a C
   notin a (appl C F).
Proof.
  intros; induction C; simpl_notin; auto with hopi.
  constructor×. apply× @notin_bind.
  intros [|]; simpl; auto with hopi.
Qed.

Inductive ltsabs: proc0 name abs Prop :=
| ltsa_inp : a P, ltsabs (a ? P) a P
| ltsa_parl : P Q a F, ltsabs P a F
              ltsabs (P // Q) a (abs_parl F Q)
| ltsa_parr : P Q a F, ltsabs P a F
              ltsabs (Q // P) a (abs_parr Q F)
| ltsa_new : P a F L, ( b, ¬In b L ab notin_ho b P
    notin_ho b F ltsabs (P b) a (F b)) ltsabs (nu P) a (nu F)
.

Inductive ltsconc: proc0 name conc Prop :=
| ltsc_out : a P Q, ltsconc (a !(P) Q) a (conc_def P Q)
| ltsc_parl : P Q a C, ltsconc P a C ltsconc (P // Q) a (conc_parl C Q)
| ltsc_parr : P Q a C, ltsconc P a C ltsconc (Q // P) a (conc_parr Q C)
| ltsc_new : P a C L, ( b, ¬In b L ab notin_ho b P
    conc_notin_ho b C ltsconc (P b) a (C b))
     C', conc_new C C' ltsconc (nu P) a C'
.

Inductive ltsproc: proc0 proc0 Prop :=
| ltsp_parl : P Q P', ltsproc P P' ltsproc (P // Q) (P' // Q)
| ltsp_parr : P Q P', ltsproc P P' ltsproc (Q // P) (Q // P')
| ltsp_new : P P' L,
    ( a, ¬In a L notin_ho a P notin_ho a P' ltsproc (P a) (P' a))
    ltsproc (nu P) (nu P')
| ltsp_taul : P Q a F C, ltsconc P a C
    ltsabs Q a F ltsproc (P // Q)(appl C F)
| ltsp_taur : P Q a F C, ltsabs Q a F
    ltsconc P a C ltsproc (Q // P) (appr F C)
.

Hint Constructors ltsabs ltsconc ltsproc:hopi.


Basic LTS properties


Lemma lts_taul' : P P' Q a F C,
    ltsconc P a C ltsabs Q a F
    (appl C F) = P' ltsproc (P // Q) P'.
Proof.
  intros. subst. eapply ltsp_taul; eassumption.
Qed.

Lemma lts_taur' : P P' Q a F C,
    ltsconc P a C ltsabs Q a F
    (appr F C) = P' ltsproc (Q // P) P'.
Proof.
  intros; subst; eapply ltsp_taur; eassumption.
Qed.

Hint Resolve lts_taul' lts_taur':hopi.

Lemma nc_parl : C P a, conc_notin a (conc_parl C P)
  notin a P conc_notin a C.
Proof.
  intros. split.
  - induction C; simpl_notin.
    fresh_list (a::nil). forwards*: H3 x.
  - induction C; simpl_notin; auto with hopi.
Qed.

Lemma nc_parl_rev : C P a, notin a P
   conc_notin a C conc_notin a (conc_parl C P).
Proof.
  intros; induction C; simpl_notin; auto with hopi.
Qed.

Lemma nc_parr : C P a, conc_notin a (conc_parr P C)
  notin a P conc_notin a C.
Proof.
  intros. split.
  - induction C; simpl_notin.
    fresh_list (a::nil). forwards*: H3 x.
  - induction C; simpl_notin; auto with hopi.
Qed.

Lemma nc_parr_rev : C P a, notin a P
   conc_notin a C conc_notin a (conc_parr P C).
Proof.
  intros; induction C; simpl_notin; auto with hopi.
Qed.

Ltac solve_notin_rename := match goal with
  | |- notin ?a (?P ?b ?c) ⇒ let P':= (eval pattern b in (P b c))
        in change (notin a P'); eapply notin_rename; eauto
  end.

Ltac solve_notin_aux a x := repeat match goal with
    | H : z, az notin a _ |- _
        forwards*: H x; clear H; simpl_notin; try solve [solve_notin_rename]
    | H : z, za notin a _ |- _
        forwards*: H x; clear H; simpl_notin; try solve [solve_notin_rename]
    | H : z, az conc_notin a _ |- _
        forwards*: H x; clear H; simpl_notin; try solve [solve_notin_rename]
    | H : z, za conc_notin a _ |- _
        forwards*: H x; clear H; simpl_notin; try solve [solve_notin_rename]
    | H : notin a (mapV _ _) |- _apply @notin_mapV_rev in H;
                                     simpl_notin
    | H : notin a (bind _ _) |- _apply @notin_bind_rev in H;
                                     destruct H; simpl_notin
     end.

Ltac solve_notin' := repeat match goal with
  | |- notin_ho _ _intros_all
  | |- conc_notin_ho _ _intros_all
  | |- notin _ (mapV _ _) ⇒ apply× @notin_mapV
  | |- notin _ (appl _ _) ⇒ apply× notin_appl
  | |- notin _ (appr _ _) ⇒ apply× notin_appr
  | |- notin _ (abs_parl _ _) ⇒ unfold abs_parl
  | |- notin _ (abs_parr _ _) ⇒ unfold abs_parr
  | |- conc_notin _ (conc_parl _ _) ⇒ apply× nc_parl_rev
  | |- conc_notin _ (conc_parr _ _) ⇒ apply× nc_parr_rev
  | |- notin _ ?Phead_constructor P; constructor
  | |- conc_notin _ ?Chead_constructor C; constructor
  end; unfold notin_ho in *; unfold conc_notin_ho in ×.

Lemma neq_symmetry : (a b:name), ab ba.
Proof.
  intros; auto.
Qed.

Ltac symmetry_hyp a := repeat match goal with
  [ H : ?x a |- _ ] ⇒ apply neq_symmetry in H
  end.

Ltac solve_notin := solve_notin';
  match goal with | |- notin ?a ?Psymmetry_hyp a;
    repeat match goal with
    | H : a ?x |- _try solve [solve_notin_aux a x];
        apply neq_symmetry in H
    end
    | |- conc_notin ?a ?Csymmetry_hyp a;
    repeat match goal with
    | H : a ?x |- _try solve [solve_notin_aux a x];
        apply neq_symmetry in H
    end
  end.

Hint Extern 1 (notin_ho ?a ?P) ⇒ solve_notin:hopi.
Hint Extern 1 (notin ?a ?P) ⇒ solve_notin:hopi.
Hint Extern 1 (conc_notin _ _) ⇒ solve_notin:hopi.
Hint Extern 1 (conc_notin_ho _ _) ⇒ solve_notin:hopi.


Lemma unsat_lc: (L:list name) C, a,
                        ¬In a L conc_notin a C.
Proof.
  intros. fresh_conc (conc_parl C (listproc L PO)).
   x. forwards*: nc_parl. forwards*: @listproc_in.
Qed.

Ltac fresh_lc L C := destruct (unsat_lc L C); simpl_notin.

Inductive sizec : conc nat Prop :=
| szc_def : P Q, sizec (conc_def P Q) 0
| szc_nu : C n, ( a, sizec (C a) n)
           sizec (conc_nu C) (1+n).

Hint Constructors sizec:hopi.

Lemma sizec_rename : n C a, conc_notin_ho a C
  sizec (C a) n b, sizec (C b) n.
Proof.
  induction n; intros; inverts H0.
  - conc_exp_ext a.
  - ho_conc_exp a C0. conc_change_ext.
    constructor. intros.
    fresh_lc (a0::a::nil) (conc_nu (C1 b)).
    apply IHn with x; auto.
    change (sizec ((fun bC1 b x) b) n).
    apply IHn with a; auto.
    intros_all. forwards*: H0 b0. simpl_notin.
Qed.

Lemma exists_szc : C, n, sizec C n.
Proof.
  induction C.
   0; auto with hopi.
  fresh_conc (conc_nu c).
  destruct (H x) as [n].
   (1+n). constructor. intros.
  eapply sizec_rename; eauto.
Qed.

Lemma conc_notin_rename' : n (C:conc), (sizec C n)
       C' c, (conc_notin_ho c C') C = (C' c)
       a b, (conc_notin a (C' b)) (conc_notin_ho a C').
Proof.
  intro n.
  induction n; introv Hs Hc Hc' Hnotin;
  inverts Hs; intros_all.
  - conc_exp_ext c.
    constructor; apply notin_rename with b; auto.
  - ho_conc_exp c C0. conc_change_ext. rename C1 into C''.
    constructor; intros z Haz.
    fresh_lc (z::a::c::nil) (conc_nu (C'' b0)). rename x into c'.
    assert ( x, xc sizec (C'' b0 x) n).
    { intros; change (sizec ((fun cC'' c x) b0) n).
      eapply sizec_rename; eauto. intros_all.
      forwards*: Hc b1. simpl_notin. }
    assert (conc_notin a (C'' b0 c')).
    { change (conc_notin a ((fun b0C'' b0 c') b0)).
      eapply IHn; eauto. intros_all.
      forwards*: Hc b1. simpl_notin. }
    clear H1. eapply IHn; eauto.
Qed.

Lemma conc_notin_rename : (C:nameconc) a b,
   conc_notin a (C b) c, ac conc_notin a (C c).
Proof.
  intros. fresh_conc (conc_nu C).
  destruct (exists_szc (conc_nu C)) as [n]. inverts H1.
  eapply conc_notin_rename'; eauto.
Qed.

Ltac solve_notin_rename ::= match goal with
  | |- notin ?a (?P ?b ?c) ⇒ let P':= (eval pattern b in (P b c))
        in change (notin a P'); eapply notin_rename; eauto
  | |- conc_notin ?a (?C ?b ?c) ⇒ let C':= (eval pattern b in (C b c))
        in change (conc_notin a C'); eapply conc_notin_rename; eauto
  end.

Lemma unsat_proc_of_conc : C, (P:proc0),
   a, notin a P conc_notin a C.
Proof.
  induction C.
  - fresh_proc (p//p0). (x!(p) p0).
    intros_all. inverts H. apply× nc_def.
  - fresh_conc (conc_nu c).     forwards× [P]: H x. exp x P.
     (nu P0).
    intros. simpl_notin. constructor. intros b Hab.
    destruct (dec_name x a); subst; auto.
    apply conc_notin_rename with x; auto.
Qed.

Lemma list_of_conc : C, L,
   a, ¬In a L conc_notin a C.
Proof.
  intros. destruct (unsat_proc_of_conc C) as [P].
  destruct (list_of_proc P). eexists; eauto.
Qed.

Ltac fn P := let L := fresh "L" in
  match type of P with
  | proc _destruct (list_of_proc P) as [L]
  | concdestruct (list_of_conc P) as [L]
  end.

Lemma unsat_pc {V:Set}: (P:proc V) C, a,
                        notin a P conc_notin a C.
Proof.
  intros. fn P. fn C. fresh_list (L++L0).
  eexists; eauto.
Qed.

Lemma unsat_lpc {V:Set}: (L:list name) (P:proc V) C, a,
                        ¬In a L notin a P conc_notin a C.
Proof.
  intros. fn P. fn C. fresh_list (L++L0++L1).
  eexists; eauto.
Qed.

Ltac fresh_pc P C := destruct (unsat_pc P C); simpl_notin.
Ltac fresh_lpc L P C := destruct (unsat_lpc L P C); simpl_notin.

Lemma conc_unused_arg : (C:name conc) a,
  conc_notin a (C a) a b, C a = C b.
Proof.
  intros C a Hnotin.
  assert (conc_notin_ho a C).
  { intros z Hz. apply conc_notin_rename with a; auto. }
  induction (C a) eqn:HH; symmetry in HH; conc_change_ext.
Qed.

Lemma conc_notin_arg: (C:name conc) a,
  conc_notin a (C a) b, conc_notin_ho b C conc_notin b (C b).
Proof.
  intros. destruct (dec_name a b); subst; auto.
  rewrite (conc_unused_arg C a H b a). forwards*: H0 a.
Qed.

Lemma two_unused_args : C a, conc_notin_ho a (fun xC x a)
   conc_notin_ho a (fun xC a x) conc_notin a (C a a).
Proof.
  intros. fresh_lc (a::nil) (conc_nu (fun x ⇒ (conc_nu (fun yC x y)))).
  forwards*: H0 x.
  fresh_list (a::x::nil). rename x0 into b.
  change (conc_notin a ((fun aC a x) a)) in H2.
  forwards: (conc_unused_arg _ a H2) a b.
  auto_conc_ext.
  rewrite H7 in ×. apply× H.
Qed.


Lemma cnew_notin : C C', conc_new C C'
    a, conc_notin_ho a C conc_notin a C'.
Proof.
  introv H. induction H; intros.
  - constructor; intros.
    forwards*: H0 b.
  - constructor; intros.
    destruct (dec_name a a0); subst.
    apply H. intros_all. forwards*: H0 b. simpl_notin.
    apply notin_rename with a0; auto. apply H.
    intros_all. forwards*: H0 b. simpl_notin.
    constructor; intros. forwards*: H0 z. simpl_notin.
  - constructor; intros.
    fresh_lc (a::b::L) (conc_nu (fun xconc_nu (fun yC x y))).
    apply conc_notin_rename with x; auto.
    eapply H0; eauto; auto with hopi.
Qed.

Lemma cnew_notin_rev : C C', conc_new C C'
    a, conc_notin a C' conc_notin_ho a C.
Proof.
  introv H. induction H; intros.
  - inverts H0. constructor; intros;
    forwards*: H3 b; simpl_notin.
  - simpl_notin. constructor; intros;
    eapply notin_rename; eauto.
  - inverts H1. constructor; intros.
    fresh_lc (a::b::L) (conc_nu (fun xconc_nu (fun yC x y))).
    forwards*: H0 x. forwards*: H5 b0.
    apply conc_notin_rename with x; auto.
Qed.

Lemma cnew_rename : C C' b, conc_notin_ho b (fun xconc_nu (C x))
  conc_notin_ho b C' conc_new (C b)(C' b) c,
  conc_new (C c)(C' c).
Proof.
  introv HbC HbC' H. remember (C b) as Cb.
  remember (C' b) as C'b. gen C C' b. induction H; intros.
  - ho_exp b P. ho_exp b Q. conc_change_ext.
    assert (conc_nu (fun x : nameconc_def (P0 b x) (Q0 b x)) =
      conc_nu (C b)) by (rewrite× HeqCb).
    change ((fun b ⇒ (conc_nu (fun xconc_def (P0 b x)(Q0 b x)))) b = (fun bconc_nu (C b)) b) in H2.
    auto_conc_ext.
    apply equal_f with c in H3. inverts H3. constructor.
    intros.
    destruct (dec_name a b); subst.
    +
      fresh_lp (c::b::nil)((nu (P0 b)) // nu (P0 c)).
      destruct (isin_notin_dec b (P0 c b)); auto.
      forwards*: @notin_arg H5 x.
      change (notin x ((fun cP0 c x) c)) in H9.
      forwards*: @notin_rename (fun c : nameP0 c x) x c H9.
      forwards*: H x.
      exfalso. forwards*: @sep x x.
    +
      change (isin a ((fun cP0 c a) c)).
      apply isin_rename with b; auto. apply H. intros_all.
      forwards*: H2 b0. auto with hopi.
  - ho_exp b P. ho_exp b Q. conc_change_ext.
    { constructor×.
      destruct (dec_name a b); subst; auto with hopi.
      fresh_lp (c::b0::nil)((nu (P0 b0)) // nu (P0 b)).
      apply notin_arg with x; auto with hopi. }
    assert (conc_nu (fun x : nameconc_def (P0 b x) (Q0 b x)) =
       conc_nu (C b)) by (rewrite× HeqCb).
    change ((fun b ⇒ (conc_nu (fun xconc_def (P0 b x)(Q0 b x)))) b = (fun bconc_nu (C b)) b) in H2.
    auto_conc_ext.
    apply equal_f with c in H3. inverts H3. constructor.
    intros. fresh_lp (c::b::nil)((nu (P0 b)) // nu (P0 c)).
    apply notin_arg with x; auto with hopi. solve_notin_rename.
  - ho_conc_exp b C'. conc_change_ext.
    destruct (conc_ho_ho_beta_exp b C) as [C'' []]; subst.
    assert (conc_nu (fun x : nameconc_nu (C'' b x)) =
       conc_nu (C0 b)) by (rewrite× HeqCb).
    change ((fun b ⇒ (conc_nu (fun xconc_nu (C'' b x)))) b = (fun bconc_nu (C0 b)) b) in H3.
    auto_conc_ext. apply equal_f with c in H4. inverts H4.
    apply cnew_nu with (b::c::L). intros. simpl_notin.
    change ((conc_new ((fun cfun xC'' c x a) c)((fun c ⇒ (C'1 c a)) c))).
    eapply H0; eauto; auto with hopi.
    + intros_all. constructor; intros.
      forwards*: H4 b0. inverts H10. forwards*: H13 b1.
      change (conc_notin a ((fun bC'' b b0 b1) b)).
      apply conc_notin_rename with c; auto.
    + intros_all. constructor; intros. forwards*: H2 b1.
      simpl_notin. forwards*: H13 b0. simpl_notin.
Qed.

Lemma dec_cnew {V:Set} : (P:nameproc V),
  ( a, notin_ho a P isin a (P a))
  ( a, notin_ho a P notin a (P a)).
Proof.
  intros. fresh_proc (nu P). destruct (isin_notin_dec x (P x)).
  - left; intros. apply isin_arg with x; auto.
  - right; intros. apply notin_arg with x; auto.
Qed.

Lemma exists_cnew' : n C'', sizec C'' n
    a C, conc_notin_ho a C C'' = C a
    C', conc_new C C'.
Proof.
  induction n; intros; inverts H.
  - conc_exp_ext a. destruct (dec_cnew P0).
    + (conc_nu (fun xconc_def (P0 x)(Q0 x))); auto with hopi.
    + (conc_def (P0 a)(nu Q0)); auto with hopi.
  - ho_conc_exp a C0. conc_change_ext.
    fresh_lc (a::nil) (conc_nu (fun x⇒ (conc_nu (fun yC1 x y)))).
    forwards× [C']: IHn (fun yC1 y x).
      { intros_all. forwards*: H0 b. simpl_notin. }
    conc_exp x C'. (conc_nu C'0).
    apply cnew_nu with (a::x::nil). intros.
    change (conc_new ((fun a0fun x0C1 x0 a0) a0) (C'0 a0)).
    apply cnew_rename with x; auto.
    intros_all. constructor; intros. forwards*: H6 b0. simpl_notin.
Qed.

Lemma exists_cnew : C, C', conc_new C C'.
Proof.
  intros. fresh_conc (conc_nu C). destruct (exists_szc (C x)).
  eapply exists_cnew'; eauto.
Qed.

Lemma cnew_unique : C C1 C2, conc_new C C1 conc_new C C2
  C1 = C2.
Proof.
  intros. gen C2. induction H; intros.
  + inverts H0; try (assert (P = P0) by fun_eq_solve;
    assert (Q = Q0) by fun_eq_solve; subst); auto.
    fresh_proc (nu P0). forwards*: H2 x.
    forwards*: H x. exfalso; forwards*: @sep x x.
    fresh_list (@nil name). fun_eq_absurd.
  + inverts H0; try fun_eq_absurd; try (
    assert (P = P0) by fun_eq_solve;
    assert (Q = Q0) by fun_eq_solve; subst); auto.
    fresh_proc (nu P0). forwards*: H2 x.
    forwards*: H x. exfalso; forwards*: @sep x x.
    fequal. fresh_proc (nu P0). forwards*: H2 x.
    eapply unused_arg; eauto.
  + inverts H1; try fun_eq_absurd.
    fresh_list (@nil name). fun_eq_absurd.
    assert (C=C0). fun_eq_solve. subst. clear H2.
    fn (conc_nu C'0). fn(conc_nu C').
    fresh_lc (L++L0++L1++L2)(conc_nu (fun xconc_nu (C0 x))).
    forwards*: H1 x. simpl_notin. clears L1.
    forwards*: H3 x. forwards*: H2. forwards*: H0 H1.
    auto_conc_ext.
Qed.


Lemma cwf_parl : L C P, cwf_aux L C
                     cwf_aux L (conc_parl C P).
Proof.
  intros; gen L; induction C; intros.
  - simpl. inverts H. constructor. auto.
  - inverts H0. simpl. econstructor.
    intros. apply× H. apply H3. eassumption. intros_all.
    forwards*: H1 b. forwards*: nc_parl.
Qed.

Lemma cwf_parr : L C P, cwf_aux L C
                     cwf_aux L (conc_parr P C).
Proof.
  intros; gen L; induction C; intros.
  - simpl. inverts H. constructor. auto.
  - inverts H0. simpl. econstructor; intros.
    apply× H. apply H3. eassumption. intros_all.
    forwards*: H1 b. forwards*: nc_parr.
Qed.

Lemma list_in_proc_rename {V:Set}: L (P:nameproc V) a,
  ¬In a L list_in_proc L (P a) b, list_in_proc L (P b).
Proof.
  induction L; intros; constructor; inverts H0; simpl_notin.
  - eapply IHL; eauto.
  - eapply isin_rename; eauto.
Qed.

Lemma cwf_aux_rename: L C a, ¬ In a L
    conc_notin_ho a C cwf_aux L (C a)
     b, cwf_aux L (C b).
Proof.
  intros. remember (C a) as Ca. gen C a b.
  induction H1; intros.
  - conc_exp_ext a. constructor.
    apply list_in_proc_rename with a; auto.
  - ho_conc_exp a C. conc_change_ext.
    apply cwf_nu with (a::b::(L++L')).
    intros; simpl_notin.
    change (cwf_aux (a0 :: L) ((fun xC1 x a0) b)).
    eapply H0; eauto; auto with hopi.
    intuition.
Qed.

Lemma cwf_new : C L L',
  ( b, ¬In b L' conc_notin_ho b C cwf_aux L (C b))
   C', conc_new C C' cwf_aux L C'.
Proof.
  intros. gen L L'. induction H0; intros.
  - apply cwf_nu with L'; intros.
    constructor. constructor.
    forwards*: H0 a. simpl_notin. inverts× H3.
    apply H; intros_all. forwards*: H2 b.
    simpl_notin.
  - constructor.
    fresh_lc (a::(L'++L))(conc_nu (fun xconc_def (P x)(Q x))).
    forwards*: H0 x. inverts H2.
    eapply list_in_proc_rename; eauto.
  - fresh_lc (L0++L++L') (conc_nu (fun x : nameconc_nu (C x))).
    forwards*: H1 x. forwards*: H x. inverts H3.
    apply cwf_nu with (x::L++L0++L'++L'0). intros. simpl_notin.
    apply cnew_notin_rev with (fun x0 : nameC x0 x) (C' x) a in H6; auto.
    simpl_notin. eapply H0; eauto; auto with hopi.
    intros_all. constructor; intros.
    forwards*: H6 b. eapply conc_notin_rename; eauto.
    intros. forwards*: H10 a.
    intros_all. forwards*: H6 x. eapply conc_notin_rename; eauto.
    change (cwf_aux (a :: L0)((fun xC x a) b)).
    apply cwf_aux_rename with x; auto with hopi. simpl_notin.
    Unshelve. exact (@nil name).
Qed.

Lemma lts_conc_wf : P a C, ltsconc P a C conc_wf C.
Proof.
  intros.
  induction H; try solve [inverts HC]; unfold conc_wf.
  - constructor. constructor.
  - apply cwf_parl. auto.
  - apply cwf_parr. auto.
  - fn (nu P). apply cwf_new with C (a::L++L0); eauto; intros.
    simpl_notin. forwards*: H2. simpl_notin. apply× H0.
Qed.


Lemma cwf_include : L C, cwf_aux L C
   L', incl L' L cwf_aux L' C.
Proof.
  introv H; induction H; intros.
  + constructor. induction L'; auto. constructor.
    assert (In a L). apply H0. apply in_eq.
    assert (incl L' L). intros_all. apply H0.
    apply× @in_cons.
    constructor×. clears L'.
    induction L; inverts× H; inverts× H1.
  + apply cwf_nu with L'; intros.
    apply× H0. intros_all. default_simp.
Qed.

Lemma list_in_proc_change {V:Set}: L' L (P:nameproc V) a,
  notin_ho a P ¬ In a L ¬ In a L'
  list_in_proc (L' ++ a :: L)(P a) b, list_in_proc (L' ++ b :: L) (P b).
Proof.
  induction L'; intros.
  - rewrite app_nil_l in ×. inverts H2. constructor.
    + apply list_in_proc_rename with a; auto.
    + apply isin_arg with a; auto.
  - rewrite <- app_comm_cons in ×. inverts H2.
    simpl_notin. constructor.
    + eapply IHL'; eauto.
    + apply isin_rename with a0; auto.
Qed.

Lemma cwf_aux_change : C L L' a,
  conc_notin_ho a C ¬ In a L ¬ In a L'
  cwf_aux (L' ++ a :: L) (C a)
   b, cwf_aux (L' ++ b :: L)(C b).
Proof.
  intros. remember (C a) as Ca.
  remember (L'++a ::L) as La. gen b C L' L.
  induction H2; intros.
  + all_exp a. conc_change_ext. constructor.
    apply list_in_proc_change with a; auto.
  + ho_conc_exp a C. conc_change_ext.
    apply cwf_nu with (a::b::(L'0++L0++L')); intros. simpl_notin.
    rewrite app_comm_cons.
    change (cwf_aux ((a0 :: L'0) ++ b :: L0) ((fun bC1 b a0) b)).
    eapply H0; eauto; auto with hopi.
    simpl_notin.
Qed.


Inductive subst_name : name name name name Prop :=
| sn_eq : b c, subst_name b c b c
| sn_not_eq : b c a, ab subst_name b c a a.

Hint Constructors subst_name:hopi.

Lemma exists_sname : a b c, d,
 subst_name b c a d.
Proof.
  intros. destruct (dec_name a b); subst; eexists; eauto with hopi.
Qed.

Lemma ltsabs_rename : P a F,
     b, notin_ho b P notin_ho b F ltsabs (P b) a (F b)
     c d, subst_name b c a d ltsabs (P c) d (F c).
Proof.
  intros. remember (P b) as Pb.
  remember (F b) as Fb. gen c d b P F. induction H1; intros.
  - destruct (dec_name a b); subst; exp_ext b;
      inverts H2; try solve [exfalso; auto]; auto with hopi.
  - all_exp b. move HeqPb after H5. change_ext.
    change ((fun babs_parl (F1 b) (Q0 b)) b = F0 b) in HeqFb.
    auto_proc_ext. apply ltsa_parl. eapply IHltsabs; eauto.
  - all_exp b. move HeqPb after H5. change_ext.
    change ((fun babs_parr (Q0 b)(F1 b)) b = F0 b) in HeqFb.
    auto_proc_ext. apply ltsa_parr. eapply IHltsabs; eauto.
  - ho_exp b P. ho_exp b F. repeat change_ext.
    apply ltsa_new with (a::b::L). intros; simpl_notin.
    change (ltsabs ((fun cP1 c b0) c) d ((fun cF1 c b0) c)).
    eapply H0; eauto; auto with hopi.
Qed.

Lemma ltsconc_rename : P a C,
     b, notin_ho b P conc_notin_ho b C ltsconc (P b) a (C b)
     c d, subst_name b c a d ltsconc (P c) d (C c).
Proof.
  intros. remember (P b) as Pb. remember (C b) as Cb.
  gen P C b c d. induction H1; intros.
  - destruct (dec_name a b); conc_exp_ext b;
    change_ext; inverts H2; try solve [exfalso; auto]; auto with hopi.
  - all_conc_exp b. move HeqPb after H4. change_ext.
    change ((fun bconc_parl (C1 b) (Q0 b)) b = C0 b) in HeqCb.
    auto_conc_ext. apply ltsc_parl. eapply IHltsconc; eauto.
  - all_conc_exp b. move HeqPb after H4. change_ext.
    change ((fun bconc_parr (Q0 b)(C1 b)) b = C0 b) in HeqCb.
    auto_conc_ext. apply ltsc_parr. eapply IHltsconc; eauto.
  - ho_exp b P. change_ext. ho_conc_exp b C.
    apply ltsc_new with (C1 c) (b::c::d::a::L).
    2:{ eapply cnew_rename; eauto. }
    intros; simpl_notin.
    change (ltsconc ((fun cP1 c b0) c) d ((fun cC1 c b0) c)).
    eapply H0; eauto; auto with hopi.
Qed.

Lemma ltsproc_rename : P P',
     b, notin_ho b P notin_ho b P' ltsproc (P b) (P' b)
     c, ltsproc (P c) (P' c).
Proof.
  intros. remember (P b) as Pb. remember (P' b) as P'b.
  gen P P' b c. induction H1; intros.
  - exp_ext b. eapply ltsp_parl; eauto.
  - exp_ext b. eapply ltsp_parr; eauto.
  - ho_exp b P. ho_exp b P'. repeat change_ext.
    apply ltsp_new with (b::c::L). intros; simpl_notin.
    change (ltsproc ((fun cP1 c a) c)((fun cP'1 c a) c)).
    eapply H0; eauto; auto with hopi.
  - all_conc_exp b. move HeqPb after H5. change_ext.
    change ((fun bappl (C0 b)(F0 b)) b = P' b) in HeqP'b.
    auto_proc_ext. destruct (exists_sname a b c) as [d].
    eapply lts_taul'; eauto.
      forwards*: ltsconc_rename H.
      forwards*: ltsabs_rename H0.
  - all_conc_exp b. move HeqPb after H5. change_ext.
    change ((fun bappr (F0 b)(C0 b)) b = P' b) in HeqP'b.
    auto_proc_ext. destruct (exists_sname a b c) as [d].
    eapply lts_taur'; eauto.
      forwards*: ltsconc_rename H0.
      forwards*: ltsabs_rename H.
Qed.


Lemma ltsabs_notin : P a F, ltsabs P a F
   b, notin b P notin b F.
Proof.
  introv H. induction H; intros; simpl_notin.
  - unfold abs_parl. constructor×. apply× @notin_mapV.
  - unfold abs_parr. constructor×. apply× @notin_mapV.
  - constructor. intros.
    fresh_lp (z::a::b::L) ((nu F)//shiftV(nu P)).
    apply notin_rename with x; auto. apply× H0. auto with hopi.
Qed.

Lemma ltsabs_notin_ho : P a F,
     b, notin_ho b P notin_ho b F ltsabs (P b) a (F b)
     c, (notin_ho c P notin_ho c F).
Proof.
  intros_all. destruct (exists_sname a b b0) as [d].
  forwards*: ltsabs_rename H1. eapply ltsabs_notin; eauto.
Qed.

Lemma ltsabs_unused_arg : P,
  ( a, notin_ho a P notin a (P a))
   b F c, notin_ho b P notin_ho b F
  ltsabs (P b) c (F b) a, notin_ho a F notin a (F a).
Proof.
  intros. fresh_proc (nu P).
  apply notin_arg with x; auto.
  destruct (exists_sname c b x) as [d].
  forwards*: ltsabs_rename H2.
  eapply ltsabs_notin; eauto.
Qed.

Lemma ltsabs_notin_label : P a F, ltsabs P a F
   b, notin b P ab.
Proof.
  introv H. induction H; intros; simpl_notin.
  fresh_lp (a::b::L) ((nu F)//shiftV(nu P)).
  apply H0 with x; auto with hopi.
Qed.

Lemma ltsconc_notin : P a C, ltsconc P a C
   b, notin b P conc_notin b C.
Proof.
  introv H. induction H; intros; simpl_notin.
  - constructor×.
  - apply× nc_parl_rev.
  - apply× nc_parr_rev.
  - apply cnew_notin with C; auto.
    intros_all. fresh_lpc (b0::a::b::L) (nu P) (conc_nu C).
    apply conc_notin_rename with x; auto.
Qed.

Lemma ltsconc_notin_ho : P a C,
     b, notin_ho b P conc_notin_ho b C ltsconc (P b) a (C b)
     c, (notin_ho c P conc_notin_ho c C).
Proof.
  intros_all. destruct (exists_sname a b b0) as [d].
  forwards*: ltsconc_rename H1. eapply ltsconc_notin; eauto.
Qed.

Lemma ltsconc_unused_arg : P,
  ( a, notin_ho a P notin a (P a))
   b C c, notin_ho b P conc_notin_ho b C
  ltsconc (P b) c (C b) a, conc_notin_ho a C conc_notin a (C a).
Proof.
  intros. fresh_proc (nu P).
  apply conc_notin_arg with x; auto.
  destruct (exists_sname c b x) as [d].
  forwards*: ltsconc_rename H2.
  eapply ltsconc_notin; eauto.
Qed.

Lemma ltsconc_notin_label : P a C, ltsconc P a C
   b, notin b P ab.
Proof.
  introv H. induction H; intros; simpl_notin.
  fresh_lpc (a::b::L) (nu P) (conc_nu C).
  apply H0 with x; auto.
Qed.

Lemma ltsproc_notin : P P', ltsproc P P'
   b, notin b P notin b P'.
Proof.
  introv H. induction H; intros; simpl_notin; auto with hopi.
  - constructor. intros.
    fresh_lp (z::b::L) ((nu P)// nu P').
    apply notin_rename with x; auto.
  - apply notin_appl. apply× ltsabs_notin.
    apply× ltsconc_notin.
  - apply notin_appr. apply× ltsabs_notin.
    apply× ltsconc_notin.
Qed.

Lemma ltsproc_notin_ho : P P',
     b, notin_ho b P notin_ho b P' ltsproc (P b)(P' b)
     c, (notin_ho c P notin_ho c P').
Proof.
  intros_all.
  forwards*: ltsproc_rename H1. eapply ltsproc_notin; eauto.
Qed.

Lemma ltsproc_unused_arg : P,
  ( a, notin_ho a P notin a (P a))
   P' b, notin_ho b P notin_ho b P'
  ltsproc (P b)(P' b) a, notin_ho a P' notin a (P' a).
Proof.
  intros. fresh_proc (nu P).
  apply notin_arg with x; auto.
  forwards*: ltsproc_rename H2.
  eapply ltsproc_notin; eauto.
Qed.