Fixpoint FA_path p p' (lp : list cbv) := match lp with
| [] => p = p'
| h :: t => In p (first_activations h) /\ FA_path h p' t
end.

(* Specifications: *)
Lemma FA_path_app p p' p'' lp1 lp2 :
FA_path p p' lp1 /\ FA_path p' p'' lp2 -> FA_path p p'' (lp1 ++ lp2).
Lemma FA_path_right p p' p'' lp :
FA_path p p' lp ->
(In p' (first_activations p'') <->
FA_path p p'' (lp ++ [p''])).
Lemma FA_path_end p p' x lp : FA_path p p' (lp++[x]) -> x = p'.
Lemma first_activations_at_given_rank_caract rk i s p0 c1 f l c2 v :
let p := cbv_update i s p0 c1 (fapply f l) c2 v in
first_activations_at_given_rank rk p =
if eq_nat_dec rk (activation_rank rank p) then [p] else
flat_map (first_activations_at_given_rank rk) (first_activations_rec p0).
Lemma first_activations_at_given_rank_path p p' i s p0 c1 t c2 v :
let proof_tree := cbv_update i s p0 c1 t c2 v in
In p' (activations proof_tree) ->
In p (activations p') ->
exists lp, FA_path p p' lp.
Lemma FA_path_activation p p' i s p0 c1 t c2 v lp :
let proof_tree := cbv_update i s p0 c1 t c2 v in
wf proof_tree ->
In p' (activations proof_tree) ->
FA_path p p' lp -> In p (activations p').
Lemma first_activations_strict p :
PPO_prog ->
wf p ->
~ p ∈ first_activations p.
Lemma first_activations_irrefl i s p0 c1 t c2 v p:
PPO_prog ->
wf (cbv_update i s p0 c1 t c2 v) ->
(cbv_update i s p0 c1 t c2 v) ∈ activations p ->
~ In p (first_activations  (cbv_update i s p0 c1 t c2 v)).
Lemma FA_path_refl p p' lp : PPO_prog -> wf p' -> FA_path p p' lp -> In p' (activations p) -> lp = [].
Lemma FA_path_app_destruct p p' lp1 lp2 : FA_path p p' (lp1 ++ lp2) ->
exists p'', FA_path p p'' lp1 /\ FA_path p'' p' lp2.
Lemma FA_path_uniqueness p i s p0 c1 t c2 v lp1 lp2 : PPO_prog ->
let p' := (cbv_update i s p0 c1 t c2 v) in
wf p' ->
FA_path p p' lp1 -> FA_path p p' lp2 -> lp1 = lp2.
Lemma activations_strict i s p0 c1 t c2 v :
wf (cbv_update i s p0 c1 t c2 v) ->
~ cbv_update i s p0 c1 t c2 v ∈ activations p0.
Lemma first_activation_down_rank_lt p p' i s p0 c1 t c2 v:
let proof_tree := cbv_update i s p0 c1 t c2 v in
PPO_prog ->
wf proof_tree ->
In p' (activations proof_tree) -> In p (first_activations p') ->
In p (first_activations_at_given_rank (activation_rank rank p) proof_tree) ->
activation_rank rank p < activation_rank rank p'.
Lemma first_activations_at_given_rank_lt_previous i s p c1 t c2 v p':
let proof_tree := cbv_update i s p c1 t c2 v in
PPO_prog ->
wf proof_tree ->
In p' (first_activations_at_given_rank (activation_rank rank p') proof_tree) ->
activation_rank rank p' < activation_rank rank proof_tree ->
exists p'', In p'' (activations proof_tree) /\
In p' (first_activations p'') /\
activation_rank rank p' < activation_rank rank p''.
Lemma length_fapplies_le_functions s t : length (fapplies_in_term (@subst variable function constructor s t)) <= length (functions_of_term t).
Lemma first_activations_length_le_first_and_semi_activations n s p c1 f l c2 v : length (first_activations (cbv_update n s p c1 (@fapply variable function constructor f l) c2 v)) <=
length (first_activations_and_semi (cbv_update n s p c1 (fapply f l) c2 v)).
Lemma degree_bounded p :
wf p -> length (first_activations p) <= max_nb_rhs_functions prog.
Lemma split_activations_by_first_activations_at_rank rk p :
wf p ->
activations_at_rank rk p = flat_map (activations_at_rank rk) (first_activations_at_given_rank rk p).
Lemma notin_nil (A: Type) (xs: list A):
(forall x, ~ In x xs) -> [] = xs.
Lemma activations_at_rank_activation_rank proof_tree p:
In p (activations proof_tree) ->
In p (activations_at_rank (activation_rank rank p) proof_tree).
Lemma first_activations_at_given_rank_incl i s p c1 t c2 v r :
let proof_tree := cbv_update i s p c1 t c2 v in
PPO_prog ->
wf proof_tree ->
r < activation_rank rank proof_tree ->
incl (first_activations_at_given_rank r proof_tree)
(flat_map (@first_activations _ _ _)
(flat_map (fun r' => activations_at_rank r' proof_tree)
(seq (1 + r) (max_rank - r)))).