//
// Course: BU CAS CS 520, Fall 2009
// Instructor: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
//

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

datasort bt = btcons of (bt, bt) | btnil of ()

dataprop SZ (bt, int) =
  | SZnil (btnil, 0)
  | {t1,t2:bt} {s1,s2:nat}
    SZcons (btcons (t1, t2), 1+s1+s2) of (SZ (t1, s1), SZ (t2, s2))
// end of [SZ]

dataprop HT (bt, int) =
  | HTnil (btnil, 0)
  | {t1,t2:bt} {h1,h2:nat}
    HTcons (btcons (t1, t2), 1+max(h1,h2)) of (HT (t1, h1), HT (t2, h2))
// end of [HT]

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

dataprop POW2 (int, int) =
  | POW2bas (0, 1)
  | {n:nat} {p:nat} POW2ind (n+1, 2*p) of POW2 (n, p)
// end of [POW2]

// POW2 is total (w.r.t. its first argument)
prfun pow2_istot {n:nat} .<n>. (): [p:nat] POW2 (n, p) =
  sif n > 0 then POW2ind (pow2_istot {n-1} ()) else POW2bas ()
// end of [pow2_istot]

// POW2 is a functional relation
prfun pow2_isfun {n:nat} {p1,p2:int} .<n>.
  (pf1: POW2 (n, p1), pf2: POW2 (n, p2)): [p1==p2] void =
  case+ (pf1, pf2) of
  | (POW2ind pf1, POW2ind pf2) => pow2_isfun (pf1, pf2)
  | (POW2bas (), POW2bas ()) => ()
// end of [pow2_isfun]  

// pow2 is an increasing function
prfun pow2_isinc {n1,n2:nat | n1 <= n2}
  {p1,p2:int} .<n2>. (pf1: POW2 (n1, p1), pf2: POW2 (n2, p2)): [p1 <= p2] void =
  sif n1 < n2 then let
    prval POW2ind pf20 = pf2
    prval () = pow2_isinc (pf1, pf20)
  in
    // nothing
  end else let
    prval () = pow2_isfun (pf1, pf2)
  in
    // nothing
  end // end of [sif]
// end of [pow2_isinc]

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

prfun lemma_SZ_HT {t:bt} {s,h,p:int} .<t>.
  (pf1: SZ (t, s), pf2: HT (t, h), pf3: POW2 (h, p)): [s < p] void =
  case+ pf1 of
  | SZnil () => let
      prval HTnil () = pf2
      prval POW2bas () = pf3
    in
      // nothing
    end // end of [SZnil]
  | SZcons (pf11, pf12) => let
      // t = btcons (t1, t2); pf11: SZ (t1, s1), pf12: SZ (t2, s2)
      prval HTcons {t1,t2} {h1,h2} (pf21, pf22) = pf2 // pf21: HT (t1, h1), HT (t2, h2)
      prval POW2ind (pf30) = pf3
      prval [p1:int] pf31 = pow2_istot {h1} () // pf32: POW2 (h1, p1)
      prval () = lemma_SZ_HT (pf11, pf21, pf31)
      prval [p2:int] pf32 = pow2_istot {h2} () // pf32: POW2 (h2, p2)
      prval () = lemma_SZ_HT (pf12, pf22, pf32)
      prval () = pow2_isinc (pf31, pf30)
      prval () = pow2_isinc (pf32, pf30)
    in
      // nothing
    end // end of [SZcons]
// end of [lemma_SZ_HT]

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

(* end of [tree.dats] *)