4 We sort an array of integers, assuming all elements are in the range 0..k-1
6 We simply count the elements equal to x, for each
7 x in 0..k-1, and then (re)fill the array with two nested loops.
9 TODO: Implement and prove a *stable* variant of counting sort,
12 Introduction to Algorithms
13 Cormen, Leiserson, Rivest
14 The MIT Press (2nd edition)
22 use export array.Array
23 use export array.IntArraySorted
25 (* values of the array are in the range 0..k-1 *)
27 ensures { 0 < result }
29 predicate k_values (a: array int) =
30 forall i: int. 0 <= i < length a -> 0 <= a[i] < k
32 (* we introduce two predicates:
33 - [numeq a v l u] is the number of values in a[l..u[ equal to v
34 - [numlt a v l u] is the number of values in a[l..u[ less than v *)
35 function numeq (a: array int) (v i j : int) : int =
36 N.numof (fun k -> a[k] = v) i j
38 function numlt (a: array int) (v i j : int) : int =
39 N.numof (fun k -> a[k] < v) i j
41 (* an ovious lemma relates numeq and numlt *)
42 let rec lemma eqlt (a: array int) (v: int) (l u: int)
43 requires { k_values a }
44 requires { 0 <= v < k }
45 requires { 0 <= l < u <= length a }
46 ensures { numlt a v l u + numeq a v l u = numlt a (v+1) l u }
48 = if l < u-1 then eqlt a v (l+1) u
50 (* permutation of two arrays is here conveniently defined using [numeq]
51 i.e. as the equality of the two multi-sets *)
52 predicate permut (a b: array int) =
53 length a = length b /\
54 forall v: int. 0 <= v < k -> numeq a v 0 (length a) = numeq b v 0 (length b)
63 (* sorts array a into array b *)
64 let counting_sort (a: array int) (b: array int)
65 requires { k_values a /\ length a = length b }
66 ensures { sorted b /\ permut a b }
67 = let c = Array.make k 0 in
68 for i = 0 to length a - 1 do
69 invariant { forall v: int. 0 <= v < k -> c[v] = numeq a v 0 i }
75 invariant { !j = numlt a v 0 (length a) }
76 invariant { sorted_sub b 0 !j }
77 invariant { forall e: int. 0 <= e < !j -> 0 <= b[e] < v }
78 invariant { forall f: int.
79 0 <= f < v -> numeq b f 0 !j = numeq a f 0 (length a) }
81 invariant { !j -i+1 = numlt a v 0 (length a) }
82 invariant { sorted_sub b 0 !j }
83 invariant { forall e: int. 0 <= e < !j -> 0 <= b[e] <= v }
84 invariant { forall f: int.
85 0 <= f < v -> numeq b f 0 !j = numeq a f 0 (length a) }
86 invariant { numeq b v 0 !j = i-1 }
91 assert { !j = length b }
95 module InPlaceCountingSort
100 (* sorts array a in place *)
101 let in_place_counting_sort (a: array int)
102 requires { k_values a }
103 ensures { sorted a /\ permut (old a) a }
104 = let c = make k 0 in
105 for i = 0 to length a - 1 do
106 invariant { forall v: int. 0 <= v < k -> c[v] = numeq a v 0 i }
112 invariant { !j = numlt (old a) v 0 (length a) }
113 invariant { sorted_sub a 0 !j }
114 invariant { forall e: int. 0 <= e < !j -> 0 <= a[e] < v }
115 invariant { forall f: int.
116 0 <= f < v -> numeq a f 0 !j = numeq (old a) f 0 (length a) }
118 invariant { !j -i+1 = numlt (old a) v 0 (length a) }
119 invariant { sorted_sub a 0 !j }
120 invariant { forall e: int. 0 <= e < !j -> 0 <= a[e] <= v }
121 invariant { forall f: int.
122 0 <= f < v -> numeq a f 0 !j = numeq (old a) f 0 (length a) }
123 invariant { numeq a v 0 !j = i-1 }
126 assert {forall f. 0 <= f < v -> numeq a f 0 !j = numeq a f 0 (!j - 1)}
129 assert { !j = length a }
136 use InPlaceCountingSort
143 in_place_counting_sort a;
144 (* a is now [0;0;1] *)
145 assert { numeq a 0 0 3 = 2 };
146 assert { numeq a 1 0 3 = 1 };