Variable rule_default : rule.
Variable prog : list rule.
Variable max_arity : nat.
Fixpoint wf (proof_tree : cbv) : Prop :=
match proof_tree with
| cbv_constr l C (capply c lt) C' (c_capply c' lv) =>
cache_path C C' l = true /\
c = c' /\
lt = map proj_left l /\ lv = map proj_right l /\
andl (map wf  l) /\ List.length l <= max_arity
| cbv_split l ((cbv_update _ _ _ C' (fapply f lv) C'' v) as p) C (fapply f' lt) C''' v' =>
C''' = C'' /\
cache_path C C' l = true /\
lt = map proj_left l /\ lv = map (@term_from_value _ _ _) (map proj_right l) /\
andl (map wf  l) /\
f = f' /\ v = v' /\
wf  p /\ length l <= max_arity
| cbv_split l ((cbv_read C' (fapply f lv) v) as p) C (fapply f' lt) C'' v' =>
C'' = C' /\
cache_path C C' l = true /\
lt = map proj_left l /\ lv = map (@term_from_value _ _ _) (map proj_right l) /\
andl (map wf  l) /\
f = f' /\ v = v' /\
wf  p /\ length l <= max_arity
| cbv_update i s p C (fapply f lv as t0) C' v =>
assoc term_beq t0 C = None /\
exists lp t,
i < length prog /\
nth i prog rule_default = rule_intro f lp t /\
lv = map (@term_from_value _ _ _) (map (psubst s) lp) /\
proj_left p = subst s t /\ proj_right p = v /\
cache_left p = C /\  True /\
C' = (t0, v) :: cache_right p /\
wf  p /\ length lv <= max_arity
| cbv_read C (fapply _ lv as t) v =>
assoc term_beq t C = Some v /\
exists lv', lv = map (@term_from_value _ _ _) lv'
| _ => False
end.

(* Specifications: *)
Lemma wf_cbv_update i s p c1 t c2 v : wf (cbv_update i s p c1 t c2 v) -> wf p.
Lemma wf_InCBV_wf p proof_tree: wf proof_tree -> InCBV p proof_tree -> wf p.
Definition cache_size (c : cache) : nat :=
suml (map (fun tv => term_size (fst tv) + value_size (snd tv)) c).