Definition rule_subst_of_cbv_update ( subst_default : variable -> value) (proof_tree : cbv) : nat * (variable -> value) :=
match proof_tree with
| cbv_update i s _ _ _ _ _ => (i, s)
| _ => (0, subst_default) (* impossible case *)
end.
Definition proj_left (proof_tree : cbv) : term :=
match proof_tree with
| cbv_constr _ _ t _ _ => t
| cbv_split _ _ _ t _ _ => t
| cbv_update _ _ _ _ t _ _ => t
| cbv_read _ t _ => t
end.
Definition proj_right (proof_tree : cbv) : value :=
match proof_tree with
| cbv_constr _ _ _ _ v => v
| cbv_split _ _ _ _ _ v => v
| cbv_update _ _ _ _ _ _ v => v
| cbv_read _ _ v => v
end.
Definition cache_left (proof_tree : cbv) : cache :=
match proof_tree with
| cbv_constr _ c _ _ _ => c
| cbv_split _ _ c _ _ _ => c
| cbv_update _ _ _ c _ _ _ => c
| cbv_read c _ _ => c
end.
Definition cache_right (proof_tree : cbv) : cache :=
match proof_tree with
| cbv_constr _ _ _ c _ => c
| cbv_split _ _ _ _ c _ => c
| cbv_update _ _ _ _ _ c _ => c
| cbv_read c _ _ => c
end.
Fixpoint cache_path (C C' : cache)(l : list cbv) : bool :=
match l with
| nil => cache_beq C C'
| p :: l' => cache_beq C (cache_left p) && cache_path (cache_right p) C' l'
end.

Lemma cache_path_ind (P : cache -> cache -> list cbv -> Prop) C :
(P C C []) ->
(forall p lp, cache_path (cache_left p) C (p :: lp) = true -> P (cache_right p) C lp ->
P (cache_left p) C (p :: lp)) ->
forall lp C', cache_path C' C lp = true -> P C' C lp.