# Ranked Nu-trees

Require Export Tree.

## Definition

(*
A nu-tree can have nu nodes in addition to the usual tree construction.
Nu nodes have a name and a subtree.
*)

Inductive NuTree : Type :=
| Tr : Name -> list NuTree -> NuTree
| Nu : Name -> NuTree -> NuTree.

Implicit Type n nt : NuTree.

(*
A default nu-tree used for nth
*)

Definition DNT :=
Tr (O, O) nil.

Inductive Ntwr : NuTree -> Prop :=
| ntwrA a l : (forall x, x el l -> Ntwr x) -> (rk a) = |l| -> Ntwr (Tr a l)
| ntwrB a x : Ntwr x -> Ntwr (Nu a x).

Lemma nt_wr_sub a l :
Ntwr (Tr a l) -> forall n, n el l -> Ntwr n.
Proof.
inversion 1. intros. auto.
Qed.

Lemma nt_wr_sub' a n :
Ntwr (Nu a n) -> Ntwr n.
Proof.
now inversion 1.
Qed.

(*
Two tactics used to solve proof obligations for wellrankedness
*)

Ltac solve_len :=
repeat match goal with
| [ H : context [?k < length ?l] |- ?k < length ?l ] => assumption
| [ H1 : context [?k < length ?l], H2 : context [ length ?l = length ?l' ] |- ?k < length ?l' ] => now rewrite <-H2
| [ H1 : context [?k < length (map ?f ?l)] |- _ ] => rewrite map_length in H1
| [ |- ?k < length (map ?f ?l) ] => rewrite map_length
| [ |- ?k < length ?l' ] => try congruence
end.

Ltac solve_wr_sub :=
match goal with
| [ H : context [Ntwr (Tr ?a ?l)] |- Ntwr (nth ?k ?l ?m) ] => apply (nt_wr_sub H), nth_In; solve_len
| [ H : context [Ntwr (Nu ?a ?n)] |- Ntwr ?n ] => apply (nt_wr_sub' H); solve_len
| [ H : context [Twr (TrA ?a ?l)] |- Twr (nth ?k ?l ?m) ] => apply (tree_wr_sub H), nth_In; solve_len
| [ H : context [ forall x, x el ?l -> Ntwr x] |- Ntwr (nth ?k ?l ?m) ] => apply H, nth_In; solve_len
| [ H : context [ forall x, x el ?l -> Twr x ] |- Twr (nth ?k ?l ?m) ] => apply H, nth_In; solve_len
end.

## Depth

Section Depth.

(*
We later define a procedure on nu-trees which is not structurally recursive.
We define the depth of a nu-tree here to enable using it as a termination parameter.
*)

Implicit Type nl : list NuTree.

Fixpoint nt_depth n : nat :=
match n with
| Tr a l => S (list_max (map nt_depth l))
| Nu a n' => S (nt_depth n')
end.

Lemma gt_depth_sub nl k d :
k < |nl| -> d >= (list_max (map nt_depth nl)) -> d >= nt_depth (nth k nl DNT).
Proof.
intros H1 H2. enough(nt_depth(nth k nl DNT) <= list_max (map nt_depth nl)) by omega.
apply list_max_max, in_map_iff. exists (nth k nl DNT).
split; auto using nth_In.
Qed.

Lemma nt_decrease a nl n :
n el nl -> nt_depth n < nt_depth (Tr a nl).
Proof.
intros H1. simpl.
assert(nt_depth n <= (list_max (map nt_depth nl))) by (apply list_max_max, in_map_iff; eauto).
omega.
Qed.

Lemma nt_decrease' a n :
nt_depth n < nt_depth (Nu a n).
Proof.
simpl. auto.
Qed.

Lemma ntd_S n :
nt_depth n <> 0.
Proof.
destruct n; simpl; auto.
Qed.

Lemma ntd_S' n :
nt_depth n > 0.
Proof.
destruct n; simpl; omega.
Qed.

End Depth.

## Names

Fixpoint nt_names n : list Name :=
match n with
| Tr a l => a :: (concat (map nt_names l))
| Nu a x => a :: nt_names x
end.

Lemma nt_name_in_sub a n a' l:
a el (nt_names n) -> n el l -> a el (nt_names (Tr a' l)).
Proof.
intros H1 H2. simpl. right. apply concat_map_el.
exists n. now split.
Qed.

(*
There is no empty tree
*)

Fact nt_names_inhab nt :
exists a, a el (nt_names nt).
Proof.
destruct nt; simpl; eauto.
Qed.

Fixpoint BN n : list Name :=
match n with
| Tr a l => concat (map BN l)
| Nu a x => a :: (BN x)
end.

Lemma BN_in_sub a n b l:
a el (BN n) -> n el l -> a el (BN (Tr b l)).
Proof.
intros H1 H2. simpl. apply concat_map_el. now exists n.
Qed.

Lemma bound_in_names n :
Ntwr n -> (BN n) <<= (nt_names n).
Proof.
induction 1 as [a' l H3 H4 _| a' x H3 H4]; simpl.
- apply incl_cons, concat_incl_list, H4.
- intros a [<-|]; auto.
Qed.

Fixpoint FN n :=
match n with
| Tr a l => a :: (concat (map FN l))
| Nu a x => rem (FN x) a
end.

Lemma FN_in_sub a n l b :
a el (FN n) -> n el l -> a el (FN (Tr b l)).
Proof.
intros H1 H2. simpl. right. apply concat_map_el. now exists n.
Qed.

Lemma free_in_names n :
Ntwr n -> (FN n) <<= (nt_names n).
Proof.
induction 1 as [a' l H3 H4 _| a' x H3 H4]; simpl.
- apply incl_shift, concat_incl_list, H4.
- intros a [H5 H6] % in_rem_iff. auto.
Qed.

Lemma tree_name_free a l :
a el FN (Tr a l).
Proof. simpl. now left. Qed.

Lemma free_sub_not a n :
Ntwr n -> ~a el nt_names n -> ~a el FN n.
Proof.
intros HW1 H1 H2 % free_in_names; auto.
Qed.

(*
A name that was free, but isn't free after adding a binding
is equal to the name that was bound.
*)

Lemma bind_free_name b a n :
b el FN n -> ~ b el FN (Nu a n) -> b = a.
Proof.
simpl. intros H1 H2. rewrite in_rem_iff in H2.
intuition. decide(b=a) as [|]; tauto.
Qed.

(*
Inductive predicate for nu-trees without any nus
*)

Inductive NoNus : NuTree -> Prop :=
nonusA a l : (forall x, x el l -> (NoNus x)) -> NoNus (Tr a l).

Fact BN_no_nus n :
Ntwr n -> (BN n = [] <-> NoNus n).
Proof.
intros H1. split.
- induction H1; simpl; auto.
+ rewrite concat_nil'. intros H2. constructor. intros n H3. apply H0; trivial.
apply H2, in_map_iff. eauto.
+ inversion 1.
- induction 1. simpl. rewrite concat_nil'. intros la [n [H2 H3]] % in_map_iff. rewrite <-H2.
inversion H1. subst. apply H0; auto.
Qed.

(*
Inductive predicate for nu-trees without any nus of given rank
*)

Inductive NoNusk (k : nat) : NuTree -> Prop :=
| nonuskA a l : (forall x, x el l -> (NoNusk k x)) -> NoNusk k (Tr a l)
| nonuskB a n : NoNusk k n -> rk a <> k -> NoNusk k (Nu a n).

Fact BN_no_nusk n k :
Ntwr n -> ((forall a, a el BN n -> rk a <> k) <-> NoNusk k n).
Proof.
intros H1. split.
- induction H1 as [a l H1 H2 H3| a n H1 H2]; simpl in *; auto.
+ intros H4. constructor. intros n H5. apply H2; trivial.
intros b H6. apply H4, (BN_in_sub a H6), H5.
+ intros H3. constructor.
* apply H2. intros b H4. apply H3. now right.
* apply H3. now left.
- induction 1 as [a l H2 H3| a n H2 H3 H4]; simpl; intros b; inversion H1; subst.
+ intros [n [H6 H7]] % concat_map_el. apply (H3 n H6); auto.
+ intros [|]; try now subst. apply H3; auto.
Qed.

## Action

Fixpoint nt_apply_perm p n :=
match n with
| Tr a l => Tr (p a) (map (nt_apply_perm p) l)
| Nu a x => Nu (p a) (nt_apply_perm p x)
end.

Notation "p *' n" := (nt_apply_perm p n) (at level 45).

Lemma nt_apply_perm_step p a l :
Tr (p a) (map (nt_apply_perm p) l) = p *' (Tr a l).
Proof. reflexivity. Qed.

Section NtAction.

Variable n : NuTree.
Hypothesis HW : Ntwr n.

Lemma nt_assoc p p' :
(p ** p') *' n = (p *' (p' *' n)).
Proof.
induction HW as [a l H1 H2 _ | a x H1 H2]; simpl; f_equal; auto.
rewrite map_map, map_ext_in with (g := (fun n => p *' (p' *' n))); auto.
Qed.

Lemma nt_id :
id *' n = n.
Proof.
induction HW as [a l H1 H2 _ | a x H1 H2]; simpl; f_equal; auto.
rewrite map_ext_in with (g := (fun x => x)); auto using map_id.
Qed.

(*
( *' ) is a sym action for NuTree.
*)

Fact nt_sym :
id *' n = n /\ forall p q, (p ** q) *' n = (p *' (q *' n)).
Proof.
split.
- apply nt_id.
- intros. apply nt_assoc.
Qed.

(*
Lemma about applying a permutation and its inverse to a nu-tree
*)

Lemma nt_perm_apply_inv p p' :
Inv p p' -> n = (p *' (p' *' n)).
Proof.
induction HW as [a l H1 H2 H3| a x H1 H2]; intros H4; simpl.
- assert(HP2: Inv p p') by assumption. specialize (H4 a) as [H4 ->].
rewrite map_map, map_ext_in with (g := fun x => x); try now rewrite map_id.
intros n H5. rewrite <-(H2 n); auto.
- assert(HP2: Inv p p') by assumption. specialize (H4 a) as [H4 ->].
rewrite <-H2; auto.
Qed.

Fact nt_perm_wr p :
Perm p -> Ntwr (p *' n).
Proof.
induction HW as [a l H1 H2 H3 | a x H1 H2]; intros HP; simpl; constructor; auto.
- intros s [s'[<- H7]] % in_map_iff. apply H2; auto.
- destruct HP as [H4 _]. now rewrite map_length, <- H4.
Qed.

Lemma nt_depth_perm p :
nt_depth n = nt_depth (p *' n).
Proof.
induction HW as [a l H1 H2 H3| a' n H1 H2]; simpl; f_equal; auto. f_equal.
rewrite map_map, map_ext_in with (g := fun n => nt_depth (p*'n)); auto.
Qed.

Lemma nt_swap_perm p p' :
(forall a, p a = p' a) -> p *' n = (p' *' n).
Proof.
intros H2. induction HW as [a l H3 H4 _ | a n H3 H4]; simpl; rewrite (H2 a); f_equal; auto.
apply map_ext_in. auto.
Qed.

(*
Stronger version than above, names not in the tree don't matter
With this lemma we get nominality.
*)

Lemma nt_swap_perm' p p' :
(forall a, a el nt_names n -> p a = p' a) -> p *' n = (p' *' n).
Proof.
intros H2. induction HW as [a l H3 H4 _ | a n H3 H4]; simpl; rewrite <-(H2 a); simpl; auto; f_equal.
- apply map_ext_in. intros n H5. apply H4; auto.
intros b H6. apply H2, (nt_name_in_sub a H6 H5).
- rewrite H4; auto. intros b H5. apply H2. simpl. auto.
Qed.

(*
This case occurs frequently.
*)

Lemma nt_swap_perm'' p p' p'' :
(forall a, a el nt_names n -> (p ** p') a = p'' a) -> p *' (p' *' n) = (p'' *' n).
Proof.
intros H1. rewrite <-nt_assoc. now apply nt_swap_perm'.
Qed.

(*
Nu-trees are nominal
*)

Fact nt_nominal p :
(forall x, x el nt_names n -> p x = x) -> p *' n = n.
Proof.
intros H2. rewrite nt_swap_perm' with (p' := id); trivial. exact (nt_id).
Qed.

Lemma nt_assoc3 p1 p2 p3 :
(p1 ** (p2 ** p3) *' n) = (p1 ** p2 ** p3 *' n).
Proof.
now apply nt_swap_perm; trivial.
Qed.

End NtAction.

## Equivariant functions

Section Equivariance.

Variable n : NuTree.
Variable p : NameF.
Hypothesis HW : Ntwr n.

(*
The functions we have defined for nu-trees are all equivariant.
*)

Lemma nt_names_equiv :
nt_names (p *' n) = (p *- (nt_names n)).
Proof.
induction HW as [a l H3 H4 H5| a n t H1]; simpl; try now rewrite H1.
unfold perm_list. rewrite concat_map, map_map, map_map. f_equal. f_equal.
apply map_ext_in. intros. apply H4; auto.
Qed.

Lemma BN_equiv :
p *- (BN n) = BN (p *' n).
Proof.
induction HW as [a l H3 H4 H5| a n t H1]; simpl; try now rewrite H1.
unfold perm_list. rewrite concat_map, map_map, map_map. f_equal. apply map_ext_in.
intros. apply H4; auto.
Qed.

Lemma rem_equiv (a : Name) (l : list Name) :
Perm p -> p *- (rem l a) = rem (p *- l) (p a) .
Proof.
intros HP. induction l as [ | b l IH]; simpl; trivial. decide (p b = p a) as [E1|E1].
- rewrite perm_inj in E1; try assumption. subst. now rewrite rem_fst, rem_fst, <-IH.
- rewrite rem_fst', rem_fst', <-IH; auto. now rewrite <-perm_inj with (p:= p).
Qed.

Lemma rem_equiv' (a b : Name) (l : list Name) :
Perm p -> b = p a -> p *- (rem l a) = rem (p *- l) b.
Proof.
intros H1 H2. subst b. now apply rem_equiv.
Qed.

Lemma FN_equiv :
Perm p -> FN (p *' n) = (p *- FN n).
Proof.
intros H1. induction HW as [a l H2 H3 H4| a n' H2 H3]; simpl.
- unfold perm_list. rewrite concat_map, map_map, map_map. f_equal. f_equal.
apply map_ext_in. intros. apply H3; auto.
- rewrite H3; trivial. now rewrite (rem_equiv a (FN n') H1).
Qed.

Lemma FN_equiv_shift p' a :
Perm p -> Inv p' p -> a el FN (p *' n) <-> p' a el FN n.
Proof.
intros H1 H2. split; intros H4.
- rewrite FN_equiv in H4; try assumption. now rewrite <-(perm_list_shift (FN n) a H2).
- rewrite FN_equiv; try assumption. now rewrite (perm_list_shift (FN n) a H2).
Qed.

Lemma no_nusk_equiv k :
Perm p -> NoNusk k n -> NoNusk k (p *' n).
Proof.
intros HP H1. rewrite <-BN_no_nusk in H1; trivial. apply BN_no_nusk; auto using nt_perm_wr.
intros a. rewrite <-BN_equiv.
destruct HP as [HP1 [p' HP2]].
rewrite (perm_list_shift (BN n) a (inv_comm HP2)).
intros H2 H3. apply (H1 (p' a)); trivial. rewrite HP1.
destruct (HP2 a) as [_ HP3]. now rewrite HP3.
Qed.

End Equivariance.

Hint Resolve ntwrA ntwrB nt_wr_sub nt_wr_sub' tree_wr_sub inv_comm nt_perm_wr free_sub_not list_max_max nth_In.

(*
Later we often need a fresh name relative to these parameters
*)

Definition fresh A n t k :=
fresh' (A ++ nt_names n ++ names t) k.

Lemma freshness A n t k :
let x := fresh A n t k in
~x el A /\ ~x el nt_names n /\ ~x el names t /\ k = rk x.
Proof.
intros x.
assert(H1: ~x el (A++(nt_names n)++(names t))) by apply freshness'.
rewrite in_app_iff, in_app_iff in H1. intuition.
Qed.

Lemma fresh_name A n t k :
{ x | ~x el A /\ ~x el nt_names n /\ ~x el names t /\ k = rk x}.
Proof.
pose(f:= fresh A n t k). exists f. apply freshness.
Qed.

## Language of Nu-tree

### Definition

Inductive NtAccept : list Name -> NuTree -> Tree -> Prop :=
| DNLs A l l' a :
(|l| = |l'|) ->
(forall (k : nat), k < |l| -> NtAccept (a::A) (nth k l DNT) (nth k l' DTR)) ->
NtAccept A (Tr a l) (TrA a l')
| DNNu A n t a b :
~ b el A -> ~ b el FN (Nu a n) -> rk a = rk b ->
NtAccept (b::A) (a\$b *' n) t ->
NtAccept A (Nu a n) t.

Notation "t 'El' [ n ] A" := (NtAccept A n t)(at level 80).

(*
Top node name has to match
*)

Lemma ntl_name A a a' l l':
TrA a' l' El [ Tr a l] A -> a = a'.
Proof. now inversion 1. Qed.

(*
If a name c appears as a free name in a nu-tree n, and t is in
the language of n, then the name c has to be in t.
Intuitively, a free name is not permuted or instantiated.
*)

Lemma ntl_name_in n t c :
Ntwr n -> forall A, t El [n] A -> c el FN n -> c el names t.
Proof.
intros H2 A H3 HC.
induction H3 as [A l l' a H3 H4 H5| A n t a b H3 H4 H5 H6 H7]; simpl in *.
- destruct HC as [|[lc [H6 H7]] % concat_el]; try now left.
rewrite nth_el_indx_map with (x:= DNT) in H7. destruct H7 as [k [H7 H8]].
right. apply concat_map_el. subst lc.
exists (nth k l' DTR). split.
+ apply nth_In. congruence.
+ apply H5; try assumption. solve_wr_sub.
- inversion H2. apply in_rem_iff in HC as [HC1 HC2]. rewrite in_rem_iff in H4.
apply H7; auto. rewrite FN_equiv_shift with (p':=a\$b); auto. solve_dec; tauto.
Qed.

Lemma ntl_name_not_in n t c :
Ntwr n -> forall A, t El [n] A -> ~c el names t -> ~c el FN n.
Proof.
intros H2 A H3 HA HC.
induction H3 as [A l l' a H3 H4 H5| A n t a b H3 H4 H5 H6 H7]; simpl in *.
- intuition. apply concat_el in H as [nl [H6 H7]].
rewrite nth_el_indx_map with (x:=DNT) in H7. destruct H7 as [k [H7 H8]]. subst nl.
apply (H5 k); auto; try solve_wr_sub; try congruence; try intros [|]; auto. intros H8.
apply H1, concat_map_el. exists (nth k l' DTR). split; trivial. apply nth_In. congruence.
- inversion H2. subst. rewrite in_rem_iff in H4.
rewrite in_rem_iff in HC. destruct HC as [H8 H9].
apply H7; auto. rewrite FN_equiv_shift with (p':=a\$b); auto.
solve_dec; tauto.
Qed.

(*
Order of names doesn't matter in the list of names that have been seen before.
*)

Lemma ntl_swap_list A B n t :
t El [n] A -> A === B -> t El [n] B.
Proof.
intros HD. revert B.
induction HD as [A l l' a H1 _ H3| A n t a b H1 H2 H3 _ H5]; intros B AB.
- constructor; trivial. intros k KL.
apply H3; trivial. now rewrite AB.
- econstructor; try eassumption.
+ rewrite <- AB. apply H1.
+ apply H5. now rewrite AB.
Qed.

### Equivariance

(*
Equivariance of the nu-tree language
*)

Fact ntl_equiv' n t A p :
Perm p -> Ntwr n -> t El [n] A -> p *> t El [p *' n] p *- A.
Proof.
intros HP HW H1. induction H1 as [A' l l' a'' H3 H4 H5| A' n t a b H3 H4 H5 H6 H7].
- simpl. constructor.
+ now rewrite map_length, map_length.
+ intros k H8. rewrite map_length in H8.
rewrite nth_indep with (d' := p *' DNT), nth_indep with (d' := p *> DTR); solve_len.
rewrite map_nth, map_nth. apply H5; auto. solve_wr_sub.
- apply DNNu with (b := p b); fold nt_apply_perm; auto.
+ now intros H8 % perm_list_el.
+ simpl in *. rewrite FN_equiv, <-rem_equiv, perm_list_el; auto; solve_wr_sub.
+ rewrite <-nt_assoc in H7; eauto.
rewrite <-perm_list_step, <-nt_assoc,
nt_swap_perm with (p':=p**a\$b); try solve_wr_sub; eauto.
symmetry. now apply transp_compose.
Qed.

(*
This fact is shown using the previous fact and the permutation inverse.
*)

Fact ntl_equiv'' n t A p :
Twr t -> Perm p -> Ntwr n -> p *> t El [p *' n] p *- A -> t El [n] A.
Proof.
intros HT HP. assert(H2: Perm p) by assumption.
destruct HP as [_ [p' HP]]. intros HW H1. assert(HP2: Inv p' p) by apply inv_comm, HP.
apply (ntl_equiv' (perm_inv_perm H2 HP) (nt_perm_wr HW H2)) in H1.
now rewrite <-(perm_apply_inv HT HP2), <-(nt_perm_apply_inv HW HP2), (perm_list_inv A (inv_comm HP)) in H1.
Qed.

Theorem ntl_equiv n t A p :
Twr t -> Perm p -> Ntwr n -> t El [n] A <-> p *> t El [p *' n] p *- A.
Proof.
intros HW1 HP HW2. split.
- intros. now apply ntl_equiv'.
- now intros H % ntl_equiv''.
Qed.

## Structurally similar nu-trees

Section Structure.

(*
Deciding structural equality on wellranked nu-trees.
We consider nu-trees structurally equal if they only differ in the names
of bindings.
The free names and the rest of the strucutre have to be the same.
*)

Variable n : NuTree.
Variable n' : NuTree.
Hypothesis HW1 : Ntwr n.
Hypothesis HW2 : Ntwr n'.

Inductive NtStr : NuTree -> NuTree -> Prop :=
| NtStrA a l l' : |l| = |l'| -> |l| = rk a -> (forall k, k < |l| -> NtStr (nth k l DNT) (nth k l' DNT)) -> NtStr (Tr a l) (Tr a l')
| NtStrB a b n n' : rk a = rk b -> ~ b el FN(n') -> ~b el FN(n) -> NtStr n (a\$b *' n') -> NtStr (Nu a n) (Nu b n').

Fixpoint nt_str n n' : bool :=
match n, n' with
| Tr a l, Tr b l' =>
if Dec (a=b)
then all_true (map_pw (map nt_str l) l')
else false
| Nu a m, Nu b m' =>
if Dec (rk a = rk b)
then if Dec(~ b el FN m')
then if Dec(~ b el FN m)
then nt_str m (a\$b *' m')
else false
else false
else false
| _, _ => false
end.

Lemma rem_id (X: eqType) (x: X) (A : list X) :
~ x el A -> rem A x = A.
Proof.
intros D. apply filter_id. intros y E.
apply Dec_reflect. congruence.
Qed.

Fact nt_str_correct_1 :
NtStr n n' -> nt_str n n' = true.
Proof.
induction 1 as [a l l' H1 H2 H3 H4| a b n n' H1 H2 H3]; simpl.
- decide (a=a) as [_|]; auto. rewrite all_true_map_pw_map with (x:=DNT)(y:=DNT); auto.
intros k H5. apply (H4 k H5); solve_wr_sub.
- inversion HW1. inversion HW2. subst.
decide (rk a = rk b) as [_|]; auto.
decide (~ b el FN n') as [_|]; auto.
decide (~ b el FN n) as [_|]; auto.
Qed.

Fact nt_str_correct_2 :
nt_str n n' = true -> NtStr n n'.
Proof.
revert HW2. revert n'. induction HW1 as [a l H1 H2 H3| a n H1 H2]; intros n' HW2; induction HW2 as [b l' H4 H5 H6| b n' H4 H5]; simpl; try discriminate 1.
- decide (a=b) as [E|]; try discriminate 1. subst b. rewrite all_true_map_pw_map with (x:=DNT)(y:=DNT); try congruence.
intros H7. constructor; auto; try congruence. intros k H8. apply H2; auto. apply H4, nth_In. congruence.
- decide (rk a = rk b) as [E1|]; try discriminate 1.
decide (~ b el (FN n')) as [E2|]; try discriminate 1.
decide (~ b el (FN n)) as [E3|]; try discriminate 1.
intros H6. constructor; auto.
Qed.

Fact nt_str_correct :
nt_str n n' = true <-> NtStr n n'.
Proof.
intros; split; eauto using nt_str_correct_1, nt_str_correct_2.
Qed.

Fact nt_str_dec :
dec (NtStr n n').
Proof.
destruct (nt_str n n') eqn:E.
- left. apply nt_str_correct; assumption.
- right. intros H3. apply nt_str_correct in H3; try assumption. congruence.
Qed.

(*
Structurally similar nu-trees have the same free names
*)

Fact nt_str_FN :
NtStr n n' -> FN n = FN n'.
Proof.
induction 1.
- simpl. f_equal. rewrite map_eq with (l':=l')(x:=DNT); auto.
intros. apply H2; auto; solve_wr_sub.
- simpl. inversion HW1. inversion HW2. subst.
decide(a el (FN n')) as [E1|E1].
+ exfalso. apply H1.
rewrite IHNtStr, FN_equiv_shift with (p':=a\$b); auto. solve_dec.
+ rewrite IHNtStr, FN_equiv, <-rem_equiv' with (a:=b); auto.
* rewrite transp_list_indep; auto.
* solve_dec.
Qed.

End Structure.