2 (** {1 Sorting an array of integers using quicksort} *)
4 (** {2 with a partitioning a la Bentley} *)
11 use array.IntArraySorted
16 predicate qs_partition (a1 a2: array int) (l m r: int) (v: int) =
17 permut_sub a1 a2 l r /\
18 (forall j: int. l <= j < m -> a2[j] < v) /\
19 (forall j: int. m < j < r -> v <= a2[j]) /\
22 (* partitioning à la Bentley, that is
25 +-+----------+----------+----------+
27 +-+----------+----------+----------+ *)
29 let rec quick_rec (a: array int) (l: int) (r: int) : unit
30 requires { 0 <= l <= r <= length a }
31 ensures { sorted_sub a l r }
32 ensures { permut_sub (old a) a l r }
34 = if l + 1 < r then begin
38 for i = l + 1 to r - 1 do
39 invariant { a[l] = v /\ l <= !m < i }
40 invariant { forall j:int. l < j <= !m -> a[j] < v }
41 invariant { forall j:int. !m < j < i -> a[j] >= v }
42 invariant { permut_sub (a at L) a l r }
44 if a[i] < v then begin
47 assert { permut_sub (a at K) a l r }
52 assert { qs_partition (a at M) a l !m r v };
55 assert { qs_partition (a at N) a l !m r v };
57 quick_rec a (!m + 1) r;
58 assert { qs_partition (a at O) a l !m r v };
59 assert { qs_partition (a at N) a l !m r v };
62 let quicksort (a: array int) =
64 ensures { permut_all (old a) a }
65 quick_rec a 0 (length a)
69 (** {2 Knuth's shuffle}
71 A realistic quicksort first shuffles the array. *)
81 let shuffle (a: array int) : unit
82 writes { a, Random.s }
83 ensures { permut_all (old a) a }
84 = for i = 1 to length a - 1 do
85 invariant { permut_all (old a) a }
86 swap a i (Random.random_int (i+1))
92 module QuicksortWithShuffle
95 use array.IntArraySorted
100 let qs (a: array int) : unit =
102 ensures { permut_all (old a) a }
108 (** {2 with 3-way partitioning}
110 A realistic quicksort also has to use 3-way partitioning, to cope
111 with arrays were many values are identical. *)
118 use array.IntArraySorted
120 use array.ArrayPermut
123 predicate qs_partition (a1 a2: array int) (l ml mr r: int) (v: int) =
124 permut_sub a1 a2 l r /\
125 (forall j: int. l <= j < ml -> a2[j] < v) /\
126 (forall j: int. ml <= j < mr -> a2[j] = v) /\
127 (forall j: int. mr <= j < r -> a2[j] > v)
129 (* 3-way partitioning
132 +----------+----------+----------+-----------+
133 | < v | = v | ? | > v |
134 +----------+----------+----------+-----------+ *)
136 let rec quick_rec (a: array int) (l r: int) : unit
137 requires { 0 <= l <= r <= length a }
138 ensures { sorted_sub a l r }
139 ensures { permut_sub (old a) a l r }
141 = if l + 1 < r then begin
145 let i = ref (l + 1) in
148 invariant { l <= !ml < !i <= !mr <= r }
149 invariant { forall j: int. l <= j < !ml -> a[j] < v }
150 invariant { forall j: int. !ml <= j < !i -> a[j] = v }
151 invariant { forall j: int. !mr <= j < r -> a[j] > v }
152 invariant { permut_sub (a at L) a l r }
155 if a[!i] < v then begin
159 assert { permut_sub (a at K) a l r }
160 end else if a[!i] > v then begin
163 assert { permut_sub (a at K) a l r }
167 assert { qs_partition (a at L) a l !ml !mr r v };
170 assert { qs_partition (a at N) a l !ml !mr r v };
173 assert { qs_partition (a at O) a l !ml !mr r v };
174 assert { qs_partition (a at N) a l !ml !mr r v }
177 let quicksort (a: array int) =
179 ensures { permut_all (old a) a }
180 quick_rec a 0 (length a)
184 let qs (a: array int) : unit =
186 ensures { permut_all (old a) a }
200 a[0] <- 7; a[1] <- 3; a[2] <- 1;
204 let test2 () ensures { result.length = 8 } =
206 a[0] <- 53; a[1] <- 91; a[2] <- 17; a[3] <- -5;
207 a[4] <- 413; a[5] <- 42; a[6] <- 69; a[7] <- 6;
211 exception BenchFailure
213 let bench () raises { BenchFailure -> true } =
215 if a[0] <> -5 then raise BenchFailure;
216 if a[1] <> 6 then raise BenchFailure;
217 if a[2] <> 17 then raise BenchFailure;
218 if a[3] <> 42 then raise BenchFailure;
219 if a[4] <> 53 then raise BenchFailure;
220 if a[5] <> 69 then raise BenchFailure;
221 if a[6] <> 91 then raise BenchFailure;
222 if a[7] <> 413 then raise BenchFailure;
232 use array.IntArraySorted
234 use array.ArrayPermut
237 let rec quick_rec (a: array int) (l: int) (r: int) : unit
238 requires { 0 <= l <= r <= length a }
239 ensures { sorted_sub a l r }
240 ensures { permut_sub (old a) a l r }
242 = if l + 1 >= r then return;
247 invariant { l <= i < r-1 }
248 invariant { forall k. l <= k <= i -> a[k] <= v }
249 invariant { l < j <= r }
250 invariant { forall k. j <= k < r -> a[k] >= v }
251 invariant { permut_sub (old a) a l r }
252 invariant { a[l] = v }
255 (* while (a[++i] < v) { if (i == r-1) break; } *)
258 invariant { i at L < i < r }
259 invariant { forall k. l <= k < i -> a[k] <= v }
261 if i = r - 1 then break;
264 (* while (v < a[--j]) { if (j == l) break; } *)
267 invariant { l <= j < j at L }
268 invariant { forall k. j < k < r -> a[k] >= v }
273 if i >= j then break;
280 let quicksort (a: array int) : unit
282 ensures { permut_all (old a) a }
283 = (* insert a call to shuffle here if you wish *)
284 quick_rec a 0 (length a)