Library LNSemantics

Require Export LNProperties.

Ltac auto_star ::= auto with hopi.

LN properties specific related to the LTS
***************************** stuff about genNu

genNu


Lemma open_genNu {V:Set}: (P:proc V) k x n, open k x (genNu n P) = genNu n (open (k+n) x P).
Proof.
  intros; gen k; induction n; simpl; auto; intros.
  - fequals. omega.
  - rewrite IHn. do 3 fequals. omega.
Qed.

Lemma close_genNu {V:Set}: (P:proc V) k x n, close k x (genNu n P) = genNu n (close (k+n) x P).
Proof.
  intros; gen k; induction n; simpl; auto; intros.
  - fequals. omega.
  - rewrite IHn. do 3 fequals. omega.
Qed.

Lemma fn_genNu {V:Set}: (P:proc V) n, fn (genNu n P) = fn P.
Proof.
  induction n; simpl; auto.
Qed.

Lemma is_proc_genNu {V:Set} : (P:proc V) n, ( x, x \in bn P x < n)
     is_proc (genNu n P).
Proof.
  intros; gen P; induction n; intros; simpl.
  - assert (bn P = \{}). autofs. forwards*: H x; auto. omega.
    apply is_proc_bn_rev; auto.
  - apply (proc_nu \{}). intros. unfold open. rewrite open_genNu.
    apply× IHn. intros. rewrite bn_open in H1. autofs.
    forwards*: H x0. destruct (classic (x0 =n)); intuition.
Qed.

Lemma mapN_genNu {V:Set}: n f (P:proc V),
    mapN f (genNu n P) = genNu n (mapN (liftN f n) P).
Proof.
  induction n; intros; simpl; auto.
  - rewrite× liftN_0.
  - rewrite IHn. rewrite× liftN_liftN.
Qed.


Tactics for fn/bn


Hint Rewrite @fn_close @fn_genNu @fn_mapN @fn_mapV:fn.

Ltac autofn := intros_all;
 repeat (try(match goal with
| [ H: _ \in fn(open _ _ _) |- _ ] ⇒ apply fn_open_sub in H
| [ H: _ \in fn(subst _ _) |- _ ] ⇒ apply fn_subst in H
| H1 : fn (?A) \c _, H2 : _ \in fn(?A) |- _apply H1 in H2
end); substs; simpl in *; auto with fs; autorewrite with fn fs in *; intuition auto; destruct_hyps).

Hint Rewrite @bn_open @bn_mapN @bn_mapV:bn.

Ltac autobn := intros_all;
 repeat (try( match goal with
| [ H: _ \in bn(close _ _ _) |- _ ] ⇒ apply bn_close_sub in H
| [ H: _ \in bn(subst _ _) |- _ ] ⇒ apply bn_subst in H
| [ H: _ \in map_fset _ _ |- _ ] ⇒ apply map_fset_spec in H
| H1 : bn(?A) \c _, H2 : _ \in bn(?A) |- _apply H1 in H2
end); substs; simpl in *; auto with fs; autorewrite with bn fs in *; intuition auto; destruct_hyps).

Ltac notinFalse :=
repeat (match goal with
| [ H: _ \notin _ |- False ] ⇒ solve [apply H; autofs]
end).

Tactic Notation "autofnF" := autofn; try solve [false; notinFalse].

Tactic Notation "autobnF" := autobn; try solve [false; notinFalse].


Lemma lts_conc_wf : P l (C:conc), lts P l C conc_wf C.
Proof.
  intros. gen_eq: (ag_conc C) as A. gen C.
  induction H; introv HC; try solve [inverts HC].
  - inverts HC. intros_all; omega.
  - destructA A; inverts HC. intros_all. forwards*: IHlts.
  - destructA A; inverts HC. intros_all. forwards*: IHlts.
  - destructA A; inverts HC.
    pick_fresh x. forwards*: H0 x. reflexivity. simpl in H1.
    rewrite bn_open in H1.
    case_if; intros_all.
    destruct (classic (k = n)); try (subst; auto).
    forwards*: H1 k. omega. autofs.
    forwards*: H1 k. autobnF. k; intuition. simpl_down.
Qed.

Lemma mapN_eq_on_bn {V:Set} : (P:proc V) f g,
  ( k, k \in bn P f k = g k) mapN f P = mapN g P.
Proof.
  induction P; intros; try solve [simpl; auto].
  - simpl. destruct n; try (rewrite H); try (erewrite IHP); eauto;
       simpl; try (intros; apply H); autobnF.
  - simpl. destruct n; try (rewrite H); try (erewrite IHP1);
     try (erewrite IHP2); eauto; simpl; try (intros; apply H); autobnF.
  - simpl; try (erewrite IHP1); try (erewrite IHP2); eauto;
      simpl; try (intros; apply H); autobnF.
  - simpl. erewrite IHP; eauto. intros. unfold liftN.
    case_if; auto. rewrite H; auto. simpl. rewrite down_fset_spec'.
    replace (S (k -1)) with k by omega. auto.
Qed.

Lemma down_id {V:Set}: (P:proc V) n, ( k, k \in bn P k n)
       mapN (down n) P = P.
Proof.
  intros. replace P with (mapN (fun xx) P) at 2 by (rewrite× @mapN_id).
  apply mapN_eq_on_bn; intros. forwards*: H k. simpl_down.
Qed.


open vs the LTS functions


Lemma open_agent_injective: A A' k x, open_agent k x A = open_agent k x A'
    x \notin fn_agent A x \notin fn_agent A' A = A'.
Proof.
  introv Haa' Hxa Hxa'; destructA A; destructA A'; inverts Haa';
    simpl in Hxa; simpl in Hxa'; try fequals; try fequals; eauto using open_injective.
Qed.

Lemma open_agent_id : k x A, is_agent A open_agent k x A = A.
Proof.
  intros. destructA A; simpl.
  - rewrite× @open_id. simpl in ×. forwards: @is_proc_bn H. rewrite H0; autobnF.
  - rewrite× @open_id. simpl in ×. forwards: @is_proc_bn H. rewrite H0; autobnF.
  - simpl in ×. repeat rewrite× @open_id; intros_all; forwards: H (k+n); autofs;
    omega.
Qed.

Lemma open_agent_open_agent : A (k1 k2 : nat) (x0 y0 : var), k1 k2
     open_agent k1 x0 (open_agent k2 y0 A) = open_agent k2 y0 (open_agent k1 x0 A).
Proof.
  intros. destructA A; simpl; rewrite× @open_open; try omega.
    rewrite (open_open _ (k1+n)); try omega. auto.
Qed.

Lemma fn_agent_open : A (k : nat) (x : var),
       (k \in bn_agent A fn_agent (open_agent k x A) = fn_agent A \u \{ x})
      (k \notin bn_agent A fn_agent (open_agent k x A) = fn_agent A).
Proof.
  intros; destructA A; simpl;
    try solve [forwards*: @fn_open; intuition eauto].
  split; intros.
    rewrite map_fset_spec in H. destruct H as [ y []].
    rewrite filter_fset_spec in H0. apply fset_extens.
    autofs; autofnF. intros_all. destruct H0. subst.
    replace (y-n+n) with y by omega. forwards*: @fn_open p y x.
    forwards*: @fn_open p0 y x0.
    autofs; try solve [left; match goal with
      | [H : ?A = _ |- ?x \in ?A ] ⇒ rewrite H; autofnF end];
      try solve [match goal with
        | [H : ?x0 \in fn ?P |- _ ] ⇒ apply fn_open_rev with P y x in H; autofs end].
    subst. right. rewrite H1; autofs.
    assert ((k+n) \notin bn p).
      intros_all. apply H. rewrite map_fset_spec. (k+n); intuition.
      rewrite filter_fset_spec; intuition. autofs.
    assert ((k+n) \notin bn p0).
      intros_all. apply H. rewrite map_fset_spec. (k+n); intuition.
      rewrite filter_fset_spec; intuition. autofs.
    forwards*: @fn_open p0 (k+n) x. forwards*: @fn_open p (k+n) x.
    intuition. rewrite H3, H6. auto.
Qed.

Lemma fn_agent_open_sub : A (k : nat) (x : var),
       fn_agent (open_agent k x A) \c fn_agent A \u \{ x}.
Proof.
  intros. forwards*:fn_agent_open A k x.
  destruct (classic (k \in bn_agent A)); intuition; rewrite H; autofs.
Qed.

Lemma fn_agent_amapN : A (f : nat nat), fn_agent (amapN f A) = fn_agent A.
Proof.
  intros; destructA A; simpl; rewrite× @fn_mapN.
    rewrite× @fn_mapN.
Qed.

Lemma fn_agent_new : A, fn_agent (new A) = fn_agent A.
Proof.
  intros; destructA A; simpl; autofnF.
    case_if; autofnF.
Qed.

Lemma app_open: P Q R n k x,
   (ag_proc (appl (conc_def n (open (k + n) x P) (open (k + n) x Q)) (abs_def (open k x R))) =
   open_agent k x (ag_proc (appl (conc_def n P Q) (abs_def R))))
   (ag_proc (appr (abs_def (open k x R)) (conc_def n (open (k + n) x P) (open (k + n) x Q))) =
    open_agent k x (ag_proc (appr (abs_def R) (conc_def n P Q)))).
Proof.
  intros. simpl.
  split;
    rewrite mapN_open; auto using shiftN_injective;
    replace (n+k) with (k+n) by omega; rewrite <- open_subst;
    rewrite open_genNu; simpl; auto.
Qed.

Lemma appr_open: P Q R n k x,
   appr (abs_def (open k x R)) (conc_def n (open (k + n) x P) (open (k + n) x Q)) =
    open k x (appr (abs_def R) (conc_def n P Q)).
Proof.
  intros. forwards*: (app_open P Q R n k) x.
  destruct H. inverts H0. auto.
Qed.

Lemma parl_open : k x A P, parl (open_agent k x A)(open k x P)
  = open_agent k x (parl A P).
Proof.
  intros. destructA A; simpl; auto.
  - rewrite× @mapV_open.
  - rewrite mapN_open; auto using shiftN_injective.
    replace (k+n) with (n+k) by omega; auto.
Qed.

Lemma parr_open : k x A P, parr (open k x P)(open_agent k x A)
  = open_agent k x (parr P A).
Proof.
  intros. destructA A; simpl; auto.
  - rewrite× @mapV_open.
  - rewrite mapN_open; auto using shiftN_injective.
    replace (k+n) with (n+k) by omega; auto.
Qed.

Lemma new_open_agent : A x k,
 new (open_agent (S k) x A) = open_agent k x (new A).
Proof.
   intros; destructA A; simpl; auto.
    repeat case_if; auto.
   - replace (S (k+n)) with (k + S n) by omega; auto.
   - false. autobnF.
   - false. autobnF. omega.
   - simpl in ×.
     asserts_rewrite (mapN (down n) (open (S (k+ n)) x p) =
                      open (k+n) x (mapN (down n) p)).
      rewrite mapN_open_gen. fequals. simpl_down.
      intros. simpl_down. destruct k; try omega.
      subst. replace (S (0 + n) - 1) with n in H by omega. intuition.
     asserts_rewrite× (mapN (permut n) (open (S (k + n)) x p0) =
          open (S (k + n)) x (mapN (permut n) p0)).
      rewrite mapN_open; auto using permut_injective.
      repeat fequals. simpl_permut.
Qed.

Lemma is_agent_amapN : A f, is_agent A amapN f A = A.
Proof.
  intros; destructA A; simpl; try solve [repeat fequals; auto using is_proc_mapN].
  simpl in H. replace p with (mapN (fun xx) p) at 2 by (rewrite× @mapN_id).
  replace p0 with (mapN (fun xx) p0) at 2 by (rewrite× @mapN_id).
  fequals. fequals; apply mapN_eq_on_bn; intros; forwards: H k; autofs; simpl_liftN.
Qed.

Lemma amapN_open : (k : nat) (x : var) A (f : nat nat), injective f
     open_agent (f k) x (amapN f A) = amapN f (open_agent k x A).
Proof.
  intros. destructA A; simpl;
    try solve [rewrite× @mapN_open].
  repeat (rewrite mapN_open); auto using liftN_preserves_injectivity.
  repeat (rewrite liftN_plus_n). replace (n+f k) with (f k+n) by omega.
  auto.
Qed.


bn_agent and decomposition


Lemma bn_agent_open : A k x, bn_agent (open_agent k x A) = bn_agent A \- \{ k}.
Proof.
  intros; destructA A; simpl; auto using bn_open.
  apply fset_extens.
  + autobnF; try omega.
     x1; autobnF.
     x1; autobnF.
  + autobnF. x1. autofs. left. intuition.
     x1. autofs. right. intuition.
Qed.

Lemma is_agent_bn : A, is_agent A bn_agent A = \{}.
Proof.
  intros. destructA A; simpl in *; auto using is_proc_bn.
  autofs; forwards*: H x0; autofs; omega.
Qed.

Lemma is_agent_bn_rev : A, bn_agent A = \{} is_agent A.
Proof.
  intros. destructA A; simpl in *; auto using is_proc_bn_rev.
  intros; destruct (classic (k<n)); auto. false.
  assert ((k-n) \in map_fset (fun kk - n)
            (filter_fset (fun kk n) (bn p \u bn p0))).
   rewrite map_fset_spec. k; intuition.
   rewrite filter_fset_spec. intuition.
  rewrite H in H2; autofs.
Qed.

Lemma bn_agent_new : A, bn_agent (new A) = down_fset (bn_agent A \- \{ 0}).
Proof.
  intros. destructA A; simpl; auto.
  case_if.
  + apply fset_extens; intros_all. apply down_fset_spec'. apply map_fset_spec.
    apply map_fset_spec in H. destruct_hyps. apply filter_fset_spec in H0. destruct_hyps.
     x0. split. omega. apply filter_fset_spec. intuition.
    apply down_fset_spec' in H. apply map_fset_spec.
    apply map_fset_spec in H. destruct_hyps. apply filter_fset_spec in H0. destruct_hyps.
     x0. split. omega. apply filter_fset_spec. intuition.
  + apply fset_extens; intros_all. apply down_fset_spec'. apply map_fset_spec.
    apply map_fset_spec in H. destruct_hyps. apply filter_fset_spec in H0. destruct_hyps.
     (S x0). split. omega. apply filter_fset_spec. intuition. rewrite bn_mapN in H1.
    autofs. simpl_down. subst. assert (x=n) by omega. subst. intuition.
    replace (S (x-1)) with x by omega. autofs.
    simpl in H. rewrite down_fset_spec' in H. autobnF. simpl_permut. subst. intuition.
    apply down_fset_spec' in H. apply map_fset_spec in H. destruct_hyps.
    apply filter_fset_spec in H0. destruct H0.
    apply map_fset_spec. (x0-1). split. omega.
    apply filter_fset_spec. intuition. autofs.
    left. autobnF. x0. split×. simpl_down.
    right. autobnF. apply down_fset_spec'. replace (S (x0-1)) with x0 by omega.
    autofs. x0. split×. simpl_permut.
Qed.

Lemma decomp_agent_gen: A k x, k \notin bn_agent A
     A', A = open_agent k x A' x \notin fn_agent A'.
Proof.
  intros. destructA A; simpl in ×.
  - forwards: @decomp_proc_gen p k x; auto. destruct H0 as [R].
     (ag_proc R). simpl. unfold decomp in *; intuition. fequals.
  - forwards: @decomp_proc_gen p k x; auto. destruct H0 as [R]. unfold decomp in ×.
     (ag_abs (abs_def R)). simpl. intuition. fequals.
  - forwards: @decomp_proc_gen p (k+n) x; auto.
      intros_all. apply H. rewrite map_fset_spec. (k+n).
      intuition. rewrite filter_fset_spec. intuition. autofs.
    destruct H0 as [R]. forwards: @decomp_proc_gen p0 (k+n) x.
      intros_all. apply H. rewrite map_fset_spec. (k+n).
      intuition. rewrite filter_fset_spec. intuition. autofs.
    destruct H1 as [R0].
     (ag_conc (conc_def n R R0)). simpl. intuition.
    subst×.
Qed.

Lemma decomp_agent: A k x,
    is_agent A A', A = open_agent k x A' x \notin fn_agent A'.
Proof.
  intros. forwards*: decomp_agent_gen A k x. forwards*: is_agent_bn H.
  intros_all. rewrite H0 in H1. autofs.
Qed.


The LTS preserves is_proc


Lemma is_proc_app : (F:abs) (C:conc), is_agent F is_agent C
   is_proc (appl C F) is_proc (appr F C).
Proof.
  intros [P] [n Q R]. intros. simpl in ×.
  split; apply is_proc_genNu; intros;
    autobnF; try solve [apply H0; autobnF];
    try solve [apply is_proc_bn in H; rewrite H in H2; autofs].
Qed.

Lemma notin_fn_notin_fnlab : P l A x,
        lts P l A x \notin fn P x \notin fn_lab l.
Proof.
  induction 1; simpl; auto.
  pick_fresh y. intros. forwards*: H0 y. autofnF.
Qed.

Hint Extern 1 (is_proc ?P) ⇒
  match goal with
  | H: bn P = \{} |- _apply is_proc_bn_rev
  | |- is_proc (open _ _ (close _ _ _)) ⇒ apply is_proc_open_close; intuition
  | |- is_proc (mapN _ _) ⇒ rewrite is_proc_mapN; intuition
  | |- is_proc (mapV _ _) ⇒ apply is_proc_mapV; intuition
  | |- is_proc (bind _ _) ⇒ apply is_proc_bind; intuition
  end : hopi.

Hint Extern 1 ( (x:incV Empty_set), is_proc (_)) ⇒
    intros [|]; simpl; intuition:hopi.

Hint Extern 1 (is_proc (appr _ _)) ⇒ apply is_proc_app; intuition:hopi.
Hint Extern 1 (is_proc (appl _ _)) ⇒ apply is_proc_app; intuition:hopi.

Lemma lts_is_proc: P l A, is_proc P lts P l A is_agent A.
Proof.
  introv Hp Hlts; induction Hlts; simpl; inverts× Hp.
  - intros. apply is_proc_bn in H1. apply is_proc_bn in H3.
    rewrite H1 in H. rewrite H3 in H. autofs.
  - destructA A; simpl in *; auto with hopi.
    intros. specialize (IHHlts H1). apply IHHlts.
    autobnF. apply is_proc_bn in H2; rewrite H2 in H0; autofs.
  - destructA A; simpl in *; auto with hopi.
    intros. specialize (IHHlts H2). apply IHHlts.
    autobnF. apply is_proc_bn in H1; rewrite H1 in H0; autofs.
  - destructA A; simpl;
      try solve [apply (proc_nu (L \u fn_lab l \u L0));
                 auto; intros; forwards*: H0 x].
    pick_fresh y. forwards*: H2 y.
    case_if; intros.
    destruct (classic (k=n)); try omega.
    forwards: H0 H1 k; try solve [autobnF].
    asserts_rewrite (mapN (down n) p = p) in H3.
      rewrite× @down_id.
      intros. destruct (classic (k0 = n)); try omega.
      forwards: H0 H1 k0; autobnF; omega.
    destruct (classic (k=n)); try omega.
    false. subst. autobnF. rewrite down_fset_spec' in H6. autobnF. simpl_permut. subst.
    forwards*: H0 H1 (S n). autobnF.
    forwards*: H0 H1 k. autobnF.
    right. autobnF. rewrite down_fset_spec' in H7. autobnF. simpl_permut.
    assert (x=k) by omega. subst×. subst×. forwards*: H0 H1 (S k); autobnF.
Qed.

Hint Extern 1 (is_proc ?P) ⇒
  match goal with
  | H: lts _ _ (ag_proc P) |- _forwards*: @lts_is_proc H; intuition
  | H: lts _ _ (ag_abs (abs_def P)) |- _forwards*: @lts_is_proc H; intuition
  end : hopi.

Hint Extern 1 (is_agent ?A) ⇒
  match goal with
  | H: lts _ _ A |- _forwards: @lts_is_proc H; auto
  end : hopi.


LTS and fn


Lemma fn_new : A, fn_agent (new A) = fn_agent A.
Proof.
  intros; destructA A; simpl; auto.
   case_if; auto. simpl. rewrite× @fn_mapN. rewrite× @fn_mapN.
Qed.

Lemma fn_appr_appl : F C, fn (appr F C) \c fn_agent C \u fn_agent F
     fn (appl C F) \c fn_agent F \u fn_agent C.
Proof.
  intros. destruct F as []; destruct C as [].
    split; autofnF; intuition.
Qed.

Lemma fn_parl: A P, fn_agent (parl A P) = fn_agent A \u fn P.
Proof.
  intros. destructA A; simpl; try solve [autofnF; autofs].
Qed.

Lemma fn_parr: A P, fn_agent (parr P A) = fn_agent A \u fn P.
Proof.
  intros. destructA A; simpl; try solve [autofnF; autofs].
Qed.

Lemma lts_fn : P l A, lts P l A fn_agent A \c fn P.
Proof.
  intros. induction H; simpl in *; try solve [autofs].
  - rewrite fn_parl; autofs.
  - rewrite fn_parr; autofs.
  - rewrite fn_new. pick_fresh x. forwards*: H0 x.
    forwards: fn_agent_open_rev A 0 x. intros_all. assert (H4:= H3).
    apply H2 in H3. apply H1 in H3. autofnF.
  - forwards: fn_appr_appl F C. intros_all. apply H1 in H2.
    destruct F as []; destruct C as []; autofs. left.
    forwards: IHlts1 x. autofs. auto. forwards: IHlts1 x. autofs. auto.
  - forwards: fn_appr_appl F C. intros_all. apply H1 in H2.
    destruct F as []; destruct C as []; autofs.
    forwards: IHlts2 x. autofs. auto. forwards: IHlts2 x. autofs. auto.
Qed.


The LTS is stable by renaming


Definition subst_lab l (x y:var) :=
  match l with
  | out nout (If (n=x) then y else n)
  | inp ninp (If (n=x) then y else n)
  | _l
  end.

Lemma subst_lab_id : l x y, x \notin fn_lab l subst_lab l x y = l.
Proof.
  intros; destruct l; simpl;
    try case_if; auto; try (false; autofnF).
Qed.

Lemma subst_lab_inv : l x y, y \notin fn_lab l subst_lab (subst_lab l x y) y x = l.
Proof.
  intros; destruct l; simpl; repeat case_if; subst; auto;
    try (false; autofnF).
Qed.

Lemma subst_lab_rename : l x y z, y \notin fn_lab l
    subst_lab (subst_lab l x y) y z = subst_lab l x z.
Proof.
  intros; destruct l; simpl; repeat case_if; subst; auto;
    try (false; autofnF).
Qed.

Lemma fn_subst_lab : l x y, fn_lab (subst_lab l x y) \c fn_lab l \u \{ y }.
Proof.
  intros; destruct l; simpl; repeat case_if; subst; autofs.
Qed.

Lemma lts_rename : P A l k x, is_proc (open k x P) lts (open k x P) l (open_agent k x A)
    x \notin fn P x \notin fn_agent A
     y, lts (open k y P) (subst_lab l x y) (open_agent k y A).
Proof.
  introv Hip Hlts. assert (is_agent (open_agent k x A)) by auto with hopi.
  remember (open k x P) as P'. remember (open_agent k x A) as A'. gen k x P A.
  induction Hlts; intros k x P' Hp A' Ha Hx HxA; destruct P'; inverts Hp; inverts Hip; simpl in Hx; intros.
  - destructA A'; inverts Ha. simpl. replace (k+0) with k in × by omega.
    destruct n; simpl in HxA; forwards*: @open_injective H4;
    forwards*: @open_injective H6; subst; clear H4 H6; repeat case_if; auto with hopi.
    inverts H1. autofs.
    inverts H1. auto with hopi.
  - destructA A'; inverts Ha. simpl.
    destruct n; simpl in HxA; forwards*: @open_injective H3;
    subst; clear H3; repeat case_if; auto with hopi.
    inverts H1. autofs.
    inverts H1. auto with hopi.
  - forwards*: decomp_agent A k x. destruct_hyps. subst.
    rewrite parl_open in Ha. forwards*: @open_agent_injective Ha. rewrite fn_parl. autofs.
    simpl. forwards*: IHHlts k x P'1 y. eapply lts_parl'; eauto.
    rewrite parl_open. rewrite× H0.
  - forwards*: decomp_agent A k x. destruct_hyps. subst.
    rewrite parr_open in Ha. forwards*: @open_agent_injective Ha. rewrite fn_parr. autofs.
    simpl. forwards*: IHHlts k x P'2 y. eapply lts_parr'; eauto.
    rewrite parr_open. rewrite× H0.
  - simpl. forwards*: decomp_agent_gen A (S k) x. apply is_agent_bn in H. rewrite bn_agent_new in H.
    apply down_fset_empty_rev in H. intros_all. apply H in H2. autofs. omega.
    destruct_hyps. rename x0 into A''.
    rewrite H2 in Ha. rewrite new_open_agent in Ha. forwards*: open_agent_injective Ha. rewrite fn_agent_new. auto.
    apply (lts_new' (L \u L0 \u fn_lab l \u fn P' \u \{x})) with (open_agent (S k) y A'').
    intros. rewrite× @open_open. rewrite× open_agent_open_agent. eapply H1; eauto.
    forwards*: H0 x0.
    rewrite× <- @open_open. rewrite× <- open_agent_open_agent. rewrite H2. auto.
    autofnF. intros_all. apply fn_agent_open_sub in H8. autofs.
    rewrite new_open_agent. rewrite× H5.
  - simpl. forwards*: decomp_agent C k x. destruct_hyps.
    destructA x0; inverts H0.
    forwards*: IHHlts1 k x P'1 (conc_def n p p0) y.
    assert (is_agent (conc_def n (open (k + n) x p) (open (k + n) x p0))) by auto with hopi.
    simpl in H0. intros. apply× H0.
    forwards*: decomp_agent F k x. destruct_hyps.
    destructA x0; inverts H4.
    forwards*: IHHlts2 k x P'2 (abs_def p1) y.
    eapply lts_taul'; eauto. forwards: (app_open p p0 p1 n k) x. destruct H6.
    simpl in Ha. rewrite H6 in Ha. clear H6 H7.
    replace (ag_proc (open k x (genNu n (p0 // subst ((shiftN n) p1) p))))
      with (open_agent k x (ag_proc (genNu n (p0 // subst ((shiftN n) p1) p)))) in Ha by reflexivity.
    forwards*: open_agent_injective Ha. autofnF.
    rewrite <- H6. forwards: (app_open p p0 p1 n k) y. destruct H7. simpl. rewrite× <- H7.
  - simpl. forwards*: decomp_agent C k x. destruct_hyps.
    destructA x0; inverts H0.
    forwards*: IHHlts2 k x P'2 (conc_def n p p0) y.
    assert (is_agent (conc_def n (open (k + n) x p) (open (k + n) x p0))) by auto with hopi.
    simpl in H0. intros. apply× H0.
    forwards*: decomp_agent F k x. destruct_hyps.
    destructA x0; inverts H4.
    forwards*: IHHlts1 k x P'1 (abs_def p1) y.
    eapply lts_taur'; eauto. forwards: (app_open p p0 p1 n k) x. destruct H6.
    simpl in Ha. rewrite H7 in Ha. clear H6 H7.
    replace (ag_proc (open k x (genNu n (subst ((shiftN n) p1) p // p0))))
      with (open_agent k x (ag_proc (genNu n (subst ((shiftN n) p1) p // p0)))) in Ha by reflexivity.
    forwards*: open_agent_injective Ha. autofnF.
    rewrite <- H6. forwards: (app_open p p0 p1 n k) y. destruct H7. simpl. rewrite× <- H8.
Qed.

Lemma lts_open : P P' A l k x, P = open k x P' is_proc P lts P l A x \notin fn P'
       A', A = open_agent k x A' (x \notin fn_agent A')
        ( y, lts (open k y P') (subst_lab l x y) (open_agent k y A')).
Proof.
  intros. forwards*: decomp_agent A k x. destruct_hyps. x0. intuition. subst.
  apply× lts_rename.
Qed.