
module HeapSort

(**** logic declarations *****)
use int.Int
use elements.Elements
use bag.Bag
use bag_of_integers.Bag_integers

use ref.Ref
use array.Array
use array.IntArraySorted
use abstract_heap.AbstractHeap

let rec lemma min_of_sorted (a: int -> int) (i n: int)
   requires { 0 <= i < n }
   requires { M.sorted_sub a 0 n }
   variant  { n }
   ensures  { min_bag (elements a i n) = a i }
 = if n > 0 && i < n - 1 then min_of_sorted a i (n-1)

(* heap sort *)

let heapSort (a : array int)
  requires { length a >= 0 }
  ensures  { sorted a /\
    elements a.elts 0 (length a) =
      elements (old a.elts) 0 (length a) }
= let len = length a in
  let h = create len in

   for i = 0 to len-1 do
    invariant
      { 0 <= i <= len /\
        card (model !h) = i /\
	model !h = elements a.elts 0 i }
  insert h a[i]
  done;

  for i = 0 to len-1 do
   invariant
     { 0 <= i <= len /\
       card (model !h) = len - i /\
       elements (old a.elts) 0 len =
         union (model !h) (elements a.elts 0 i) /\
       sorted_sub a 0 i /\
       forall j:int. 0 <= j < i -> a[j] <= min_bag (model !h)
     }
   a[i] <- extractMin h;
   assert { a[i] <=  min_bag (model !h) }
  done

end
