Definition cbv_cache_entry (proof_tree : cbv) := (proj_left proof_tree, proj_right proof_tree).

(* Specifications: *)
Lemma cache_content (proof_tree : cbv) : wf proof_tree -> cache_right proof_tree = map cbv_cache_entry (activations_cache_order proof_tree) ++ cache_left proof_tree.
Lemma cache_content_on_path c1 c2 lp: andl (map wf lp) -> cache_path c1 c2 lp = true -> c2 = map cbv_cache_entry (revflatten (map activations_cache_order lp)) ++ c1.
Lemma cache_path_proj_left_in_tail_not_in_head t p lp c1 c2 : cache_path c1 c2 (p :: lp) = true -> andl (map wf (p :: lp)) -> In t (map proj_left (revflatten (map activations_cache_order lp))) -> ~ In t (map proj_left (activations_cache_order p)).
Lemma whole_cache_path_consistent lp : forall c1 c2, cache_path c1 c2 lp = true -> andl (map wf lp) -> exists C, cache_beq c2 (C ++ c1) = true /\ (forall t, assoc_cache t C <> None -> assoc_cache t c1 = None).
Lemma cache_path_proj_left_not_in_init t lp c1 c2 : cache_path c1 c2 lp = true -> andl (map wf lp) -> In t (map proj_left (revflatten (map activations_cache_order lp))) -> ~ In t (map fst c1).
Lemma cache_lookup_term (p: cbv) (ext: cache): wf p -> (forall t: term, assoc_cache t ext <> None -> assoc_cache t (cache_right p) = None) -> cache_lookup (ext ++ cache_right p) (proj_left p) = @term_from_value _ _ _ (proj_right p).
Lemma first_activations_residues_activation i s p c1 t c2 v : let proof_tree := cbv_update i s p c1 t c2 v in wf proof_tree -> Forall2 (fun p' t' => match (proj_left p', t') with | (fapply f lv, fapply f' lt) => f = f' /\ Forall2 (fun t v => cache_lookup (cache_left p') t = v) lt lv | _ => False end) (first_activations_and_semi proof_tree) (fapplies_in_term (proj_left p)).
Lemma nb_nodes_bound i s p' c1 t c2 v : let p := cbv_update i s p' c1 t c2 v in nb_nodes p <= suml (map nb_judgements_sub (activations p)) + length (activations p).
Lemma nb_judgements_bound i s p' c1 t c2 v : let p := cbv_update i s p' c1 t c2 v in nb_judgements p <= suml (map nb_judgements_sub (activations p)) + length (activations p) + nb_read p.
Lemma nb_judgements_sub_rec_bound p : wf p -> nb_judgements_sub_rec p <= term_size (proj_left p).
Lemma nb_judgements_sub_bound i s p c1 t c2 v : wf (cbv_update i s p c1 t c2 v) -> nb_judgements_sub (cbv_update i s p c1 t c2 v) <= activation_bound prog (term_size t).
Lemma right_from_activation_or_from_left p : wf p -> maxl (map (fun tv : term * value => value_size (snd tv)) (cache_right p)) <= max (max_active_size p) (maxl (map (fun tv : term * value => value_size (snd tv)) (cache_left p))).
Lemma right_from_activation_or_from_left_path lp c1 c2 : andl (map wf lp) -> cache_path c1 c2 lp = true -> maxl (map (fun tv : term * value => value_size (snd tv)) c2) <= max (maxl (map max_active_size lp)) (maxl (map (fun tv : term * value => value_size (snd tv)) c1)).
Lemma value_size_bounded_by_nb_judgements p : wf p -> value_size (proj_right p) <= (1 + max (max_active_size p) (maxl (map (fun tv => value_size (snd tv)) (cache_left p)))) * nb_judgements p.
Lemma size_bounded_nb_size_judgements p : size p <= nb_judgements p * max_judgement_size p + cache_size (cache_left p).
Lemma nb_judgements_sub_bound_gen : forall p p', let S := max_active_size p in wf p -> In p' (activations p) -> nb_judgements_sub p' <= activation_bound prog S.
Lemma nb_judgements_bound_gen : forall i s p' c1 t c2 v, let p := cbv_update i s p' c1 t c2 v in let A := length (activations p) in let S := max_active_size p in wf p -> nb_judgements p <= A * activation_bound prog S + A + (Datatypes.S (max_arity * nb_nodes p)).
Lemma cache_path_incl : forall lp c1 c2, andl (map wf lp) -> cache_path c1 c2 lp = true -> incl c1 c2.
Lemma InCBV_cache_right_incl p proof_tree : wf proof_tree -> InCBV p proof_tree -> incl (cache_right p) (cache_right proof_tree).
Lemma InCBV_read_cache_right c t v p: wf p -> InCBV (cbv_read c t v) p -> In (t, v) (cache_right p).
Lemma term_size_proj_left_bound : forall i s p' c1 t c2 v, let p := cbv_update i s p' c1 t c2 v in let S := max_active_size p in wf p -> forall p', InCBV p' p -> term_size (proj_left p') <= activation_bound prog S + S + cache_size c1.
Lemma nb_nodes_bound_gen i s p' c1 t c2 v : let p := cbv_update i s p' c1 t c2 v in let A := length (activations p) in let S := max_active_size p in wf p -> nb_nodes p <= A * (1 + activation_bound prog S).
Lemma size_judgement : forall i s p' c1 t c2 v, let p := cbv_update i s p' c1 t c2 v in let A := length (activations p) in let S := max_active_size p in let C := maxl (map (fun tv : term * value => value_size (snd tv)) c1) in wf p -> max_judgement_size p <= activation_bound prog S + S + cache_size c1 + (1 + max S C) * (1 + (A * activation_bound prog S + A) + max_arity * (A * activation_bound prog S + A)).
Theorem size_bound_gen : forall i s p' c1 t c2 v, let p := cbv_update i s p' c1 t c2 v in let A := length (activations p) in let S := max_active_size p in wf p -> size p <= (A * activation_bound prog S + A + 1 + (max_arity * A * (1 + activation_bound prog S))) * (activation_bound prog S + S + cache_size c1 + (1 + max S (maxl (map (fun tv : term * value => value_size (snd tv)) c1))) * (1 + (A * activation_bound prog S + A) + max_arity * (A * activation_bound prog S + A))) + cache_size c1.