//
//
// Some dependently typed operations on Braun Trees
//
// Hongwei Xi (hwxi AT cs DOT bu DOT edu)
// October 2008
//

datatype brauntree (a:t@ype, int) =
  | {m:nat} {n:nat | n <= m; m <= n+1}
    Br (a, m+n+1) of (a, brauntree(a, m), brauntree(a, n))
  | Lf (a, 0)

(* ****** ****** *)

extern fun{a:t@ype} brauntree_size
  {n:nat} (t: brauntree (a, n)):<> int n
  
extern fun{a:t@ype} brauntree_get_at
  {n,i:nat | i < n} (t: brauntree (a, n), i: int i):<> a

extern fun{a:t@ype} brauntree_loext
  {n:nat} (t: brauntree (a, n), x0: a):<> brauntree (a, n+1)
   
extern fun{a:t@ype} brauntree_lorem
  {n:pos} (t: brauntree (a, n)):<> brauntree (a, n-1)

(* ****** ****** *)

(*
** The size function is implemented using Okasaki's algorithm:
** its time-complexity is O(log^2 n)
*)

typedef bt (a:t@ype, n: int) = brauntree (a, n)

implement{a}
brauntree_size (t) = size (t) where {
  fun diff {n,k:nat | k <= n && n <= k+1} .<k>. 
    (k: int k, t: bt (a, n)):<> int (n-k) = begin case+ t of
    | Br (_, l, r) => begin
        if k > 0 then
          if k nmod 2 = 1 then diff (k/2, l) else diff (k/2-1, r)
        else 1
      end // end of [Br]
     | Lf () => 0
  end // end of [diff]

  fun size {n:nat} .<n>. (t: bt (a, n)):<> int n = begin
    case+ t of
    | Br (_, l, r) => begin
        let val k = size r in 1 + k + k + diff (k, l) end
      end // end of [Br]
    | Lf () => 0
  end // end of [size]
} // end of [brauntree_size]

(* ****** ****** *)

implement{a}
brauntree_get_at (t, i) = get_at (t, i) where {
  fun get_at {n,i:nat | i < n} .<n>. (t: bt (a, n), i: int i):<> a =
    if i > 0 then let
      val+ Br (_, l, r) = t
    in
      if i nmod 2 = 1 then get_at (l, (i-1)/2) else get_at (r, i/2-1)
    end else let
      val+ Br (x, _, _) = t in x
    end // end of [if]
} // end of [brauntree_get_at]

(* ****** ****** *)

// insertion

implement{a}
brauntree_loext (t, x0) = loext (t, x0) where {
  fun loext {n:nat} .<n>.
    (t: bt (a, n), x0: a):<> bt (a, n+1) = begin
    case+ t of
    | Br (x, l, r) => Br (x0, loext (r, x), l)
    | Lf () => Br (x0, Lf (), Lf ())
  end
} // end of [brauntree_loext]

(* ****** ****** *)

// deletion
  
implement{a}
brauntree_lorem (t) = lorem (t) where {
  fun lorem {n:int | n > 0} .<n>.
    (t: bt (a, n)):<> bt (a, n-1) = let
    val+ Br (_, l, r) = t
  in
    case+ l of Br (x, _, _) => Br (x, r, lorem l) | Lf () => Lf ()
  end
} // end of [brauntree_lorem]

(* ****** ****** *)

(* end of [brauntree-2008-10-02.dats] *)