val lemma_sel_upd_other (#a:eqtype) (#b:Type) (m:map a b) (key kx:a) (value:b) : Lemma
  (requires key =!= kx)
  (ensures sel (upd m key value) kx == sel m kx)
  [SMTPat (sel (upd m key value) kx)]
let lemma_sel_upd_other #a #b (Map is_le t _ _) key kx value =
  lemma_get_put_other is_le t key kx value None None
val lemma_sel_upd_other (#a:eqtype) (#b:Type) (m:map a b) (key kx:a) (value:b) : Lemma
  (requires key =!= kx)
  (ensures sel (upd m key value) kx == sel m kx)
  [SMTPat (sel (upd m key value) kx)]
let lemma_sel_upd_other #a #b (Map is_le t _ _) key kx value =
lemma_get_put_other is_le t key kx value None None
Vale.Lib.MapTree.fst.checked
prims.fst.checked FStar.Pervasives.Native.fst.checked FStar.Pervasives.fsti.checked FStar.Mul.fst.checked
Vale.Lib.MapTree.fst
Prims.eqtype Vale.Lib.MapTree.map Prims.bool Vale.Lib.MapTree.tree Prims.squash Prims.l_and Vale.Lib.MapTree.is_cmp Vale.Lib.MapTree.inv FStar.Pervasives.Native.None Vale.Lib.MapTree.lemma_get_put_other Prims.unit
module Vale.Lib.MapTree
open FStar.Mul

(** Balanced tree implementation *)

type tree (a:eqtype) (b:Type) =
  | Empty : tree a b
  | Node : a -> b -> nat -> tree a b -> tree a b -> tree a b

let height (#a:eqtype) (#b:Type) (t:tree a b) : nat =
  match t with
  | Empty -> 0
  | Node _ _ h _ _ -> h

let mkNode (#a:eqtype) (#b:Type) (key:a) (value:b) (l r:tree a b) : tree a b =
  let hl = height l in
  let hr = height r in
  let h = if hl > hr then hl else hr in
  Node key value (h + 1) l r

let rotate_l (#a:eqtype) (#b:Type) (t:tree a b) : tree a b =
  match t with
  | Node kl vl _ l (Node kr vr _ lr rr) -> mkNode kr vr (mkNode kl vl l lr) rr
  | _ -> t

let rotate_r (#a:eqtype) (#b:Type) (t:tree a b) : tree a b =
  match t with
  | Node kr vr _ (Node kl vl _ ll rl) r -> mkNode kl vl ll (mkNode kr vr rl r)
  | _ -> t

let balance (#a:eqtype) (#b:Type) (t:tree a b) : tree a b =
  match t with
  | Node _ _ _ l r ->
    let hl = height l in
    let hr = height r in
    if hl >= hr + 2 then rotate_r t else
    if hr >= hl + 2 then rotate_l t else
    t
  | _ -> t

let rec get (#a:eqtype) (#b:Type) (is_le:a -> a -> bool) (t:tree a b) (key:a) : option b =
  match t with
  | Empty -> None
  | Node k v h l r ->
    if key = k then Some v
    else if is_le key k then
      get is_le l key
    else
      get is_le r key

let rec put (#a:eqtype) (#b:Type) (is_le:a -> a -> bool) (t:tree a b) (key:a) (value:b) : tree a b =
  match t with
  | Empty -> mkNode key value Empty Empty
  | Node k v _ l r ->
    if key = k then mkNode k value l r
    else if is_le key k then
      balance (mkNode k v (put is_le l key value) r)
    else
      balance (mkNode k v l (put is_le r key value))

(** Invariants and proofs of get-put correctness *)

let is_lt_option (#a:eqtype) (is_le:a -> a -> bool) (x y:option a) : bool =
  match (x, y) with
  | (Some x, Some y) -> is_le x y && x <> y
  | _ -> true

let rec inv (#a:eqtype) (#b:Type) (is_le:a -> a -> bool) (t:tree a b) (lo hi:option a) =
  let (<) x y = is_lt_option is_le x y in
  match t with
  | Empty -> True
  | Node x _ _ l r ->
    let x = Some x in
    lo < x /\ x < hi /\ inv is_le l lo x /\ inv is_le r x hi

#push-options "--max_fuel 2 --max_ifuel 1"
let rec lemma_put_inv (#a:eqtype) (#b:Type) (is_le:a -> a -> bool) (t:tree a b) (key:a) (value:b) (lo hi:option a)
  : Lemma
    (requires
      is_cmp is_le /\
      inv is_le t lo hi /\
      is_lt_option is_le lo (Some key) /\
      is_lt_option is_le (Some key) hi
    )
    (ensures inv is_le (put is_le t key value) lo hi)
  =
  match t with
  | Empty -> ()
  | Node k v _ l r ->
    if key = k then ()
    else if is_le key k then
      lemma_put_inv is_le l key value lo (Some k)
    else
      lemma_put_inv is_le r key value (Some k) hi

let rec lemma_get_put_self (#a:eqtype) (#b:Type) (is_le:a -> a -> bool) (t:tree a b) (key:a) (value:b) (lo hi:option a) : Lemma
  (requires is_cmp is_le /\ inv is_le t lo hi)
  (ensures get is_le (put is_le t key value) key == Some value)
  =
  match t with
  | Empty -> ()
  | Node k v _ l r ->
    if key = k then ()
    else if is_le key k then
      lemma_get_put_self is_le l key value lo (Some k)
    else
      lemma_get_put_self is_le r key value (Some k) hi

let rec lemma_get_put_other (#a:eqtype) (#b:Type) (is_le:a -> a -> bool) (t:tree a b) (key kx:a) (value:b) (lo hi:option a)
  : Lemma
    (requires
      is_cmp is_le /\
      inv is_le t lo hi /\
      is_lt_option is_le lo (Some key) /\
      is_lt_option is_le (Some key) hi /\
      key =!= kx
    )
    (ensures get is_le (put is_le t key value) kx == get is_le t kx)
  =
  lemma_put_inv is_le t key value lo hi;
  match t with
  | Empty -> ()
  | Node k v _ l r ->
    if key = k then ()
    else if is_le key k then
      lemma_get_put_other is_le l key kx value lo (Some k)
    else
      lemma_get_put_other is_le r key kx value (Some k) hi
#pop-options

(** Map interface *)

#push-options "--max_fuel 1 --max_ifuel 2"
noeq
type map' (a:eqtype) b =
  | Map :
    is_le:(a -> a -> bool) ->
    t:tree a b ->
    default_v:b ->
    invs:squash (is_cmp is_le /\ inv is_le t None None) ->
    map' a b
#pop-options

let map = map'

let const a b is_le d =
  Map is_le Empty d ()

let sel #a #b (Map is_le t d _) key =
  match get is_le t key with Some v -> v | None -> d

let upd #a #b (Map is_le t d _) key value =
  let t' = put is_le t key value in
  lemma_put_inv is_le t key value None None;
  Map is_le t' d ()

let lemma_const a b is_le d key =
  ()

let lemma_sel_upd_self #a #b (Map is_le t _ _) key value =
  lemma_get_put_self is_le t key value None None
val lemma_sel_upd_other (#a:eqtype) (#b:Type) (m:map a b) (key kx:a) (value:b) : Lemma
  (requires key =!= kx)
  (ensures sel (upd m key value) kx == sel m kx)
  [SMTPat (sel (upd m key value) kx)]
m: Vale.Lib.MapTree.map a b -> key: a -> kx: a -> value: b
  -> FStar.Pervasives.Lemma (requires ~(key == kx))
      (ensures
        Vale.Lib.MapTree.sel (Vale.Lib.MapTree.upd m key value) kx == Vale.Lib.MapTree.sel m kx)
      [SMTPat (Vale.Lib.MapTree.sel (Vale.Lib.MapTree.upd m key value) kx)]