Fixpoint revsize (n: positive) (lr l: list key) : positive * list key :=
 match l with
 | nil => (n, lr)
 | x::xs => revsize (Psucc n) (x::lr) xs
 end.Function linear_union_aux (st : tree*tree) (nl: positive * list key)
   {measure (fun st => size (fst st) + size (snd st)) st} : positive * list key  :=
 match rgopher (fst st), rgopher (snd st) with
 | EE , EE => nl
 | T _ sl j EE as st1 , T _ tl j' EE as st2 =>
    match K.compare j j' with
    | Lt => linear_union_aux (st1, tl) (Psucc (fst nl), j':: snd nl)
    | Gt => linear_union_aux (sl, st2) (Psucc (fst nl), j:: snd nl)
    | Eq => linear_union_aux (sl,tl) (Psucc (fst nl), j:: snd nl)
    end
 | T _ sl j EE, EE => linear_union_aux (sl,EE) (Psucc (fst nl), j:: snd nl)
 |  EE, T _ tl j' EE => linear_union_aux (EE,tl) (Psucc (fst nl), j':: snd nl)
 | _, _ => nl (* impossible *)
 end.Definition linear_union (s1 s2 : tree) : tree :=
  let (n,l) := linear_union_aux (s1,s2) (1%positive, nil)
   in fst (treeify_g n l).Function linear_diff_aux (st : tree*tree) (nl: positive * list key)
   {measure (fun st => size (fst st) + size (snd st)) st} : positive * list key  :=
 match rgopher (fst st), rgopher (snd st) with
 | EE , _ => nl
 | T _ sl j EE as st1 , T _ tl j' EE as st2 =>
    match K.compare j j' with
    | Lt => linear_diff_aux (st1, tl) nl
    | Gt => linear_diff_aux (sl, st2) (Psucc (fst nl), j:: snd nl)
    | Eq => linear_diff_aux (sl,tl) nl
    end
 | T _ sl j EE, EE => linear_diff_aux (sl,EE) (Psucc (fst nl), j:: snd nl)
 | _, _ => nl (* impossible *)
 end.Definition linear_diff (s1 s2 : tree) : tree :=
  let (n,l) := linear_diff_aux (s1,s2) (1%positive, nil)
   in fst (treeify_g n l).Fixpoint fold' (A: Type) (f: key -> A -> A) (x: tree) (base: A) : A :=
  match x with
  | EE => base
  | T _ t1 k t2 => fold' A f t2 (f k (fold' A f t1 base))
 end.Definition skip_red t :=
 match t with
 | T Red t' _ _ => t'
 | _ => t
 end.Definition skip_black t :=
  match skip_red t with
  | T Black t' _ _ => t'
  | t' => t'
  end.(* compare_height returns Lt if height(s2) is at least twice height(s1);
  returns Gt if height(s1) is at least twice height (s2);
  returns Eq if heights are approximately equal.
  Warning: this is not an equivalence relation!  but who cares....
*)
Fixpoint compare_height (s1x s1 s2 s2x: tree) : comparison :=
 match skip_red s1x, skip_red s1, skip_red s2, skip_red s2x with
 | T _ s1x' _ _, T _ s1' _ _, T _ s2' _ _, T _ s2x' _ _ =>
        compare_height (skip_black s2x') s1' s2' (skip_black s2x')
 | _, EE, _, T _ _ _ _ => Lt
 | T _ _ _ _, _, EE, _ => Gt
 | T _ s1x' _ _, T _ s1' _ _, T _ s2' _ _, EE =>
        compare_height (skip_black s1x') s1' s2' EE
 | EE, T _ s1' _ _, T _ s2' _ _, T _ s2x' _ _ =>
        compare_height EE s1'  s2'  (skip_black s2x')
 | _, _, _, _ => Eq
 end.Function linear_inter_aux (st : tree*tree) (nl: positive * list key)
   {measure (fun st => size (fst st) + size (snd st)) st} : positive * list key  :=
 match rgopher (fst st), rgopher (snd st) with
 | T _ sl j EE as st1, T _ tl j' EE as st2 =>
    match K.compare j j' with
    | Lt => linear_inter_aux (st1, tl) nl
    | Gt => linear_inter_aux (sl, st2) nl
    | Eq => linear_inter_aux (sl,tl) (Psucc (fst nl), j:: snd nl)
    end
 | _, _ => nl
 end.Definition linear_inter (s1 s2 : tree) : tree :=
  let (n,l) := linear_inter_aux (s1,s2) (1%positive,nil)
   in fst (treeify_g n l).Fixpoint plog2 (p: positive) : nat :=
 match p with
 | xH => O
 | xO n => S (plog2 n)
 | xI n => S (plog2 n)
 end.

(* Specifications: *)
Lemma nat_of_P_pos: forall n, nat_of_P n > 0.
Lemma nat_of_P_pospos: forall n, n<>1%positive -> nat_of_P n > 1.
Lemma treeify_f_length: forall n l, length l >= nat_of_P n -> length(snd(treeify_f n l))+nat_of_P n = length l.