• Top
    • Documentation
    • Books
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
    • Proof-automation
    • Macro-libraries
    • ACL2
      • Theories
      • Rule-classes
        • Type-prescription
        • Rewrite
          • Force
          • Hide
          • Syntaxp
          • Free-variables
          • Bind-free
          • Loop-stopper
          • Backchain-limit
          • Double-rewrite
          • Rewrite-lambda-object
          • Rewriting-versus-cleaning-up-lambda-objects
          • Random-remarks-on-rewriting
          • Set-rw-cache-state
          • Case-split
          • Rewrite-lambda-object-actions
          • Syntactically-clean-lambda-objects-theory
          • Hands-off-lambda-objects-theory
          • Rewrite-lambda-objects-theory
          • Simple
          • Rewrite-stack-limit
          • Rewrite-equiv
          • Assume-true-false-aggressive-p
          • Remove-trivial-equivalences-enabled-p
          • Rewrite-lambda-modep
          • Rewrite-if-avoid-swap
          • Set-rw-cache-state!
          • Rw-cache-state
        • Meta
        • Linear
        • Definition
        • Clause-processor
        • Tau-system
        • Forward-chaining
        • Equivalence
        • Congruence
        • Free-variables
        • Executable-counterpart
        • Induction
        • Type-reasoning
        • Compound-recognizer
        • Rewrite-quoted-constant
        • Elim
        • Well-founded-relation-rule
        • Built-in-clause
        • Well-formedness-guarantee
        • Patterned-congruence
        • Rule-classes-introduction
        • Guard-holders
        • Refinement
        • Type-set-inverter
        • Generalize
        • Corollary
        • Induction-heuristics
        • Backchaining
        • Default-backchain-limit
      • Proof-builder
      • Recursion-and-induction
      • Hons-and-memoization
      • Events
      • Parallelism
      • History
      • Programming
      • Operational-semantics
      • Real
      • Start-here
      • Debugging
      • Miscellaneous
      • Output-controls
      • Macros
      • Interfacing-tools
    • Interfacing-tools
    • Hardware-verification
    • Software-verification
    • Math
    • Testing-utilities
  • Rule-classes

Rewrite

Make some :rewrite rules (possibly conditional ones)

See rule-classes for a general discussion of rule classes, including how they are used to build rules from formulas and a discussion of the various keywords in a rule class description.

This doc topic discusses the rule-class :rewrite. If you want a general discussion of how rewriting works in ACL2 and some guidance on how to construct effective rewrite rules, see introduction-to-rewrite-rules-part-1 and then see introduction-to-rewrite-rules-part-2. If you want a flexible, convenient interface to the ACL2 rewriter that can be called programmatically, see rewrite$.

Examples:

(defthm plus-commutes                 ; Replace (+ a b) by (+ b a) provided
  (equal (+ x y) (+ y x)))            ; certain heuristics approve the
                                      ; permutation.

(defthm plus-commutes                 ; equivalent to the above
  (equal (+ x y) (+ y x))
  :rule-classes ((:rewrite :corollary (equal (+ x y) (+ y x))
                           :loop-stopper ((x y binary-+))
                           :match-free :all)))

(defthm append-nil                    ; Replace (append a nil) by a, if
  (implies (true-listp x)             ; (true-listp a) rewrites to t.
           (equal (append x nil) x)))

(defthm append-nil                    ; as above, but with defaults and
  (implies (true-listp x)             ; a backchain limit
           (equal (append x nil) x))
  :rule-classes ((:rewrite :corollary (implies (true-listp x)
                                               (equal (append x nil) x))
                           :backchain-limit-lst (3) ; or equivalently, 3
                           :match-free :all)))

(defthm member-append                 ; Replace (member e (append b c)) by
  (implies                            ; (or (member e b) (member e c) in
   (and                               ; contexts in which propositional
    (true-listp x)                    ; equivalence is sufficient, provided
    (true-listp y))                   ; b and c are true-lists.
   (iff (member e (append x y))
        (or (member e x) (member e y)))))

General Form:
(and ...
     (implies (and ...hi...)
              (implies (and ...hk...)
                       (and ...
                            (equiv lhs rhs)
                            ...)))
     ...)

Note: One :rewrite rule class object might create many rewrite rules from the :corollary formula. To create the rules, we first translate the formula, expanding all macros (see trans) and also removing guard-holders. Next, we then flatten the and and implies structure of the formula; for example, if the hypothesis or conclusion is of the form (and (and term1 term2) term3), then we replace that by the ``flat'' term (and term1 term2 term3). (The latter is actually an abbreviation for the right-associated term (and term1 (and term2 term3)).) During this flattening process, we eliminate lambdas as necessary in order to continue flattening; one may think of this step as simply substituting to eliminate let, let*, and mv-let in order to expose more calls of implies and and. The result is a conjunction of formulas, each of the form

(implies (and h1 ... hn) concl)

where no hypothesis is a conjunction and concl is neither a conjunction nor an implication. If necessary, the hypothesis of such a conjunct may be vacuous. We then further coerce each concl into the form (equiv lhs rhs), where we continue to eliminate lambdas until we reach this form, and then we eliminate lambdas from the first argument of equiv but not the second argument. Here equiv is a known equivalence relation. If we do not reach an equivalence relation, even after eliminating lambdas, then we replace the resulting term, term by (iff term t), except that we replace (not term) by (iff term nil). By these steps we reduce the given :corollary to a sequence of conjuncts, each of which is of the form

(implies (and h1 ... hn)
         (equiv lhs rhs))

where equiv is a known equivalence relation and lhs has no lambdas. See equivalence for a general discussion of the introduction of new equivalence relations. At this point, we check whether lhs and rhs are the same term; if so, we cause an error, since this rule will loop. (But this is just a basic check; the rule could loop in other cases, for example if rhs is an instance of lhs; see loop-stopper.)

You can experiment by creating some rewrite rules using defthm and then using :pr to see how the rule was stored.

We create a :rewrite rule for each such conjunct, if possible, and otherwise cause an error. It is possible to create a rewrite rule from such a conjunct provided lhs is not a variable, a quoted constant, a let-expression, or a lambda application. Although it is legal to create a rewrite rule from an if-expression (if tst tbr fbr), note that the rewriter uses the truth or falsity of the test, tst, when rewriting the true and false branches tbr and fbr, respectively; so rewrite rules are most often unnecessary for if-expressions.

A :rewrite rule is used when any instance of the lhs occurs in a context in which the equivalence relation is an admissible congruence relation. First, we find a substitution that makes lhs equal to the target term. Then we attempt to relieve the instantiated hypotheses of the rule. Hypotheses that are fully instantiated are relieved by recursive rewriting. Hypotheses that contain ``free variables'' (variables not assigned by the unifying substitution) are relieved by attempting to guess a suitable instance so as to make the hypothesis equal to some known assumption in the context of the target. If the hypotheses are relieved, and certain restrictions that prevent some forms of infinite regress are met (see loop-stopper), the target is replaced by the instantiated rhs, which is then recursively rewritten.

ACL2's rewriting process has some optimizations, including the following.

  • The suggestion, above, that the rewriter looks through the goal clause for ``any instance of the lhs'' is not quite true. :Rewrite rules are never applied to quoted constants or any term inside a call of hide. If you want to rewrite a quoted constant use a :rewrite-quoted-constant rule.
  • The notion of ``a substitution that makes lhs equal to the target term'' is a bit more generous than the most straightforward such notion. Suppose for example that lhs is (f (+ 3 x)) and the target term is (f (+ 3 (g y)). (Aside: ACL2 deals in so-called translated terms, so since + is a macro, lhs and term would actually be (f (binary-+ '3 x)) and (f (binary-+ '3 (g y))); we will ignore this distinction, but if you want more information, see term.) Then of course, that substitution binds x to (g y). But now suppose that instead the target term is (f 10). You may be surprised to learn that the substitution binding x to 7 makes (f (+ 3 x)) equal to (f 10); for example, the rewrite rule (equal (f (+ x 3)) (h x))) would rewrite (f 10) to (h 7). This would also be the case if lhs were instead (f (+ x 3)). This sort of optimization occurs when the new constant has ACL2-count no greater than the old constant. There are similar optimizations for *, /, -, strings, symbols, and conses (for details see ACL2 source function one-way-unify1-quotep-subproblems).
  • When a term t1 is rewritten to a new term t2, the rewriter is then immediately applied to t2. On rare occasions you may find that you do not want this behavior, in which case you may wish to use a trick involving hide; see meta, near the end of that documentation.
  • When the hypotheses and right-hand side are rewritten, ACL2 does not really first apply the substitution and then rewrite; instead, as it rewrites those terms it looks up the already rewritten values of the bound variables. Sometimes you may want those bindings rewritten again, e.g., because the variables occur in slots that admit additional equivalence relations. See double-rewrite.

See introduction-to-rewrite-rules-part-1 and see introduction-to-rewrite-rules-part-2 for an extended discussion of how to create effective rewrite rules.

Subtopics

Force
Identity function used to force a hypothesis
Hide
Hide a term from the rewriter
Syntaxp
Attach a heuristic filter on a rule
Free-variables
Free variables in rules
Bind-free
To bind free variables of a rewrite, definition, or linear rule
Loop-stopper
Limit application of permutative rewrite rules
Backchain-limit
Limiting the effort expended on relieving hypotheses
Double-rewrite
Cause a term to be rewritten twice
Rewrite-lambda-object
rewriting lambda objects in :FN slots
Rewriting-versus-cleaning-up-lambda-objects
why change the default action on rewriting lambda objects
Random-remarks-on-rewriting
Some basic facts about the ACL2 rewriter
Set-rw-cache-state
Set the default rw-cache-state
Case-split
Like force but immediately splits the top-level goal on the hypothesis
Rewrite-lambda-object-actions
actions available when rewriting lambda objects
Syntactically-clean-lambda-objects-theory
how to specify syntactic cleaning of lambda objects
Hands-off-lambda-objects-theory
how to specify no modification of lambda objects
Rewrite-lambda-objects-theory
how to specify rewriting of lambda objects
Simple
:definition and :rewrite rules used in preprocessing
Rewrite-stack-limit
Limiting the stack depth of the ACL2 rewriter
Rewrite-equiv
Force ACL2 to perform substitution using a stylized equivalence hypothesis
Assume-true-false-aggressive-p
Control rewriter's use of the type-alist with IF calls
Remove-trivial-equivalences-enabled-p
Avoid removal of trivial equivalences during rewriting
Rewrite-lambda-modep
switch controlling rewriting of lambda objects
Rewrite-if-avoid-swap
Control rewriter's swapping of branches of IF calls
Set-rw-cache-state!
Set the default rw-cache-state non-locally
Rw-cache-state
The current rw-cache-state