
(*
  ``Same fringe'' is a famous problem.
  Given two binary search trees, you must decide whether they contain the
  same elements. See for instance http://www.c2.com/cgi/wiki?SameFringeProblem
*)

module SameFringe

  use int.Int
  use list.List
  use list.Length
  use list.Append

  (* binary trees with elements at the nodes *)

  type elt

  val eq (x y: elt) : bool ensures { result <-> x=y }

  type tree =
    | Empty
    | Node tree elt tree

  function elements (t : tree) : list elt = match t with
    | Empty -> Nil
    | Node l x r -> elements l ++ Cons x (elements r)
  end

  (* the left spine of a tree, as a bottom-up list *)

  type enum =
    | Done
    | Next elt tree enum

  function enum_elements (e : enum) : list elt = match e with
    | Done -> Nil
    | Next x r e -> Cons x (elements r ++ enum_elements e)
  end

  (* the enum of a tree [t], prepended to a given enum [e] *)

  let rec enum t e variant { t }
    ensures { enum_elements result = elements t ++ enum_elements e }
  = match t with
    | Empty -> e
    | Node l x r -> enum l (Next x r e)
    end

  let rec eq_enum e1 e2 variant { length (enum_elements e1) }
    ensures { result=True <-> enum_elements e1 = enum_elements e2 }
  = match e1, e2 with
    | Done, Done ->
        True
    | Next x1 r1 e1, Next x2 r2 e2 ->
        eq x1 x2 && eq_enum (enum r1 e1) (enum r2 e2)
    | _ ->
        False
    end

  let same_fringe t1 t2
    ensures { result=True <-> elements t1 = elements t2 }
  = eq_enum (enum t1 Done) (enum t2 Done)

  let test1 () = enum Empty Done
  let test2 () = eq_enum Done Done
  let test3 () = same_fringe Empty Empty

  val constant a : elt
  val constant b : elt

  let leaf x = Node Empty x Empty

  let test4 () = same_fringe (Node (leaf a) b Empty) (Node Empty a (leaf b))
  let test5 () = same_fringe (Node (leaf a) b Empty) (Node Empty b (leaf a))

  exception BenchFailure

  let bench () raises { BenchFailure -> true } =
    if not (test4 ()) then raise BenchFailure

end

module Test

  use int.Int
  clone SameFringe with type elt = int

  let test1 () = enum Empty Done
  let test2 () = eq_enum Done Done
  let test3 () = same_fringe Empty Empty

  constant a : int = 1
  constant b : int = 2

  let leaf x = Node Empty x Empty

  let test4 () = same_fringe (Node (leaf a) b Empty) (Node Empty a (leaf b))
  let test5 () = same_fringe (Node (leaf a) b Empty) (Node Empty b (leaf a))

end
