Major Section: MISCELLANEOUS

So far we have used computed hints only to compute when a fixed set
of keys and values are to be used as a hint. But computed hints
can, of course, compute the set of keys and values. You might, for
example, write a hint that recognizes when a clause ``ought'' to be
provable by a `:BDD`

hint and generate the appropriate hint. You
might build in a set of useful lemmas and check to see if the clause
is provable `:BY`

one of them. You can keep all function symbols
disabled and use computed hints to compute which ones you want to
`:EXPAND`

. In general, you can write a theorem prover for use in
your hints, provided you can get it to do its job by directing our
theorem prover.

Suppose for example we wish to find every occurrence of an instance
of `(SWAP x)`

and provide the corresponding instance of
`ALL-SWAPS-HAVE-THE-PROPERTY`

. Obviously, we must explore the
clause looking for instances of `(SWAP x)`

and build the
appropriate instances of the lemma. We could do this in many
different ways, but below we show a general purpose set of utilities
for doing it. The functions are not defined in ACL2 but could be
defined as shown.

Our plan is: (1) Find all instances of a given pattern (term) in a
clause, obtaining a set of substitutions. (2) Build a set of
`:instance`

expressions for a given lemma name and set of
substitutions. (3) Generate a `:use`

hint for those instances when
instances are found.

The pair of functions below find all instances of a given pattern
term in either a term or a list of terms. The functions each return
a list of substitutions, each substitution accounting for one of the
matches of pat to a subterm. At this level in ACL2 substitutions
are lists of pairs of the form `(var . term)`

. All terms mentioned
here are presumed to be in translated form.

The functions take as their third argument a list of substitutions accumulated to date and add to it the substitutions produced by matching pat to the subterms of the term. We intend this accumulator to be nil initially. If the returned value is nil, then no instances of pat occurred.

(mutual-recursion (defun find-all-instances (pat term alists) (declare (xargs :mode :program)) (mv-let (instancep alist) (one-way-unify pat term) (let ((alists (if instancep (add-to-set-equal alist alists) alists))) (cond ((variablep term) alists) ((fquotep term) alists) (t (find-all-instances-list pat (fargs term) alists)))))) (defun find-all-instances-list (pat list-of-terms alists) (declare (xargs :mode :program)) (cond ((null list-of-terms) alists) (t (find-all-instances pat (car list-of-terms) (find-all-instances-list pat (cdr list-of-terms) alists))))))

Caveat: The following aside has nothing to do with computed hints. Does an
instance of `(CAR (CDR x))`

occur in `((LAMBDA (V) (CAR V)) (CDR A))`

?
It does if one beta-reduces the lambda-expression to `(CAR (CDR A))`

;
the appropriate substitution is to replace `x`

by `A`

. But the
definition of `find-all-instances`

above does *not* find this instance
because it does not do beta-reduction.

We now turn our attention to converting a list of substitutions into a list of lemma instances, each of the form

(:INSTANCE name (var1 term1) ... (vark termk))as written in

`:use`

hints. In the code shown above, substitutions
are lists of pairs of the form `(var . term)`

, but in lemma
instances we must write ``doublets.'' So here we show how to
convert from one to the other:
(defun pairs-to-doublets (alist) (declare (xargs :mode :program)) (cond ((null alist) nil) (t (cons (list (caar alist) (cdar alist)) (pairs-to-doublets (cdr alist))))))

Now we can make a list of lemma instances:

(defun make-lemma-instances (name alists) (declare (xargs :mode :program)) (cond ((null alists) nil) (t (cons (list* :instance name (pairs-to-doublets (car alists))) (make-lemma-instances name (cdr alists))))))

Finally, we can package it all together into a hint function. The
function takes a pattern, `pat`

, which must be a translated term,
the name of a lemma, `name`

, and a clause. If some instances of
`pat`

occur in `clause`

, then the corresponding instances of
`name`

are `:USE`

d in the computed hint. Otherwise, the hint does
not apply.

(defun add-corresponding-instances (pat name clause) (declare (xargs :mode :program)) (let ((alists (find-all-instances-list pat clause nil))) (cond ((null alists) nil) (t (list :use (make-lemma-instances name alists))))))The design of this particular hint function makes it important that the variables of the pattern be the variables of the named lemma and that all of the variables we wish to instantiate occur in the pattern. We could, of course, redesign it to allow ``free variables'' or some sort of renaming.

We could now use this hint as shown below:

(defthm ... ... :hints ((add-corresponding-instances '(SWAP x) 'ALL-SWAPS-HAVE-THE-PROPERTY clause)))The effect of the hint above is that any time a clause arises in which any instance of

`(SWAP x)`

appears, we add the corresponding
instance of `ALL-SWAPS-HAVE-THE-PROPERTY`

. So for example, if
Subgoal *1/3.5 contains the subterm `(SWAP (SWAP A))`

then this
hint fires and makes the system behave as though the hint:
("Subgoal *1/3.5" :USE ((:INSTANCE ALL-SWAPS-HAVE-THE-PROPERTY (X A)) (:INSTANCE ALL-SWAPS-HAVE-THE-PROPERTY (X (SWAP A)))))had been present.