Section POSTORDER.
Variable ginit: graph.
Variable root: node.
Inductive invariant (s: state) : Prop :=
Invariant
(* current graph is a subset of ginit *)
(SUB: forall x y, s.(gr)!x = Some y -> ginit!x = Some y)
(* root is not in current graph *)
(ROOT: s.(gr)!root = None)
(* mapped nodes have their numbers below next *)
(BELOW: forall x y, s.(map)!x = Some y -> Plt y s.(next))
(* mapping is injective *)
(INJ: forall x1 x2 y, s.(map)!x1 = Some y -> s.(map)!x2 = Some y -> x1 = x2)
(* nodes not yet visited have no number *)
(REM: forall x y, s.(gr)!x = Some y -> s.(map)!x = None)
(* black nodes have no white son *)
(COLOR: forall x succs n y,
ginit!x = Some succs -> s.(map)!x = Some n ->
In y succs -> s.(gr)!y = None)
(* worklist is well-formed *)
(WKLIST: forall x l, In (x, l) s.(wrk) ->
s.(gr)!x = None /\
exists l', ginit!x = Some l'
/\ forall y, In y l' -> ~In y l -> s.(gr)!y = None)
(* all grey nodes are on the worklist *)
(GREY: forall x, ginit!x <> None -> s.(gr)!x = None -> s.(map)!x = None ->
exists l, In (x,l) s.(wrk)).
Inductive postcondition (map: PTree.t positive) : Prop :=
Postcondition
(INJ: forall x1 x2 y, map!x1 = Some y -> map!x2 = Some y -> x1 = x2)
(ROOT: ginit!root <> None -> map!root <> None)
(SUCCS: forall x succs y, ginit!x = Some succs -> map!x <> None -> In y succs -> ginit!y <> None -> map!y <> None).
Remark In_sort:
forall x l, In x l <-> In x (Sort.sort l).
(** Termination criterion. *)
Fixpoint size_worklist (w: list (positive * list positive)) : nat :=
match w with
| nil => 0%nat
| (x, succs) :: w' => (S (List.length succs) + size_worklist w')%nat
end.
Definition lt_state (s1 s2: state) : Prop :=
lex_ord lt lt (PTree_Properties.cardinal s1.(gr), size_worklist s1.(wrk))
(PTree_Properties.cardinal s2.(gr), size_worklist s2.(wrk)).
End POSTORDER.
Definition postorder (g: graph) (root: node) :=
WfIter.iterate _ _ transition lt_state lt_state_wf transition_decreases (init_state g root).
Inductive reachable (g: graph) (root: positive) : positive -> Prop :=
| reachable_root:
reachable g root root
| reachable_succ: forall x succs y,
reachable g root x -> g!x = Some succs -> In y succs ->
reachable g root y.

Theorem postorder_correct:
forall g root,
let m := postorder g root in
(forall x1 x2 y, m!x1 = Some y -> m!x2 = Some y -> x1 = x2)
/\ (forall x, reachable g root x -> g!x <> None -> m!x <> None).