8
We consider an example of how to write an in-situ quicksort function in
9
ACL2. For efficiency, we would like to use a common store which holds the array
10
we are sorting in place. This leads us to write a quicksort using stobjs. Our
11
spec is the standard insertion sort, and we would like to prove that the
12
quicksort produces the same answer as the insertion sort.
14
The present version has been updated from the original 2002 ACL2 Workshop
15
supporting materials to incorporate stobjs inlining.
19
(set-verify-guards-eagerness 1)
21
(include-book "total-order")
22
(include-book "nth-update-nth")
23
(include-book "arithmetic/top-with-meta" :dir :system)
25
;(defthm natp-compound-recognizer
29
; :rule-classes :compound-recognizer)
31
(in-theory (disable natp))
34
(defthm len-resize-list
35
(equal (len (resize-list l n d))
38
;; The store just has one field: objs
41
(objs :type (array T (0))
47
(defthm objsp-is-true-listp
48
(equal (objsp x) (true-listp x))))
50
(defthm nth-update-nth-diff-objsi
51
(implies (not (equal (nfix n) (nfix m)))
52
(equal (objsi n (update-objsi m v l)) (objsi n l))))
54
(defthm nth-update-nth-same-objsi
55
(implies (equal (nfix n) (nfix m))
56
(equal (objsi n (update-objsi m v l)) v)))
58
(defthm update-nth-update-nth-same-objsi
59
(equal (update-objsi n v (update-objsi n x l))
60
(update-objsi n v l)))
62
(defthm update-nth-update-nth-diff-objsi
63
(implies (not (equal (nfix n) (nfix m)))
64
(equal (update-objsi n v (update-objsi m x l))
65
(update-objsi m x (update-objsi n v l))))
66
:rule-classes ((:rewrite :loop-stopper ((n m)))))
68
(in-theory (disable objsi update-objsi))
70
(defun alloc-qs (N qstor)
71
(declare (xargs :stobjs qstor))
72
(resize-objs N qstor))
75
(defthm alloc-qs-qstorp
77
(qstorp (alloc-qs N qs)))))
80
(defthm objs-length-alloc-qs
81
(equal (objs-length (alloc-qs N qs))
85
(defthm objs-length-update-objs
86
(equal (len (nth 0 (update-objsi m x l)))
87
(len (update-nth m x (nth 0 l))))
88
:hints (("Goal" :in-theory (enable update-objsi)))))
90
(defun load-qs (x lo N qstor)
91
(declare (xargs :guard (and (true-listp x)
98
(let ((qstor (update-objsi lo (first x) qstor)))
99
(load-qs (rest x) (1+ lo) (1- N) qstor))))
102
(defthm load-qs-qstorp
104
(qstorp (load-qs x i N qs)))
105
:hints (("Goal" :in-theory (enable update-objsi)))))
108
(defthm load-qs-objs-length
109
(implies (and (natp i)
111
(<= (+ i N) (objs-length qs)))
112
(= (objs-length (load-qs x i N qs))
114
:hints (("Goal" :in-theory (enable update-objsi)))))
116
(defun extract-qs (lo hi qstor)
117
(declare (xargs :guard (and (natp lo)
119
(< hi (objs-length qstor)))
121
:measure (nfix (1+ (- hi lo)))))
125
(cons (objsi lo qstor)
126
(extract-qs (1+ lo) hi qstor))
129
(defun swap (i j qstor)
130
(declare (xargs :guard (and (natp i)
132
(< i (objs-length qstor))
133
(< j (objs-length qstor)))
135
(let* ((temp (objsi i qstor))
136
(qstor (update-objsi i (objsi j qstor) qstor))
137
(qstor (update-objsi j temp qstor)))
141
(defthm swap-preserves-qstorp
143
(qstorp (swap i j qs)))
144
:hints (("Goal" :in-theory (enable update-objsi)))))
147
(defthm swap-preserves-objs-length
148
(implies (and (natp i)
150
(< i (objs-length qs))
151
(< j (objs-length qs)))
152
(= (objs-length (swap i j qs))
154
:hints (("Goal" :in-theory (enable update-objsi)))))
157
(in-theory (disable alloc-qs swap qstorp objs-length)))
160
(declare (xargs :guard t))
167
(declare (xargs :guard t))
175
(defun split-qs (lo hi splitter qstor)
176
(declare (xargs :guard (and (integerp lo)
178
(<= lo (objs-length qstor))
179
(< hi (objs-length qstor)))
181
:measure (nfix (1+ (- hi lo)))))
184
(let* ((swap-lo (<<= splitter (objsi lo qstor)))
185
(swap-hi (<< (objsi hi qstor) splitter))
186
(qstor (if (and swap-lo swap-hi)
189
(split-qs (if (implies swap-lo swap-hi)
192
(if (implies swap-hi swap-lo)
198
(defthm qstorp-split-qs
200
(qstorp (cadr (split-qs lo hi x qs))))))
203
(defthm objs-length-split-qs
204
(implies (and (natp lo)
206
(<= lo (objs-length qs))
207
(< hi (objs-length qs)))
208
(= (objs-length (cadr (split-qs lo hi x qs)))
211
;; I do not like to write defthms in the middle of function definitions, but I
212
;; do it here, simply because the sort-qs function defined soon below is a pain in
213
;; the butt to go thru....
216
(in-theory (enable alloc-qs swap qstorp objs-length)))
218
(defthm property-of-swap
219
(implies (and (natp i)
222
(equal (objsi i (swap lo hi qs))
229
:cases ((equal lo hi)))))
231
(in-theory (disable swap))
235
(implies (and (not (natp (1- hi)))
238
:rule-classes :forward-chaining)
242
(defthm split-qs-returns-a-value-<=-hi+1
243
(implies (and (natp lo)
246
(<= (mv-nth 0 (split-qs lo hi splitter qs))
249
:induct (split-qs lo hi splitter qs)
253
(defthm split-qs-returns-natp
254
(implies (and (natp lo)
256
(natp (mv-nth 0 (split-qs lo hi splitter qs)))))
260
(implies (and (<= i hi)
263
:rule-classes :forward-chaining)
268
(implies (and (<= i hi)
271
(not (equal i (1+ hi))))
272
:rule-classes :forward-chaining)
276
(defthm if-splitter-is-lo-then-split-qs-neq-hi+1
277
(implies (and (natp lo)
280
(equal splitter (objsi lo qs)))
281
(not (equal (mv-nth 0 (split-qs lo hi splitter qs)) (1+ hi))))
282
:hints (("Goal" ; needed for v2-8 addition of natp-posp book
283
:in-theory (disable natp-posp--1))
286
:in-theory (disable split-qs-returns-a-value-<=-hi+1))
288
:use ((:instance split-qs-returns-a-value-<=-hi+1
290
(splitter (objsi lo qs)))))
293
:use ((:instance split-qs-returns-a-value-<=-hi+1
297
(splitter (objsi lo qs)))))))
302
(implies (and (<= i (1+ hi))
305
(not (equal i (1+ hi))))
311
(defthm split-qs-returns-a-number-<=hi
312
(implies (and (natp lo)
314
(equal splitter (objsi lo qs))
316
(<= (mv-nth 0 (split-qs lo hi splitter qs))
319
:in-theory (disable split-qs)
320
:use ((:instance arith-003
321
(i (mv-nth 0 (split-qs lo hi (objsi lo qs) qs)))))))
322
:rule-classes :linear)
324
(defun sort-qs (lo hi qstor)
325
(declare (xargs :guard (and (natp lo)
327
(<= lo (objs-length qstor))
328
(< hi (objs-length qstor)))
331
:measure (nfix (- hi lo))
333
:in-theory (enable natp)
334
:induct (split-qs lo hi splitter qs)))))
337
(mv-let (index qstor)
338
(split-qs lo hi (objsi lo qstor) qstor)
340
(sort-qs (1+ lo) hi qstor)
341
(let* ((qstor (sort-qs index hi qstor))
342
(qstor (sort-qs lo (1- index) qstor)))
346
(in-theory (disable alloc-qs swap qstorp objs-length)))
349
(defthm split-qs-<=-objs-length
350
(implies (and (integerp lo)
352
(< lo (objs-length qs))
353
(< hi (objs-length qs)))
354
(<= (car (split-qs lo hi x qs))
356
:rule-classes :linear))
359
(defthm mv-nth-0-is-car
360
(equal (mv-nth 0 x) (car x))
361
:hints (("Goal" :in-theory (enable mv-nth)))))
364
(defthm mv-nth-1-is-cadr
365
(equal (mv-nth 1 x) (cadr x))
366
:hints (("Goal" :in-theory (enable mv-nth)))))
369
(defthm qstorp-sort-qs
371
(qstorp (sort-qs lo hi qs)))))
374
(defthm objs-length-sort-qs
375
(implies (and (natp lo)
377
(<= lo (objs-length qs))
378
(< hi (objs-length qs)))
379
(= (objs-length (sort-qs lo hi qs))
382
(verify-guards sort-qs)
384
(local (in-theory (disable mv-nth-0-is-car mv-nth-1-is-cadr)))
387
(declare (xargs :guard (true-listp x)))
389
(with-local-stobj qstor
391
(let* ((size (length x))
392
(qstor (alloc-qs size qstor))
393
(qstor (load-qs x 0 size qstor))
394
(qstor (sort-qs 0 (1- size) qstor)))
395
(mv (extract-qs 0 (1- size) qstor)
399
;; Now we define the abstract spec.
402
(declare (xargs :guard t))
407
(insert e (rest x)))))
410
(declare (xargs :guard t))