End ITree.
Module ZTree := ITree(ZIndexed).
(** * Additional properties over trees *)
Module Tree_Properties(T: TREE).
(** An induction principle over [fold]. *)
Section TREE_FOLD_IND.
Variables V A: Type.
Variable f: A -> T.elt -> V -> A.
Variable P: T.t V -> A -> Prop.
Variable init: A.
Variable m_final: T.t V.
Hypothesis P_compat:
forall m m' a,
(forall x, T.get x m = T.get x m') ->
P m a -> P m' a.
Hypothesis H_base:
P (T.empty _) init.
Hypothesis H_rec:
forall m a k v,
T.get k m = None -> T.get k m_final = Some v -> P m a -> P (T.set k v m) (f a k v).
Let f' (a: A) (p : T.elt * V) := f a (fst p) (snd p).
Let P' (l: list (T.elt * V)) (a: A) : Prop :=
forall m, list_equiv l (T.elements m) -> P m a.
Remark H_base':
P' nil init.
Remark H_rec':
forall k v l a,
~In k (List.map (@fst T.elt V) l) ->
In (k, v) (T.elements m_final) ->
P' l a ->
P' (l ++ (k, v) :: nil) (f a k v).

(* Specifications: *)
Lemma fold_rec_aux:
forall l1 l2 a,
list_equiv (l2 ++ l1) (T.elements m_final) ->
list_disjoint (List.map (@fst T.elt V) l1) (List.map (@fst T.elt V) l2) ->
list_norepet (List.map (@fst T.elt V) l1) ->
P' l2 a -> P' (l2 ++ l1) (List.fold_left f' l1 a).
Theorem fold_rec:
P m_final (T.fold f m_final init).
Lemma fold_rec_aux:
forall l1 l2 a,
list_equiv (l2 ++ l1) (T.elements m_final) ->
list_disjoint (List.map (@fst T.elt V) l1) (List.map (@fst T.elt V) l2) ->
list_norepet (List.map (@fst T.elt V) l1) ->
P' l2 a -> P' (l2 ++ l1) (List.fold_left f' l1 a).
Theorem fold_rec:
P m_final (T.fold f m_final init).