; Defsort - Defines a stable sort when given a comparison function ; Copyright (C) 2008 Centaur Technology ; ; Contact: ; Centaur Technology Formal Verification Group ; 7600-C N. Capital of Texas Highway, Suite 300, Austin, TX 78731, USA. ; http://www.centtech.com/ ; ; License: (An MIT/X11-style license) ; ; Permission is hereby granted, free of charge, to any person obtaining a ; copy of this software and associated documentation files (the "Software"), ; to deal in the Software without restriction, including without limitation ; the rights to use, copy, modify, merge, publish, distribute, sublicense, ; and/or sell copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following conditions: ; ; The above copyright notice and this permission notice shall be included in ; all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ; DEALINGS IN THE SOFTWARE. ; ; Original author: Jared Davis ; Defsort Examples. ; ; You do not need to load this book to use defsort; it is only here to show you ; some examples of using defsort. (in-package "ACL2") (include-book "defsort") (include-book "misc/total-order" :dir :system) (include-book "misc/assert" :dir :system) ;; The following defines (<-SORT X), which orders a list of rational numbers ;; in ascending order. (defsort :comparablep rationalp :compare< < :prefix < :weak nil) (assert! (equal (<-sort '(5 5 3 4 4)) '(3 4 4 5 5))) ;; We cannot define (>-SORT X) directly using >, because in ACL2 > is a macro ;; instead of a function. So, we define a wrapper. (defun greater-p (x y) (declare (xargs :guard (and (rationalp x) (rationalp y)))) (> x y)) (defsort :comparablep rationalp :compare< greater-p :prefix > :weak nil) (assert! (equal (>-sort '(5 5 3 4 4)) '(5 5 4 4 3))) ;; new syntax with sort function name first (defsort bigger-sort :comparablep rationalp :compare< (lambda (x y) (< y x)) :prefix bigger :weak nil) ;; new syntax with sort function name and no prefix (defsort littler-sort :comparablep rationalp :compare< (lambda (x y) (< x y)) :weak nil) ;; We can define an arbitrary sort using <<. This is almost the same as ;; SET::mergesort in the ordered sets library, except that defsorts are ;; always duplicate-preserving while SET::mergesort throws away identical ;; elements. (defsort :compare< << :prefix < * :formals (x) :guard t)) (local (defun sortelt-p (x) (and x t))) (defthm type-of-sortelt-p (booleanp (sortelt-p x)) :rule-classes :type-prescription))) (local (encapsulate (((sortcmp * *) => * :formals (x y) :guard (and (sortelt-p x) (sortelt-p y)))) (local (defun sortcmp (x y) (< (nfix x) (nfix y)))) (defthm type-of-sortcmp (booleanp (sortcmp x y)) :rule-classes :type-prescription) (defthm sortcmp-transitive (implies (and (sortcmp x y) (sortcmp y z)) (sortcmp x z))))) (local (encapsulate () (local (defsort :prefix gensort :comparablep sortelt-p :compare< sortcmp :true-listp nil)) (value-triple :test-true-listp-t-without-listp))) (local (encapsulate () (local (defun sorteltlist-p (x) (declare (xargs :guard t)) (if (atom x) (not x) (and (sortelt-p (car x)) (sorteltlist-p (cdr x)))))) (local (defsort :prefix gensort :comparablep sortelt-p :compare< sortcmp :true-listp t)) (value-triple :test-true-listp-t-with-listp))) (local (encapsulate () (local (defun sorteltlist-p (x) (declare (xargs :guard t)) (if (atom x) t (and (sortelt-p (car x)) (sorteltlist-p (cdr x)))))) (local (defsort :prefix gensort :comparablep sortelt-p :compare< sortcmp)) (value-triple :test-true-listp-nil-with-listp))) #|| ; Below are some performance comparisions. ; We do our timings on CCL on Lisp2. (include-book ;; Line break fools dependency scanner. "std/osets/top" :dir :system) :q (ccl::set-lisp-heap-gc-threshold (expt 2 30)) (defparameter *integers* ;; A test vector of 10,000 integers which are the numbers 1 through 1000, ;; each repeated ten times. (loop for j from 1 to 10 nconc (loop for i from 1 to 1000 collect i))) (defparameter *strings* (loop for j from 1 to 10 nconc (loop for i from 1 to 1000 collect (concatenate 'string "string_number_" (coerce (explode-atom i 10) 'string))))) ;; 9.13 seconds with 4.4 GB allocated (progn (ccl::gc) (time (loop for i fixnum from 1 to 1000 do (let ((result (SET::mergesort (cons i *integers*)))) (declare (ignore result)) nil)))) ;; 4.25 seconds with 1.5 GB allocated (progn (ccl::gc) (time (loop for i fixnum from 1 to 1000 do (let ((result (<<-sort (cons i *integers*)))) (declare (ignore result)) nil)))) ;; 2.71 seconds with 1.5 GB allocated (progn (ccl::gc) (time (loop for i fixnum from 1 to 1000 do (let ((result (<-sort (cons i *integers*)))) (declare (ignore result)) nil)))) ;; 2.97 seconds with 1.6 GB allocated (progn (ccl::gc) (time (loop for i fixnum from 1 to 1000 do (let ((result (>-sort (cons i *integers*)))) (declare (ignore result)) nil)))) ;; 25.4 seconds with 4.4 GB allocated (progn (ccl::gc) (time (loop for i fixnum from 1 to 1000 do (let ((result (SET::mergesort (cons "foo" *strings*)))) (declare (ignore result)) nil)))) ;; 18.8 seconds with 1.5 GB allocated (progn (ccl::gc) (time (loop for i fixnum from 1 to 1000 do (let ((result (<<-sort (cons "foo" *strings*)))) (declare (ignore result)) nil)))) ;; 11.7 seconds with 1.5 GB allocated (progn (ccl::gc) (time (loop for i fixnum from 1 to 1000 do (let ((result (string-sort (cons "foo" *strings*)))) (declare (ignore result)) nil)))) (include-book ;; NOTE: not compatible with other includes "defexec/other-apps/qsort/programs" :dir :system) ;; 16.1 seconds with 240 MB allocated -- interesting (progn (ccl::gc) (time (loop for i fixnum from 1 to 1000 do (let ((result (qsort (cons i *integers*)))) (declare (ignore result)) nil)))) ||#