Section COMBINE.
Variables A B C: Type.
Variable f: option A -> option B -> option C.
Hypothesis f_none_none: f None None = None.
Fixpoint xcombine_l (m : t A) {struct m} : t C :=
match m with
| Leaf => Leaf
| Node l o r => Node' (xcombine_l l) (f o None) (xcombine_l r)
end.
Fixpoint xcombine_r (m : t B) {struct m} : t C :=
match m with
| Leaf => Leaf
| Node l o r => Node' (xcombine_r l) (f None o) (xcombine_r r)
end.
Fixpoint combine (m1: t A) (m2: t B) {struct m1} : t C :=
match m1 with
| Leaf => xcombine_r m2
| Node l1 o1 r1 =>
match m2 with
| Leaf => xcombine_l m1
| Node l2 o2 r2 => Node' (combine l1 l2) (f o1 o2) (combine r1 r2)
end
end.
End COMBINE.
Fixpoint xelements (A : Type) (m : t A) (i : positive)
(k: list (positive * A)) {struct m}
: list (positive * A) :=
match m with
| Leaf => k
| Node l None r =>
xelements l (xO i) (xelements r (xI i) k)
| Node l (Some x) r =>
xelements l (xO i)
((prev i, x) :: xelements r (xI i) k)
end.
Definition elements (A: Type) (m : t A) := xelements m xH nil.
Remark xelements_append:
forall A (m: t A) i k1 k2,
xelements m i (k1 ++ k2) = xelements m i k1 ++ k2.
Remark xelements_leaf:
forall A i, xelements (@Leaf A) i nil = nil.
Remark xelements_node:
forall A (m1: t A) o (m2: t A) i,
xelements (Node m1 o m2) i nil =
xelements m1 (xO i) nil
++ match o with None => nil | Some v => (prev i, v) :: nil end
++ xelements m2 (xI i) nil.
Definition xkeys (A: Type) (m: t A) (i: positive) :=
List.map (@fst positive A) (xelements m i nil).
Remark xkeys_leaf:
forall A i, xkeys (@Leaf A) i = nil.
Remark xkeys_node:
forall A (m1: t A) o (m2: t A) i,
xkeys (Node m1 o m2) i =
xkeys m1 (xO i)
++ match o with None => nil | Some v => prev i :: nil end
++ xkeys m2 (xI i).
Remark xelements_empty:
forall (A: Type) (m: t A) i, (forall i, get i m = None) -> xelements m i nil = nil.

Theorem elements_canonical_order:
forall (A B: Type) (R: A -> B -> Prop) (m: t A) (n: t B),
(forall i x, get i m = Some x -> exists y, get i n = Some y /\ R x y) ->
(forall i y, get i n = Some y -> exists x, get i m = Some x /\ R x y) ->
list_forall2
(fun i_x i_y => fst i_x = fst i_y /\ R (snd i_x) (snd i_y))
(elements m) (elements n).