Fixpoint first_activations_and_semi_rec (proof_tree : cbv) : list cbv :=
match proof_tree with
| cbv_constr lp _ _ _ _          => flat_map first_activations_and_semi_rec lp
| cbv_split lp p _ _ _ _         => first_activations_and_semi_rec p ++ flat_map first_activations_and_semi_rec lp
| cbv_update _ _ _ _ _ _ _ as p' => [p']
| cbv_read _ _ _ as p'           => [p']
end.
Definition first_activations_and_semi (proof_tree : cbv) : list cbv :=
match proof_tree with
| cbv_constr lp _ _ _ _    => []
| cbv_split lp p _ _ _ _   => []
| cbv_update _ _ p _ _ _ _ => first_activations_and_semi_rec p
| cbv_read _ _ _           => []
end.

(* Specifications: *)
Lemma incl_first_activations_semi p :
incl (first_activations p) (first_activations_and_semi p).
Lemma first_activations_and_semi_rec_incl_sub_trees p :
incl (first_activations_and_semi_rec p) (sub_trees p).
Lemma first_activations_and_semi_incl_sub_trees p :
incl (first_activations_and_semi p) (sub_trees p).
Lemma cbv_big_induction :
forall (P : cbv -> Prop),
(forall i s p c1 t c2 v, (forall p', In p' (first_activations (cbv_update i s p c1 t c2 v)) -> P p') -> P (cbv_update i s p c1 t c2 v)) ->
forall i s p c1 t c2 v, P (cbv_update i s p c1 t c2 v).
Lemma activations_first_activations i s p' c1 t c2 v :
let p := cbv_update i s p' c1 t c2 v in
activations p = p :: flat_map activations (first_activations p).
Lemma cache_consistent p :
wf p ->
exists C,
cache_beq (cache_right p) (C ++ cache_left p) = true /\
(forall t, assoc_cache t C <> None -> assoc_cache t (cache_left p) = None).
Lemma cache_path_consistent c1 c2 lp :
andl (map wf lp) ->
cache_path c1 c2 lp = true ->
forall p, In p lp ->
exists c3,
c2 = c3 ++ cache_right p /\
(forall t, assoc_cache t c3 <> None -> assoc_cache t (cache_right p) = None).
Lemma cache_path_consistent_head C p lp :
wf p -> andl (map wf lp) ->
cache_path (cache_right p) C lp = true ->
exists C',
C = C' ++ cache_right p /\
(forall t, assoc_cache t C' <> None -> assoc_cache t (cache_right p) = None).
Lemma assoc_cache_hd (f: function) (lv: list term) (v: value) (C: cache) :
assoc_cache (fapply f lv) ((fapply f lv, v) :: C) = Some v.