;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Computed Hints Enhancements ;; ;; Jun Sawada ;; sawada@cs.utexas.edu ;; University of Texas at Austin, 1999 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (in-package "ACL2") (program) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; use-hint-always: Apply hints whenever possible. ; ; This hint fires always. ; (defthm thm-name body ; :hints ((use-hint-always (:cases '((< 0 b)))))) ; ; This hint looks like a hint supplied to "Goal", but it is not ; exactly the same. If you supply more than one hints for "Goal", ; only one hint is applied, and the other will never be applied. ; Use-hint-always applies the hint whenever it is allowed to. For ; example, if you want to case-split on the condition (equal x 0), ; and then, for each case, you want to case-split on the condition ; (equal y 0), you can write a hint like ; ; (defthm thm-name body ; :hints ((use-hint-always :cases '((equal x 0))) ; (use-hint-always :cases '((equal y 0))))) ; ; Computational hints are removed once it is applied. So ; use-hint-always never keep applying its hint. (Should have been ; named use-hint-whenever-possible or something.) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro use-hint-always (&rest hint) `',hint) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; When-occur: Find an term occurence and fire the hint. ; ; When term is found in the goal clause, hint is invoked. An example ; usage follows: ;:hints ((when-occur (FETCHED-INST MT (MT-FINAL-ISA MT) ; (MT-IN-SPECULTV? MT)) ; :cases ((b1p (MT-IN-SPECULTV? MT))))) ; ; The case split is performed when the expression (FETCHED-INST ...) ; is found. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-occur (term &rest hint) `(and (occur-lst ',term clause) ',hint)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; When-occur-&: Find an term occurence and try another computed hint. ; ; Compination version of When-occur. User can combine more than ; one combination version of computation hints. For example you can ; apply hint like: ; hints ((when-occur-& (foo x) ; (when-occur (bar x) :cases ((b1p (MT-IN-SPECULTV? MT))))) ; This applies only when both (foo x) and (bar x) appears in the ; goal. You can combine unlimited number of computed hints macros. ; Combined computed hint macros should end with a non combination ; version just like in the example shown above. Unless the all ; computed hint conditions are met and the hint is actually fired, ; the computed hint is not elimiated from the hint list. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-occur-& (term hint) `(and (occur-lst ',term clause) ,hint)) ;(defun multiple-occur-check (terms) ; (if (endp terms) ; nil ; (if (endp (cdr terms)) ; `(occur-lst ',(car terms) clause) ; `(and (occur-lst ',(car terms) clause) ; ,(multiple-occur-check (cdr terms)))))) ;(defmacro when-multiple-occur (terms &rest hint) ; `(and ,(multiple-occur-check terms) ',hint)) (defun multiple-occur-check (terms clause) (if (endp terms) nil (if (endp (cdr terms)) (occur-lst (car terms) clause) (and (occur-lst (car terms) clause) (multiple-occur-check (cdr terms) clause))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; when-multiple-occur: Fire hint when multiple terms appear in the ; clause ; ; Example: ; (defthm p-is-true-2 (p z) ; :hints ((when-multiple-occur ((buz x) (bar x)) ; :use (:instance bar-or-buz (x z))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-multiple-occur (terms &rest hint) `(and (multiple-occur-check ',terms clause) ',hint)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Combination version of when-multiple-occur ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-multiple-occur-& (terms hint) `(and (multiple-occur-check ',terms clause) ,hint)) ;; This is from ACL2 manual ;; This function print out the used computed hints to the display. ;; This function is helpful to debug computed hints. ;; Usage: ;; (defthm .... ;; :hints (... (show-hint ) ....)) (defmacro show-hint (hint &optional marker) (cond ((and (consp hint) (stringp (car hint))) hint) (t `(let ((marker ,marker) (ans ,(if (symbolp hint) `(,hint id clause world) hint))) (if ans (prog2$ (cw "~%***** Computed Hint~#0~[~/ (from hint ~x1)~]****~%~x2~%~%" (if (null marker) 0 1) marker (cons (string-for-tilde-@-clause-id-phrase id) ans)) ans) nil))))) ; ; Pattern match functions ; ; do not check if x is a cons. (defun fmeta-varp (x) (and (equal (car x) '@) (symbolp (cadr x)))) (defun fmeta-var-name (x) (cadr x)) (defmacro mv2-or (first second) `(mv-let (flg val) ,first (if flg (mv flg val) ,second))) ; restriction on pattern matching. ; We don't look into quoted constants. Quoted constants should be literally ; equal to the pattern or match to a meta-variable as it is. ; Pattern Match returns the substitution for the outer-most matching pattern. ; There may be more than two subterms that match the same pattern. (mutual-recursion (defun pattern-match (pattern term subst) (cond ((variablep pattern) (if (eq pattern term) (mv t subst) (mv nil nil))) ((fquotep pattern) (if (equal pattern term) (mv t subst) (mv nil nil))) ((fmeta-varp pattern) (let ((inst (assoc-eq (fmeta-var-name pattern) subst))) (if inst (if (equal term (cdr inst)) (mv t subst) (mv nil nil)) (mv t (cons (cons (fmeta-var-name pattern) term) subst))))) ((and (not (variablep term)) (not (fquotep term)) (eq (ffn-symb pattern) (ffn-symb term))) (pattern-match-lst (fargs pattern) (fargs term) subst)) (t (mv nil nil)))) (defun pattern-match-lst (patterns terms subst) (cond ((and (null patterns) (null terms)) (mv t subst)) ((or (null patterns) (null terms)) (mv nil nil)) (t (mv-let (flg new-subst) (pattern-match (car patterns) (car terms) subst) (if flg (pattern-match-lst (cdr patterns) (cdr terms) new-subst) (mv nil nil)))))) ) (mutual-recursion (defun pattern-occur (pattern term subst) (if (or (variablep term) (fquotep term)) (pattern-match pattern term subst) (mv2-or (pattern-match pattern term subst) (pattern-occur-lst pattern (fargs term) subst)))) (defun pattern-occur-lst (patterns args subst) (cond ((null args) (mv nil nil)) (t (mv2-or (pattern-occur patterns (car args) subst) (pattern-occur-lst patterns (cdr args) subst))))) ) (mutual-recursion (defun subst-meta (pattern subst) (cond ((or (variablep pattern) (fquotep pattern)) pattern) ((fmeta-varp pattern) (let ((inst (assoc-eq (fmeta-var-name pattern) subst))) (if inst (cdr inst) pattern))) (t (subst-meta-lst pattern subst)))) (defun subst-meta-lst (patterns subst) (if (null patterns) nil (cons (subst-meta (car patterns) subst) (subst-meta-lst (cdr patterns) subst)))) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; when-pattern: Fire hint when a pattern appears in the current ; clause ; ; The pattern is provided with an expression including ; "meta-variables". Meta variables is denoted by a list of symbol @ ; and another symbol. For example (f x (@ x)) matches a term ; (f x z), by substituting z for (@ x). The computed hint: ; ; (defthm f-of-f-of-x (f (f y)) ; :hints ((when-pattern (f (@ z)) ; :use (:instance f-is-true (x (@ z)))))) ; ; is applied when a pattern (f (@ z)) is found. Before applying the ; hint, the meta-variables in the hints are replaced with the ; corresponding expression. In the example above, (f (f y)) matches ; (f (@ z)) and we use the lemma f-is-true with the substitution ; (f y) for x. ; ; Note: we do not provide the combination version of when-pattern ; hints. Variable substitution makes its implementation difficult. ; Users are recommended to put the when-pattern macro at the end ; of combined hints. For example: ; (defthm f-iterated-2 ; (and (f x) (f (f x)) (f (f (f x)))) ; :hints ((when-not-GS-match-& ((0) nil . 0) ; (when-pattern (f (@ v)) ; :use ((:instance f-is-true ((x (@ v))))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-pattern (term &rest hint) `(mv-let (flg subst) (pattern-occur-lst ',term clause nil) (if flg (subst-meta ',hint subst) nil))) (defun multiple-pattern-check (terms) (if (endp terms) nil (if (endp (cdr terms)) `(pattern-occur-lst ',(car terms) clause nil) `(mv-let (flg subst) ,(multiple-pattern-check (cdr terms)) (if flg (pattern-occur-lst ',(car terms) clause subst) (mv nil nil)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; When-multi-patterns: Apply hints when a multiple pattern ; matches to (possibly distinct) subexpressions of the clause. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-multi-patterns (terms &rest hint) `(mv-let (flg subst) ,(multiple-pattern-check (reverse terms)) (if flg (subst-meta ',hint subst) nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; when-GS-match: Apply hints when the goal spec match the pattern. ; ; The hint is applied to any subgoal whose goal spec falls into the ; given pattern. For example: ; ; (defthm f-iterated ; (and (f x) (f (f x)) (f (f (f x)))) ; :hints ((when-GS-match ((0) (*) . 0) :in-theory (enable f-is-true)))) ; ; This hint fires for any "Subgoal n" where n is arbitrary positive ; integer. The goal spec is specified with clause ID with wild cards. ; It is better to give a number of examples to illustrate how to use ; clause ID with wild cards. ; ; (* * . *) Any goal-specs ; ((0 1 2) * 2) "Subgoal *1.2/n0.n1....ni'' ; ((0) (1 2 *) . 0) "Subgoal *1.2.n" ; ((0) (1 2 . *) . 0) "Subgoal *1.2.n0.n1....ni ; ((3 *) (1 2) . *) "[3]Subgoal *n0/1.2'n' ; ; A wild card can be any natural number or a list of natural numbers. ; However, the clause ID is always of form ; ((m1 m2 ... mj) (n1 n2 ... ni) l) ; the wild card can match only a limited type of objects. For ; example, the first two * in goal pattern (* * . *) match lists of ; natural numbers, while the last * matches a natural number. ; See ACL2 manual for detailed ID clause document. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-GS-match (spec-pattern &rest hint) `(and (gs-pattern-match id ',spec-pattern) ',hint)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Combination version of when-GS-match. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-GS-match-& (spec-pattern hint) `(and (gs-pattern-match id ',spec-pattern) ,hint)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Complement version of when-GS-match. The hint is applied when ; the goal spec does not match the pattern. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-not-GS-match (spec-pattern &rest hint) `(and (not (gs-pattern-match id ',spec-pattern)) ',hint)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Combination version of when-not-GS-match ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-not-GS-match-& (spec-pattern hint) `(and (not (gs-pattern-match id ',spec-pattern)) ,hint)) (defun gsnum-pattern-match (id pattern) (or (equal pattern '*) (equal id pattern))) (defun gslist-pattern-match (id pattern) (if (atom pattern) (if (equal pattern '*) T (equal id pattern)) (if (atom id) nil (and (gsnum-pattern-match (car id) (car pattern)) (gslist-pattern-match (cdr id) (cdr pattern)))))) (defun gs-pattern-match (id pattern) (and (gslist-pattern-match (car id) (car pattern)) (gslist-pattern-match (cadr id) (cadr pattern)) (gsnum-pattern-match (cddr id) (cddr pattern)))) ;; Asserted or Disasserted (defmacro show-clause (hint) (cond ((and (consp hint) (stringp (car hint))) hint) (t `(let ((ans ,(if (symbolp hint) `(,hint id clause world) hint))) (prog2$ (cw "~%***** Computed Hint~x0~%~x1~%~%" clause (cons (string-for-tilde-@-clause-id-phrase id) ans)) (if ans ans nil)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; When-occur-positive. If a literal appeas positively in the target ; clause. ; When-occur-negative. If a literal appeas negatively in the target ; clause. ; ; The target clause is internally represeted as a disjunction of ; literals. A literal is an expression or a negation of an expression. ; When an expression is a literal, it is consider to appear in the ; clause positively. If the negation of an expression is a literal in ; the clause, it is consider to appear negatively. ; ; Consider following example: ; (defthm complex-lemma ; (and (implies (f x) (f (g x x))) ; (implies (h (h y)) (and (h y) (g x y))))) ; :hints ((when-occur-negative (h (h y)) ; :use (:instance h-h-x-is-false (x y))) ; (when-occur-positive (f (g x x)) ; :use (:insance f-is-true (x (g x x)))))) ; :rule-classes nil) ; ; From the body of the lemma, three clauses are generated ; ~ (f y) \/ (f (g x x)) ; ~ (h (h y)) \/ (h y) ; ~ (h (h y)) \/ (g x y) ; (f y) and (h (h y)) appear neagively in these clauses, and ; (f (g x x)) (h y) and (g x y) appear positvely. ; As a result h-h-x-is-false is applied to the second and the third ; clauses, while f-is-true is applied to the first clause. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-occur-positive (literal &rest hint) `(and (member-equal ',literal clause) ',hint)) (defmacro when-occur-negative (literal &rest hint) `(and (member-equal '(not ,literal) clause) ',hint)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Combination version of when-occur-positive and when-occur-negative ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-occur-positive-& (literal hint) `(and (member-equal ',literal clause) ,hint)) (defmacro when-occur-negative-& (literal hint) `(and (member-equal '(not ,literal) clause) ,hint)) (defun pattern-positive-p (lit clause subst) (if (endp clause) (mv nil nil) (mv2-or (pattern-match lit (car clause) subst) (pattern-positive-p lit (cdr clause) subst)))) (defun pattern-negative-p (lit clause subst) (if (endp clause) (mv nil nil) (mv2-or (pattern-match `(not ,lit) (car clause) subst) (pattern-negative-p lit (cdr clause) subst)))) (defun multi-patterns-positive-p (lts clause subst) (if (endp lts) (mv t subst) (mv-let (flag new-subst) (pattern-positive-p (car lts) clause subst) (if flag (multi-patterns-positive-p (cdr lts) clause new-subst) (mv nil nil))))) (defun multi-patterns-negative-p (lts clause subst) (if (endp lts) (mv t subst) (mv-let (flag new-subst) (pattern-negative-p (car lts) clause subst) (if flag (multi-patterns-negative-p (cdr lts) clause new-subst) (mv nil nil))))) (defun multi-patterns-asserted-p (plit nlit clause subst) (mv-let (flg new-subst) (multi-patterns-positive-p plit clause subst) (if flg (multi-patterns-negative-p nlit clause new-subst) (mv nil nil)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; when-pos/neg-occur ; Combined occurence of positive and negative clauses fire hint. ; ; Example ; :hints ((when-pos/neg-occur ((f x)) ((g x)) ; :use (g-implies-f))) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro when-pos/neg-occur (plit nlit &rest hint) `(mv-let (flg subst) (multi-patterns-asserted-p ',plit ',nlit clause nil) (if flg (subst-meta ',hint subst) nil)))