other
(in-package "ACL2")
include-book
(include-book "xdoc/top" :dir :system)
include-book
(include-book "defmacroq")
other
(defxdoc make-termination-theorem :parents (termination-theorem history measure kestrel-utilities) :short "Create a copy of a function's termination theorem that calls stubs." :long "<p>The @(':')@(tsee termination-theorem) @(see lemma-instance) provides a way to re-use a recursive definition's termination (measure) theorem. You might find it convenient, however, to create a @('defthm') event for that theorem. Moreover, a termination theorem can mention the function symbol that is being defined, but it may be convenient to have a version of that theorem that instead mentions an unconstrained function symbol, which can support the use of @(see functional-instantiation).</p> <p>The form @('(make-termination-theorem f)') will create such a @('defthm') event, named @('F$TTHM'), with @(':')@(tsee rule-classes) @('nil'), whose body is the termination-theorem for @('f'), but modified to replace calls of @('f'). Here is a small example; for more extensive examples see @(see community-book) @('kestrel/utilities/make-termination-theorem-tests.lisp'). Suppose we submit the following definition.</p> @({ (defun f (x) (if (consp x) (and (f (caar x)) (f (cddr x))) x)) }) <p>Here is the termination-theorem for @('f').</p> @({ ACL2 !>:tthm f (AND (O-P (ACL2-COUNT X)) (OR (NOT (CONSP X)) (O< (ACL2-COUNT (CAR (CAR X))) (ACL2-COUNT X))) (OR (NOT (CONSP X)) (NOT (F (CAR (CAR X)))) (O< (ACL2-COUNT (CDDR X)) (ACL2-COUNT X)))) ACL2 !> }) <p>We now create the corresponding @('defthm') event shown below.</p> @({ ACL2 !>(make-termination-theorem f) Summary Form: ( MAKE-EVENT (ER-LET* ...)) Rules: NIL Time: 0.01 seconds (prove: 0.00, print: 0.00, other: 0.01) (DEFTHM F$TTHM (AND (O-P (ACL2-COUNT X)) (OR (NOT (CONSP X)) (O< (ACL2-COUNT (CAR (CAR X))) (ACL2-COUNT X))) (OR (NOT (CONSP X)) (NOT (F$STUB (CAR (CAR X)))) (O< (ACL2-COUNT (CDDR X)) (ACL2-COUNT X)))) :HINTS (("Goal" :USE (:TERMINATION-THEOREM F ((F F$STUB))) :IN-THEORY (THEORY 'MINIMAL-THEORY))) :RULE-CLASSES NIL) ACL2 !> }) <p>Notice that the call of @('f') in the termination-theorem has been replaced, in the @('defthm') form above, by a new function symbol, @('f$stub'). That new symbol was introduced using @(tsee defstub), which has no constraints, thus easing the application of @(see functional-instantiation) to this theorem.</p> @({ General Form: (make-termination-theorem Fun :subst S ; default described below :thm-name N ; default Fun$TTHM :rule-classes R ; default nil :verbose Vflg ; default nil :show-only Sflg ; default nil ) }) <p>where no keyword argument is evaluated unless wrapped in @(':eval'), as @('make-termination-theorem') is defined with @('defmacroq'); see @(see defmacroq). Evaluation of this form produces a @(tsee defthm) event based on the @(see termination-theorem) of @('Fun'), taking into account the arguments as follows.</p> <ul> <li>@('Fun') is a function symbol defined by recursion (possibly @(tsee mutual-recursion)).</li> <li>@('S') is a functional substitution, that is, a list of 2-element lists of symbols @('(fi gi)'). For each symbol @('gi') that is not a function symbol in the current @(see world), a suitable @(tsee defstub) event will be introduced for @('gi'). If @('Fun') is singly recursive then there will be a single such pair @('(Fun g)'); otherwise @('Fun') is defined by @(tsee mutual-recursion) and each @('fi') must have been defined together with @('Fun'), in the same @('mutual-recursion') form. If @(':subst') is omitted then each suitable function symbol @('f') — that is, @('Fun') as well as, in the case of mutual recursion, the others defined with @('Fun') — is paired with the result of adding the suffix @('"$STUB"') to the @(see symbol-name) of @('f').</li> <li>@('R') is the @(':')@(tsee rule-classes) argument of the generated @('defthm') event.</li> <li>Output is mostly suppressed by default, but is enabled when @('Vflg') is not @('nil').</li> <li>If @('Sflg') is not @('nil'), then the generated @('defthm') event @('EV') will not be submitted; instead, it will be returned in an error-triple @('(mv nil EV state)').</li> </ul>")
other
(program)
other
(set-state-ok t)
make-termination-theorem-substfunction
(defun make-termination-theorem-subst (fns) (cond ((endp fns) nil) (t (cons (list (car fns) (add-suffix (car fns) "$STUB")) (make-termination-theorem-subst (cdr fns))))))
make-termination-theorem-defstub-eventsfunction
(defun make-termination-theorem-defstub-events (subst wrld) (cond ((endp subst) nil) ((function-symbolp (cadar subst) wrld) (make-termination-theorem-defstub-events (cdr subst) wrld)) (t (cons `(defstub ,(CADAR SUBST) ,(FORMALS (CAAR SUBST) WRLD) t) (make-termination-theorem-defstub-events (cdr subst) wrld)))))
make-termination-theorem-fnfunction
(defun make-termination-theorem-fn (fn subst subst-p thm-name rule-classes verbose wrld ctx state) (let ((fn-nest (and (symbolp fn) (getpropc fn 'recursivep nil wrld))) (thm-name (or thm-name (add-suffix fn "$TTHM")))) (cond ((null fn-nest) (er soft ctx "The first argument, ~x0, is not a recursively defined function ~ symbol." fn)) ((and subst-p (not (doublet-style-symbol-to-symbol-alistp subst))) (er soft ctx "The :subst argument, is not a list of pairs of the form (old-sym ~ new-sym)" subst)) ((and subst-p (not (subsetp-eq (strip-cars subst) fn-nest))) (cond ((null (cdr fn-nest)) (er soft ctx "The :subst argument has key ~x0, which should be ~x1." (caar subst) fn)) (t (er soft ctx "The keys of the substitution specified by :subst must all be ~ introduced in the same mutual-recursion as the given function ~ symbol, ~x0. But this fails for ~&1." fn (set-difference-eq (strip-cars subst) fn-nest))))) (t (let* ((subst (if subst-p subst (make-termination-theorem-subst fn-nest))) (tformula (sublis-fn-simple (pairlis$ (strip-cars subst) (strip-cadrs subst)) (termination-theorem fn wrld))) (formula (untranslate tformula t wrld)) (thm `(defthm ,THM-NAME ,FORMULA :hints (("Goal" :use (:termination-theorem ,FN ,SUBST) :in-theory (theory 'minimal-theory))) :rule-classes ,RULE-CLASSES))) (value `(with-output :off :all :gag-mode nil :on error :stack :push (progn ,@(MAKE-TERMINATION-THEOREM-DEFSTUB-EVENTS SUBST WRLD) ,(IF VERBOSE `(WITH-OUTPUT :STACK :POP ,THM) THM) (value-triple ',THM)))))))))
other
(defmacroq make-termination-theorem (fn &key (subst 'nil subst-p) thm-name rule-classes verbose show-only) `(make-event (er-let* ((event (make-termination-theorem-fn ,FN ,SUBST ,SUBST-P ,THM-NAME ,RULE-CLASSES ,VERBOSE (w state) 'make-termination-theorem state))) (if ,SHOW-ONLY (value `(value-triple ',EVENT)) (value event)))))