Equivalences Laws


Require Export NuTree.

Definition NtlEq A n n' :=
  forall t, Twr t -> t El [n] A <-> t El [n'] A.

Lemma ntl_eq_refl A n :
  NtlEq A n n.
Proof.
  intros t H1. reflexivity.
Qed.

Rho-Renamings

Section Renaming.

(*
  A Rho-Renaming of a nu-tree n is a permutation where all free names are fixed.
  In this development we call it just Renaming.
*)

Definition Renaming n p :=
  forall a, a el FN n -> p a = a.

Lemma renaming_sub a l p :
  Renaming (Tr a l) p -> forall n, n el l -> Renaming n p.
Proof.
  intros H1 n H2 b H3. rewrite H1; trivial. now apply (FN_in_sub a H3).
Qed.

Lemma renaming_sub' a n p :
  Renaming (Nu a n) p -> p a = a -> Renaming n p.
Proof.
  intros H1 H2 b H3. decide(b=a) as [->|H4]; try assumption.
  rewrite H1; try reflexivity. simpl. auto.
Qed.

Lemma renaming_nil n p :
  FN n = [] -> Renaming n p.
Proof.
  intros H1 a H2. rewrite H1 in H2. auto.
Qed.

Lemma renaming_inverse p p' n :
  Inv p p' -> Renaming n p -> Renaming n p'.
Proof.
  intros H1 H2 a H3. rewrite <-(H2 a H3) at 1. apply H1.
Qed.

(*
  A renaming is still a renaming after renaming the tree
*)

Lemma renaming_invariant n p :
  Ntwr n -> Perm p -> Renaming n p -> Renaming (p *' n) p.
Proof.
  intros H1 H2 H3.
  assert(HP: Perm p) by assumption.
  destruct H2 as [HP1 [p' HP2]].
  destruct H1 as [a' l H5 | a' n H5]; intros c H4;
    rewrite FN_equiv_shift with (p':=p') in H4; auto;
      rewrite <-(perm_inv c (inv_comm HP2)) at 2;
      rewrite <-(H3 (p' c) H4), (perm_inv c); auto.
Qed.

(*
  Any free name is still free after renaming
*)

Lemma free_name_in_renaming a n p :
  Ntwr n -> Perm p -> a el FN n -> Renaming n p -> a el FN (p *' n).
Proof.
  intros H1 H2 H3 H4. assert(HP: Perm p) by assumption.
  destruct H2 as [_ [p' H2]]. apply (renaming_inverse H2) in H4.
  destruct H1 as [a' l H5| a' n H5]; rewrite (FN_equiv_shift) with (p':=p');auto; now rewrite H4.
Qed.

(*
  Inverse direction of the previous lemma
  Any free name was free before renaming
  Proof uses previous lemma + inverse permutation
*)

Lemma free_name_in_renaming' a n p :
  Ntwr n -> Perm p -> Renaming n p -> a el FN (p *' n) -> a el FN n.
Proof.
  intros H1 H2 H3 H4. assert(HP: Perm p) by assumption.
  destruct H2 as [HP1 [p' HP2]]. apply (free_name_in_renaming) with (p := p') in H4; auto.
  - rewrite <-(nt_perm_apply_inv H1 (inv_comm HP2)) in H4; assumption.
  - eauto.
  - apply renaming_inverse with (p := p); try assumption. apply renaming_invariant; trivial.
Qed.

Lemma free_in_renaming a n p :
  Ntwr n -> Perm p -> Renaming n p -> a el FN n <-> a el FN (p *' n).
Proof.
  intros H1 H2 H3. split; eauto using free_name_in_renaming, free_name_in_renaming'.
Qed.

(*
  If a transposition transposes two names that are not free, then it's a renaming.
*)

Lemma transp_renaming n a b :
  Ntwr n -> ~ a el FN n -> ~b el FN n -> Renaming n (a$b).
Proof.
  unfold Renaming, transp. intros. solve_dec.
Qed.

Lemma compose_renaming n p p' :
  Ntwr n -> Perm p -> Perm p' -> Renaming n p -> Renaming n p' -> Renaming n (p**p').
Proof.
  unfold Renaming, compose. intros H1 H2 H3 H4 H5 a H6. rewrite H4, H5; trivial. now rewrite H5.
Qed.

(*
  Any renaming for a nu-tree is a renaming for a structurally similar nu-tree 
*)

Lemma nt_str_renaming n n' p :
  Ntwr n -> Ntwr n' -> NtStr n n' -> Renaming n p -> Renaming n' p.
Proof.
  unfold Renaming. intros HW1 HW2 H1 H2 a H3. apply H2. now rewrite (nt_str_FN HW1 HW2 H1).
Qed.

Hint Resolve transp_renaming.

(*
  The next four lemmas treat special cases when and which some names are free
*)

Lemma nu_FN n a b :
  a el FN(a$b *' n) -> Ntwr n -> rk a = rk b -> b <> a -> b el FN(Nu a n).
Proof.
  intros H1 H2 H3 H4. rewrite FN_equiv_shift in H1; eauto.
  cbn. apply in_rem_iff. unfold transp in H1. split; trivial. now solve_dec.
Qed.

Lemma nu_FN' n a b c :
  c el FN(a$b *' n) -> Ntwr n -> rk a = rk b -> a <> c -> b <> c -> c el FN(Nu a n).
Proof.
  intros H1 H2 H3 H4 H5. rewrite FN_equiv_shift in H1; eauto.
  cbn. apply in_rem_iff. split; auto. unfold transp in H1. now solve_dec.
Qed.

Lemma transp_FN n a b :
  Ntwr n -> rk a = rk b -> a el FN n -> ~b el FN n -> b el FN (a $ b *' n).
Proof.
  simpl. intros. rewrite FN_equiv_shift; auto. solve_dec.
Qed.

Lemma transp_FN' n a b c :
  Ntwr n -> c el FN n -> rk a = rk b -> c <> a -> c <> b -> c el FN (a $ b *' n).
Proof.
  intros. rewrite FN_equiv_shift with (p':=a$b); auto. solve_dec.
Qed.

(*
  A renaming doesn't change the nu-tree language
*)

Fact ntl_renaming' n t A :
  Ntwr n -> Twr t -> t El [n] A -> forall p, Perm p -> Renaming n p -> t El [p*'n] A.
Proof.
  intros H1 H3 H4.
  induction H4 as [A' l l' a H5 H6 H7| A' n t a b H4 H5 H6 H7 H8]; simpl; intros p HP H2.
  - assert(H8: p a = a) by apply H2, tree_name_free. rewrite H8. constructor; try now rewrite map_length.
    intros k H9. rewrite map_length in H9.
    rewrite map_nth_indep; trivial. apply H7; trivial; try solve_wr_sub.
    apply (renaming_sub H2), nth_In, H9.
  - apply DNNu with (b := b); trivial.
    + change (~ b el FN (p *' (Nu a n))). now rewrite <-(free_in_renaming b H1 HP H2).
    + destruct HP as [HP _]. now rewrite <-(HP a).
    + inversion H1 as [|a' n' H9 [H10 H11]]. subst.
      rewrite (@nt_swap_perm n H9 p ((p a$p b) ** p ** (a$b))); eauto.
      * rewrite <-nt_assoc, nt_assoc3, nt_assoc; eauto. apply H8; auto.
        -- apply perm_compose_perm; auto.
           apply transp_perm. destruct HP as [HP _]. now rewrite <-(HP a).
        -- intros c HC. solve_dec.
           ++ exfalso. apply H5. apply (nu_FN HC); eauto; congruence.
           ++ decide (p a = c); trivial. exfalso. apply H5.
              enough (c el FN (Nu a n)) by now rewrite (H2 c).
              apply (nu_FN' HC); eauto; congruence.
           ++ exfalso. apply H5. apply (nu_FN HC); eauto. congruence.
           ++ apply H2. apply (nu_FN' HC); eauto; congruence.
      * intros c. solve_dec.
Qed.

(*
  The otther direction of renaming is shown using previous fact + permutation inverse
*)

Fact ntl_renaming'' n t A :
  Ntwr n -> Twr t -> forall p, Perm p -> Renaming n p -> t El [p*'n] A -> t El [n] A.
Proof.
  intros H1 H2 p H3 H4 H5.
  assert(HP1: Perm p) by assumption. destruct H3 as [HP2 [p' HP3]].
  apply ntl_renaming' with (p := p') in H5; auto.
  - rewrite <-(nt_perm_apply_inv) in H5; auto.
  - exact (perm_inv_perm HP1 HP3).
  - now apply renaming_inverse with (p := p), renaming_invariant.
Qed.

Theorem ntl_renaming n A :
  Ntwr n -> forall p, Perm p -> Renaming n p -> NtlEq A n (p*'n).
Proof.
  intros H1 p H2 H3. split; intros H5.
  - apply ntl_renaming'; assumption.
  - apply ntl_renaming'' with (p:=p); assumption.
Qed.

Corollary ntl_closed n A p :
  Ntwr n -> Perm p -> FN n = [] -> NtlEq A n (p*'n).
Proof.
  intros H1 H2 H3. apply ntl_renaming; auto using renaming_nil.
Qed.

Definition NtlRho n n' :=
  exists p, Perm p /\ Renaming n p /\ p*'n = n'.

(*
  Rho-equivalent nu-trees have the same language
*)

Corollary ntl_alpha_eq n n' A :
  Ntwr n -> Ntwr n' -> NtlRho n n' -> NtlEq A n n'.
Proof.
  intros H1 H2 [p [H3 [H4 H5]]]. rewrite <-H5. apply ntl_renaming; assumption.
Qed.

End Renaming.

Empty bindings

Section NuIndep.

  Variable n : NuTree.
  Hypothesis HW1 : Ntwr n.

  Lemma ntl_weakening A B c t :
    Twr t -> t El [n] A -> A === (c::B) -> t El [n] B.
  Proof.
    intros HW2 H1. revert B c.
    induction H1 as [A l l' a H1 H2 H3| A n t a b H1 H2 H3 H4 H5]; simpl.
    - intros B c H4. constructor; trivial. intros k H7. apply H3 with (c:=c); try assumption; try solve_wr_sub.
      rewrite H4. apply equi_swap.
    - intros B c H6. apply DNNu with (b:=b); try assumption.
      + rewrite H6 in H1. auto.
      + inversion HW1. subst. apply H5 with (c:=c); auto. now rewrite equi_swap, <-H6.
  Qed.

  (*
    If a name doesn't bind anything, we can ignore it.
   *)

  Lemma ntl_nu_ignore a A t :
    Twr t -> t El [Nu a n] A -> ~ a el FN n -> t El [n] A.
  Proof.
    intros HW2. inversion 1; subst; intros.
    apply ntl_renaming in H7; auto.
    - apply ntl_weakening with (A:=b::A)(c:=b); auto.
    - apply transp_renaming; try assumption. decide (b=a) as [|E1]; try now subst.
      intros H8. now apply E1, bind_free_name with (n:=n).
  Qed.

  Lemma ntl_strengthening A B c t :
    Twr t -> t El [n] A -> (c::A) === B -> ~ c el names t -> t El [n] B.
  Proof.
    intros HW2 HD. revert B c.
    induction HD as [A l l' a H1 H2 H3| A n t a b H1 H2 H3 H4 H5]; simpl.
    - intros B c H4 H5. constructor; trivial.
      intros k H7. apply H3 with (c := c); auto; try solve_wr_sub.
      + rewrite <-H4. apply equi_swap.
      + intros H6. apply H5. right. apply concat_map_el. exists (nth k l' DTR).
        split; try assumption. apply nth_In. congruence.
    - intros B c H6 H7. inversion HW1. subst.
      decide(b=c) as [E3|E3].
      + subst c. decide (b el FN n) as [E1|E1].
        * apply (bind_free_name E1) in H2. subst b.
          rewrite nt_swap_perm with (p':=id), nt_id in H4; auto.
          contradict H7. apply ntl_name_in with (A:=a::A)(n:=n); assumption.
        * decide (a el FN n) as [E2|E2].
          -- contradict H7. apply ntl_name_in with (A:=b::A)(n:=a$b *'n); auto. now apply transp_FN.
          -- destruct (fresh_name (b::B) (Nu a n) t (rk a)) as [f [HF1 [HF2 [HF3 HF4]]]].
             simpl in *. apply DNNu with (b:=f), ntl_renaming; try apply transp_renaming; auto.
             apply ntl_renaming with (p:=a$b); auto using transp_renaming.
             apply H5 with (c:=f); auto. now rewrite <-H6.
      + apply DNNu with (b:=b); auto.
        * rewrite <-H6. intros [H9|H9]; auto.
        * apply H5 with (c:=c); auto. rewrite <-H6. apply equi_swap.
  Qed.

  (*
    We can add a nu that doesn't bind anything.
    We show that the newly added nu can be instantiated by
    a fresh name and that won't change the nu-tree language
   *)

  Lemma ntl_nu_add A a t :
    Twr t -> t El [n] A -> ~ a el FN n -> t El [Nu a n] A.
  Proof.
    intros HW2 HD H1.
    destruct (fresh_name A (Nu a n) t (rk a)) as [c [HF1 [HF2 [HF3 HF4]]]].
    simpl in *. apply DNNu with (b:=c); try apply free_sub_not; try apply freshness; auto.
    apply ntl_renaming; auto.
    - apply transp_renaming; auto.
    - apply ntl_strengthening with (A:=A)(c:=c); auto.
  Qed.

  Theorem ntl_nu_indep A a :
    ~ a el FN n -> NtlEq A n (Nu a n).
  Proof.
    intros H1 H2. split; eauto using ntl_nu_add, ntl_nu_ignore.
  Qed.

  Hint Resolve ntl_nu_indep ntl_nu_add ntl_nu_ignore.

End NuIndep.

Renaming of Nu's

Section NuRename.

  Variable n : NuTree.
  Variable A : list Name.
  Hypothesis HW1 : Ntwr n.

  Fact ntl_nu_rename_1 a b t :
    Twr t -> t El [Nu a n] A -> rk a = rk b -> ~ b el FN (Nu a n) -> t El [a$b *' Nu a n] A.
  Proof.
    intros HW2 H1 H2 H3.
    apply ntl_renaming; auto. apply transp_renaming; simpl; auto.
  Qed.

  Fact ntl_nu_rename_2 a b t :
    Twr t -> rk a = rk b -> ~ b el FN (Nu a n) -> t El [a$b *' Nu a n] A -> t El [Nu a n] A.
  Proof.
    intros HW2 H1 H2 H3.
    apply ntl_renaming in H3; auto. apply transp_renaming; simpl; auto.
  Qed.

  Corollary ntl_nu_rename a b :
    rk a = rk b -> ~ b el FN (Nu a n) -> NtlEq A (Nu a n) (a$b *' Nu a n).
  Proof.
    intros H1 H2 H3. split; intros H4.
    - now apply ntl_nu_rename_1.
    - now apply ntl_nu_rename_2 with (b:=b).
  Qed.

End NuRename.

Swapping successive Nu's

Section NuSwap.

  Variable n : NuTree.
  Variable A : list Name.
  Hypothesis HW1 : Ntwr n.

  (*
    Technical lemma showing that the free names below two bindings stay
    the same when the bindings are instantiated in different order.
    Only needed in the ntl_nu_swap fact.
   *)

  Lemma nu_swap_FN a b c d :
    Ntwr n -> ~ c el FN (Nu a (Nu b n)) -> ~ d el FN (Nu ((a $ c) b) (a $ c *' n)) -> rk a = rk c-> rk b = rk d -> c<>d -> a<>b -> ~ c el FN (Nu ((b $ d) a) (b $ d *' n)).
  Proof.
    intros H1 H2 H3 H4 H5 H6 H7. simpl. rewrite in_rem_iff, FN_equiv_shift with (p':=b$d); auto; try (apply transp_perm; solve_dec).
    intros [H8 H9]. simpl in *.
    repeat rewrite in_rem_iff in H2.
    repeat rewrite in_rem_iff, FN_equiv_shift in H3; auto.
    unfold transp in *. solve_dec; auto.
  Qed.

  Fact ntl_nu_swap' a b t :
    Twr t -> t El [Nu a (Nu b n)] A -> t El [Nu b (Nu a n)] A.
  Proof.
    intros HW2 H3.
    inversion H3 as [| A' n' t' a' c H4 H5 H6 H7 H8 [H9 H10] H11].
    simpl in H7. subst.
    inversion H7 as [| A' n' t' b' d H8 H9 H10 H11 H12 [H13 H14] H15].
    subst. rewrite <-nt_assoc in H11; try assumption.
    assert(H12: c <> d).
    { intros H12. subst. now apply H8. }
    decide (a=b) as [ES|ES]; try now subst.
    apply DNNu with (b:=d); auto.
    - simpl. intros [[H13 H14] % in_rem_iff H15] % in_rem_iff. apply H9.
      apply in_rem_iff; fold FN. split.
      + apply transp_FN'; auto.
      + apply transp_diff; congruence.
    - rewrite <-H10. solve_dec.
    - simpl. unfold transp in H10.
      apply DNNu with (b:=c); simpl; auto.
      + apply nu_swap_FN; auto. solve_dec.
      + now solve_dec.
      + rewrite nt_swap_perm'' with (p'':= (a$c)b$d ** a$c); auto using transp_chain'.
        apply ntl_swap_list with (A:=d::c::A); auto. apply equi_swap.
  Qed.

  (*
    Showing one direction of a "swapping" lemma gives you a proof for both directions.
   *)

  Theorem ntl_nu_swap a b :
    NtlEq A (Nu a (Nu b n)) (Nu b (Nu a n)).
  Proof.
    split; intros; apply ntl_nu_swap'; assumption.
  Qed.

End NuSwap.

Pushing Nu's


Section NuPush.

  (*
    The list only matters when instantiating nus.
    If there are no nus in the nu-tree, then the list doesn't matter.
   *)

  Lemma ntl_pure_list n A B t :
    NoNus n -> t El [n] A -> t El [n] B.
  Proof.
    intros H1 H2. revert B; induction H2; intros B; inversion H1; subst.
    constructor; trivial. intros k H5. apply H2; auto.
  Qed.

  (*
    If there are no nus of rank k in the tree, then we can add any name of rank k to the list.
   *)

  Lemma ntl_nusk_list n A B t c k :
    NoNusk k n -> Ntwr n -> t El [n] A -> B === (c::A) -> rk c = k -> t El [n] B.
  Proof.
    intros H1 HW H2. revert B; induction H2 as [A l l' a H2 H3 H4| A n t a b H2 H3 H4 H5 H6]; intros B H7 H8; inversion H1; subst.
    - constructor; trivial. intros k H8. apply H4; auto; try solve_wr_sub. rewrite H7. apply equi_swap.
    - apply DNNu with (b:=b); auto.
      + rewrite H7. simpl. intros [|]; subst; auto.
      + inversion HW. apply H6; auto.
        * apply no_nusk_equiv; auto.
        * rewrite H7. apply equi_swap.
  Qed.

  (*
    The next three lemmas treat certain cases of freshness conditions
    that need to be considered when pushing nu-bindings
   *)

  Lemma FN_nu_sub a b c n nl :
    ~c el FN (Nu a (Tr b nl)) -> n el nl -> ~c el FN (Nu a n).
  Proof.
    simpl. intros.
    rewrite in_rem_iff. intros [H14 H15].
    apply H, in_rem_iff. split; trivial.
    right. apply concat_map_el. exists n. now split.
  Qed.

  Lemma FN_sub_other a b c n nl :
    ~c el FN (Nu a (Tr b nl)) -> n el nl -> ~ a el FN n -> ~ c el FN n.
  Proof.
    simpl. intros H1 H2 H3 H4. apply H1. apply in_rem_iff. split.
    - right. apply concat_map_el. now exists n.
    - intros H5. now subst c.
  Qed.

  Lemma FN_sub_incl a b c n nl k k' A :
    k < |nl| -> k' < |nl| -> k <> k' -> (filter (fun x => Dec(~x el b::A)) (FN (Nu a (Tr b (rep_nth k nl n))))) <<= FN (Nu a n) -> ~ a el FN (nth k' nl DNT) -> ~ c el (FN (Nu a n)) -> ~c el b::A -> ~ c el FN (nth k' nl DNT).
  Proof.
    intros HL1 HL2 HK H1 H2 H3 H4 H5.
    apply H3, H1. simpl. apply in_filter_iff. split; auto.
    apply in_rem_iff. split; try congruence.
    right. apply concat_map_el. exists (nth k' nl DNT).
    split; trivial. apply rep_nth_el'; assumption.
  Qed.

  Fact ntl_nu_push' a b nl t A k :
    Ntwr (Tr b nl) -> Twr t ->
    a <> b -> k < |nl| ->
    (forall k', k' < |nl| -> k <> k' -> ~ a el FN (nth k' nl DNT)) ->
    t El [Nu a (Tr b nl)] A ->
    t El [Tr b (rep_nth k nl (Nu a (nth k nl DNT)))] A.
  Proof.
    intros HW1 HW2 H2 H3 H5 H1.
    inversion H1 as [| A' n' t' a' c H6 H7 H8 H9 H10 [H11 H12] H13]. subst.
    simpl in H9.
    inversion H9 as [A' nl' tl' a' H10 H11 H12 [H13 H14] H15 |]. subst.
    assert(HA: b = (a$c)b). {
      solve_dec. contradict H7. simpl. apply in_rem_iff. split; auto.
    }
    rewrite <-HA, map_length in *. inversion HW1. subst.
    constructor; try now apply rep_nth_len'. rewrite rep_nth_len. intros k' H13.
    specialize(H11 k' H13).
    - decide (k=k') as [E1|E1].
      + subst k'. rewrite rep_nth_exact; trivial. unfold transp in HA.
        apply DNNu with (b:=c); trivial; simpl in *.
        * solve_dec. auto.
        * apply FN_nu_sub with (b:=b)(nl:=nl); auto.
        * rewrite map_nth_indep in H11; trivial.
          apply ntl_swap_list with (A:=b::c::A); auto using equi_swap.
      + apply ntl_weakening with (B:=b::A)(c:=c) in H11; try apply equi_swap; try solve_wr_sub; try rewrite map_nth_indep; auto.
        rewrite rep_nth_indep; trivial. rewrite map_nth_indep in H11; trivial.
        apply ntl_renaming in H11; auto; try solve_wr_sub.
        apply transp_renaming; auto; try solve_wr_sub.
        apply FN_sub_other with (a:=a)(b:=b)(nl:=nl); auto.
  Qed.

  (*
    This direction needs more assumptions because of the freshness conditions
   *)

  Fact ntl_nu_push'' a b nl n t A k :
    Ntwr (Tr b nl) -> Twr t ->
    a <> b ->
    k < |nl| -> nth k nl DNT = (Nu a n) ->
    (forall k', k' < |nl| -> k <> k' -> ~ a el FN (nth k' nl DNT)) ->
    (forall k', k' < |nl| -> k <> k' -> NoNusk (rk a) (nth k' nl DNT)) ->
    (filter (fun x => Dec (~ x el b::A)) (FN (Nu a (Tr b (rep_nth k nl n))))) <<= FN (Nu a n) ->
    t El [Tr b nl] A ->
    t El [Nu a (Tr b (rep_nth k nl n))] A.
  Proof.
    intros HW1 HW2 H2 H3 H4 H6 HT HF H1.
    inversion H1 as [A' nl' tl' a' H7 H8 H9 [H10 H11] H12 |]. subst.
    assert(HN : nth k tl' DTR El [nth k nl DNT] b :: A) by now apply H8.
    rewrite H4 in HN.
    inversion HN as [| A' n' t' a' c H9 H10 H11 H12 H13 [H14 H15] H16]. subst.
    assert(HB: b = (a$c)b).
    { solve_dec. contradict H9. now left. }
    apply DNNu with (b:=c); auto.
    - intros H13.
      apply H10, HF, in_filter_iff. split; auto.
    - simpl. rewrite <-HB in *. constructor; rewrite map_length, rep_nth_len; trivial.
      intros k' H13.
      rewrite nth_indep with (d':=a$c*'DNT); try now rewrite map_length, rep_nth_len.
      rewrite map_nth. decide (k=k') as [E1|E1].
      + subst k'. rewrite rep_nth_exact; trivial. apply ntl_swap_list with (A:=c::b::A); auto using equi_swap.
      + rewrite rep_nth_indep; trivial.
        apply ntl_renaming; auto; try solve_wr_sub.
        * apply transp_renaming; auto; try solve_wr_sub.
          apply FN_sub_incl with (a:=a)(b:=b)(n:=n)(k:=k)(A:=A); auto.
        * apply ntl_nusk_list with (A:=b::A)(c:=c)(k:=rk a); auto using equi_swap; try solve_wr_sub.
  Qed.

  Theorem ntl_nu_push a b nl n A k :
    Ntwr (Tr b nl) ->
    a <> b -> k < |nl| ->
    nth k nl DNT = (Nu a n) ->
    (forall k', k' < |nl| -> k <> k' -> ~ a el FN (nth k' nl DNT)) ->
    (forall k', k' < |nl| -> k <> k' -> NoNusk (rk a) (nth k' nl DNT)) ->
    (filter (fun x => Dec (~ x el b::A)) (FN (Nu a (Tr b (rep_nth k nl n))))) <<= FN (Nu a n) ->
    NtlEq A (Tr b nl) (Nu a (Tr b (rep_nth k nl n))).
  Proof.
    intros. intros t H6. split.
    - now apply ntl_nu_push''; trivial.
    - rewrite <-rep_nth_id with (X:=NuTree)(k:=k)(l:=nl)(xd:=DNT) at 2; trivial.
      rewrite H2. intros H7.
      replace (rep_nth k nl (Nu a n)) with
          (rep_nth k (rep_nth k nl n) (Nu a (nth k (rep_nth k nl (n)) DNT))).
      + apply ntl_nu_push'; auto; try now rewrite rep_nth_len.
        * inversion H. subst. constructor; try now rewrite rep_nth_len.
          intros n' [H12 |H12] % rep_nth_el_or; auto. subst.
          specialize(H10 (nth k nl DNT) (nth_In nl DNT H1)).
          rewrite H2 in H10. now inversion H10.
        * intros k'. rewrite rep_nth_len. intros H8 H9 H10. apply (H3 k'); trivial.
          now rewrite rep_nth_indep in H10.
      + rewrite rep_nth_exact, rep_nth_overwrite; trivial.
  Qed.

End NuPush.