(****************************************************************************************)
(* Encoding of Ambient Calculus with the modal logical system proposed in               *)
(* "Logical Properties of Name Restriction" by Luca Cardelli, Andrew D. Gordon, TLCA'01 *)
(* Author: Ivan Scagnetto                                                               *)
(****************************************************************************************)

Parameter name: Set.

Inductive Nlist : Set :=
   empty : Nlist
 | cons  : name -> Nlist -> Nlist.

Inductive Nlist_notin [x:name] : Nlist -> Prop :=
   Nlist_notin_empty  : (Nlist_notin x empty)
 | Nlist_notin_cons   : (y:name)(l:Nlist)
                        ~x=y -> (Nlist_notin x l) -> (Nlist_notin x (cons y l)).

Inductive Nlist_isin [x:name] : Nlist -> Prop :=
   Nlist_isin_name  : (Nlist_isin x (cons x empty))
 | Nlist_isin_cons  : (y:name)(l:Nlist)
                      x=y \/ (Nlist_isin x l) -> (Nlist_isin x (cons y l)).

Inductive cap: Set :=
    name2cap : name -> cap
  | in_cap  : cap -> cap
  | out_cap : cap -> cap
  | open    : cap -> cap
  | eps     : cap
  | path    : cap -> cap -> cap.

Inductive notin_cap [m:name]: cap -> Prop :=
    notin_cap_name : (n:name)~m=n -> (notin_cap m (name2cap n))
  | notin_cap_in   : (M:cap)(notin_cap m M) -> (notin_cap m (in_cap M))
  | notin_cap_out  : (M:cap)(notin_cap m M) -> (notin_cap m (out_cap M))
  | notin_cap_open : (M:cap)(notin_cap m M) -> (notin_cap m (open M))
  | notin_cap_eps  : (notin_cap m eps)
  | notin_cap_path : (M,N:cap)(notin_cap m M) -> (notin_cap m N) -> (notin_cap m (path M N)).

Inductive isin_cap [m:name]: cap -> Prop :=
    isin_cap_name : (isin_cap m (name2cap m))
  | isin_cap_in   : (M:cap)(isin_cap m M) -> (isin_cap m (in_cap M))
  | isin_cap_out  : (M:cap)(isin_cap m M) -> (isin_cap m (out_cap M))
  | isin_cap_open : (M:cap)(isin_cap m M) -> (isin_cap m (open M))
  | isin_cap_path : (M,N:cap)(isin_cap m M) \/ (isin_cap m N) -> (isin_cap m (path M N)).

Lemma SEP_CAP: (M:cap)(m,n:name)(isin_cap m M)->(notin_cap n M)->~m=n.

Proof.

Induction M; Intros.

Inversion_clear H; Inversion_clear H0; Auto.

Inversion_clear H0; Inversion_clear H1; Apply H; Auto.

Inversion_clear H0; Inversion_clear H1; Apply H; Auto.

Inversion_clear H0; Inversion_clear H1; Apply H; Auto.

Inversion_clear H.

Inversion_clear H1; Inversion_clear H2; Inversion_clear H3; [Apply H | Apply H0]; Auto.

Qed.

Lemma ISIN_NOTIN_CAP_FALSE: (C:cap)(n:name)(isin_cap n C) -> (notin_cap n C) -> False.

Proof.

Intros; Cut ~n=n; [Intro | Apply SEP_CAP with C; Assumption].
Unfold not in H1; Apply H1; Trivial.

Qed.

Inductive proc: Set :=
    nu      : (name -> proc) -> proc
  | nil     : proc
  | par     : proc -> proc -> proc
  | bang    : proc -> proc
  | ambient : cap -> proc -> proc
  | cap_act : cap -> proc -> proc
  | in_act  : (name -> proc) -> proc
  | out_act : cap -> proc.

Inductive notin_proc [m:name]: proc -> Prop :=
    notin_proc_nu   : (P:name->proc)((n:name)~m=n -> (notin_proc m (P n))) -> (notin_proc m (nu P))
  | notin_proc_nil  : (notin_proc m nil)
  | notin_proc_par  : (P,Q:proc)(notin_proc m P) -> (notin_proc m Q) -> (notin_proc m (par P Q))
  | notin_proc_bang : (P:proc)(notin_proc m P) -> (notin_proc m (bang P))
  | notin_proc_amb  : (M:cap)(P:proc)(notin_cap m M) -> (notin_proc m P) -> (notin_proc m (ambient M P))
  | notin_proc_act  : (M:cap)(P:proc)(notin_cap m M) -> (notin_proc m P) -> (notin_proc m (cap_act M P))
  | notin_proc_in   : (P:name->proc)((n:name)~m=n -> (notin_proc m (P n))) -> (notin_proc m (in_act P))
  | notin_proc_out  : (M:cap)(notin_cap m M) -> (notin_proc m (out_act M)).

Inductive isin_proc [m:name]: proc -> Prop :=
    isin_proc_nu   : (P:name->proc)((n:name)(isin_proc m (P n))) -> (isin_proc m (nu P))
  | isin_proc_par  : (P,Q:proc)(isin_proc m P) \/ (isin_proc m Q) -> (isin_proc m (par P Q))
  | isin_proc_bang : (P:proc)(isin_proc m P) -> (isin_proc m (bang P))
  | isin_proc_amb  : (M:cap)(P:proc)(isin_cap m M) \/ (isin_proc m P) -> (isin_proc m (ambient M P))
  | isin_proc_act  : (M:cap)(P:proc)(isin_cap m M) \/ (isin_proc m P) -> (isin_proc m (cap_act M P))
  | isin_proc_in   : (P:name->proc)((n:name)(isin_proc m (P n))) -> (isin_proc m (in_act P))
  | isin_proc_out  : (M:cap)(isin_cap m M) -> (isin_proc m (out_act M)).

Inductive form: Set :=
    T: form
  | neg: form -> form
  | Or: form -> form -> form
  | zero: form
  | comp: form -> form -> form
  | comp_adj: form -> form -> form
  | loc: name -> form -> form
  | loc_adj: form -> name -> form
  | rev: name -> form -> form
  | rev_adj: form -> name -> form
  | sometime: form -> form
  | somewhere: form -> form
  | forall: (name -> form) -> form
  | new: (name -> form) -> form.

Inductive notin_form [m:name] : form->Prop :=
    notin_T: (notin_form m T)
  | notin_neg: (F:form)(notin_form m F) -> (notin_form m (neg F))
  | notin_Or: (F,G:form)(notin_form m F) -> (notin_form m G) -> (notin_form m (Or F G))
  | notin_zero: (notin_form m zero)
  | notin_comp: (F,G:form)(notin_form m F) -> (notin_form m G) -> (notin_form m (comp F G))
  | notin_comp_adj: (F,G:form)(notin_form m F) -> (notin_form m G) -> (notin_form m (comp_adj F G))
  | notin_loc: (F:form)(n:name)~m=n -> (notin_form m F) -> (notin_form m (loc n F))
  | notin_loc_adj: (F:form)(n:name)~m=n -> (notin_form m F) -> (notin_form m (loc_adj F n))
  | notin_rev: (F:form)(n:name)~m=n -> (notin_form m F) -> (notin_form m (rev n F))
  | notin_rev_adj: (F:form)(n:name)~m=n -> (notin_form m F) -> (notin_form m (rev_adj F n))
  | notin_sometime: (F:form)(notin_form m F) -> (notin_form m (sometime F))
  | notin_somewhere: (F:form)(notin_form m F) -> (notin_form m (somewhere F))
  | notin_forall: (F:name->form)((n:name)~m=n -> (notin_form m (F n))) -> (notin_form m (forall F))
  | notin_new: (F:name->form)((n:name)~m=n -> (notin_form m (F n))) -> (notin_form m (new F)).

Inductive isin_form [m:name] : form->Prop :=
    isin_neg: (F:form)(isin_form m F) -> (isin_form m (neg F))
  | isin_Or: (F,G:form)(isin_form m F) \/ (isin_form m G) -> (isin_form m (Or F G))
  | isin_comp: (F,G:form)(isin_form m F) \/ (isin_form m G) -> (isin_form m (comp F G))
  | isin_comp_adj: (F,G:form)(isin_form m F) \/ (isin_form m G) -> (isin_form m (comp_adj F G))
  | isin_loc: (F:form)(n:name)m=n \/ (isin_form m F) -> (isin_form m (loc n F))
  | isin_loc_adj: (F:form)(n:name)m=n \/ (isin_form m F) -> (isin_form m (loc_adj F n))
  | isin_rev: (F:form)(n:name)m=n \/ (isin_form m F) -> (isin_form m (rev n F))
  | isin_rev_adj: (F:form)(n:name)m=n \/ (isin_form m F) -> (isin_form m (rev_adj F n))
  | isin_sometime: (F:form)(isin_form m F) -> (isin_form m (sometime F))
  | isin_somewhere: (F:form)(isin_form m F) -> (isin_form m (somewhere F))
  | isin_forall: (F:name->form)((n:name)(isin_form m (F n))) -> (isin_form m (forall F))
  | isin_new: (F:name->form)((n:name)(isin_form m (F n))) -> (isin_form m (new F)).

Axiom unsat: (P:proc)(F:form)(Ex [n:name]((notin_proc n P) /\ (notin_form n F))).

Lemma NLIST_NOTIN_PROC: (l:Nlist)(Ex [P:proc]((x:name)(notin_proc x P) -> (Nlist_notin x l)) /\ ((x:name)(Nlist_isin x l) -> (isin_proc x P))).

Proof.

Induction l; Intros; [Exists nil; Split; Intros; [Apply Nlist_notin_empty | Inversion_clear H] | Inversion_clear H; Inversion_clear H0; Exists (ambient (name2cap n) x); Split; Intros; [Inversion_clear H0; Inversion_clear H2; Apply Nlist_notin_cons; Auto | Inversion_clear H0; [Apply isin_proc_amb; Left; Apply isin_cap_name | Inversion_clear H2; [Rewrite H0; Apply isin_proc_amb; Left; Apply isin_cap_name | Apply isin_proc_amb; Right; Auto]]]].

Qed.

Lemma UNSAT_NLIST_CAP_PROC_FORM: (l:Nlist)(M:cap)(P:proc)(F:form)(Ex [n:name]((Nlist_notin n l) /\ (notin_cap n M) /\ (notin_proc n P) /\ (notin_form n F))).

Proof.

Intros; Elim (NLIST_NOTIN_PROC l); Intros.
Inversion_clear H.
Elim (unsat (cap_act M (par x P)) F); Intros.
Inversion_clear H; Inversion_clear H2; Inversion_clear H4.
Exists x0; Split; Try Split; Auto.

Qed.

Lemma UNSAT_PROC_NLIST: (P:proc)(l:Nlist)(Ex [n:name](notin_proc n P) /\ (Nlist_notin n l)).

Proof.

Intros; Elim (UNSAT_NLIST_CAP_PROC_FORM l eps P T); Intros.
Inversion_clear H; Inversion_clear H1; Inversion_clear H2.
Exists x; Split; Try Split; Assumption.

Qed.

Lemma UNSAT_FORM_NLIST: (A:form)(l:Nlist)(Ex [n:name](notin_form n A) /\ (Nlist_notin n l)).

Proof.

Intros; Elim (UNSAT_NLIST_CAP_PROC_FORM l eps nil A); Intros.
Inversion_clear H; Inversion_clear H1; Inversion_clear H2.
Exists x; Split; Try Split; Assumption.

Qed.

Lemma UNSAT_FORM: (F:form)(Ex [x:name](notin_form x F)).

Proof.

Intro; Elim (UNSAT_NLIST_CAP_PROC_FORM empty eps nil F); Intros.
Inversion_clear H; Inversion_clear H1; Inversion_clear H2.
Exists x; Assumption.

Qed.

Lemma UNSAT_CAP_PROC_NLIST: (M:cap)(P:proc)(l:Nlist)(Ex [n:name](notin_cap n M) /\ (notin_proc n P) /\ (Nlist_notin n l)).

Proof.

Intros; Elim (UNSAT_NLIST_CAP_PROC_FORM l M P T); Intros.
Inversion_clear H; Inversion_clear H1; Inversion_clear H2.
Exists x; Split; Try Split; Assumption.

Qed.

Lemma UNSAT_NLIST_PROC_FORM: (l:Nlist)(P:proc)(F:form)(Ex [n:name]((Nlist_notin n l) /\ (notin_proc n P) /\ (notin_form n F))).

Proof.

Intros; Elim (UNSAT_NLIST_CAP_PROC_FORM l eps P F); Intros.
Inversion_clear H; Inversion_clear H1; Inversion_clear H2.
Exists x; Split; Try Split; Assumption.

Qed.

Lemma SEP_PROC: (P:proc)(m,n:name)(isin_proc m P)->(notin_proc n P)->~m=n.

Proof.

Induction P; Intros.

Inversion_clear H0; Inversion_clear H1.
Elim (UNSAT_PROC_NLIST nil (cons m (cons n empty))); Intros.
Inversion_clear H1; Clear H3; Inversion_clear H4; Inversion_clear H3; Clear H5.
Apply H with x; Auto.

Inversion_clear H.

Inversion_clear H1; Inversion_clear H2; Inversion_clear H3; [Apply H | Apply H0]; Auto.

Inversion_clear H0; Inversion_clear H1; Apply H; Auto.

Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; [Apply SEP_CAP with c | Apply H]; Assumption.

Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; [Apply SEP_CAP with c | Apply H]; Assumption.

Inversion_clear H0; Inversion_clear H1.
Elim (UNSAT_PROC_NLIST nil (cons m (cons n empty))); Intros.
Inversion_clear H1; Clear H3; Inversion_clear H4; Inversion_clear H3; Clear H5.
Apply H with x; Auto.

Inversion_clear H; Inversion_clear H0; Apply SEP_CAP with c; Assumption.

Qed.

Lemma ISIN_NOTIN_PROC_FALSE: (P:proc)(n:name)(isin_proc n P) -> (notin_proc n P) -> False.

Proof.

Intros; Cut ~n=n; [Intro | Apply SEP_PROC with P; Assumption].
Unfold not in H1; Apply H1; Trivial.

Qed.

Lemma SEP_FORM: (A:form)(m,n:name)(isin_form m A)->(notin_form n A)->~m=n.

Proof.

Induction A; Intros.

Inversion_clear H.

Inversion_clear H0; Inversion_clear H1; Apply H; Auto.

Inversion_clear H1; Inversion_clear H2; Inversion_clear H3; [Apply H | Apply H0]; Auto.

Inversion_clear H.

Inversion_clear H1; Inversion_clear H2; Inversion_clear H3; [Apply H | Apply H0]; Auto.

Inversion_clear H1; Inversion_clear H2; Inversion_clear H3; [Apply H | Apply H0]; Auto.

Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; [Rewrite H1; Auto | Apply H; Assumption].

Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; [Rewrite H1; Auto | Apply H; Assumption].

Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; [Rewrite H1; Auto | Apply H; Assumption].

Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; [Rewrite H1; Auto | Apply H; Assumption].

Inversion_clear H0; Inversion_clear H1; Apply H; Auto.

Inversion_clear H0; Inversion_clear H1; Apply H; Auto.

Inversion_clear H0; Inversion_clear H1.
Elim (UNSAT_FORM_NLIST T (cons m (cons n empty))); Intros.
Inversion_clear H1; Clear H3; Inversion_clear H4; Inversion_clear H3; Clear H5.
Apply H with x; Auto.

Inversion_clear H0; Inversion_clear H1.
Elim (UNSAT_FORM_NLIST T (cons m (cons n empty))); Intros.
Inversion_clear H1; Clear H3; Inversion_clear H4; Inversion_clear H3; Clear H5.
Apply H with x; Auto.

Qed.

Lemma ISIN_NOTIN_FORM_FALSE: (A:form)(n:name)(isin_form n A) -> (notin_form n A) -> False.

Proof.

Intros; Cut ~n=n; [Intro | Apply SEP_FORM with A; Assumption].
Unfold not in H1; Apply H1; Trivial.

Qed.

Inductive struct_eq: proc -> proc -> Prop :=
    struct_refl       : (P:proc)(struct_eq P P)
  | struct_symm       : (P,Q:proc)(struct_eq P Q) -> (struct_eq Q P)
  | struct_trans      : (P,Q,R:proc)(struct_eq P Q) -> (struct_eq Q R) -> (struct_eq P R)
  | struct_res        : (P,Q:name->proc)(l:Nlist)((n:name)(Nlist_notin n l) -> (notin_proc n (nu P)) -> (notin_proc n (nu Q)) -> (struct_eq (P n) (Q n))) -> (struct_eq (nu P) (nu Q))
  | struct_par        : (P,Q:proc)(struct_eq P Q) -> (R:proc)(struct_eq (par P R) (par Q R))
  | struct_repl       : (P,Q:proc)(struct_eq P Q) -> (struct_eq (bang P) (bang Q))
  | struct_amb        : (P,Q:proc)(struct_eq P Q) -> (n:name)(struct_eq (ambient (name2cap n) P) (ambient (name2cap n) Q))
  | struct_action     : (P,Q:proc)(struct_eq P Q) -> (M:cap)(struct_eq (cap_act M P) (cap_act M Q))
  | struct_input      : (P,Q:name->proc)(l:Nlist)((n:name)(Nlist_notin n l) -> (notin_proc n (nu P)) -> (notin_proc n (nu Q)) -> (struct_eq (P n) (Q n))) -> (struct_eq (in_act P) (in_act Q))
  | struct_epsilon    : (P:proc)(struct_eq (cap_act eps P) P)
  | struct_path       : (M,M':cap)(P:proc)(struct_eq (cap_act (path M M') P) (cap_act M (cap_act M' P)))
  | struct_res_res    : (P:name->name->proc)(struct_eq (nu [n:name](nu [m:name](P n m))) (nu [n:name](nu [m:name](P m n))))
  | struct_res_zero   : (struct_eq (nu [n:name]nil) nil)
  | struct_res_par    : (P:proc)(Q:name->proc)(struct_eq (nu [n:name](par P (Q n))) (par P (nu Q)))
  | struct_res_amb    : (m:name)(P:name->proc)(struct_eq (nu [n:name](ambient (name2cap m) (P n))) (ambient (name2cap m) (nu P)))
  | struct_par_zero   : (P:proc)(struct_eq (par P nil) P)
  | struct_par_comm   : (P,Q:proc)(struct_eq (par P Q) (par Q P))
  | struct_par_assoc  : (P,Q,R:proc)(struct_eq (par (par P Q) R) (par P (par Q R)))
  | struct_repl_zero  : (struct_eq (bang nil) nil)
  | struct_repl_par   : (P,Q:proc)(struct_eq (bang (par P Q)) (par (bang P) (bang Q)))
  | struct_repl_copy  : (P:proc)(struct_eq (bang P) (par P (bang P)))
  | struct_repl_repl  : (P:proc)(struct_eq (bang P) (bang (bang P))).

Inductive subst_cap [M:cap]: (name->cap) -> cap -> Prop :=
    subst_cap_name : (subst_cap M name2cap M)
  | subst_cap_void : (n:name)(subst_cap M [_:name](name2cap n) (name2cap n))
  | subst_cap_in   : (N:name->cap)(N':cap)(subst_cap M N N') ->
                     (subst_cap M [n:name](in_cap (N n)) (in_cap N'))
  | subst_cap_out  : (N:name->cap)(N':cap)(subst_cap M N N') ->
                     (subst_cap M [n:name](out_cap (N n)) (out_cap N'))
  | subst_cap_open : (N:name->cap)(N':cap)(subst_cap M N N') ->
                     (subst_cap M [x:name](open (N x)) (open N'))
  | subst_cap_eps  : (subst_cap M [_:name]eps eps)
  | subst_cap_path : (N,O:name->cap)(N',O':cap)(subst_cap M N N') ->
                     (subst_cap M O O') ->
                     (subst_cap M [x:name](path (N x) (O x)) (path N' O')).

Inductive subst_proc [M:cap]: (name->proc) -> proc -> Prop :=
    subst_proc_nu   : (P:name->name->proc)(P':name->proc)
                      ((y:name)(subst_proc M [x:name](P x y) (P' y))) ->
                      (subst_proc M [x:name](nu (P x)) (nu P'))
  | subst_proc_nil  : (subst_proc M [_:name]nil nil)
  | subst_proc_par  : (P,Q:name->proc)(P',Q':proc)(subst_proc M P P') ->
                      (subst_proc M Q Q') -> (subst_proc M [x:name](par (P x) (Q x)) (par P' Q'))
  | subst_proc_bang : (P:name->proc)(P':proc)(subst_proc M P P') -> (subst_proc M [x:name](bang (P x)) (bang P'))
  | subst_proc_amb  : (N:name->cap)(P:name->proc)(N':cap)(P':proc)
                      (subst_cap M N N') -> (subst_proc M P P') ->
                      (subst_proc M [x:name](ambient (N x) (P x)) (ambient N' P'))
  | subst_proc_cap  : (N:name->cap)(P:name->proc)(N':cap)(P':proc)
                      (subst_cap M N N') -> (subst_proc M P P') ->
                      (subst_proc M [x:name](cap_act (N x) (P x)) (cap_act N' P'))
  | subst_proc_in   : (P:name->name->proc)(P':name->proc)
                      ((y:name)(subst_proc M [x:name](P x y) (P' y))) ->
                      (subst_proc M [x:name](in_act (P x)) (in_act P'))
  | subst_proc_out  : (N:name->cap)(N':cap)
                      (subst_cap M N N') ->
                      (subst_proc M [x:name](out_act (N x)) (out_act N')).

Inductive red: proc -> proc -> Prop :=
    red_in        : (m,n:name)(P,Q,R:proc)(red (par (ambient (name2cap n) (par (cap_act (in_cap (name2cap m)) P) Q)) (ambient (name2cap m) R)) (ambient (name2cap m) (par (ambient (name2cap n) (par P Q)) R)))
  | red_out       : (m,n:name)(P,Q,R:proc)(red (ambient (name2cap m) (par (ambient (name2cap n) (par (cap_act (out_cap (name2cap m)) P) Q)) R)) (par (ambient (name2cap n) (par P Q)) (ambient (name2cap m) R)))
  | red_open      : (n:name)(P,Q:proc)(red (par (cap_act (open (name2cap n)) P) (ambient (name2cap n) Q)) (par P Q))
  | red_comm      : (P:name->proc)(M:cap)(P':proc)(subst_proc M P P') -> (red (par (in_act P) (out_act M)) P')
  | red_res       : (P,Q:name->proc)(l:Nlist)((n:name)(Nlist_notin n l) -> (notin_proc n (nu P)) -> (notin_proc n (nu Q)) -> (red (P n) (Q n))) -> (red (nu P) (nu Q))
  | red_par       : (P,Q:proc)(red P Q) -> (R:proc)(red (par P R) (par Q R))
  | red_amb       : (P,Q:proc)(red P Q) -> (n:name)(red (ambient (name2cap n) P) (ambient (name2cap n) Q))
  | red_struct_eq : (P,Q:proc)(red P Q) -> (P':proc)(struct_eq P P') -> (Q':proc)(struct_eq Q Q') -> (red P' Q').

Inductive red_star: proc -> proc -> Prop :=
    base_red   : (P,Q:proc)(red P Q) -> (red_star P Q)
  | red_refl   : (P:proc)(red_star P P)
  | red_trans  : (P,Q,R:proc)(red_star P Q) -> (red_star Q R) -> (red_star P R).

Definition nest:=
  [P:proc][P':proc](Ex [n:name](Ex [P'':proc](struct_eq P (par (ambient (name2cap n) P') P'')))).

Inductive nest_star: proc -> proc -> Prop :=
    base_nest   : (P,Q:proc)(nest P Q) -> (nest_star P Q)
  | nest_refl   : (P:proc)(nest_star P P)
  | nest_trans  : (P,Q,R:proc)(nest_star P Q) -> (nest_star Q R) -> (nest_star P R).

Parameter sat : proc -> form -> Prop.

Axiom sat_T: (P:proc)(sat P T).
Axiom sat_neg: (P:proc)(A:form)
               ~(sat P A)
               <-> (sat P (neg A)).
Axiom sat_Or: (P:proc)(A,B:form)
              ((sat P A) \/ (sat P B))
              <-> (sat P (Or A B)).
Axiom sat_zero: (P:proc)(struct_eq P nil)
                <-> (sat P zero).
Axiom sat_comp: (P:proc)(A,B:form)
                (Ex [P':proc](Ex [P'':proc](struct_eq P (par P' P''))
                                        /\ (sat P' A) /\ (sat P'' B)))
                <-> (sat P (comp A B)).
Axiom sat_comp_adj: (P:proc)(A,B:form)
                    ((P':proc)(sat P' A) -> (sat (par P P') B))
                    <-> (sat P (comp_adj A B)).
Axiom sat_loc: (P:proc)(n:name)(A:form)
               (Ex [P':proc](struct_eq P (ambient (name2cap n) P')) /\
                            (sat P' A))
               <-> (sat P (loc n A)).
Axiom sat_loc_adj: (P:proc)(A:form)(n:name)
                   (sat (ambient (name2cap n) P) A)
                   <-> (sat P (loc_adj A n)).

Axiom sat_rev: (P:proc)(n:name)(A:form)
               ((notin_proc n P) /\ (Ex [P':name->proc](struct_eq P (nu P'))
                               /\ (sat (P' n) A)))
               <-> (sat P (rev n A)).

Axiom sat_rev_adj: (P:proc)(n:name)(A:form)
                   (Ex [P':name->proc]P=(P' n) /\ (notin_proc n (nu P')) /\ (sat (nu P') A))
                   <-> (sat P (rev_adj A n)).
Axiom sat_sometime: (P:proc)(A:form)
                    (Ex [P':proc](red_star P P') /\ (sat P' A))
                    <-> (sat P (sometime A)).
Axiom sat_somewhere: (P:proc)(A:form)
                     (Ex [P':proc](nest_star P P') /\ (sat P' A))
                     <-> (sat P (somewhere A)).
Axiom sat_forall: (P:proc)(A:name->form)
                  ((m:name)(sat P (A m)))
                  <-> (sat P (forall A)).

Axiom sat_new: (P:proc)(A:name->form)
               (Ex [m:name](notin_proc m P) /\
                           (notin_form m (forall A)) /\
                           (sat P (A m)))
               <-> (sat P (new A)).

Axiom proc_ext: (P,Q:name->proc)(x:name)(notin_proc x (nu P)) -> (notin_proc x (nu Q)) -> (P x)=(Q x) -> P=Q.

Axiom proc_exp: (P:proc)(n:name)(Ex [P':name->proc](notin_proc n (nu P')) /\
                                                   P=(P' n)).

Axiom dec_name: (x,y:name)x=y \/ ~x=y.

Axiom ho_proc_exp: (P:name->proc)(n:name)(Ex [P':name->name->proc]
                                               (notin_proc n (nu [_:name](nu (P' _)))) /\
                                               P=(P' n)).

Definition notin_ho_cap:=[n:name][M:name->cap]((m:name)~n=m -> (notin_cap n (M m))).

Definition notin_ho2_cap:=[n:name][M:name->name->cap]((m:name)~n=m -> (notin_ho_cap n (M m))).

Definition isin_ho_cap:=[n:name][M:name->cap]((m:name)(isin_cap n (M m))).

Axiom cap_ext: (M,N:name->cap)(n:name)(notin_ho_cap n M) -> (notin_ho_cap n N) -> (M n)=(N n) -> M=N.

Axiom ho_cap_ext: (M,N:name->name->cap)(n:name)(notin_ho2_cap n M) -> (notin_ho2_cap n N) -> (M n)=(N n) -> M=N.

Axiom cap_exp: (M:cap)(n:name)(Ex [M':name->cap](notin_ho_cap n M') /\ M=(M' n)).

Axiom ho_cap_exp: (M:name->cap)(n:name)(Ex [M':name->name->cap](notin_ho2_cap n M') /\ M=(M' n)).

Axiom ho2_proc_exp: (P:name->name->proc)(n:name)
                    (Ex [P':name->name->name->proc]
                        (notin_proc n (nu [u:name](nu [v:name](nu (P' u v))))) /\
                        P=(P' n)).

Inductive lnp: proc -> nat -> Prop:=
    lnp_nu : (P:name->proc)(n:nat)((x:name)(lnp (P x) n)) -> (lnp (nu P) (S n))
  | lnp_nil : (lnp nil (S O))
  | lnp_par : (P,Q:proc)(n1,n2:nat)(lnp P n1) -> (lnp Q n2) -> (lnp (par P Q) (S (plus n1 n2)))
  | lnp_bang : (P:proc)(n:nat)(lnp P n) -> (lnp (bang P) (S n))
  | lnp_amb : (P:proc)(n:nat)(lnp P n) -> (M:cap)(lnp (ambient M P) (S n))
  | lnp_cap : (P:proc)(n:nat)(lnp P n) -> (M:cap)(lnp (cap_act M P) (S n))
  | lnp_in : (P:name->proc)(n:nat)((x:name)(lnp (P x) n)) -> (lnp (in_act P) (S n))
  | lnp_out : (M:cap)(lnp (out_act M) (S O)).

Require Omega.

Section nat_ind_complete.

Lemma NAT_COMPLETE: (P:nat->Prop)
                    ((n:nat)((m:nat)(lt m n) -> (P m))->(P n)) ->
                    (a,b:nat)(lt b a) -> (P b).

Proof.

Do 2 Intro.
Induction a; Intros.
Inversion_clear H0.
Inversion_clear H1.
Apply H; Intros; Apply H0; Auto.
Apply H0; Unfold lt; Assumption.

Qed.

Lemma NAT_IND: (P:nat->Prop)
               (P O)->
               ((n:nat)((m:nat)(lt m n) -> (P m))->(P n))->
               (n:nat)(P n).

Proof.

Do 3 Intro; Induction n; Intros.

Assumption.

Apply H0; Intros.
Inversion H2.
Assumption.
Apply NAT_COMPLETE with (S n0); Assumption.

Qed.

End nat_ind_complete.

Lemma LNP_S: (P:proc)(n:nat)(lnp P n)->(lt O n).

Proof.

Induction P; Intros.

Inversion_clear H0; Elim (UNSAT_PROC_NLIST nil empty); Intros.
Clear H0; Cut (lt (0) n0); [Intro | Apply H with x; Auto].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H; Unfold lt; Apply le_n.

Inversion_clear H1.
Cut (lt (0) n1); [Intro | Apply H; Assumption].
Cut (lt (0) n2); [Intro | Apply H0; Assumption].
Omega.

Inversion_clear H0.
Cut (lt (0) n0); [Intro | Auto].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H0.
Cut (lt (0) n0); [Intro | Auto].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H0.
Cut (lt (0) n0); [Intro | Auto].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H0; Elim (UNSAT_PROC_NLIST nil empty); Intros.
Clear H0; Cut (lt (0) n0); [Intro | Apply H with x; Auto].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H.
Unfold lt; Apply le_n.

Qed.

Lemma LNP_RW: (n:nat)(P:proc)(lnp P n) -> (x:name)(Q:name->proc)(notin_proc x (nu Q)) -> P=(Q x) -> (y:name)(lnp (Q y) n).

Proof.

Intro; Pattern n; Apply NAT_IND; Intros.

Cut (lt O (0)); [Intro | Apply LNP_S with P; Assumption].
Inversion_clear H2.

Inversion H0.

Rewrite <-H4 in H2; Elim (ho_proc_exp P0 x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Cut Q=([_:name](nu (x0 _))); [Intro | Apply proc_ext with x; Auto].
Rewrite H6; Apply lnp_nu; Intro.
Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons x (cons y (cons x1 empty)))); Intros.
Inversion_clear H9; Inversion_clear H11; Inversion_clear H12; Inversion_clear H13; Inversion_clear H14.
Apply H with (x0 y x2) x2; Inversion_clear H10; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Change (lnp ([_:name](x0 _ x2) y) n1); Apply H with (x0 x x2) x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Rewrite <-H8; Auto.
Inversion_clear H7; Apply notin_proc_nu; Intros.
Cut (notin_proc x (nu (x0 n2))); [Intro | Auto].
Inversion_clear H14; Auto.

Rewrite <-H3 in H2; Cut Q=([_:name]nil); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Apply notin_proc_nil); Auto].
Rewrite H5; Apply lnp_nil.

Rewrite <-H5 in H2; Elim (proc_exp P0 x); Elim (proc_exp Q0 x); Intros.
Inversion_clear H7; Inversion_clear H8.
Rewrite H10 in H2; Rewrite H11 in H2.
Cut Q=([_:name](par (x1 _) (x0 _))); [Intro | Apply proc_ext with x; Inversion_clear H7; Inversion_clear H9; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par); Auto].
Rewrite H8; Apply lnp_par; [Apply H with P0 x | Apply H with Q0 x]; Try (Rewrite <-H6; Omega); Auto.

Rewrite <-H4 in H2; Elim (proc_exp P0 x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Cut Q=([_:name](bang (x0 _))); [Intro | Apply proc_ext with x; Inversion_clear H7; Try (Apply notin_proc_nu; Intros; Apply notin_proc_bang); Auto].
Rewrite H6; Apply lnp_bang; Apply H with P0 x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.

Rewrite <-H4 in H2; Elim (proc_exp P0 x); Elim (cap_exp M x); Intros.
Inversion_clear H6; Inversion_clear H7.
Rewrite H9 in H2; Rewrite H10 in H2; Cut Q=([_:name](ambient (x0 _) (x1 _))); [Intro | Apply proc_ext with x; Inversion_clear H6; Unfold notin_ho_cap in H8; Try (Apply notin_proc_nu; Intros; Apply notin_proc_amb); Auto].
Rewrite H7; Apply lnp_amb; Apply H with P0 x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.

Rewrite <-H4 in H2; Elim (proc_exp P0 x); Elim (cap_exp M x); Intros.
Inversion_clear H6; Inversion_clear H7.
Rewrite H9 in H2; Rewrite H10 in H2; Cut Q=([_:name](cap_act (x0 _) (x1 _))); [Intro | Apply proc_ext with x; Inversion_clear H6; Unfold notin_ho_cap in H8; Try (Apply notin_proc_nu; Intros; Apply notin_proc_act); Auto].
Rewrite H7; Apply lnp_cap; Apply H with P0 x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.

Rewrite <-H4 in H2; Elim (ho_proc_exp P0 x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Cut Q=([_:name](in_act (x0 _))); [Intro | Apply proc_ext with x; Try (Inversion_clear H7; Apply notin_proc_nu; Intros; Apply notin_proc_in; Intros; Cut (notin_proc x (nu (x0 n2))); [Intro | Auto]; Inversion_clear H10); Auto].
Rewrite H6; Apply lnp_in; Intro.
Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons x (cons y (cons x1 empty)))); Intros.
Inversion_clear H9; Inversion_clear H11; Inversion_clear H12; Inversion_clear H13; Inversion_clear H14.
Apply H with (x0 y x2) x2; Inversion_clear H10; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Change (lnp ([_:name](x0 _ x2) y) n1); Apply H with (x0 x x2) x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Rewrite <-H8; Auto.
Inversion_clear H7; Apply notin_proc_nu; Intros.
Cut (notin_proc x (nu (x0 n2))); [Intro | Auto].
Inversion_clear H14; Auto.

Rewrite <-H3 in H2; Elim (cap_exp M x); Intros.
Inversion_clear H5.
Rewrite H7 in H2; Cut Q=([_:name](out_act (x0 _))); [Intro | Apply proc_ext with x; Unfold notin_ho_cap in H6; Try (Apply notin_proc_nu; Intros; Apply notin_proc_out); Auto].
Rewrite H5; Apply lnp_out.

Qed.

Lemma LNP_TOT: (P:proc)(Ex [n:nat](lnp P n)).

Proof.

Induction P; Intros.

Elim (UNSAT_PROC_NLIST (nu p) empty); Intros.
Inversion_clear H0; Clear H2; Elim (H x); Intros.
Exists (S x0); Apply lnp_nu; Intro.
Apply LNP_RW with (p x) x; Auto.

Exists (S O); Apply lnp_nil.

Inversion_clear H; Inversion_clear H0.
Exists (S (plus x x0)); Apply lnp_par; Assumption.

Inversion_clear H.
Exists (S x); Apply lnp_bang; Assumption.

Inversion_clear H.
Exists (S x); Apply lnp_amb; Assumption.

Inversion_clear H.
Exists (S x); Apply lnp_cap; Assumption.

Elim (UNSAT_PROC_NLIST (nu p) empty); Intros.
Inversion_clear H0; Clear H2; Elim (H x); Intros.
Exists (S x0); Apply lnp_in; Intro.
Apply LNP_RW with (p x) x; Auto.

Exists (S O); Apply lnp_out.

Qed.

Axiom ho_proc_ext: (P,Q:name->name->proc)(x:name)
        (notin_proc x (nu [_:name](nu (P _)))) -> (notin_proc x (nu [_:name](nu (Q _)))) -> (P x)=(Q x) -> P=Q.

Lemma PRE_NOTIN_CAP_MONO: (A:cap)(M:name->cap)(z:name)(notin_ho_cap z M) -> A=(M z) -> (x,y:name)(notin_cap x (M y)) -> (notin_ho_cap x M).

Proof.

Induction A; Intros.

Elim (dec_name n z); Intros.
Rewrite H2 in H0; Cut M=name2cap; [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Rewrite H3; Unfold notin_ho_cap; Intros; Apply notin_cap_name; Assumption.
Cut M=([_:name](name2cap n)); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Rewrite H3; Unfold notin_ho_cap; Intros; Apply notin_cap_name; Rewrite H3 in H1; Inversion_clear H1; Assumption.

Elim (cap_exp c z); Intros.
Inversion_clear H3; Rewrite H5 in H1.
Cut M=([_:name](in_cap (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H4; Unfold notin_ho_cap; Intros; Apply notin_cap_in); Auto].
Rewrite H3; Unfold notin_ho_cap; Intros; Apply notin_cap_in; Rewrite H3 in H2; Inversion_clear H2; Cut (notin_ho_cap x x0); [Intro; Unfold notin_ho_cap in H2 | Apply H with z y]; Auto.

Elim (cap_exp c z); Intros.
Inversion_clear H3; Rewrite H5 in H1.
Cut M=([_:name](out_cap (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H4; Unfold notin_ho_cap; Intros; Apply notin_cap_out); Auto].
Rewrite H3; Unfold notin_ho_cap; Intros; Apply notin_cap_out; Rewrite H3 in H2; Inversion_clear H2; Cut (notin_ho_cap x x0); [Intro; Unfold notin_ho_cap in H2 | Apply H with z y]; Auto.

Elim (cap_exp c z); Intros.
Inversion_clear H3; Rewrite H5 in H1.
Cut M=([_:name](open (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H4; Unfold notin_ho_cap; Intros; Apply notin_cap_open); Auto].
Rewrite H3; Unfold notin_ho_cap; Intros; Apply notin_cap_open; Rewrite H3 in H2; Inversion_clear H2; Cut (notin_ho_cap x x0); [Intro; Unfold notin_ho_cap in H2 | Apply H with z y]; Auto.

Cut M=([_:name]eps); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_eps); Auto].
Rewrite H2; Unfold notin_ho_cap; Intros; Apply notin_cap_eps.

Elim (cap_exp c z); Elim(cap_exp c0 z); Intros.
Inversion_clear H4; Inversion_clear H5.
Rewrite H7 in H2; Rewrite H8 in H2.
Cut M=([_:name](path (x1 _) (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H4; Unfold notin_ho_cap in H6; Unfold notin_ho_cap; Intros; Apply notin_cap_path); Auto].
Rewrite H5; Unfold notin_ho_cap; Intros; Rewrite H5 in H3; Inversion_clear H3; Apply notin_cap_path; [Cut (notin_ho_cap x x1); [Intro; Unfold notin_ho_cap in H3 | Apply H with z y] | Cut (notin_ho_cap x x0); [Intro; Unfold notin_ho_cap in H3 | Apply H0 with z y]]; Auto.

Qed.

Lemma NOTIN_CAP_MONO: (M:name->cap)(x,y:name)(notin_cap x (M y)) -> (notin_ho_cap x M).

Proof.

Intros.
Elim (UNSAT_PROC_NLIST (nu ([_:name](out_act (M _)))) empty); Intros.
Inversion_clear H0; Inversion_clear H1; Clear H2.
Apply PRE_NOTIN_CAP_MONO with (M x0) x0 y; Auto.
Unfold notin_ho_cap; Intros.
Cut (notin_proc x0 (out_act (M m))); [Intro | Auto].
Inversion_clear H2; Assumption.

Qed.

Lemma PRE_NOTIN_PROC_MONO: (n:nat)(A:proc)(lnp A n) -> (P:name->proc)(z:name)(notin_proc z (nu P)) -> A=(P z) -> (x,y:name)(notin_proc x (P y))->(notin_proc x (nu P)).

Proof.

Intro; Pattern n; Apply NAT_IND; Intros.

Cut (lt O (0)); [Intro | Apply LNP_S with A; Assumption].
Inversion_clear H3.

Inversion H0.

Rewrite <-H5 in H2; Elim (ho_proc_exp P0 z); Intros.
Inversion_clear H7; Rewrite H9 in H2.
Cut P=([_:name](nu (x0 _))); [Intro | Apply proc_ext with z; Auto].
Rewrite H7; Do 2 (Apply notin_proc_nu; Intros).
Rewrite H7 in H3; Inversion_clear H3.
Cut (notin_proc x (x0 y n3)); [Intro | Auto].
Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons n3 empty)); Intros.
Inversion_clear H13; Inversion_clear H15; Clear H16.
Cut (notin_proc x (nu [_:name](x0 _ n3))); [Intro; Inversion_clear H15; Auto | Idtac].
Apply H with n1 (x0 x1 n3) x1 y; [Rewrite <-H6; Unfold lt; Apply le_n | Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons x1 (cons z empty))); Intros; Inversion_clear H15; Inversion_clear H17; Inversion_clear H18; Clear H19; Apply LNP_RW with (x0 x1 x2) x2; [Change (lnp ([_:name](x0 _ x2) x1) n1); Apply LNP_RW with (x0 z x2) z; [Rewrite <-H9; Auto | Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc z (nu (x0 n4))); [Intro | Auto]; Inversion_clear H19; Auto | Trivial] | Inversion_clear H16; Apply notin_proc_nu; Intros; Cut (notin_proc x2 (nu (x0 x1))); [Intro | Auto]; Inversion_clear H19; Auto | Trivial]; Auto | Inversion_clear H14; Apply notin_proc_nu; Intros; Cut (notin_proc x1 (nu (x0 n4))); [Intro | Auto]; Inversion_clear H16; Auto | Trivial | Assumption].

Rewrite <-H4 in H2; Cut P=([_:name]nil); [Intro | Apply proc_ext with z; Try (Apply notin_proc_nu; Intros; Apply notin_proc_nil); Auto].
Rewrite H6; Apply notin_proc_nu; Intros; Apply notin_proc_nil.

Rewrite <-H6 in H2; Elim (proc_exp P0 z); Elim (proc_exp Q z); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H2; Rewrite H12 in H2.
Cut P=([_:name](par (x1 _) (x0 _))); [Intro | Apply proc_ext with z; Try (Inversion_clear H8; Inversion_clear H10; Apply notin_proc_nu; Intros; Apply notin_proc_par); Auto].
Rewrite H9; Apply notin_proc_nu; Intros; Apply notin_proc_par.
Cut (notin_proc x (nu x1)); [Intro; Inversion_clear H14; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H7; Omega | Apply LNP_RW with (x1 z) z; [Rewrite <-H12; Assumption | Assumption | Trivial] | Assumption | Trivial | Rewrite H9 in H3; Inversion_clear H3; Assumption]].
Cut (notin_proc x (nu x0)); [Intro; Inversion_clear H14; Auto | Apply H with n2 (x0 z) z y; [Rewrite <-H7; Omega | Apply LNP_RW with (x0 z) z; [Rewrite <-H11; Assumption | Assumption | Trivial] | Assumption | Trivial | Rewrite H9 in H3; Inversion_clear H3; Assumption]].

Rewrite <-H5 in H2; Elim (proc_exp P0 z); Intros.
Inversion_clear H7; Rewrite H9 in H2.
Cut P=([_:name](bang (x0 _))); [Intro | Apply proc_ext with z; Try (Inversion_clear H8; Apply notin_proc_nu; Intros; Apply notin_proc_bang); Auto].
Rewrite H7; Apply notin_proc_nu; Intros; Apply notin_proc_bang.
Cut (notin_proc x (nu x0)); [Intro; Inversion_clear H11; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Apply LNP_RW with (x0 z) z; [Rewrite <-H9; Assumption | Assumption | Trivial] | Assumption | Trivial | Rewrite H7 in H3; Inversion_clear H3; Assumption]].

Rewrite <-H5 in H2; Elim (cap_exp M z); Elim (proc_exp P0 z); Intros.
Inversion_clear H7; Inversion_clear H8.
Rewrite H10 in H2; Rewrite H11 in H2.
Cut P=([_:name](ambient (x1 _) (x0 _))); [Intro | Apply proc_ext with z; Try (Unfold notin_ho_cap in H7; Inversion_clear H9; Apply notin_proc_nu; Intros; Apply notin_proc_amb); Auto].
Rewrite H8; Apply notin_proc_nu; Intros; Apply notin_proc_amb.
Rewrite H8 in H3; Inversion_clear H3; Cut (notin_ho_cap x x1); [Intro | Apply NOTIN_CAP_MONO with y; Auto].
Unfold notin_ho_cap in H3; Auto.
Cut (notin_proc x (nu x0)); [Intro; Inversion_clear H13; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Apply LNP_RW with (x0 z) z; [Rewrite <-H10; Assumption | Assumption | Trivial] | Assumption | Trivial | Rewrite H8 in H3; Inversion_clear H3; Assumption]].

Rewrite <-H5 in H2; Elim (cap_exp M z); Elim (proc_exp P0 z); Intros.
Inversion_clear H7; Inversion_clear H8.
Rewrite H10 in H2; Rewrite H11 in H2.
Cut P=([_:name](cap_act (x1 _) (x0 _))); [Intro | Apply proc_ext with z; Try (Unfold notin_ho_cap in H7; Inversion_clear H9; Apply notin_proc_nu; Intros; Apply notin_proc_act); Auto].
Rewrite H8; Apply notin_proc_nu; Intros; Apply notin_proc_act.
Rewrite H8 in H3; Inversion_clear H3; Cut (notin_ho_cap x x1); [Intro | Apply NOTIN_CAP_MONO with y; Auto].
Unfold notin_ho_cap in H3; Auto.
Cut (notin_proc x (nu x0)); [Intro; Inversion_clear H13; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Apply LNP_RW with (x0 z) z; [Rewrite <-H10; Assumption | Assumption | Trivial] | Assumption | Trivial | Rewrite H8 in H3; Inversion_clear H3; Assumption]].

Rewrite <-H5 in H2; Elim (ho_proc_exp P0 z); Intros.
Inversion_clear H7; Rewrite H9 in H2.
Cut P=([_:name](in_act (x0 _))); [Intro | Apply proc_ext with z; Try (Inversion_clear H8; Apply notin_proc_nu; Intros; Apply notin_proc_in; Intros; Cut (notin_proc z (nu (x0 n2))); [Intro | Auto]; Inversion_clear H11); Auto].
Rewrite H7; Apply notin_proc_nu; Intros; Apply notin_proc_in; Intros.
Rewrite H7 in H3; Inversion_clear H3.
Cut (notin_proc x (x0 y n3)); [Intro | Auto].
Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons n3 empty)); Intros.
Inversion_clear H13; Inversion_clear H15; Clear H16.
Cut (notin_proc x (nu [_:name](x0 _ n3))); [Intro; Inversion_clear H15; Auto | Idtac].
Apply H with n1 (x0 x1 n3) x1 y; [Rewrite <-H6; Unfold lt; Apply le_n | Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons x1 (cons z empty))); Intros; Inversion_clear H15; Inversion_clear H17; Inversion_clear H18; Clear H19; Apply LNP_RW with (x0 x1 x2) x2; [Change (lnp ([_:name](x0 _ x2) x1) n1); Apply LNP_RW with (x0 z x2) z; [Rewrite <-H9; Auto | Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc z (nu (x0 n4))); [Intro | Auto]; Inversion_clear H19; Auto | Trivial] | Inversion_clear H16; Apply notin_proc_nu; Intros; Cut (notin_proc x2 (nu (x0 x1))); [Intro | Auto]; Inversion_clear H19; Auto | Trivial]; Auto | Inversion_clear H14; Apply notin_proc_nu; Intros; Cut (notin_proc x1 (nu (x0 n4))); [Intro | Auto]; Inversion_clear H16; Auto | Trivial | Assumption].

Rewrite <-H4 in H2; Elim (cap_exp M z); Intros.
Inversion_clear H6; Rewrite H8 in H2.
Cut P=([_:name](out_act (x0 _))); [Intro | Apply proc_ext with z; Try (Unfold notin_ho_cap in H7; Apply notin_proc_nu; Intros; Apply notin_proc_out); Auto].
Rewrite H6; Apply notin_proc_nu; Intros; Apply notin_proc_out.
Cut (notin_ho_cap x x0); [Intro | Apply NOTIN_CAP_MONO with y; Rewrite H6 in H3; Inversion_clear H3; Auto].
Unfold notin_ho_cap in H10; Auto.

Qed.

Lemma NOTIN_PROC_MONO: (P:name->proc)(x,y:name)(notin_proc x (P y))->(notin_proc x (nu P)).

Proof.

Intros.
Elim (UNSAT_PROC_NLIST (nu P) empty); Intros.
Inversion_clear H0; Clear H2.
Elim (LNP_TOT (P x0)); Intros.
Apply PRE_NOTIN_PROC_MONO with x1 (P x0) x0 y; Auto.

Qed.

Lemma PRE_ISIN_CAP_MONO: (A:cap)(M:name->cap)(z:name)(notin_ho_cap z M) -> A=(M z) -> (x,y:name)~x=y -> (isin_cap x (M y)) -> (isin_ho_cap x M).

Proof.

Induction A; Intros.

Elim (dec_name n z); Intros.
Rewrite H3 in H0; Cut M=name2cap; [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Rewrite H4; Rewrite H4 in H2; Inversion H2; Unfold isin_ho_cap; Intros; Absurd x=y; Assumption.
Cut M=([_:name](name2cap n)); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Rewrite H4; Rewrite H4 in H2; Inversion H2; Unfold isin_ho_cap; Intros; Apply isin_cap_name.

Elim (cap_exp c z); Intros.
Inversion_clear H4; Rewrite H6 in H1.
Cut M=([_:name](in_cap (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H5; Unfold notin_ho_cap; Intros; Apply notin_cap_in); Auto].
Rewrite H4; Unfold isin_ho_cap; Intros; Apply isin_cap_in; Rewrite H4 in H3; Inversion_clear H3; Cut (isin_ho_cap x x0); [Intro; Unfold isin_ho_cap in H3 | Apply H with z y]; Auto.

Elim (cap_exp c z); Intros.
Inversion_clear H4; Rewrite H6 in H1.
Cut M=([_:name](out_cap (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H5; Unfold notin_ho_cap; Intros; Apply notin_cap_out); Auto].
Rewrite H4; Unfold isin_ho_cap; Intros; Apply isin_cap_out; Rewrite H4 in H3; Inversion_clear H3; Cut (isin_ho_cap x x0); [Intro; Unfold isin_ho_cap in H3 | Apply H with z y]; Auto.

Elim (cap_exp c z); Intros.
Inversion_clear H4; Rewrite H6 in H1.
Cut M=([_:name](open (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H5; Unfold notin_ho_cap; Intros; Apply notin_cap_open); Auto].
Rewrite H4; Unfold isin_ho_cap; Intros; Apply isin_cap_open; Rewrite H4 in H3; Inversion_clear H3; Cut (isin_ho_cap x x0); [Intro; Unfold isin_ho_cap in H3 | Apply H with z y]; Auto.

Cut M=([_:name]eps); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_eps); Auto].
Rewrite H3 in H2; Inversion_clear H2.

Elim (cap_exp c z); Elim(cap_exp c0 z); Intros.
Inversion_clear H5; Inversion_clear H6.
Rewrite H8 in H2; Rewrite H9 in H2.
Cut M=([_:name](path (x1 _) (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H5; Unfold notin_ho_cap in H7; Unfold notin_ho_cap; Intros; Apply notin_cap_path); Auto].
Rewrite H6; Unfold isin_ho_cap; Intros; Rewrite H6 in H4; Inversion_clear H4; Apply isin_cap_path; Inversion_clear H10; [Left; Cut (isin_ho_cap x x1); [Intro; Unfold isin_ho_cap in H10 | Apply H with z y] | Right; Cut (isin_ho_cap x x0); [Intro; Unfold isin_ho_cap in H10 | Apply H0 with z y]]; Auto.
 
Qed.

Lemma ISIN_CAP_MONO: (M:name->cap)(x,y:name)~x=y -> (isin_cap x (M y)) -> (isin_ho_cap x M).

Proof.

Intros.
Elim (UNSAT_PROC_NLIST (nu ([_:name](out_act (M _)))) empty); Intros.
Inversion_clear H1; Inversion_clear H2; Clear H3.
Apply PRE_ISIN_CAP_MONO with (M x0) x0 y; Auto.
Unfold notin_ho_cap; Intros.
Cut (notin_proc x0 (out_act (M m))); [Intro | Auto].
Inversion_clear H3; Assumption.

Qed.

Lemma PRE_ISIN_PROC_MONO: (n:nat)(A:proc)(lnp A n) -> (P:name->proc)(z:name)(notin_proc z (nu P)) -> A=(P z) -> (x,y:name)~x=y -> (isin_proc x (P y))->(isin_proc x (nu P)).

Proof.

Intro; Pattern n; Apply NAT_IND; Intros.

Cut (lt O (0)); [Intro | Apply LNP_S with A; Assumption].
Inversion_clear H4.

Inversion H0.

Rewrite <-H6 in H2; Elim (ho_proc_exp P0 z); Intros.
Inversion_clear H8; Rewrite H10 in H2.
Cut P=([_:name](nu (x0 _))); [Intro | Apply proc_ext with z; Auto].
Rewrite H8; Do 2 (Apply isin_proc_nu; Intro).
Rewrite H8 in H4; Inversion_clear H4.
Cut (isin_proc x (x0 y n3)); [Intro | Auto].
Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons n3 empty)); Intros.
Inversion_clear H12; Inversion_clear H14; Clear H15.
Cut (isin_proc x (nu [_:name](x0 _ n3))); [Intro; Inversion_clear H14; Auto | Idtac].
Apply H with n1 (x0 x1 n3) x1 y; [Rewrite <-H7; Unfold lt; Apply le_n | Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons x1 (cons z empty))); Intros; Inversion_clear H14; Inversion_clear H16; Inversion_clear H17; Clear H18; Apply LNP_RW with (x0 x1 x2) x2; [Change (lnp ([_:name](x0 _ x2) x1) n1); Apply LNP_RW with (x0 z x2) z; [Rewrite <-H10; Auto | Inversion_clear H9; Apply notin_proc_nu; Intros; Cut (notin_proc z (nu (x0 n4))); [Intro | Auto]; Inversion_clear H18; Auto | Trivial] | Inversion_clear H15; Apply notin_proc_nu; Intros; Cut (notin_proc x2 (nu (x0 x1))); [Intro | Auto]; Inversion_clear H18; Auto | Trivial]; Auto | Inversion_clear H13; Apply notin_proc_nu; Intros; Cut (notin_proc x1 (nu (x0 n4))); [Intro | Auto]; Inversion_clear H15; Auto | Trivial | Assumption | Assumption].

Rewrite <-H5 in H2; Cut P=([_:name]nil); [Intro | Apply proc_ext with z; Try (Apply notin_proc_nu; Intros; Apply notin_proc_nil); Auto].
Rewrite H7 in H4; Inversion_clear H4.

Rewrite <-H7 in H2; Elim (proc_exp P0 z); Elim (proc_exp Q z); Intros.
Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H2; Rewrite H13 in H2.
Cut P=([_:name](par (x1 _) (x0 _))); [Intro | Apply proc_ext with z; Try (Inversion_clear H9; Inversion_clear H11; Apply notin_proc_nu; Intros; Apply notin_proc_par); Auto].
Rewrite H10; Rewrite H10 in H4; Apply isin_proc_nu; Intro; Apply isin_proc_par; Inversion_clear H4; Inversion_clear H14; [Left | Right].
Cut (isin_proc x (nu x1)); [Intro; Inversion_clear H14; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H8; Omega | Apply LNP_RW with (x1 z) z; [Rewrite <-H13; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Assumption]].
Cut (isin_proc x (nu x0)); [Intro; Inversion_clear H14; Auto | Apply H with n2 (x0 z) z y; [Rewrite <-H8; Omega | Apply LNP_RW with (x0 z) z; [Rewrite <-H12; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Assumption]].

Rewrite <-H6 in H2; Elim (proc_exp P0 z); Intros.
Inversion_clear H8; Rewrite H10 in H2.
Cut P=([_:name](bang (x0 _))); [Intro | Apply proc_ext with z; Try (Inversion_clear H9; Apply notin_proc_nu; Intros; Apply notin_proc_bang); Auto].
Rewrite H8; Apply isin_proc_nu; Intros; Apply isin_proc_bang.
Cut (isin_proc x (nu x0)); [Intro; Inversion_clear H11; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Apply LNP_RW with (x0 z) z; [Rewrite <-H10; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Rewrite H8 in H4; Inversion_clear H4; Assumption]].

Rewrite <-H6 in H2; Elim (cap_exp M z); Elim (proc_exp P0 z); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H2; Rewrite H12 in H2.
Cut P=([_:name](ambient (x1 _) (x0 _))); [Intro | Apply proc_ext with z; Try (Unfold notin_ho_cap in H8; Inversion_clear H10; Apply notin_proc_nu; Intros; Apply notin_proc_amb); Auto].
Rewrite H9; Apply isin_proc_nu; Intro; Apply isin_proc_amb; Rewrite H9 in H4; Inversion_clear H4; Inversion_clear H13; [Left | Right].
Cut (isin_ho_cap x x1); [Intro; Unfold isin_ho_cap in H13; Auto | Apply ISIN_CAP_MONO with y; Auto].
Cut (isin_proc x (nu x0)); [Intro; Inversion_clear H13; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Apply LNP_RW with (x0 z) z; [Rewrite <-H11; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Assumption]].

Rewrite <-H6 in H2; Elim (cap_exp M z); Elim (proc_exp P0 z); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H2; Rewrite H12 in H2.
Cut P=([_:name](cap_act (x1 _) (x0 _))); [Intro | Apply proc_ext with z; Try (Unfold notin_ho_cap in H8; Inversion_clear H10; Apply notin_proc_nu; Intros; Apply notin_proc_act); Auto].
Rewrite H9; Apply isin_proc_nu; Intro; Apply isin_proc_act; Rewrite H9 in H4; Inversion_clear H4; Inversion_clear H13; [Left | Right].
Cut (isin_ho_cap x x1); [Intro; Unfold isin_ho_cap in H13; Auto | Apply ISIN_CAP_MONO with y; Auto].
Cut (isin_proc x (nu x0)); [Intro; Inversion_clear H13; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Apply LNP_RW with (x0 z) z; [Rewrite <-H11; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Assumption]].

Rewrite <-H6 in H2; Elim (ho_proc_exp P0 z); Intros.
Inversion_clear H8; Rewrite H10 in H2.
Cut P=([_:name](in_act (x0 _))); [Intro | Apply proc_ext with z; Try (Inversion_clear H9; Apply notin_proc_nu; Intros; Apply notin_proc_in; Intros; Cut (notin_proc z (nu (x0 n2))); [Intro | Auto]; Inversion_clear H12); Auto].
Rewrite H8; Apply isin_proc_nu; Intro; Apply isin_proc_in; Intro.
Rewrite H8 in H4; Inversion_clear H4.
Cut (isin_proc x (x0 y n3)); [Intro | Auto].
Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons n3 empty)); Intros.
Inversion_clear H12; Inversion_clear H14; Clear H15.
Cut (isin_proc x (nu [_:name](x0 _ n3))); [Intro; Inversion_clear H14; Auto | Idtac].
Apply H with n1 (x0 x1 n3) x1 y; [Rewrite <-H7; Unfold lt; Apply le_n | Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons x1 (cons z empty))); Intros; Inversion_clear H14; Inversion_clear H16; Inversion_clear H17; Clear H18; Apply LNP_RW with (x0 x1 x2) x2; [Change (lnp ([_:name](x0 _ x2) x1) n1); Apply LNP_RW with (x0 z x2) z; [Rewrite <-H10; Auto | Inversion_clear H9; Apply notin_proc_nu; Intros; Cut (notin_proc z (nu (x0 n4))); [Intro | Auto]; Inversion_clear H18; Auto | Trivial] | Inversion_clear H15; Apply notin_proc_nu; Intros; Cut (notin_proc x2 (nu (x0 x1))); [Intro | Auto]; Inversion_clear H18; Auto | Trivial]; Auto | Inversion_clear H13; Apply notin_proc_nu; Intros; Cut (notin_proc x1 (nu (x0 n4))); [Intro | Auto]; Inversion_clear H15; Auto | Trivial | Assumption | Assumption].

Rewrite <-H5 in H2; Elim (cap_exp M z); Intros.
Inversion_clear H7; Rewrite H9 in H2.
Cut P=([_:name](out_act (x0 _))); [Intro | Apply proc_ext with z; Try (Unfold notin_ho_cap in H8; Apply notin_proc_nu; Intros; Apply notin_proc_out); Auto].
Rewrite H7; Apply isin_proc_nu; Intro; Apply isin_proc_out.
Cut (isin_ho_cap x x0); [Intro | Apply ISIN_CAP_MONO with y; [Assumption | Rewrite H7 in H4; Inversion_clear H4; Auto]].
Unfold notin_ho_cap in H10; Auto.

Qed.

Lemma ISIN_PROC_MONO: (P:name->proc)(x,y:name)~x=y -> (isin_proc x (P y)) -> (isin_proc x (nu P)).

Proof.

Intros.
Elim (UNSAT_PROC_NLIST (nu P) empty); Intros.
Inversion_clear H1; Clear H3.
Elim (LNP_TOT (P x0)); Intros.
Apply PRE_ISIN_PROC_MONO with x1 (P x0) x0 y; Auto.

Qed.

Lemma NOTIN_CAP_DEC: (M:cap)(x:name)(isin_cap x M) \/ (notin_cap x M).

Proof.

Induction M; Intros.

Elim (dec_name n x); Intros; [Rewrite H; Left; Apply isin_cap_name | Right; Apply notin_cap_name; Auto].

Elim (H x); Intros; [Left; Apply isin_cap_in | Right; Apply notin_cap_in]; Assumption.

Elim (H x); Intros; [Left; Apply isin_cap_out | Right; Apply notin_cap_out]; Assumption.

Elim (H x); Intros; [Left; Apply isin_cap_open | Right; Apply notin_cap_open]; Assumption.

Right; Apply notin_cap_eps.

Elim (H x); Elim (H0 x); Intros.

Left; Apply isin_cap_path; Left; Assumption.
Left; Apply isin_cap_path; Left; Assumption.
Left; Apply isin_cap_path; Right; Assumption.
Right; Apply notin_cap_path; Assumption.

Qed.

Lemma NOTIN_PROC_DEC: (P:proc)(n:name)(isin_proc n P) \/ (notin_proc n P).

Proof.

Induction P; Intros.

Elim (UNSAT_PROC_NLIST nil (cons n empty)); Intros.
Inversion_clear H0; Clear H1; Inversion_clear H2; Clear H1.
Elim (H x n); Intros.
Left; Apply ISIN_PROC_MONO with x; Auto.
Right; Apply NOTIN_PROC_MONO with x; Assumption.

Right; Apply notin_proc_nil.

Elim (H n); Elim (H0 n); Intros.
Left; Apply isin_proc_par; Left; Assumption.
Left; Apply isin_proc_par; Left; Assumption.
Left; Apply isin_proc_par; Right; Assumption.
Right; Apply notin_proc_par; Assumption.

Elim (H n); Intros.
Left; Apply isin_proc_bang; Assumption.
Right; Apply notin_proc_bang; Assumption.

Elim (H n); Intros.
Left; Apply isin_proc_amb; Right; Assumption.
Elim (NOTIN_CAP_DEC c n); Intros.
Left; Apply isin_proc_amb; Left; Assumption.
Right; Apply notin_proc_amb; Assumption.

Elim (H n); Intros.
Left; Apply isin_proc_act; Right; Assumption.
Elim (NOTIN_CAP_DEC c n); Intros.
Left; Apply isin_proc_act; Left; Assumption.
Right; Apply notin_proc_act; Assumption.

Elim (UNSAT_PROC_NLIST nil (cons n empty)); Intros.
Inversion_clear H0; Clear H1; Inversion_clear H2; Clear H1.
Elim (H x n); Intros.
Left; Cut (isin_proc n (nu p)); [Intro; Inversion_clear H2; Apply isin_proc_in; Intro | Apply ISIN_PROC_MONO with x]; Auto.
Right; Cut (notin_proc n (nu p)); [Intro; Inversion_clear H2; Apply notin_proc_in; Intros | Apply NOTIN_PROC_MONO with x]; Auto.

Elim (NOTIN_CAP_DEC c n); Intros.
Left; Apply isin_proc_out; Assumption.
Right; Apply notin_proc_out; Assumption.

Qed.

Lemma NOTIN_CAP_CASE: (M:name->cap)(y:name)(notin_ho_cap y M) -> (x:name)(notin_cap x (M y)) -> ~x=y \/ (notin_cap x (M x)).

Proof.

Intros; Elim (dec_name x y); Intro; [Right; Rewrite H1; Rewrite H1 in H0 | Left]; Assumption.

Qed.

Lemma NOTIN_PROC_CASE: (P:name->proc)(y:name)(notin_proc y (nu P)) -> (x:name)(notin_proc x (P y)) -> ~x=y \/ (notin_proc x (P x)).

Proof.

Intros; Elim (dec_name x y); Intro; [Right; Rewrite H1; Rewrite H1 in H0 | Left]; Assumption.

Qed.

Lemma STRUCT_NOTIN: (A,B:proc)(struct_eq A B) -> (x:name)((notin_proc x A) -> (notin_proc x B)) /\ ((notin_proc x B) -> (notin_proc x A)).

Proof.

Induction 1; Intros.

Split; Intro; Assumption.

Cut ((notin_proc x P)->(notin_proc x Q)) /\ ((notin_proc x Q)->(notin_proc x P)); [Intro; Inversion_clear H2; Split; Intro; Auto | Apply H1].

Cut ((notin_proc x P)->(notin_proc x Q)) /\ ((notin_proc x Q)->(notin_proc x P)); [Intro | Apply H1].
Cut ((notin_proc x Q)->(notin_proc x R)) /\ ((notin_proc x R)->(notin_proc x Q)); [Intro | Apply H3].
Inversion_clear H4; Inversion_clear H5; Split; Intro; Auto.

Elim (UNSAT_PROC_NLIST (par (nu P) (par (nu Q) (out_act (name2cap x)))) l); Intros.
Inversion_clear H2; Inversion_clear H3; Inversion_clear H5; Inversion_clear H6; Inversion_clear H5.
Cut ((notin_proc x (P x0))->(notin_proc x (Q x0))) /\ ((notin_proc x (Q x0))->(notin_proc x (P x0))); [Intro | Apply H1; Auto].
Split; Intro.
Inversion_clear H5; Inversion_clear H7; Apply NOTIN_PROC_MONO with x0; Auto.
Inversion_clear H5; Inversion_clear H7; Apply NOTIN_PROC_MONO with x0; Auto.

Cut ((notin_proc x P)->(notin_proc x Q)) /\ ((notin_proc x Q)->(notin_proc x P)); [Intro | Auto]; Split; Intro.
Inversion_clear H2; Inversion_clear H3; Cut (notin_proc x Q); [Intro | Auto]; Apply notin_proc_par; Assumption.
Inversion_clear H2; Inversion_clear H3; Cut (notin_proc x P); [Intro | Auto]; Apply notin_proc_par; Assumption.

Cut ((notin_proc x P)->(notin_proc x Q)) /\ ((notin_proc x Q)->(notin_proc x P)); [Intro | Auto]; Split; Intro.
Inversion_clear H2; Inversion_clear H3; Cut (notin_proc x Q); [Intro | Auto]; Apply notin_proc_bang; Assumption.
Inversion_clear H2; Inversion_clear H3; Cut (notin_proc x P); [Intro | Auto]; Apply notin_proc_bang; Assumption.

Cut ((notin_proc x P)->(notin_proc x Q)) /\ ((notin_proc x Q)->(notin_proc x P)); [Intro | Auto]; Split; Intro.
Inversion_clear H2; Inversion_clear H3; Cut (notin_proc x Q); [Intro | Auto]; Apply notin_proc_amb; Assumption.
Inversion_clear H2; Inversion_clear H3; Cut (notin_proc x P); [Intro | Auto]; Apply notin_proc_amb; Assumption.

Cut ((notin_proc x P)->(notin_proc x Q)) /\ ((notin_proc x Q)->(notin_proc x P)); [Intro | Auto]; Split; Intro.
Inversion_clear H2; Inversion_clear H3; Cut (notin_proc x Q); [Intro | Auto]; Apply notin_proc_act; Assumption.
Inversion_clear H2; Inversion_clear H3; Cut (notin_proc x P); [Intro | Auto]; Apply notin_proc_act; Assumption.

Elim (UNSAT_PROC_NLIST (par (nu P) (par (nu Q) (out_act (name2cap x)))) l); Intros.
Inversion_clear H2; Inversion_clear H3; Inversion_clear H5; Inversion_clear H6; Inversion_clear H5.
Cut ((notin_proc x (P x0))->(notin_proc x (Q x0))) /\ ((notin_proc x (Q x0))->(notin_proc x (P x0))); [Intro | Apply H1; Auto].
Split; Intro.
Inversion_clear H5; Inversion_clear H7; Cut (notin_proc x (nu Q)); [Intro | Apply NOTIN_PROC_MONO with x0; Auto].
Apply notin_proc_in; Intros; Inversion_clear H7; Auto.
Inversion_clear H5; Inversion_clear H7; Cut (notin_proc x (nu P)); [Intro | Apply NOTIN_PROC_MONO with x0; Auto].
Apply notin_proc_in; Intros; Inversion_clear H7; Auto.

Split; Intro; [Inversion_clear H0; Assumption | Apply notin_proc_act; [Apply notin_cap_eps | Assumption]].

Split; Intro.
Inversion_clear H0; Inversion_clear H1; Apply notin_proc_act; [Idtac | Apply notin_proc_act]; Assumption.
Inversion_clear H0; Inversion_clear H2; Apply notin_proc_act; [Apply notin_cap_path | Idtac]; Assumption.

Split; Intro.
Inversion_clear H0; Do 2 (Apply notin_proc_nu; Intros).
Cut (notin_proc x (nu [m:name](P n0 m))); [Intro | Auto].
Inversion_clear H3; Auto.
Inversion_clear H0; Do 2 (Apply notin_proc_nu; Intros).
Cut (notin_proc x (nu [m:name](P m n0))); [Intro | Auto].
Inversion_clear H3; Auto.

Split; Intro; [Idtac | Apply notin_proc_nu; Intros]; Apply notin_proc_nil.

Split; Intro.
Inversion_clear H0; Apply notin_proc_par.
Elim (UNSAT_PROC_NLIST (out_act (name2cap x)) empty); Intros.
Inversion_clear H0; Clear H3; Inversion_clear H2; Inversion_clear H0.
Cut (notin_proc x (par P (Q x0))); [Intro | Auto].
Inversion_clear H0; Assumption.
Apply notin_proc_nu; Intros.
Cut (notin_proc x (par P (Q n))); [Intro | Auto].
Inversion_clear H2; Assumption.
Inversion_clear H0; Inversion_clear H2; Apply notin_proc_nu; Intros; Apply notin_proc_par; Auto.

Split; Intro.
Inversion_clear H0; Apply notin_proc_amb.
Elim (UNSAT_PROC_NLIST (out_act (name2cap x)) empty); Intros.
Inversion_clear H0; Clear H3; Inversion_clear H2; Inversion_clear H0.
Cut (notin_proc x (ambient (name2cap m) (P x0))); [Intro | Auto].
Inversion_clear H0; Assumption.
Apply notin_proc_nu; Intros.
Cut (notin_proc x (ambient (name2cap m) (P n))); [Intro | Auto].
Inversion_clear H2; Assumption.
Inversion_clear H0; Apply notin_proc_nu; Intros; Inversion_clear H2; Apply notin_proc_amb; Auto.

Split; Intro; [Inversion_clear H0; Assumption | Apply notin_proc_par; [Assumption | Apply notin_proc_nil]].

Split; Intro; Inversion_clear H0; Apply notin_proc_par; Assumption.

Split; Intro.
Inversion_clear H0; Inversion_clear H1.
Apply notin_proc_par; [Assumption | Apply notin_proc_par; Assumption].
Inversion_clear H0; Inversion_clear H2.
Apply notin_proc_par; [Apply notin_proc_par; Assumption | Assumption].

Split; Intro; [Apply notin_proc_nil | Apply notin_proc_bang; Apply notin_proc_nil].

Split; Intro.
Inversion_clear H0; Inversion_clear H1.
Apply notin_proc_par; Apply notin_proc_bang; Assumption.
Inversion_clear H0; Inversion_clear H1; Inversion_clear H2.
Apply notin_proc_bang; Apply notin_proc_par; Assumption.

Split; Intro.
Inversion_clear H0; Apply notin_proc_par; [Idtac | Apply notin_proc_bang]; Assumption.
Inversion_clear H0; Assumption.

Split; Intro; [Apply notin_proc_bang; Assumption | Inversion_clear H0; Assumption].

Qed.

Lemma STRUCT_ISIN: (A,B:proc)(struct_eq A B) -> (x:name)((isin_proc x A) -> (isin_proc x B)) /\ ((isin_proc x B) -> (isin_proc x A)).

Proof.

Intros; Split; Intro.

Elim (NOTIN_PROC_DEC B x); Intros; [Assumption | Elim (STRUCT_NOTIN A B H x); Intros; Cut (notin_proc x A); [Intro | Auto]; Absurd x=x; [Apply SEP_PROC with A; Assumption | Trivial]].

Elim (NOTIN_PROC_DEC A x); Intros; [Assumption | Elim (STRUCT_NOTIN A B H x); Intros; Cut (notin_proc x B); [Intro | Auto]; Absurd x=x; [Apply SEP_PROC with B; Assumption | Trivial]].

Qed.

Lemma PRE_STRUCT_RW: (A,B:proc)(struct_eq A B) ->
                     (P,Q:name->proc)(x:name)
                     (notin_proc x (nu P)) -> (notin_proc x (nu Q)) ->
                     A=(P x) -> B=(Q x) ->
                     (y:name)~x=y ->
                     (notin_proc y (nu P)) -> (notin_proc y (nu Q)) ->
                     (struct_eq (P y) (Q y)).

Proof.

Do 3 Intro; Generalize H; Pattern A B; Apply struct_eq_ind; Intros; Auto.

Cut P0=Q; [Intro; Rewrite H8; Apply struct_refl | Rewrite H4 in H3; Apply proc_ext with x; Auto].

Apply struct_symm; Apply H1 with x; Auto.

Elim (proc_exp Q x); Intros.
Inversion_clear H12; Cut (z:name)((notin_proc z P) -> (notin_proc z Q)) /\ ((notin_proc z Q) -> (notin_proc z P)); [Intro | Intro; Apply STRUCT_NOTIN; Assumption].
Cut (notin_proc y P); [Intro | Rewrite H7; Inversion_clear H10; Auto].
Cut ((notin_proc y P)->(notin_proc y Q)) /\ ((notin_proc y Q)->(notin_proc y P)); [Intro | Auto].
Inversion_clear H16; Cut (notin_proc y Q); [Intro | Auto].
Rewrite H14 in H16; Cut (notin_proc y (nu x0)); [Intro | Apply NOTIN_PROC_MONO with x; Assumption].
Apply struct_trans with (x0 y); [Apply H1 with x | Apply H3 with x]; Auto.

Elim (ho_proc_exp P x); Elim (ho_proc_exp Q x); Intros.
Inversion_clear H10; Inversion_clear H11.
Rewrite H13 in H6; Rewrite H14 in H5.
Cut Q0=([_:name](nu (x0 _))); [Intro | Apply proc_ext with x; Auto].
Cut P0=([_:name](nu (x1 _))); [Intro | Apply proc_ext with x; Auto].
Rewrite H11; Rewrite H15.
Apply struct_res with (cons x (cons y l)); Intros.
Inversion_clear H16; Inversion_clear H20; Change (struct_eq ([_:name](x1 _ n) y) ([_:name](x0 _ n) y)); Apply H1 with n x; Auto.
Rewrite H14; Apply notin_proc_nu; Intros.
Cut (notin_proc n (nu [_:name](nu (x1 _)))); [Intro | Apply NOTIN_PROC_MONO with y; Assumption].
Inversion_clear H22; Cut (notin_proc n (nu (x1 x))); [Intro | Auto].
Inversion_clear H22; Auto.
Rewrite H13; Apply notin_proc_nu; Intros.
Cut (notin_proc n (nu [_:name](nu (x0 _)))); [Intro | Apply NOTIN_PROC_MONO with y; Assumption].
Inversion_clear H22; Cut (notin_proc n (nu (x0 x))); [Intro | Auto].
Inversion_clear H22; Auto.
Apply H0; Auto.
Rewrite H14; Apply notin_proc_nu; Intros.
Cut (notin_proc n (nu [_:name](nu (x1 _)))); [Intro | Apply NOTIN_PROC_MONO with y; Assumption].
Inversion_clear H22; Cut (notin_proc n (nu (x1 x))); [Intro | Auto].
Inversion_clear H22; Auto.
Rewrite H13; Apply notin_proc_nu; Intros.
Cut (notin_proc n (nu [_:name](nu (x0 _)))); [Intro | Apply NOTIN_PROC_MONO with y; Assumption].
Inversion_clear H22; Cut (notin_proc n (nu (x0 x))); [Intro | Auto].
Inversion_clear H22; Auto.
Inversion_clear H10; Apply notin_proc_nu; Intros.
Cut (notin_proc x (nu (x1 n0))); [Intro | Auto].
Inversion_clear H22; Auto.
Inversion_clear H12; Apply notin_proc_nu; Intros.
Cut (notin_proc x (nu (x0 n0))); [Intro | Auto].
Inversion_clear H22; Auto.
Rewrite H14; Trivial.
Rewrite H13; Trivial.
Rewrite H15 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros.
Cut (notin_proc y (nu (x1 n0))); [Intro | Auto].
Inversion_clear H22; Auto.
Rewrite H11 in H9; Inversion_clear H9; Apply notin_proc_nu; Intros.
Cut (notin_proc y (nu (x0 n0))); [Intro | Auto].
Inversion_clear H22; Auto.

Elim (proc_exp P x); Elim (proc_exp Q x); Elim (proc_exp R x); Intros.
Inversion_clear H10; Inversion_clear H11; Inversion_clear H12.
Rewrite H14 in H5; Rewrite H14 in H6; Rewrite H15 in H6; Rewrite H16 in H5.
Cut Q0=([_:name](par (x1 _) (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H13; Inversion_clear H10; Apply notin_proc_par); Auto].
Cut P0=([_:name](par (x2 _) (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H13; Inversion_clear H11; Apply notin_proc_par); Auto].
Rewrite H12; Rewrite H17; Apply struct_par; Apply H1 with x; Auto.
Rewrite H17 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros.
Cut (notin_proc y (par (x2 n) (x0 n))); [Intro | Auto].
Inversion_clear H19; Auto.
Rewrite H12 in H9; Inversion_clear H9; Apply notin_proc_nu; Intros.
Cut (notin_proc y (par (x1 n) (x0 n))); [Intro | Auto].
Inversion_clear H19; Auto.

Elim (proc_exp P x); Elim (proc_exp Q x); Intros.
Inversion_clear H10; Inversion_clear H11.
Rewrite H13 in H6; Rewrite H14 in H5.
Cut Q0=([_:name](bang (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H12; Apply notin_proc_bang); Auto].
Cut P0=([_:name](bang (x1 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H10; Apply notin_proc_bang); Auto].
Rewrite H11; Rewrite H15; Apply struct_repl; Apply H1 with x; Auto.
Rewrite H15 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros.
Cut (notin_proc y (bang (x1 n))); [Intro | Auto].
Inversion_clear H17; Auto.
Rewrite H11 in H9; Inversion_clear H9; Apply notin_proc_nu; Intros.
Cut (notin_proc y (bang (x0 n))); [Intro | Auto].
Inversion_clear H17; Auto.

Elim (proc_exp P x); Elim (proc_exp Q x); Intros.
Inversion_clear H10; Inversion_clear H11.
Rewrite H13 in H6; Rewrite H14 in H5.
Elim (dec_name n x); Intros.
Rewrite H11 in H5; Rewrite H11 in H6;
Cut Q0=([_:name](ambient (name2cap _) (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H12; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Cut P0=([_:name](ambient (name2cap _) (x1 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H10; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Rewrite H15; Rewrite H16; Apply struct_amb; Apply H1 with x; Auto.
Rewrite H16 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros.
Cut (notin_proc y (ambient (name2cap n0) (x1 n0))); [Intro | Auto].
Inversion_clear H18; Auto.
Rewrite H15 in H9; Inversion_clear H9; Apply notin_proc_nu; Intros.
Cut (notin_proc y (ambient (name2cap n0) (x0 n0))); [Intro | Auto].
Inversion_clear H18; Auto.
Cut Q0=([_:name](ambient (name2cap n) (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H12; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Cut P0=([_:name](ambient (name2cap n) (x1 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H10; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Rewrite H15; Rewrite H16; Apply struct_amb; Apply H1 with x; Auto.
Rewrite H16 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros.
Cut (notin_proc y (ambient (name2cap n) (x1 n0))); [Intro | Auto].
Inversion_clear H18; Auto.
Rewrite H15 in H9; Inversion_clear H9; Apply notin_proc_nu; Intros.
Cut (notin_proc y (ambient (name2cap n) (x0 n0))); [Intro | Auto].
Inversion_clear H18; Auto.

Elim (cap_exp M x); Elim (proc_exp P x); Elim (proc_exp Q x); Intros.
Inversion_clear H10; Inversion_clear H11; Inversion_clear H12.
Rewrite H14 in H6; Rewrite H15 in H5; Rewrite H16 in H5; Rewrite H16 in H6.
Cut Q0=([_:name](cap_act (x2 _) (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Unfold notin_ho_cap in H11; Inversion_clear H13; Apply notin_proc_act); Auto].
Cut P0=([_:name](cap_act (x2 _) (x1 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Unfold notin_ho_cap in H11; Inversion_clear H10; Apply notin_proc_act); Auto].
Rewrite H12; Rewrite H17; Apply struct_action; Apply H1 with x; Auto.
Rewrite H17 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros.
Cut (notin_proc y (cap_act (x2 n) (x1 n))); [Intro | Auto].
Inversion_clear H19; Auto.
Rewrite H12 in H9; Inversion_clear H9; Apply notin_proc_nu; Intros.
Cut (notin_proc y (cap_act (x2 n) (x0 n))); [Intro | Auto].
Inversion_clear H19; Auto.

Elim (ho_proc_exp P x); Elim (ho_proc_exp Q x); Intros.
Inversion_clear H10; Inversion_clear H11.
Rewrite H13 in H6; Rewrite H14 in H5.
Cut Q0=([_:name](in_act (x0 _))); [Intro | Apply proc_ext with x; Auto].
Cut P0=([_:name](in_act (x1 _))); [Intro | Apply proc_ext with x; Auto].
Rewrite H11; Rewrite H15.
Apply struct_input with (cons x (cons y l)); Intros.
Inversion_clear H16; Inversion_clear H20; Change (struct_eq ([_:name](x1 _ n) y) ([_:name](x0 _ n) y)); Apply H1 with n x; Auto.
Rewrite H14; Apply notin_proc_nu; Intros.
Cut (notin_proc n (nu [_:name](nu (x1 _)))); [Intro | Apply NOTIN_PROC_MONO with y; Assumption].
Inversion_clear H22; Cut (notin_proc n (nu (x1 x))); [Intro | Auto].
Inversion_clear H22; Auto.
Rewrite H13; Apply notin_proc_nu; Intros.
Cut (notin_proc n (nu [_:name](nu (x0 _)))); [Intro | Apply NOTIN_PROC_MONO with y; Assumption].
Inversion_clear H22; Cut (notin_proc n (nu (x0 x))); [Intro | Auto].
Inversion_clear H22; Auto.
Apply H0; Auto.
Rewrite H14; Apply notin_proc_nu; Intros.
Cut (notin_proc n (nu [_:name](nu (x1 _)))); [Intro | Apply NOTIN_PROC_MONO with y; Assumption].
Inversion_clear H22; Cut (notin_proc n (nu (x1 x))); [Intro | Auto].
Inversion_clear H22; Auto.
Rewrite H13; Apply notin_proc_nu; Intros.
Cut (notin_proc n (nu [_:name](nu (x0 _)))); [Intro | Apply NOTIN_PROC_MONO with y; Assumption].
Inversion_clear H22; Cut (notin_proc n (nu (x0 x))); [Intro | Auto].
Inversion_clear H22; Auto.
Inversion_clear H10; Apply notin_proc_nu; Intros.
Cut (notin_proc x (nu (x1 n0))); [Intro | Auto].
Inversion_clear H22; Auto.
Inversion_clear H12; Apply notin_proc_nu; Intros.
Cut (notin_proc x (nu (x0 n0))); [Intro | Auto].
Inversion_clear H22; Auto.
Rewrite H14; Trivial.
Rewrite H13; Trivial.
Rewrite H15 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros.
Cut (notin_proc y (in_act (x1 n0))); [Intro | Auto].
Inversion_clear H22; Auto.
Rewrite H11 in H9; Inversion_clear H9; Apply notin_proc_nu; Intros.
Cut (notin_proc y (in_act (x0 n0))); [Intro | Auto].
Inversion_clear H22; Auto.
Apply notin_proc_nu; Intros; Apply notin_proc_in; Intros; Inversion_clear H10.
Cut (notin_proc x (nu (x1 n))); [Intro | Auto].
Inversion_clear H10; Auto.
Apply notin_proc_nu; Intros; Apply notin_proc_in; Intros; Inversion_clear H12.
Cut (notin_proc x (nu (x0 n))); [Intro | Auto].
Inversion_clear H12; Auto.

Elim (proc_exp P x); Intros.
Inversion_clear H8.
Rewrite H10 in H3; Cut P0=([_:name](cap_act eps (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H9; Apply notin_proc_act; [Apply notin_cap_eps | Idtac]); Auto].
Rewrite H10 in H4; Cut Q=x0; [Intro | Apply proc_ext with x; Auto].
Rewrite H8; Rewrite H11; Apply struct_epsilon.

Elim (cap_exp M x); Elim (cap_exp M' x); Elim (proc_exp P x); Intros.
Inversion_clear H8; Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H3; Rewrite H12 in H4; Rewrite H13 in H3; Rewrite H13 in H4; Rewrite H14 in H3; Rewrite H14 in H4.
Cut P0=([_:name](cap_act (path (x2 _) (x1 _)) (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H11; Unfold notin_ho_cap in H8; Unfold notin_ho_cap in H9; Apply notin_proc_act; [Apply notin_cap_path | Idtac]); Auto].
Cut Q=([_:name](cap_act (x2 _) (cap_act (x1 _) (x0 _)))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H11; Unfold notin_ho_cap in H8; Unfold notin_ho_cap in H9; Apply notin_proc_act; [Idtac | Apply notin_proc_act]); Auto].
Rewrite H10; Rewrite H15; Apply struct_path.

Elim (ho2_proc_exp P x); Intros.
Inversion_clear H8.
Rewrite H10 in H3; Rewrite H10 in H4.
Cut P0=([_:name](nu [n:name](nu [m:name](x0 _ n m)))); [Intro | Apply proc_ext with x; Auto; Try (Do 3 (Apply notin_proc_nu; Intros); Inversion_clear H9)].
Cut Q=([_:name](nu [n:name](nu [m:name](x0 _ m n)))); [Intro | Apply proc_ext with x; Auto; Try (Do 3 (Apply notin_proc_nu; Intros); Inversion_clear H9)].
Rewrite H8; Rewrite H11; Apply struct_res_res.
Cut (notin_proc x (nu [v:name](nu (x0 n v)))); [Intro | Auto]. Inversion_clear H9; Cut (notin_proc x (nu (x0 n n1))); [Intro | Auto]; Inversion_clear H9; Auto.
Cut (notin_proc x (nu [v:name](nu (x0 n v)))); [Intro | Auto]; Inversion_clear H9; Cut (notin_proc x (nu (x0 n n0))); [Intro | Auto]; Inversion_clear H9; Auto.

Cut P=([_:name](nu [u:name]nil)); [Intro | Apply proc_ext with x; Try (Do 2 (Apply notin_proc_nu; Intros); Apply notin_proc_nil); Auto].
Cut Q=([_:name]nil); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Apply notin_proc_nil); Auto].
Rewrite H8; Rewrite H9; Apply struct_res_zero.

Elim (proc_exp P x); Elim (ho_proc_exp Q x); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H3; Rewrite H12 in H3; Rewrite H11 in H4; Rewrite H12 in H4.
Cut P0=([_:name](nu [n:name](par (x1 _) (x0 _ n)))); [Intro | Apply proc_ext with x; Try (Do 2 (Apply notin_proc_nu; Intros); Inversion_clear H10; Inversion_clear H8; Cut (notin_proc x (nu (x0 n))); [Intro | Auto]; Inversion_clear H8; Apply notin_proc_par); Auto].
Cut Q0=([_:name](par (x1 _) (nu (x0 _)))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H10; Inversion_clear H8; Cut (notin_proc x (nu (x0 n))); [Intro | Auto]; Inversion_clear H8; Apply notin_proc_par; [Idtac | Apply notin_proc_nu; Intros]); Auto].
Rewrite H9; Rewrite H13; Apply struct_res_par.

Elim (ho_proc_exp P x); Intros; Elim (dec_name m x); Intros.
Inversion_clear H8; Rewrite H9 in H3; Rewrite H9 in H4.
Rewrite H11 in H3; Rewrite H11 in H4.
Cut P0=([_:name](nu [n:name](ambient (name2cap _) (x0 _ n)))); [Intro | Apply proc_ext with x; Try (Do 2 (Apply notin_proc_nu; Intros); Inversion_clear H10; Cut (notin_proc x (nu (x0 n))); [Intro | Auto]; Inversion_clear H10; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Cut Q=([_:name](ambient (name2cap _) (nu (x0 _)))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H10; Cut (notin_proc x (nu (x0 n))); [Intro | Auto]; Inversion_clear H10; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Rewrite H8; Rewrite H12; Apply struct_res_amb.
Inversion_clear H8.
Rewrite H11 in H3; Rewrite H11 in H4.
Cut P0=([_:name](nu [n:name](ambient (name2cap m) (x0 _ n)))); [Intro | Apply proc_ext with x; Try (Do 2 (Apply notin_proc_nu; Intros); Inversion_clear H10; Cut (notin_proc x (nu (x0 n))); [Intro | Auto]; Inversion_clear H10; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Cut Q=([_:name](ambient (name2cap m) (nu (x0 _)))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H10; Cut (notin_proc x (nu (x0 n))); [Intro | Auto]; Inversion_clear H10; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Rewrite H8; Rewrite H12; Apply struct_res_amb.

Elim (proc_exp P x); Intros.
Inversion_clear H8.
Rewrite H10 in H3; Rewrite H10 in H4.
Cut P0=([_:name](par (x0 _) nil)); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H9; Apply notin_proc_par; [Idtac | Apply notin_proc_nil]); Auto].
Cut Q=x0; [Intro | Apply proc_ext with x; Auto].
Rewrite H8; Rewrite H11; Apply struct_par_zero.

Elim (proc_exp P x); Elim (proc_exp Q x); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H3; Rewrite H11 in H4; Rewrite H12 in H3; Rewrite H12 in H4.
Cut P0=([_:name](par (x1 _) (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H8; Inversion_clear H10; Apply notin_proc_par); Auto].
Cut Q0=([_:name](par (x0 _) (x1 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H8; Inversion_clear H10; Apply notin_proc_par); Auto].
Rewrite H9; Rewrite H13; Apply struct_par_comm.

Elim (proc_exp P x); Elim (proc_exp Q x); Elim (proc_exp R x); Intros.
Inversion_clear H8; Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H3; Rewrite H12 in H4; Rewrite H13 in H3; Rewrite H13 in H4; Rewrite H14 in H3; Rewrite H14 in H4.
Cut P0=([_:name](par (par (x2 _) (x1 _)) (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H8; Inversion_clear H9; Inversion_clear H11; Apply notin_proc_par; [Apply notin_proc_par | Idtac]); Auto].
Cut Q0=([_:name](par (x2 _) (par (x1 _) (x0 _)))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H8; Inversion_clear H9; Inversion_clear H11; Apply notin_proc_par; [Idtac | Apply notin_proc_par]); Auto].
Rewrite H10; Rewrite H15; Apply struct_par_assoc.

Cut P=([_:name](bang nil)); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Apply notin_proc_bang; Apply notin_proc_nil); Auto].
Cut Q=([_:name]nil); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Apply notin_proc_nil); Auto].
Rewrite H8; Rewrite H9; Apply struct_repl_zero.

Elim (proc_exp P x); Elim (proc_exp Q x); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H3; Rewrite H11 in H4; Rewrite H12 in H3; Rewrite H12 in H4.
Cut P0=([_:name](bang (par (x1 _) (x0 _)))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Apply notin_proc_bang; Inversion_clear H8; Inversion_clear H10; Apply notin_proc_par); Auto].
Cut Q0=([_:name](par (bang (x1 _)) (bang (x0 _)))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H8; Inversion_clear H10; Apply notin_proc_par; Apply notin_proc_bang); Auto].
Rewrite H9; Rewrite H13; Apply struct_repl_par.

Elim (proc_exp P x); Intros.
Inversion_clear H8.
Rewrite H10 in H3; Rewrite H10 in H4.
Cut P0=([_:name](bang (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Apply notin_proc_bang; Inversion_clear H9); Auto].
Cut Q=([_:name](par (x0 _) (bang (x0 _)))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Inversion_clear H9; Apply notin_proc_par; [Idtac | Apply notin_proc_bang]); Auto].
Rewrite H8; Rewrite H11; Apply struct_repl_copy.

Elim (proc_exp P x); Intros.
Inversion_clear H8.
Rewrite H10 in H3; Rewrite H10 in H4.
Cut P0=([_:name](bang (x0 _))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Apply notin_proc_bang; Inversion_clear H9); Auto].
Cut Q=([_:name](bang (bang (x0 _)))); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Do 2 (Apply notin_proc_bang); Inversion_clear H9); Auto].
Rewrite H8; Rewrite H11; Apply struct_repl_repl.

Qed.

Lemma STRUCT_RW: (P,Q:name->proc)(x:name)
                 (notin_proc x (nu P)) -> (notin_proc x (nu Q)) ->
                 (struct_eq (P x) (Q x)) ->
                 (y:name)
                 (notin_proc y (nu P)) -> (notin_proc y (nu Q)) ->
                 (struct_eq (P y) (Q y)).

Proof.

Intros; Elim (dec_name x y); Intros; [Rewrite <-H4; Assumption | Apply PRE_STRUCT_RW with (P x) (Q x) x; Auto].

Qed.

Lemma STRUCT_RES: (P,Q:name->proc)(x:name)(notin_proc x (nu P)) -> (notin_proc x (nu Q))
                  -> (struct_eq (P x) (Q x)) -> (struct_eq (nu P) (nu Q)).

Proof.

Intros.

Apply struct_res with empty; Intros.
Clear H2; Apply STRUCT_RW with x; Assumption.

Qed.

Lemma RED_STAR: (P,Q:proc)(red_star P Q) -> P=Q \/ (Ex [R:proc](red P R) /\ (red_star R Q)).

Proof.

Do 3 Intro; Generalize H; Pattern P Q; Apply red_star_ind; Intros; Auto.

Right; Exists Q0; Split; [Assumption | Apply red_refl].

Cut P0=Q0\/(EX R:proc | (red P0 R)/\(red_star R Q0)); [Intro | Auto].
Cut Q0=R\/(EX R0:proc | (red Q0 R0)/\(red_star R0 R)); [Intro | Auto].
Inversion_clear H5; Inversion_clear H6.
Left; Rewrite H7; Rewrite H5; Trivial.
Inversion_clear H5; Inversion_clear H6; Right; Exists x; Split; [Rewrite <-H7 in H5; Assumption | Assumption].
Inversion_clear H7; Inversion_clear H6; Right; Exists x; Split; [Assumption | Apply red_trans with Q0; Assumption].
Inversion_clear H5; Inversion_clear H7; Inversion_clear H5; Inversion_clear H6; Right; Exists x0; Split; [Assumption | Apply red_trans with Q0; Assumption].

Qed.

Lemma NEST_STAR: (P,Q:proc)(nest_star P Q) -> P=Q \/ (Ex [R:proc](nest P R) /\ (nest_star R Q)).

Proof.

Do 3 Intro; Generalize H; Pattern P Q; Apply nest_star_ind; Intros; Auto.

Right; Exists Q0; Split; [Assumption | Apply nest_refl].

Cut P0=Q0\/(EX R:proc | (nest P0 R)/\(nest_star R Q0)); [Intro | Auto].
Cut Q0=R\/(EX R0:proc | (nest Q0 R0)/\(nest_star R0 R)); [Intro | Auto].
Inversion_clear H5; Inversion_clear H6.
Left; Rewrite H7; Rewrite H5; Trivial.
Inversion_clear H5; Inversion_clear H6; Right; Exists x; Split; [Rewrite <-H7 in H5; Assumption | Assumption].
Inversion_clear H7; Inversion_clear H6; Right; Exists x; Split; [Assumption | Apply nest_trans with Q0; Assumption].
Inversion_clear H5; Inversion_clear H7; Inversion_clear H5; Inversion_clear H6; Right; Exists x0; Split; [Assumption | Apply nest_trans with Q0; Assumption].

Qed.

Lemma SAT_UPTO_STRUCT_EQ: (A:form)(P:proc)(sat P A) -> (P':proc)(struct_eq P P') -> (sat P' A).

Proof.

Induction A; Intros.

Apply sat_T.

Elim (sat_neg P f); Elim (sat_neg P' f); Intros.
Apply H2; Unfold not; Intros; Cut ~(sat P f); [Intro | Auto].
Unfold not in H7; Apply H7; Apply H with P'; [Assumption | Apply struct_symm; Assumption].

Elim (sat_Or P f f0); Elim (sat_Or P' f f0); Intros.
Apply H3; Cut (sat P f)\/(sat P f0); [Intro | Auto].
Inversion_clear H7; [Left; Apply H with P | Right; Apply H0 with P]; Assumption.

Elim (sat_zero P); Elim (sat_zero P'); Intros.
Cut (struct_eq P nil); [Intro | Auto]; Apply H1; Apply struct_trans with P; [Apply struct_symm; Assumption | Assumption].

Elim (sat_comp P f f0); Elim (sat_comp P' f f0); Intros.
Cut (EX P':proc | (EX P'':proc | (struct_eq P (par P' P''))/\(sat P' f)/\(sat P'' f0))); [Intro | Auto]; Apply H3.
Inversion_clear H7; Inversion_clear H8; Inversion_clear H7; Inversion_clear H9.
Exists x; Exists x0; Split; Try Split; Auto.
Apply struct_trans with P; [Apply struct_symm | Idtac]; Assumption.

Elim (sat_comp_adj P f f0); Elim (sat_comp_adj P' f f0); Intros.
Cut (P':proc)(sat P' f)->(sat (par P P') f0); [Intro | Auto]; Apply H3; Intros.
Apply H0 with (par P P'0); [Auto | Apply struct_par; Assumption].

Elim (sat_loc P n f); Elim (sat_loc P' n f); Intros.
Cut (EX P':proc | (struct_eq P (ambient (name2cap n) P'))/\(sat P' f)); [Intro | Auto]; Apply H2.
Inversion_clear H6; Inversion_clear H7.
Exists x; Split; Auto.
Apply struct_trans with P; [Apply struct_symm | Idtac]; Assumption.

Elim (sat_loc_adj P f n); Elim (sat_loc_adj P' f n); Intros.
Cut (sat P (loc_adj f n))->(sat (ambient (name2cap n) P) f); [Intro | Auto]; Apply H2.
Apply H with (ambient (name2cap n) P); Auto.
Apply struct_amb; Assumption.

Elim (sat_rev P n f); Elim (sat_rev P' n f); Intros.
Cut (notin_proc n P) /\ (EX P':name->proc | (struct_eq P (nu P')) /\ (sat (P' n) f)); [Intro | Auto]; Apply H2.
Inversion_clear H6; Inversion_clear H8; Inversion_clear H6.
Split; [Elim (STRUCT_NOTIN P P' H1 n); Intros; Auto | Idtac].
Exists x; Split; Auto.
Apply struct_trans with P; [Apply struct_symm | Idtac]; Assumption.

Elim (sat_rev_adj P n f); Elim (sat_rev_adj P' n f); Intros.
Cut (EX P':name->proc | P=(P' n)/\(notin_proc n (nu P'))/\(sat (nu P') f)); [Intro | Auto]; Apply H2.
Inversion_clear H6; Inversion_clear H7; Inversion_clear H8.
Elim (proc_exp P' n); Intros; Inversion_clear H8.
Exists x0; Split; Try Split; Auto.
Apply H with (nu x); Auto.
Rewrite H6 in H1; Rewrite H11 in H1; Apply STRUCT_RES with n; Assumption.

Elim (sat_sometime P f); Elim (sat_sometime P' f); Intros.
Cut (EX P':proc | (red_star P P')/\(sat P' f)); [Intro | Auto]; Apply H2.
Inversion_clear H6; Inversion_clear H7.
Elim (RED_STAR P x H6); Intros.
Exists P'; Split; [Apply red_refl | Rewrite <-H7 in H8; Apply H with P; Assumption].
Inversion_clear H7; Inversion_clear H9.
Exists x; Split; [Apply red_trans with x0; [Apply base_red; Apply red_struct_eq with P x0; [Assumption | Assumption | Apply struct_refl] | Assumption] | Assumption].

Elim (sat_somewhere P f); Elim (sat_somewhere P' f); Intros.
Cut (EX P':proc | (nest_star P P')/\(sat P' f)); [Intro | Auto]; Apply H2.
Inversion_clear H6; Inversion_clear H7.
Elim (NEST_STAR P x H6); Intros.
Exists P'; Split; [Apply nest_refl | Rewrite <-H7 in H8; Apply H with P; Assumption].
Inversion_clear H7; Inversion_clear H9.
Exists x; Split; [Apply nest_trans with x0; [Apply base_nest; Unfold nest; Unfold nest in H7; Inversion_clear H7; Inversion_clear H9; Exists x1; Exists x2; Apply struct_trans with P; [Apply struct_symm; Assumption | Assumption] | Assumption] | Assumption].

Elim (sat_forall P f); Elim (sat_forall P' f); Intros.
Apply H2; Intro; Apply H with P; Auto.

Elim (sat_new P f); Elim (sat_new P' f); Intros.
Apply H2; Cut (EX m:name | (notin_proc m P)/\(notin_form m (forall f))/\(sat P (f m))); [Intro | Auto].
Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Exists x; Split; Try Split; Auto.
Cut ((notin_proc x P)->(notin_proc x P'))/\((notin_proc x P')->(notin_proc x P)); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion_clear H8; Auto.
Apply H with P; Assumption.

Qed.

Inductive ln: form -> nat -> Prop:=
    ln_T : (ln T (S O))
  | ln_neg : (F:form)(n:nat)(ln F n) -> (ln (neg F) (S n))
  | ln_Or : (F,G:form)(n1,n2:nat)(ln F n1) -> (ln G n2) -> (ln (Or F G) (S (plus n1 n2)))
  | ln_zero : (ln zero (S O))
  | ln_comp : (F,G:form)(n1,n2:nat)(ln F n1) -> (ln G n2) -> (ln (comp F G) (S (plus n1 n2)))
  | ln_comp_adj : (F,G:form)(n1,n2:nat)(ln F n1) -> (ln G n2) -> (ln (comp_adj F G) (S (plus n1 n2)))
  | ln_loc : (F:form)(x:name)(n:nat)(ln F n) -> (ln (loc x F) (S n))
  | ln_loc_adj : (F:form)(x:name)(n:nat)(ln F n) -> (ln (loc_adj F x) (S n))
  | ln_rev : (F:form)(x:name)(n:nat)(ln F n) -> (ln (rev x F) (S n))
  | ln_rev_adj : (F:form)(x:name)(n:nat)(ln F n) -> (ln (rev_adj F x) (S n))
  | ln_sometime : (F:form)(n:nat)(ln F n) -> (ln (sometime F) (S n))
  | ln_somewhere : (F:form)(n:nat)(ln F n) -> (ln (somewhere F) (S n))
  | ln_forall : (F:name->form)(n:nat)((x:name)(ln (F x) n)) -> (ln (forall F) (S n))
  | ln_new : (F:name->form)(n:nat)((x:name)(ln (F x) n)) -> (ln (new F) (S n)).

Axiom form_ext: (F,G:name->form)(x:name)
        (notin_form x (forall F))->(notin_form x (forall G))->(F x)=(G x)->F=G.

Axiom form_exp: (F:form)(n:name)
                (EX G:name->form | (notin_form n (forall G)) /\ F=(G n)).

Axiom ho_form_exp: (F:name->form)(n:name)
                (EX G:name->name->form | (notin_form n (forall ([_:name](forall (G _))))) /\ F=(G n)).

Axiom ho2_form_exp: (F:name->name->form)(n:name)
                (EX G:name->name->name->form | (notin_form n (forall ([u:name](forall [v:name](forall (G u v)))))) /\ F=(G n)).

Lemma LN_S: (A:form)(n:nat)(ln A n)->(lt O n).

Proof.

Induction A; Intros.

Inversion_clear H; Unfold lt; Apply le_n.

Inversion_clear H0; Unfold lt; Unfold lt in H; Apply le_S; Apply H; Assumption.

Inversion_clear H1.
Cut (lt (0) n1); [Intro | Apply H; Assumption].
Cut (lt (0) n2); [Intro | Apply H0; Assumption].
Omega.

Inversion_clear H; Unfold lt; Apply le_n.

Inversion_clear H1.
Cut (lt (0) n1); [Intro | Apply H; Assumption].
Cut (lt (0) n2); [Intro | Apply H0; Assumption].
Omega.

Inversion_clear H1.
Cut (lt (0) n1); [Intro | Apply H; Assumption].
Cut (lt (0) n2); [Intro | Apply H0; Assumption].
Omega.

Inversion_clear H0.
Cut (lt (0) n1); [Intro | Apply H; Assumption].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H0.
Cut (lt (0) n1); [Intro | Apply H; Assumption].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H0.
Cut (lt (0) n1); [Intro | Apply H; Assumption].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H0.
Cut (lt (0) n1); [Intro | Apply H; Assumption].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H0.
Cut (lt (0) n0); [Intro | Apply H; Assumption].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H0.
Cut (lt (0) n0); [Intro | Apply H; Assumption].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H0.
Elim (UNSAT_PROC_NLIST nil empty); Intros.
Clear H0; Cut (lt (0) n0); [Intro | Apply H with x; Auto].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Inversion_clear H0.
Elim (UNSAT_PROC_NLIST nil empty); Intros.
Clear H0; Cut (lt (0) n0); [Intro | Apply H with x; Auto].
Unfold lt; Unfold lt in H0; Apply le_S; Assumption.

Qed.

Lemma LN_RW: (n:nat)(A:form)(ln A n) -> (x:name)(B:name->form)(notin_form x (forall B)) -> A=(B x) -> (y:name)(ln (B y) n).

Proof.

Intro; Pattern n; Apply NAT_IND; Intros.

Cut (lt O (0)); [Intro | Apply LN_S with A; Assumption].
Inversion_clear H2.

Inversion H0.

Rewrite <-H3 in H2; Cut B=([_:name]T); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_T); Auto].
Rewrite H5; Apply ln_T.

Rewrite <-H4 in H2; Elim (form_exp F x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Cut B=([_:name](neg (x0 _))); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_neg); Auto].
Rewrite H6; Apply ln_neg; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.

Rewrite <-H5 in H2; Elim (form_exp F x); Elim (form_exp G x); Intros.
Inversion_clear H7; Inversion_clear H8.
Rewrite H10 in H2; Rewrite H11 in H2.
Cut B=([_:name](Or (x1 _) (x0 _))); [Intro | Apply form_ext with x; Inversion_clear H7; Inversion_clear H9; Try (Apply notin_forall; Intros; Apply notin_Or); Auto].
Rewrite H8; Apply ln_Or; [Apply H with F x | Apply H with G x]; Try (Rewrite <-H6; Omega); Auto.

Rewrite <-H3 in H2; Cut B=([_:name]zero); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_zero); Auto].
Rewrite H5; Apply ln_zero.

Rewrite <-H5 in H2; Elim (form_exp F x); Elim (form_exp G x); Intros.
Inversion_clear H7; Inversion_clear H8.
Rewrite H10 in H2; Rewrite H11 in H2.
Cut B=([_:name](comp (x1 _) (x0 _))); [Intro | Apply form_ext with x; Inversion_clear H7; Inversion_clear H9; Try (Apply notin_forall; Intros; Apply notin_comp); Auto].
Rewrite H8; Apply ln_comp; [Apply H with F x | Apply H with G x]; Try (Rewrite <-H6; Omega); Auto.

Rewrite <-H5 in H2; Elim (form_exp F x); Elim (form_exp G x); Intros.
Inversion_clear H7; Inversion_clear H8.
Rewrite H10 in H2; Rewrite H11 in H2.
Cut B=([_:name](comp_adj (x1 _) (x0 _))); [Intro | Apply form_ext with x; Inversion_clear H7; Inversion_clear H9; Try (Apply notin_forall; Intros; Apply notin_comp_adj); Auto].
Rewrite H8; Apply ln_comp_adj; [Apply H with F x | Apply H with G x]; Try (Rewrite <-H6; Omega); Auto.

Rewrite <-H4 in H2; Elim (form_exp F x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Elim (dec_name x0 x); Intros.
Rewrite H6 in H2; Cut B=([_:name](loc _ (x1 _))); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_loc); Auto].
Rewrite H9; Apply ln_loc; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Cut B=([_:name](loc x0 (x1 _))); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_loc); Auto].
Rewrite H9; Apply ln_loc; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.

Rewrite <-H4 in H2; Elim (form_exp F x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Elim (dec_name x0 x); Intros.
Rewrite H6 in H2; Cut B=([_:name](loc_adj (x1 _) _)); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_loc_adj); Auto].
Rewrite H9; Apply ln_loc_adj; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Cut B=([_:name](loc_adj (x1 _) x0)); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_loc_adj); Auto].
Rewrite H9; Apply ln_loc_adj; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.

Rewrite <-H4 in H2; Elim (form_exp F x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Elim (dec_name x0 x); Intros.
Rewrite H6 in H2; Cut B=([_:name](rev _ (x1 _))); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_rev); Auto].
Rewrite H9; Apply ln_rev; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Cut B=([_:name](rev x0 (x1 _))); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_rev); Auto].
Rewrite H9; Apply ln_rev; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.

Rewrite <-H4 in H2; Elim (form_exp F x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Elim (dec_name x0 x); Intros.
Rewrite H6 in H2; Cut B=([_:name](rev_adj (x1 _) _)); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_rev_adj); Auto].
Rewrite H9; Apply ln_rev_adj; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Cut B=([_:name](rev_adj (x1 _) x0)); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_rev_adj); Auto].
Rewrite H9; Apply ln_rev_adj; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.

Rewrite <-H4 in H2; Elim (form_exp F x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Cut B=([_:name](sometime (x0 _))); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_sometime); Auto].
Rewrite H6; Apply ln_sometime; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.

Rewrite <-H4 in H2; Elim (form_exp F x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Cut B=([_:name](somewhere (x0 _))); [Intro | Apply form_ext with x; Inversion_clear H7; Try (Apply notin_forall; Intros; Apply notin_somewhere); Auto].
Rewrite H6; Apply ln_somewhere; Apply H with F x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.

Rewrite <-H4 in H2; Elim (ho_form_exp F x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Cut B=([_:name](forall (x0 _))); [Intro | Apply form_ext with x; Auto].
Rewrite H6; Apply ln_forall; Intro.
Elim (UNSAT_FORM (Or (loc x T) (Or (loc y T) (Or (loc x1 T) (forall [_:name](forall (x0 _))))))); Intros.
Inversion_clear H9; Inversion_clear H10; Inversion_clear H11; Inversion_clear H10; Inversion_clear H13; Inversion_clear H10.
Clear H12; Clear H14; Clear H16.
Apply H with (x0 y x2) x2; Inversion_clear H15; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Change (ln ([_:name](x0 _ x2) y) n1); Apply H with (x0 x x2) x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Rewrite <-H8; Auto.
Inversion_clear H7; Apply notin_forall; Intros.
Cut (notin_form x (forall (x0 n2))); [Intro | Auto].
Inversion_clear H14; Auto.

Rewrite <-H4 in H2; Elim (ho_form_exp F x); Intros.
Inversion_clear H6.
Rewrite H8 in H2; Cut B=([_:name](new (x0 _))); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_new; Intros; Inversion_clear H7; Cut (notin_form x (forall (x0 n2))); [Intro | Auto]; Inversion_clear H7); Auto].
Rewrite H6; Apply ln_new; Intro.
Elim (UNSAT_FORM (Or (loc x T) (Or (loc y T) (Or (loc x1 T) (forall [_:name](forall (x0 _))))))); Intros.
Inversion_clear H9; Inversion_clear H10; Inversion_clear H11; Inversion_clear H10; Inversion_clear H13; Inversion_clear H10.
Clear H12; Clear H14; Clear H16.
Apply H with (x0 y x2) x2; Inversion_clear H15; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Change (ln ([_:name](x0 _ x2) y) n1); Apply H with (x0 x x2) x; Try (Rewrite <-H5; Unfold lt; Apply le_n); Auto.
Rewrite <-H8; Auto.
Inversion_clear H7; Apply notin_forall; Intros.
Cut (notin_form x (forall (x0 n2))); [Intro | Auto].
Inversion_clear H14; Auto.

Qed.

Lemma LN_TOT: (A:form)(Ex [n:nat](ln A n)).

Proof.

Induction A; Intros.

Exists (S O); Apply ln_T.

Inversion_clear H.
Exists (S x); Apply ln_neg; Assumption.

Inversion_clear H; Inversion_clear H0.
Exists (S (plus x x0)); Apply ln_Or; Assumption.

Exists (S O); Apply ln_zero.

Inversion_clear H; Inversion_clear H0.
Exists (S (plus x x0)); Apply ln_comp; Assumption.

Inversion_clear H; Inversion_clear H0.
Exists (S (plus x x0)); Apply ln_comp_adj; Assumption.

Inversion_clear H.
Exists (S x); Apply ln_loc; Assumption.

Inversion_clear H.
Exists (S x); Apply ln_loc_adj; Assumption.

Inversion_clear H.
Exists (S x); Apply ln_rev; Assumption.

Inversion_clear H.
Exists (S x); Apply ln_rev_adj; Assumption.

Inversion_clear H.
Exists (S x); Apply ln_sometime; Assumption.

Inversion_clear H.
Exists (S x); Apply ln_somewhere; Assumption.

Elim (UNSAT_FORM (forall f)); Intros.
Elim (H x); Intros.
Exists (S x0); Apply ln_forall; Intro.
Apply LN_RW with (f x) x; Auto.

Elim (UNSAT_FORM (forall f)); Intros.
Elim (H x); Intros.
Exists (S x0); Apply ln_new; Intro.
Apply LN_RW with (f x) x; Auto.

Qed.

Lemma PRE_SUBST_CAP_RW: (A,B:cap)(C:name->cap)(subst_cap B C A) ->
                        (M,R:name->cap)(N:name->name->cap)
                        (x:name)(notin_ho_cap x M) -> (notin_ho_cap x R) ->
                        (notin_ho2_cap x N) ->
                        A=(R x) -> B=(M x) -> C=(N x) ->
                        (y:name)~x=y ->
                        (subst_cap (M y) (N y) (R y)).

Proof.

Induction 1; Intros.

Rewrite H4 in H3; Cut M=R; [Intro | Apply cap_ext with x; Auto].
Cut N=([_:name]name2cap); [Intro | Apply ho_cap_ext with x; Try (Unfold notin_ho2_cap; Intros; Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Rewrite H7; Rewrite H8; Apply subst_cap_name.

Elim (dec_name n x); Intros.
Rewrite H7 in H3; Rewrite H7 in H5.
Cut R=name2cap; [Intro | Apply cap_ext with x; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Cut N=([x:name][_:name](name2cap x)); [Intro | Apply ho_cap_ext with x; Try (Unfold notin_ho2_cap; Intros; Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Rewrite H8; Rewrite H9; Apply subst_cap_void.
Cut R=([_:name](name2cap n)); [Intro | Apply cap_ext with x; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Cut N=([x:name][_:name](name2cap n)); [Intro | Apply ho_cap_ext with x; Try (Unfold notin_ho2_cap; Intros; Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Rewrite H8; Rewrite H9; Apply subst_cap_void.

Elim (cap_exp N' x); Elim (ho_cap_exp N x); Intros.
Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H7; Rewrite H13 in H5.
Cut N0=([x:name][n:name](in_cap (x0 x n))); [Intro | Apply ho_cap_ext with x; Unfold notin_ho2_cap in H11; Unfold notin_ho_cap in H11; Try (Unfold notin_ho2_cap; Intros; Unfold notin_ho_cap; Intros; Apply notin_cap_in); Auto].
Cut R=([_:name](in_cap (x1 _))); [Intro | Apply cap_ext with x; Unfold notin_ho_cap in H9; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_in); Auto].
Rewrite H10; Rewrite H14; Apply subst_cap_in; Apply H1 with x; Auto.

Elim (cap_exp N' x); Elim (ho_cap_exp N x); Intros.
Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H7; Rewrite H13 in H5.
Cut N0=([x:name][n:name](out_cap (x0 x n))); [Intro | Apply ho_cap_ext with x; Unfold notin_ho2_cap in H11; Unfold notin_ho_cap in H11; Try (Unfold notin_ho2_cap; Intros; Unfold notin_ho_cap; Intros; Apply notin_cap_out); Auto].
Cut R=([_:name](out_cap (x1 _))); [Intro | Apply cap_ext with x; Unfold notin_ho_cap in H9; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_out); Auto].
Rewrite H10; Rewrite H14; Apply subst_cap_out; Apply H1 with x; Auto.

Elim (cap_exp N' x); Elim (ho_cap_exp N x); Intros.
Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H7; Rewrite H13 in H5.
Cut N0=([x:name][n:name](open (x0 x n))); [Intro | Apply ho_cap_ext with x; Unfold notin_ho2_cap in H11; Unfold notin_ho_cap in H11; Try (Unfold notin_ho2_cap; Intros; Unfold notin_ho_cap; Intros; Apply notin_cap_open); Auto].
Cut R=([_:name](open (x1 _))); [Intro | Apply cap_ext with x; Unfold notin_ho_cap in H9; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_open); Auto].
Rewrite H10; Rewrite H14; Apply subst_cap_open; Apply H1 with x; Auto.

Cut N=([x:name][_:name]eps); [Intro | Apply ho_cap_ext with x; Try (Unfold notin_ho2_cap; Intros; Unfold notin_ho_cap; Intros; Apply notin_cap_eps); Auto].
Cut R=([_:name]eps); [Intro | Apply cap_ext with x; Try (Unfold notin_ho2_cap; Intros; Unfold notin_ho_cap; Intros; Apply notin_cap_eps); Auto].
Rewrite H7; Rewrite H8; Apply subst_cap_eps.

Elim (ho_cap_exp N x); Elim (ho_cap_exp O x); Elim (cap_exp N' x); Elim (cap_exp O' x); Intros.
Inversion_clear H11; Inversion_clear H12; Inversion_clear H13; Inversion_clear H14.
Rewrite H16 in H7; Rewrite H17 in H7; Rewrite H18 in H9; Rewrite H19 in H9.
Cut N0=([_:name][x0:name](path (x3 _ x0) (x2 _ x0))); [Intro | Apply ho_cap_ext with x; Unfold notin_ho2_cap in H12; Unfold notin_ho2_cap in H13; Unfold notin_ho_cap in H12; Unfold notin_ho_cap in H13; Try (Unfold notin_ho2_cap; Intros; Unfold notin_ho_cap; Intros; Apply notin_cap_path); Auto].
Cut R=([_:name](path (x1 _) (x0 _))); [Intro | Apply cap_ext with x; Unfold notin_ho_cap in H11; Unfold notin_ho_cap in H15; Try (Unfold notin_ho2_cap; Intros; Unfold notin_ho_cap; Intros; Apply notin_cap_path); Auto].
Rewrite H14; Rewrite H20; Apply subst_cap_path; [Apply H1 with x | Apply H3 with x]; Auto.

Qed.

Lemma SUBST_CAP_RW: (M,R:name->cap)(N:name->name->cap)
                    (x:name)(notin_ho_cap x M) -> (notin_ho_cap x R) ->
                    (notin_ho2_cap x N) ->
                    (subst_cap (M x) (N x) (R x)) ->
                    (y:name)(subst_cap (M y) (N y) (R y)).

Proof.

Intros; Elim (dec_name x y); Intros.
Rewrite <-H3; Assumption.
Apply PRE_SUBST_CAP_RW with (R x) (M x) (N x) x; Auto.

Qed.

Lemma PRE_SUBST_PROC_RW: (n:nat)(B:proc)(lnp B n) ->
                         (M:cap)(A:name->proc)(subst_proc M A B) ->
                         (N:name->cap)(P:name->name->proc)(Q:name->proc)
                         (x:name)(notin_ho_cap x N) ->
                         (notin_proc x (nu [_:name](nu (P _)))) ->
                         (notin_proc x (nu Q)) ->
                         A=(P x) -> B=(Q x) -> M=(N x) ->
                         (y:name)~x=y -> (subst_proc (N y) (P y) (Q y)).

Proof.

Intro; Pattern n; Apply NAT_IND; Intros.

Cut (lt O (0)); [Intro | Apply LNP_S with B; Assumption].
Inversion_clear H8.

Inversion H1.

Rewrite <-H11 in H0; Inversion H0.
Elim (ho2_proc_exp P0 x); Elim (ho_proc_exp P' x); Intros.
Inversion_clear H15; Inversion_clear H16.
Rewrite H18 in H11; Rewrite H19 in H10; Rewrite <-H10 in H5; Rewrite <-H11 in H6.
Cut P=([_:name][x0:name](nu (x1 _ x0))); [Intro | Apply ho_proc_ext with x; Auto].
Cut Q=([_:name](nu (x0 _))); [Intro | Apply proc_ext with x; Auto].
Rewrite H16; Rewrite H20; Apply subst_proc_nu; Intro.
Elim (UNSAT_CAP_PROC_NLIST (N y) (par (nu [_:name](nu (x0 _))) (nu [u:name](nu [v:name](nu (x1 u v))))) (cons x (cons y (cons y0 empty)))); Intros.
Inversion_clear H21; Inversion_clear H23; Inversion_clear H21; Inversion_clear H24; Inversion_clear H26; Inversion_clear H27; Clear H28.
Change (subst_proc ([_:name](N y) y0) ([_:name][x3:name](x1 y x3 _) y0) (x0 y y0)); Apply H with n1 (x0 y x2) (N y) [x3:name](x1 y x3 x2) x2; [Rewrite <-H14; Unfold lt; Apply le_n | Cut (lnp (x0 x x2) n1); [Intro | Rewrite <-H18; Auto]; Change (lnp ([_:name](x0 _ x2) y) n1); Apply LNP_RW with (x0 x x2) x; Try (Inversion_clear H17; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x0 n2))); [Intro | Auto]; Inversion_clear H29; Auto); Auto | Idtac | Unfold notin_ho_cap; Intros; Assumption | Inversion_clear H25; Apply notin_proc_nu; Intros; Cut (notin_proc x2 (nu [v:name](nu (x1 y v)))); [Intro | Auto]; Inversion_clear H28; Apply notin_proc_nu; Intros; Cut (notin_proc x2 (nu (x1 y n3))); [Intro | Auto]; Inversion_clear H30; Auto | Inversion_clear H23; Auto | Auto | Auto | Auto | Auto].
Change (subst_proc (N y) ([_:name][x3:name](x1 _ x3 x2) y) ([_:name](x0 _ x2) y)); Apply H with n1 (x0 x x2) (N x) [x3:name](x1 x x3 x2) x; [Rewrite <-H14; Unfold lt; Apply le_n | Rewrite <-H18; Auto | Rewrite <-H7; Rewrite <-H18; Rewrite <-H19; Auto | Assumption | Inversion_clear H15; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu [v:name](nu (x1 n2 v)))); [Intro | Auto]; Inversion_clear H28; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x1 n2 n3))); [Intro | Auto]; Inversion_clear H30; Auto | Inversion_clear H17; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x0 n2))); [Intro | Auto]; Inversion_clear H28; Auto | Auto | Auto | Auto | Auto].

Rewrite <-H9 in H5; Rewrite <-H10 in H6.
Cut P=([u:name][v:name]nil); [Intro | Apply ho_proc_ext with x; Try (Do 2 (Apply notin_proc_nu; Intros); Apply notin_proc_nil); Auto].
Cut Q=([_:name]nil); [Intro | Apply proc_ext with x; Try (Apply notin_proc_nu; Intros; Apply notin_proc_nil); Auto].
Rewrite H11; Rewrite H12; Apply subst_proc_nil.

Rewrite <-H11 in H5; Rewrite <-H12 in H6.
Elim (ho_proc_exp P0 x); Elim (ho_proc_exp Q0 x); Elim (proc_exp P' x); Elim (proc_exp Q' x); Intros.
Inversion_clear H13; Inversion_clear H14; Inversion_clear H15; Inversion_clear H16.
Rewrite H18 in H6; Rewrite H19 in H6; Rewrite H20 in H5; Rewrite H21 in H5.
Cut P=([_:name][x0:name](par (x3 _ x0) (x2 _ x0))); [Intro | Apply ho_proc_ext with x; Inversion_clear H14; Inversion_clear H15; Try (Do 2 (Apply notin_proc_nu; Intros); Apply notin_proc_par; [Cut (notin_proc x (nu (x3 n1))); [Intro | Auto] | Cut (notin_proc x (nu (x2 n1))); [Intro | Auto]]; Inversion_clear H23); Auto].
Cut Q=([_:name](par (x1 _) (x0 _))); [Intro | Apply proc_ext with x; Inversion_clear H13; Inversion_clear H17; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par); Auto].
Rewrite <-H12 in H0; Inversion H0; Rewrite H16; Rewrite H22; Apply subst_proc_par; [Apply H with n1 (x1 x) (N x) (x3 x) x; [Rewrite <-H26; Omega | Rewrite <-H19; Assumption | Rewrite <-H7; Rewrite <-H19; Rewrite <-H21; Assumption | Assumption | Assumption | Assumption | Trivial | Trivial | Trivial | Assumption] | Apply H with n2 (x0 x) (N x) (x2 x) x; [Rewrite <-H26; Omega | Rewrite <-H18; Assumption | Rewrite <-H7; Rewrite <-H18; Rewrite <-H20; Assumption | Assumption | Assumption | Assumption | Trivial | Trivial | Trivial | Assumption]].

Rewrite <-H11 in H0; Inversion H0; Rewrite <-H10 in H5; Rewrite <-H11 in H6.
Elim (ho_proc_exp P0 x); Elim (proc_exp P' x); Intros.
Inversion_clear H15; Inversion_clear H16.
Rewrite H18 in H6; Rewrite H19 in H5.
Cut P=([_:name][x0:name](bang (x1 _ x0))); [Intro | Apply ho_proc_ext with x; Try (Inversion_clear H15; Do 2 (Apply notin_proc_nu; Intros); Apply notin_proc_bang; Cut (notin_proc x (nu (x1 n2))); [Intro | Auto]; Inversion_clear H21); Auto].
Cut Q=([_:name](bang (x0 _))); [Intro | Apply proc_ext with x; Try (Inversion_clear H17; Apply notin_proc_nu; Intros; Apply notin_proc_bang); Auto].
Rewrite H16; Rewrite H20; Apply subst_proc_bang.
Apply H with n1 (x0 x) (N x) (x1 x) x; [Rewrite <-H14; Unfold lt; Apply le_n | Rewrite <-H18; Assumption | Rewrite <-H7; Rewrite <-H18; Rewrite <-H19; Assumption | Assumption | Assumption | Assumption | Trivial | Trivial | Trivial | Assumption].

Rewrite <-H12 in H0; Inversion H0; Rewrite <-H11 in H5; Rewrite <-H12 in H6.
Elim (ho_cap_exp N0 x); Elim (ho_proc_exp P0 x); Elim (cap_exp N' x); Elim (proc_exp P' x); Intros.
Inversion_clear H17; Inversion_clear H18; Inversion_clear H19; Inversion_clear H20.
Rewrite H22 in H6; Rewrite H23 in H6; Rewrite H24 in H5; Rewrite H25 in H5.
Cut P=([_:name][x0:name](ambient (x3 _ x0) (x2 _ x0))); [Intro | Apply ho_proc_ext with x; Try (Inversion_clear H18; Unfold notin_ho2_cap in H19; Unfold notin_ho_cap in H19; Do 2 (Apply notin_proc_nu; Intros); Apply notin_proc_amb; [Idtac | Cut (notin_proc x (nu (x2 n2))); [Intro | Auto]; Inversion_clear H27]; Auto); Auto].
Cut Q=([_:name](ambient (x1 _) (x0 _))); [Intro | Apply proc_ext with x; Unfold notin_ho_cap in H17; Inversion_clear H21; Try (Apply notin_proc_nu; Intros; Apply notin_proc_amb); Auto].
Rewrite H20; Rewrite H26; Apply subst_proc_amb.
Apply SUBST_CAP_RW with x; Try (Rewrite<-H7; Rewrite <-H23; Rewrite <-H25); Auto.
Apply H with n1 (x0 x) (N x) (x2 x) x; [Rewrite <-H14; Unfold lt; Apply le_n | Rewrite <-H22; Assumption | Rewrite <-H7; Rewrite <-H22; Rewrite <-H24; Assumption | Assumption | Assumption | Assumption | Trivial | Trivial | Trivial | Assumption].

Rewrite <-H12 in H0; Inversion H0; Rewrite <-H11 in H5; Rewrite <-H12 in H6.
Elim (ho_cap_exp N0 x); Elim (ho_proc_exp P0 x); Elim (cap_exp N' x); Elim (proc_exp P' x); Intros.
Inversion_clear H17; Inversion_clear H18; Inversion_clear H19; Inversion_clear H20.
Rewrite H22 in H6; Rewrite H23 in H6; Rewrite H24 in H5; Rewrite H25 in H5.
Cut P=([_:name][x0:name](cap_act (x3 _ x0) (x2 _ x0))); [Intro | Apply ho_proc_ext with x; Try (Inversion_clear H18; Unfold notin_ho2_cap in H19; Unfold notin_ho_cap in H19; Do 2 (Apply notin_proc_nu; Intros); Apply notin_proc_act; [Idtac | Cut (notin_proc x (nu (x2 n2))); [Intro | Auto]; Inversion_clear H27]; Auto); Auto].
Cut Q=([_:name](cap_act (x1 _) (x0 _))); [Intro | Apply proc_ext with x; Unfold notin_ho_cap in H17; Inversion_clear H21; Try (Apply notin_proc_nu; Intros; Apply notin_proc_act); Auto].
Rewrite H20; Rewrite H26; Apply subst_proc_cap.
Apply SUBST_CAP_RW with x; Try (Rewrite<-H7; Rewrite <-H23; Rewrite <-H25); Auto.
Apply H with n1 (x0 x) (N x) (x2 x) x; [Rewrite <-H14; Unfold lt; Apply le_n | Rewrite <-H22; Assumption | Rewrite <-H7; Rewrite <-H22; Rewrite <-H24; Assumption | Assumption | Assumption | Assumption | Trivial | Trivial | Trivial | Assumption].

Rewrite <-H11 in H0; Inversion H0.
Elim (ho2_proc_exp P0 x); Elim (ho_proc_exp P' x); Intros.
Inversion_clear H15; Inversion_clear H16.
Rewrite H18 in H11; Rewrite H19 in H10; Rewrite <-H10 in H5; Rewrite <-H11 in H6.
Cut P=([_:name][x0:name](in_act (x1 _ x0))); [Intro | Apply ho_proc_ext with x; Try (Inversion_clear H15; Do 2 (Apply notin_proc_nu; Intros); Apply notin_proc_in; Intros; Cut (notin_proc x (nu [v:name](nu (x1 n2 v)))); [Intro | Auto]; Inversion_clear H22; Cut (notin_proc x (nu (x1 n2 n3))); [Intro | Auto]; Inversion_clear H22; Auto); Auto].
Cut Q=([_:name](in_act (x0 _))); [Intro | Apply proc_ext with x; Inversion_clear H17; Try (Apply notin_proc_nu; Intros; Apply notin_proc_in; Intros; Cut (notin_proc x (nu (x0 n2))); [Intro | Auto]; Inversion_clear H22); Auto].
Rewrite H16; Rewrite H20; Apply subst_proc_in; Intro.
Elim (UNSAT_CAP_PROC_NLIST (N y) (par (nu [_:name](nu (x0 _))) (nu [u:name](nu [v:name](nu (x1 u v))))) (cons x (cons y (cons y0 empty)))); Intros.
Inversion_clear H21; Inversion_clear H23; Inversion_clear H21; Inversion_clear H24; Inversion_clear H26; Inversion_clear H27; Clear H28.
Change (subst_proc ([_:name](N y) y0) ([_:name][x3:name](x1 y x3 _) y0) (x0 y y0)); Apply H with n1 (x0 y x2) (N y) [x3:name](x1 y x3 x2) x2; [Rewrite <-H14; Unfold lt; Apply le_n | Cut (lnp (x0 x x2) n1); [Intro | Rewrite <-H18; Auto]; Change (lnp ([_:name](x0 _ x2) y) n1); Apply LNP_RW with (x0 x x2) x; Try (Inversion_clear H17; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x0 n2))); [Intro | Auto]; Inversion_clear H29; Auto); Auto | Idtac | Unfold notin_ho_cap; Intros; Assumption | Inversion_clear H25; Apply notin_proc_nu; Intros; Cut (notin_proc x2 (nu [v:name](nu (x1 y v)))); [Intro | Auto]; Inversion_clear H28; Apply notin_proc_nu; Intros; Cut (notin_proc x2 (nu (x1 y n3))); [Intro | Auto]; Inversion_clear H30; Auto | Inversion_clear H23; Auto | Auto | Auto | Auto | Auto].
Change (subst_proc (N y) ([_:name][x3:name](x1 _ x3 x2) y) ([_:name](x0 _ x2) y)); Apply H with n1 (x0 x x2) (N x) [x3:name](x1 x x3 x2) x; [Rewrite <-H14; Unfold lt; Apply le_n | Rewrite <-H18; Auto | Rewrite <-H7; Rewrite <-H18; Rewrite <-H19; Auto | Assumption | Inversion_clear H15; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu [v:name](nu (x1 n2 v)))); [Intro | Auto]; Inversion_clear H28; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x1 n2 n3))); [Intro | Auto]; Inversion_clear H30; Auto | Inversion_clear H17; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x0 n2))); [Intro | Auto]; Inversion_clear H28; Auto | Auto | Auto | Auto | Auto].

Rewrite <-H11 in H0; Inversion H0; Rewrite <-H10 in H5; Rewrite <-H11 in H6.
Elim (ho_cap_exp N0 x); Elim (cap_exp N' x); Intros.
Inversion_clear H14; Inversion_clear H15.
Rewrite H17 in H6; Rewrite H18 in H5.
Cut P=([_:name][x0:name](out_act (x1 _ x0))); [Intro | Apply ho_proc_ext with x; Try (Unfold notin_ho2_cap in H14; Unfold notin_ho_cap in H14; Do 2 (Apply notin_proc_nu; Intros); Apply notin_proc_out); Auto].
Cut Q=([_:name](out_act (x0 _))); [Intro | Apply proc_ext with x; Try (Unfold notin_ho_cap in H16; Apply notin_proc_nu; Intros; Apply notin_proc_out); Auto].
Rewrite H15; Rewrite H19; Apply subst_proc_out.
Apply SUBST_CAP_RW with x; Try (Rewrite <-H7; Rewrite <-H17; Rewrite <-H18); Auto.

Qed.

Lemma SUBST_PROC_RW: (M:name->cap)(P:name->name->proc)(Q:name->proc)
                     (x:name)(notin_ho_cap x M) ->
                     (notin_proc x (nu [_:name](nu (P _)))) ->
                     (notin_proc x (nu Q)) ->
                     (subst_proc (M x) (P x) (Q x)) ->
                     (y:name)(subst_proc (M y) (P y) (Q y)).

Proof.

Intros; Elim (dec_name x y); Intros.
Rewrite <-H3; Assumption.
Elim (LNP_TOT (Q x)); Intros.
Apply PRE_SUBST_PROC_RW with x0 (Q x) (M x) (P x) x; Auto.

Qed.

Lemma PRE_RED_RW: (A,B:proc)(red A B) ->
                  (P,Q:name->proc)(x:name)
                  (notin_proc x (nu P)) -> (notin_proc x (nu Q)) ->
                  A=(P x) -> B=(Q x) ->
                  (y:name)~x=y ->
                  (notin_proc y (nu P)) -> (notin_proc y (nu Q)) ->
                  (red (P y) (Q y)).

Proof.

Induction 1; Intros.

Elim (proc_exp P x); Elim (proc_exp Q x); Elim (proc_exp R x); Intros.
Inversion_clear H7; Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H2; Rewrite H11 in H3; Rewrite H12 in H2; Rewrite H12 in H3; Rewrite H13 in H2; Rewrite H13 in H3.
Elim (dec_name m x); Elim (dec_name n x); Intros.
Rewrite H9 in H2; Rewrite H9 in H3; Rewrite H14 in H2; Rewrite H14 in H3.
Cut P0=([_:name](par (ambient (name2cap _) (par (cap_act (in_cap (name2cap _)) (x2 _)) (x1 _))) (ambient (name2cap _) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [Apply notin_proc_act; [Apply notin_cap_in; Apply notin_cap_name | Idtac] | Idtac]] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]; Auto); Auto].
Cut Q0=([_:name](ambient (name2cap _) (par (ambient (name2cap _) (par (x2 _) (x1 _))) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par] | Idtac]]); Auto].
Rewrite H15; Rewrite H16; Apply red_in.
Rewrite H14 in H2; Rewrite H14 in H3.
Cut P0=([_:name](par (ambient (name2cap n) (par (cap_act (in_cap (name2cap _)) (x2 _)) (x1 _))) (ambient (name2cap _) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [Apply notin_proc_act; [Apply notin_cap_in; Apply notin_cap_name | Idtac] | Idtac]] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]; Auto); Auto].
Cut Q0=([_:name](ambient (name2cap _) (par (ambient (name2cap n) (par (x2 _) (x1 _))) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par] | Idtac]]); Auto].
Rewrite H15; Rewrite H16; Apply red_in.
Rewrite H9 in H2; Rewrite H9 in H3.
Cut P0=([_:name](par (ambient (name2cap _) (par (cap_act (in_cap (name2cap m)) (x2 _)) (x1 _))) (ambient (name2cap m) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [Apply notin_proc_act; [Apply notin_cap_in; Apply notin_cap_name | Idtac] | Idtac]] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]; Auto); Auto].
Cut Q0=([_:name](ambient (name2cap m) (par (ambient (name2cap _) (par (x2 _) (x1 _))) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par] | Idtac]]); Auto].
Rewrite H15; Rewrite H16; Apply red_in.
Cut P0=([_:name](par (ambient (name2cap n) (par (cap_act (in_cap (name2cap m)) (x2 _)) (x1 _))) (ambient (name2cap m) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [Apply notin_proc_act; [Apply notin_cap_in; Apply notin_cap_name | Idtac] | Idtac]] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]; Auto); Auto].
Cut Q0=([_:name](ambient (name2cap m) (par (ambient (name2cap n) (par (x2 _) (x1 _))) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par] | Idtac]]); Auto].
Rewrite H15; Rewrite H16; Apply red_in.

Elim (proc_exp P x); Elim (proc_exp Q x); Elim (proc_exp R x); Intros.
Inversion_clear H7; Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H2; Rewrite H11 in H3; Rewrite H12 in H2; Rewrite H12 in H3; Rewrite H13 in H2; Rewrite H13 in H3.
Elim (dec_name m x); Elim (dec_name n x); Intros.
Rewrite H9 in H2; Rewrite H9 in H3; Rewrite H14 in H2; Rewrite H14 in H3.
Cut P0=([_:name](ambient (name2cap _) (par (ambient (name2cap _) (par (cap_act (out_cap (name2cap _)) (x2 _)) (x1 _))) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [ Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [ Apply notin_proc_act; [Apply notin_cap_out; Apply notin_cap_name | Idtac] | Idtac]] | Idtac]]); Auto].
Cut Q0=([_:name](par (ambient (name2cap _) (par (x2 _) (x1 _))) (ambient (name2cap _) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]); Auto].
Rewrite H15; Rewrite H16; Apply red_out.
Rewrite H14 in H2; Rewrite H14 in H3.
Cut P0=([_:name](ambient (name2cap _) (par (ambient (name2cap n) (par (cap_act (out_cap (name2cap _)) (x2 _)) (x1 _))) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [ Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [ Apply notin_proc_act; [Apply notin_cap_out; Apply notin_cap_name | Idtac] | Idtac]] | Idtac]]); Auto].
Cut Q0=([_:name](par (ambient (name2cap n) (par (x2 _) (x1 _))) (ambient (name2cap _) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]); Auto].
Rewrite H15; Rewrite H16; Apply red_out.
Rewrite H9 in H2; Rewrite H9 in H3.
Cut P0=([_:name](ambient (name2cap m) (par (ambient (name2cap _) (par (cap_act (out_cap (name2cap m)) (x2 _)) (x1 _))) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [ Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [ Apply notin_proc_act; [Apply notin_cap_out; Apply notin_cap_name | Idtac] | Idtac]] | Idtac]]); Auto].
Cut Q0=([_:name](par (ambient (name2cap _) (par (x2 _) (x1 _))) (ambient (name2cap m) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]); Auto].
Rewrite H15; Rewrite H16; Apply red_out.
Cut P0=([_:name](ambient (name2cap m) (par (ambient (name2cap n) (par (cap_act (out_cap (name2cap m)) (x2 _)) (x1 _))) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [ Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [ Apply notin_proc_act; [Apply notin_cap_out; Apply notin_cap_name | Idtac] | Idtac]] | Idtac]]); Auto].
Cut Q0=([_:name](par (ambient (name2cap n) (par (x2 _) (x1 _))) (ambient (name2cap m) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H5; Inversion_clear H6; Inversion_clear H7; Inversion_clear H8; Inversion_clear H10; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]); Auto].
Rewrite H15; Rewrite H16; Apply red_out.

Elim (proc_exp P x); Elim (proc_exp Q x); Intros.
Inversion_clear H7; Inversion_clear H8.
Rewrite H10 in H2; Rewrite H10 in H3; Rewrite H11 in H2; Rewrite H11 in H3.
Elim (dec_name n x); Intros.
Rewrite H8 in H2.
Cut P0=([_:name](par (cap_act (open (name2cap _)) (x1 _)) (ambient (name2cap _) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H7; Inversion_clear H9; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_act; [Apply notin_cap_open; Apply notin_cap_name | Idtac] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]); Auto].
Cut Q0=([_:name](par (x1 _) (x0 _))); [Intro | Apply proc_ext with x; Inversion_clear H7; Inversion_clear H9; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par); Auto].
Rewrite H12; Rewrite H13; Apply red_open.
Cut P0=([_:name](par (cap_act (open (name2cap n)) (x1 _)) (ambient (name2cap n) (x0 _)))); [Intro | Apply proc_ext with x; Inversion_clear H7; Inversion_clear H9; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_act; [Apply notin_cap_open; Apply notin_cap_name | Idtac] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]); Auto].
Cut Q0=([_:name](par (x1 _) (x0 _))); [Intro | Apply proc_ext with x; Inversion_clear H7; Inversion_clear H9; Try (Apply notin_proc_nu; Intros; Apply notin_proc_par); Auto].
Rewrite H12; Rewrite H13; Apply red_open.

Elim (ho_proc_exp P x); Elim (proc_exp P' x); Elim (cap_exp M x); Intros.
Inversion_clear H8; Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H0; Rewrite H13 in H0; Rewrite H14 in H0; Rewrite H12 in H3; Rewrite H14 in H3; Rewrite H13 in H4.
Cut P0=([_:name](par (in_act (x2 _)) (out_act (x0 _)))); [Intro | Apply proc_ext with x; Try (Unfold notin_ho_cap in H11; Inversion_clear H9; Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_in; Intros; Cut (notin_proc x (nu (x2 n))); [Intro | Auto]; Inversion_clear H16 | Apply notin_proc_out]); Auto].
Cut Q=x1; [Intro | Apply proc_ext with x; Auto].
Rewrite H10; Rewrite H15; Apply red_comm; Apply SUBST_PROC_RW with x; Assumption.

Elim (ho_proc_exp P x); Elim (ho_proc_exp Q x); Intros.
Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H5; Rewrite H13 in H4.
Cut P0=([_:name](nu (x1 _))); [Intro | Apply proc_ext with x; Auto].
Cut Q0=([_:name](nu (x0 _))); [Intro | Apply proc_ext with x; Auto].
Rewrite H10; Rewrite H14; Apply red_res with (cons x (cons y l)); Intros.
Inversion_clear H15; Inversion_clear H19.
Change (red ([_:name](x1 _ n) y) ([_:name](x0 _ n) y)); Apply H1 with n x; [Assumption | Cut (notin_proc n (nu [_:name](nu (x1 _)))); [Intro | Apply NOTIN_PROC_MONO with y; Assumption]; Inversion_clear H19; Rewrite H13; Auto | Cut (notin_proc n (nu [_:name](nu (x0 _)))); [Intro | Apply NOTIN_PROC_MONO with y; Assumption]; Inversion_clear H19; Rewrite H12; Auto | Inversion_clear H9; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x1 n0))); [Intro | Auto]; Inversion_clear H21; Auto | Inversion_clear H11; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x0 n0))); [Intro | Auto]; Inversion_clear H21; Auto | Rewrite <-H13; Trivial | Rewrite <-H12; Trivial | Assumption | Rewrite H10 in H7; Inversion_clear H7; Apply notin_proc_nu; Intros; Cut (notin_proc y (nu (x1 n0))); [Intro | Auto]; Inversion_clear H21; Auto | Rewrite H14 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc y (nu (x0 n0))); [Intro | Auto]; Inversion_clear H21; Auto].

Elim (proc_exp P x); Elim (proc_exp Q x); Elim (proc_exp R x); Intros.
Inversion_clear H9; Inversion_clear H10; Inversion_clear H11.
Rewrite H13 in H4; Rewrite H13 in H5; Rewrite H14 in H5; Rewrite H15 in H4.
Cut P0=([_:name](par (x2 _) (x0 _))); [Intro | Apply proc_ext with x; Try (Inversion_clear H10; Inversion_clear H12; Apply notin_proc_nu; Intros; Apply notin_proc_par); Auto].
Cut Q0=([_:name](par (x1 _) (x0 _))); [Intro | Apply proc_ext with x; Try (Inversion_clear H9; Inversion_clear H12; Apply notin_proc_nu; Intros; Apply notin_proc_par); Auto].
Rewrite H11; Rewrite H16; Apply red_par; Apply H1 with x; [Assumption | Assumption | Rewrite H15; Trivial | Rewrite H14; Trivial | Assumption | Rewrite H11 in H7; Inversion_clear H7; Apply notin_proc_nu; Intros; Cut (notin_proc y (par (x2 n) (x0 n))); [Intro | Auto]; Inversion_clear H18; Auto | Rewrite H16 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc y (par (x1 n) (x0 n))); [Intro | Auto]; Inversion_clear H18; Auto].

Elim (proc_exp P x); Elim (proc_exp Q x); Intros.
Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H5; Rewrite H13 in H4; Elim (dec_name n x); Intros.
Rewrite H10 in H4; Rewrite H10 in H5.
Cut P0=([_:name](ambient (name2cap _) (x1 _))); [Intro | Apply proc_ext with x; Try (Inversion_clear H9; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Cut Q0=([_:name](ambient (name2cap _) (x0 _))); [Intro | Apply proc_ext with x; Try (Inversion_clear H11; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Rewrite H14; Rewrite H15; Apply red_amb; Apply H1 with x; [Assumption | Assumption | Rewrite H13; Trivial | Rewrite H12; Trivial | Assumption | Rewrite H14 in H7; Inversion_clear H7; Apply notin_proc_nu; Intros; Cut (notin_proc y (ambient (name2cap n0) (x1 n0))); [Intro | Auto]; Inversion_clear H17; Auto | Rewrite H15 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc y (ambient (name2cap n0) (x0 n0))); [Intro | Auto]; Inversion_clear H17; Auto].
Cut P0=([_:name](ambient (name2cap n) (x1 _))); [Intro | Apply proc_ext with x; Try (Inversion_clear H9; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Cut Q0=([_:name](ambient (name2cap n) (x0 _))); [Intro | Apply proc_ext with x; Try (Inversion_clear H11; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]); Auto].
Rewrite H14; Rewrite H15; Apply red_amb; Apply H1 with x; [Assumption | Assumption | Rewrite H13; Trivial | Rewrite H12; Trivial | Assumption | Rewrite H14 in H7; Inversion_clear H7; Apply notin_proc_nu; Intros; Cut (notin_proc y (ambient (name2cap n) (x1 n0))); [Intro | Auto]; Inversion_clear H17; Auto | Rewrite H15 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc y (ambient (name2cap n) (x0 n0))); [Intro | Auto]; Inversion_clear H17; Auto].

Elim (proc_exp P x); Elim (proc_exp Q x); Intros.
Inversion_clear H11; Inversion_clear H12.
Rewrite H14 in H3; Rewrite H15 in H2; Rewrite H6 in H2; Rewrite H7 in H3.
Cut ((notin_proc y (x1 x))->(notin_proc y (P0 x))) /\ ((notin_proc y (P0 x))->(notin_proc y (x1 x))); [Intro | Apply STRUCT_NOTIN; Assumption].
Cut ((notin_proc y (x0 x))->(notin_proc y (Q0 x))) /\ ((notin_proc y (Q0 x))->(notin_proc y (x0 x))); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion_clear H9; Inversion_clear H10; Inversion_clear H12; Inversion_clear H16; Cut (notin_proc y (P0 x)); [Intro | Auto]; Cut (notin_proc y (Q0 x)); [Intro | Auto].
Cut (notin_proc y (x0 x)); [Intro | Auto]; Cut (notin_proc y (x1 x)); [Intro | Auto].
Apply red_struct_eq with (x1 y) (x0 y).
Rewrite H14 in H0; Rewrite H15 in H0; Apply H1 with x; Try (Apply NOTIN_PROC_MONO with x; Assumption); Auto.
Apply STRUCT_RW with x; Try (Apply NOTIN_PROC_MONO with x; Assumption); Auto.
Apply STRUCT_RW with x; Try (Apply NOTIN_PROC_MONO with x; Assumption); Auto.

Qed.

Lemma RED_RW: (P,Q:name->proc)(x:name)
              (notin_proc x (nu P)) -> (notin_proc x (nu Q)) ->
              (red (P x) (Q x)) ->
              (y:name)
              (notin_proc y (nu P)) -> (notin_proc y (nu Q)) ->
              (red (P y) (Q y)).

Proof.

Intros; Elim (dec_name x y); Intros.
Rewrite <-H4; Assumption.
Apply PRE_RED_RW with (P x) (Q x) x; Auto.

Qed.

Lemma NEST_RW: (P,Q:name->proc)(x:name)
               (notin_proc x (nu P)) -> (notin_proc x (nu Q)) ->
               (nest (P x) (Q x)) ->
               (y:name)
               (notin_proc y (nu P)) -> (notin_proc y (nu Q)) ->
               (nest (P y) (Q y)).

Proof.

Intros; Elim (dec_name x y); Intros.
Rewrite <-H4; Assumption.
Unfold nest in H1; Unfold nest.
Inversion_clear H1; Inversion_clear H5.
Elim (proc_exp x1 x); Intros.
Inversion_clear H5.
Rewrite H7 in H1.
Cut ((notin_proc y (P x)) -> (notin_proc y (par (ambient (name2cap x0) (Q x)) (x2 x)))) /\ ((notin_proc y (par (ambient (name2cap x0) (Q x)) (x2 x))) -> (notin_proc y (P x))); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion H2; Inversion_clear H5.
Cut (notin_proc y (par (ambient (name2cap x0) (Q x)) (x2 x))); [Intro | Auto].
Elim (dec_name x0 x); Intros.
Rewrite H12 in H1; Exists y; Exists (x2 y).
Change (struct_eq (P y) ([_:name](par (ambient (name2cap _) (Q _)) (x2 _)) y)); Apply STRUCT_RW with x; Auto.
Inversion_clear H0; Inversion_clear H6; Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Idtac] | Idtac]; Auto.
Rewrite H12 in H5; Apply NOTIN_PROC_MONO with x; Assumption.
Exists x0; Exists (x2 y).
Change (struct_eq (P y) ([_:name](par (ambient (name2cap x0) (Q _)) (x2 _)) y)); Apply STRUCT_RW with x; Auto.
Inversion_clear H0; Inversion_clear H6; Apply notin_proc_nu; Intros; Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Idtac] | Idtac]; Auto.
Apply NOTIN_PROC_MONO with x; Assumption.

Qed.

Lemma SUBST_CAP_NOTIN: (M:cap)(N:name->cap)(N':cap)
                       (subst_cap M N N') ->
                       (x:name)(notin_cap x M) ->
                       (notin_ho_cap x N) -> (notin_cap x N').

Proof.

Induction 1; Intros.

Assumption.

Unfold notin_ho_cap in H1; Elim (UNSAT_PROC_NLIST nil (cons x empty)); Intros.
Inversion_clear H2; Clear H3; Inversion_clear H4; Clear H3; Cut (notin_cap x (name2cap n)); [Intro; Assumption | Apply H1 with x0; Auto].

Apply notin_cap_in; Apply H1; Try (Unfold notin_ho_cap; Intros; Unfold notin_ho_cap in H3; Cut (notin_cap x (in_cap (N0 m))); [Intro | Auto]; Inversion_clear H5; Assumption); Auto.

Apply notin_cap_out; Apply H1; Try (Unfold notin_ho_cap; Intros; Unfold notin_ho_cap in H3; Cut (notin_cap x (out_cap (N0 m))); [Intro | Auto]; Inversion_clear H5; Assumption); Auto.

Apply notin_cap_open; Apply H1; Try (Unfold notin_ho_cap; Intros; Unfold notin_ho_cap in H3; Cut (notin_cap x (open (N0 m))); [Intro | Auto]; Inversion_clear H5; Assumption); Auto.

Apply notin_cap_eps.

Apply notin_cap_path; [Apply H1 | Apply H3]; Try (Unfold notin_ho_cap; Intros; Unfold notin_ho_cap in H5; Cut (notin_cap x (path (N0 m) (O m))); [Intro | Auto]; Inversion_clear H7; Assumption); Auto.

Qed.

Lemma SUBST_PROC_NOTIN: (M:cap)(A:name->proc)(B:proc)
                        (subst_proc M A B) ->
                        (x:name)(notin_cap x M) ->
                        (notin_proc x (nu A)) -> (notin_proc x B).

Proof.

Induction 1; Intros.

Apply notin_proc_nu; Intros; Apply H1; Try (Inversion_clear H3; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (P n0))); [Intro | Auto]; Inversion_clear H6); Auto.

Apply notin_proc_nil.

Apply notin_proc_par; [Apply H1 | Apply H3]; Try (Inversion_clear H5; Apply notin_proc_nu; Intros; Cut (notin_proc x (par (P n) (Q n))); [Intro | Auto]; Inversion_clear H7); Auto.

Apply notin_proc_bang; Apply H1; Try (Inversion_clear H3; Apply notin_proc_nu; Intros; Cut (notin_proc x (bang (P n))); [Intro | Auto]; Inversion_clear H5); Auto.

Apply notin_proc_amb; [Apply SUBST_CAP_NOTIN with M N; Try (Inversion_clear H4; Unfold notin_ho_cap; Intros; Cut (notin_proc x (ambient (N m) (P m))); [Intro | Auto]; Inversion_clear H6; Assumption) | Apply H2; Try (Inversion_clear H4; Apply notin_proc_nu; Intros; Cut (notin_proc x (ambient (N n) (P n))); [Intro | Auto]; Inversion_clear H6; Assumption)]; Auto.

Apply notin_proc_act; [Apply SUBST_CAP_NOTIN with M N; Try (Inversion_clear H4; Unfold notin_ho_cap; Intros; Cut (notin_proc x (cap_act (N m) (P m))); [Intro | Auto]; Inversion_clear H6; Assumption) | Apply H2; Try (Inversion_clear H4; Apply notin_proc_nu; Intros; Cut (notin_proc x (cap_act (N n) (P n))); [Intro | Auto]; Inversion_clear H6; Assumption)]; Auto.

Apply notin_proc_in; Intros; Apply H1; Try (Inversion_clear H3; Apply notin_proc_nu; Intros; Cut (notin_proc x (in_act (P n0))); [Intro | Auto]; Inversion_clear H6); Auto.

Apply notin_proc_out; Apply SUBST_CAP_NOTIN with M N; Try (Inversion_clear H2; Unfold notin_ho_cap; Intros; Cut (notin_proc x (out_act (N m))); [Intro | Auto]; Inversion_clear H4; Assumption); Auto.

Qed.

Lemma RED_NOTIN: (A,B:proc)(red A B) ->
                 (x:name)(notin_proc x A)->(notin_proc x B).

Proof.

Induction 1; Intros.

Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; Inversion_clear H0; Inversion_clear H1; Inversion_clear H3; Inversion_clear H1; Clear H3.
Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par] | Idtac]]; Auto.

Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; Inversion_clear H1; Inversion_clear H4; Inversion_clear H1; Inversion_clear H2; Clear H4.
Apply notin_proc_par; [Apply notin_proc_amb; [Apply notin_cap_name | Apply notin_proc_par] | Apply notin_proc_amb; [Apply notin_cap_name | Idtac]]; Auto.

Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; Clear H0; Inversion_clear H1.
Apply notin_proc_par; Assumption.

Inversion_clear H1; Inversion_clear H3; Apply SUBST_PROC_NOTIN with M P; Try (Inversion_clear H2; Apply notin_proc_nu; Intros; Auto); Auto.

Elim (UNSAT_PROC_NLIST (par (nu P) (nu Q)) (cons x l)); Intros.
Inversion_clear H3; Inversion_clear H4; Inversion_clear H5.
Cut (notin_proc x (Q x0)); [Intro | Inversion_clear H2; Apply H1; Auto].
Apply NOTIN_PROC_MONO with x0; Assumption.

Inversion_clear H2; Cut (notin_proc x Q); [Intro; Apply notin_proc_par; Assumption | Auto].

Inversion_clear H2; Cut (notin_proc x Q); [Intro; Apply notin_proc_amb; Assumption | Auto].

Cut ((notin_proc x P) -> (notin_proc x P')) /\ ((notin_proc x P')->(notin_proc x P)); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion_clear H5; Cut (notin_proc x P); [Intro | Auto].
Cut (notin_proc x Q); [Intro | Auto].
Cut ((notin_proc x Q) -> (notin_proc x Q')) /\ ((notin_proc x Q')->(notin_proc x Q)); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion_clear H9; Auto.

Qed.

Lemma RED_STAR_NOTIN: (A,B:proc)(red_star A B) ->
                      (x:name)(notin_proc x A)->(notin_proc x B).

Proof.

Induction 1; Intros.

Apply RED_NOTIN with P; Assumption.

Assumption.

Auto.

Qed.

Lemma PRE_RED_STAR_RW: (A,B:proc)(red_star A B) ->
                       (P,Q:name->proc)(x:name)
                       (notin_proc x (nu P)) -> (notin_proc x (nu Q)) ->
                       A=(P x) -> B=(Q x) ->
                       (y:name)~x=y ->
                       (notin_proc y (nu P)) -> (notin_proc y (nu Q)) ->
                       (red_star (P y) (Q y)).

Proof.

Induction 1; Intros.

Elim (proc_exp P x); Elim (proc_exp Q x); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H4; Rewrite H12 in H3.
Cut P0=x1; [Intro | Apply proc_ext with x; Auto].
Cut Q0=x0; [Intro | Apply proc_ext with x; Auto].
Rewrite H11 in H0; Rewrite H12 in H0; Rewrite H9; Rewrite H13; Apply base_red; Apply RED_RW with x; Auto.
Rewrite <-H9; Assumption.
Rewrite <-H13; Assumption.

Rewrite H3 in H2; Cut P0=Q; [Intro | Apply proc_ext with x; Auto].
Rewrite H7; Apply red_refl.

Elim (proc_exp Q x); Intros.
Inversion_clear H11; Cut (z:name)(notin_proc z P) -> (notin_proc z Q); [Intro | Intros; Apply RED_STAR_NOTIN with P; Assumption].
Cut (notin_proc y P); [Intro | Rewrite H6; Inversion_clear H9; Auto].
Cut (notin_proc y Q); [Intro | Auto].
Rewrite H13 in H15; Apply red_trans with (x0 y); [Apply H1 with x | Apply H3 with x]; Auto.
Apply NOTIN_PROC_MONO with x; Assumption.
Apply NOTIN_PROC_MONO with x; Assumption.

Qed.

Lemma RED_STAR_RW: (P,Q:name->proc)(x:name)
                   (notin_proc x (nu P)) -> (notin_proc x (nu Q)) ->
                   (red_star (P x) (Q x)) ->
                   (y:name)
                   (notin_proc y (nu P)) -> (notin_proc y (nu Q)) ->
                   (red_star (P y) (Q y)).

Proof.

Intros; Elim (dec_name x y); Intros.
Rewrite <-H4; Assumption.
Apply PRE_RED_STAR_RW with (P x) (Q x) x; Auto.

Qed.

Lemma NEST_NOTIN: (A,B:proc)(nest A B) ->
                  (x:name)(notin_proc x A)->(notin_proc x B).

Proof.

Induction 1; Intros.

Inversion_clear H0; Cut ((notin_proc x0 A) -> (notin_proc x0 (par (ambient (name2cap x) B) x1))) /\ ((notin_proc x0 (par (ambient (name2cap x) B) x1)) -> (notin_proc x0 A)); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion_clear H0; Cut (notin_proc x0 (par (ambient (name2cap x) B) x1)); [Intro | Auto].
Inversion_clear H0; Inversion_clear H5; Assumption.

Qed.

Lemma NEST_STAR_NOTIN: (A,B:proc)(nest_star A B) ->
                       (x:name)(notin_proc x A)->(notin_proc x B).

Proof.

Induction 1; Intros.

Apply NEST_NOTIN with P; Assumption.

Assumption.

Auto.

Qed.

Lemma PRE_NEST_STAR_RW: (A,B:proc)(nest_star A B) ->
                        (P,Q:name->proc)(x:name)
                        (notin_proc x (nu P)) -> (notin_proc x (nu Q)) ->
                        A=(P x) -> B=(Q x) ->
                        (y:name)~x=y ->
                        (notin_proc y (nu P)) -> (notin_proc y (nu Q)) ->
                        (nest_star (P y) (Q y)).

Proof.

Induction 1; Intros.

Elim (proc_exp P x); Elim (proc_exp Q x); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H4; Rewrite H12 in H3.
Cut P0=x1; [Intro | Apply proc_ext with x; Auto].
Cut Q0=x0; [Intro | Apply proc_ext with x; Auto].
Rewrite H11 in H0; Rewrite H12 in H0; Rewrite H9; Rewrite H13; Apply base_nest; Apply NEST_RW with x; Auto.
Rewrite <-H9; Assumption.
Rewrite <-H13; Assumption.

Rewrite H3 in H2; Cut P0=Q; [Intro | Apply proc_ext with x; Auto].
Rewrite H7; Apply nest_refl.

Elim (proc_exp Q x); Intros.
Inversion_clear H11; Cut (z:name)(notin_proc z P) -> (notin_proc z Q); [Intro | Intros; Apply NEST_STAR_NOTIN with P; Assumption].
Cut (notin_proc y P); [Intro | Rewrite H6; Inversion_clear H9; Auto].
Cut (notin_proc y Q); [Intro | Auto].
Rewrite H13 in H15; Apply nest_trans with (x0 y); [Apply H1 with x | Apply H3 with x]; Auto.
Apply NOTIN_PROC_MONO with x; Assumption.
Apply NOTIN_PROC_MONO with x; Assumption.

Qed.

Lemma NEST_STAR_RW: (P,Q:name->proc)(x:name)
                    (notin_proc x (nu P)) -> (notin_proc x (nu Q)) ->
                    (nest_star (P x) (Q x)) ->
                    (y:name)
                    (notin_proc y (nu P)) -> (notin_proc y (nu Q)) ->
                    (nest_star (P y) (Q y)).

Proof.

Intros; Elim (dec_name x y); Intros.
Rewrite <-H4; Assumption.
Apply PRE_NEST_STAR_RW with (P x) (Q x) x; Auto.

Qed.

Lemma PRE_NOTIN_CAP_VOID: (A:cap)(M:name->cap)(z:name)(notin_ho_cap z M) -> A=(M z) -> (x:name)~x=z -> (notin_ho_cap x M) -> (notin_cap x (M x)) -> (y:name)~x=y -> ~y=z -> (notin_ho_cap y M) -> (notin_cap y (M y)).

Proof.

Induction A; Intros.

Elim (dec_name n z); Intros.
Rewrite H7 in H0; Cut M=name2cap; [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Rewrite H8 in H3; Inversion_clear H3.
Absurd x=x; Auto.
Cut M=([_:name](name2cap n)); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_name); Auto].
Rewrite H8; Rewrite H8 in H6; Unfold notin_ho_cap in H6; Apply H6 with z; Assumption.

Elim (cap_exp c z); Intros.
Inversion_clear H8.
Rewrite H10 in H1; Cut M=([_:name](in_cap (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H9; Unfold notin_ho_cap; Intros; Apply notin_cap_in); Auto].
Rewrite H8; Apply notin_cap_in; Apply H with z x; [Assumption | Assumption  | Assumption | Rewrite H8 in H3; Unfold notin_ho_cap in H3; Unfold notin_ho_cap; Intros; Cut (notin_cap x (in_cap (x0 m))); [Intro | Auto]; Inversion_clear H12; Assumption | Rewrite H8 in H4; Inversion_clear H4; Assumption | Assumption | Assumption | Rewrite H8 in H7; Unfold notin_ho_cap in H7; Unfold notin_ho_cap; Intros; Cut (notin_cap y (in_cap (x0 m))); [Intro | Auto]; Inversion_clear H12; Assumption].

Elim (cap_exp c z); Intros.
Inversion_clear H8.
Rewrite H10 in H1; Cut M=([_:name](out_cap (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H9; Unfold notin_ho_cap; Intros; Apply notin_cap_out); Auto].
Rewrite H8; Apply notin_cap_out; Apply H with z x; [Assumption | Assumption  | Assumption | Rewrite H8 in H3; Unfold notin_ho_cap in H3; Unfold notin_ho_cap; Intros; Cut (notin_cap x (out_cap (x0 m))); [Intro | Auto]; Inversion_clear H12; Assumption | Rewrite H8 in H4; Inversion_clear H4; Assumption | Assumption | Assumption | Rewrite H8 in H7; Unfold notin_ho_cap in H7; Unfold notin_ho_cap; Intros; Cut (notin_cap y (out_cap (x0 m))); [Intro | Auto]; Inversion_clear H12; Assumption].

Elim (cap_exp c z); Intros.
Inversion_clear H8.
Rewrite H10 in H1; Cut M=([_:name](open (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H9; Unfold notin_ho_cap; Intros; Apply notin_cap_open); Auto].
Rewrite H8; Apply notin_cap_open; Apply H with z x; [Assumption | Assumption  | Assumption | Rewrite H8 in H3; Unfold notin_ho_cap in H3; Unfold notin_ho_cap; Intros; Cut (notin_cap x (open (x0 m))); [Intro | Auto]; Inversion_clear H12; Assumption | Rewrite H8 in H4; Inversion_clear H4; Assumption | Assumption | Assumption | Rewrite H8 in H7; Unfold notin_ho_cap in H7; Unfold notin_ho_cap; Intros; Cut (notin_cap y (open (x0 m))); [Intro | Auto]; Inversion_clear H12; Assumption].

Cut M=([_:name]eps); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap; Intros; Apply notin_cap_eps); Auto].
Rewrite H7; Apply notin_cap_eps.

Elim (cap_exp c z); Elim (cap_exp c0 z); Intros.
Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H2; Rewrite H13 in H2.
Cut M=([_:name](path (x1 _) (x0 _))); [Intro | Apply cap_ext with z; Try (Unfold notin_ho_cap in H9; Unfold notin_ho_cap in H11; Unfold notin_ho_cap; Intros; Apply notin_cap_path); Auto].
Rewrite H10; Apply notin_cap_path.
Apply H with z x; [Assumption | Assumption | Assumption | Rewrite H10 in H4; Unfold notin_ho_cap in H4; Unfold notin_ho_cap; Intros; Cut (notin_cap x (path (x1 m) (x0 m))); [Intro | Auto]; Inversion_clear H15; Assumption | Rewrite H10 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H10 in H8; Unfold notin_ho_cap in H8; Unfold notin_ho_cap; Intros; Cut (notin_cap y (path (x1 m) (x0 m))); [Intro | Auto]; Inversion_clear H15; Assumption].
Apply H0 with z x; [Assumption | Assumption | Assumption | Rewrite H10 in H4; Unfold notin_ho_cap in H4; Unfold notin_ho_cap; Intros; Cut (notin_cap x (path (x1 m) (x0 m))); [Intro | Auto]; Inversion_clear H15; Assumption | Rewrite H10 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H10 in H8; Unfold notin_ho_cap in H8; Unfold notin_ho_cap; Intros; Cut (notin_cap y (path (x1 m) (x0 m))); [Intro | Auto]; Inversion_clear H15; Assumption].

Qed.

Lemma PRE_NOTIN_PROC_VOID: (n:nat)(A:proc)(lnp A n) -> (P:name->proc)(z:name)(notin_proc z (nu P)) -> A=(P z) -> (x:name)~x=z -> (notin_proc x (nu P)) -> (notin_proc x (P x)) -> (y:name)~x=y -> ~y=z -> (notin_proc y (nu P)) -> (notin_proc y (P y)).

Proof.

Intro; Pattern n; Apply NAT_IND; Intros.

Cut (lt O (0)); [Intro | Apply LNP_S with A; Assumption].
Inversion_clear H8.

Inversion H0.

Rewrite <-H10 in H2; Elim (ho_proc_exp P0 z); Intros.
Inversion_clear H12.
Rewrite H14 in H2; Cut P=([_:name](nu (x0 _))); [Intro | Apply proc_ext with z; Auto].
Rewrite H12; Rewrite H12 in H8; Inversion_clear H8.
Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons x (cons y (cons z empty)))); Intros.
Inversion_clear H8; Inversion_clear H17; Inversion_clear H18; Inversion_clear H19; Clear H20.
Apply NOTIN_PROC_MONO with x1.
Change (notin_proc y ([_:name](x0 _ x1) y)); Apply H with n1 (x0 z x1) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Auto | Inversion_clear H13; Apply notin_proc_nu; Intros; Cut (notin_proc z (nu (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto | Trivial | Assumption | Rewrite H12 in H4; Inversion_clear H4; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto | Rewrite H12 in H5; Inversion_clear H5; Auto | Assumption | Assumption | Apply notin_proc_nu; Intros; Cut (notin_proc y (nu (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto].

Rewrite <-H9 in H2; Cut P=([_:name]nil); [Intro | Apply proc_ext with z; Try (Apply notin_proc_nu; Intros; Apply notin_proc_nil); Auto].
Rewrite H11; Apply notin_proc_nil.

Rewrite <-H11 in H2; Elim (proc_exp P0 z); Elim (proc_exp Q z); Intros.
Inversion_clear H13; Inversion_clear H14.
Rewrite H16 in H2; Rewrite H17 in H2; Cut P=([_:name](par (x1 _) (x0 _))); [Intro | Apply proc_ext with z; Try (Inversion_clear H13; Inversion_clear H15; Apply notin_proc_nu; Intros; Apply notin_proc_par); Auto].
Rewrite H14; Apply notin_proc_par.
Apply H with n1 (x1 z) z x; [Rewrite <-H12; Omega | Rewrite <-H17; Assumption | Assumption | Trivial | Assumption | Rewrite H14 in H4; Inversion_clear H4; Apply notin_proc_nu; Intros; Cut (notin_proc x (par (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Assumption | Rewrite H14 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H14 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc y (par (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Auto].
Apply H with n2 (x0 z) z x; [Rewrite <-H12; Omega | Rewrite <-H16; Assumption | Assumption | Trivial | Assumption | Rewrite H14 in H4; Inversion_clear H4; Apply notin_proc_nu; Intros; Cut (notin_proc x (par (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Assumption | Rewrite H14 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H14 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc y (par (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Auto].

Rewrite <-H10 in H2; Elim (proc_exp P0 z); Intros.
Inversion_clear H12; Rewrite H14 in H2; Cut P=([_:name](bang (x0 _))); [Intro | Apply proc_ext with z; Try (Inversion_clear H13; Apply notin_proc_nu; Intros; Apply notin_proc_bang); Auto].
Rewrite H12; Apply notin_proc_bang.
Apply H with n1 (x0 z) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Trivial | Assumption | Rewrite H12 in H4; Inversion_clear H4; Apply notin_proc_nu; Intros; Cut (notin_proc x (bang (x0 n2))); [Intro | Auto]; Inversion_clear H16; Assumption | Rewrite H12 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H12 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc y (bang (x0 n2))); [Intro | Auto]; Inversion_clear H16; Auto].

Rewrite <-H10 in H2; Elim (cap_exp M z); Elim (proc_exp P0 z); Intros.
Inversion_clear H12; Inversion_clear H13.
Rewrite H15 in H2; Rewrite H16 in H2.
Cut P=([_:name](ambient (x1 _) (x0 _))); [Intro | Apply proc_ext with z; Try (Unfold notin_ho_cap in H12; Inversion_clear H14; Apply notin_proc_nu; Intros; Apply notin_proc_amb); Auto].
Rewrite H13; Apply notin_proc_amb.
Apply PRE_NOTIN_CAP_VOID with (x1 z) z x; Auto.
Rewrite H13 in H4; Inversion_clear H4; Unfold notin_ho_cap; Intros.
Cut (notin_proc x (ambient (x1 m) (x0 m))); [Intro | Auto].
Inversion_clear H18; Assumption.
Rewrite H13 in H5; Inversion_clear H5; Assumption.
Rewrite H13 in H8; Inversion_clear H8; Unfold notin_ho_cap; Intros.
Cut (notin_proc y (ambient (x1 m) (x0 m))); [Intro | Auto].
Inversion_clear H18; Assumption.
Apply H with n1 (x0 z) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H15; Assumption | Assumption | Trivial | Assumption | Rewrite H13 in H4; Inversion_clear H4; Apply notin_proc_nu; Intros; Cut (notin_proc x (ambient (x1 n2) (x0 n2))); [Intro | Auto]; Inversion_clear H18; Assumption | Rewrite H13 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H13 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc y (ambient (x1 n2) (x0 n2))); [Intro | Auto]; Inversion_clear H18; Assumption].

Rewrite <-H10 in H2; Elim (cap_exp M z); Elim (proc_exp P0 z); Intros.
Inversion_clear H12; Inversion_clear H13.
Rewrite H15 in H2; Rewrite H16 in H2.
Cut P=([_:name](cap_act (x1 _) (x0 _))); [Intro | Apply proc_ext with z; Try (Unfold notin_ho_cap in H12; Inversion_clear H14; Apply notin_proc_nu; Intros; Apply notin_proc_act); Auto].
Rewrite H13; Apply notin_proc_act.
Apply PRE_NOTIN_CAP_VOID with (x1 z) z x; Auto.
Rewrite H13 in H4; Inversion_clear H4; Unfold notin_ho_cap; Intros.
Cut (notin_proc x (cap_act (x1 m) (x0 m))); [Intro | Auto].
Inversion_clear H18; Assumption.
Rewrite H13 in H5; Inversion_clear H5; Assumption.
Rewrite H13 in H8; Inversion_clear H8; Unfold notin_ho_cap; Intros.
Cut (notin_proc y (cap_act (x1 m) (x0 m))); [Intro | Auto].
Inversion_clear H18; Assumption.
Apply H with n1 (x0 z) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H15; Assumption | Assumption | Trivial | Assumption | Rewrite H13 in H4; Inversion_clear H4; Apply notin_proc_nu; Intros; Cut (notin_proc x (cap_act (x1 n2) (x0 n2))); [Intro | Auto]; Inversion_clear H18; Assumption | Rewrite H13 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H13 in H8; Inversion_clear H8; Apply notin_proc_nu; Intros; Cut (notin_proc y (cap_act (x1 n2) (x0 n2))); [Intro | Auto]; Inversion_clear H18; Assumption].

Rewrite <-H10 in H2; Elim (ho_proc_exp P0 z); Intros.
Inversion_clear H12.
Rewrite H14 in H2; Cut P=([_:name](in_act (x0 _))); [Intro | Apply proc_ext with z; Try (Inversion_clear H13; Apply notin_proc_nu; Intros; Apply notin_proc_in; Intros; Cut (notin_proc z (nu (x0 n2))); [Intro | Auto]; Inversion_clear H16); Auto].
Rewrite H12; Rewrite H12 in H8; Inversion_clear H8.
Elim (UNSAT_PROC_NLIST (nu [_:name](nu (x0 _))) (cons x (cons y (cons z empty)))); Intros.
Inversion_clear H8; Inversion_clear H17; Inversion_clear H18; Inversion_clear H19; Clear H20.
Cut (notin_proc y (nu (x0 y))); [Intro; Inversion_clear H19; Apply notin_proc_in; Intros; Auto | Apply NOTIN_PROC_MONO with x1].
Change (notin_proc y ([_:name](x0 _ x1) y)); Apply H with n1 (x0 z x1) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Auto | Inversion_clear H13; Apply notin_proc_nu; Intros; Cut (notin_proc z (nu (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto | Trivial | Assumption | Rewrite H12 in H4; Inversion_clear H4; Apply notin_proc_nu; Intros; Cut (notin_proc x (in_act (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto | Rewrite H12 in H5; Inversion_clear H5; Auto | Assumption | Assumption | Apply notin_proc_nu; Intros; Cut (notin_proc y (in_act (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto].

Rewrite <-H9 in H2; Elim (cap_exp M z); Intros.
Inversion_clear H11; Rewrite H13 in H2.
Cut P=([_:name](out_act (x0 _))); [Intro | Apply proc_ext with z; Try (Unfold notin_ho_cap in H12; Apply notin_proc_nu; Intros; Apply notin_proc_out); Auto].
Rewrite H11; Apply notin_proc_out.
Apply PRE_NOTIN_CAP_VOID with (x0 z) z x; Auto.
Rewrite H11 in H4; Inversion_clear H4; Unfold notin_ho_cap; Intros.
Cut (notin_proc x (out_act (x0 m))); [Intro | Auto].
Inversion_clear H15; Assumption.
Rewrite H11 in H5; Inversion_clear H5; Assumption.
Rewrite H11 in H8; Inversion_clear H8; Unfold notin_ho_cap; Intros.
Cut (notin_proc y (out_act (x0 m))); [Intro | Auto].
Inversion_clear H15; Assumption.

Qed.

Lemma NOTIN_PROC_VOID: (P:name->proc)(x:name)(notin_proc x (nu P)) -> (notin_proc x (P x)) -> (y:name)(notin_proc y (nu P)) -> (notin_proc y (P y)).

Proof.

Intros; Elim (dec_name x y); Intros.
Rewrite <-H2; Assumption.
Elim (UNSAT_PROC_NLIST (nu P) (cons x (cons y empty))); Intros.
Inversion_clear H3; Inversion_clear H5; Inversion_clear H6; Clear H7.
Elim (LNP_TOT (P x0)); Intros.
Apply PRE_NOTIN_PROC_VOID with x1 (P x0) x0 x; Auto.

Qed.

Lemma PRE_NOTIN_FORM_MONO: (n:nat)(A:form)(ln A n) ->
                           (F:name->form)(z:name)(notin_form z (forall F)) ->
                           A=(F z) -> (x,y:name)(notin_form x (F y)) ->
                           (notin_form x (forall F)).

Proof.

Intro; Pattern n; Apply NAT_IND; Intros.

Cut (lt O (0)); [Intro | Apply LN_S with A; Assumption].
Inversion_clear H3.

Inversion H0.

Rewrite <-H4 in H2; Cut F=([_:name]T); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Apply notin_T); Auto].
Rewrite H6; Apply notin_forall; Intros; Apply notin_T.

Rewrite <-H5 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H7.
Rewrite H9 in H2; Cut F=([_:name](neg (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H8; Apply notin_forall; Intros; Apply notin_neg); Auto].
Rewrite H7; Apply notin_forall; Intros; Apply notin_neg.
Cut (notin_form x (forall x0)); [Intro; Inversion_clear H11; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H7 in H3; Inversion_clear H3; Assumption]].

Rewrite <-H6 in H2; Elim (form_exp F0 z); Elim (form_exp G z); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H2; Rewrite H12 in H2.
Cut F=([_:name](Or (x1 _) (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H8; Inversion_clear H10; Apply notin_forall; Intros; Apply notin_Or); Auto].
Rewrite H9; Apply notin_forall; Intros; Apply notin_Or; [Cut (notin_form x (forall x1)) | Cut (notin_form x (forall x0))]; Try (Intro; Inversion_clear H14; Auto).
Apply H with n1 (x1 z) z y; [Rewrite <-H7; Omega | Rewrite <-H12; Assumption | Assumption | Trivial | Rewrite H9 in H3; Inversion_clear H3; Assumption].
Apply H with n2 (x0 z) z y; [Rewrite <-H7; Omega | Rewrite <-H11; Assumption | Assumption | Trivial | Rewrite H9 in H3; Inversion_clear H3; Assumption].

Rewrite <-H4 in H2; Cut F=([_:name]zero); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Apply notin_zero); Auto].
Rewrite H6; Apply notin_forall; Intros; Apply notin_zero.

Rewrite <-H6 in H2; Elim (form_exp F0 z); Elim (form_exp G z); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H2; Rewrite H12 in H2.
Cut F=([_:name](comp (x1 _) (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H8; Inversion_clear H10; Apply notin_forall; Intros; Apply notin_comp); Auto].
Rewrite H9; Apply notin_forall; Intros; Apply notin_comp; [Cut (notin_form x (forall x1)) | Cut (notin_form x (forall x0))]; Try (Intro; Inversion_clear H14; Auto).
Apply H with n1 (x1 z) z y; [Rewrite <-H7; Omega | Rewrite <-H12; Assumption | Assumption | Trivial | Rewrite H9 in H3; Inversion_clear H3; Assumption].
Apply H with n2 (x0 z) z y; [Rewrite <-H7; Omega | Rewrite <-H11; Assumption | Assumption | Trivial | Rewrite H9 in H3; Inversion_clear H3; Assumption].

Rewrite <-H6 in H2; Elim (form_exp F0 z); Elim (form_exp G z); Intros.
Inversion_clear H8; Inversion_clear H9.
Rewrite H11 in H2; Rewrite H12 in H2.
Cut F=([_:name](comp_adj (x1 _) (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H8; Inversion_clear H10; Apply notin_forall; Intros; Apply notin_comp_adj); Auto].
Rewrite H9; Apply notin_forall; Intros; Apply notin_comp_adj; [Cut (notin_form x (forall x1)) | Cut (notin_form x (forall x0))]; Try (Intro; Inversion_clear H14; Auto).
Apply H with n1 (x1 z) z y; [Rewrite <-H7; Omega | Rewrite <-H12; Assumption | Assumption | Trivial | Rewrite H9 in H3; Inversion_clear H3; Assumption].
Apply H with n2 (x0 z) z y; [Rewrite <-H7; Omega | Rewrite <-H11; Assumption | Assumption | Trivial | Rewrite H9 in H3; Inversion_clear H3; Assumption].

Rewrite <-H5 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H7.
Rewrite H9 in H2; Elim (dec_name x0 z); Intros.
Rewrite H7 in H2; Cut F=([_:name](loc _ (x1 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H8; Apply notin_loc); Auto].
Rewrite H10; Apply notin_forall; Intros; Cut (notin_form x (forall x1)); [Intro; Inversion_clear H12; Apply notin_loc; Auto | Idtac].
Apply H with n1 (x1 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H10 in H3; Inversion_clear H3; Assumption].
Cut F=([_:name](loc x0 (x1 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H8; Apply notin_loc); Auto].
Rewrite H10; Apply notin_forall; Intros; Cut (notin_form x (forall x1)); [Intro; Inversion_clear H12; Rewrite H10 in H3; Inversion_clear H3; Apply notin_loc; Auto | Idtac].
Apply H with n1 (x1 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H10 in H3; Inversion_clear H3; Assumption].

Rewrite <-H5 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H7.
Rewrite H9 in H2; Elim (dec_name x0 z); Intros.
Rewrite H7 in H2; Cut F=([_:name](loc_adj (x1 _) _)); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H8; Apply notin_loc_adj); Auto].
Rewrite H10; Apply notin_forall; Intros; Cut (notin_form x (forall x1)); [Intro; Inversion_clear H12; Apply notin_loc_adj; Auto | Idtac].
Apply H with n1 (x1 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H10 in H3; Inversion_clear H3; Assumption].
Cut F=([_:name](loc_adj (x1 _) x0)); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H8; Apply notin_loc_adj); Auto].
Rewrite H10; Apply notin_forall; Intros; Cut (notin_form x (forall x1)); [Intro; Inversion_clear H12; Rewrite H10 in H3; Inversion_clear H3; Apply notin_loc_adj; Auto | Idtac].
Apply H with n1 (x1 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H10 in H3; Inversion_clear H3; Assumption].

Rewrite <-H5 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H7.
Rewrite H9 in H2; Elim (dec_name x0 z); Intros.
Rewrite H7 in H2; Cut F=([_:name](rev _ (x1 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H8; Apply notin_rev); Auto].
Rewrite H10; Apply notin_forall; Intros; Cut (notin_form x (forall x1)); [Intro; Inversion_clear H12; Apply notin_rev; Auto | Idtac].
Apply H with n1 (x1 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H10 in H3; Inversion_clear H3; Assumption].
Cut F=([_:name](rev x0 (x1 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H8; Apply notin_rev); Auto].
Rewrite H10; Apply notin_forall; Intros; Cut (notin_form x (forall x1)); [Intro; Inversion_clear H12; Rewrite H10 in H3; Inversion_clear H3; Apply notin_rev; Auto | Idtac].
Apply H with n1 (x1 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H10 in H3; Inversion_clear H3; Assumption].

Rewrite <-H5 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H7.
Rewrite H9 in H2; Elim (dec_name x0 z); Intros.
Rewrite H7 in H2; Cut F=([_:name](rev_adj (x1 _) _)); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H8; Apply notin_rev_adj); Auto].
Rewrite H10; Apply notin_forall; Intros; Cut (notin_form x (forall x1)); [Intro; Inversion_clear H12; Apply notin_rev_adj; Auto | Idtac].
Apply H with n1 (x1 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H10 in H3; Inversion_clear H3; Assumption].
Cut F=([_:name](rev_adj (x1 _) x0)); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H8; Apply notin_rev_adj); Auto].
Rewrite H10; Apply notin_forall; Intros; Cut (notin_form x (forall x1)); [Intro; Inversion_clear H12; Rewrite H10 in H3; Inversion_clear H3; Apply notin_rev_adj; Auto | Idtac].
Apply H with n1 (x1 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H10 in H3; Inversion_clear H3; Assumption].

Rewrite <-H5 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H7.
Rewrite H9 in H2; Cut F=([_:name](sometime (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H8; Apply notin_forall; Intros; Apply notin_sometime); Auto].
Rewrite H7; Apply notin_forall; Intros; Apply notin_sometime.
Cut (notin_form x (forall x0)); [Intro; Inversion_clear H11; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H7 in H3; Inversion_clear H3; Assumption]].

Rewrite <-H5 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H7.
Rewrite H9 in H2; Cut F=([_:name](somewhere (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H8; Apply notin_forall; Intros; Apply notin_somewhere); Auto].
Rewrite H7; Apply notin_forall; Intros; Apply notin_somewhere.
Cut (notin_form x (forall x0)); [Intro; Inversion_clear H11; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H6; Unfold lt; Apply le_n | Rewrite <-H9; Assumption | Assumption | Trivial | Rewrite H7 in H3; Inversion_clear H3; Assumption]].

Rewrite <-H5 in H2; Elim (ho_form_exp F0 z); Intros.
Inversion_clear H7.
Rewrite H9 in H2; Cut F=([_:name](forall (x0 _))); [Intro | Apply form_ext with z; Auto].
Rewrite H7; Do 2 (Apply notin_forall; Intros).
Rewrite H7 in H3; Inversion_clear H3.
Cut (notin_form x (x0 y n3)); [Intro | Auto].
Elim (UNSAT_FORM_NLIST (forall [_:name](forall (x0 _))) (cons n3 empty)); Intros.
Inversion_clear H13; Inversion_clear H15; Clear H16.
Cut (notin_form x (forall [_:name](x0 _ n3))); [Intro; Inversion_clear H15; Auto | Idtac].
Apply H with n1 (x0 x1 n3) x1 y; [Rewrite <-H6; Unfold lt; Apply le_n | Elim (UNSAT_FORM_NLIST (forall [_:name](forall (x0 _))) (cons x1 (cons z empty))); Intros; Inversion_clear H15; Inversion_clear H17; Inversion_clear H18; Clear H19; Apply LN_RW with (x0 x1 x2) x2; [Change (ln ([_:name](x0 _ x2) x1) n1); Apply LN_RW with (x0 z x2) z; [Rewrite <-H9; Auto | Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form z (forall (x0 n4))); [Intro | Auto]; Inversion_clear H19; Auto | Trivial] | Inversion_clear H16; Apply notin_forall; Intros; Cut (notin_form x2 (forall (x0 x1))); [Intro | Auto]; Inversion_clear H19; Auto | Trivial]; Auto | Inversion_clear H14; Apply notin_forall; Intros; Cut (notin_form x1 (forall (x0 n4))); [Intro | Auto]; Inversion_clear H16; Auto | Trivial | Assumption].

Rewrite <-H5 in H2; Elim (ho_form_exp F0 z); Intros.
Inversion_clear H7.
Rewrite H9 in H2; Cut F=([_:name](new (x0 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Apply notin_new; Intros; Inversion_clear H8; Cut (notin_form z (forall (x0 n2))); [Intro | Auto]; Inversion_clear H8); Auto].
Rewrite H7; Apply notin_forall; Intros; Apply notin_new; Intros.
Rewrite H7 in H3; Inversion_clear H3.
Cut (notin_form x (x0 y n3)); [Intro | Auto].
Elim (UNSAT_FORM_NLIST (forall [_:name](forall (x0 _))) (cons n3 empty)); Intros.
Inversion_clear H13; Inversion_clear H15; Clear H16.
Cut (notin_form x (forall [_:name](x0 _ n3))); [Intro; Inversion_clear H15; Auto | Idtac].
Apply H with n1 (x0 x1 n3) x1 y; [Rewrite <-H6; Unfold lt; Apply le_n | Elim (UNSAT_FORM_NLIST (forall [_:name](forall (x0 _))) (cons x1 (cons z empty))); Intros; Inversion_clear H15; Inversion_clear H17; Inversion_clear H18; Clear H19; Apply LN_RW with (x0 x1 x2) x2; [Change (ln ([_:name](x0 _ x2) x1) n1); Apply LN_RW with (x0 z x2) z; [Rewrite <-H9; Auto | Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form z (forall (x0 n4))); [Intro | Auto]; Inversion_clear H19; Auto | Trivial] | Inversion_clear H16; Apply notin_forall; Intros; Cut (notin_form x2 (forall (x0 x1))); [Intro | Auto]; Inversion_clear H19; Auto | Trivial]; Auto | Inversion_clear H14; Apply notin_forall; Intros; Cut (notin_form x1 (forall (x0 n4))); [Intro | Auto]; Inversion_clear H16; Auto | Trivial | Assumption].

Qed.

Lemma NOTIN_FORM_MONO: (A:name->form)(x,y:name)(notin_form x (A y))->(notin_form x (forall A)).

Proof.

Intros.
Elim (UNSAT_FORM_NLIST (forall A) empty); Intros.
Inversion_clear H0; Clear H2.
Elim (LN_TOT (A x0)); Intros.
Apply PRE_NOTIN_FORM_MONO with x1 (A x0) x0 y; Auto.

Qed.

Lemma PRE_ISIN_FORM_MONO: (n:nat)(A:form)(ln A n) -> (F:name->form)(z:name)(notin_form z (forall F)) -> A=(F z) -> (x,y:name)~x=y -> (isin_form x (F y))->(isin_form x (forall F)).

Proof.

Intro; Pattern n; Apply NAT_IND; Intros.

Cut (lt O (0)); [Intro | Apply LN_S with A; Assumption].
Inversion_clear H4.

Inversion H0.

Rewrite <-H5 in H2; Cut F=([_:name]T); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Apply notin_T); Auto].
Rewrite H7 in H4; Inversion_clear H4.

Rewrite <-H6 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H8; Rewrite H10 in H2.
Cut F=([_:name](neg (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_neg); Auto].
Rewrite H8; Apply isin_forall; Intro; Apply isin_neg.
Cut (isin_form x (forall x0)); [Intro; Inversion_clear H11; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Apply LN_RW with (x0 z) z; [Rewrite <-H10; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Rewrite H8 in H4; Inversion_clear H4; Assumption]].

Rewrite <-H7 in H2; Elim (form_exp F0 z); Elim (form_exp G z); Intros.
Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H2; Rewrite H13 in H2.
Cut F=([_:name](Or (x1 _) (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Inversion_clear H11; Apply notin_forall; Intros; Apply notin_Or); Auto].
Rewrite H10; Rewrite H10 in H4; Apply isin_forall; Intro; Apply isin_Or; Inversion_clear H4; Inversion_clear H14; [Left | Right].
Cut (isin_form x (forall x1)); [Intro; Inversion_clear H14; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H8; Omega | Apply LN_RW with (x1 z) z; [Rewrite <-H13; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Assumption]].
Cut (isin_form x (forall x0)); [Intro; Inversion_clear H14; Auto | Apply H with n2 (x0 z) z y; [Rewrite <-H8; Omega | Apply LN_RW with (x0 z) z; [Rewrite <-H12; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Assumption]].

Rewrite <-H5 in H2; Cut F=([_:name]zero); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Apply notin_zero); Auto].
Rewrite H7 in H4; Inversion_clear H4.

Rewrite <-H7 in H2; Elim (form_exp F0 z); Elim (form_exp G z); Intros.
Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H2; Rewrite H13 in H2.
Cut F=([_:name](comp (x1 _) (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Inversion_clear H11; Apply notin_forall; Intros; Apply notin_comp); Auto].
Rewrite H10; Rewrite H10 in H4; Apply isin_forall; Intro; Apply isin_comp; Inversion_clear H4; Inversion_clear H14; [Left | Right].
Cut (isin_form x (forall x1)); [Intro; Inversion_clear H14; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H8; Omega | Apply LN_RW with (x1 z) z; [Rewrite <-H13; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Assumption]].
Cut (isin_form x (forall x0)); [Intro; Inversion_clear H14; Auto | Apply H with n2 (x0 z) z y; [Rewrite <-H8; Omega | Apply LN_RW with (x0 z) z; [Rewrite <-H12; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Assumption]].

Rewrite <-H7 in H2; Elim (form_exp F0 z); Elim (form_exp G z); Intros.
Inversion_clear H9; Inversion_clear H10.
Rewrite H12 in H2; Rewrite H13 in H2.
Cut F=([_:name](comp_adj (x1 _) (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Inversion_clear H11; Apply notin_forall; Intros; Apply notin_comp_adj); Auto].
Rewrite H10; Rewrite H10 in H4; Apply isin_forall; Intro; Apply isin_comp_adj; Inversion_clear H4; Inversion_clear H14; [Left | Right].
Cut (isin_form x (forall x1)); [Intro; Inversion_clear H14; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H8; Omega | Apply LN_RW with (x1 z) z; [Rewrite <-H13; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Assumption]].
Cut (isin_form x (forall x0)); [Intro; Inversion_clear H14; Auto | Apply H with n2 (x0 z) z y; [Rewrite <-H8; Omega | Apply LN_RW with (x0 z) z; [Rewrite <-H12; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Assumption]].

Rewrite <-H6 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H8.
Rewrite H10 in H2; Elim (dec_name x0 z); Intros.
Rewrite H8 in H2; Cut F=([_:name](loc _ (x1 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_loc); Auto].
Rewrite H11 in H4; Inversion_clear H4; Rewrite H11; Apply isin_forall; Intro; Apply isin_loc.
Inversion_clear H12; [Absurd x=y; Assumption | Right; Cut (isin_form x (forall x1)); [Intro; Inversion_clear H12; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Rewrite <-H10; Assumption | Assumption | Trivial | Assumption | Assumption]]].
Cut F=([_:name](loc x0 (x1 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_loc); Auto].
Rewrite H11 in H4; Inversion_clear H4; Rewrite H11; Apply isin_forall; Intro; Apply isin_loc.
Inversion_clear H12; [Left; Assumption | Right; Cut (isin_form x (forall x1)); [Intro; Inversion_clear H12; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Rewrite <-H10; Assumption | Assumption | Trivial | Assumption | Assumption]]].

Rewrite <-H6 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H8.
Rewrite H10 in H2; Elim (dec_name x0 z); Intros.
Rewrite H8 in H2; Cut F=([_:name](loc_adj (x1 _) _)); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_loc_adj); Auto].
Rewrite H11 in H4; Inversion_clear H4; Rewrite H11; Apply isin_forall; Intro; Apply isin_loc_adj.
Inversion_clear H12; [Absurd x=y; Assumption | Right; Cut (isin_form x (forall x1)); [Intro; Inversion_clear H12; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Rewrite <-H10; Assumption | Assumption | Trivial | Assumption | Assumption]]].
Cut F=([_:name](loc_adj (x1 _) x0)); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_loc_adj); Auto].
Rewrite H11 in H4; Inversion_clear H4; Rewrite H11; Apply isin_forall; Intro; Apply isin_loc_adj.
Inversion_clear H12; [Left; Assumption | Right; Cut (isin_form x (forall x1)); [Intro; Inversion_clear H12; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Rewrite <-H10; Assumption | Assumption | Trivial | Assumption | Assumption]]].

Rewrite <-H6 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H8.
Rewrite H10 in H2; Elim (dec_name x0 z); Intros.
Rewrite H8 in H2; Cut F=([_:name](rev _ (x1 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_rev); Auto].
Rewrite H11 in H4; Inversion_clear H4; Rewrite H11; Apply isin_forall; Intro; Apply isin_rev.
Inversion_clear H12; [Absurd x=y; Assumption | Right; Cut (isin_form x (forall x1)); [Intro; Inversion_clear H12; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Rewrite <-H10; Assumption | Assumption | Trivial | Assumption | Assumption]]].
Cut F=([_:name](rev x0 (x1 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_rev); Auto].
Rewrite H11 in H4; Inversion_clear H4; Rewrite H11; Apply isin_forall; Intro; Apply isin_rev.
Inversion_clear H12; [Left; Assumption | Right; Cut (isin_form x (forall x1)); [Intro; Inversion_clear H12; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Rewrite <-H10; Assumption | Assumption | Trivial | Assumption | Assumption]]].

Rewrite <-H6 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H8.
Rewrite H10 in H2; Elim (dec_name x0 z); Intros.
Rewrite H8 in H2; Cut F=([_:name](rev_adj (x1 _) _)); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_rev_adj); Auto].
Rewrite H11 in H4; Inversion_clear H4; Rewrite H11; Apply isin_forall; Intro; Apply isin_rev_adj.
Inversion_clear H12; [Absurd x=y; Assumption | Right; Cut (isin_form x (forall x1)); [Intro; Inversion_clear H12; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Rewrite <-H10; Assumption | Assumption | Trivial | Assumption | Assumption]]].
Cut F=([_:name](rev_adj (x1 _) x0)); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_rev_adj); Auto].
Rewrite H11 in H4; Inversion_clear H4; Rewrite H11; Apply isin_forall; Intro; Apply isin_rev_adj.
Inversion_clear H12; [Left; Assumption | Right; Cut (isin_form x (forall x1)); [Intro; Inversion_clear H12; Auto | Apply H with n1 (x1 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Rewrite <-H10; Assumption | Assumption | Trivial | Assumption | Assumption]]].

Rewrite <-H6 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H8; Rewrite H10 in H2.
Cut F=([_:name](sometime (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_sometime); Auto].
Rewrite H8; Apply isin_forall; Intro; Apply isin_sometime.
Cut (isin_form x (forall x0)); [Intro; Inversion_clear H11; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Apply LN_RW with (x0 z) z; [Rewrite <-H10; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Rewrite H8 in H4; Inversion_clear H4; Assumption]].

Rewrite <-H6 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H8; Rewrite H10 in H2.
Cut F=([_:name](somewhere (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H9; Apply notin_forall; Intros; Apply notin_somewhere); Auto].
Rewrite H8; Apply isin_forall; Intro; Apply isin_somewhere.
Cut (isin_form x (forall x0)); [Intro; Inversion_clear H11; Auto | Apply H with n1 (x0 z) z y; [Rewrite <-H7; Unfold lt; Apply le_n | Apply LN_RW with (x0 z) z; [Rewrite <-H10; Assumption | Assumption | Trivial] | Assumption | Trivial | Assumption | Rewrite H8 in H4; Inversion_clear H4; Assumption]].

Rewrite <-H6 in H2; Elim (ho_form_exp F0 z); Intros.
Inversion_clear H8; Rewrite H10 in H2.
Cut F=([_:name](forall (x0 _))); [Intro | Apply form_ext with z; Auto].
Rewrite H8; Do 2 (Apply isin_forall; Intro).
Rewrite H8 in H4; Inversion_clear H4.
Cut (isin_form x (x0 y n3)); [Intro | Auto].
Elim (UNSAT_FORM_NLIST (forall [_:name](forall (x0 _))) (cons n3 empty)); Intros.
Inversion_clear H12; Inversion_clear H14; Clear H15.
Cut (isin_form x (forall [_:name](x0 _ n3))); [Intro; Inversion_clear H14; Auto | Idtac].
Apply H with n1 (x0 x1 n3) x1 y; [Rewrite <-H7; Unfold lt; Apply le_n | Elim (UNSAT_FORM_NLIST (forall [_:name](forall (x0 _))) (cons x1 (cons z empty))); Intros; Inversion_clear H14; Inversion_clear H16; Inversion_clear H17; Clear H18; Apply LN_RW with (x0 x1 x2) x2; [Change (ln ([_:name](x0 _ x2) x1) n1); Apply LN_RW with (x0 z x2) z; [Rewrite <-H10; Auto | Inversion_clear H9; Apply notin_forall; Intros; Cut (notin_form z (forall (x0 n4))); [Intro | Auto]; Inversion_clear H18; Auto | Trivial] | Inversion_clear H15; Apply notin_forall; Intros; Cut (notin_form x2 (forall (x0 x1))); [Intro | Auto]; Inversion_clear H18; Auto | Trivial]; Auto | Inversion_clear H13; Apply notin_forall; Intros; Cut (notin_form x1 (forall (x0 n4))); [Intro | Auto]; Inversion_clear H15; Auto | Trivial | Assumption | Assumption].

Rewrite <-H6 in H2; Elim (ho_form_exp F0 z); Intros.
Inversion_clear H8; Rewrite H10 in H2.
Cut F=([_:name](new (x0 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Apply notin_new; Intros; Inversion_clear H9; Cut (notin_form z (forall (x0 n2))); [Intro | Auto]; Inversion_clear H9); Auto].
Rewrite H8; Apply isin_forall; Intro; Apply isin_new; Intro.
Rewrite H8 in H4; Inversion_clear H4.
Cut (isin_form x (x0 y n3)); [Intro | Auto].
Elim (UNSAT_FORM_NLIST (forall [_:name](forall (x0 _))) (cons n3 empty)); Intros.
Inversion_clear H12; Inversion_clear H14; Clear H15.
Cut (isin_form x (forall [_:name](x0 _ n3))); [Intro; Inversion_clear H14; Auto | Idtac].
Apply H with n1 (x0 x1 n3) x1 y; [Rewrite <-H7; Unfold lt; Apply le_n | Elim (UNSAT_FORM_NLIST (forall [_:name](forall (x0 _))) (cons x1 (cons z empty))); Intros; Inversion_clear H14; Inversion_clear H16; Inversion_clear H17; Clear H18; Apply LN_RW with (x0 x1 x2) x2; [Change (ln ([_:name](x0 _ x2) x1) n1); Apply LN_RW with (x0 z x2) z; [Rewrite <-H10; Auto | Inversion_clear H9; Apply notin_forall; Intros; Cut (notin_form z (forall (x0 n4))); [Intro | Auto]; Inversion_clear H18; Auto | Trivial] | Inversion_clear H15; Apply notin_forall; Intros; Cut (notin_form x2 (forall (x0 x1))); [Intro | Auto]; Inversion_clear H18; Auto | Trivial]; Auto | Inversion_clear H13; Apply notin_forall; Intros; Cut (notin_form x1 (forall (x0 n4))); [Intro | Auto]; Inversion_clear H15; Auto | Trivial | Assumption | Assumption].

Qed.

Lemma ISIN_FORM_MONO: (A:name->form)(x,y:name)~x=y -> (isin_form x (A y)) -> (isin_form x (forall A)).

Proof.

Intros.
Elim (UNSAT_FORM_NLIST (forall A) empty); Intros.
Inversion_clear H1; Clear H3.
Elim (LN_TOT (A x0)); Intros.
Apply PRE_ISIN_FORM_MONO with x1 (A x0) x0 y; Auto.

Qed.

Lemma NOTIN_FORM_DEC: (A:form)(n:name)(isin_form n A) \/ (notin_form n A).

Proof.

Induction A; Intros.

Right; Apply notin_T.

Elim (H n); Intros.
Left; Apply isin_neg; Assumption.
Right; Apply notin_neg; Assumption.

Elim (H n); Elim (H0 n); Intros.
Left; Apply isin_Or; Left; Assumption.
Left; Apply isin_Or; Left; Assumption.
Left; Apply isin_Or; Right; Assumption.
Right; Apply notin_Or; Assumption.

Right; Apply notin_zero.

Elim (H n); Elim (H0 n); Intros.
Left; Apply isin_comp; Left; Assumption.
Left; Apply isin_comp; Left; Assumption.
Left; Apply isin_comp; Right; Assumption.
Right; Apply notin_comp; Assumption.

Elim (H n); Elim (H0 n); Intros.
Left; Apply isin_comp_adj; Left; Assumption.
Left; Apply isin_comp_adj; Left; Assumption.
Left; Apply isin_comp_adj; Right; Assumption.
Right; Apply notin_comp_adj; Assumption.

Elim (dec_name n0 n); Intros.
Rewrite H0; Left; Apply isin_loc; Left; Trivial.
Elim (H n0); Intros.
Left; Apply isin_loc; Right; Assumption.
Right; Apply notin_loc; Assumption.

Elim (dec_name n0 n); Intros.
Rewrite H0; Left; Apply isin_loc_adj; Left; Trivial.
Elim (H n0); Intros.
Left; Apply isin_loc_adj; Right; Assumption.
Right; Apply notin_loc_adj; Assumption.

Elim (dec_name n0 n); Intros.
Rewrite H0; Left; Apply isin_rev; Left; Trivial.
Elim (H n0); Intros.
Left; Apply isin_rev; Right; Assumption.
Right; Apply notin_rev; Assumption.

Elim (dec_name n0 n); Intros.
Rewrite H0; Left; Apply isin_rev_adj; Left; Trivial.
Elim (H n0); Intros.
Left; Apply isin_rev_adj; Right; Assumption.
Right; Apply notin_rev_adj; Assumption.

Elim (H n); Intros.
Left; Apply isin_sometime; Assumption.
Right; Apply notin_sometime; Assumption.

Elim (H n); Intros.
Left; Apply isin_somewhere; Assumption.
Right; Apply notin_somewhere; Assumption.

Elim (UNSAT_FORM_NLIST T (cons n empty)); Intros.
Inversion_clear H0; Clear H1; Inversion_clear H2; Clear H1.
Elim (H x n); Intros.
Left; Apply ISIN_FORM_MONO with x; Auto.
Right; Apply NOTIN_FORM_MONO with x; Assumption.

Elim (UNSAT_FORM_NLIST T (cons n empty)); Intros.
Inversion_clear H0; Clear H1; Inversion_clear H2; Clear H1.
Elim (H x n); Intros.
Cut (isin_form n (forall f)); [Intro | Apply ISIN_FORM_MONO with x; Auto].
Inversion_clear H2; Left; Apply isin_new; Intro; Auto.
Cut (notin_form n (forall f)); [Intro | Apply NOTIN_FORM_MONO with x; Auto].
Inversion_clear H2; Right; Apply notin_new; Intros; Auto.

Qed.

Lemma PRE_NOTIN_FORM_VOID: (n:nat)(A:form)(ln A n) -> (F:name->form)(z:name)(notin_form z (forall F)) -> A=(F z) -> (x:name)~x=z -> (notin_form x (forall F)) -> (notin_form x (F x)) -> (y:name)~x=y -> ~y=z -> (notin_form y (forall F)) -> (notin_form y (F y)).

Proof.

Intro; Pattern n; Apply NAT_IND; Intros.

Cut (lt O (0)); [Intro | Apply LN_S with A; Assumption].
Inversion_clear H8.

Inversion H0.

Rewrite <-H9 in H2; Cut F=([_:name]T); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Apply notin_T); Auto].
Rewrite H11; Apply notin_T.

Rewrite <-H10 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H12; Rewrite H14 in H2; Cut F=([_:name](neg (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H13; Apply notin_forall; Intros; Apply notin_neg); Auto].
Rewrite H12; Apply notin_neg.
Apply H with n1 (x0 z) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Trivial | Assumption | Rewrite H12 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (neg (x0 n2))); [Intro | Auto]; Inversion_clear H16; Assumption | Rewrite H12 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (neg (x0 n2))); [Intro | Auto]; Inversion_clear H16; Auto].

Rewrite <-H11 in H2; Elim (form_exp F0 z); Elim (form_exp G z); Intros.
Inversion_clear H13; Inversion_clear H14.
Rewrite H16 in H2; Rewrite H17 in H2; Cut F=([_:name](Or (x1 _) (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H13; Inversion_clear H15; Apply notin_forall; Intros; Apply notin_Or); Auto].
Rewrite H14; Apply notin_Or.
Apply H with n1 (x1 z) z x; [Rewrite <-H12; Omega | Rewrite <-H17; Assumption | Assumption | Trivial | Assumption | Rewrite H14 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (Or (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Assumption | Rewrite H14 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (Or (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Auto].
Apply H with n2 (x0 z) z x; [Rewrite <-H12; Omega | Rewrite <-H16; Assumption | Assumption | Trivial | Assumption | Rewrite H14 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (Or (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Assumption | Rewrite H14 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (Or (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Auto].

Rewrite <-H9 in H2; Cut F=([_:name]zero); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Apply notin_zero); Auto].
Rewrite H11; Apply notin_zero.

Rewrite <-H11 in H2; Elim (form_exp F0 z); Elim (form_exp G z); Intros.
Inversion_clear H13; Inversion_clear H14.
Rewrite H16 in H2; Rewrite H17 in H2; Cut F=([_:name](comp (x1 _) (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H13; Inversion_clear H15; Apply notin_forall; Intros; Apply notin_comp); Auto].
Rewrite H14; Apply notin_comp.
Apply H with n1 (x1 z) z x; [Rewrite <-H12; Omega | Rewrite <-H17; Assumption | Assumption | Trivial | Assumption | Rewrite H14 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (comp (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Assumption | Rewrite H14 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (comp (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Auto].
Apply H with n2 (x0 z) z x; [Rewrite <-H12; Omega | Rewrite <-H16; Assumption | Assumption | Trivial | Assumption | Rewrite H14 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (comp (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Assumption | Rewrite H14 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (comp (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Auto].

Rewrite <-H11 in H2; Elim (form_exp F0 z); Elim (form_exp G z); Intros.
Inversion_clear H13; Inversion_clear H14.
Rewrite H16 in H2; Rewrite H17 in H2; Cut F=([_:name](comp_adj (x1 _) (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H13; Inversion_clear H15; Apply notin_forall; Intros; Apply notin_comp_adj); Auto].
Rewrite H14; Apply notin_comp_adj.
Apply H with n1 (x1 z) z x; [Rewrite <-H12; Omega | Rewrite <-H17; Assumption | Assumption | Trivial | Assumption | Rewrite H14 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (comp_adj (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Assumption | Rewrite H14 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (comp_adj (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Auto].
Apply H with n2 (x0 z) z x; [Rewrite <-H12; Omega | Rewrite <-H16; Assumption | Assumption | Trivial | Assumption | Rewrite H14 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (comp_adj (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Assumption | Rewrite H14 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (comp_adj (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H19; Auto].

Rewrite <-H10 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H12.
Rewrite H14 in H2; Elim (dec_name x0 z); Intros.
Rewrite H12 in H2; Cut F=([_:name](loc _ (x1 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H13; Apply notin_loc); Auto].
Rewrite H15 in H5; Inversion_clear H5; Absurd x=x; Auto.
Cut F=([_:name](loc x0 (x1 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H13; Apply notin_loc); Auto].
Rewrite H15; Apply notin_loc; Try (Rewrite H15 in H8; Inversion_clear H8; Cut (notin_form y (loc x0 (x1 x))); [Intro | Auto]; Inversion_clear H8; Auto).
Apply H with n1 (x1 z) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Trivial | Assumption | Rewrite H15 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (loc x0 (x1 n2))); [Intro | Auto]; Inversion_clear H19; Auto | Rewrite H15 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Apply NOTIN_FORM_MONO with x; Assumption].

Rewrite <-H10 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H12.
Rewrite H14 in H2; Elim (dec_name x0 z); Intros.
Rewrite H12 in H2; Cut F=([_:name](loc_adj (x1 _) _)); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H13; Apply notin_loc_adj); Auto].
Rewrite H15 in H5; Inversion_clear H5; Absurd x=x; Auto.
Cut F=([_:name](loc_adj (x1 _) x0)); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H13; Apply notin_loc_adj); Auto].
Rewrite H15; Apply notin_loc_adj; Try (Rewrite H15 in H8; Inversion_clear H8; Cut (notin_form y (loc_adj (x1 x) x0)); [Intro | Auto]; Inversion_clear H8; Auto).
Apply H with n1 (x1 z) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Trivial | Assumption | Rewrite H15 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (loc_adj (x1 n2) x0)); [Intro | Auto]; Inversion_clear H19; Auto | Rewrite H15 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Apply NOTIN_FORM_MONO with x; Assumption].

Rewrite <-H10 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H12.
Rewrite H14 in H2; Elim (dec_name x0 z); Intros.
Rewrite H12 in H2; Cut F=([_:name](rev _ (x1 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H13; Apply notin_rev); Auto].
Rewrite H15 in H5; Inversion_clear H5; Absurd x=x; Auto.
Cut F=([_:name](rev x0 (x1 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H13; Apply notin_rev); Auto].
Rewrite H15; Apply notin_rev; Try (Rewrite H15 in H8; Inversion_clear H8; Cut (notin_form y (rev x0 (x1 x))); [Intro | Auto]; Inversion_clear H8; Auto).
Apply H with n1 (x1 z) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Trivial | Assumption | Rewrite H15 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (rev x0 (x1 n2))); [Intro | Auto]; Inversion_clear H19; Auto | Rewrite H15 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Apply NOTIN_FORM_MONO with x; Assumption].

Rewrite <-H10 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H12.
Rewrite H14 in H2; Elim (dec_name x0 z); Intros.
Rewrite H12 in H2; Cut F=([_:name](rev_adj (x1 _) _)); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H13; Apply notin_rev_adj); Auto].
Rewrite H15 in H5; Inversion_clear H5; Absurd x=x; Auto.
Cut F=([_:name](rev_adj (x1 _) x0)); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Inversion_clear H13; Apply notin_rev_adj); Auto].
Rewrite H15; Apply notin_rev_adj; Try (Rewrite H15 in H8; Inversion_clear H8; Cut (notin_form y (rev_adj (x1 x) x0)); [Intro | Auto]; Inversion_clear H8; Auto).
Apply H with n1 (x1 z) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Trivial | Assumption | Rewrite H15 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (rev_adj (x1 n2) x0)); [Intro | Auto]; Inversion_clear H19; Auto | Rewrite H15 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Apply NOTIN_FORM_MONO with x; Assumption].

Rewrite <-H10 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H12; Rewrite H14 in H2; Cut F=([_:name](sometime (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H13; Apply notin_forall; Intros; Apply notin_sometime); Auto].
Rewrite H12; Apply notin_sometime.
Apply H with n1 (x0 z) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Trivial | Assumption | Rewrite H12 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (sometime (x0 n2))); [Intro | Auto]; Inversion_clear H16; Assumption | Rewrite H12 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (sometime (x0 n2))); [Intro | Auto]; Inversion_clear H16; Auto].

Rewrite <-H10 in H2; Elim (form_exp F0 z); Intros.
Inversion_clear H12; Rewrite H14 in H2; Cut F=([_:name](somewhere (x0 _))); [Intro | Apply form_ext with z; Try (Inversion_clear H13; Apply notin_forall; Intros; Apply notin_somewhere); Auto].
Rewrite H12; Apply notin_somewhere.
Apply H with n1 (x0 z) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Trivial | Assumption | Rewrite H12 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (somewhere (x0 n2))); [Intro | Auto]; Inversion_clear H16; Assumption | Rewrite H12 in H5; Inversion_clear H5; Assumption | Assumption | Assumption | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (somewhere (x0 n2))); [Intro | Auto]; Inversion_clear H16; Auto].

Rewrite <-H10 in H2; Elim (ho_form_exp F0 z); Intros.
Inversion_clear H12.
Rewrite H14 in H2; Cut F=([_:name](forall (x0 _))); [Intro | Apply form_ext with z; Auto].
Rewrite H12; Rewrite H12 in H8; Inversion_clear H8.
Elim (UNSAT_FORM_NLIST (forall [_:name](forall (x0 _))) (cons x (cons y (cons z empty)))); Intros.
Inversion_clear H8; Inversion_clear H17; Inversion_clear H18; Inversion_clear H19; Clear H20.
Apply NOTIN_FORM_MONO with x1.
Change (notin_form y ([_:name](x0 _ x1) y)); Apply H with n1 (x0 z x1) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Auto | Inversion_clear H13; Apply notin_forall; Intros; Cut (notin_form z (forall (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto | Trivial | Assumption | Rewrite H12 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (forall (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto | Rewrite H12 in H5; Inversion_clear H5; Auto | Assumption | Assumption | Apply notin_forall; Intros; Cut (notin_form y (forall (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto].

Rewrite <-H10 in H2; Elim (ho_form_exp F0 z); Intros.
Inversion_clear H12.
Rewrite H14 in H2; Cut F=([_:name](new (x0 _))); [Intro | Apply form_ext with z; Try (Apply notin_forall; Intros; Apply notin_new; Intros; Inversion_clear H13; Cut (notin_form z (forall (x0 n2))); [Intro | Auto]; Inversion_clear H13); Auto].
Rewrite H12; Rewrite H12 in H8; Inversion_clear H8.
Elim (UNSAT_FORM_NLIST (forall [_:name](forall (x0 _))) (cons x (cons y (cons z empty)))); Intros.
Inversion_clear H8; Inversion_clear H17; Inversion_clear H18; Inversion_clear H19; Clear H20.
Cut (notin_form y (forall (x0 y))); [Intro; Inversion_clear H19; Apply notin_new; Intros; Auto | Apply NOTIN_FORM_MONO with x1].
Change (notin_form y ([_:name](x0 _ x1) y)); Apply H with n1 (x0 z x1) z x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Auto | Inversion_clear H13; Apply notin_forall; Intros; Cut (notin_form z (forall (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto | Trivial | Assumption | Rewrite H12 in H4; Inversion_clear H4; Apply notin_forall; Intros; Cut (notin_form x (new (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto | Rewrite H12 in H5; Inversion_clear H5; Auto | Assumption | Assumption | Apply notin_forall; Intros; Cut (notin_form y (new (x0 n2))); [Intro | Auto]; Inversion_clear H20; Auto].

Qed.

Lemma NOTIN_FORM_VOID: (A:name->form)(x:name)(notin_form x (forall A)) -> (notin_form x (A x)) -> (y:name)(notin_form y (forall A)) -> (notin_form y (A y)).

Proof.

Intros; Elim (dec_name x y); Intros.
Rewrite <-H2; Assumption.
Elim (UNSAT_FORM_NLIST (forall A) (cons x (cons y empty))); Intros.
Inversion_clear H3; Inversion_clear H5; Inversion_clear H6; Clear H7.
Elim (LN_TOT (A x0)); Intros.
Apply PRE_NOTIN_FORM_VOID with x1 (A x0) x0 x; Auto.

Qed.

Lemma PRE_SAT_RW:  (n:nat)(F:form)(ln F n) ->
                   (P:proc)(sat P F) ->
                   (Q:name->proc)(G:name->form)(x:name)
                   (notin_proc x (nu Q)) -> (notin_form x (forall G)) ->
                   P=(Q x) -> F=(G x) ->
                   (y:name)~x=y ->
                   (notin_proc y (nu Q)) -> (notin_form y (forall G)) ->
                   (sat (Q y) (G y)).

Proof.

Intro; Pattern n; Apply NAT_IND; Intros.

Cut (lt O (0)); [Intro | Apply LN_S with F; Assumption].
Inversion_clear H8.

Inversion H0.

Rewrite <-H9 in H5; Cut G=([_:name]T); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_T); Auto].
Rewrite H11; Apply sat_T.

Elim (form_exp F0 x); Intros.
Inversion_clear H12.
Rewrite <-H10 in H5; Rewrite H14 in H5; Cut G=([_:name](neg (x0 _))); [Intro | Apply form_ext with x; Try (Inversion_clear H13; Apply notin_forall; Intros; Apply notin_neg); Auto].
Cut ~(sat (Q y) (x0 y))<->(sat (Q y) (neg (x0 y))); [Intro | Apply sat_neg].
Unfold iff in H15; Inversion_clear H15.
Rewrite H12; Apply H16; Unfold not; Intro.
Rewrite H4 in H1; Rewrite <-H10 in H1; Rewrite H14 in H1; Cut ~(sat (Q x) (x0 x)) <-> (sat (Q x) (neg (x0 x))); [Intro | Apply sat_neg].
Unfold iff in H15; Inversion_clear H18.
Cut ~(sat (Q x) (x0 x)); [Intro | Auto].
Unfold not in H18; Apply H18.
Apply H with n1 (x0 y) (Q y) y; Auto.
Rewrite <-H11; Unfold lt; Apply le_n.
Rewrite H14 in H9; Apply LN_RW with (x0 x) x; Auto.
Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros.
Cut (notin_form y (neg (x0 n2))); [Intro | Auto].
Inversion_clear H22; Assumption.

Elim (form_exp F0 x); Elim (form_exp G0 x); Intros.
Inversion_clear H13; Inversion_clear H14.
Rewrite H16 in H11; Rewrite H17 in H11; Rewrite <-H11 in H5.
Cut G=([_:name](Or (x1 _) (x0 _))); [Intro | Apply form_ext with x; Try (Inversion_clear H13; Inversion_clear H15; Apply notin_forall; Intros; Apply notin_Or); Auto].
Rewrite H14; Cut (sat (Q y) (x1 y)) \/ (sat (Q y) (x0 y)) <-> (sat (Q y) (Or (x1 y) (x0 y))); [Intro | Apply sat_Or].
Unfold iff in H18; Inversion_clear H18.
Apply H19; Rewrite H4 in H1; Rewrite <-H11 in H1; Cut (sat (Q x) (x1 x)) \/ (sat (Q x) (x0 x)) <-> (sat (Q x) (Or (x1 x) (x0 x))); [Intro | Apply sat_Or].
Inversion_clear H18; Cut (sat (Q x) (x1 x)) \/ (sat (Q x) (x0 x)); [Intro | Auto].
Inversion_clear H18; [Left; Apply H with n1 (x1 x) (Q x) x | Right; Apply H with n2 (x0 x) (Q x) x]; Auto.
Rewrite <-H12; Omega.
Rewrite H17 in H9; Apply LN_RW with (x1 x) x; Auto.
Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros.
Cut (notin_form y (Or (x1 n3) (x0 n3))); [Intro | Auto].
Inversion_clear H24; Assumption.
Rewrite <-H12; Omega.
Rewrite H16 in H10; Apply LN_RW with (x0 x) x; Auto.
Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros.
Cut (notin_form y (Or (x1 n3) (x0 n3))); [Intro | Auto].
Inversion_clear H24; Assumption.

Rewrite <-H9 in H1; Cut (struct_eq P nil) <-> (sat P zero); [Intro | Apply sat_zero].
Inversion_clear H11; Cut (struct_eq P nil); [Intro | Auto].
Rewrite H4 in H11; Cut (struct_eq (Q y) nil); [Intro | Change (struct_eq (Q y) ([_:name]nil y)); Apply STRUCT_RW with x; Try (Apply notin_proc_nu; Intros; Apply notin_proc_nil); Auto].
Rewrite <-H9 in H5; Cut G=([_:name]zero); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_zero); Auto].
Rewrite H15; Cut (struct_eq (Q y) nil) <-> (sat (Q y) zero); [Intro | Apply sat_zero].
Inversion_clear H16; Auto.

Elim (form_exp F0 x); Elim (form_exp G0 x); Intros.
Inversion_clear H13; Inversion_clear H14.
Rewrite H16 in H11; Rewrite H17 in H11; Rewrite <-H11 in H1; Rewrite <-H11 in H5.
Cut G=([_:name](comp (x1 _) (x0 _))); [Intro | Apply form_ext with x; Try (Inversion_clear H13; Inversion_clear H15; Apply notin_forall; Intros; Apply notin_comp); Auto].
Cut (Ex [P':proc](Ex [P'':proc]((struct_eq (Q x) (par P' P'')) /\ (sat P' (x1 x)) /\ (sat P'' (x0 x))))) <-> (sat (Q x) (comp (x1 x) (x0 x))); [Intro | Apply sat_comp].
Rewrite H4 in H1; Inversion_clear H18; Cut (Ex [P':proc](Ex [P'':proc]((struct_eq (Q x) (par P' P'')) /\ (sat P' (x1 x)) /\ (sat P'' (x0 x))))); [Intro | Auto].
Inversion_clear H18; Inversion_clear H21; Inversion_clear H18; Inversion_clear H22.
Cut (Ex [P':proc](Ex [P'':proc]((struct_eq (Q y) (par P' P'')) /\ (sat P' (x1 y)) /\ (sat P'' (x0 y))))) <-> (sat (Q y) (comp (x1 y) (x0 y))); [Intro | Apply sat_comp].
Rewrite H14; Inversion_clear H22; Apply H24.
Elim (proc_exp x2 x); Elim (proc_exp x3 x); Intros.
Inversion_clear H22; Inversion_clear H26.
Rewrite H28 in H23; Rewrite H28 in H21; Rewrite H29 in H18; Rewrite H29 in H21.
Exists (x5 y); Exists (x4 y); Split.
Change (struct_eq (Q y) ([_:name](par (x5 _) (x4 _)) y)); Apply STRUCT_RW with x; Auto.
Inversion_clear H22; Inversion_clear H27; Apply notin_proc_nu; Intros; Apply notin_proc_par; Auto.
Cut ((notin_proc y (Q x)) -> (notin_proc y (par (x5 x) (x4 x)))) /\ ((notin_proc y (par (x5 x) (x4 x))) -> (notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion_clear H26; Apply NOTIN_PROC_MONO with x; Apply H30; Inversion_clear H7; Auto.
Split; [Apply H with n1 (x1 x) (x5 x) x | Apply H with n2 (x0 x) (x4 x) x]; Auto.
Rewrite <-H12; Omega.
Rewrite H17 in H9; Assumption.
Cut ((notin_proc y (Q x)) -> (notin_proc y (par (x5 x) (x4 x)))) /\ ((notin_proc y (par (x5 x) (x4 x))) -> (notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion_clear H26; Apply NOTIN_PROC_MONO with x.
Cut (notin_proc y (par (x5 x) (x4 x))); [Intro | Apply H30; Inversion_clear H7; Auto].
Inversion_clear H26; Assumption.
Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros.
Cut (notin_form y (comp (x1 n3) (x0 n3))); [Intro | Auto].
Inversion_clear H30; Assumption.
Rewrite <-H12; Omega.
Rewrite H16 in H10; Assumption.
Cut ((notin_proc y (Q x)) -> (notin_proc y (par (x5 x) (x4 x)))) /\ ((notin_proc y (par (x5 x) (x4 x))) -> (notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion_clear H26; Apply NOTIN_PROC_MONO with x.
Cut (notin_proc y (par (x5 x) (x4 x))); [Intro | Apply H30; Inversion_clear H7; Auto].
Inversion_clear H26; Assumption.
Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros.
Cut (notin_form y (comp (x1 n3) (x0 n3))); [Intro | Auto].
Inversion_clear H30; Assumption.

Elim (form_exp F0 x); Elim (form_exp G0 x); Intros.
Inversion_clear H13; Inversion_clear H14.
Rewrite H16 in H11; Rewrite H17 in H11; Rewrite <-H11 in H1; Rewrite <-H11 in H5.
Cut G=([_:name](comp_adj (x1 _) (x0 _))); [Intro | Apply form_ext with x; Try (Inversion_clear H13; Inversion_clear H15; Apply notin_forall; Intros; Apply notin_comp_adj); Auto].
Cut ((P':proc)(sat P' (x1 x)) -> (sat (par (Q x) P') (x0 x))) <-> (sat (Q x) (comp_adj (x1 x) (x0 x))); [Intro | Apply sat_comp_adj].
Rewrite H4 in H1; Inversion_clear H18; Cut ((P':proc)(sat P' (x1 x)) -> (sat (par (Q x) P') (x0 x))); [Intro | Auto].
Cut ((P':proc)(sat P' (x1 y)) -> (sat (par (Q y) P') (x0 y))) <-> (sat (Q y) (comp_adj (x1 y) (x0 y))); [Intro | Apply sat_comp_adj].
Rewrite H14; Inversion_clear H21; Apply H22; Intros.
Elim (proc_exp P' y); Intros.
Inversion_clear H24.
Rewrite H26 in H21; Elim (ho_proc_exp x2 x); Intros.
Inversion_clear H24.
Rewrite H28 in H21; Elim (UNSAT_NLIST_PROC_FORM (cons x (cons y empty)) (par (nu [_:name](nu (x3 _))) (nu Q)) (Or (forall x0) (forall x1))); Intros.
Inversion_clear H24; Inversion_clear H29; Inversion_clear H30; Inversion_clear H29; Inversion_clear H31; Inversion_clear H32; Clear H34.
Cut (sat (x3 x4 y) (x1 y)); [Intro | Change (sat ([_:name](x3 _ y) x4) ([_:name](x1 y) x4)); Apply H with n1 (x1 y) (x3 x y) x; [Rewrite <-H12; Omega | Rewrite H17 in H9; Apply LN_RW with (x1 x) x; Auto | Assumption | Inversion_clear H27; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x3 n3))); [Intro | Auto]; Inversion_clear H34; Auto | Inversion_clear H13; Apply notin_forall; Intros; Auto | Trivial | Trivial | Auto | Inversion_clear H30; Apply notin_proc_nu; Intros; Cut (notin_proc x4 (nu (x3 n3))); [Intro | Auto]; Inversion_clear H34; Auto | Inversion_clear H35; Apply notin_forall; Intros; Auto]].
Cut (sat (x3 x4 x) (x1 x)); [Intro | Change (sat (x3 x4 x) (x1 x)); Apply H with n1 (x1 y) (x3 x4 y) y; [ Rewrite <-H12; Omega | Rewrite H17 in H9; Apply LN_RW with (x1 x) x; Auto | Assumption | Cut (notin_proc y (nu [_:name](nu (x3 _)))); [Intro | Apply NOTIN_PROC_MONO with x; Rewrite <-H28; Assumption]; Inversion_clear H34; Auto | Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (comp_adj (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H36; Assumption | Trivial | Trivial | Auto | Inversion_clear H27; Auto | Assumption]].
Cut (sat (par (Q x) (x3 x4 x)) (x0 x)); [Intro | Auto].
Rewrite H26; Rewrite H28.
Change (sat ([_:name](par (Q y) (x3 _ y)) x) ([_:name](x0 y) x)); Apply H with n2 (x0 y) (par (Q y) (x3 x4 y)) x4; [Rewrite <-H12; Omega | Rewrite H16 in H10; Apply LN_RW with (x0 x) x; Auto | Idtac | Inversion_clear H30; Inversion_clear H33; Apply notin_proc_nu; Intros; Apply notin_proc_par; [Auto | Cut (notin_proc x4 (nu (x3 n3))); [Intro | Auto]; Inversion_clear H38; Auto] | Inversion_clear H31; Apply notin_forall; Intros; Auto | Trivial | Trivial | Assumption | Inversion_clear H2; Inversion_clear H27; Apply notin_proc_nu; Intros; Apply notin_proc_par; [Auto | Cut (notin_proc x (nu (x3 n3))); [Intro | Auto]; Inversion_clear H38; Auto] | Inversion_clear H15; Apply notin_forall; Intros; Auto].
Change (sat ([_:name](par (Q _) (x3 x4 _)) y) (x0 y)); Apply H with n2 (x0 x) (par (Q x) (x3 x4 x)) x; [Rewrite <-H12; Omega | Rewrite H16 in H10; Apply LN_RW with (x0 x) x; Auto | Assumption | Inversion_clear H2; Inversion_clear H27; Apply notin_proc_nu; Intros; Apply notin_proc_par; [Auto | Cut (notin_proc x (nu (x3 x4))); [Intro | Auto]; Inversion_clear H38; Auto] | Assumption | Trivial | Trivial | Assumption | Cut (notin_proc y (nu [_:name](nu (x3 _)))); [Intro | Apply NOTIN_PROC_MONO with x; Rewrite <-H28; Assumption]; Inversion_clear H7; Inversion_clear H37; Apply notin_proc_nu; Intros; Apply notin_proc_par; [Auto | Cut (notin_proc y (nu (x3 x4))); [Intro | Auto]; Inversion_clear H39; Auto] | Rewrite H14 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (comp_adj (x1 n3) (x0 n3))); [Intro | Auto]; Inversion_clear H38; Auto].

Elim (form_exp F0 x); Intros.
Inversion_clear H12.
Rewrite H14 in H10; Rewrite <-H10 in H5; Rewrite H4 in H1; Rewrite <-H10 in H1; Cut (Ex [P':proc]((struct_eq (Q x) (ambient (name2cap x0) P')) /\ (sat P' (x1 x)))) <-> (sat (Q x) (loc x0 (x1 x))); [Intro | Apply sat_loc].
Inversion_clear H12; Cut (Ex [P':proc]((struct_eq (Q x) (ambient (name2cap x0) P')) /\ (sat P' (x1 x)))); [Intro | Auto].
Inversion_clear H12; Inversion_clear H17; Elim (dec_name x0 x); Intros.
Rewrite H17 in H5; Rewrite H17 in H12; Cut G=([_:name](loc _ (x1 _))); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_loc; [Idtac | Inversion_clear H13]); Auto].
Rewrite H19; Cut (Ex [P':proc]((struct_eq (Q y) (ambient (name2cap y) P')) /\ (sat P' (x1 y)))) <-> (sat (Q y) (loc y (x1 y))); [Intro | Apply sat_loc].
Inversion_clear H20; Elim (proc_exp x2 x); Intros; Inversion_clear H20.
Rewrite H24 in H18; Rewrite H24 in H12.
Apply H21; Exists (x3 y); Split.
Change (struct_eq (Q y) ([_:name](ambient (name2cap _) (x3 _)) y)); Apply STRUCT_RW with x; Auto.
Inversion_clear H23; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]; Auto.
Cut (notin_proc y (nu x3)); [Intro | Apply NOTIN_PROC_MONO with x; Cut ((notin_proc y (Q x)) -> (notin_proc y (ambient (name2cap x) (x3 x)))) /\ ((notin_proc y (ambient (name2cap x) (x3 x)))->(notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption]; Inversion_clear H20; Cut (notin_proc y (Q x)); [Intro | Inversion_clear H7; Auto]; Cut (notin_proc y (ambient (name2cap x) (x3 x))); [Intro | Auto]; Inversion_clear H27; Assumption].
Inversion_clear H20; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]; Auto.
Apply H with n1 (x1 x) (x3 x) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Assumption | Assumption | Trivial | Trivial | Assumption | Apply NOTIN_PROC_MONO with x; Cut ((notin_proc y (Q x)) -> (notin_proc y (ambient (name2cap x) (x3 x)))) /\ ((notin_proc y (ambient (name2cap x) (x3 x)))->(notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption]; Inversion_clear H20; Cut (notin_proc y (Q x)); [Intro | Inversion_clear H7; Auto]; Cut (notin_proc y (ambient (name2cap x) (x3 x))); [Intro | Auto]; Inversion_clear H27; Assumption | Rewrite H19 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (loc n2 (x1 n2))); [Intro | Auto]; Inversion_clear H25; Assumption].
Cut G=([_:name](loc x0 (x1 _))); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_loc; [Idtac | Inversion_clear H13]); Auto].
Rewrite H19; Cut (Ex [P':proc]((struct_eq (Q y) (ambient (name2cap x0) P')) /\ (sat P' (x1 y)))) <-> (sat (Q y) (loc x0 (x1 y))); [Intro | Apply sat_loc].
Inversion_clear H20; Elim (proc_exp x2 x); Intros; Inversion_clear H20.
Rewrite H24 in H18; Rewrite H24 in H12.
Apply H21; Exists (x3 y); Split.
Change (struct_eq (Q y) ([_:name](ambient (name2cap x0) (x3 _)) y)); Apply STRUCT_RW with x; Auto.
Inversion_clear H23; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]; Auto.
Cut (notin_proc y (nu x3)); [Intro | Apply NOTIN_PROC_MONO with x; Cut ((notin_proc y (Q x)) -> (notin_proc y (ambient (name2cap x0) (x3 x)))) /\ ((notin_proc y (ambient (name2cap x0) (x3 x)))->(notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption]; Inversion_clear H20; Cut (notin_proc y (Q x)); [Intro | Inversion_clear H7; Auto]; Cut (notin_proc y (ambient (name2cap x0) (x3 x))); [Intro | Auto]; Inversion_clear H27; Assumption].
Rewrite H19 in H8; Inversion_clear H8.
Cut (notin_form y (loc x0 (x1 x))); [Intro | Auto].
Inversion_clear H8; Inversion_clear H20; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]; Auto.
Apply H with n1 (x1 x) (x3 x) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Assumption | Assumption | Trivial | Trivial | Assumption | Apply NOTIN_PROC_MONO with x; Cut ((notin_proc y (Q x)) -> (notin_proc y (ambient (name2cap x0) (x3 x)))) /\ ((notin_proc y (ambient (name2cap x0) (x3 x)))->(notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption]; Inversion_clear H20; Cut (notin_proc y (Q x)); [Intro | Inversion_clear H7; Auto]; Cut (notin_proc y (ambient (name2cap x0) (x3 x))); [Intro | Auto]; Inversion_clear H27; Assumption | Rewrite H19 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (loc x0 (x1 n2))); [Intro | Auto]; Inversion_clear H25; Assumption].

Elim (form_exp F0 x); Intros.
Inversion_clear H12.
Rewrite H14 in H10; Rewrite <-H10 in H5; Rewrite H4 in H1; Rewrite <-H10 in H1; Cut (sat (ambient (name2cap x0) (Q x)) (x1 x))<->(sat (Q x) (loc_adj (x1 x) x0)); [Intro | Apply sat_loc_adj].
Inversion_clear H12; Cut (sat (ambient (name2cap x0) (Q x)) (x1 x)); [Intro | Auto].
Elim (dec_name x0 x); Intros.
Rewrite H17 in H5; Rewrite H17 in H12; Cut G=([_:name](loc_adj (x1 _) _)); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_loc_adj; [Idtac | Inversion_clear H13]); Auto].
Rewrite H18; Cut (sat (ambient (name2cap y) (Q y)) (x1 y))<->(sat (Q y) (loc_adj (x1 y) y)); [Intro | Apply sat_loc_adj].
Inversion_clear H19; Apply H20.
Change (sat ([_:name](ambient (name2cap _) (Q _)) y) (x1 y)); Apply H with n1 (x1 x) (ambient (name2cap x) (Q x)) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Inversion_clear H2; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]; Auto | Assumption | Trivial | Trivial | Assumption | Inversion_clear H7; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]; Auto | Rewrite H18 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (loc_adj (x1 n2) n2)); [Intro | Auto]; Inversion_clear H22; Assumption].
Cut G=([_:name](loc_adj (x1 _) x0)); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_loc_adj; [Idtac | Inversion_clear H13]); Auto].
Rewrite H18; Cut (sat (ambient (name2cap x0) (Q y)) (x1 y))<->(sat (Q y) (loc_adj (x1 y) x0)); [Intro | Apply sat_loc_adj].
Inversion_clear H19; Apply H20.
Change (sat ([_:name](ambient (name2cap x0) (Q _)) y) (x1 y)); Apply H with n1 (x1 x) (ambient (name2cap x0) (Q x)) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Inversion_clear H2; Apply notin_proc_nu; Intros; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]; Auto | Assumption | Trivial | Trivial | Assumption | Rewrite H18 in H8; Inversion_clear H8; Inversion_clear H7; Apply notin_proc_nu; Intros; Cut (notin_form y (loc_adj (x1 n2) x0)); [Intro | Auto]; Inversion_clear H22; Apply notin_proc_amb; [Apply notin_cap_name | Idtac]; Auto | Rewrite H18 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (loc_adj (x1 n2) x0)); [Intro | Auto]; Inversion_clear H22; Assumption].

Elim (form_exp F0 x); Intros.
Inversion_clear H12.
Rewrite H14 in H10; Rewrite <-H10 in H5; Rewrite H4 in H1; Rewrite <-H10 in H1; Cut (notin_proc x0 (Q x)) /\ (Ex [P':name->proc]((struct_eq (Q x) (nu P')) /\ (sat (P' x0) (x1 x)))) <-> (sat (Q x) (rev x0 (x1 x))); [Intro | Apply sat_rev].
Inversion_clear H12.
Cut (notin_proc x0 (Q x)) /\ (Ex [P':name->proc]((struct_eq (Q x) (nu P')) /\ (sat (P' x0) (x1 x)))); [Intro | Auto].
Inversion_clear H12; Inversion_clear H18; Inversion_clear H12; Elim (dec_name x0 x); Intros.
Rewrite H12 in H1; Rewrite H12 in H5; Rewrite H12 in H17; Rewrite H12 in H19.
Cut G=([_:name](rev _ (x1 _))); [Intro | Apply form_ext with x; Try (Inversion_clear H13; Apply notin_forall; Intros; Apply notin_rev); Auto].
Rewrite H20; Cut (notin_proc y (Q y)) /\ (Ex [P':name->proc]((struct_eq (Q y) (nu P')) /\ (sat (P' y) (x1 y)))) <-> (sat (Q y) (rev y (x1 y))); [Intro | Apply sat_rev].
Inversion_clear H21.
Apply H22; Split.

Apply NOTIN_PROC_VOID with x; Assumption.
Elim (ho_proc_exp x2 x); Intros.
Inversion_clear H21.
Rewrite H25 in H18; Rewrite H25 in H19.
Exists (x3 y); Split.
Change (struct_eq (Q y) ([_:name](nu (x3 _)) y)); Apply STRUCT_RW with x; Auto.
Cut ((notin_proc y (Q x)) -> (notin_proc y (nu (x3 x)))) /\ ((notin_proc y (nu (x3 x))) -> (notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion H7; Inversion_clear H21; Cut (notin_proc y (nu (x3 x))); [Intro | Auto].
Apply NOTIN_PROC_MONO with x; Assumption.
Change (sat ([_:name](x3 _ _) y) (x1 y)); Apply H with n1 (x1 x) (x3 x x) x; [ Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Inversion_clear H24; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x3 n2))); [Intro | Auto]; Inversion_clear H26; Auto | Assumption | Trivial | Trivial | Assumption | Cut ((notin_proc y (Q x)) -> (notin_proc y (nu (x3 x)))) /\ ((notin_proc y (nu (x3 x))) -> (notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption]; Inversion_clear H7; Inversion_clear H21; Cut (notin_proc y (nu (x3 x))); [Intro | Auto]; Apply NOTIN_PROC_MONO with x; Inversion_clear H21; Auto | Rewrite H20 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (rev n2 (x1 n2))); [Intro | Auto]; Inversion_clear H26; Assumption].
Cut G=([_:name](rev x0 (x1 _))); [Intro | Apply form_ext with x; Try (Inversion_clear H13; Apply notin_forall; Intros; Apply notin_rev); Auto].
Rewrite H20; Cut (notin_proc x0 (Q y)) /\ (Ex [P':name->proc]((struct_eq (Q y) (nu P')) /\ (sat (P' x0) (x1 y)))) <-> (sat (Q y) (rev x0 (x1 y))); [Intro | Apply sat_rev].
Inversion_clear H21.
Apply H22; Split.
Rewrite H20 in H8; Inversion_clear H8.
Cut (notin_form y (rev x0 (x1 x))); [Intro | Auto].
Cut (notin_proc x0 (nu Q)); [Intro | Apply NOTIN_PROC_MONO with x; Assumption].
Inversion_clear H8; Inversion_clear H24; Auto.
Elim (ho_proc_exp x2 x); Intros.
Inversion_clear H21.
Rewrite H25 in H18; Rewrite H25 in H19.
Exists (x3 y); Split.
Change (struct_eq (Q y) ([_:name](nu (x3 _)) y)); Apply STRUCT_RW with x; Auto.
Cut ((notin_proc y (Q x)) -> (notin_proc y (nu (x3 x)))) /\ ((notin_proc y (nu (x3 x))) -> (notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption].
Inversion H7; Inversion_clear H21; Cut (notin_proc y (nu (x3 x))); [Intro | Auto].
Apply NOTIN_PROC_MONO with x; Assumption.
Change (sat ([_:name](x3 _ x0) y) (x1 y)); Apply H with n1 (x1 x) (x3 x x0) x; [ Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Inversion_clear H24; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x3 n2))); [Intro | Auto]; Inversion_clear H26; Auto | Assumption | Trivial | Trivial | Assumption | Cut ((notin_proc y (Q x)) -> (notin_proc y (nu (x3 x)))) /\ ((notin_proc y (nu (x3 x))) -> (notin_proc y (Q x))); [Intro | Apply STRUCT_NOTIN; Assumption]; Inversion_clear H7; Inversion_clear H21; Cut (notin_proc y (nu (x3 x))); [Intro | Auto]; Rewrite H20 in H8; Inversion_clear H8; Cut (notin_form y (rev x0 (x1 x))); [Intro | Auto]; Inversion_clear H8; Apply NOTIN_PROC_MONO with x; Inversion_clear H21; Auto | Rewrite H20 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (rev x0 (x1 n2))); [Intro | Auto]; Inversion_clear H26; Assumption].

Elim (form_exp F0 x); Intros.
Inversion_clear H12.
Rewrite H14 in H10; Rewrite <-H10 in H5; Rewrite H4 in H1; Rewrite <-H10 in H1; Cut (Ex [P':name->proc]((Q x)=(P' x0) /\ (notin_proc x0 (nu P')) /\ (sat (nu P') (x1 x)))) <-> (sat (Q x) (rev_adj (x1 x) x0)); [Intro | Apply sat_rev_adj].
Inversion_clear H12; Cut (Ex [P':name->proc]((Q x)=(P' x0) /\ (notin_proc x0 (nu P')) /\ (sat (nu P') (x1 x)))); [Intro | Auto].
Inversion_clear H12; Inversion_clear H17; Inversion_clear H18.
Elim (dec_name x0 x); Intros.
Rewrite H18 in H1; Rewrite H18 in H5; Rewrite H18 in H12; Rewrite H18 in H17; Cut G=([_:name](rev_adj (x1 _) _)); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_rev_adj; [Idtac | Inversion_clear H13]); Auto].
Rewrite H20; Cut (Ex [P':name->proc]((Q y)=(P' y) /\ (notin_proc y (nu P')) /\ (sat (nu P') (x1 y)))) <-> (sat (Q y) (rev_adj (x1 y) y)); [Intro | Apply sat_rev_adj].
Inversion_clear H21; Apply H22.
Exists x2; Split; Try Split.
Cut Q=x2; [Intro; Rewrite H21; Trivial | Apply proc_ext with x; Auto].
Apply NOTIN_PROC_MONO with x; Rewrite <-H12; Inversion_clear H7; Auto.
Change (sat ([_:name](nu x2) y) (x1 y)); Apply H with n1 (x1 x) (nu x2) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Inversion_clear H17; Do 2 (Apply notin_proc_nu; Intros); Auto | Assumption | Trivial | Trivial | Assumption | Apply notin_proc_nu; Intros; Apply NOTIN_PROC_MONO with x; Rewrite <-H12; Inversion_clear H7; Auto | Rewrite H20 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (rev_adj (x1 n2) n2)); [Intro | Auto]; Inversion_clear H24; Assumption].
Elim (ho_proc_exp x2 x); Intros.
Inversion_clear H20.
Rewrite H22 in H12; Cut Q=([_:name](x3 _ x0)); [Intro | Apply proc_ext with x; Try (Inversion_clear H2; Inversion_clear H21; Apply notin_proc_nu; Intros; Cut (notin_proc x (nu (x3 n2))); [Intro | Auto]; Inversion_clear H23); Auto].
Cut G=([_:name](rev_adj (x1 _) x0)); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_rev_adj; [Idtac | Inversion_clear H13]); Auto].
Rewrite H20; Rewrite H23; Cut (Ex [P':name->proc]((Q y)=(P' x0) /\ (notin_proc x0 (nu P')) /\ (sat (nu P') (x1 y)))) <-> (sat (Q y) (rev_adj (x1 y) x0)); [Intro | Apply sat_rev_adj].
Rewrite H20 in H24; Inversion_clear H24; Apply H25.
Exists (x3 y); Split; Try Split.
Rewrite H23 in H8; Inversion_clear H8; Rewrite H22 in H17; Cut (notin_proc x0 (nu [_:name](nu (x3 _)))); [Intro | Apply NOTIN_PROC_MONO with x; Assumption].
Cut (notin_form y (rev_adj (x1 x) x0)); [Intro | Auto].
Inversion_clear H27; Inversion_clear H8; Auto.
Change (sat ([_:name](nu (x3 _)) y) (x1 y)); Apply H with n1 (x1 x) (nu (x3 x)) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Rewrite <-H22; Assumption | Assumption | Assumption | Trivial | Trivial | Assumption | Apply NOTIN_PROC_MONO with x; Apply NOTIN_PROC_MONO with x0; Rewrite <-H12; Inversion_clear H7; Auto | Rewrite H23 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (rev_adj (x1 n2) x0)); [Intro | Auto]; Inversion_clear H27; Assumption].

Rewrite <-H10 in H5; Elim (form_exp F0 x); Intros.
Inversion_clear H12.
Rewrite H14 in H5; Cut G=([_:name](sometime (x0 _))); [Intro | Apply form_ext with x; Try (Inversion_clear H13; Apply notin_forall; Intros; Apply notin_sometime); Auto].
Cut (Ex [P':proc]((red_star (Q x) P') /\ (sat P' (x0 x)))) <-> (sat (Q x) (sometime (x0 x))); [Intro | Apply sat_sometime].
Inversion_clear H15; Rewrite <-H10 in H1; Rewrite H14 in H1; Rewrite H4 in H1; Cut (Ex [P':proc]((red_star (Q x) P') /\ (sat P' (x0 x)))); [Intro | Auto].
Cut (Ex [P':proc]((red_star (Q y) P') /\ (sat P' (x0 y)))) <-> (sat (Q y) (sometime (x0 y))); [Intro | Apply sat_sometime].
Inversion_clear H18; Rewrite H12; Apply H19.
Inversion_clear H15; Inversion_clear H18.
Elim (proc_exp x1 x); Intros.
Inversion_clear H18; Rewrite H23 in H15; Rewrite H23 in H21.
Exists (x2 y); Split.
Apply RED_STAR_RW with x; Auto.
Inversion_clear H7; Apply NOTIN_PROC_MONO with x; Apply RED_STAR_NOTIN with (Q x); Auto.
Apply H with n1 (x0 x) (x2 x) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Assumption | Assumption | Trivial | Trivial | Assumption | Inversion_clear H7; Apply NOTIN_PROC_MONO with x; Apply RED_STAR_NOTIN with (Q x); Auto | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (sometime (x0 n2))); [Intro | Auto]; Inversion_clear H24; Assumption].

Rewrite <-H10 in H5; Elim (form_exp F0 x); Intros.
Inversion_clear H12.
Rewrite H14 in H5; Cut G=([_:name](somewhere (x0 _))); [Intro | Apply form_ext with x; Try (Inversion_clear H13; Apply notin_forall; Intros; Apply notin_somewhere); Auto].
Cut (Ex [P':proc]((nest_star (Q x) P') /\ (sat P' (x0 x)))) <-> (sat (Q x) (somewhere (x0 x))); [Intro | Apply sat_somewhere].
Inversion_clear H15; Rewrite <-H10 in H1; Rewrite H14 in H1; Rewrite H4 in H1; Cut (Ex [P':proc]((nest_star (Q x) P') /\ (sat P' (x0 x)))); [Intro | Auto].
Cut (Ex [P':proc]((nest_star (Q y) P') /\ (sat P' (x0 y)))) <-> (sat (Q y) (somewhere (x0 y))); [Intro | Apply sat_somewhere].
Inversion_clear H18; Rewrite H12; Apply H19.
Inversion_clear H15; Inversion_clear H18.
Elim (proc_exp x1 x); Intros.
Inversion_clear H18; Rewrite H23 in H15; Rewrite H23 in H21.
Exists (x2 y); Split.
Apply NEST_STAR_RW with x; Auto.
Inversion_clear H7; Apply NOTIN_PROC_MONO with x; Apply NEST_STAR_NOTIN with (Q x); Auto.
Apply H with n1 (x0 x) (x2 x) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Assumption | Assumption | Assumption | Assumption | Trivial | Trivial | Assumption | Inversion_clear H7; Apply NOTIN_PROC_MONO with x; Apply NEST_STAR_NOTIN with (Q x); Auto | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (somewhere (x0 n2))); [Intro | Auto]; Inversion_clear H24; Assumption].

Rewrite H4 in H1; Rewrite <-H10 in H1; Elim (ho_form_exp F0 x); Intros.
Inversion_clear H12.
Rewrite H14 in H1; Rewrite H14 in H10; Rewrite <-H10 in H5.
Cut G=([_:name](forall (x0 _))); [Intro | Apply form_ext with x; Auto].
Cut ((m:name)(sat (Q x) ((x0 x) m)))<->(sat (Q x) (forall (x0 x))); [Intro | Apply sat_forall].
Inversion_clear H15; Cut ((m:name)(sat (Q x) ((x0 x) m))); [Intro | Auto].
Cut ((m:name)(sat (Q y) ((x0 y) m)))<->(sat (Q y) (forall (x0 y))); [Intro | Apply sat_forall].
Rewrite H12; Inversion_clear H18; Apply H19; Intro.
Elim (dec_name m x); Elim (dec_name m y); Intros.
Rewrite H21 in H18; Absurd x=y; Assumption.
Rewrite H21.
Elim (UNSAT_NLIST_PROC_FORM (cons x (cons y empty)) (nu Q) (forall [_:name](forall (x0 _)))); Intros.
Inversion_clear H22; Inversion_clear H23; Inversion_clear H24; Inversion_clear H25; Clear H27.
Change (sat ([_:name](Q y) x) (x0 y x)); Apply H with n1 (x0 y x1) (Q y) x1; [Rewrite <-H11; Unfold lt; Apply le_n | Change (ln ([_:name](x0 _ x1) y) n1); Apply LN_RW with (x0 x x1) x; [Rewrite <-H14; Auto | Inversion_clear H13; Apply notin_forall; Intros; Cut (notin_form x (forall (x0 n2))); [Intro | Auto]; Inversion_clear H27; Auto | Trivial] | Idtac | Inversion_clear H23; Apply notin_proc_nu; Intros; Auto | Inversion_clear H26; Apply notin_forall; Intros; Cut (notin_form x1 (forall (x0 y))); [Intro | Auto]; Inversion_clear H27; Auto | Trivial | Trivial | Assumption | Inversion_clear H2; Apply notin_proc_nu; Intros; Auto | Rewrite H12 in H3; Inversion_clear H3; Apply notin_forall; Intros; Cut (notin_form x (forall (x0 y))); [Intro | Auto]; Inversion_clear H27; Auto].
Change (sat (Q y) ([_:name](x0 _ x1) y)); Apply H with n1 (x0 x x1) (Q x) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Auto | Auto | Assumption | Inversion_clear H13; Apply notin_forall; Intros; Cut (notin_form x (forall (x0 n2))); [Intro | Auto]; Inversion_clear H27; Auto | Trivial | Trivial | Assumption | Assumption | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (forall (x0 n2))); [Intro | Auto]; Inversion_clear H27; Auto].
Rewrite H18.
Change (sat (Q y) ([_:name](x0 _ _) y)); Apply H with n1 (x0 x x) (Q x) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Auto | Auto | Assumption | Inversion_clear H13; Apply notin_forall; Intros; Cut (notin_form x (forall (x0 n2))); [Intro | Auto]; Inversion_clear H23; Auto | Trivial | Trivial | Assumption | Assumption | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (forall (x0 n2))); [Intro | Auto]; Inversion_clear H23; Auto].
Change (sat (Q y) ([_:name](x0 _ m) y)); Apply H with n1 (x0 x m) (Q x) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite <-H14; Auto | Auto | Assumption | Rewrite H12 in H3; Inversion_clear H3; Apply notin_forall; Intros; Cut (notin_form x (forall (x0 n2))); [Intro | Auto]; Inversion_clear H23; Auto | Trivial | Trivial | Assumption | Assumption | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (forall (x0 n2))); [Intro | Auto]; Inversion_clear H23; Auto].

Rewrite H4 in H1; Rewrite <-H10 in H1; Elim (ho_form_exp F0 x); Intros.
Inversion_clear H12.
Rewrite H14 in H1; Rewrite H14 in H10; Rewrite <-H10 in H5.
Cut G=([_:name](new (x0 _))); [Intro | Apply form_ext with x; Try (Apply notin_forall; Intros; Apply notin_new; Intros; Inversion_clear H13; Cut (notin_form x (forall (x0 n2))); [Intro | Auto]; Inversion_clear H13); Auto].
Cut (EX m:name | (notin_proc m (Q x))/\(notin_form m (forall (x0 x)))/\(sat (Q x) (x0 x m)))<->(sat (Q x) (new (x0 x))); [Intro | Apply sat_new].
Inversion_clear H15; Cut (EX m:name | (notin_proc m (Q x))/\(notin_form m (forall (x0 x)))/\(sat (Q x) (x0 x m))); [Intro | Auto].
Cut (EX m:name | (notin_proc m (Q y))/\(notin_form m (forall (x0 y)))/\(sat (Q y) (x0 y m)))<->(sat (Q y) (new (x0 y))); [Intro | Apply sat_new].
Rewrite H12; Inversion_clear H18; Apply H19.
Inversion_clear H15; Inversion_clear H18; Inversion_clear H21.
Elim (dec_name x1 x); Elim (dec_name x1 y); Intros.
Rewrite H23 in H21; Absurd x=y; Assumption.
Rewrite H23 in H15; Rewrite H23 in H18; Rewrite H23 in H22; Exists y; Split; Try Split.
Apply NOTIN_PROC_VOID with x; Assumption.
Change (notin_form y ([_:name](forall (x0 _)) y)); Apply NOTIN_FORM_VOID with x; Auto.
Rewrite H12 in H8; Inversion_clear H8; Do 2 (Apply notin_forall; Intros).
Cut (notin_form y (new (x0 n2))); [Intro | Auto].
Inversion_clear H26; Auto.
Change (sat (Q y) ([_:name](x0 _ _) y)); Apply H with n1 (x0 x x) (Q x) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite H14 in H9; Auto | Assumption | Assumption | Inversion_clear H13; Apply notin_forall; Intros; Cut (notin_form x (forall (x0 n2))); [Intro | Auto]; Inversion_clear H25; Auto | Trivial | Trivial | Assumption | Assumption | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (new (x0 n2))); [Intro | Auto]; Inversion_clear H25; Auto].
Rewrite H21 in H15; Rewrite H21 in H18; Rewrite H21 in H22; Elim (UNSAT_NLIST_PROC_FORM (cons x (cons y empty)) (nu Q) (forall [_:name](forall (x0 _)))); Intros.
Inversion_clear H24; Inversion_clear H25; Inversion_clear H26; Inversion_clear H27; Clear H29.
Exists x2; Split; Try Split.
Inversion_clear H25; Auto.
Inversion_clear H28; Auto.
Change (sat (Q y) ([_:name](x0 _ x2) y)); Apply H with n1 (x0 x x2) (Q x) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite H14 in H9; Auto | Idtac | Assumption | Inversion_clear H13; Apply notin_forall; Intros; Cut (notin_form x (forall (x0 n2))); [Intro | Auto]; Inversion_clear H29; Auto | Trivial | Trivial | Assumption | Assumption | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (new (x0 n2))); [Intro | Auto]; Inversion_clear H29; Auto].
Change (sat ([_:name](Q x) x2) (x0 x x2)); Apply H with n1 (x0 x y) (Q x) y; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite H14 in H9; Auto | Assumption | Apply notin_proc_nu; Intros; Assumption | Assumption | Trivial | Trivial | Auto | Inversion_clear H25; Apply notin_proc_nu; Auto | Inversion_clear H28; Auto].
Exists x1; Split; Try Split.
Cut (notin_proc x1 (nu Q)); [Intro | Apply NOTIN_PROC_MONO with x; Assumption].
Inversion_clear H24; Auto.
Cut (notin_form x1 (forall [_:name](forall (x0 _)))); [Intro | Apply NOTIN_FORM_MONO with x; Assumption].
Inversion_clear H24; Auto.
Change (sat (Q y) ([_:name](x0 _ x1) y)); Apply H with n1 (x0 x x1) (Q x) x; [Rewrite <-H11; Unfold lt; Apply le_n | Rewrite H14 in H9; Auto | Assumption | Assumption | Rewrite H12 in H3; Inversion_clear H3; Apply notin_forall; Intros; Cut (notin_form x (new (x0 n2))); [Intro | Auto]; Inversion_clear H25; Auto | Trivial | Trivial | Assumption | Assumption | Rewrite H12 in H8; Inversion_clear H8; Apply notin_forall; Intros; Cut (notin_form y (new (x0 n2))); [Intro | Auto]; Inversion_clear H25; Auto].

Qed.

Lemma SAT_RW: (P:name->proc)(F:name->form)(x:name)
              (notin_proc x (nu P)) -> (notin_form x (forall F)) ->
              (sat (P x) (F x)) ->
              (y:name)
              (notin_proc y (nu P)) -> (notin_form y (forall F)) ->
              (sat (P y) (F y)).

Proof.

Intros; Elim (dec_name x y); Intros.
Rewrite <-H4; Assumption.
Elim (LN_TOT (F x)); Intros.
Apply PRE_SAT_RW with x0 (F x) (P x) x; Auto.

Qed.

(* Functional version of satisfaction. *)

Fixpoint satF[P:proc;A:form]: Prop:=
  <Prop>Cases A of
            T => True
          | (neg B) => ((satF P B) -> False)
          | (Or A1 A2) => ((satF P A1) \/ (satF P A2))
          | zero => (struct_eq P nil)
          | (comp A1 A2) => (Ex [P':proc](Ex [P'':proc](struct_eq P (par P' P''))
                                        /\ (satF P' A1) /\ (satF P'' A2)))
          | (comp_adj A1 A2) => ((P':proc)(satF P' A1) -> (satF (par P P') A2))
          | (loc n B) => (Ex [P':proc](struct_eq P (ambient (name2cap n) P')) /\ (satF P' B))
          | (loc_adj B n) => (satF (ambient (name2cap n) P) B)
          | (rev n B) => ((notin_proc n P) /\ (Ex [P':name->proc](struct_eq P (nu P'))
                               /\ (satF (P' n) B)))
          | (rev_adj B n) => (Ex [P':name->proc]P=(P' n) /\ (notin_proc n (nu P')) /\ (satF (nu P') B))
          | (sometime B) => (Ex [P':proc](red_star P P') /\ (satF P' B))
          | (somewhere B) => (Ex [P':proc](nest_star P P') /\ (satF P' B))
          | (forall B) => ((m:name)(satF P (B m)))
          | (new B) => (Ex [m:name](notin_proc m P) /\ (notin_form m (forall B)) /\ (satF P (B m)))
        end.

(* Internal cross adequacy between sat and sat'. *)

Lemma SATF_SAT: (A:form)(P:proc)((satF P A) -> (sat P A)) /\ ((sat P A) -> (satF P A)).

Proof.

Induction A; Intros; Split; Intro.

Apply sat_T.

Simpl; Trivial.

Cut ~(sat P f)<->(sat P (neg f)); [Intro | Apply sat_neg].
Simpl in H0; Unfold iff in H1; Inversion_clear H1; Elim (H P); Intros.
Apply H2; Unfold not; Intro; Apply H0; Auto.

Elim (H P); Intros; Simpl; Cut ~(sat P f)<->(sat P (neg f)); [Intro | Apply sat_neg]; Intro.
Unfold iff in H3; Inversion_clear H3; Cut ~(sat P f); [Intro | Auto].
Unfold not in H3; Apply H3; Auto.

Simpl in H1; Elim (H P); Elim (H0 P); Intros; Cut (sat P f)\/(sat P f0)<->(sat P (Or f f0)); [Intro | Apply sat_Or].
Unfold iff in H6; Inversion_clear H6.
Apply H7; Inversion_clear H1; [Left | Right]; Auto.

Elim (H P); Elim (H0 P); Intros; Simpl; Cut (sat P f)\/(sat P f0)<->(sat P (Or f f0)); [Intro | Apply sat_Or].
Unfold iff in H6; Inversion_clear H6; Cut (sat P f) \/ (sat P f0); [Intro | Auto].
Inversion_clear H6; [Left | Right]; Auto.

Simpl in H; Cut (struct_eq P nil)<->(sat P zero); [Intro | Apply sat_zero].
Unfold iff in H0; Inversion_clear H0; Auto.

Simpl; Cut (struct_eq P nil)<->(sat P zero); [Intro | Apply sat_zero].
Unfold iff in H0; Inversion_clear H0; Auto.

Simpl in H1; Cut (EX P':proc | (EX P'':proc | (struct_eq P (par P' P''))/\(sat P' f)/\(sat P'' f0)))<->(sat P (comp f f0)); [Intro | Apply sat_comp].
Inversion_clear H1; Inversion_clear H3; Inversion_clear H1; Inversion_clear H4; Unfold iff in H2; Inversion_clear H2; Apply H4.
Elim (H x); Elim (H0 x0); Intros; Exists x; Exists x0; Split; Try Split; Auto.

Simpl; Cut (EX P':proc | (EX P'':proc | (struct_eq P (par P' P''))/\(sat P' f)/\(sat P'' f0)))<->(sat P (comp f f0)); [Intro | Apply sat_comp].
Unfold iff in H2; Inversion_clear H2; Cut (EX P':proc | (EX P'':proc | (struct_eq P (par P' P''))/\(sat P' f)/\(sat P'' f0))); [Intro | Auto].
Inversion_clear H2; Inversion_clear H5; Inversion_clear H2; Inversion_clear H6; Elim (H x); Elim (H0 x0); Intros; Exists x; Exists x0; Split; Try Split; Auto.

Simpl in H1; Cut ((P':proc)(sat P' f)->(sat (par P P') f0))<->(sat P (comp_adj f f0)); [Intro | Apply sat_comp_adj].
Unfold iff in H2; Inversion_clear H2; Apply H3; Intros.
Elim (H P'); Elim (H0 (par P P')); Intros; Auto.

Simpl; Intros; Cut ((P':proc)(sat P' f)->(sat (par P P') f0))<->(sat P (comp_adj f f0)); [Intro | Apply sat_comp_adj].
Unfold iff in H3; Inversion_clear H3; Cut ((P':proc)(sat P' f)->(sat (par P P') f0)); [Intro | Auto].
Elim (H P'); Elim (H0 (par P P')); Intros; Auto.

Simpl in H0; Inversion_clear H0; Inversion_clear H1; Cut (EX P':proc | (struct_eq P (ambient (name2cap n) P'))/\(sat P' f))<->(sat P (loc n f)); [Intro | Apply sat_loc].
Unfold iff in H1; Inversion_clear H1; Apply H3.
Elim (H x); Intros; Exists x; Split; Auto.

Simpl; Cut (EX P':proc | (struct_eq P (ambient (name2cap n) P'))/\(sat P' f))<->(sat P (loc n f)); [Intro | Apply sat_loc].
Unfold iff in H1; Inversion_clear H1; Cut (EX P':proc | (struct_eq P (ambient (name2cap n) P'))/\(sat P' f)); [Intro | Auto].
Inversion_clear H1; Inversion_clear H4; Elim (H x); Intros; Exists x; Split; Auto.

Simpl in H0; Cut (sat (ambient (name2cap n) P) f)<->(sat P (loc_adj f n)); [Intro | Apply sat_loc_adj].
Unfold iff in H1; Inversion_clear H1; Apply H2; Elim (H (ambient (name2cap n) P)); Intros; Auto.

Simpl; Cut (sat (ambient (name2cap n) P) f)<->(sat P (loc_adj f n)); [Intro | Apply sat_loc_adj].
Unfold iff in H1; Inversion_clear H1; Elim (H (ambient (name2cap n) P)); Intros; Auto.

Simpl in H0; Inversion_clear H0; Cut (notin_proc n P)/\(EX P':name->proc | (struct_eq P (nu P'))/\(sat (P' n) f))<->(sat P (rev n f)); [Intro | Apply sat_rev].
Unfold iff in H0; Inversion_clear H0; Inversion_clear H2; Inversion_clear H0; Apply H3; Split; [Assumption | Elim (H (x n)); Intros; Exists x; Split; Auto].

Simpl; Cut (notin_proc n P)/\(EX P':name->proc | (struct_eq P (nu P'))/\(sat (P' n) f))<->(sat P (rev n f)); [Intro | Apply sat_rev].
Unfold iff in H1; Inversion_clear H1; Cut (notin_proc n P)/\(EX P':name->proc | (struct_eq P (nu P'))/\(sat (P' n) f)); [Intro | Auto].
Inversion_clear H1; Inversion_clear H5; Inversion_clear H1; Split; [Assumption | Elim (H (x n)); Intros; Exists x; Split; Auto].

Simpl in H0; Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; Cut (EX P':name->proc | P=(P' n)/\(notin_proc n (nu P'))/\(sat (nu P') f))<->(sat P (rev_adj f n)); [Intro | Apply sat_rev_adj].
Unfold iff in H2; Inversion_clear H2; Apply H4; Elim (H (nu x)); Intros; Exists x; Split; Try Split; Auto.

Simpl; Cut (EX P':name->proc | P=(P' n)/\(notin_proc n (nu P'))/\(sat (nu P') f))<->(sat P (rev_adj f n)); [Intro | Apply sat_rev_adj].
Unfold iff in H1; Inversion_clear H1; Cut (EX P':name->proc | P=(P' n)/\(notin_proc n (nu P'))/\(sat (nu P') f)); [Intro | Auto].
Inversion_clear H1; Inversion_clear H4; Inversion_clear H5; Elim (H (nu x)); Intros; Exists x; Split; Try Split; Auto.

Simpl in H0; Inversion_clear H0; Inversion_clear H1; Cut (EX P':proc | (red_star P P')/\(sat P' f))<->(sat P (sometime f)); [Intro | Apply sat_sometime].
Unfold iff in H1; Inversion_clear H1; Apply H3.
Elim (H x); Intros; Exists x; Split; Auto.

Simpl; Cut (EX P':proc | (red_star P P')/\(sat P' f))<->(sat P (sometime f)); [Intro | Apply sat_sometime].
Unfold iff in H1; Inversion_clear H1; Cut (EX P':proc | (red_star P P')/\(sat P' f)); [Intro | Auto].
Inversion_clear H1; Inversion_clear H4; Elim (H x); Intros; Exists x; Split; Auto.

Simpl in H0; Inversion_clear H0; Inversion_clear H1; Cut (EX P':proc | (nest_star P P')/\(sat P' f))<->(sat P (somewhere f)); [Intro | Apply sat_somewhere].
Unfold iff in H1; Inversion_clear H1; Apply H3.
Elim (H x); Intros; Exists x; Split; Auto.

Simpl; Cut (EX P':proc | (nest_star P P')/\(sat P' f))<->(sat P (somewhere f)); [Intro | Apply sat_somewhere].
Unfold iff in H1; Inversion_clear H1; Cut (EX P':proc | (nest_star P P')/\(sat P' f)); [Intro | Auto].
Inversion_clear H1; Inversion_clear H4; Elim (H x); Intros; Exists x; Split; Auto.

Simpl in H0; Cut ((m:name)(sat P (f m)))<->(sat P (forall f)); [Intro | Apply sat_forall].
Unfold iff in H1; Inversion_clear H1; Apply H2; Intro.
Elim (H m P); Intros; Auto.

Simpl; Intro; Cut ((m:name)(sat P (f m)))<->(sat P (forall f)); [Intro | Apply sat_forall].
Unfold iff in H1; Inversion_clear H1; Cut ((m:name)(sat P (f m))); [Intro | Auto].
Elim (H m P); Intros; Auto.

Simpl in H0; Cut (EX m:name | (notin_proc m P)/\(notin_form m (forall f))/\(sat P (f m)))<->(sat P (new f)); [Intro | Apply sat_new].
Unfold iff in H1; Inversion_clear H1; Apply H2; Inversion_clear H0; Inversion_clear H1; Inversion_clear H4.
Elim (H x P); Intros; Exists x; Split; Try Split; Auto.

Simpl; Cut (EX m:name | (notin_proc m P)/\(notin_form m (forall f))/\(sat P (f m)))<->(sat P (new f)); [Intro | Apply sat_new].
Unfold iff in H1; Inversion_clear H1; Cut (EX m:name | (notin_proc m P)/\(notin_form m (forall f))/\(sat P (f m))); [Intro | Auto].
Inversion_clear H1; Inversion_clear H4; Inversion_clear H5.
Elim (H x P); Intros; Exists x; Split; Try Split; Auto.

Qed.

Lemma SATF_RW: (P:name->proc)(F:name->form)(x:name)
               (notin_proc x (nu P)) -> (notin_form x (forall F)) ->
               (satF (P x) (F x)) ->
               (y:name)
               (notin_proc y (nu P)) -> (notin_form y (forall F)) ->
               (satF (P y) (F y)).

Proof.

Intros; Elim (dec_name x y); Intros.
Rewrite <-H4; Assumption.
Elim (LN_TOT (F x)); Intros.
Elim (SATF_SAT (F y) (P y)); Intros.
Elim (SATF_SAT (F x) (P x)); Intros.
Apply H7; Apply PRE_SAT_RW with x0 (F x) (P x) x; Auto.

Qed.

(* Existential-Universal nature of freshness
   w.r.t. the satisfaction relation. *)

Lemma EXISTS_FORALL: (P:proc)(A:name->form)(Ex [m:name]((notin_proc m P) /\ (notin_form m (forall A)) /\ (sat P (A m)))) <-> ((m:name)((notin_proc m P) /\ (notin_form m (forall A))) -> (sat P (A m))).

Proof.

Intros; Unfold iff; Split; Intros.

Inversion_clear H; Inversion_clear H0; Inversion_clear H1; Inversion_clear H3.
Change (sat ([_:name]P m) (A m)); Apply SAT_RW with x; Try (Apply notin_proc_nu; Intros); Auto.

Elim (unsat P (forall A)); Intros.
Inversion_clear H0; Exists x; Split; Try Split; Auto.

Qed.

Lemma EXISTS_FORALL_F: (P:proc)(A:name->form)(Ex [m:name]((notin_proc m P) /\ (notin_form m (forall A)) /\ (satF P (A m)))) <-> ((m:name)((notin_proc m P) /\ (notin_form m (forall A))) -> (satF P (A m))).

Proof.

Intros; Unfold iff; Split; Intros.

Inversion_clear H; Inversion_clear H0; Inversion_clear H1; Inversion_clear H3.
Change (satF ([_:name]P m) (A m)); Apply SATF_RW with x; Try (Apply notin_proc_nu; Intros); Auto.

Elim (unsat P (forall A)); Intros.
Inversion_clear H0; Exists x; Split; Try Split; Auto.

Qed.

Lemma NEW_EXISTS: (A:name->form)(P:proc)(sat P (new A)) <-> (Ex [m:name]((notin_proc m P) /\ (notin_form m (forall A)) /\ (sat P (A m)))).

Proof.

Intros; Unfold iff; Split; Intro; (Cut (EX m:name | (notin_proc m P)/\(notin_form m (forall A))/\(sat P (A m)))<->(sat P (new A)); [Intro | Apply sat_new]; Unfold iff in H0; Inversion_clear H0; Auto).

Qed.

Lemma NEW_FORALL: (A:name->form)(P:proc)(sat P (new A)) <-> ((m:name)((notin_proc m P) /\ (notin_form m (forall A)) -> (sat P (A m)))).

Proof.

Intros; Unfold iff; Split; Intros.

Inversion_clear H0; Cut (EX m:name | (notin_proc m P)/\(notin_form m (forall A))/\(sat P (A m)))<->(sat P (new A)); [Intro | Apply sat_new].
Unfold iff in H0; Inversion_clear H0; Cut (EX m:name | (notin_proc m P)/\(notin_form m (forall A))/\(sat P (A m))); [Intro | Auto].
Inversion_clear H0; Inversion_clear H5; Inversion_clear H6.
Change (sat ([_:name]P m) (A m)); Apply SAT_RW with x; Try (Apply notin_proc_nu; Intros); Auto.

Cut (EX m:name | (notin_proc m P)/\(notin_form m (forall A))/\(sat P (A m)))<->(sat P (new A)); [Intro | Apply sat_new].
Unfold iff in H0; Inversion_clear H0; Apply H1.
Elim (unsat P (forall A)); Intros.
Inversion_clear H0; Cut (sat P (A x)); [Intro | Auto].
Exists x; Split; Try Split; Assumption.

Qed.

Lemma NEW_FORALL_F: (A:name->form)(P:proc)(satF P (new A)) <-> ((m:name)((notin_proc m P) /\ (notin_form m (forall A)) -> (satF P (A m)))).

Proof.

Intros; Unfold iff; Split; Intros; Simpl in H; Simpl.

Inversion_clear H; Inversion_clear H0; Inversion_clear H1; Inversion_clear H3; Change (satF ([_:name]P m) (A m)); Apply SATF_RW with x; Try (Apply notin_proc_nu; Intros); Auto.

Elim (unsat P (forall A)); Intros.
Inversion_clear H0; Cut (satF P (A x)); [Intro | Auto].
Exists x; Split; Try Split; Assumption.

Qed.

Lemma NEW_NOT_F: (A:name->form)(P:proc)(satF P (neg (new A))) <-> (satF P (new [x:name](neg (A x)))).

Proof.

Intros; Unfold iff; Split; Intro.
Simpl in H; Simpl.
Cut (EX m:name | (notin_proc m P) /\ (notin_form m (forall [_:name](neg (A _)))) /\ (satF P (neg (A m)))) <-> ((m:name)(notin_proc m P) /\ (notin_form m (forall [_:name](neg (A _)))) -> (satF P (neg (A m)))); [Intro | Change (EX m:name | (notin_proc m P) /\ (notin_form m (forall [_:name](neg (A _)))) /\ (satF P ([_:name](neg (A _)) m))) <-> ((m:name)(notin_proc m P) /\ (notin_form m (forall [_:name](neg (A _)))) -> (satF P ([_:name](neg (A _)) m))); Apply EXISTS_FORALL_F].
Unfold iff in H0; Inversion_clear H0; Apply H2; Intros.
Inversion_clear H0; Simpl; Intro; Apply H.
Exists m; Split; Try Split; Auto.
Inversion_clear H4; Apply notin_forall; Intros.
Cut (notin_form m (neg (A n))); [Intro | Auto].
Inversion_clear H6; Assumption.

Simpl in H; Simpl; Intro.
Inversion_clear H; Inversion_clear H1; Inversion_clear H2.
Apply H3; Elim (EXISTS_FORALL_F P A); Intros.
Cut (m:name)(notin_proc m P)/\(notin_form m (forall A))->(satF P (A m)); [Intro; Apply H5; Split | Idtac]; Auto.
Inversion_clear H1; Apply notin_forall; Intros.
Cut (notin_form x (neg (A n))); [Intro | Auto].
Inversion_clear H7; Assumption.

Qed.

Lemma NEW_COMP_F: (A,B:name->form)(P:proc)(satF P (new [x:name](comp (A x) (B x)))) <-> (satF P (comp (new A) (new B))).

Proof.

Intros; Unfold iff; Split; Intro; Simpl in H; Simpl.

Inversion_clear H; Inversion_clear H0; Inversion_clear H1; Inversion_clear H2; Inversion_clear H1; Inversion_clear H2; Inversion_clear H3.
Elim (STRUCT_NOTIN P (par x0 x1) H1 x); Intros; Cut (notin_proc x (par x0 x1)); [Intro | Auto].
Inversion_clear H6; Exists x0; Exists x1; Split; [Assumption | Split; Exists x; Split; Try Split; Try (Inversion_clear H0; Apply notin_forall; Intros; Cut (notin_form x (comp (A n) (B n))); [Intro | Auto]; Inversion_clear H9); Auto].

Inversion_clear H; Inversion_clear H0; Inversion_clear H; Inversion_clear H1.
Elim (EXISTS_FORALL_F x A); Elim (EXISTS_FORALL_F x0 B); Intros.
Elim (unsat (par P (par x x0)) (Or (forall A) (forall B))); Intros.
Inversion_clear H6; Inversion_clear H7; Inversion_clear H8.
Exists x1; Split; [Assumption | Split; [Apply notin_forall; Intros; Apply notin_comp; [Inversion_clear H7 | Inversion_clear H10]; Auto | Exists x; Exists x0; Split; Try Split; Auto]].
Cut (m:name)(notin_proc m x)/\(notin_form m (forall A))->(satF x (A m)); [Intro | Auto].
Apply H8; Split; [Inversion_clear H9 | Idtac]; Assumption.
Cut (m:name)(notin_proc m x0)/\(notin_form m (forall B))->(satF x0 (B m)); [Intro | Auto].
Apply H8; Split; [Inversion_clear H9 | Idtac]; Assumption.

Qed.

(* Hidden-Name Quantifier *)

Definition nu_f: (name -> form) -> form := [A:name->form](new [x:name](rev x (A x))).

Lemma NU_F_SATF: (P:proc)(A:name->form)(satF P (nu_f A)) <->
                 (Ex [m:name]((notin_proc m P) /\ (notin_form m (forall A))
                           /\ (Ex [P':name->proc](struct_eq P (nu P')) /\ (satF (P' m) (A m))))).

Proof.

Intros; Unfold iff; Split; Intro.

Unfold nu_f in H; Simpl in H.
Inversion_clear H; Inversion_clear H0; Inversion_clear H1; Inversion_clear H2.
Exists x; Split; [Assumption | Split; [Apply notin_forall; Intros; Inversion_clear H0; Cut (notin_form x (rev n (A n))); [Intro | Auto]; Inversion_clear H0; Assumption | Assumption]].

Inversion_clear H; Inversion_clear H0; Inversion_clear H1; Unfold nu_f; Simpl.
Exists x; Split; [Assumption | Split; [Apply notin_forall; Intros; Inversion_clear H0; Apply notin_rev; Auto | Split; Assumption]].

Qed.

Lemma NU_F_SATF_PROPER: (n:name)(P:proc)(A:name->form)(notin_proc n P) ->
                        (notin_form n (forall A)) -> (satF P (nu_f A)) <->
                        (Ex [P':name->proc](struct_eq P (nu P')) /\ (satF (P' n) (A n))).

Proof.

Intros; Unfold iff; Split; Intro.

Simpl in H1.
Inversion_clear H1; Inversion_clear H2; Inversion_clear H3; Inversion_clear H4; Inversion_clear H5; Inversion_clear H4.
Exists x0; Split; [Assumption | Apply SATF_RW with x; Auto].
Elim (STRUCT_NOTIN P (nu x0) H5 x); Intros; Auto.
Inversion_clear H0; Apply notin_forall; Intros.
Cut (notin_form x (rev n0 (A n0))); [Intro | Auto].
Inversion_clear H7; Assumption.
Inversion_clear H2.
Cut (notin_form x (rev n0 (A n0))); [Intro | Auto].
Inversion_clear H2; Apply notin_rev; Auto.
Elim (STRUCT_NOTIN P (nu x0) H5 n); Intros; Auto.

Inversion_clear H1; Simpl.
Inversion_clear H2; Exists n; Split; Try Split; Auto.
Inversion_clear H0; Apply notin_forall; Intros.
Cut (notin_form n (A n0)); [Intro | Auto].
Apply notin_rev; Auto.
Split; [Assumption | Exists x; Split; Auto].

Qed.

(* Mutual Inductive Definition of satisfaction relation *)

Mutual Inductive satI: proc -> form -> Prop:=
    satI_T: (P:proc)(satI P T)
  | satI_neg: (P:proc)(A:form)(n_satI P A) -> (satI P (neg A))
  | satI_OrL: (P:proc)(A,B:form)(satI P A) -> (satI P (Or A B))
  | satI_OrR: (P:proc)(A,B:form)(satI P B) -> (satI P (Or A B))
  | satI_zero: (P:proc)(struct_eq P nil) -> (satI P zero)
  | satI_comp: (P:proc)(A,B:form)
               (Ex [P':proc](Ex [P'':proc]
                 (struct_eq P (par P' P'')) /\ (satI P' A) /\ (satI P'' B))) ->
               (satI P (comp A B))
  | satI_comp_adj: (P:proc)(A,B:form)
                   ((P':proc)(n_satI P' A) \/ (satI (par P P') B)) ->
                   (satI P (comp_adj A B))
  | satI_loc: (P:proc)(n:name)(A:form)
              (Ex [P':proc](struct_eq P (ambient (name2cap n) P')) /\
              (satI P' A)) -> (satI P (loc n A))
  | satI_loc_adj: (P:proc)(n:name)(A:form)(satI (ambient (name2cap n) P) A) ->
                  (satI P (loc_adj A n))
  | satI_rev: (P:proc)(n:name)(A:form)(notin_proc n P) /\
              (Ex [P':name->proc](struct_eq P (nu P')) /\ (satI (P' n) A)) ->
              (satI P (rev n A))
  | satI_rev_adj: (P:proc)(n:name)(A:form)
                  (Ex [P':name->proc]P=(P' n) /\
                    (notin_proc n (nu P')) /\ (satI (nu P') A)) ->
                  (satI P (rev_adj A n))
  | satI_sometime: (P:proc)(A:form)
                   (Ex [P':proc](red_star P P') /\ (satI P' A)) ->
                   (satI P (sometime A))
  | satI_somewhere: (P:proc)(A:form)
                    (Ex [P':proc](nest_star P P') /\ (satI P' A)) ->
                    (satI P (somewhere A))
  | satI_forall: (P:proc)(A:name->form)
                 ((m:name)(satI P (A m))) -> (satI P (forall A))
  | satI_new: (P:proc)(A:name->form)
              (Ex [m:name](notin_proc m P) /\ (notin_form m (forall A)) /\
                          (satI P (A m))) ->
              (satI P (new A))
with n_satI: proc -> form -> Prop:=
    n_satI_neg: (P:proc)(A:form)(satI P A) -> (n_satI P (neg A))
  | n_satI_Or: (P:proc)(A,B:form)((n_satI P A) /\ (n_satI P B)) ->
              (n_satI P (Or A B))
  | n_satI_zero: (P:proc)~(struct_eq P nil) -> (n_satI P zero)
  | n_satI_comp: (P:proc)(A,B:form)
                 ((P',P'':proc)
                  (struct_eq P (par P' P'')) ->
                  ((n_satI P' A) \/ (n_satI P'' B))) ->
                 (n_satI P (comp A B))
  | n_satI_comp_adj: (P:proc)(A,B:form)
                     (Ex [P':proc](satI P' A) /\ (n_satI (par P P') B)) ->
                     (n_satI P (comp_adj A B))
  | n_satI_loc: (P:proc)(n:name)(A:form)
                ((P':proc)(struct_eq P (ambient (name2cap n) P')) ->
                 (n_satI P' A)) -> (n_satI P (loc n A))
  | n_satI_loc_adj: (P:proc)(n:name)(A:form)
                    (n_satI (ambient (name2cap n) P) A) ->
                    (n_satI P (loc_adj A n))
  | n_satI_rev: (P:proc)(n:name)(A:form)(isin_proc n P) \/
                ((P':name->proc)(struct_eq P (nu P')) -> (n_satI (P' n) A)) ->
                (n_satI P (rev n A))
  | n_satI_rev_adj: (P:proc)(n:name)(A:form)
                    ((P':name->proc)P=(P' n) /\
                      (notin_proc n (nu P')) -> (n_satI (nu P') A)) ->
                    (n_satI P (rev_adj A n))
  | n_satI_sometime: (P:proc)(A:form)
                     ((P':proc)(red_star P P') -> (n_satI P' A)) ->
                     (n_satI P (sometime A))
  | n_satI_somewhere: (P:proc)(A:form)
                      ((P':proc)(nest_star P P') -> (n_satI P' A)) ->
                      (n_satI P (somewhere A))
  | n_satI_forall: (P:proc)(A:name->form)
                   (Ex [m:name](n_satI P (A m))) -> (n_satI P (forall A))
  | n_satI_new: (P:proc)(A:name->form)
                ((m:name)(notin_proc m P) /\ (notin_form m (forall A)) ->
                         (n_satI P (A m))) ->
                (n_satI P (new A)).

Lemma NSATI_NOT_SATI: (A:form)(P:proc)(n_satI P A) -> ~(satI P A).

Proof.

Induction A; Intros.

Inversion_clear H.

Inversion_clear H0; Unfold not; Intro; Inversion_clear H0; Cut ~(satI P f); [Intro | Apply H; Assumption]; Unfold not in H0; Auto.

Unfold not; Intro; Inversion_clear H1.
Inversion_clear H3.
Inversion_clear H2; [Cut ~(satI P f); [Intro | Auto] | Cut ~(satI P f0); [Intro | Auto]]; Unfold not in H2; Auto.

Inversion_clear H.
Unfold not; Intro.
Unfold not in H0; Apply H0.
Inversion_clear H; Assumption.

Unfold not; Intro; Inversion_clear H1; Inversion_clear H2.
Inversion_clear H1; Inversion_clear H2; Inversion_clear H1; Inversion_clear H4.
Cut (struct_eq P (par x x0))->(n_satI x f)\/(n_satI x0 f0); [Intro | Auto].
Cut (n_satI x f)\/(n_satI x0 f0); [Intro | Auto].
Inversion_clear H6; [Cut ~(satI x f); [Intro | Auto] | Cut ~(satI x0 f0); [Intro | Auto]]; Unfold not in H6; Auto.

Unfold not; Intro; Inversion_clear H1; Inversion_clear H2.
Inversion_clear H3; Inversion_clear H2.
Cut (n_satI x f)\/(satI (par P x) f0); [Intro | Auto].
Inversion_clear H2; [Cut (n_satI x f)->~(satI x f); [Intro | Auto] | Cut (n_satI (par P x) f0)->~(satI (par P x) f0); [Intro | Auto]]; Unfold not in H2; Auto.

Inversion_clear H0; Unfold not; Intro; Inversion_clear H0; Inversion_clear H2; Inversion_clear H0.
Cut (n_satI x f)->~(satI x f); [Intro | Auto].
Cut (n_satI x f); [Intro | Auto].
Cut ~(satI x f); [Intro | Auto].
Unfold not in H5; Apply H5; Auto.

Inversion_clear H0; Unfold not; Intro; Inversion_clear H0.
Cut ~(satI (ambient (name2cap n) P) f); [Intro | Auto].
Unfold not in H0; Apply H0; Auto.

Inversion_clear H0; Unfold not; Intro; Inversion_clear H1.
Inversion_clear H0; Inversion_clear H1; Inversion_clear H3; Inversion_clear H1.
Apply ISIN_NOTIN_PROC_FALSE with P n; Assumption.
Inversion_clear H0; Inversion_clear H1; Inversion_clear H3; Inversion_clear H1.
Cut (n_satI (x n) f); [Intro | Auto].
Cut ~(satI (x n) f); [Intro | Auto].
Unfold not in H5; Apply H5; Assumption.

Inversion_clear H0; Unfold not; Intro; Inversion_clear H0.
Inversion_clear H2; Inversion_clear H0; Inversion_clear H3.
Cut (n_satI (nu x) f); [Intro | Auto].
Cut ~(satI (nu x) f); [Intro | Auto].
Unfold not in H5; Apply H5; Assumption.

Inversion_clear H0; Unfold not; Intro; Inversion_clear H0.
Inversion_clear H2; Inversion_clear H0.
Cut (n_satI x f); [Intro | Auto].
Cut ~(satI x f); [Intro | Auto].
Unfold not in H4; Apply H4; Assumption.

Inversion_clear H0; Unfold not; Intro; Inversion_clear H0.
Inversion_clear H2; Inversion_clear H0.
Cut (n_satI x f); [Intro | Auto].
Cut ~(satI x f); [Intro | Auto].
Unfold not in H4; Apply H4; Assumption.

Inversion_clear H0; Unfold not; Intro; Inversion_clear H0.
Inversion_clear H1.
Cut ~(satI P (f x)); [Intro | Auto].
Unfold not in H1; Apply H1; Auto.

Inversion_clear H0; Unfold not; Intro; Inversion_clear H0.
Inversion_clear H2; Inversion_clear H0; Inversion_clear H3.
Cut (n_satI P (f x)); [Intro | Apply H1; Split; Assumption].
Cut ~(satI P (f x)); [Intro | Auto].
Unfold not in H5; Apply H5; Assumption.

Qed.

Lemma SATI_NOT_NSATI: (A:form)(P:proc)(satI P A) -> ~(n_satI P A).

Proof.

Intros; Unfold not; Intro; Cut ~(satI P A); [Intro | Apply NSATI_NOT_SATI; Assumption].
Unfold not in H1; Apply H1; Assumption.

Qed.

Lemma SATI_NSATI: (A:form)(P:proc)(satI P A) -> (n_satI P A) -> False.

Proof.

Intros; Cut ~(satI P A); [Intro | Apply NSATI_NOT_SATI; Assumption].
Unfold not in H1; Apply H1; Assumption.

Qed.
