(in-package "PACO") ; Note: Some function definitions in the Paco sources are ; accompanied by guards. However, I ignore guards for the moment ; and the only reason these functions are guarded is that they ; happened to be guarded in the ACL2 source files and I see no ; reason to throw away the guards. Guard verification is turned ; off during the processing of Paco sources. ;----------------------------------------------------------------- ; Section: Basic Lisp Processing Functions and Predicates (defun rev (x) (if (endp x) nil (append (rev (cdr x)) (list (car x))))) (defun alistp (l) (declare (xargs :guard t)) (cond ((atom l) (eq l nil)) (t (and (consp (car l)) (alistp (cdr l)))))) (defun symbol-alistp (x) (declare (xargs :guard t)) (cond ((atom x) (eq x nil)) (t (and (consp (car x)) (symbolp (car (car x))) (symbol-alistp (cdr x)))))) (defun assoc-eq (x alist) (declare (xargs :guard (if (symbolp x) (alistp alist) (symbol-alistp alist)))) (cond ((endp alist) nil) ((eq x (car (car alist))) (car alist)) (t (assoc-eq x (cdr alist))))) (defun assoc-equal (x alist) (declare (xargs :guard (alistp alist))) (cond ((endp alist) nil) ((equal x (car (car alist))) (car alist)) (t (assoc-equal x (cdr alist))))) (defun member-equal (x lst) (declare (xargs :guard (true-listp lst))) (cond ((endp lst) nil) ((equal x (car lst)) lst) (t (member-equal x (cdr lst))))) (defun keyword-value-listp (l) (declare (xargs :guard t)) (cond ((atom l) (null l)) (t (and (keywordp (car l)) (consp (cdr l)) (keyword-value-listp (cddr l)))))) (defun evens (l) (declare (xargs :guard (true-listp l))) (cond ((endp l) nil) (t (cons (car l) (evens (cddr l)))))) (defun odds (l) (declare (xargs :guard (true-listp l))) (evens (cdr l))) (defun symbol-listp (lst) (declare (xargs :guard t)) (cond ((atom lst) (eq lst nil)) (t (and (symbolp (car lst)) (symbol-listp (cdr lst)))))) (defun fix (x) (declare (xargs :guard t)) (if (acl2-numberp x) x 0)) (defun character-listp (l) (declare (xargs :guard t)) (cond ((atom l) (equal l nil)) (t (and (characterp (car l)) (character-listp (cdr l)))))) (defun make-character-list (x) (declare (xargs :guard t)) (cond ((atom x) nil) ((characterp (car x)) (cons (car x) (make-character-list (cdr x)))) (t ; There's nothing special about (code-char 0), but at least it ; will look strange when people come across it. (cons (code-char 0) (make-character-list (cdr x)))))) (defun member-eq (x lst) (declare (xargs :guard (if (symbolp x) (true-listp lst) (symbol-listp lst)))) (cond ((endp lst) nil) ((eq x (car lst)) lst) (t (member-eq x (cdr lst))))) (defun union-eq (lst1 lst2) (declare (xargs :guard (and (symbol-listp lst1) (true-listp lst2)))) (cond ((endp lst1) lst2) ((member-eq (car lst1) lst2) (union-eq (cdr lst1) lst2)) (t (cons (car lst1) (union-eq (cdr lst1) lst2))))) (defun add-to-set-eq (x lst) (declare (xargs :guard (if (symbolp x) (true-listp lst) (symbol-listp lst)))) (cond ((member-eq x lst) lst) (t (cons x lst)))) (defun subst-for-nth (new n lst) ; This substitutes the new for the nth element in lst (0 based). (cond ((zp n) (cons new (cdr lst))) (t (cons (car lst) (subst-for-nth new (1- n) (cdr lst)))))) (defun no-duplicatesp-equal (l) (declare (xargs :guard (true-listp l))) (cond ((endp l) t) ((member-equal (car l) (cdr l)) nil) (t (no-duplicatesp-equal (cdr l))))) (defun set-difference-eq (l1 l2) (declare (xargs :guard (and (true-listp l1) (true-listp l2) (or (symbol-listp l1) (symbol-listp l2))))) (cond ((endp l1) nil) ((member-eq (car l1) l2) (set-difference-eq (cdr l1) l2)) (t (cons (car l1) (set-difference-eq (cdr l1) l2))))) (defun subsetp-eq (x y) (declare (xargs :guard (and (true-listp x) (true-listp y) (or (symbol-listp x) (symbol-listp y))))) (cond ((endp x) t) ((member-eq (car x) y) (subsetp-eq (cdr x) y)) (t nil))) (defun set-difference-equal (l1 l2) (declare (xargs :guard (and (true-listp l1) (true-listp l2)))) (cond ((endp l1) nil) ((member-equal (car l1) l2) (set-difference-equal (cdr l1) l2)) (t (cons (car l1) (set-difference-equal (cdr l1) l2))))) (defun intersectp-eq (x y) (declare (xargs :guard (and (symbol-listp x) (symbol-listp y)))) (cond ((endp x) nil) ((member-eq (car x) y) t) (t (intersectp-eq (cdr x) y)))) (defun subsetp-equal (x y) (declare (xargs :guard (and (true-listp y) (true-listp x)))) (cond ((endp x) t) ((member-equal (car x) y) (subsetp-equal (cdr x) y)) (t nil))) (defun add-to-set-equal (x l) (declare (xargs :guard (true-listp l))) (cond ((member-equal x l) l) (t (cons x l)))) (defun union-equal (x y) (declare (xargs :guard (and (true-listp x) (true-listp y)))) (cond ((endp x) y) ((member-equal (car x) y) (union-equal (cdr x) y)) (t (cons (car x) (union-equal (cdr x) y))))) (defun intersection-eq (l1 l2) (declare (xargs :guard (and (symbol-listp l1) (symbol-listp l2)))) (cond ((endp l1) nil) ((member-eq (car l1) l2) (cons (car l1) (intersection-eq (cdr l1) l2))) (t (intersection-eq (cdr l1) l2)))) (defun delete1-eq (x lst) (cond ((endp lst) nil) ((eq x (car lst)) (cdr lst)) (t (cons (car lst) (delete1-eq x (cdr lst)))))) (defun delete1-equal (x lst) (cond ((endp lst) nil) ((equal x (car lst)) (cdr lst)) (t (cons (car lst) (delete1-equal x (cdr lst)))))) (defun delete-assoc-eq (key alist) (declare (xargs :guard (if (symbolp key) (alistp alist) (symbol-alistp alist)))) (cond ((endp alist) nil) ((eq key (caar alist)) (cdr alist)) (t (cons (car alist) (delete-assoc-eq key (cdr alist)))))) (defun strip-cadrs (x) (cond ((endp x) nil) (t (cons (cadar x) (strip-cadrs (cdr x)))))) (defun remove-duplicates-equal (x) (cond ((endp x) nil) ((member-equal (car x) (cdr x)) (remove-duplicates-equal (cdr x))) (t (cons (car x) (remove-duplicates-equal (cdr x)))))) (defun all-but-last (l) (cond ((endp l) nil) ((endp (cdr l)) nil) (t (cons (car l) (all-but-last (cdr l)))))) (defun last (l) (declare (xargs :guard (listp l))) (if (atom (cdr l)) l (last (cdr l)))) (defun symbol-< (x y) (declare (xargs :guard (and (symbolp x) (symbolp y)))) (let ((x1 (symbol-name x)) (y1 (symbol-name y))) (or (string< x1 y1) (and (equal x1 y1) (string< (symbol-package-name x) (symbol-package-name y)))))) (defun alphorder (x y) (declare (xargs :guard t)) (cond ((rationalp x) (cond ((rationalp y) (<= x y)) (t t))) ((rationalp y) nil) ((complex-rationalp x) (cond ((complex-rationalp y) (or (< (realpart x) (realpart y)) (and (= (realpart x) (realpart y)) (<= (imagpart x) (imagpart y))))) (t t))) ((complex-rationalp y) nil) ((characterp x) (cond ((characterp y) (<= (char-code x) (char-code y))) (t t))) ((characterp y) nil) ((stringp x) (cond ((stringp y) (and (string<= x y) t)) (t t))) ((stringp y) nil) (t (cond ((symbolp x) (cond ((symbolp y) (not (symbol-< y x))) (t t))) ((symbolp y) nil) (t (acl2::bad-atom<= x y)))))) (defun lexorder (x y) (declare (xargs :guard t)) (cond ((atom x) (cond ((atom y) (alphorder x y)) (t t))) ((atom y) nil) ((equal (car x) (car y)) (lexorder (cdr x) (cdr y))) (t (lexorder (car x) (car y))))) (defun kwote (x) (declare (xargs :guard t)) (list 'quote x)) ; We next develop the function that maps a natural number to its ; ``printed'' representation as a list of characters, e.g., 31415 ; is mapped to (#\3 #\1 #\4 #\1 #\5). (defun digit-to-char (n) (declare (xargs :guard (and (integerp n) (<= 0 n) (<= n 9)))) (case n (1 #\1) (2 #\2) (3 #\3) (4 #\4) (5 #\5) (6 #\6) (7 #\7) (8 #\8) (9 #\9) (otherwise #\0))) ; We'll need a few facts about floor and mod to admit the function ; that maps from numbers to their printed representation. (local (include-book "ihs/ihs-lemmas" :dir :system)) (defthm justify-integer-floor-recursion ; To use this, be sure to disable acl2-count and floor. If you ; leave acl2-count enabled, then prove a version of this ; appropriate to that setting. (implies (and (integerp i) (integerp j) (not (equal i 0)) (not (equal i -1)) (> j 1)) (< (acl2-count (floor i j)) (acl2-count i))) :rule-classes :linear :hints (("Goal" :in-theory (disable floor)))) ; So here is the function we want. (defun explode-nonnegative-integer (n ans) (declare (xargs :guard (and (integerp n) (>= n 0)) :hints (("Goal" :in-theory (disable acl2-count floor))))) (cond ((zp n) (cond ((endp ans) '(#\0)) (t ans))) (t (explode-nonnegative-integer (floor n 10) (cons (digit-to-char (mod n 10)) ans))))) ; We will eventually need to know that the printed ; representations of two numbers are identical iff the numbers ; are the same. I found it too hard to deal with the accumulator ; above; I could not find a suitably general version of the lemma ; enni-uique, below, when the accumulator was around. So I have ; decided to map from the efficient function ; explode-nonnegative-integer to a more elegant one. (defun enni (n) (declare (xargs :hints (("Goal" :in-theory (disable acl2-count floor))))) (cond ((zp n) nil) (t (cons (digit-to-char (mod n 10)) (enni (floor n 10)))))) (defun enni-induct (i j) (declare (xargs :hints (("Goal" :in-theory (disable acl2-count floor))))) (cond ((zp i) nil) ((zp j) nil) (t (enni-induct (floor i 10) (floor j 10))))) ; Here's the basic uniqueness result vis-a-vis the printed ; representation (even though enni ``prints'' in the reverse ; order and ``prints'' 0 as the empty string of characters). (defthm enni-unique (equal (equal (enni i) (enni j)) (equal (nfix i) (nfix j))) :hints (("Goal" :induct (enni-induct i j)))) ; So here is the explanation of the accumulator. (defthm explode-nonnegative-integer-is-enni (equal (explode-nonnegative-integer n a) (append (rev (enni n)) (if (and (endp a) (zp n)) '(#\0) a))) :hints (("Goal" :in-theory (disable digit-to-char floor mod)))) ; So now we must prove that explode-nonnegative-integer produces ; unique representations. That is surprisingly hard, because of ; all the ways the append expression above can seem to identify ; results. As an indication of how messy it is, consider how ; many lemmas I need about append, reverse, and enni below. All ; of these are here simply to get the uniqueness result for ; explode-nonnegative-integer. (defthm assoc-of-append (equal (append (append a b) c) (append a (append b c)))) (defthm true-listp-append (equal (true-listp (append a b)) (true-listp b))) (defthm len-append (equal (len (append a b)) (+ (len a) (len b)))) (defthm equal-len-0 (equal (equal (len x) 0) (endp x))) (defthm append-id-implies-endp (equal (equal (append x a) a) (endp x)) :hints (("Goal" :use (:instance len-append (a x) (b a)) :in-theory (disable len-append)))) (defun double-cdr-hint (x y) (cond ((endp x) t) ((endp y) t) (t (double-cdr-hint (cdr x) (cdr y))))) (defthm equal-append-1 (implies (and (true-listp a) (true-listp b)) (equal (equal (append a c) (append b c)) (equal a b))) :hints (("Goal" :induct (double-cdr-hint a b)))) (defthm equal-append-2 (equal (equal (append a b) (append a c)) (equal b c))) (defthm equal-append-3 (implies (and (true-listp a) (true-listp b)) (equal (equal (append a (list e)) (append b (list d))) (and (equal a b) (equal e d)))) :hints (("Goal" :induct (double-cdr-hint a b)))) (defthm equal-append-singleton (equal (equal (append a b) (list e)) (if (consp a) (and (equal (car a) e) (endp (cdr a)) (null b)) (equal b (list e))))) (defthm consp-rev (equal (consp (rev x)) (consp x))) (defthm true-listp-rev (true-listp (rev x)) :rule-classes :type-prescription) (defthm equal-rev (implies (and (true-listp a) (true-listp b)) (equal (equal (rev a) (rev b)) (equal a b))) :hints (("Goal" :induct (double-cdr-hint a b)))) (defthm car-append (equal (car (append a b)) (if (consp a) (car a) (car b)))) ; Neat fact: The leading digit in the printed representation is ; #\0 only if the number is 0. (defthm enni-minnie-zero (implies (not (zp i)) (not (equal (car (rev (enni i))) #\0))) :hints (("Goal" :in-theory (disable floor mod)))) (defthm consp-enni (equal (consp (enni i)) (not (zp i)))) ; And here is the uniqueness result we wanted. (defthm explode-nonnegative-integer-unique (equal (equal (explode-nonnegative-integer i a) (explode-nonnegative-integer j a)) (equal (nfix i) (nfix j))) :hints (("Goal" :in-theory (disable floor mod digit-to-char)))) (in-theory (disable explode-nonnegative-integer-is-enni)) (defun explode-atom (x) (declare (xargs :guard (or (acl2-numberp x) (characterp x) (stringp x) (symbolp x)))) (cond ((rationalp x) (cond ((integerp x) (cond ((< x 0) (cons #\- (explode-nonnegative-integer (- x) nil))) (t (explode-nonnegative-integer x nil)))) (t (append (explode-atom (numerator x)) (cons #\/ (explode-nonnegative-integer (denominator x) nil)))))) ((complex-rationalp x) (list* #\# #\C #\( (append (explode-atom (realpart x)) (cons #\Space (append (explode-atom (imagpart x)) '(#\))))))) ((characterp x) (list x)) ((stringp x) (coerce x 'list)) (t (coerce (symbol-name x) 'list)))) (defun packn1 (lst) (cond ((endp lst) nil) (t (append (explode-atom (car lst)) (packn1 (cdr lst)))))) (defun packn (lst) (intern (coerce (packn1 lst) 'string) "ACL2")) ;----------------------------------------------------------------- ; Section: Records (defun record-maker-function-name (name) (intern-in-package-of-symbol (coerce (append (coerce "Make " 'list) (coerce (symbol-name name) 'list) (coerce " record" 'list)) 'string) name)) (defun record-accessor-function-name (name field) (intern-in-package-of-symbol (coerce (append (coerce "Access " 'list) (coerce (symbol-name name) 'list) (coerce " record field " 'list) (coerce (symbol-name field) 'list)) 'string) name)) (defun record-changer-function-name (name) (intern-in-package-of-symbol (coerce (append (coerce "Change " 'list) (coerce (symbol-name name) 'list) (coerce " record fields" 'list)) 'string) name)) (defmacro make (&rest args) (cons (record-maker-function-name (car args)) (cdr args))) (defmacro access (name rec field) (list (record-accessor-function-name name field) rec)) (defmacro change (&rest args) (cons (record-changer-function-name (car args)) (cdr args))) (defun make-record-car-cdrs1 (lst var) (cond ((endp lst) var) (t (list (car lst) (make-record-car-cdrs1 (cdr lst) var))))) (defun make-record-car-cdrs (field-layout car-cdr-lst) (cond ((atom field-layout) (cond ((null field-layout) nil) (t (list (make-record-car-cdrs1 car-cdr-lst 'record))))) (t (append (make-record-car-cdrs (car field-layout) (cons 'car car-cdr-lst)) (make-record-car-cdrs (cdr field-layout) (cons 'cdr car-cdr-lst)))))) (defun make-record-accessors (name field-lst car-cdrs) (cond ((endp field-lst) nil) (t (cons (list 'defmacro (record-accessor-function-name name (car field-lst)) '(record) `(list 'let (list (list 'record record)) ',(car car-cdrs))) (make-record-accessors name (cdr field-lst) (cdr car-cdrs)))))) (defun symbol-name-tree-occur (sym sym-tree) ; Sym is a symbol -- in fact, a keyword in proper usage -- and ; sym-tree is a tree of symbols. We ask whether a symbol with ; the same symbol-name as key occurs in sym-tree. If so, we ; return that symbol. Otherwise we return nil. (cond ((symbolp sym-tree) (cond ((equal (symbol-name sym) (symbol-name sym-tree)) sym-tree) (t nil))) ((atom sym-tree) nil) (t (or (symbol-name-tree-occur sym (car sym-tree)) (symbol-name-tree-occur sym (cdr sym-tree)))))) (defun some-symbol-name-tree-occur (syms sym-tree) (cond ((endp syms) nil) ((symbol-name-tree-occur (car syms) sym-tree) t) (t (some-symbol-name-tree-occur (cdr syms) sym-tree)))) (defun make-record-changer-cons (fields field-layout x) ; Fields is the list of keyword field specifiers that are being ; changed. Field-layout is the user's layout of the record. X ; is the name of the variable holding the instance of the record. (cond ((not (some-symbol-name-tree-occur fields field-layout)) x) ((atom field-layout) field-layout) (t (list 'cons (make-record-changer-cons fields (car field-layout) (list 'car x)) (make-record-changer-cons fields (cdr field-layout) (list 'cdr x)))))) (defun make-record-changer-let-bindings (field-layout lst) ; Field-layout is the symbol tree provided by the user describing ; the layout of the fields. Lst is the keyword/value list in a ; change form. We want to bind each field name to the ; corresponding value. The only reason we take field-layout as ; an argument is that we don't know from :key which package 'key ; is in. (cond ((endp lst) nil) (t (let ((var (symbol-name-tree-occur (car lst) field-layout))) (cons (list var (cadr lst)) (make-record-changer-let-bindings field-layout (cddr lst))))))) (defun make-record-changer-let (name field-layout rec lst) (declare (ignore name)) (list 'let (cons (list 'record-changer-not-to-be-used-elsewhere rec) (make-record-changer-let-bindings field-layout lst)) (make-record-changer-cons (evens lst) field-layout 'record-changer-not-to-be-used-elsewhere))) (defun make-record-changer (name field-layout) (list 'defmacro (record-changer-function-name name) '(&rest args) (list 'make-record-changer-let (kwote name) (kwote field-layout) '(car args) '(cdr args)))) (defun make-record-maker-cons (fields field-layout) ; Fields is the list of keyword field specifiers being ; initialized in a record. Field-layout is the user's ; specification of the layout. We lay down a cons tree ; isomorphic to field-layout whose tips are either the ; corresponding tip of field-layout or nil according to whether ; the keyword corresponding to the field-layout tip is in fields. (cond ((atom field-layout) (cond ((some-symbol-name-tree-occur fields field-layout) ; The above call is a little strange isn't it? Field-layout is ; an atom, a symbol really, and here we are asking whether any ; element of fields symbol-name-tree-occurs in it. We're really ; just exploiting some-symbol-name-tree-occur to walk down fields ; for us taking the symbol-name of each element and seeing if it ; occurs in (i.e., in this case, is) the symbol name of ; field-layout. field-layout) (t nil))) (t (list 'cons (make-record-maker-cons fields (car field-layout)) (make-record-maker-cons fields (cdr field-layout)))))) (defun make-record-maker-let (name field-layout lst) (declare (ignore name)) (list 'let (make-record-changer-let-bindings field-layout lst) (make-record-maker-cons (evens lst) field-layout))) (defun make-record-maker (name field-layout) (list 'defmacro (record-maker-function-name name) '(&rest args) (list 'make-record-maker-let (kwote name) (kwote field-layout) 'args))) (defun make-record-field-lst (field-layout) (cond ((atom field-layout) (cond ((null field-layout) nil) (t (list field-layout)))) (t (append (make-record-field-lst (car field-layout)) (make-record-field-lst (cdr field-layout)))))) (defun record-macros (name field-layout) (cons 'progn (append (make-record-accessors name (make-record-field-lst field-layout) (make-record-car-cdrs field-layout nil)) (list (make-record-changer name field-layout) (make-record-maker name field-layout))))) ; WARNING: If you change the layout of records, you must change ; certain functions that build them in. Generally, these ; functions are defined before defrec was defined, but need to ; access components. See the warning associated with defrec ; rewrite-constant for a list of one group of such functions. ; You might also search for occurrences of the word defrec prior ; to this definition of it. (defmacro defrec (name field-lst) (record-macros name field-lst)) ; ---------------------------------------------------------------- ; Section: Property lists (defun worldp (alist) (declare (xargs :guard t)) (cond ((atom alist) (eq alist nil)) (t (and (consp (car alist)) (symbolp (car (car alist))) (consp (cdr (car alist))) (symbolp (cadr (car alist))) (worldp (cdr alist)))))) (defconst *acl2-property-unbound* :acl2-property-unbound) (defun getprop (symb key default alist) (declare (xargs :guard (and (symbolp symb) (symbolp key) (worldp alist)))) ; In the PSIM world, we would prefer for this function, ; paco::getprop, to be defined as shown below. We call this the ; ``slow version.'' #| (cond ((endp alist) default) ((and (eq symb (caar alist)) (eq key (cadar alist))) (let ((ans (cddar alist))) (if (eq ans *acl2-property-unbound*) default ans))) (t (getprop symb key default (cdr alist))))|# ; However, for purposes of testing before PSIM is complete, it is ; nice to assume that the world alist has been installed under ; the name paco::paco. If that is true, this function is much ; faster but is still equivalent to the slow version above. We ; arrange for the acl2::db function to install the Paco world it ; creates. See database.lisp. (acl2::getprop symb key default 'paco::paco alist)) (defun global-val (symb alist) (getprop symb 'global-value nil alist)) ; ---------------------------------------------------------------- ; Section Balanced Binary-Trees ; We only need two features of balanced binary trees: how to ; build one from a list of numbers and how to ask whether a ; number is in the resulting tree. We are content to reconstruct ; the tree from scratch when we need to insert or delete an ; element. So we don't implement insertion, deletion, or ; dyanamic re-balancing. (defun in-btreep (n btree) (cond ((atom btree) (equal n btree)) ((< n (car btree)) (in-btreep n (cadr btree))) ((> n (car btree)) (in-btreep n (cddr btree))) (t t))) (defun btree-contents (btree) ; Return the list containing the numbers in btree. (cond ((atom btree) (if (null btree) nil (list btree))) (t (append (btree-contents (cadr btree)) (cons (car btree) (btree-contents (cddr btree))))))) ; To build a btree, we sort the list of numbers into ascending ; order, split the list into a middle pivot element and two ; almost equal length halves and recursively build the subtrees ; around that pivot. (defun merge-ascending (l1 l2) (declare (xargs :measure (+ (acl2-count l1) (acl2-count l2)))) (cond ((endp l1) l2) ((endp l2) l1) ((<= (car l1) (car l2)) (cons (car l1) (merge-ascending (cdr l1) l2))) (t (cons (car l2) (merge-ascending l1 (cdr l2)))))) (defthm acl2-count-evens (implies (consp (cdr x)) (< (acl2-count (evens x)) (acl2-count x)))) ; This is the merge sort function. (defun merge-sort-ascending (l) (cond ((endp (cdr l)) l) (t (merge-ascending (merge-sort-ascending (evens l)) (merge-sort-ascending (odds l)))))) (defun find-pivot1 (lst x) (cond ((endp (cdr x)) nil) (t (cons (car lst) (find-pivot1 (cdr lst) (cddr x)))))) (defun find-pivot2 (lst x) (cond ((endp (cdr x)) lst) (t (find-pivot2 (cdr lst) (cddr x))))) (defun find-pivot (lst) ; Lst is ordered. We split it into (mv first-part pivot ; last-part). (cond ((endp lst) (mv nil nil nil)) ((endp (cdr lst)) (mv nil (car lst) nil)) (t (let ((lst1 (find-pivot1 lst lst)) (lst2 (find-pivot2 lst lst))) (mv lst1 (car lst2) (cdr lst2)))))) (defthm len-find-pivot1 (implies (and (consp lst) (consp x) (<= (len x) (len lst))) (< (len (find-pivot1 lst x)) (len lst))) :rule-classes :linear) (defthm len-find-pivot2 (implies (and (consp lst) (consp (cdr x))) (< (len (find-pivot2 lst x)) (len lst))) :rule-classes :linear) (defun make-btree1 (lst) (declare (xargs :measure (len lst) :hints (("Subgoal 2" :use (:instance len-find-pivot2 (lst lst) (x lst)))))) (cond ((endp lst) nil) ((endp (cdr lst)) (car lst)) (t (mv-let (lst1 n lst2) (find-pivot lst) (cons n (cons (make-btree1 lst1) (make-btree1 lst2))))))) (defun make-btree (lst) ; It is assumed lst has no duplicates in it. This function ; actually works if there are duplications, but duplications make ; the search less efficient. (make-btree1 (merge-sort-ascending lst)))