-
Notifications
You must be signed in to change notification settings - Fork 0
/
array-kmed.timl
74 lines (67 loc) · 2.91 KB
/
array-kmed.timl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
(* K-median search *)
structure ArrayKthMedian = struct
open Basic
open Nat
open Array
datatype nat_less_equal_than {n : Nat} =
NatLE {m : Nat} {m <= n} of nat {m} --> nat_less_equal_than {n}
fun swap ['a] {len i j : Nat} {i < len} {j < len} (a : array 'a {len}, i : nat {i}, j : nat {j}) =
let
val tmp = sub (a, i)
val () = update (a, i, sub (a, j))
val () = update (a, j, tmp)
in
()
end
(* big-O inference fails for this function so a precise bound is given *)
idx T_array_pivot_on_range = fn m n => 23.0 * ($m + 1.0) * $n + 8.0
fun array_pivot_on_range ['a] {m len l n : Nat} {l + n <= len} (le : 'a * 'a -- $m --> bool) (a : array 'a {len}, l : nat {l}, n : nat {n}, x : 'a) return nat_less_equal_than {n} using T_array_pivot_on_range m n =
case Nat.le (n, #0) return using (T_array_pivot_on_range m n) - 8.0 of
Le => NatLE #0
| Gt =>
let
val n' = nat_minus (n, #1)
val who = nat_plus (l, n')
val ele = sub (a, who)
in
if le (ele, x) then
let
val () = swap (a, l, who)
in
case array_pivot_on_range le (a, nat_plus (l, #1), n', x) of
NatLE p => NatLE p
end
else
case array_pivot_on_range le (a, l, n', x) of
NatLE p => NatLE (nat_plus (p, #1))
end
(* big-O inference fails for this function so a precise bound is given *)
idx T_array_kth_median_on_range = fn m n => 48.0 * ($m + 1.0) * $n * $n + 8.0
fun array_kth_median_on_range ['a] {m len l n k : Nat} {l + n <= len} {1 <= k} {k <= n} (le : 'a * 'a -- $m --> bool) (a : array 'a {len}, l : nat {l}, n : nat {n}, k : nat {k}) return 'a using T_array_kth_median_on_range m n =
case Nat.le (n, #0) return using (T_array_kth_median_on_range m n - 8.0) of
Le => never
| Gt =>
let
val x = sub (a, l)
val res = array_pivot_on_range le (a, nat_plus (l, #1), nat_minus (n, #1), x)
in
case res of
NatLE gtc =>
let
val rank = nat_plus (gtc, #1)
in
case cmp (rank, k) of
Equal => x
| Less =>
let
val () = swap (a, l, nat_plus (l, nat_minus (n, rank)))
in
(* here we need local time annotation to forget a local index variable *)
array_kth_median_on_range le (a, l, nat_minus (n, rank), nat_minus (k, rank)) using (T_array_kth_median_on_range m (n - 1)) + 6.0
end
| Greater =>
(* here we need local time annotation to forget a local index variable *)
array_kth_median_on_range le (a, nat_plus (l, nat_minus (n, gtc)), gtc, k) using (T_array_kth_median_on_range m (n - 1)) + 6.0
end
end
end