% ---------------------------------------------------------------------------- %
% heapsort.m
% Ralph Becket <rbeck@microsoft.com>
% Tue Jan 9 14:18:19 GMT 2001
% vim: ts=4 sw=4 et tw=0 wm=0 ff=unix
%
% ---------------------------------------------------------------------------- %
:- module mytest.
:- interface.
:- import_module io.
:- pred main(io__state, io__state).
:- mode main(di, uo) is det.
:- implementation.
:- import_module float, int, array, random, list, string, require.
:- type heap == array(float).
main -->
io__command_line_arguments(ArgV),
( { ArgV = [], N = 1 }
; { ArgV = [Arg], N = string__det_to_int(Arg) }
; { ArgV = [_,_|_], error("usage: heapsort [N]") }
),
{ A = heapsort(N - 1, random_heap(0, seed, array__init(N, 0.0))) },
io__format("%.10f", [f(array__lookup(A, N - 1))]),
io__nl.
:- func random_heap(int, int, heap) = heap.
:- mode random_heap(in, in, array_di) = array_uo is det.
random_heap(I, S0, H0) = H :-
( if I =< array__max(H0) then
gen_random(R, S0, S),
H = random_heap(I + 1, S, up_heap(I, R, H0))
else
H = H0
).
:- func up_heap(int, float, heap) = heap.
:- mode up_heap(in, in, array_di) = array_uo is det.
up_heap(N, Y, H) =
( if 0 < N, X < Y then
up_heap(HalfN, Y, array__set(H, N, X))
else
array__set(H, N, Y)
)
:-
HalfN = N // 2,
X = array__lookup(H, HalfN).
:- func heapsort(int, heap) = heap.
:- mode heapsort(in, array_di) = array_uo is det.
heapsort(N, H) =
( if N = 0 then H else heapsort(N - 1, remove_greatest(N, H)) ).
:- func remove_greatest(int, heap) = heap.
:- mode remove_greatest(in, array_di) = array_uo is det.
remove_greatest(N, H) = down_heap(0, N - 1, Y, array__set(H, N, X)) :-
X = array__lookup(H, 0),
Y = array__lookup(H, N).
:- func down_heap(int, int, float, heap) = heap.
:- mode down_heap(in, in, in, array_di) = array_uo is det.
down_heap(I, N, X, H0) = H :-
L = I + I + 1,
R = L + 1,
( if N < L then
H = array__set(H0, I, X)
else
J = ( if R < N, array__lookup(H0, R) > array__lookup(H0, L) then R
else L ),
Y = array__lookup(H0, J),
( if X > Y then
H = array__set(H0, I, X)
else
H = down_heap(J, N, X, array__set(H0, I, Y))
)
).
:- pred gen_random(float, int, int).
:- mode gen_random(out, in, out) is det.
gen_random(R, S0, S) :-
S = (S0 * ia + ic) `mod` im,
R = float(S) / float(im).
:- func im = int. im = 139968.
:- func ia = int. ia = 3877.
:- func ic = int. ic = 29573.
:- func seed = int. seed = 42.