summaryrefslogtreecommitdiff
path: root/theories/MSets/MSetRBT.v
diff options
context:
space:
mode:
Diffstat (limited to 'theories/MSets/MSetRBT.v')
-rw-r--r--theories/MSets/MSetRBT.v1931
1 files changed, 1931 insertions, 0 deletions
diff --git a/theories/MSets/MSetRBT.v b/theories/MSets/MSetRBT.v
new file mode 100644
index 00000000..b53c0392
--- /dev/null
+++ b/theories/MSets/MSetRBT.v
@@ -0,0 +1,1931 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(** * MSetRBT : Implementation of MSetInterface via Red-Black trees *)
+
+(** Initial author: Andrew W. Appel, 2011.
+ Extra modifications by: Pierre Letouzey
+
+The design decisions behind this implementation are described here:
+
+ - Efficient Verified Red-Black Trees, by Andrew W. Appel, September 2011.
+ http://www.cs.princeton.edu/~appel/papers/redblack.pdf
+
+Additional suggested reading:
+
+ - Red-Black Trees in a Functional Setting by Chris Okasaki.
+ Journal of Functional Programming, 9(4):471-477, July 1999.
+ http://www.eecs.usma.edu/webs/people/okasaki/jfp99redblack.pdf
+
+ - Red-black trees with types, by Stefan Kahrs.
+ Journal of Functional Programming, 11(4), 425-432, 2001.
+
+ - Functors for Proofs and Programs, by J.-C. Filliatre and P. Letouzey.
+ ESOP'04: European Symposium on Programming, pp. 370-384, 2004.
+ http://www.lri.fr/~filliatr/ftp/publis/fpp.ps.gz
+*)
+
+Require MSetGenTree.
+Require Import Bool List BinPos Pnat Setoid SetoidList NPeano Psatz.
+Local Open Scope list_scope.
+
+(* For nicer extraction, we create induction principles
+ only when needed *)
+Local Unset Elimination Schemes.
+Local Unset Case Analysis Schemes.
+
+(** An extra function not (yet?) in MSetInterface.S *)
+
+Module Type MSetRemoveMin (Import M:MSetInterface.S).
+
+ Parameter remove_min : t -> option (elt * t).
+
+ Axiom remove_min_spec1 : forall s k s',
+ remove_min s = Some (k,s') ->
+ min_elt s = Some k /\ remove k s [=] s'.
+
+ Axiom remove_min_spec2 : forall s, remove_min s = None -> Empty s.
+
+End MSetRemoveMin.
+
+(** The type of color annotation. *)
+
+Inductive color := Red | Black.
+
+Module Color.
+ Definition t := color.
+End Color.
+
+(** * Ops : the pure functions *)
+
+Module Ops (X:Orders.OrderedType) <: MSetInterface.Ops X.
+
+(** ** Generic trees instantiated with color *)
+
+(** We reuse a generic definition of trees where the information
+ parameter is a color. Functions like mem or fold are also
+ provided by this generic functor. *)
+
+Include MSetGenTree.Ops X Color.
+
+Definition t := tree.
+Local Notation Rd := (Node Red).
+Local Notation Bk := (Node Black).
+
+(** ** Basic tree *)
+
+Definition singleton (k: elt) : tree := Bk Leaf k Leaf.
+
+(** ** Changing root color *)
+
+Definition makeBlack t :=
+ match t with
+ | Leaf => Leaf
+ | Node _ a x b => Bk a x b
+ end.
+
+Definition makeRed t :=
+ match t with
+ | Leaf => Leaf
+ | Node _ a x b => Rd a x b
+ end.
+
+(** ** Balancing *)
+
+(** We adapt when one side is not a true red-black tree.
+ Both sides have the same black depth. *)
+
+Definition lbal l k r :=
+ match l with
+ | Rd (Rd a x b) y c => Rd (Bk a x b) y (Bk c k r)
+ | Rd a x (Rd b y c) => Rd (Bk a x b) y (Bk c k r)
+ | _ => Bk l k r
+ end.
+
+Definition rbal l k r :=
+ match r with
+ | Rd (Rd b y c) z d => Rd (Bk l k b) y (Bk c z d)
+ | Rd b y (Rd c z d) => Rd (Bk l k b) y (Bk c z d)
+ | _ => Bk l k r
+ end.
+
+(** A variant of [rbal], with reverse pattern order.
+ Is it really useful ? Should we always use it ? *)
+
+Definition rbal' l k r :=
+ match r with
+ | Rd b y (Rd c z d) => Rd (Bk l k b) y (Bk c z d)
+ | Rd (Rd b y c) z d => Rd (Bk l k b) y (Bk c z d)
+ | _ => Bk l k r
+ end.
+
+(** Balancing with different black depth.
+ One side is almost a red-black tree, while the other is
+ a true red-black tree, but with black depth + 1.
+ Used in deletion. *)
+
+Definition lbalS l k r :=
+ match l with
+ | Rd a x b => Rd (Bk a x b) k r
+ | _ =>
+ match r with
+ | Bk a y b => rbal' l k (Rd a y b)
+ | Rd (Bk a y b) z c => Rd (Bk l k a) y (rbal' b z (makeRed c))
+ | _ => Rd l k r (* impossible *)
+ end
+ end.
+
+Definition rbalS l k r :=
+ match r with
+ | Rd b y c => Rd l k (Bk b y c)
+ | _ =>
+ match l with
+ | Bk a x b => lbal (Rd a x b) k r
+ | Rd a x (Bk b y c) => Rd (lbal (makeRed a) x b) y (Bk c k r)
+ | _ => Rd l k r (* impossible *)
+ end
+ end.
+
+(** ** Insertion *)
+
+Fixpoint ins x s :=
+ match s with
+ | Leaf => Rd Leaf x Leaf
+ | Node c l y r =>
+ match X.compare x y with
+ | Eq => s
+ | Lt =>
+ match c with
+ | Red => Rd (ins x l) y r
+ | Black => lbal (ins x l) y r
+ end
+ | Gt =>
+ match c with
+ | Red => Rd l y (ins x r)
+ | Black => rbal l y (ins x r)
+ end
+ end
+ end.
+
+Definition add x s := makeBlack (ins x s).
+
+(** ** Deletion *)
+
+Fixpoint append (l:tree) : tree -> tree :=
+ match l with
+ | Leaf => fun r => r
+ | Node lc ll lx lr =>
+ fix append_l (r:tree) : tree :=
+ match r with
+ | Leaf => l
+ | Node rc rl rx rr =>
+ match lc, rc with
+ | Red, Red =>
+ let lrl := append lr rl in
+ match lrl with
+ | Rd lr' x rl' => Rd (Rd ll lx lr') x (Rd rl' rx rr)
+ | _ => Rd ll lx (Rd lrl rx rr)
+ end
+ | Black, Black =>
+ let lrl := append lr rl in
+ match lrl with
+ | Rd lr' x rl' => Rd (Bk ll lx lr') x (Bk rl' rx rr)
+ | _ => lbalS ll lx (Bk lrl rx rr)
+ end
+ | Black, Red => Rd (append_l rl) rx rr
+ | Red, Black => Rd ll lx (append lr r)
+ end
+ end
+ end.
+
+Fixpoint del x t :=
+ match t with
+ | Leaf => Leaf
+ | Node _ a y b =>
+ match X.compare x y with
+ | Eq => append a b
+ | Lt =>
+ match a with
+ | Bk _ _ _ => lbalS (del x a) y b
+ | _ => Rd (del x a) y b
+ end
+ | Gt =>
+ match b with
+ | Bk _ _ _ => rbalS a y (del x b)
+ | _ => Rd a y (del x b)
+ end
+ end
+ end.
+
+Definition remove x t := makeBlack (del x t).
+
+(** ** Removing minimal element *)
+
+Fixpoint delmin l x r : (elt * tree) :=
+ match l with
+ | Leaf => (x,r)
+ | Node lc ll lx lr =>
+ let (k,l') := delmin ll lx lr in
+ match lc with
+ | Black => (k, lbalS l' x r)
+ | Red => (k, Rd l' x r)
+ end
+ end.
+
+Definition remove_min t : option (elt * tree) :=
+ match t with
+ | Leaf => None
+ | Node _ l x r =>
+ let (k,t) := delmin l x r in
+ Some (k, makeBlack t)
+ end.
+
+(** ** Tree-ification
+
+ We rebuild a tree of size [if pred then n-1 else n] as soon
+ as the list [l] has enough elements *)
+
+Definition bogus : tree * list elt := (Leaf, nil).
+
+Notation treeify_t := (list elt -> tree * list elt).
+
+Definition treeify_zero : treeify_t :=
+ fun acc => (Leaf,acc).
+
+Definition treeify_one : treeify_t :=
+ fun acc => match acc with
+ | x::acc => (Rd Leaf x Leaf, acc)
+ | _ => bogus
+ end.
+
+Definition treeify_cont (f g : treeify_t) : treeify_t :=
+ fun acc =>
+ match f acc with
+ | (l, x::acc) =>
+ match g acc with
+ | (r, acc) => (Bk l x r, acc)
+ end
+ | _ => bogus
+ end.
+
+Fixpoint treeify_aux (pred:bool)(n: positive) : treeify_t :=
+ match n with
+ | xH => if pred then treeify_zero else treeify_one
+ | xO n => treeify_cont (treeify_aux pred n) (treeify_aux true n)
+ | xI n => treeify_cont (treeify_aux false n) (treeify_aux pred n)
+ end.
+
+Fixpoint plength (l:list elt) := match l with
+ | nil => 1%positive
+ | _::l => Psucc (plength l)
+end.
+
+Definition treeify (l:list elt) :=
+ fst (treeify_aux true (plength l) l).
+
+(** ** Filtering *)
+
+Fixpoint filter_aux (f: elt -> bool) s acc :=
+ match s with
+ | Leaf => acc
+ | Node _ l k r =>
+ let acc := filter_aux f r acc in
+ if f k then filter_aux f l (k::acc)
+ else filter_aux f l acc
+ end.
+
+Definition filter (f: elt -> bool) (s: t) : t :=
+ treeify (filter_aux f s nil).
+
+Fixpoint partition_aux (f: elt -> bool) s acc1 acc2 :=
+ match s with
+ | Leaf => (acc1,acc2)
+ | Node _ sl k sr =>
+ let (acc1, acc2) := partition_aux f sr acc1 acc2 in
+ if f k then partition_aux f sl (k::acc1) acc2
+ else partition_aux f sl acc1 (k::acc2)
+ end.
+
+Definition partition (f: elt -> bool) (s:t) : t*t :=
+ let (ok,ko) := partition_aux f s nil nil in
+ (treeify ok, treeify ko).
+
+(** ** Union, intersection, difference *)
+
+(** union of the elements of [l1] and [l2] into a third [acc] list. *)
+
+Fixpoint union_list l1 : list elt -> list elt -> list elt :=
+ match l1 with
+ | nil => @rev_append _
+ | x::l1' =>
+ fix union_l1 l2 acc :=
+ match l2 with
+ | nil => rev_append l1 acc
+ | y::l2' =>
+ match X.compare x y with
+ | Eq => union_list l1' l2' (x::acc)
+ | Lt => union_l1 l2' (y::acc)
+ | Gt => union_list l1' l2 (x::acc)
+ end
+ end
+ end.
+
+Definition linear_union s1 s2 :=
+ treeify (union_list (rev_elements s1) (rev_elements s2) nil).
+
+Fixpoint inter_list l1 : list elt -> list elt -> list elt :=
+ match l1 with
+ | nil => fun _ acc => acc
+ | x::l1' =>
+ fix inter_l1 l2 acc :=
+ match l2 with
+ | nil => acc
+ | y::l2' =>
+ match X.compare x y with
+ | Eq => inter_list l1' l2' (x::acc)
+ | Lt => inter_l1 l2' acc
+ | Gt => inter_list l1' l2 acc
+ end
+ end
+ end.
+
+Definition linear_inter s1 s2 :=
+ treeify (inter_list (rev_elements s1) (rev_elements s2) nil).
+
+Fixpoint diff_list l1 : list elt -> list elt -> list elt :=
+ match l1 with
+ | nil => fun _ acc => acc
+ | x::l1' =>
+ fix diff_l1 l2 acc :=
+ match l2 with
+ | nil => rev_append l1 acc
+ | y::l2' =>
+ match X.compare x y with
+ | Eq => diff_list l1' l2' acc
+ | Lt => diff_l1 l2' acc
+ | Gt => diff_list l1' l2 (x::acc)
+ end
+ end
+ end.
+
+Definition linear_diff s1 s2 :=
+ treeify (diff_list (rev_elements s1) (rev_elements s2) nil).
+
+(** [compare_height] returns:
+ - [Lt] if [height s2] is at least twice [height s1];
+ - [Gt] if [height s1] is at least twice [height s2];
+ - [Eq] if heights are approximately equal.
+ Warning: this is not an equivalence relation! but who cares.... *)
+
+Definition skip_red t :=
+ match t with
+ | Rd t' _ _ => t'
+ | _ => t
+ end.
+
+Definition skip_black t :=
+ match skip_red t with
+ | Bk t' _ _ => t'
+ | t' => t'
+ end.
+
+Fixpoint compare_height (s1x s1 s2 s2x: tree) : comparison :=
+ match skip_red s1x, skip_red s1, skip_red s2, skip_red s2x with
+ | Node _ s1x' _ _, Node _ s1' _ _, Node _ s2' _ _, Node _ s2x' _ _ =>
+ compare_height (skip_black s2x') s1' s2' (skip_black s2x')
+ | _, Leaf, _, Node _ _ _ _ => Lt
+ | Node _ _ _ _, _, Leaf, _ => Gt
+ | Node _ s1x' _ _, Node _ s1' _ _, Node _ s2' _ _, Leaf =>
+ compare_height (skip_black s1x') s1' s2' Leaf
+ | Leaf, Node _ s1' _ _, Node _ s2' _ _, Node _ s2x' _ _ =>
+ compare_height Leaf s1' s2' (skip_black s2x')
+ | _, _, _, _ => Eq
+ end.
+
+(** When one tree is quite smaller than the other, we simply
+ adds repeatively all its elements in the big one.
+ For trees of comparable height, we rather use [linear_union]. *)
+
+Definition union (t1 t2: t) : t :=
+ match compare_height t1 t1 t2 t2 with
+ | Lt => fold add t1 t2
+ | Gt => fold add t2 t1
+ | Eq => linear_union t1 t2
+ end.
+
+Definition diff (t1 t2: t) : t :=
+ match compare_height t1 t1 t2 t2 with
+ | Lt => filter (fun k => negb (mem k t2)) t1
+ | Gt => fold remove t2 t1
+ | Eq => linear_diff t1 t2
+ end.
+
+Definition inter (t1 t2: t) : t :=
+ match compare_height t1 t1 t2 t2 with
+ | Lt => filter (fun k => mem k t2) t1
+ | Gt => filter (fun k => mem k t1) t2
+ | Eq => linear_inter t1 t2
+ end.
+
+End Ops.
+
+(** * MakeRaw : the pure functions and their specifications *)
+
+Module Type MakeRaw (X:Orders.OrderedType) <: MSetInterface.RawSets X.
+Include Ops X.
+
+(** Generic definition of binary-search-trees and proofs of
+ specifications for generic functions such as mem or fold. *)
+
+Include MSetGenTree.Props X Color.
+
+Local Notation Rd := (Node Red).
+Local Notation Bk := (Node Black).
+
+Local Hint Immediate MX.eq_sym.
+Local Hint Unfold In lt_tree gt_tree Ok.
+Local Hint Constructors InT bst.
+Local Hint Resolve MX.eq_refl MX.eq_trans MX.lt_trans @ok.
+Local Hint Resolve lt_leaf gt_leaf lt_tree_node gt_tree_node.
+Local Hint Resolve lt_tree_not_in lt_tree_trans gt_tree_not_in gt_tree_trans.
+Local Hint Resolve elements_spec2.
+
+(** ** Singleton set *)
+
+Lemma singleton_spec x y : InT y (singleton x) <-> X.eq y x.
+Proof.
+ unfold singleton; intuition_in.
+Qed.
+
+Instance singleton_ok x : Ok (singleton x).
+Proof.
+ unfold singleton; auto.
+Qed.
+
+(** ** makeBlack, MakeRed *)
+
+Lemma makeBlack_spec s x : InT x (makeBlack s) <-> InT x s.
+Proof.
+ destruct s; simpl; intuition_in.
+Qed.
+
+Lemma makeRed_spec s x : InT x (makeRed s) <-> InT x s.
+Proof.
+ destruct s; simpl; intuition_in.
+Qed.
+
+Instance makeBlack_ok s `{Ok s} : Ok (makeBlack s).
+Proof.
+ destruct s; simpl; ok.
+Qed.
+
+Instance makeRed_ok s `{Ok s} : Ok (makeRed s).
+Proof.
+ destruct s; simpl; ok.
+Qed.
+
+(** ** Generic handling for red-matching and red-red-matching *)
+
+Definition isblack t :=
+ match t with Bk _ _ _ => True | _ => False end.
+
+Definition notblack t :=
+ match t with Bk _ _ _ => False | _ => True end.
+
+Definition notred t :=
+ match t with Rd _ _ _ => False | _ => True end.
+
+Definition rcase {A} f g t : A :=
+ match t with
+ | Rd a x b => f a x b
+ | _ => g t
+ end.
+
+Inductive rspec {A} f g : tree -> A -> Prop :=
+ | rred a x b : rspec f g (Rd a x b) (f a x b)
+ | relse t : notred t -> rspec f g t (g t).
+
+Fact rmatch {A} f g t : rspec (A:=A) f g t (rcase f g t).
+Proof.
+destruct t as [|[|] l x r]; simpl; now constructor.
+Qed.
+
+Definition rrcase {A} f g t : A :=
+ match t with
+ | Rd (Rd a x b) y c => f a x b y c
+ | Rd a x (Rd b y c) => f a x b y c
+ | _ => g t
+ end.
+
+Notation notredred := (rrcase (fun _ _ _ _ _ => False) (fun _ => True)).
+
+Inductive rrspec {A} f g : tree -> A -> Prop :=
+ | rrleft a x b y c : rrspec f g (Rd (Rd a x b) y c) (f a x b y c)
+ | rrright a x b y c : rrspec f g (Rd a x (Rd b y c)) (f a x b y c)
+ | rrelse t : notredred t -> rrspec f g t (g t).
+
+Fact rrmatch {A} f g t : rrspec (A:=A) f g t (rrcase f g t).
+Proof.
+destruct t as [|[|] l x r]; simpl; try now constructor.
+destruct l as [|[|] ll lx lr], r as [|[|] rl rx rr]; now constructor.
+Qed.
+
+Definition rrcase' {A} f g t : A :=
+ match t with
+ | Rd a x (Rd b y c) => f a x b y c
+ | Rd (Rd a x b) y c => f a x b y c
+ | _ => g t
+ end.
+
+Fact rrmatch' {A} f g t : rrspec (A:=A) f g t (rrcase' f g t).
+Proof.
+destruct t as [|[|] l x r]; simpl; try now constructor.
+destruct l as [|[|] ll lx lr], r as [|[|] rl rx rr]; now constructor.
+Qed.
+
+(** Balancing operations are instances of generic match *)
+
+Fact lbal_match l k r :
+ rrspec
+ (fun a x b y c => Rd (Bk a x b) y (Bk c k r))
+ (fun l => Bk l k r)
+ l
+ (lbal l k r).
+Proof.
+ exact (rrmatch _ _ _).
+Qed.
+
+Fact rbal_match l k r :
+ rrspec
+ (fun a x b y c => Rd (Bk l k a) x (Bk b y c))
+ (fun r => Bk l k r)
+ r
+ (rbal l k r).
+Proof.
+ exact (rrmatch _ _ _).
+Qed.
+
+Fact rbal'_match l k r :
+ rrspec
+ (fun a x b y c => Rd (Bk l k a) x (Bk b y c))
+ (fun r => Bk l k r)
+ r
+ (rbal' l k r).
+Proof.
+ exact (rrmatch' _ _ _).
+Qed.
+
+Fact lbalS_match l x r :
+ rspec
+ (fun a y b => Rd (Bk a y b) x r)
+ (fun l =>
+ match r with
+ | Bk a y b => rbal' l x (Rd a y b)
+ | Rd (Bk a y b) z c => Rd (Bk l x a) y (rbal' b z (makeRed c))
+ | _ => Rd l x r
+ end)
+ l
+ (lbalS l x r).
+Proof.
+ exact (rmatch _ _ _).
+Qed.
+
+Fact rbalS_match l x r :
+ rspec
+ (fun a y b => Rd l x (Bk a y b))
+ (fun r =>
+ match l with
+ | Bk a y b => lbal (Rd a y b) x r
+ | Rd a y (Bk b z c) => Rd (lbal (makeRed a) y b) z (Bk c x r)
+ | _ => Rd l x r
+ end)
+ r
+ (rbalS l x r).
+Proof.
+ exact (rmatch _ _ _).
+Qed.
+
+(** ** Balancing for insertion *)
+
+Lemma lbal_spec l x r y :
+ InT y (lbal l x r) <-> X.eq y x \/ InT y l \/ InT y r.
+Proof.
+ case lbal_match; intuition_in.
+Qed.
+
+Instance lbal_ok l x r `(Ok l, Ok r, lt_tree x l, gt_tree x r) :
+ Ok (lbal l x r).
+Proof.
+ destruct (lbal_match l x r); ok.
+Qed.
+
+Lemma rbal_spec l x r y :
+ InT y (rbal l x r) <-> X.eq y x \/ InT y l \/ InT y r.
+Proof.
+ case rbal_match; intuition_in.
+Qed.
+
+Instance rbal_ok l x r `(Ok l, Ok r, lt_tree x l, gt_tree x r) :
+ Ok (rbal l x r).
+Proof.
+ destruct (rbal_match l x r); ok.
+Qed.
+
+Lemma rbal'_spec l x r y :
+ InT y (rbal' l x r) <-> X.eq y x \/ InT y l \/ InT y r.
+Proof.
+ case rbal'_match; intuition_in.
+Qed.
+
+Instance rbal'_ok l x r `(Ok l, Ok r, lt_tree x l, gt_tree x r) :
+ Ok (rbal' l x r).
+Proof.
+ destruct (rbal'_match l x r); ok.
+Qed.
+
+Hint Rewrite In_node_iff In_leaf_iff
+ makeRed_spec makeBlack_spec lbal_spec rbal_spec rbal'_spec : rb.
+
+Ltac descolor := destruct_all Color.t.
+Ltac destree t := destruct t as [|[|] ? ? ?].
+Ltac autorew := autorewrite with rb.
+Tactic Notation "autorew" "in" ident(H) := autorewrite with rb in H.
+
+(** ** Insertion *)
+
+Lemma ins_spec : forall s x y,
+ InT y (ins x s) <-> X.eq y x \/ InT y s.
+Proof.
+ induct s x.
+ - intuition_in.
+ - intuition_in. setoid_replace y with x; eauto.
+ - descolor; autorew; rewrite IHl; intuition_in.
+ - descolor; autorew; rewrite IHr; intuition_in.
+Qed.
+Hint Rewrite ins_spec : rb.
+
+Instance ins_ok s x `{Ok s} : Ok (ins x s).
+Proof.
+ induct s x; auto; descolor;
+ (apply lbal_ok || apply rbal_ok || ok); auto;
+ intros y; autorew; intuition; order.
+Qed.
+
+Lemma add_spec' s x y :
+ InT y (add x s) <-> X.eq y x \/ InT y s.
+Proof.
+ unfold add. now autorew.
+Qed.
+
+Hint Rewrite add_spec' : rb.
+
+Lemma add_spec s x y `{Ok s} :
+ InT y (add x s) <-> X.eq y x \/ InT y s.
+Proof.
+ apply add_spec'.
+Qed.
+
+Instance add_ok s x `{Ok s} : Ok (add x s).
+Proof.
+ unfold add; auto_tc.
+Qed.
+
+(** ** Balancing for deletion *)
+
+Lemma lbalS_spec l x r y :
+ InT y (lbalS l x r) <-> X.eq y x \/ InT y l \/ InT y r.
+Proof.
+ case lbalS_match.
+ - intros; autorew; intuition_in.
+ - clear l. intros l _.
+ destruct r as [|[|] rl rx rr].
+ * autorew. intuition_in.
+ * destree rl; autorew; intuition_in.
+ * autorew. intuition_in.
+Qed.
+
+Instance lbalS_ok l x r :
+ forall `(Ok l, Ok r, lt_tree x l, gt_tree x r), Ok (lbalS l x r).
+Proof.
+ case lbalS_match; intros.
+ - ok.
+ - destruct r as [|[|] rl rx rr].
+ * ok.
+ * destruct rl as [|[|] rll rlx rlr]; intros; ok.
+ + apply rbal'_ok; ok.
+ intros w; autorew; auto.
+ + intros w; autorew.
+ destruct 1 as [Hw|[Hw|Hw]]; try rewrite Hw; eauto.
+ * ok. autorew. apply rbal'_ok; ok.
+Qed.
+
+Lemma rbalS_spec l x r y :
+ InT y (rbalS l x r) <-> X.eq y x \/ InT y l \/ InT y r.
+Proof.
+ case rbalS_match.
+ - intros; autorew; intuition_in.
+ - intros t _.
+ destruct l as [|[|] ll lx lr].
+ * autorew. intuition_in.
+ * destruct lr as [|[|] lrl lrx lrr]; autorew; intuition_in.
+ * autorew. intuition_in.
+Qed.
+
+Instance rbalS_ok l x r :
+ forall `(Ok l, Ok r, lt_tree x l, gt_tree x r), Ok (rbalS l x r).
+Proof.
+ case rbalS_match; intros.
+ - ok.
+ - destruct l as [|[|] ll lx lr].
+ * ok.
+ * destruct lr as [|[|] lrl lrx lrr]; intros; ok.
+ + apply lbal_ok; ok.
+ intros w; autorew; auto.
+ + intros w; autorew.
+ destruct 1 as [Hw|[Hw|Hw]]; try rewrite Hw; eauto.
+ * ok. apply lbal_ok; ok.
+Qed.
+
+Hint Rewrite lbalS_spec rbalS_spec : rb.
+
+(** ** Append for deletion *)
+
+Ltac append_tac l r :=
+ induction l as [| lc ll _ lx lr IHlr];
+ [intro r; simpl
+ |induction r as [| rc rl IHrl rx rr _];
+ [simpl
+ |destruct lc, rc;
+ [specialize (IHlr rl); clear IHrl
+ |simpl;
+ assert (Hr:notred (Bk rl rx rr)) by (simpl; trivial);
+ set (r:=Bk rl rx rr) in *; clearbody r; clear IHrl rl rx rr;
+ specialize (IHlr r)
+ |change (append _ _) with (Rd (append (Bk ll lx lr) rl) rx rr);
+ assert (Hl:notred (Bk ll lx lr)) by (simpl; trivial);
+ set (l:=Bk ll lx lr) in *; clearbody l; clear IHlr ll lx lr
+ |specialize (IHlr rl); clear IHrl]]].
+
+Fact append_rr_match ll lx lr rl rx rr :
+ rspec
+ (fun a x b => Rd (Rd ll lx a) x (Rd b rx rr))
+ (fun t => Rd ll lx (Rd t rx rr))
+ (append lr rl)
+ (append (Rd ll lx lr) (Rd rl rx rr)).
+Proof.
+ exact (rmatch _ _ _).
+Qed.
+
+Fact append_bb_match ll lx lr rl rx rr :
+ rspec
+ (fun a x b => Rd (Bk ll lx a) x (Bk b rx rr))
+ (fun t => lbalS ll lx (Bk t rx rr))
+ (append lr rl)
+ (append (Bk ll lx lr) (Bk rl rx rr)).
+Proof.
+ exact (rmatch _ _ _).
+Qed.
+
+Lemma append_spec l r x :
+ InT x (append l r) <-> InT x l \/ InT x r.
+Proof.
+ revert r.
+ append_tac l r; autorew; try tauto.
+ - (* Red / Red *)
+ revert IHlr; case append_rr_match;
+ [intros a y b | intros t Ht]; autorew; tauto.
+ - (* Black / Black *)
+ revert IHlr; case append_bb_match;
+ [intros a y b | intros t Ht]; autorew; tauto.
+Qed.
+
+Hint Rewrite append_spec : rb.
+
+Lemma append_ok : forall x l r `{Ok l, Ok r},
+ lt_tree x l -> gt_tree x r -> Ok (append l r).
+Proof.
+ append_tac l r.
+ - (* Leaf / _ *)
+ trivial.
+ - (* _ / Leaf *)
+ trivial.
+ - (* Red / Red *)
+ intros; inv.
+ assert (IH : Ok (append lr rl)) by (apply IHlr; eauto). clear IHlr.
+ assert (X.lt lx rx) by (transitivity x; eauto).
+ assert (G : gt_tree lx (append lr rl)).
+ { intros w. autorew. destruct 1; [|transitivity x]; eauto. }
+ assert (L : lt_tree rx (append lr rl)).
+ { intros w. autorew. destruct 1; [transitivity x|]; eauto. }
+ revert IH G L; case append_rr_match; intros; ok.
+ - (* Red / Black *)
+ intros; ok.
+ intros w; autorew; destruct 1; eauto.
+ - (* Black / Red *)
+ intros; ok.
+ intros w; autorew; destruct 1; eauto.
+ - (* Black / Black *)
+ intros; inv.
+ assert (IH : Ok (append lr rl)) by (apply IHlr; eauto). clear IHlr.
+ assert (X.lt lx rx) by (transitivity x; eauto).
+ assert (G : gt_tree lx (append lr rl)).
+ { intros w. autorew. destruct 1; [|transitivity x]; eauto. }
+ assert (L : lt_tree rx (append lr rl)).
+ { intros w. autorew. destruct 1; [transitivity x|]; eauto. }
+ revert IH G L; case append_bb_match; intros; ok.
+ apply lbalS_ok; ok.
+Qed.
+
+(** ** Deletion *)
+
+Lemma del_spec : forall s x y `{Ok s},
+ InT y (del x s) <-> InT y s /\ ~X.eq y x.
+Proof.
+induct s x.
+- intuition_in.
+- autorew; intuition_in.
+ assert (X.lt y x') by eauto. order.
+ assert (X.lt x' y) by eauto. order.
+ order.
+- destruct l as [|[|] ll lx lr]; autorew;
+ rewrite ?IHl by trivial; intuition_in; order.
+- destruct r as [|[|] rl rx rr]; autorew;
+ rewrite ?IHr by trivial; intuition_in; order.
+Qed.
+
+Hint Rewrite del_spec : rb.
+
+Instance del_ok s x `{Ok s} : Ok (del x s).
+Proof.
+induct s x.
+- trivial.
+- eapply append_ok; eauto.
+- assert (lt_tree x' (del x l)).
+ { intro w. autorew; trivial. destruct 1. eauto. }
+ destruct l as [|[|] ll lx lr]; auto_tc.
+- assert (gt_tree x' (del x r)).
+ { intro w. autorew; trivial. destruct 1. eauto. }
+ destruct r as [|[|] rl rx rr]; auto_tc.
+Qed.
+
+Lemma remove_spec s x y `{Ok s} :
+ InT y (remove x s) <-> InT y s /\ ~X.eq y x.
+Proof.
+unfold remove. now autorew.
+Qed.
+
+Hint Rewrite remove_spec : rb.
+
+Instance remove_ok s x `{Ok s} : Ok (remove x s).
+Proof.
+unfold remove; auto_tc.
+Qed.
+
+(** ** Removing the minimal element *)
+
+Lemma delmin_spec l y r c x s' `{O : Ok (Node c l y r)} :
+ delmin l y r = (x,s') ->
+ min_elt (Node c l y r) = Some x /\ del x (Node c l y r) = s'.
+Proof.
+ revert y r c x s' O.
+ induction l as [|lc ll IH ly lr _].
+ - simpl. intros y r _ x s' _. injection 1; intros; subst.
+ now rewrite MX.compare_refl.
+ - intros y r c x s' O.
+ simpl delmin.
+ specialize (IH ly lr). destruct delmin as (x0,s0).
+ destruct (IH lc x0 s0); clear IH; [ok|trivial|].
+ remember (Node lc ll ly lr) as l.
+ simpl min_elt in *.
+ intros E.
+ replace x0 with x in * by (destruct lc; now injection E).
+ split.
+ * subst l; intuition.
+ * assert (X.lt x y).
+ { inversion_clear O.
+ assert (InT x l) by now apply min_elt_spec1. auto. }
+ simpl. case X.compare_spec; try order.
+ destruct lc; injection E; clear E; intros; subst l s0; auto.
+Qed.
+
+Lemma remove_min_spec1 s x s' `{Ok s}:
+ remove_min s = Some (x,s') ->
+ min_elt s = Some x /\ remove x s = s'.
+Proof.
+ unfold remove_min.
+ destruct s as [|c l y r]; try easy.
+ generalize (delmin_spec l y r c).
+ destruct delmin as (x0,s0). intros D.
+ destruct (D x0 s0) as (->,<-); auto.
+ fold (remove x0 (Node c l y r)).
+ inversion_clear 1; auto.
+Qed.
+
+Lemma remove_min_spec2 s : remove_min s = None -> Empty s.
+Proof.
+ unfold remove_min.
+ destruct s as [|c l y r].
+ - easy.
+ - now destruct delmin.
+Qed.
+
+Lemma remove_min_ok (s:t) `{Ok s}:
+ match remove_min s with
+ | Some (_,s') => Ok s'
+ | None => True
+ end.
+Proof.
+ generalize (remove_min_spec1 s).
+ destruct remove_min as [(x0,s0)|]; auto.
+ intros R. destruct (R x0 s0); auto. subst s0. auto_tc.
+Qed.
+
+(** ** Treeify *)
+
+Notation ifpred p n := (if p then pred n else n%nat).
+
+Definition treeify_invariant size (f:treeify_t) :=
+ forall acc,
+ size <= length acc ->
+ let (t,acc') := f acc in
+ cardinal t = size /\ acc = elements t ++ acc'.
+
+Lemma treeify_zero_spec : treeify_invariant 0 treeify_zero.
+Proof.
+ intro. simpl. auto.
+Qed.
+
+Lemma treeify_one_spec : treeify_invariant 1 treeify_one.
+Proof.
+ intros [|x acc]; simpl; auto; inversion 1.
+Qed.
+
+Lemma treeify_cont_spec f g size1 size2 size :
+ treeify_invariant size1 f ->
+ treeify_invariant size2 g ->
+ size = S (size1 + size2) ->
+ treeify_invariant size (treeify_cont f g).
+Proof.
+ intros Hf Hg EQ acc LE. unfold treeify_cont.
+ specialize (Hf acc).
+ destruct (f acc) as (t1,acc1).
+ destruct Hf as (Hf1,Hf2).
+ { lia. }
+ destruct acc1 as [|x acc1].
+ { exfalso. subst acc.
+ rewrite <- app_nil_end, <- elements_cardinal in LE. lia. }
+ specialize (Hg acc1).
+ destruct (g acc1) as (t2,acc2).
+ destruct Hg as (Hg1,Hg2).
+ { subst acc. rewrite app_length, <- elements_cardinal in LE.
+ simpl in LE. unfold elt in *. lia. }
+ simpl. split.
+ * lia.
+ * rewrite elements_node, app_ass. simpl. unfold elt in *; congruence.
+Qed.
+
+Lemma treeify_aux_spec n (p:bool) :
+ treeify_invariant (ifpred p (Pos.to_nat n)) (treeify_aux p n).
+Proof.
+ revert p.
+ induction n as [n|n|]; intros p; simpl treeify_aux.
+ - eapply treeify_cont_spec; [ apply (IHn false) | apply (IHn p) | ].
+ rewrite Pos2Nat.inj_xI. generalize (Pos2Nat.is_pos n).
+ destruct p; simpl; lia.
+ - eapply treeify_cont_spec; [ apply (IHn p) | apply (IHn true) | ].
+ rewrite Pos2Nat.inj_xO. generalize (Pos2Nat.is_pos n).
+ destruct p; simpl; lia.
+ - destruct p; [ apply treeify_zero_spec | apply treeify_one_spec ].
+Qed.
+
+Lemma plength_spec l : Pos.to_nat (plength l) = S (length l).
+Proof.
+ induction l; simpl; now rewrite ?Pos2Nat.inj_succ, ?IHl.
+Qed.
+
+Lemma treeify_elements l : elements (treeify l) = l.
+Proof.
+ assert (H := treeify_aux_spec (plength l) true l).
+ unfold treeify. destruct treeify_aux as (t,acc); simpl in *.
+ destruct H as (H,H'). { now rewrite plength_spec. }
+ subst l. rewrite plength_spec, app_length, <- elements_cardinal in *.
+ destruct acc.
+ * now rewrite app_nil_r.
+ * simpl in H. lia.
+Qed.
+
+Lemma treeify_spec x l : InT x (treeify l) <-> InA X.eq x l.
+Proof.
+ intros. now rewrite <- elements_spec1, treeify_elements.
+Qed.
+
+Lemma treeify_ok l : sort X.lt l -> Ok (treeify l).
+Proof.
+ intros. apply elements_sort_ok. rewrite treeify_elements; auto.
+Qed.
+
+
+(** ** Filter *)
+
+Lemma filter_app A f (l l':list A) :
+ List.filter f (l ++ l') = List.filter f l ++ List.filter f l'.
+Proof.
+ induction l as [|x l IH]; simpl; trivial.
+ destruct (f x); simpl; now rewrite IH.
+Qed.
+
+Lemma filter_aux_elements s f acc :
+ filter_aux f s acc = List.filter f (elements s) ++ acc.
+Proof.
+ revert acc.
+ induction s as [|c l IHl x r IHr]; simpl; trivial.
+ intros acc.
+ rewrite elements_node, filter_app. simpl.
+ destruct (f x); now rewrite IHl, IHr, app_ass.
+Qed.
+
+Lemma filter_elements s f :
+ elements (filter f s) = List.filter f (elements s).
+Proof.
+ unfold filter.
+ now rewrite treeify_elements, filter_aux_elements, app_nil_r.
+Qed.
+
+Lemma filter_spec s x f :
+ Proper (X.eq==>Logic.eq) f ->
+ (InT x (filter f s) <-> InT x s /\ f x = true).
+Proof.
+ intros Hf.
+ rewrite <- elements_spec1, filter_elements, filter_InA, elements_spec1;
+ now auto_tc.
+Qed.
+
+Instance filter_ok s f `(Ok s) : Ok (filter f s).
+Proof.
+ apply elements_sort_ok.
+ rewrite filter_elements.
+ apply filter_sort with X.eq; auto_tc.
+Qed.
+
+(** ** Partition *)
+
+Lemma partition_aux_spec s f acc1 acc2 :
+ partition_aux f s acc1 acc2 =
+ (filter_aux f s acc1, filter_aux (fun x => negb (f x)) s acc2).
+Proof.
+ revert acc1 acc2.
+ induction s as [ | c l Hl x r Hr ]; simpl.
+ - trivial.
+ - intros acc1 acc2.
+ destruct (f x); simpl; now rewrite Hr, Hl.
+Qed.
+
+Lemma partition_spec s f :
+ partition f s = (filter f s, filter (fun x => negb (f x)) s).
+Proof.
+ unfold partition, filter. now rewrite partition_aux_spec.
+Qed.
+
+Lemma partition_spec1 s f :
+ Proper (X.eq==>Logic.eq) f ->
+ Equal (fst (partition f s)) (filter f s).
+Proof. now rewrite partition_spec. Qed.
+
+Lemma partition_spec2 s f :
+ Proper (X.eq==>Logic.eq) f ->
+ Equal (snd (partition f s)) (filter (fun x => negb (f x)) s).
+Proof. now rewrite partition_spec. Qed.
+
+Instance partition_ok1 s f `(Ok s) : Ok (fst (partition f s)).
+Proof. rewrite partition_spec; now apply filter_ok. Qed.
+
+Instance partition_ok2 s f `(Ok s) : Ok (snd (partition f s)).
+Proof. rewrite partition_spec; now apply filter_ok. Qed.
+
+
+(** ** An invariant for binary list functions with accumulator. *)
+
+Ltac inA :=
+ rewrite ?InA_app_iff, ?InA_cons, ?InA_nil, ?InA_rev in *; auto_tc.
+
+Record INV l1 l2 acc : Prop := {
+ l1_sorted : sort X.lt (rev l1);
+ l2_sorted : sort X.lt (rev l2);
+ acc_sorted : sort X.lt acc;
+ l1_lt_acc x y : InA X.eq x l1 -> InA X.eq y acc -> X.lt x y;
+ l2_lt_acc x y : InA X.eq x l2 -> InA X.eq y acc -> X.lt x y}.
+Local Hint Resolve l1_sorted l2_sorted acc_sorted.
+
+Lemma INV_init s1 s2 `(Ok s1, Ok s2) :
+ INV (rev_elements s1) (rev_elements s2) nil.
+Proof.
+ rewrite !rev_elements_rev.
+ split; rewrite ?rev_involutive; auto; intros; now inA.
+Qed.
+
+Lemma INV_sym l1 l2 acc : INV l1 l2 acc -> INV l2 l1 acc.
+Proof.
+ destruct 1; now split.
+Qed.
+
+Lemma INV_drop x1 l1 l2 acc :
+ INV (x1 :: l1) l2 acc -> INV l1 l2 acc.
+Proof.
+ intros (l1s,l2s,accs,l1a,l2a). simpl in *.
+ destruct (sorted_app_inv _ _ l1s) as (U & V & W); auto.
+ split; auto.
+Qed.
+
+Lemma INV_eq x1 x2 l1 l2 acc :
+ INV (x1 :: l1) (x2 :: l2) acc -> X.eq x1 x2 ->
+ INV l1 l2 (x1 :: acc).
+Proof.
+ intros (U,V,W,X,Y) EQ. simpl in *.
+ destruct (sorted_app_inv _ _ U) as (U1 & U2 & U3); auto.
+ destruct (sorted_app_inv _ _ V) as (V1 & V2 & V3); auto.
+ split; auto.
+ - constructor; auto. apply InA_InfA with X.eq; auto_tc.
+ - intros x y; inA; intros Hx [Hy|Hy].
+ + apply U3; inA.
+ + apply X; inA.
+ - intros x y; inA; intros Hx [Hy|Hy].
+ + rewrite Hy, EQ; apply V3; inA.
+ + apply Y; inA.
+Qed.
+
+Lemma INV_lt x1 x2 l1 l2 acc :
+ INV (x1 :: l1) (x2 :: l2) acc -> X.lt x1 x2 ->
+ INV (x1 :: l1) l2 (x2 :: acc).
+Proof.
+ intros (U,V,W,X,Y) EQ. simpl in *.
+ destruct (sorted_app_inv _ _ U) as (U1 & U2 & U3); auto.
+ destruct (sorted_app_inv _ _ V) as (V1 & V2 & V3); auto.
+ split; auto.
+ - constructor; auto. apply InA_InfA with X.eq; auto_tc.
+ - intros x y; inA; intros Hx [Hy|Hy].
+ + rewrite Hy; clear Hy. destruct Hx; [order|].
+ transitivity x1; auto. apply U3; inA.
+ + apply X; inA.
+ - intros x y; inA; intros Hx [Hy|Hy].
+ + rewrite Hy. apply V3; inA.
+ + apply Y; inA.
+Qed.
+
+Lemma INV_rev l1 l2 acc :
+ INV l1 l2 acc -> Sorted X.lt (rev_append l1 acc).
+Proof.
+ intros. rewrite rev_append_rev.
+ apply SortA_app with X.eq; eauto with *.
+ intros x y. inA. eapply l1_lt_acc; eauto.
+Qed.
+
+(** ** union *)
+
+Lemma union_list_ok l1 l2 acc :
+ INV l1 l2 acc -> sort X.lt (union_list l1 l2 acc).
+Proof.
+ revert l2 acc.
+ induction l1 as [|x1 l1 IH1];
+ [intro l2|induction l2 as [|x2 l2 IH2]];
+ intros acc inv.
+ - eapply INV_rev, INV_sym; eauto.
+ - eapply INV_rev; eauto.
+ - simpl. case X.compare_spec; intro C.
+ * apply IH1. eapply INV_eq; eauto.
+ * apply (IH2 (x2::acc)). eapply INV_lt; eauto.
+ * apply IH1. eapply INV_sym, INV_lt; eauto. now apply INV_sym.
+Qed.
+
+Instance linear_union_ok s1 s2 `(Ok s1, Ok s2) :
+ Ok (linear_union s1 s2).
+Proof.
+ unfold linear_union. now apply treeify_ok, union_list_ok, INV_init.
+Qed.
+
+Instance fold_add_ok s1 s2 `(Ok s1, Ok s2) :
+ Ok (fold add s1 s2).
+Proof.
+ rewrite fold_spec, <- fold_left_rev_right.
+ unfold elt in *.
+ induction (rev (elements s1)); simpl; unfold flip in *; auto_tc.
+Qed.
+
+Instance union_ok s1 s2 `(Ok s1, Ok s2) : Ok (union s1 s2).
+Proof.
+ unfold union. destruct compare_height; auto_tc.
+Qed.
+
+Lemma union_list_spec x l1 l2 acc :
+ InA X.eq x (union_list l1 l2 acc) <->
+ InA X.eq x l1 \/ InA X.eq x l2 \/ InA X.eq x acc.
+Proof.
+ revert l2 acc.
+ induction l1 as [|x1 l1 IH1].
+ - intros l2 acc; simpl. rewrite rev_append_rev. inA. tauto.
+ - induction l2 as [|x2 l2 IH2]; intros acc; simpl.
+ * rewrite rev_append_rev. inA. tauto.
+ * case X.compare_spec; intro C.
+ + rewrite IH1, !InA_cons, C; tauto.
+ + rewrite (IH2 (x2::acc)), !InA_cons. tauto.
+ + rewrite IH1, !InA_cons; tauto.
+Qed.
+
+Lemma linear_union_spec s1 s2 x :
+ InT x (linear_union s1 s2) <-> InT x s1 \/ InT x s2.
+Proof.
+ unfold linear_union.
+ rewrite treeify_spec, union_list_spec, !rev_elements_rev.
+ rewrite !InA_rev, InA_nil, !elements_spec1 by auto_tc.
+ tauto.
+Qed.
+
+Lemma fold_add_spec s1 s2 x :
+ InT x (fold add s1 s2) <-> InT x s1 \/ InT x s2.
+Proof.
+ rewrite fold_spec, <- fold_left_rev_right.
+ rewrite <- (elements_spec1 s1), <- InA_rev by auto_tc.
+ unfold elt in *.
+ induction (rev (elements s1)); simpl.
+ - rewrite InA_nil. tauto.
+ - unfold flip. rewrite add_spec', IHl, InA_cons. tauto.
+Qed.
+
+Lemma union_spec' s1 s2 x :
+ InT x (union s1 s2) <-> InT x s1 \/ InT x s2.
+Proof.
+ unfold union. destruct compare_height.
+ - apply linear_union_spec.
+ - apply fold_add_spec.
+ - rewrite fold_add_spec. tauto.
+Qed.
+
+Lemma union_spec : forall s1 s2 y `{Ok s1, Ok s2},
+ (InT y (union s1 s2) <-> InT y s1 \/ InT y s2).
+Proof.
+ intros; apply union_spec'.
+Qed.
+
+(** ** inter *)
+
+Lemma inter_list_ok l1 l2 acc :
+ INV l1 l2 acc -> sort X.lt (inter_list l1 l2 acc).
+Proof.
+ revert l2 acc.
+ induction l1 as [|x1 l1 IH1]; [|induction l2 as [|x2 l2 IH2]]; simpl.
+ - eauto.
+ - eauto.
+ - intros acc inv.
+ case X.compare_spec; intro C.
+ * apply IH1. eapply INV_eq; eauto.
+ * apply (IH2 acc). eapply INV_sym, INV_drop, INV_sym; eauto.
+ * apply IH1. eapply INV_drop; eauto.
+Qed.
+
+Instance linear_inter_ok s1 s2 `(Ok s1, Ok s2) :
+ Ok (linear_inter s1 s2).
+Proof.
+ unfold linear_inter. now apply treeify_ok, inter_list_ok, INV_init.
+Qed.
+
+Instance inter_ok s1 s2 `(Ok s1, Ok s2) : Ok (inter s1 s2).
+Proof.
+ unfold inter. destruct compare_height; auto_tc.
+Qed.
+
+Lemma inter_list_spec x l1 l2 acc :
+ sort X.lt (rev l1) ->
+ sort X.lt (rev l2) ->
+ (InA X.eq x (inter_list l1 l2 acc) <->
+ (InA X.eq x l1 /\ InA X.eq x l2) \/ InA X.eq x acc).
+Proof.
+ revert l2 acc.
+ induction l1 as [|x1 l1 IH1].
+ - intros l2 acc; simpl. inA. tauto.
+ - induction l2 as [|x2 l2 IH2]; intros acc.
+ * simpl. inA. tauto.
+ * simpl. intros U V.
+ destruct (sorted_app_inv _ _ U) as (U1 & U2 & U3); auto.
+ destruct (sorted_app_inv _ _ V) as (V1 & V2 & V3); auto.
+ case X.compare_spec; intro C.
+ + rewrite IH1, !InA_cons, C; tauto.
+ + rewrite (IH2 acc); auto. inA. intuition; try order.
+ assert (X.lt x x1) by (apply U3; inA). order.
+ + rewrite IH1; auto. inA. intuition; try order.
+ assert (X.lt x x2) by (apply V3; inA). order.
+Qed.
+
+Lemma linear_inter_spec s1 s2 x `(Ok s1, Ok s2) :
+ InT x (linear_inter s1 s2) <-> InT x s1 /\ InT x s2.
+Proof.
+ unfold linear_inter.
+ rewrite !rev_elements_rev, treeify_spec, inter_list_spec
+ by (rewrite rev_involutive; auto_tc).
+ rewrite !InA_rev, InA_nil, !elements_spec1 by auto_tc. tauto.
+Qed.
+
+Local Instance mem_proper s `(Ok s) :
+ Proper (X.eq ==> Logic.eq) (fun k => mem k s).
+Proof.
+ intros x y EQ. apply Bool.eq_iff_eq_true; rewrite !mem_spec; auto.
+ now rewrite EQ.
+Qed.
+
+Lemma inter_spec s1 s2 y `{Ok s1, Ok s2} :
+ InT y (inter s1 s2) <-> InT y s1 /\ InT y s2.
+Proof.
+ unfold inter. destruct compare_height.
+ - now apply linear_inter_spec.
+ - rewrite filter_spec, mem_spec by auto_tc; tauto.
+ - rewrite filter_spec, mem_spec by auto_tc; tauto.
+Qed.
+
+(** ** difference *)
+
+Lemma diff_list_ok l1 l2 acc :
+ INV l1 l2 acc -> sort X.lt (diff_list l1 l2 acc).
+Proof.
+ revert l2 acc.
+ induction l1 as [|x1 l1 IH1];
+ [intro l2|induction l2 as [|x2 l2 IH2]];
+ intros acc inv.
+ - eauto.
+ - unfold diff_list. eapply INV_rev; eauto.
+ - simpl. case X.compare_spec; intro C.
+ * apply IH1. eapply INV_drop, INV_sym, INV_drop, INV_sym; eauto.
+ * apply (IH2 acc). eapply INV_sym, INV_drop, INV_sym; eauto.
+ * apply IH1. eapply INV_sym, INV_lt; eauto. now apply INV_sym.
+Qed.
+
+Instance diff_inter_ok s1 s2 `(Ok s1, Ok s2) :
+ Ok (linear_diff s1 s2).
+Proof.
+ unfold linear_inter. now apply treeify_ok, diff_list_ok, INV_init.
+Qed.
+
+Instance fold_remove_ok s1 s2 `(Ok s2) :
+ Ok (fold remove s1 s2).
+Proof.
+ rewrite fold_spec, <- fold_left_rev_right.
+ unfold elt in *.
+ induction (rev (elements s1)); simpl; unfold flip in *; auto_tc.
+Qed.
+
+Instance diff_ok s1 s2 `(Ok s1, Ok s2) : Ok (diff s1 s2).
+Proof.
+ unfold diff. destruct compare_height; auto_tc.
+Qed.
+
+Lemma diff_list_spec x l1 l2 acc :
+ sort X.lt (rev l1) ->
+ sort X.lt (rev l2) ->
+ (InA X.eq x (diff_list l1 l2 acc) <->
+ (InA X.eq x l1 /\ ~InA X.eq x l2) \/ InA X.eq x acc).
+Proof.
+ revert l2 acc.
+ induction l1 as [|x1 l1 IH1].
+ - intros l2 acc; simpl. inA. tauto.
+ - induction l2 as [|x2 l2 IH2]; intros acc.
+ * intros; simpl. rewrite rev_append_rev. inA. tauto.
+ * simpl. intros U V.
+ destruct (sorted_app_inv _ _ U) as (U1 & U2 & U3); auto.
+ destruct (sorted_app_inv _ _ V) as (V1 & V2 & V3); auto.
+ case X.compare_spec; intro C.
+ + rewrite IH1; auto. f_equiv. inA. intuition; try order.
+ assert (X.lt x x1) by (apply U3; inA). order.
+ + rewrite (IH2 acc); auto. f_equiv. inA. intuition; try order.
+ assert (X.lt x x1) by (apply U3; inA). order.
+ + rewrite IH1; auto. inA. intuition; try order.
+ left; split; auto. destruct 1. order.
+ assert (X.lt x x2) by (apply V3; inA). order.
+Qed.
+
+Lemma linear_diff_spec s1 s2 x `(Ok s1, Ok s2) :
+ InT x (linear_diff s1 s2) <-> InT x s1 /\ ~InT x s2.
+Proof.
+ unfold linear_diff.
+ rewrite !rev_elements_rev, treeify_spec, diff_list_spec
+ by (rewrite rev_involutive; auto_tc).
+ rewrite !InA_rev, InA_nil, !elements_spec1 by auto_tc. tauto.
+Qed.
+
+Lemma fold_remove_spec s1 s2 x `(Ok s2) :
+ InT x (fold remove s1 s2) <-> InT x s2 /\ ~InT x s1.
+Proof.
+ rewrite fold_spec, <- fold_left_rev_right.
+ rewrite <- (elements_spec1 s1), <- InA_rev by auto_tc.
+ unfold elt in *.
+ induction (rev (elements s1)); simpl; intros.
+ - rewrite InA_nil. intuition.
+ - unfold flip in *. rewrite remove_spec, IHl, InA_cons. tauto.
+ clear IHl. induction l; simpl; auto_tc.
+Qed.
+
+Lemma diff_spec s1 s2 y `{Ok s1, Ok s2} :
+ InT y (diff s1 s2) <-> InT y s1 /\ ~InT y s2.
+Proof.
+ unfold diff. destruct compare_height.
+ - now apply linear_diff_spec.
+ - rewrite filter_spec, Bool.negb_true_iff,
+ <- Bool.not_true_iff_false, mem_spec;
+ intuition.
+ intros x1 x2 EQ. f_equal. now apply mem_proper.
+ - now apply fold_remove_spec.
+Qed.
+
+End MakeRaw.
+
+(** * Balancing properties
+
+ We now prove that all operations preserve a red-black invariant,
+ and that trees have hence a logarithmic depth.
+*)
+
+Module BalanceProps(X:Orders.OrderedType)(Import M : MakeRaw X).
+
+Local Notation Rd := (Node Red).
+Local Notation Bk := (Node Black).
+Import M.MX.
+
+(** ** Red-Black invariants *)
+
+(** In a red-black tree :
+ - a red node has no red children
+ - the black depth at each node is the same along all paths.
+ The black depth is here an argument of the predicate. *)
+
+Inductive rbt : nat -> tree -> Prop :=
+ | RB_Leaf : rbt 0 Leaf
+ | RB_Rd n l k r :
+ notred l -> notred r -> rbt n l -> rbt n r -> rbt n (Rd l k r)
+ | RB_Bk n l k r : rbt n l -> rbt n r -> rbt (S n) (Bk l k r).
+
+(** A red-red tree is almost a red-black tree, except that it has
+ a _red_ root node which _may_ have red children. Note that a
+ red-red tree is hence non-empty, and all its strict subtrees
+ are red-black. *)
+
+Inductive rrt (n:nat) : tree -> Prop :=
+ | RR_Rd l k r : rbt n l -> rbt n r -> rrt n (Rd l k r).
+
+(** An almost-red-black tree is almost a red-black tree, except that
+ it's permitted to have two red nodes in a row at the very root (only).
+ We implement this notion by saying that a quasi-red-black tree
+ is either a red-black tree or a red-red tree. *)
+
+Inductive arbt (n:nat)(t:tree) : Prop :=
+ | ARB_RB : rbt n t -> arbt n t
+ | ARB_RR : rrt n t -> arbt n t.
+
+(** The main exported invariant : being a red-black tree for some
+ black depth. *)
+
+Class Rbt (t:tree) := RBT : exists d, rbt d t.
+
+(** ** Basic tactics and results about red-black *)
+
+Scheme rbt_ind := Induction for rbt Sort Prop.
+Local Hint Constructors rbt rrt arbt.
+Local Hint Extern 0 (notred _) => (exact I).
+Ltac invrb := intros; invtree rrt; invtree rbt; try contradiction.
+Ltac desarb := match goal with H:arbt _ _ |- _ => destruct H end.
+Ltac nonzero n := destruct n as [|n]; [try split; invrb|].
+
+Lemma rr_nrr_rb n t :
+ rrt n t -> notredred t -> rbt n t.
+Proof.
+ destruct 1 as [l x r Hl Hr].
+ destruct l, r; descolor; invrb; auto.
+Qed.
+
+Local Hint Resolve rr_nrr_rb.
+
+Lemma arb_nrr_rb n t :
+ arbt n t -> notredred t -> rbt n t.
+Proof.
+ destruct 1; auto.
+Qed.
+
+Lemma arb_nr_rb n t :
+ arbt n t -> notred t -> rbt n t.
+Proof.
+ destruct 1; destruct t; descolor; invrb; auto.
+Qed.
+
+Local Hint Resolve arb_nrr_rb arb_nr_rb.
+
+(** ** A Red-Black tree has indeed a logarithmic depth *)
+
+Definition redcarac s := rcase (fun _ _ _ => 1) (fun _ => 0) s.
+
+Lemma rb_maxdepth s n : rbt n s -> maxdepth s <= 2*n + redcarac s.
+Proof.
+ induction 1.
+ - simpl; auto.
+ - replace (redcarac l) with 0 in * by now destree l.
+ replace (redcarac r) with 0 in * by now destree r.
+ simpl maxdepth. simpl redcarac.
+ rewrite Nat.add_succ_r, <- Nat.succ_le_mono.
+ now apply Nat.max_lub.
+ - simpl. Nat.nzsimpl. rewrite <- Nat.succ_le_mono.
+ apply Nat.max_lub; eapply Nat.le_trans; eauto.
+ destree l; simpl; lia.
+ destree r; simpl; lia.
+Qed.
+
+Lemma rb_mindepth s n : rbt n s -> n + redcarac s <= mindepth s.
+Proof.
+ induction 1; simpl.
+ - trivial.
+ - rewrite Nat.add_succ_r.
+ apply -> Nat.succ_le_mono.
+ replace (redcarac l) with 0 in * by now destree l.
+ replace (redcarac r) with 0 in * by now destree r.
+ now apply Nat.min_glb.
+ - apply -> Nat.succ_le_mono. apply Nat.min_glb; lia.
+Qed.
+
+Lemma maxdepth_upperbound s : Rbt s ->
+ maxdepth s <= 2 * log2 (S (cardinal s)).
+Proof.
+ intros (n,H).
+ eapply Nat.le_trans; [eapply rb_maxdepth; eauto|].
+ generalize (rb_mindepth s n H).
+ generalize (mindepth_log_cardinal s). lia.
+Qed.
+
+Lemma maxdepth_lowerbound s : s<>Leaf ->
+ log2 (cardinal s) < maxdepth s.
+Proof.
+ apply maxdepth_log_cardinal.
+Qed.
+
+
+(** ** Singleton *)
+
+Lemma singleton_rb x : Rbt (singleton x).
+Proof.
+ unfold singleton. exists 1; auto.
+Qed.
+
+(** ** [makeBlack] and [makeRed] *)
+
+Lemma makeBlack_rb n t : arbt n t -> Rbt (makeBlack t).
+Proof.
+ destruct t as [|[|] l x r].
+ - exists 0; auto.
+ - destruct 1; invrb; exists (S n); simpl; auto.
+ - exists n; auto.
+Qed.
+
+Lemma makeRed_rr t n :
+ rbt (S n) t -> notred t -> rrt n (makeRed t).
+Proof.
+ destruct t as [|[|] l x r]; invrb; simpl; auto.
+Qed.
+
+(** ** Balancing *)
+
+Lemma lbal_rb n l k r :
+ arbt n l -> rbt n r -> rbt (S n) (lbal l k r).
+Proof.
+case lbal_match; intros; desarb; invrb; auto.
+Qed.
+
+Lemma rbal_rb n l k r :
+ rbt n l -> arbt n r -> rbt (S n) (rbal l k r).
+Proof.
+case rbal_match; intros; desarb; invrb; auto.
+Qed.
+
+Lemma rbal'_rb n l k r :
+ rbt n l -> arbt n r -> rbt (S n) (rbal' l k r).
+Proof.
+case rbal'_match; intros; desarb; invrb; auto.
+Qed.
+
+Lemma lbalS_rb n l x r :
+ arbt n l -> rbt (S n) r -> notred r -> rbt (S n) (lbalS l x r).
+Proof.
+ intros Hl Hr Hr'.
+ destruct r as [|[|] rl rx rr]; invrb. clear Hr'.
+ revert Hl.
+ case lbalS_match.
+ - destruct 1; invrb; auto.
+ - intros. apply rbal'_rb; auto.
+Qed.
+
+Lemma lbalS_arb n l x r :
+ arbt n l -> rbt (S n) r -> arbt (S n) (lbalS l x r).
+Proof.
+ case lbalS_match.
+ - destruct 1; invrb; auto.
+ - clear l. intros l Hl Hl' Hr.
+ destruct r as [|[|] rl rx rr]; invrb.
+ * destruct rl as [|[|] rll rlx rlr]; invrb.
+ right; auto using rbal'_rb, makeRed_rr.
+ * left; apply rbal'_rb; auto.
+Qed.
+
+Lemma rbalS_rb n l x r :
+ rbt (S n) l -> notred l -> arbt n r -> rbt (S n) (rbalS l x r).
+Proof.
+ intros Hl Hl' Hr.
+ destruct l as [|[|] ll lx lr]; invrb. clear Hl'.
+ revert Hr.
+ case rbalS_match.
+ - destruct 1; invrb; auto.
+ - intros. apply lbal_rb; auto.
+Qed.
+
+Lemma rbalS_arb n l x r :
+ rbt (S n) l -> arbt n r -> arbt (S n) (rbalS l x r).
+Proof.
+ case rbalS_match.
+ - destruct 2; invrb; auto.
+ - clear r. intros r Hr Hr' Hl.
+ destruct l as [|[|] ll lx lr]; invrb.
+ * destruct lr as [|[|] lrl lrx lrr]; invrb.
+ right; auto using lbal_rb, makeRed_rr.
+ * left; apply lbal_rb; auto.
+Qed.
+
+
+(** ** Insertion *)
+
+(** The next lemmas combine simultaneous results about rbt and arbt.
+ A first solution here: statement with [if ... then ... else] *)
+
+Definition ifred s (A B:Prop) := rcase (fun _ _ _ => A) (fun _ => B) s.
+
+Lemma ifred_notred s A B : notred s -> (ifred s A B <-> B).
+Proof.
+ destruct s; descolor; simpl; intuition.
+Qed.
+
+Lemma ifred_or s A B : ifred s A B -> A\/B.
+Proof.
+ destruct s; descolor; simpl; intuition.
+Qed.
+
+Lemma ins_rr_rb x s n : rbt n s ->
+ ifred s (rrt n (ins x s)) (rbt n (ins x s)).
+Proof.
+induction 1 as [ | n l k r | n l k r Hl IHl Hr IHr ].
+- simpl; auto.
+- simpl. rewrite ifred_notred in * by trivial.
+ elim_compare x k; auto.
+- rewrite ifred_notred by trivial.
+ unfold ins; fold ins. (* simpl is too much here ... *)
+ elim_compare x k.
+ * auto.
+ * apply lbal_rb; trivial. apply ifred_or in IHl; intuition.
+ * apply rbal_rb; trivial. apply ifred_or in IHr; intuition.
+Qed.
+
+Lemma ins_arb x s n : rbt n s -> arbt n (ins x s).
+Proof.
+ intros H. apply (ins_rr_rb x), ifred_or in H. intuition.
+Qed.
+
+Instance add_rb x s : Rbt s -> Rbt (add x s).
+Proof.
+ intros (n,H). unfold add. now apply (makeBlack_rb n), ins_arb.
+Qed.
+
+(** ** Deletion *)
+
+(** A second approach here: statement with ... /\ ... *)
+
+Lemma append_arb_rb n l r : rbt n l -> rbt n r ->
+ (arbt n (append l r)) /\
+ (notred l -> notred r -> rbt n (append l r)).
+Proof.
+revert r n.
+append_tac l r.
+- split; auto.
+- split; auto.
+- (* Red / Red *)
+ intros n. invrb.
+ case (IHlr n); auto; clear IHlr.
+ case append_rr_match.
+ + intros a x b _ H; split; invrb.
+ assert (rbt n (Rd a x b)) by auto. invrb. auto.
+ + split; invrb; auto.
+- (* Red / Black *)
+ split; invrb. destruct (IHlr n) as (_,IH); auto.
+- (* Black / Red *)
+ split; invrb. destruct (IHrl n) as (_,IH); auto.
+- (* Black / Black *)
+ nonzero n.
+ invrb.
+ destruct (IHlr n) as (IH,_); auto; clear IHlr.
+ revert IH.
+ case append_bb_match.
+ + intros a x b IH; split; destruct IH; invrb; auto.
+ + split; [left | invrb]; auto using lbalS_rb.
+Qed.
+
+(** A third approach : Lemma ... with ... *)
+
+Lemma del_arb s x n : rbt (S n) s -> isblack s -> arbt n (del x s)
+with del_rb s x n : rbt n s -> notblack s -> rbt n (del x s).
+Proof.
+{ revert n.
+ induct s x; try destruct c; try contradiction; invrb.
+ - apply append_arb_rb; assumption.
+ - assert (IHl' := del_rb l x). clear IHr del_arb del_rb.
+ destruct l as [|[|] ll lx lr]; auto.
+ nonzero n. apply lbalS_arb; auto.
+ - assert (IHr' := del_rb r x). clear IHl del_arb del_rb.
+ destruct r as [|[|] rl rx rr]; auto.
+ nonzero n. apply rbalS_arb; auto. }
+{ revert n.
+ induct s x; try assumption; try destruct c; try contradiction; invrb.
+ - apply append_arb_rb; assumption.
+ - assert (IHl' := del_arb l x). clear IHr del_arb del_rb.
+ destruct l as [|[|] ll lx lr]; auto.
+ nonzero n. destruct n as [|n]; [invrb|]; apply lbalS_rb; auto.
+ - assert (IHr' := del_arb r x). clear IHl del_arb del_rb.
+ destruct r as [|[|] rl rx rr]; auto.
+ nonzero n. apply rbalS_rb; auto. }
+Qed.
+
+Instance remove_rb s x : Rbt s -> Rbt (remove x s).
+Proof.
+ intros (n,H). unfold remove.
+ destruct s as [|[|] l y r].
+ - apply (makeBlack_rb n). auto.
+ - apply (makeBlack_rb n). left. apply del_rb; simpl; auto.
+ - nonzero n. apply (makeBlack_rb n). apply del_arb; simpl; auto.
+Qed.
+
+(** ** Treeify *)
+
+Definition treeify_rb_invariant size depth (f:treeify_t) :=
+ forall acc,
+ size <= length acc ->
+ rbt depth (fst (f acc)) /\
+ size + length (snd (f acc)) = length acc.
+
+Lemma treeify_zero_rb : treeify_rb_invariant 0 0 treeify_zero.
+Proof.
+ intros acc _; simpl; auto.
+Qed.
+
+Lemma treeify_one_rb : treeify_rb_invariant 1 0 treeify_one.
+Proof.
+ intros [|x acc]; simpl; auto; inversion 1.
+Qed.
+
+Lemma treeify_cont_rb f g size1 size2 size d :
+ treeify_rb_invariant size1 d f ->
+ treeify_rb_invariant size2 d g ->
+ size = S (size1 + size2) ->
+ treeify_rb_invariant size (S d) (treeify_cont f g).
+Proof.
+ intros Hf Hg H acc Hacc.
+ unfold treeify_cont.
+ specialize (Hf acc).
+ destruct (f acc) as (l, acc1). simpl in *.
+ destruct Hf as (Hf1, Hf2). { lia. }
+ destruct acc1 as [|x acc2]; simpl in *. { lia. }
+ specialize (Hg acc2).
+ destruct (g acc2) as (r, acc3). simpl in *.
+ destruct Hg as (Hg1, Hg2). { lia. }
+ split; [auto | lia].
+Qed.
+
+Lemma treeify_aux_rb n :
+ exists d, forall (b:bool),
+ treeify_rb_invariant (ifpred b (Pos.to_nat n)) d (treeify_aux b n).
+Proof.
+ induction n as [n (d,IHn)|n (d,IHn)| ].
+ - exists (S d). intros b.
+ eapply treeify_cont_rb; [ apply (IHn false) | apply (IHn b) | ].
+ rewrite Pos2Nat.inj_xI. generalize (Pos2Nat.is_pos n).
+ destruct b; simpl; lia.
+ - exists (S d). intros b.
+ eapply treeify_cont_rb; [ apply (IHn b) | apply (IHn true) | ].
+ rewrite Pos2Nat.inj_xO. generalize (Pos2Nat.is_pos n).
+ destruct b; simpl; lia.
+ - exists 0; destruct b;
+ [ apply treeify_zero_rb | apply treeify_one_rb ].
+Qed.
+
+(** The black depth of [treeify l] is actually a log2, but
+ we don't need to mention that. *)
+
+Instance treeify_rb l : Rbt (treeify l).
+Proof.
+ unfold treeify.
+ destruct (treeify_aux_rb (plength l)) as (d,H).
+ exists d.
+ apply H.
+ now rewrite plength_spec.
+Qed.
+
+(** ** Filtering *)
+
+Instance filter_rb f s : Rbt (filter f s).
+Proof.
+ unfold filter; auto_tc.
+Qed.
+
+Instance partition_rb1 f s : Rbt (fst (partition f s)).
+Proof.
+ unfold partition. destruct partition_aux. simpl. auto_tc.
+Qed.
+
+Instance partition_rb2 f s : Rbt (snd (partition f s)).
+Proof.
+ unfold partition. destruct partition_aux. simpl. auto_tc.
+Qed.
+
+(** ** Union, intersection, difference *)
+
+Instance fold_add_rb s1 s2 : Rbt s2 -> Rbt (fold add s1 s2).
+Proof.
+ intros. rewrite fold_spec, <- fold_left_rev_right. unfold elt in *.
+ induction (rev (elements s1)); simpl; unfold flip in *; auto_tc.
+Qed.
+
+Instance fold_remove_rb s1 s2 : Rbt s2 -> Rbt (fold remove s1 s2).
+Proof.
+ intros. rewrite fold_spec, <- fold_left_rev_right. unfold elt in *.
+ induction (rev (elements s1)); simpl; unfold flip in *; auto_tc.
+Qed.
+
+Lemma union_rb s1 s2 : Rbt s1 -> Rbt s2 -> Rbt (union s1 s2).
+Proof.
+ intros. unfold union, linear_union. destruct compare_height; auto_tc.
+Qed.
+
+Lemma inter_rb s1 s2 : Rbt s1 -> Rbt s2 -> Rbt (inter s1 s2).
+Proof.
+ intros. unfold inter, linear_inter. destruct compare_height; auto_tc.
+Qed.
+
+Lemma diff_rb s1 s2 : Rbt s1 -> Rbt s2 -> Rbt (diff s1 s2).
+Proof.
+ intros. unfold diff, linear_diff. destruct compare_height; auto_tc.
+Qed.
+
+End BalanceProps.
+
+(** * Final Encapsulation
+
+ Now, in order to really provide a functor implementing [S], we
+ need to encapsulate everything into a type of binary search trees.
+ They also happen to be well-balanced, but this has no influence
+ on the correctness of operations, so we won't state this here,
+ see [BalanceProps] if you need more than just the MSet interface.
+*)
+
+Module Type MSetInterface_S_Ext := MSetInterface.S <+ MSetRemoveMin.
+
+Module Make (X: Orders.OrderedType) <:
+ MSetInterface_S_Ext with Module E := X.
+ Module Raw. Include MakeRaw X. End Raw.
+ Include MSetInterface.Raw2Sets X Raw.
+
+ Definition opt_ok (x:option (elt * Raw.t)) :=
+ match x with Some (_,s) => Raw.Ok s | None => True end.
+
+ Definition mk_opt_t (x: option (elt * Raw.t))(P: opt_ok x) :
+ option (elt * t) :=
+ match x as o return opt_ok o -> option (elt * t) with
+ | Some (k,s') => fun P : Raw.Ok s' => Some (k, Mkt s')
+ | None => fun _ => None
+ end P.
+
+ Definition remove_min s : option (elt * t) :=
+ mk_opt_t (Raw.remove_min (this s)) (Raw.remove_min_ok s).
+
+ Lemma remove_min_spec1 s x s' :
+ remove_min s = Some (x,s') ->
+ min_elt s = Some x /\ Equal (remove x s) s'.
+ Proof.
+ destruct s as (s,Hs).
+ unfold remove_min, mk_opt_t, min_elt, remove, Equal, In; simpl.
+ generalize (fun x s' => @Raw.remove_min_spec1 s x s' Hs).
+ set (P := Raw.remove_min_ok s). clearbody P.
+ destruct (Raw.remove_min s) as [(x0,s0)|]; try easy.
+ intros H U. injection U. clear U; intros; subst. simpl.
+ destruct (H x s0); auto. subst; intuition.
+ Qed.
+
+ Lemma remove_min_spec2 s : remove_min s = None -> Empty s.
+ Proof.
+ destruct s as (s,Hs).
+ unfold remove_min, mk_opt_t, Empty, In; simpl.
+ generalize (Raw.remove_min_spec2 s).
+ set (P := Raw.remove_min_ok s). clearbody P.
+ destruct (Raw.remove_min s) as [(x0,s0)|]; now intuition.
+ Qed.
+
+End Make.