(* Since posMap is a dictionary, we need to have a sortedness notation over a dictionary  *)
  Definition sortedDict (dict: list (nat * nat)) := forall i j k1 v1 k2 v2,
      i < j ->
      nth_error dict i = Some (k1, v1) ->
      nth_error dict j = Some (k2, v2) ->
      k1 = i /\ k2 = j.Fixpoint fixedSlots (rt: PBTree (list BlockEntry)) (sz : nat) : Prop :=
    match rt with
    | Leaf _  idx val  => (List.length val) = sz
    | Node _ idx val lc rc => (List.length val) = sz /\
                               (fixedSlots lc sz) /\
                               (fixedSlots rc sz)
    end.Definition posMapSimplInit (posMap : list(nat * nat)) (memSize : nat) := List.length(posMap) = memSize /\ (sortedDict posMap).(* TODO: show PathORAM satisfies the invariant before an access and also show that it satisfies the invariant after an access.  *)

  Fixpoint In_BlEntry (lbe : list BlockEntry) (key : nat) : Prop :=
    match lbe with
    | [] => False
    | BV k v :: t => k = key \/ In_BlEntry t key 
    end.Fixpoint In_PBTree (rt : PBTree(list BlockEntry)) (key : nat) : Prop :=
    match rt with
    | Leaf _ idx val => idx = key \/ False
    | Node _ idx val lc rc =>
        idx = key \/ In_PBTree lc key \/
          In_PBTree rc key
    end.(* Print xorb. *)

  (* Inductive xxor : Prop -> Prop -> Prop := *)
  (* | f_f (x y : Prop): ~x -> ~y -> xxor x y *)
  (* | f_t (x y : Prop): ~x -> y -> xxor x y *)
  (* | t_f(x y : Prop): x -> ~y -> xxor x y *)
  (* | t_t (x y : Prop): x -> y -> xxor x y. *)
                                 
  (* Definition invariant (stsh: list BlockEntry) (rt: PBTree (list BlockEntry)) (memSz : nat) := *)
  (*   forall i, O <= i < memSz -> xxor (In_BlEntry stsh i) (In_PBTree rt i). *)


  Fixpoint counting_begin (begin : nat) (lnat : list nat) : bool :=
    match lnat with
    | [] => true
    | h :: t => if Nat.eqb begin h
              then (counting_begin (S begin) t)
              else false 
    end.Fixpoint count_lst (lnat : list nat) : bool :=
    match lnat with
    | [] => true
    | h :: t => (counting_begin h lnat)
    end.(* get the list of block ids that live in the stash or a given path *) 
  
  Definition getBlockIdsFromBELst (belst : list BlockEntry) : list nat :=
    List.map BlockEntry_fst belst.Fixpoint getBlockIdsFromPath (rt: PBTree (list BlockEntry)) (l : list nat) : list nat := 
    match l with
    | [] => []
    | h :: t => match rt with
              | Leaf _ idx val =>
                  if Nat.eqb h idx
                  then getBlockIdsFromBELst val
                  else getBlockIdsFromPath rt t
              | Node _ idx val lc rc =>
                  if Nat.eqb h idx
                  then (getBlockIdsFromBELst val) ++ (getBlockIdsFromPath lc t) ++
                                                  (getBlockIdsFromPath rc t)
                  else (getBlockIdsFromPath lc t) ++ (getBlockIdsFromPath rc t)
              end
    end.Definition caterpillar (BId_stsh : list nat) (BId_path : list nat) : Prop :=
    NoDup (NatSort.sort (BId_stsh ++ BId_path)).Definition isLeafNode (n : nat) (rt : PBTree (list BlockEntry)) : Prop :=
    let l := (getHeight rt) in
    (ge n (2^(l - 1))) /\ (le n (2^l - 1)).Definition init_invariant
             (s: st_rand) (memSz : nat): Prop :=
    match s with
    | (strm, (stsh, rt)) => 
        forall bId posMap,
          bId < memSz ->
          (exists x, (isLeafNode x rt ->
                 In bId (getBlockIdsFromPath rt (getPath' x)) \/
                   (In bId (getBlockIdsFromBELst stsh))) /\
                  (posMapLookUp bId posMap = (Some x)))
    end.Fixpoint insert {X} (x : X) (xs : list X) (n : nat) :=
    match xs with
    | [] => [x]
    | y :: ys =>
        match n with
        | O => x :: xs
        | S m => y :: insert x ys m
        end
    end.Inductive parts_into {X} : list X -> list X -> list X -> Prop :=
  | part_nil : parts_into [] [] []
  | parts_cons_l {xs zs} {x} i ys :
    parts_into xs ys zs ->
    parts_into (x :: xs) (insert x ys i) zs
  | parts_cons_r {xs ys} {x} i zs :
    parts_into xs ys zs ->
    parts_into (x :: xs) ys (insert x zs i).Inductive parts_into {X} : list X -> list X -> list X -> Prop :=
  | part_nil : parts_into [] [] []
  | parts_cons_l {xs zs} {x} i ys :
    parts_into xs ys zs ->
    parts_into (x :: xs) (insert x ys i) zs
  | parts_cons_r {xs ys} {x} i zs :
    parts_into xs ys zs ->
    parts_into (x :: xs) ys (insert x zs i).Inductive parts_into {X} : list X -> list X -> list X -> Prop :=
  | part_nil : parts_into [] [] []
  | parts_cons_l {xs zs} {x} i ys :
    parts_into xs ys zs ->
    parts_into (x :: xs) (insert x ys i) zs
  | parts_cons_r {xs ys} {x} i zs :
    parts_into xs ys zs ->
    parts_into (x :: xs) ys (insert x zs i).Inductive parts_into {X} : list X -> list X -> list X -> Prop :=
  | part_nil : parts_into [] [] []
  | parts_cons_l {xs zs} {x} i ys :
    parts_into xs ys zs ->
    parts_into (x :: xs) (insert x ys i) zs
  | parts_cons_r {xs ys} {x} i zs :
    parts_into xs ys zs ->
    parts_into (x :: xs) ys (insert x zs i).Goal parts_into [1;2;3;4;5] [5;2] [1;4;3].

Lemma inListPartition: forall {A} (a b c: list A) x, In x a \/ In x (b ++ c) -> In x (a ++ b) \/ In x c.