Included Books
other
(in-package "ACL2")
include-book
(include-book "xdoc/top" :dir :system)
other
(defpointer defpm def-partial-measure)
other
(defxdoc def-partial-measure :parents (macro-libraries) :short "Introduce measure and termination predicates for a partial function definition" :long "<h3>Introduction By Way of an Example</h3> <p>We begin with a motivating example. Suppose we want to admit factorial without the need to prove termination, as follows.</p> @({ (fact x) = (if (equal x 0) 1 (* x (fact (1- x)))) }) <p>Of course, this ``definition'' is non-terminating on negative number inputs. But with @('def-partial-measure'), or @('defpm') for short, we can admit a suitable definition for this partial function as follows. First, we define a function to represent the termination test and another function to represent the actual parameter of the recursive call.</p> @({ (defun fact-test (x) (equal x 0)) (defun fact-step (x) (1- x)) }) <p>Now we can execute our utility: we provide it with the names of the two functions above, and it generates a measure, a termination predicate, and a potentially helpful theory, respectively.</p> @({ (defpm fact-test fact-step fact-measure fact-terminates fact-theory) }) <p>Here are the @(see events) exported by the @('defpm') call above.</p> @({ ; The first three lemmas can be useful for reasoning about the termination ; predicate, FACT-TERMINATES. (DEFTHM FACT-TERMINATES-BASE (IMPLIES (FACT-TEST X) (FACT-TERMINATES X))) (DEFTHM FACT-TERMINATES-STEP (IMPLIES (NOT (FACT-TEST X)) (EQUAL (FACT-TERMINATES (FACT-STEP X)) (FACT-TERMINATES X)))) (DEFTHMD FACT-TERMINATES-STEP-COMMUTED (IMPLIES (AND (SYNTAXP (SYMBOLP X)) (NOT (FACT-TEST X))) (EQUAL (FACT-TERMINATES X) (FACT-TERMINATES (FACT-STEP X))))) (THEORY-INVARIANT (INCOMPATIBLE (:REWRITE FACT-TERMINATES-STEP) (:REWRITE FACT-TERMINATES-STEP-COMMUTED))) ; The next two lemmas can be useful for defining functions whose termination ; is ensured by the measure just introduced. (DEFTHM FACT-MEASURE-TYPE (O-P (FACT-MEASURE X))) (DEFTHM FACT-MEASURE-DECREASES (IMPLIES (AND (FACT-TERMINATES X) (NOT (FACT-TEST X))) (O< (FACT-MEASURE (FACT-STEP X)) (FACT-MEASURE X)))) ; Finally, the four enabled rewrite rules above are collected into a theory. (DEFTHEORY FACT-THEORY '(FACT-TERMINATES-BASE FACT-TERMINATES-STEP FACT-MEASURE-TYPE FACT-MEASURE-DECREASES)) }) <p>With the events above, we can introduce the following definition, which in effect guards the body with the termination predicate. (Perhaps at some point we will extend @('defpm') to create this definition automatically.) The @(':')@(tsee in-theory) hint below was carefully crafted to allow the proof to succeed very quickly.</p> @({ (defun fact (x) (declare (xargs :measure (fact-measure x) :hints (("Goal" :in-theory (union-theories (theory 'fact-theory) (theory 'minimal-theory)))))) (if (fact-terminates x) (if (fact-test x) 1 (* x (fact (fact-step x)))) 1 ; don't-care )) }) <p>With the events above (not necessarily including the definition of @('fact')), we can prove that @('fact') terminates on natural number inputs. A second macro, @('defthm-domain'), automates much of that task:</p> @({ (defthm-domain fact-terminates-holds-on-natp (implies (natp x) (fact-terminates x)) :measure (nfix x)) }) <p>See @(see defthm-domain).</p> <h3>Detailed Documentation</h3> <p>General form:</p> @({ (defpm ; or equivalently, def-partial-measure ; ; TEST STEP MEASURE TERMINATES THEORY :formals FORMALS ; default is (x) :verbose VERBOSE ; default is nil ) }) <p>where there is no output unless @('VERBOSE') is non-@('nil'). The remaining arguments are as follows.</p> <p>First consider the case that @('FORMALS') is the default, @('(x)'). The arguments @('TEST') and @('STEP') are conceptually ``inputs'': they should name existing functions on the indicated value for formals (which by default is @('(x)')). Then @('defpm') will attempt to generate a measure and termination predicate on those formals, with the indicated names (@('MEASURE') and @('TERMINATES'), respectively). These theorems are suitable for admitting a function of the following form, where capitalized names refer to those in the @('defpm') call above, and where additional code may appear as indicated with ``...''.</p> @({ (defun foo (x) (declare (xargs :measure (MEASURE x) :hints (("Goal" :in-theory (union-theories (theory 'THEORY) (theory 'minimal-theory)))))) (if (TERMINATES x) (if (TEST x) ... (... (fact (STEP x)) ...) ...)) }) <p>The generated @('THEORY') names the four rules generated by the @('defpm') call, as in the example above.</p> @({ (defthm TERMINATES-base (implies (TEST x) (TERMINATES x))) (defthm TERMINATES-step (implies (not (TEST x)) (equal (TERMINATES (STEP x)) (TERMINATES x)))) (defthmd TERMINATES-step-commuted (implies (AND (syntaxp (symbolp x)) (not (TEST x))) (equal (TERMINATES x) (TERMINATES (STEP x))))) (theory-invariant (incompatible (:rewrite TERMINATES-step) (:rewrite TERMINATES-step-commuted))) (defthm MEASURE-type (o-p (MEASURE x))) (defthm MEASURE-decreases (implies (and (TERMINATES x) (not (TEST x))) (o< (MEASURE (STEP x)) (MEASURE x)))) (deftheory THEORY '(TERMINATES-base TERMINATES-step MEASURE-type MEASURE-decreases)) }) <p>For arbitrary formals the situation is similar, except that there is one step function per formal, obtained by adding the formal name as a suffix to the specified @('STEP') separated by a hyphen. Thus we have the following events when @('FORMALS') is @('(y1 ... yk)').</p> @({ (defthm TERMINATES-base (implies (TEST y1 ... yk) (TERMINATES y1 ... yk))) (defthm TERMINATES-step (implies (not (TEST y1 ... yk)) (equal (TERMINATES (STEP-y1 y1 ... yk) ... (STEP-yk y1 ... yk)) (TERMINATES y1 ... yk)))) (defthm TERMINATES-step-commuted (implies (AND (syntaxp (symbolp y1)) ... (syntaxp (symbolp yk)) (not (TEST y1 ... yk))) (equal (TERMINATES (STEP-y1 y1 ... yk) ... (STEP-yk y1 ... yk)) (TERMINATES y1 ... yk)))) (theory-invariant (incompatible (:rewrite TERMINATES-step) (:rewrite TERMINATES-step-commuted))) (defthm MEASURE-type (o-p (MEASURE y1 ... yk))) (defthm MEASURE-decreases (implies (and (TERMINATES y1 ... yk) (not (TEST y1 ... yk))) (o< (MEASURE (STEP-y1 y1 ... yk) ... (STEP-yk y1 ... yk)) (MEASURE y1 ... yk)))) (deftheory THEORY '(TERMINATES-base TERMINATES-step MEASURE-type MEASURE-decreases)) }) <h3>Implementation</h3> <p>The implementation of @('defpm') (i.e., @('def-partial-measure') has been designed to make proofs efficient. It should be completely unnecessary to know anything about the implementation in order to use @('defpm') effectively. If however you are interested, you can execute @(':')@(tsee trans1) on your @('defpm') call to see the @(see events) that it generates.</p> <h3>More Information</h3> <p>The community book @('misc/defpm.lisp') illustrates how to use @('defpm') and @('defthm-domain') to define ``partial'' functions. Search for calls of @('my-test') in that book to see examples.</p> <p>Related work of Dave Greve, in particular his utility @('def::ung'), may be found in community books directory @('books/coi/defung/'). Our utilities @('def-partial-measure') and @(tsee defthm-domain) were developed independently using an approach that seems considerably simpler than Greve's development. However, his utility is much more powerful in that it generates a termination test, rather than requiring the user to provide it, and also it handles reflexive functions — definitions with recursive calls like @('(mc91 (mc91 (+ n 11)))') — while ours were not designed to do so.</p>")
other
(defxdoc defthm-domain :parents (macro-libraries) :short "Prove termination on a given domain" :long "<p>This utility can be useful after executing a call of @('defpm'); see @(see def-partial-measure). Indeed, we assume that you have read the example in that @(see documentation) topic describing this call:</p> @({ (defpm fact-test fact-step fact-measure fact-terminates fact-theory) }) <h3>Introduction By Way of an Example</h3> <p>Consider the following form.</p> @({ (defthm-domain trfact-terminates-holds-on-natp (implies (natp x) (trfact-terminates x acc)) :test trfact-test ; optional test name: can be deduced by the tool ; :step trfact-step ; optional step name: can be deduced by the tool ; :measure (nfix x) ; required argument ; ) }) <p>This call produces a proof of the indicated formula, where the first argument of @('implies'), @('(natp x)'), provides a ``domain hypothesis.'' You can use @(':')@(tsee trans1) to see the macroexpansion of this @('defthm-domain') call. In short, @(see hints) are supplied to automate all ``boilerplate'' reasoning. The @(':measure') is used to guide a proof by induction. At this stage of development, the best way to use this macro is probably to submit the form in the hope that the proof will complete automatically; but if it doesn't, then use @(':')@(tsee trans1) to see what the form generates, and modify that event manually in order to fix the failed proofs.</p> <h3>Detailed Documentation</h3> <p>General form:</p> @({ (defthm-domain NAME (implies DOMAIN-TERM (TERMINATES FORMAL-1 ... FORMAL-K)) :test TEST :step STEP :measure MEASURE :verbose VERBOSE :root ROOT ) }) <p>where there is no output unless @('VERBOSE') is non-@('nil'). It is allowed to replace the @(tsee implies) call above by its second argument (the @('TERMINATES') call) if @('DOMAIN-TERM') is @('t'). The remaining arguments are as follows.</p> <p>The keywords @(':test') and @(':step') both have value @('nil') by default. So does @(':root'), unless @('TERMINATES') has a @(tsee symbol-name) of the form @('"root-TERMINATES"'), in which case :root is the symbol in the package of @('TERMINATES') whose name is that string, @('root'). If @(':root') has a value of @('nil'), even after taking this default into account, then both @(':test') and @(':step') must have a non-@('nil') value. The reason for this requirement is that when @(':test') and/or @(':step') is omitted, the value is computed from the root by adding the suffix @('"-TEST"') or @('"-STEP"') to the root (respectively). The functions introduced for @(':test') and @(':step') are exactly as for @('defpm'); see @(see def-partial-measure). Note however that the formals are those from the call of @('TERMINATES').</p> <p>See the discussion above about ``boilerplate'' reasoning for hints on how to deal with failures of @('defthm-domain') calls.</p> <h3>More Information</h3> <p>The community book @('misc/defpm.lisp') illustrates how to use @('defpm') and @('defthm-domain') to define ``partial'' functions. Search for calls of @('my-test') in that book to see examples.</p>")
defpm-add-suffixfunction
(defun defpm-add-suffix (sym suffix) (declare (xargs :guard (and (symbolp sym) (or (symbolp suffix) (stringp suffix))))) (intern-in-package-of-symbol (concatenate 'string (symbol-name sym) "-" (if (symbolp suffix) (symbol-name suffix) suffix)) sym))
defpm-add-suffix-lstfunction
(defun defpm-add-suffix-lst (sym lst) (declare (xargs :guard (and (symbolp sym) (or (symbol-listp lst) (string-listp lst))))) (cond ((endp lst) nil) (t (cons (defpm-add-suffix sym (car lst)) (defpm-add-suffix-lst sym (cdr lst))))))
defpm-make-suffix-lstfunction
(defun defpm-make-suffix-lst (str lst) (declare (xargs :guard (and (stringp str) (symbol-listp lst)))) (cond ((endp lst) nil) (t (cons (concatenate 'string str (symbol-name (car lst))) (defpm-make-suffix-lst str (cdr lst))))))
defpm-make-callsfunction
(defun defpm-make-calls (fns formals) (declare (xargs :guard (and (symbol-listp fns) (symbol-listp formals)))) (cond ((endp fns) nil) (t (cons (cons (car fns) formals) (defpm-make-calls (cdr fns) formals)))))
syntaxp-symbolp-lstfunction
(defun syntaxp-symbolp-lst (formals) (declare (xargs :guard (true-listp formals))) (cond ((endp formals) nil) (t (cons `(syntaxp (symbolp ,(CAR FORMALS))) (syntaxp-symbolp-lst (cdr formals))))))
other
(make-event (pprogn (f-put-global 'defpm-arithmetic-top-book (extend-pathname (cbd) "arithmetic-top-theory" state) state) (value '(value-triple :defpm-arithmetic-top-book-set))) :check-expansion t)
defpm-formfunction
(defun defpm-form (test steps measure terminates theory formals) (declare (xargs :guard (and (symbol-listp (list measure terminates theory)) (or (symbolp steps) (symbol-listp steps)) (symbol-listp formals) (not (intersectp-eq '(defpm-m defpm-n defpm-clk) formals))))) (let* ((steps (if (symbolp steps) (if (cdr formals) (defpm-add-suffix-lst steps formals) (list steps)) steps)) (step-calls (defpm-make-calls steps formals)) (measure-type (defpm-add-suffix measure "TYPE")) (terminates-base (defpm-add-suffix terminates "BASE")) (terminates-step (defpm-add-suffix terminates "STEP")) (terminates-step-commuted (defpm-add-suffix terminates "STEP-COMMUTED")) (measure-decreases (defpm-add-suffix measure "DECREASES"))) `(encapsulate ((,MEASURE ,FORMALS t) (,TERMINATES ,FORMALS t)) (local (make-event (list 'include-book (@ defpm-arithmetic-top-book)))) (local (in-theory (theory 'arithmetic-top-theory))) (local (in-theory (enable natp))) (local (encapsulate nil (defun defpm-clk-rec (,@FORMALS n) (declare (xargs :measure (nfix n))) (cond ((,TEST ,@FORMALS) n) ((zp n) nil) (t (defpm-clk-rec ,@STEP-CALLS (1- n))))) (defchoose defpm-clk-wit (defpm-n) ,FORMALS (and (natp defpm-n) (defpm-clk-rec ,@FORMALS defpm-n))) (defun defpm-clk-bound ,FORMALS (let ((defpm-n (defpm-clk-wit ,@FORMALS))) (and (natp defpm-n) (defpm-clk-rec ,@FORMALS defpm-n) defpm-n))) (defun defpm-clk ,FORMALS (let ((defpm-n (defpm-clk-bound ,@FORMALS))) (and defpm-n (- defpm-n (defpm-clk-rec ,@FORMALS defpm-n))))) (defthm defpm-clk-rec-decreases (implies (natp defpm-n) (<= (defpm-clk-rec ,@FORMALS defpm-n) defpm-n)) :rule-classes :linear) (defthm defpm-clk-0-implies-test-lemma-1 (implies (and (natp defpm-n) (natp defpm-m) (defpm-clk-rec ,@FORMALS defpm-n) (defpm-clk-rec ,@FORMALS defpm-m)) (equal (- defpm-n (defpm-clk-rec ,@FORMALS defpm-n)) (- defpm-m (defpm-clk-rec ,@FORMALS defpm-m)))) :rule-classes nil) (defthm defpm-clk-suff (implies (and (defpm-clk-rec ,@FORMALS defpm-n) (natp defpm-n)) (defpm-clk ,@FORMALS)) :hints (("Goal" :use defpm-clk-wit))) (defthm defpm-tailrec-lemma-1 (implies (and (defpm-clk ,@FORMALS) (not (,TEST ,@FORMALS))) (defpm-clk ,@STEP-CALLS)) :hints (("Goal" :in-theory (disable defpm-clk) :expand ((defpm-clk ,@FORMALS) (defpm-clk-rec ,@FORMALS (defpm-clk-wit ,@FORMALS)))))) (defthm defpm-tailrec-lemma-2 (implies (and (posp defpm-clk) (defpm-clk-rec ,@FORMALS (+ -1 defpm-clk))) (equal (defpm-clk-rec ,@FORMALS (+ -1 defpm-clk)) (1- (defpm-clk-rec ,@FORMALS defpm-clk))))) (defthm defpm-tailrec-lemma-3 (implies (and (posp defpm-clk) (defpm-clk-rec ,@FORMALS (+ -1 defpm-clk))) (defpm-clk-rec ,@FORMALS defpm-clk))) (defthm defpm-tailrec-lemma-4 (implies (and (defpm-clk ,@FORMALS) (not (,TEST ,@FORMALS))) (< (defpm-clk ,@STEP-CALLS) (defpm-clk ,@FORMALS))) :hints (("Goal" :expand ((defpm-clk ,@FORMALS) (defpm-clk-rec ,@FORMALS (defpm-clk-wit ,@FORMALS))) :use ((:instance defpm-clk-0-implies-test-lemma-1 ,@(PAIRLIS$ FORMALS (PAIRLIS$ STEP-CALLS NIL)) (defpm-m (defpm-clk-wit ,@FORMALS)) (defpm-n (defpm-clk-wit ,@STEP-CALLS)))))) :rule-classes :linear) (defthm defpm-terminates-step-lemma (implies (not (,TEST ,@FORMALS)) (implies (defpm-clk ,@STEP-CALLS) (defpm-clk ,@FORMALS))) :hints (("Goal" :in-theory (disable defpm-clk-suff) :use ((:instance defpm-clk-suff (defpm-n (1+ (defpm-clk-wit ,@STEP-CALLS))))))) :rule-classes nil) (defun ,MEASURE ,FORMALS (or (defpm-clk ,@FORMALS) 0)) (defun ,TERMINATES ,FORMALS (and (defpm-clk ,@FORMALS) t)))) (defthm ,TERMINATES-BASE (implies (,TEST ,@FORMALS) (,TERMINATES ,@FORMALS)) :hints (("Goal" :use ((:instance defpm-clk-wit (defpm-n 0)))))) (defthm ,TERMINATES-STEP (implies (not (,TEST ,@FORMALS)) (equal (,TERMINATES ,@STEP-CALLS) (,TERMINATES ,@FORMALS))) :hints (("Goal" :in-theory (disable defpm-clk) :use defpm-terminates-step-lemma))) (defthmd ,TERMINATES-STEP-COMMUTED (implies (and ,@(SYNTAXP-SYMBOLP-LST FORMALS) (not (,TEST ,@FORMALS))) (equal (,TERMINATES ,@FORMALS) (,TERMINATES ,@STEP-CALLS))) :hints (("Goal" :in-theory (disable defpm-clk) :use defpm-terminates-step-lemma))) (defthm ,MEASURE-TYPE (o-p (,MEASURE ,@FORMALS))) (defthm ,MEASURE-DECREASES (implies (and (,TERMINATES ,@FORMALS) (not (,TEST ,@FORMALS))) (o< (,MEASURE ,@STEP-CALLS) (,MEASURE ,@FORMALS))) :hints (("Goal" :in-theory (disable defpm-clk)))) ,@(AND THEORY `((DEFTHEORY ,THEORY '(,TERMINATES-BASE ,TERMINATES-STEP ,MEASURE-TYPE ,MEASURE-DECREASES)))))))
maybe-verbose-formfunction
(defun maybe-verbose-form (form verbose) (cond (verbose form) (t `(with-output :off :all :on (error) :gag-mode nil ,FORM))))
def-partial-measuremacro
(defmacro def-partial-measure (test step measure terminates theory &key (formals '(x)) (verbose 'nil)) (maybe-verbose-form (defpm-form test step measure terminates theory formals) verbose))
defpmmacro
(defmacro defpm (test step measure terminates theory &key (formals '(x) formals-p) (verbose 'nil verbose-p)) `(def-partial-measure ,TEST ,STEP ,MEASURE ,TERMINATES ,THEORY ,@(AND FORMALS-P `(:FORMALS ,FORMALS)) ,@(AND VERBOSE-P `(:VERBOSE ,VERBOSE))))
defpm-root-from-terminatesfunction
(defun defpm-root-from-terminates (terminates) (and (symbolp terminates) (let* ((term-string (symbol-name terminates)) (tsuff "-TERMINATES") (len-suff (length tsuff)) (len-term (length term-string))) (cond ((and (< len-suff len-term) (equal (subseq term-string (- len-term len-suff) len-term) tsuff)) (intern-in-package-of-symbol (subseq term-string 0 (- len-term len-suff)) terminates)) (t nil)))))
defthm-domain-formfunction
(defun defthm-domain-form (thm-name root test step terminates measure domain-term formals) (let* ((test (or test (defpm-add-suffix root "TEST"))) (step (or step (defpm-add-suffix root "STEP"))) (thm-name-fn (defpm-add-suffix thm-name "FN")) (thm-name-fn-main (defpm-add-suffix thm-name-fn "MAIN")) (thm-name-induction-hint (defpm-add-suffix thm-name "INDUCTION-HINT")) (steps (if (symbolp step) (if (cdr formals) (defpm-add-suffix-lst step formals) (list step)) step)) (step-calls (defpm-make-calls steps formals)) (test-call (cons test formals)) (terminates-base (defpm-add-suffix terminates "BASE")) (terminates-step (defpm-add-suffix terminates "STEP")) (domain-implies-terminates-base (defpm-add-suffix thm-name "BASE")) (domain-implies-terminates-step (defpm-add-suffix thm-name "STEP")) (step-preserves-domain (intern-in-package-of-symbol (concatenate 'string (symbol-name step) "-PRESERVES-" (symbol-name terminates)) step))) `(encapsulate nil (local (progn (defun ,THM-NAME-FN ,FORMALS (implies ,DOMAIN-TERM (,TERMINATES ,@FORMALS))) (defun ,THM-NAME-INDUCTION-HINT ,FORMALS (declare (xargs :measure ,MEASURE :hints (("Goal" :in-theory (enable ,TEST ,@STEPS))))) (if (or (not ,DOMAIN-TERM) ,TEST-CALL) (list ,@FORMALS) (,THM-NAME-INDUCTION-HINT ,@STEP-CALLS))) (defthm ,DOMAIN-IMPLIES-TERMINATES-BASE (implies (or (not ,DOMAIN-TERM) ,TEST-CALL) (,THM-NAME-FN ,@FORMALS)) :hints (("Goal" :in-theory (union-theories '(,THM-NAME-FN ,TERMINATES-BASE) (theory 'minimal-theory))))) (defthm ,STEP-PRESERVES-DOMAIN (implies (and ,DOMAIN-TERM (not ,TEST-CALL)) (let ,(PAIRLIS$ FORMALS (PAIRLIS$ STEP-CALLS NIL)) (declare (ignorable ,@FORMALS)) ,DOMAIN-TERM)) :hints (("Goal" :in-theory (enable ,TEST ,@STEPS))) :rule-classes nil) (defthm ,DOMAIN-IMPLIES-TERMINATES-STEP (implies (and (not ,TEST-CALL) (,THM-NAME-FN ,@STEP-CALLS)) (,THM-NAME-FN ,@FORMALS)) :hints (("Goal" :use ,STEP-PRESERVES-DOMAIN :in-theory (union-theories '(,TERMINATES-STEP ,THM-NAME-FN) (theory 'minimal-theory))))) (defthm ,THM-NAME-FN-MAIN (,THM-NAME-FN ,@FORMALS) :hints (("Goal" :induct (,THM-NAME-INDUCTION-HINT ,@FORMALS) :in-theory (union-theories '(,THM-NAME-INDUCTION-HINT ,DOMAIN-IMPLIES-TERMINATES-BASE ,DOMAIN-IMPLIES-TERMINATES-STEP) (theory 'minimal-theory)))) :rule-classes nil))) (defthm ,THM-NAME ,(LET ((TERM (CONS TERMINATES FORMALS))) (IF (EQ DOMAIN-TERM T) TERM `(IMPLIES ,DOMAIN-TERM ,TERM))) :hints (("Goal" :use ,THM-NAME-FN-MAIN :in-theory (union-theories '(,THM-NAME-FN) (theory 'minimal-theory))))))))
defthm-domainmacro
(defmacro defthm-domain (thm-name form &key root test step measure verbose) (mv-let (domain-term terminates formals) (case-match form (('implies domain-term (terminates . formals)) (mv domain-term terminates formals)) ((terminates . formals) (mv t terminates formals)) (& (mv (er hard! 'defthm-domain "Illegal form (see :doc defthm-domain):~|~x0" form) nil nil))) (let ((root (or root (defpm-root-from-terminates terminates)))) (prog2$ (or root (and test step) (er hard 'defthm-domain "Non-nil values are required in a defthm-domain either ~ for keyword :root or for for keywords :test and :step, ~ unless the termination predicate is a symbol whose name ~ ends in "-TERMINATES", for example, FOO-TERMINATES. ~ The following form has termination predicate ~x0 is ~ thus illegal:~|~x1" terminates form)) (maybe-verbose-form (defthm-domain-form thm-name root test step terminates measure domain-term formals) verbose)))))
local
(local (defmacro my-test (label &rest forms) `(encapsulate nil (deflabel ,LABEL) (local (progn ,@FORMS)))))
local
(local (my-test test1 (defstub defpm-test (x) t) (defstub defpm-step (x) t) (defpm defpm-test defpm-step defpm-measure defpm-terminates defpm-theory) (defun defpm-tailrec (x) (declare (xargs :measure (defpm-measure x) :hints (("Goal" :in-theory (union-theories (theory 'defpm-theory) (theory 'minimal-theory)))))) (if (defpm-terminates x) (if (defpm-test x) x (defpm-tailrec (defpm-step x))) x))))
local
(local (my-test test2 (defun trfact-test (x acc) (declare (ignore acc)) (equal x 0)) (defun trfact-step-x (x acc) (declare (ignore acc)) (1- x)) (defun trfact-step-acc (x acc) (* x acc)) (defpm trfact-test trfact-step trfact-measure trfact-terminates trfact-theory :formals (x acc)) (defun trfact-simple (x acc) (declare (xargs :measure (trfact-measure x acc) :hints (("Goal" :in-theory (union-theories (theory 'trfact-theory) (theory 'minimal-theory)))))) (if (trfact-terminates x acc) (if (trfact-test x acc) acc (trfact-simple (trfact-step-x x acc) (trfact-step-acc x acc))) acc)) (defun trfact (x acc) (declare (xargs :measure (trfact-measure x acc) :hints (("Goal" :use (trfact-measure-decreases trfact-measure-type) :in-theory (union-theories '(trfact-test trfact-step-x trfact-step-acc) (theory 'ground-zero)))))) (if (trfact-terminates x acc) (if (equal x 0) acc (trfact (1- x) (* x acc))) acc)) (defthm-domain trfact-terminates-holds-on-natp (implies (natp x) (trfact-terminates x acc)) :test trfact-test :step trfact-step :measure (nfix x)) (encapsulate nil (set-enforce-redundancy t) (defthm trfact-terminates-holds-on-natp (implies (natp x) (trfact-terminates x acc))))))
local
(local (my-test test3 (defund fact-test (x) (equal x 0)) (defund fact-step (x) (1- x)) (defpm fact-test fact-step fact-measure fact-terminates fact-theory) (defun fact (x) (declare (xargs :measure (fact-measure x) :hints (("Goal" :in-theory (union-theories (theory 'fact-theory) (theory 'minimal-theory)))))) (if (fact-terminates x) (if (fact-test x) 1 (* x (fact (fact-step x)))) 1)) (defthm-domain fact-terminates-holds-on-natp (implies (natp x) (fact-terminates x)) :measure (nfix x)) (encapsulate nil (set-enforce-redundancy t) (defthm fact-terminates-holds-on-natp (implies (natp x) (fact-terminates x)))) (defthm-domain fact-terminates-holds-on-natp (implies (natp x) (fact-terminates x)) :root fact :measure (nfix x)) (defthm fact-def (implies (force (natp x)) (equal (fact x) (if (fact-test x) 1 (* x (fact (fact-step x)))))) :hints (("Goal" :in-theory (union-theories '(fact fact-terminates-holds-on-natp) (theory 'minimal-theory)))) :rule-classes :definition)))
local
(local (my-test test4 (defund fact2-test (x) (declare (xargs :guard t)) (equal x 0)) (defund fact2-step (x) (declare (xargs :guard (natp x))) (1- x)) (defpm fact2-test fact2-step fact2-measure fact2-terminates fact2-theory) (defthm-domain fact2-terminates-holds-on-natp (implies (natp x) (fact2-terminates x)) :root fact2 :measure (nfix x)) (defthmd natp-fact2-step (implies (and (not (fact2-test x)) (natp x)) (natp (fact2-step x))) :hints (("Goal" :in-theory (enable fact2-test fact2-step)))) (defun fact2 (x) (declare (xargs :guard (natp x) :measure (fact2-measure x) :guard-hints (("Goal" :in-theory (union-theories '(natp-fact2-step fact2-terminates-holds-on-natp) (union-theories (theory 'fact2-theory) (theory 'minimal-theory))))) :hints (("Goal" :in-theory (union-theories (theory 'fact2-theory) (theory 'minimal-theory)))))) (mbe :logic (if (fact2-terminates x) (if (fact2-test x) 1 (* x (fact2 (fact2-step x)))) 1) :exec (if (fact2-test x) 1 (* x (fact2 (fact2-step x))))))))