Filtering...

remove-hyps

books/tools/remove-hyps

Included Books

other
(in-package "ACL2")
include-book
(include-book "xdoc/top" :dir :system)
other
(defxdoc remove-hyps
  :parents (proof-automation debugging)
  :short "Macro for defining a theorem with a minimal set of hypotheses"
  :long "<p>For a call of @(tsee defthm), @(tsee defthmd), or @(tsee thm), the
 application of @('remove-hyps') attempts to produce a minimal set of
 hypotheses.  For example:</p>

 @({
 (remove-hyps
  (defthm nth-append
    (implies (and (true-listp x)
                  (natp n)
                  (true-listp y))
             (equal (nth n (append x y))
                    (if (< n (len x))
                        (nth n x)
                      (nth (- n (len x)) y))))
    :rule-classes nil))
 })

 <p>generates:</p>

 @({
 (DEFTHM NTH-APPEND
   (IMPLIES (NATP N)
            (EQUAL (NTH N (APPEND X Y))
                   (IF (< N (LEN X))
                       (NTH N X)
                     (NTH (- N (LEN X)) Y))))
   :RULE-CLASSES NIL)
 })

 <p>Note however that @('remove-hyps') works by removing one hypothesis at a
 time, with each resulting proof attempt made using a limited number of
 steps (see @(see with-prover-step-limit)) that depends on the number of steps
 taken before removing the hypothesis.  So if the removal of a hypothesis
 requires a proof that takes sufficiently many more steps than the original
 proof, or if two or more hypotheses must be removed together for the proof to
 succeed with fewer hypotheses, then the result will not have a minimal set of
 hypotheses.</p>

 <p>Acceptable forms are as follows, where @('HYP') can be a conjunction of
 hypotheses, @('(and HYP1 ... HYPn)'), and ``@('defthm NAME')'' may be
 replaced by ``@('defthmd NAME')'' or ``@('THM')''.</p>

 @({
 (defthm NAME (implies HYP CONCL) ...)
 (defthm NAME CONCL ...)
 (defthm NAME (let ... (implies HYP CONCL)) ...)
 (defthm NAME (let ... CONCL) ...)
 (defthm NAME (let* ... (implies HYP CONCL)) ...)
 (defthm NAME (let* ... CONCL) ...)
 })

 <p>Normally, before using @('remove-hyps'), one succesfully submits the given
 call of @('defthm'), @('defthmd'), or @('thm').  Thus by default,
 @('remove-hyps') evaluates silently.  To see output from proof attempts, add a
 non-nil optional argument.  For example, for event @('E'), use @('(remove-hyps
 E t)').</p>

 <p>Unless there is an error (for example, due to malformed input), then in the
 case of a call of @('thm'), the value returned is the keyword,
 @(':REMOVE-HYPS-COMPLETED'); otherwise, the value returned is the name of the
 theorem.  (Technically, the value returned is an error triple with such a
 value; see @(see error-triple).)</p>

 <p>Consider the case that a call of @('remove-hyps') is made in a context
 where proofs are normally skipped (see @(see ld-skip-proofsp)).  If this
 happens while including a certified book with @(tsee include-book), then
 proofs will indeed be skipped, because the earlier result of this
 @('remove-hyps') call was saved in the book's @(see certificate).  But
 otherwise, the tool temporarily turns off the skipping of proofs (that is,
 restores the act of doing proofs) while it tries to remove hypotheses, to
 avoid the undesirable situation that all hypotheses are removed merely because
 all proofs succeed when skipping proofs.</p>

 <p>Finally, note that when @('remove-hyps') is applied to a call of
 @('defthm') or @('defthmd'), then @('remove-hyps') will conclude by submitting
 the generated event to ACL2.  But since @('thm') does not modify the logical
 @(tsee world), @('remove-hyps') does not perform an extra such call at the end
 for calls of @('thm').</p>")
other
(set-state-ok t)
other
(program)
remove-hyps-formula-stepsfunction
(defun remove-hyps-formula-steps
  (steps)
  (min *default-step-limit* (+ 1000 (* 3 steps))))
dumb-implicatefunction
(defun dumb-implicate
  (hyps concl)
  (cond ((null hyps) concl)
    ((null (cdr hyps)) `(implies ,(CAR HYPS) ,CONCL))
    (t `(implies (and ,@HYPS) ,CONCL))))
make-defthmfunction
(defun make-defthm
  (deft name hyps concl kwd-alist let/let* bindings)
  (let* ((form0 (dumb-implicate hyps concl)) (form (if bindings
          `(,LET/LET* ,BINDINGS
            (declare (ignorable ,@(STRIP-CARS BINDINGS)))
            ,FORM0)
          form0)))
    (if (null name)
      (assert$ (eq deft 'thm) `(thm ,FORM ,@KWD-ALIST))
      `(,DEFT ,NAME ,FORM ,@KWD-ALIST))))
event-stepsfunction
(defun event-steps
  (form verbose-p extra-forms state)
  (let ((new-form `(with-output :stack :push :off :all :gag-mode nil
         (progn (make-event (pprogn (f-put-global 'our-steps nil state)
               (value '(value-triple nil))))
           ,(IF VERBOSE-P
     `(WITH-OUTPUT :STACK :POP ,FORM)
     FORM)
           (make-event (pprogn (f-put-global 'our-steps
                 (or (last-prover-steps state) 1)
                 state)
               ,@EXTRA-FORMS
               (value '(value-triple nil))))
           (defconst *bad*)))))
    (er-progn (trans-eval new-form 'event-steps state t)
      (value (f-get-global 'our-steps state)))))
remove-hyps-formula-1function
(defun remove-hyps-formula-1
  (name rev-init-hyps
    rest-hyps
    concl
    kwd-alist
    let/let*
    bindings
    steps
    verbose-p
    state)
  (cond ((endp rest-hyps) (value (reverse rev-init-hyps)))
    ((and (consp (car rest-hyps))
       (member-eq (caar rest-hyps) '(syntaxp bind-free synp))) (remove-hyps-formula-1 name
        (cons (car rest-hyps) rev-init-hyps)
        (cdr rest-hyps)
        concl
        kwd-alist
        let/let*
        bindings
        steps
        verbose-p
        state))
    (t (let ((form `(with-prover-step-limit ,STEPS
             ,(MAKE-DEFTHM 'DEFTHM NAME (REVAPPEND REV-INIT-HYPS (CDR REST-HYPS)) CONCL
  KWD-ALIST LET/LET* BINDINGS))))
        (er-let* ((event-steps (event-steps form verbose-p nil state)))
          (remove-hyps-formula-1 name
            (cond ((null event-steps) (cons (car rest-hyps) rev-init-hyps))
              (t rev-init-hyps))
            (cdr rest-hyps)
            concl
            kwd-alist
            let/let*
            bindings
            steps
            verbose-p
            state))))))
remove-hyps-formulafunction
(defun remove-hyps-formula
  (form name
    hyps
    concl
    kwd-alist
    let/let*
    bindings
    verbose-p
    ctx
    state)
  (do-proofs? t
    nil
    (mv-let (thmp name2 kwd-alist+)
      (assert$ (iff (eq (car form) 'thm) (null name))
        (if (null name)
          (mv t
            (gen-new-name 'remove-hyps-name (w state))
            (append kwd-alist '(:rule-classes nil)))
          (mv nil name kwd-alist)))
      (er-let* ((steps (event-steps (if thmp
               `(defthm ,NAME2 ,@(CDR FORM) :rule-classes nil)
               form)
             verbose-p
             nil
             state)))
        (cond ((null steps) (er soft ctx "Original theorem failed!"))
          (t (er-let* ((final-hyps (remove-hyps-formula-1 name2
                   nil
                   hyps
                   concl
                   kwd-alist+
                   let/let*
                   bindings
                   (remove-hyps-formula-steps steps)
                   verbose-p
                   state)))
              (value (if (equal (length hyps) (length final-hyps))
                  nil
                  (make-defthm (car form)
                    name
                    final-hyps
                    concl
                    kwd-alist
                    let/let*
                    bindings))))))))))
remove-hyps-fnfunction
(defun remove-hyps-fn
  (form name hyps concl kwd-alist let/let* bindings verbose-p)
  `(make-event (er-let* ((new-form (remove-hyps-formula ',FORM
           ',NAME
           ',HYPS
           ',CONCL
           ',KWD-ALIST
           ',LET/LET*
           ',BINDINGS
           ',VERBOSE-P
           'remove-hyps
           state)) (thmp (value (eq (car ',FORM) 'thm))))
      (pprogn (cond ((null new-form) (fms "Note: REMOVE-HYPS left its input unchanged.~|~@0"
              (list (cons #\0
                  (if thmp
                    ""
                    "Now silently submitting the original ~
                                         form.~|")))
              (standard-co state)
              state
              nil))
          (t (fms "New form from REMOVE-HYPS:~|~%~x0~|~%~@1"
              (list (cons #\0 new-form)
                (cons #\1
                  (if thmp
                    ""
                    "Now silently submitting the new ~
                                           form (above).~|")))
              (standard-co state)
              state
              nil)))
        (value (if thmp
            '(value-triple :remove-hyps-completed)
            (list 'with-output
              :off :all :gag-mode t
              (or new-form ',FORM))))))))
remove-hypsmacro
(defmacro remove-hyps
  (form &optional verbose-p)
  (or (and (consp form)
      (member-eq (car form) '(defthm defthmd thm))
      (mv-let (name form-without-name)
        (if (eq (car form) 'thm)
          (mv nil (cdr form))
          (mv (cadr form) (cddr form)))
        (case-match form-without-name
          ((('implies hyp concl) . kwd-alist) (let ((hyps (if (and (consp hyp) (eq (car hyp) 'and))
                   (cdr hyp)
                   (list hyp))))
              (remove-hyps-fn form
                name
                hyps
                concl
                kwd-alist
                nil
                nil
                verbose-p)))
          (((let/let* bindings ('implies hyp concl)) . kwd-alist) (and (member-eq let/let*
                '(let let*
                  b*))
              (let ((hyps (if (and (consp hyp) (eq (car hyp) 'and))
                     (cdr hyp)
                     (list hyp))))
                (remove-hyps-fn form
                  name
                  hyps
                  concl
                  kwd-alist
                  let/let*
                  bindings
                  verbose-p))))
          (& nil))))
    `(er soft
      'remove-hyps
      "Illegal argument to remove-hyps:~|~%~y0"
      ',FORM)))
other
(logic)
local
(local (include-book "arithmetic/top" :dir :system))
local
(local (remove-hyps (defthm nth-append
      (implies (and (true-listp x) (natp n) (true-listp y))
        (equal (nth n (append x y))
          (if (< n (len x))
            (nth n x)
            (nth (- n (len x)) y))))
      :rule-classes nil)))
other
(set-enforce-redundancy t)
local
(local (defthm nth-append
    (implies (natp n)
      (equal (nth n (append x y))
        (if (< n (len x))
          (nth n x)
          (nth (- n (len x)) y))))
    :rule-classes nil))
other
(set-enforce-redundancy nil)
local
(local (remove-hyps (defthm nth-append-alt
      (implies (and (true-listp x) (natp n) (true-listp y))
        (equal (nth n (append x y))
          (if (not (natp n))
            (car (append x y))
            (if (< n (len x))
              (nth n x)
              (nth (- n (len x)) y)))))
      :rule-classes nil)))
other
(set-enforce-redundancy t)
local
(local (defthm nth-append-alt
    (equal (nth n (append x y))
      (if (not (natp n))
        (car (append x y))
        (if (< n (len x))
          (nth n x)
          (nth (- n (len x)) y))))
    :rule-classes nil))
other
(set-enforce-redundancy nil)
local
(local (remove-hyps (defthm nth-append-alt-2
      (let ((xx x))
        (implies (and (true-listp xx) (natp n) (true-listp y))
          (equal (nth n (append xx y))
            (if (< n (len x))
              (nth n x)
              (nth (- n (len xx)) y)))))
      :hints (("Goal'" :induct t)))))
other
(set-enforce-redundancy t)
local
(local (defthm nth-append-alt-2
    (let ((xx x))
      (declare (ignorable xx))
      (implies (natp n)
        (equal (nth n (append xx y))
          (if (< n (len x))
            (nth n x)
            (nth (- n (len xx)) y)))))
    :hints (("Goal'" :induct t))))