• Top
    • Documentation
    • Books
    • Recursion-and-induction
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
    • Proof-automation
      • Gl
      • Witness-cp
      • Ccg
      • Install-not-normalized
      • Rewrite$
      • Removable-runes
      • Efficiency
      • Rewrite-bounds
      • Bash
      • Def-dag-measure
      • Fgl
        • Fgl-rewrite-rules
          • Fgl-syntactic-checker-binders
          • Binder
          • Fancy-ev
          • Def-fgl-program
          • Bind-var
          • Add-fgl-brewrites
          • Def-fgl-rewrite
          • Narrow-equiv
          • Def-fgl-branch-merge
          • Add-fgl-rewrites
          • Fgl-interp-obj
          • Fgl-prog2
          • Collect-cmr-rewrites-for-formula-name
          • Syntax-bind
          • Fgl-time
          • Assume
          • Add-fgl-binder-meta
          • Add-fgl-primitive
          • Add-fgl-meta
          • Add-fgl-branch-merges
          • Cmr::rewritelist->lhses
          • Remove-fgl-brewrites
          • Remove-fgl-branch-merges
          • Lhses->branch-function-syms
          • Enable-execution
          • Abort-rewrite
          • Syntax-interp
          • Remove-fgl-rewrites
          • Lhses->leading-function-syms
          • Remove-fgl-primitive
          • Remove-fgl-binder-meta
          • If!
          • Disable-execution
          • Remove-fgl-meta
          • Fgl-time-fn
          • Disable-definition
          • Def-fgl-brewrite
        • Fgl-function-mode
        • Fgl-object
        • Fgl-solving
        • Fgl-handling-if-then-elses
        • Fgl-getting-bits-from-objects
        • Fgl-primitive-and-meta-rules
        • Fgl-interpreter-overview
        • Fgl-counterexamples
        • Fgl-correctness-of-binding-free-variables
        • Fgl-debugging
        • Fgl-testbenches
        • Def-fgl-boolean-constraint
        • Fgl-stack
        • Fgl-rewrite-tracing
        • Def-fgl-param-thm
        • Def-fgl-thm
        • Fgl-fast-alist-support
        • Advanced-equivalence-checking-with-fgl
        • Fgl-array-support
        • Fgl-internals
      • Bdd
      • Remove-hyps
      • Contextual-rewriting
      • Simp
      • Rewrite$-hyps
      • Bash-term-to-dnf
      • Use-trivial-ancestors-check
      • Minimal-runes
      • Clause-processor-tools
      • Fn-is-body
      • Without-subsumption
      • Rewrite-equiv-hint
      • Def-bounds
      • Rewrite$-context
      • Try-gl-concls
      • Hint-utils
    • Macro-libraries
    • ACL2
    • Interfacing-tools
    • Hardware-verification
    • Software-verification
    • Testing-utilities
    • Math
  • Fgl

Fgl-rewrite-rules

Differences between FGL and ACL2 rewrite rules

FGL rewrite rules are essentially just ACL2 rewrite rules. More specifically, they are derived from formulas that have basically the same form as ACL2 rewrite rules; they need not be stored with :rule-classes :rewrite. FGL uses a different set of rules than the ones that are enabled for use in ACL2, because not all good ACL2 rewrite rules are good FGL rewrite rules, and vice versa. A particularly important difference is that syntaxp and bind-free forms receive FGL symbolic objects as their inputs, rather than ACL2 terms. FGL rewrite rules also allow special constructs bind-var, binder, and syntax-bind which allow free variables to be bound as with bind-free, but in the RHS of the rewrite rule rather than in the hyps. They additionally support a form abort-rewrite which causes the application of the rule to be aborted when encountered in the RHS, similarly to if a hypothesis was not relieved.

Creating and Removing FGL Rewrite Rules

An FGL rewrite rule is an ACL2 rewrite rule. You can register an existing ACL2 theorem for use as an FGL rewrite rule using:

(fgl::add-fgl-rewrite my-rule)

And you can disable that rule for use by FGL using:

(fgl::remove-fgl-rewrite my-rule)

To create a new rewrite rule and enable it for FGL, you may use:

(fgl::def-fgl-rewrite my-rule
   body
  :hints ...)

This just expands to:

(defthmd my-rule ...)
(fgl::add-fgl-rewrite my-rule)

FGL also supports rewrite rules that are triggered not on the leading function symbol of the LHS, but on the leading function symbol of an if-then-else branch. These rules can be added using (fgl::add-fgl-branch-merge my-rule) and they can be created using:

(fgl::def-fgl-branch-merge my-rule
   body
   ...)

A suitable branch merge rule has a left-hand side of the form (if test then else) where then is a function call. Generally, test and else should be free variables, but this isn't a hard and fast rule.

Advanced Features

FGL rewrite rules support ACL2's syntaxp and bind-free hypothesis forms. However, it generally won't work to use the same rewrite rule in both the ACL2 and FGL rewriters if it has syntaxp or bind-free hypotheses, because in FGL the variables in the syntaxp/bind-free forms will be bound to symbolic objects, whereas in ACL2 they will be bound to terms. Therefore to use syntaxp, bind-free, and bind-var (discussed below), one needs to be familiar with FGL symbolic objects -- see fgl-object.

Two additional features support a new style of programming rewrite rules. Bind-var and syntax-bind allow functionality similar to bind-free, but available within the right-hand side of a rewrite rule. Abort-rewrite allows the rewrite operation to be cancelled partway through interpreting the right-hand side.

Here is an example that uses both syntax-bind and abort-rewrite, from "bitops.lisp":

(def-fgl-rewrite logtail-to-logtail-helper
  (implies (syntaxp (not (fgl-object-case n :g-concrete)))
           (equal (logtail n x)
                  (b* ((x (int x))
                       (n (nfix (int n)))
                       ((when (syntax-bind n-concrete (fgl-object-case n :g-concrete)))
                        (logtail n x))
                       (n-width (syntax-bind n-width (fgl-object-case n
                                                       :g-integer (max 0 (1- (len n.bits)))
                                                       :otherwise nil)))
                       ((unless (and n-width
                                     (check-unsigned-byte-p n-width n)))
                        (abort-rewrite (logtail n x)))
                       (n-rev (int-revapp n-width n 0)))
                    (logtail-helper n-rev n-width x)))))

When attempting to apply this rewrite rule, the FGL rewriter starts in much the same way as the ACL2 rewriter. As a precondition for attempting to apply this rule, the term we are rewriting must be a call of logtail, and that call must unify with the LHS of this rule -- in this case any call of logtail will do so.

Next, we relieve the hyps. This rule only has one hyp, which is a syntaxp call; we check that n is not a :g-concrete object.

Then we proceed by interpreting the RHS. We bind x to the result of rewriting (int x) (where int is an alias for ifix and rebind n to the result of rewriting (nfix (int n)), and then we encounter our first syntax-bind form. The syntax-bind form has the free variable n-concrete, which is here to logically represent the result we get from evaluating the syntax-bind form. A syntax-bind form is logically equivalent to its first argument, so when we prove logtail-to-logtail-helper correct we prove it with the free variable n-concrete in place of the syntax-bind. That means we are logically justified in returning anything we want from the syntax-bind form -- since n-concrete is a free variable not previously bound, the rule is applicable for any value of n-concrete. In this case we evaluate (fgl-object-case n :g-concrete). (Note: syntax-bind is a macro that uses the primitive forms bind-var and syntax-interp to implement this behavior; see their documentation for more general usage.) This will produce a Boolean value, which is a concrete FGL object representing itself. If true, then n is concrete and we will produce the result of again rewriting (logtail n x) -- note that we haven't created a loop here because the syntaxp hyp required that the original n was not concrete. Otherwise, we proceed with the next syntax-bind form.

This next syntax-bind form (note it must use a different free variable than the other form!) returns either some natural number value or else NIL. Again, either way it is a concrete object representing itself. We bind this to n-width. We then require that n-width is nonnil and that we can show n satisfies (unsigned-byte-p n-width n) (note: check-unsigned-byte-p is an alias for unsigned-byte-p which has rules that try to prove it cheaply). If not, then we come to an abort-rewrite form. When FGL arrives at an abort-rewrite form, it aborts the current rewrite rule attempt, ignoring the form inside the abort-rewrite. (In this case the form (logtail n x) inside the abort-rewrite was selected to make it easy to prove logtail-to-logtail-helper correct.) Otherwise, we go on with our rewrite.

Note we needed to know (unsigned-byte-p n-width n) in order to prove logtail-to-logtail-helper. The syntax-bind form produces the correct number, but while proving logtail-to-logtail-helper we don't know that. Fortunately, it's fairly efficient to verify that after the fact using check-unsigned-byte-p.

Examining the Interpreter State

FGL's implementation of syntaxp, bind-free, and syntax-bind interpret the syntactic term using a custom evaluator, fancy-ev, that can be instrumented to call functions that examine the ACL2 state and the FGL interpreter state, and even make limited modifications to them. See the documentation for fancy-ev for how to use it, and see fgl-interpreter-state for documentation of the contents of the interpreter state. One main use of this is to examine counterexamples produced from incremental SAT calls. By default, after loading fgl/top, the rewrite rule show-counterexample-rw rewrites the constant-nil function (show-counterexample msg) such that a syntax-bind form fetches the latest incremental SAT counterexample and prints it.

Subtopics

Fgl-syntactic-checker-binders
Functions for checking syntactic properties of objects, and inferring the logical properties that they imply
Binder
Form that can bind a free variable to the result of some (possibly nondeterministic) computation.
Fancy-ev
Term evaluator used by FGL for syntaxp, bind-free, and syntax-bind interpretation.
Def-fgl-program
Define a function that is logically just NIL but has special extralogical behavior in FGL.
Bind-var
Form that can bind a free variable to the result of an arbitrary computation.
Add-fgl-brewrites
Enable some binder rewrite rules for use in FGL
Def-fgl-rewrite
Define a rewrite rule for FGL to use on term-level objects
Narrow-equiv
FGL testbench function to interpret a term under a narrower (stricter) equivalence context.
Def-fgl-branch-merge
Define a rule for FGL to use in merging IF branches
Add-fgl-rewrites
Enable some rewrite rules for use in FGL
Fgl-interp-obj
FGL testbench function to interpret a term that is the result of evaluating some form.
Fgl-prog2
In the FGL interpreter, run the first form for side effects and return the result from the second form.
Collect-cmr-rewrites-for-formula-name
Syntax-bind
Form that can bind a free variable to a value computed from examining the syntax of other bound variables in the RHS of an FGL rewrite rule.
Fgl-time
FGL alternative to time$ that does not get elided by rewrite rule storage.
Assume
FGL testbench function to assume some condition while interpreting a term.
Add-fgl-binder-meta
Register a metafunction for use in rewriting binder invocations of a trigger function in FGL.
Add-fgl-primitive
Register a primitive function for use in rewriting calls of a trigger function in FGL.
Add-fgl-meta
Register a metafunction for use in rewriting calls of a trigger function in FGL.
Add-fgl-branch-merges
Enable some rewrite rules's use for branch merging in FGL.
Cmr::rewritelist->lhses
Remove-fgl-brewrites
Disable some binder rewrite rules' use in FGL.
Remove-fgl-branch-merges
Disable some rewrite rules' use for branch merging in FGL.
Lhses->branch-function-syms
Enable-execution
Enable the use of concrete execution of a function in FGL rewriting.
Abort-rewrite
Form that aborts the application of an FGL rewrite rule when encountered while processing the RHS of the rule.
Syntax-interp
Interpret a form on the syntactic representations of variables.
Remove-fgl-rewrites
Disable some rewrite rules' use in FGL.
Lhses->leading-function-syms
Remove-fgl-primitive
Deregister a primitive function for use in FGL.
Remove-fgl-binder-meta
Deregister a binder metafunction for use in FGL.
If!
Function implementing IF that under FGL interpretation makes a :g-ite object instead of doing the usual merging process.
Disable-execution
Disable the use of concrete execution of a function in FGL rewriting.
Remove-fgl-meta
Deregister a metafunction for use in FGL.
Fgl-time-fn
Disable-definition
Disable the use of the given formula in FGL rewriting.
Def-fgl-brewrite
Define a binder rewrite rule for FGL to use on term-level objects