(** Allocator: returns an address not in the domain of [m].
  This allocator is optimal in that it returns the lowest possible address,
  in the usual ordering on integers. It is not the most efficient, however. *)
  Fixpoint ad_alloc_opt (m:Map A) : ad :=
    match m with
    | M0 => N0
    | M1 a _ => if Neqb a N0 then Npos 1 else N0
    | M2 m1 m2 =>
        Nmin (Ndouble (ad_alloc_opt m1))
          (Ndouble_plus_one (ad_alloc_opt m2))
    end.

(* Specifications: *)
Lemma ad_alloc_opt_allocates_1 : forall m:Map A, MapGet A m (ad_alloc_opt m) = None.
Lemma ad_alloc_opt_allocates : forall m:Map A, in_dom A (ad_alloc_opt m) m = false.
Lemma ad_alloc_opt_optimal_1 : forall (m:Map A) (a:ad), Nleb (ad_alloc_opt m) a = false -> {y : A | MapGet A m a = Some y}.
Lemma ad_alloc_opt_optimal : forall (m:Map A) (a:ad), Nleb (ad_alloc_opt m) a = false -> in_dom A a m = true.