• Top
    • Documentation
    • Books
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
    • Proof-automation
      • Gl
      • Witness-cp
      • Ccg
      • Install-not-normalized
      • Rewrite$
      • Fgl
        • Fgl-rewrite-rules
          • Binder-functions
          • Fgl-syntactic-checker-binders
          • Binder
          • Fancy-ev
          • Binder-rules
          • Def-fgl-program
          • Bind-var
          • Add-fgl-brewrites
          • Def-fgl-rewrite
          • Narrow-equiv
          • Def-fgl-branch-merge
          • Add-fgl-rewrites
          • Fgl-interp-obj
          • Syntax-bind
          • Collect-cmr-rewrites-for-formula-name
          • Fgl-time
          • Fgl-prog2
          • 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-counterexamples
        • Fgl-interpreter-overview
        • 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
        • Fgl-array-support
        • Advanced-equivalence-checking-with-fgl
        • Fgl-fty-support
        • Fgl-internals
      • Removable-runes
      • Efficiency
      • Rewrite-bounds
      • Bash
      • Def-dag-measure
      • 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
    • Math
    • Testing-utilities
  • 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.

Binding Free Variables

There are several ways in which variables not present in the LHS of the rule can become bound:

  • Bind-free hypotheses: similar to ACL2's bind-free, but sees existing variables' values as FGL objects and must bind new variables to FGL objects (see fgl-object), rather than ACL2 terms.
  • Binder functions: see bind-var, binder, and syntax-bind. Binder functions can also determine the values to be assigned to the free variables using rewriting; see binder-rules.
  • Equivalence-based binding hypotheses: a hypothesis of the form (equiv free-var form) where equiv is a known equivalence relation and free-var is a variable not bound in the current rewriting context. This will result in FGL rewriting form under equivalence relation equiv and binding the result to free-var.
  • Match-assums hypotheses: A hypothesis of the form (fgl::match-assums hyp) will look for an assumption in the current path condition that matches the form of hyp and binds any free variables in hyp accordingly. In more detail, for each Boolean variable in the interpreter's Boolean variable database whose associated object's leading function symbol is the same as that of hyp, we check whether that object unifies with hyp under the existing variable bindings, and if so whether that variable is currently assumed in the path condition. If so, we add the unifying subsitution to the current variable bindings.

Advanced Features

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 (integer-length-bound n-width n))
                       ((unless n-width)
                        (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 form.

The next form appears to bind (integer-length-bound n-width n) to n-width, which may appear mysterious since n-width is used in its own binding. This is because integer-length-bound is a binder-function intended to bind its first argument (which must be a free variable) to some value determined by the rest of its arguments. So here n-width is a free variable that will be bound to some value determined by examining n; the definition of integer-length-bound guarantees that that value is either a bound on the integer-length of n or is NIL. In fact, the value to be bound is derived in this case by a meta rule integer-length-bound-binder. In other cases it could be determined by a rewrite rule; see binder-rules.

We then require that n-width is nonnil, meaning we have found a good bound for the integer-length of n. If not, we have an abort-rewrite form which causes the current rewrite rule attempt to end, 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.

Last, we finish this rewrite: the point of this rule was to replace a call of logtail with a logtail-helper form which can be opened iteratively to create the symbolic value needed.

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

Binder-functions
Functions that describe constraints on bindings for free variables.
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.
Binder-rules
Determining free variable bindings using rewriting
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.
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.
Collect-cmr-rewrites-for-formula-name
Fgl-time
FGL alternative to time$ that does not get elided by rewrite rule storage.
Fgl-prog2
In the FGL interpreter, run the first form for side effects and return the result from the second form.
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