From Undecidability.L Require Import Util.L_facts.
Notation "A '.[' i  ']'" := (elAt A i) (no associativity, at level 50).
Fixpoint appCross A B :=
match A with
| nil => nil
| a :: A => map (app a) B ++ appCross A B
end.
Fixpoint T n :=
match n with
| 0 => [#n]
| S n => let A := T n in A ++ [#(S n)] ++ filter (fun x => Dec (~ x el A)) ( map lam A ++ appCross A A )
end.
Fixpoint exh_size s := match s with
| #n => n
| app s1 s2 => 1 + exh_size s1 + exh_size s2
| lam s => 1 + exh_size s
end.
Proof with
simpl; repeat rewrite in_app_iff; repeat rewrite in_filter_iff; try rewrite <- appCross_correct; eauto using in_filter_iff, in_app_iff, appCross_correct, el_elAt, elAt_el, T_ge, in_map.
induction s.
- destruct n; simpl; auto.
- eapply T_app; eapply T_el_ge; try eassumption; fold exh_size plus; lia.
- now eapply T_lam.
Qed.
induction m.
- simpl; lia.
- simpl. rewrite app_length. simpl. lia.
Qed.
Definition g s := match pos s (T (exh_size s)) with None => 0 | Some n => n end.
Definition g_inv n := match elAt (T n) n with None => #0 | Some n => n end.
Hint Unfold left_inverse injective right_inverse surjective : core.
Proof with eauto using dupfree; intuition.
induction 1; intros dpf_B; simpl...
eapply dupfree_app...
-eapply disjoint_forall. intros y D Hy.
edestruct (appCross_app Hy) as [y1 [y2 Hyy]]; subst. eapply appCross_correct in Hy as [].
eapply in_map_iff in D. destruct D as [d [D1 D2]]. inv D1...
-eapply dupfree_map... congruence.
Qed.
Hint Unfold left_inverse injective surjective g g_inv : core.
Fixpoint C (n : nat) :=
match n with
| 0  => [(0,0)]
| S n => C n ++ (S n, 0) :: filter (fun x => Dec (not (x el C n))) (map (fun p : nat * nat => let (p1,p2) := p in (p1,S p2)) (C n))
end.

Lemma C_S p n m : C n .[ m ] = Some p -> C (S n).[ m ] = Some p.