This is acl2-doc-emacs.info, produced by makeinfo version 4.13 from
acl2-doc-emacs.texinfo.

This is documentation for ACL2 Version 6.3
Copyright (C) 2013  University of Texas at Austin

This program is free software; you can redistribute it and/or modify
it under the terms of Version 2 of the GNU General Public License as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Written by:  Matt Kaufmann and J Strother Moore
Department of Computer Sciences
University of Texas at Austin
Austin, TX 78712-1188 U.S.A.

INFO-DIR-SECTION Math
START-INFO-DIR-ENTRY
* acl2: (acl2-doc-emacs). Applicative Common Lisp
END-INFO-DIR-ENTRY


File: acl2-doc-emacs.info,  Node: NOTE8,  Next: NOTE8-UPDATE,  Prev: NOTE7,  Up: RELEASE-NOTES

NOTE8    ACL2 Version 1.8 (May, 1995) Notes

See *note NOTE8-UPDATE:: for yet more recent changes.

Guards have been eliminated from the ACL2 logic.  A summary is
contained in this brief note.  Also see *note DEFUN-MODE:: and see
*note SET-GUARD-CHECKING::.

Guards may be included in defuns as usual but are ignored from the
perspective of admission to the logic: functions must terminate on all
arguments.

As in Nqthm, primitive functions, e.g., + and car, logically default
unexpected arguments to convenient values.  Thus, (+ 'abc 3) is 3 and
(car 'abc) is nil.  See *note PROGRAMMING::, and see the documentation
for the individual primitive functions.

In contrast to earlier versions of ACL2, Version 1.8 logical functions
are executed at Nqthm speeds even when guards have not been verified.
In versions before 1.8, such functions were interpreted by ACL2.

Colors have been eliminated.  Two "defun-modes" are supported, :program
and :logic.  Roughly speaking, :program does what :red used to do,
namely, allow you to prototype functions for execution without any
proof burdens.  :Logic mode does what :blue used to do, namely, allow
you to add a new definitional axiom to the logic.  A global
default-defun-mode is comparable to the old default color.  The system
comes up in :logic mode.  To change the global defun-mode, type
:program or :logic at the top-level.  To specify the defun-mode of a
defun locally use

     (declare (xargs :mode mode)).

The prompt has changed.  The initial prompt, indicating :logic mode, is

     ACL2 !>

If you change to :program mode the prompt becomes

     ACL2 p!>

Guards can be seen as having either of two roles: (a) they are a
specification device allowing you to characterize the kinds of inputs a
function "should" have, or (b) they are an efficiency device allowing
logically defined functions to be executed directly in Common Lisp.  If
a guard is specified, as with xargs :guard, then it is "verified" at
defun-time (unless you also specify xargs :verify-guards nil).  Guard
verification means what it always has: the input guard is shown to
imply the guards on all subroutines in the body.  If the guards of a
function are verified, then a call of the function on inputs satisfying
the guard can be computed directly by Common Lisp.  Thus, verifying the
guards on your functions will allow them to execute more efficiently.
But it does not affect their logical behavior and since you will
automatically get Nqthm speeds on unverified logical definitions, most
users will probably use guards either as a specification device or only
use them when execution efficiency is extremely important.

Given the presence of guards in the system, two issues are unavoidable.
Are guards verified as part of the defun process?  And are guards
checked when terms are evaluated?  We answer both of those questions
below.

Roughly speaking, in its initial state the system will try to verify
the guards of a defun if a :guard is supplied in the xargs and will not
try otherwise.  However, guard verification in defun can be inhibited
"locally" by supplying the xargs :verify-guards nil.  "Global"
inhibition can be obtained via the :set-verify-guards-eagerness.  If
you do not use the :guard xargs, you will not need to think about guard
verification.

We now turn to the evaluation of expressions.  Even if your functions
contain no guards, the primitive functions do and hence you have the
choice: when you submit an expression for evaluation do you mean for
guards to be checked at runtime or not?  Put another way, do you mean
for the expression to be evaluated in Common Lisp (if possible) or in
the logic?  Note: If Common Lisp delivers an answer, it will be the
same as in the logic, but it might be erroneous to execute the form in
Common Lisp.  For example, should (car 'abc) cause a guard violation
error or return nil?

The top-level ACL2 loop has a variable which controls which sense of
execution is provided.  To turn "guard checking on," by which we mean
that guards are checked at runtime, execute the top-level form
:set-guard-checking t.  To turn it off, do :set-guard-checking nil.
The status of this variable is reflected in the prompt.

     ACL2 !>

means guard checking is on and

     ACL2 >

means guard checking is off.  The exclamation mark can be thought of as
"barring" certain computations.  The absence of the mark suggests the
absence of error messages or unbarred access to the logical axioms.
Thus, for example

     ACL2 !>(car 'abc)

will signal an error, while

     ACL2 >(car 'abc)

will return nil.

Note that whether or not guards are checked at runtime is independent
of whether you are operating in :program mode or :logic mode and
whether theorems are being proved or not.  (Although it must be added
that functions defined in :program mode cannot help but check their
guards because no logical definition exists.)

Version 1.8 permits the verification of the guards of theorems, thus
insuring that all instances of the theorem will evaluate without error
in Common Lisp.  To verify the guards of a theorem named name execute
the event

     (verify-guards name).

If a theorem's guards have been verified, the theorem is guaranteed to
evaluate without error to non-nil in Common Lisp (provided resource
errors do not arise).

Caveat about verify-guards: implies is a function symbol, so in the
term (implies p q), p cannot be assumed true when q is evaluated; they
are both evaluated "outside."  Hence, you cannot generally verify the
guards on a theorem if implies is used to state the hypotheses.  Use if
instead.  In a future version of ACL2, implies will likely be a macro.

See sum-list-example.lisp for a nice example of the use of Version 1.8.
This is roughly the same as the documentation for guard-example.

We have removed the capability to do "old-style-forcing" as existed
before Version 1.5.  See *note NOTE5::.

NOTE:  Some low level details have, of course, changed.  One such
change is that there are no longer two distinct type prescriptions
stored when a function is admitted with its guards verified.  So for
example, the type prescription rune for binary-append is now

     (:type-prescription binary-append)

while in Versions 1.7 and earlier, there were two such runes:

     (:type-prescription binary-append . 1)
     (:type-prescription binary-append . 2)

Nqthm-style forcing on linear arithmetic assumptions is no longer
executed when forcing is disabled.

Functional instantiation now benefits from a trick also used in Nqthm:
once a constraint generated by a :functional-instance lemma instance
(see *note LEMMA-INSTANCE::) has been proved on behalf of a successful
event, it will not have to be re-proved on behalf of a later event.

1+ and 1- are now macros in the logic, not functions.  Hence, for
example, it is "safe" to use them on left-hand sides of rewrite rules,
without invoking the common warning about the presence of nonrecursive
function symbols.

A new documentation section file-reading-example illustrates how to
process forms in a file.

A new proof-checker command forwardchain has been added; see *note
ACL2-PC||FORWARDCHAIN::.

It is now possible to use quantifiers.  See *note DEFUN-SK:: and see
*note DEFCHOOSE::.

There is a new event set-inhibit-warnings, which allows the user to
turn off warnings of various types.  see *note SET-INHIBIT-WARNINGS::.

An unsoundness relating encapsulate and :functional-instance hints has
been remedied, with a few small effects visible at the user level.  The
main observable effect is that defaxiom and non-local include-book
events are no longer allowed in the scope of any encapsulate event that
has a non-empty signature.

When certify-book is called, we now require that the default defun-mode
(see *note DEFAULT-DEFUN-MODE::) be :logic.  On a related note, the
default defun-mode is irrelevant to include-book; the mode is always
set to :logic initially, though it may be changed within the book and
reverts to its original value at the conclusion of the include-book.  A
bug in include-book prevented it from acting this way even though the
documentation said otherwise.

The documentation has been substantially improved.  A new section
"Programming" contains documentation of many useful functions provided
by ACL2; see *note PROGRAMMING::.  Also, the documentation has been
"marked up" extensively.  Thus in particular, users of Mosaic will find
many links in the documentation.

The symbols force, mv-nth, and acl2-count have been added to the list
*acl2-exports*.

We now permit most names from the main Lisp package to be used as
names, except for names that define functions, macros, or constants.
See *note NAME::.

We have changed the list of imports from the Common Lisp package to
ACL2, i.e., the list *common-lisp-symbols-from-main-lisp-package*, to
be exactly those external symbols of the Common Lisp package as
specified by the draft Common Lisp standard.  In order to accommodate
this change, we have renamed some ACL2 functions as shown below, but
these and other ramifications of this change should be transparent to
most ACL2 users.

     warning      --> warning$
     print-object --> print-object$

Proof trees are no longer enabled by default.  To start them up,
:start-proof-tree.

We have added the capability of building smaller images.  The easiest
way to do this on a Unix (trademark of AT&T) system is: make small.

Here we will put some less important changes, additions, and so on.

We have added definitions for the Common Lisp function position (for
the test eql), as well as corresponding versions position-equal and
position-eq that use tests equal and eq, respectively.  See *note
POSITION::, see *note POSITION-EQUAL::, and see *note POSITION-EQ::.

The defthm event rational-listp-implies-rationalp-car no longer exists.

We fixed a bug in the hint mechanism that applied :by, :cases, and :use
hints to the first induction goal when the prover reverted to proving
the original goal by induction.

We fixed a bug in the handling of (set-irrelevant-formals-ok :warn).

In support of removing the old-style forcing capability, we deleted the
initialization of state global old-style-forcing and deleted the
definitions of recover-assumptions, recover-assumptions-from-goal,
remove-assumptions1, remove-assumptions, and split-on-assumptions, and
we renamed split-on-assumptions1 to split-on-assumptions.

The special value 'none in the proof-checker commands claim and = has
been replaced by :none.

A bug in the handling of hints by subgoals has been fixed.  For
example, formerly a :do-not hint could be "erased" by a :use hint on a
subgoal.  Thanks go to Art Flatau for noticing the bug.

The functions weak-termp and weak-term-listp have been deleted, and
their calls have been replaced by corresponding calls of pseudo-termp
and pseudo-term-listp.  The notion of pseudo-termp has been slightly
strenthened by requiring that terms of the form (quote ...) have length
2.

Performance has been improved in various ways.  At the prover level,
backchaining through the recognizer alist has been eliminated in order
to significantly speed up ACL2's rewriter.  Among the other prover
changes (of which there are several, all technical):  we no longer
clausify the input term when a proof is interrupted in favor of
inducting on the input term.  At the IO level, we have improved
performance somewhat by suitable declarations and proclamations.  These
include technical modifications to the macros mv and mv-let, and
introduction of a macro the-mv analogous to the macro the but for forms
returning multiple values.

The function spaces now takes an extra argument, the current column.

A bug in the proof-checker equiv command was fixed.

The function intersectp has been deleted, because it was essentially
duplicated by the function intersectp-equal.

We now proclaim functions in AKCL and GCL before compiling books.  This
should result in somewhat increased speed.

The function repeat has been eliminated; use make-list instead.

The proof-checker command expand has been fixed so that it eliminates
let (lambda) expressions when one would expect it to.

A new primitive function, mv-nth, has been introduced.  Mv-nth is
equivalent to nth and is used in place of nth in the translation of
mv-let expressions.  This allows the user to control the simplification
of mv-let expressions without affecting how nth is treated.  In that
spirit, the rewriter has been modified so that certain mv-nth
expressions, namely those produced in the translation of (mv-let (a b
c)(mv x y z) p), are given special treatment.

A minor bug in untranslate has been fixed, which for example will fix
the printing of conjunctions.

Translate now takes a logicp argument, which indicates whether it
enforces the restriction that :program mode functions do not occur in
the result.

The modified version of trace provided by ACL2, for use in raw Lisp,
has been modified so that the lisp special variable *trace-alist* has a
slightly different functionality.  This alist associates, using eq,
symbols with the print representations of their values.  For example,
initially *trace-alist* is a one-element list containing the pair (cons
'state '|*the-live-state*|).  Thus, one may cons the pair (cons '*foo*
"It's a FOO!") on to *trace-alist*; then until *foo* is defined, this
change will have no effect, but after for example

     (defconst *foo* 17)

then trace will print 17 as "It's a FOO!".

Trace also traces the corresponding logic function.

Proof-tree display has been improved slightly in the case of successful
proofs and certain event failures.

The function positive-integer-log2 has been deleted.

The macro skip-proofs now prints a warning message when it is
encountered in the context of an encapsulate event or a book.  See
*note SKIP-PROOFS::.

Some functions related to the-fn and wormhole1 now have defun-mode
:program, but this change is almost certain to be inconsequential to
all users.


File: acl2-doc-emacs.info,  Node: NOTE8-UPDATE,  Next: NOTE9,  Prev: NOTE8,  Up: RELEASE-NOTES

NOTE8-UPDATE    ACL2 Version 1.8 (Summer, 1995) Notes

ACL2 can now use Ordered Binary Decision Diagram technology.  See *note
BDD::.  There is also a proof-checker bdd command.

ACL2 is now more respectful of the intention of the function hide.  In
particular, it is more careful not to dive inside any call of hide
during equality substitution and case splitting.

The ld special (see *note LD::) ld-pre-eval-print may now be used to
turn off printing of input forms during processing of encapsulate and
certify-book forms, by setting it to the value :never, i.e.,
(set-ld-pre-eval-print :never state).  See *note LD-PRE-EVAL-PRINT::.

The TUTORIAL documentation section (now obsolete) has, with much help
from Bill Young, been substantially improved to a bona fide
introduction.

The term pretty-printer has been modified to introduce (<= X Y) as an
abbreviation for (not (< Y X)).

Forward chaining and linear arithmetic now both benefit from the
evaluation of ground subterms.

A new macro set-inhibit-output-lst has been defined.  This should be
used when setting the state global inhibit-output-lst; see *note
SET-INHIBIT-OUTPUT-LST:: and see *note PROOF-TREE::.

The test for redundancy in definitions includes the guard and type
declarations.  See *note REDUNDANT-EVENTS::.

See *note GENERALIZED-BOOLEANS:: for a discussion of a potential
soundness problem for ACL2 related to the question:  Which Common Lisp
functions are known to return Boolean values?

Here we will put some less important changes, additions, and so on.

A bug has been fixed so that now, execution of :comp t (see *note
COMP::) correctly handles non-standard characters.

A bug in digit-char-p has been fixed, so that the "default" is nil
rather than 0.

True-listp now tests the final cdr against nil using eq instead of
equal, for improved efficiency.  The logical meaning is, however,
unchanged.

Put-assoc-equal has been added to the logic (it used to have
:defun-mode :program, and has been documented.


File: acl2-doc-emacs.info,  Node: NOTE9,  Prev: NOTE8-UPDATE,  Up: RELEASE-NOTES

NOTE9    ACL2 Version 1.9 (Fall, 1996) Notes

By default, when the system is started it is illegal to use the
variable STATE as a formal parameter of a function definition.  The aim
is to prevent novice users from stumbling into the Byzantine syntactic
restrictions on that variable symbol.  Use

     :set-state-ok t

or, equivalently,

     (set-state-ok t)

to switch back to the old default mode.  See *note SET-STATE-OK::

Set-state-ok is an event that affects the ACL2 defaults table (see
*note ACL2-DEFAULTS-TABLE::).  Recall that when books are included, the
defaults table is restored to its pre-inclusion state.  Thus, while a
set-state-ok form will permit the book to define a state-using
function, it will not permit the user of the book to make such a
definition.  We recommend putting (set-state-ok t) in any book that
defines a state using function.

Books certified under Version 1.8 must be recertified under Version
1.9.  See :DOC version.

The simplifier has been made to look out for built-in clauses, whereas
in past versions such clauses were only noticed by the "preprocessor"
at the top of the waterfall.  THIS CHANGE MAY PREVENT OLD SCRIPTS FROM
REPLAYING!  The undesirable side-effect is caused by the fact that
:HINTS require you to refer to clauses by their exact name (see *note
GOAL-SPEC::) and because the new simplifier proves more clauses than
before, the goals produced have different names.  Thus, if a script
uses :HINTS that refer to clauses other than "Goal", e.g., "Subgoal
1.3" then the hint may be applied to a different subgoal than
originally intended.

The use of built-in-clauses has been made more efficient.  If a set of
clauses arise often in a piece of work, it might be advantageous to
build them in even if that results in a large set (hundreds?) of
built-in clauses.  See *note BUILT-IN-CLAUSE::

Wormholes can now be used in :logic mode functions. See *note WORMHOLE::

It is now possible to provide "computed hints."  For example, have you
ever wished to say "in all goals with a name like this, :use that" or
"if this term is in the subgoal, then :use that"?  Well, see *note
COMPUTED-HINTS:: and the extraordinarily long example in see *note
USING-COMPUTED-HINTS::.

Hide terms may be rewritten with :rewrite rules about hide.  See *note
HIDE::, where we also now explain why hide terms are sometimes
introduced into your proof attempts.

A bug that sometimes caused the "non-lazy IF" hard error message was
fixed.

A bug that sometimes caused a hard error in forward chaining was fixed.

A bug in print-rules (:pr) was fixed.

We report the use of :executable-counterparts in the evaluation of
SYNTAXP forms.

Some documentation errors were fixed.

A bug in parent-tree tracking in add-literal-and-pt was fixed.

A bug in ok$, go$ and eval$ was fixed.

Clausify now optimizes (mv-nth 'k (list x0 ... xk ... xn)) to xk.


File: acl2-doc-emacs.info,  Node: RULE-CLASSES,  Next: SERIALIZE,  Prev: RELEASE-NOTES,  Up: Top

RULE-CLASSES    adding rules to the database

     Example Form (from community book finite-set-theory/total-ordering.lisp):
     (defthm <<-trichotomy
       (implies (and (ordinaryp x)
                     (ordinaryp y))
                (or (<< x y)
                    (equal x y)
                    (<< y x)))
       :rule-classes
       ((:rewrite :corollary
                  (implies (and (ordinaryp x)
                                (ordinaryp y)
                                (not (<< x y))
                                (not (equal x y)))
                           (<< y x)))))

     General Form:
     a true list of rule class objects as defined below

     Special Cases:
     a symbol abbreviating a single rule class object

When defthm is used to prove a named theorem, rules may be derived from
the proved formula and stored in the database.  The user specifies which
kinds of rules are to be built, by providing a list of rule class names
or, more generally, rule class objects, which name the kind of rule to
build and optionally specify varioius attributes of the desired rule.
The rule class names are :REWRITE, :BUILT-IN-CLAUSE, :CLAUSE-PROCESSOR,
:COMPOUND-RECOGNIZER, :CONGRUENCE, :DEFINITION, :ELIM, :EQUIVALENCE,
:FORWARD-CHAINING, :GENERALIZE, :INDUCTION, :LINEAR, :META,
:REFINEMENT, :TAU-SYSTEM, :TYPE-PRESCRIPTION, :TYPE-SET-INVERTER, and
:WELL-FOUNDED-RELATION.  Some classes require the user-specification of
certain class-specific attributes.  Each class of rule affects the
theorem prover's behavior in a different way, as discussed in the
corresponding documentation topic.  In this topic we discuss the
various attributes that may be attached to rule classes.

A rule class object is either one of the :class keywords or else is a
list of the form shown below.  Those fields marked with "(!)"  are
required when the :class is as indicated.

     (:class
       :COROLLARY term
       :TRIGGER-FNS (fn1 ... fnk) ; provided :class = :META (!)
       :TRIGGER-TERMS (t1 ... tk) ; provided :class = :FORWARD-CHAINING
                                  ;       or :class = :LINEAR
       :TYPE-SET n                ; provided :class = :TYPE-SET-INVERTER
       :TYPED-TERM term           ; provided :class = :TYPE-PRESCRIPTION
       :CLIQUE (fn1 ... fnk)      ; provided :class = :DEFINITION
       :CONTROLLER-ALIST alist    ; provided :class = :DEFINITION
       :INSTALL-BODY directive    ; provided :class = :DEFINITION
       :LOOP-STOPPER alist        ; provided :class = :REWRITE
       :PATTERN term              ; provided :class = :INDUCTION (!)
       :CONDITION term            ; provided :class = :INDUCTION
       :SCHEME term               ; provided :class = :INDUCTION (!)
       :MATCH-FREE all-or-once    ; provided :class = :REWRITE
                                          or :class = :LINEAR
                                          or :class = :FORWARD-CHAINING
       :BACKCHAIN-LIMIT-LST limit ; provided :class = :REWRITE
                                          or :class = :META
                                          or :class = :LINEAR
                                          or :class = :TYPE-PRESCRIPTION
       :HINTS hints               ; provided instrs = nil
       :INSTRUCTIONS instrs       ; provided  hints = nil
       :OTF-FLG flg)

When rule class objects are provided by the user, most of the fields are
optional and their values are computed in a context sensitive way.
When a :class keyword is used as a rule class object, all relevant
fields are determined contextually.  Each rule class object in
:rule-classes causes one or more rules to be added to the database.
The :class keywords are documented individually under the following
names.  Note that when one of these names is used as a :class, it is
expected to be in the keyword package (i.e., the names below should be
preceded by a colon but the ACL2 documentation facilities do not permit
us to use keywords below).

* Menu:

* BUILT-IN-CLAUSE:: to build a clause into the simplifier

* CLAUSE-PROCESSOR:: make or apply a :clause-processor rule (goal-level simplifier)

* COMPOUND-RECOGNIZER:: make a rule used by the typing mechanism

* CONGRUENCE:: the relations to maintain while simplifying arguments

* DEFINITION:: make a rule that acts like a function definition

* ELIM:: make a destructor elimination rule

* EQUIVALENCE:: mark a relation as an equivalence relation

* FORWARD-CHAINING:: make a rule to forward chain when a certain trigger arises

* FREE-VARIABLES:: free variables in rules

* GENERALIZE:: make a rule to restrict generalizations

* INDUCTION:: make a rule that suggests a certain induction

* LINEAR:: make some arithmetic inequality rules

* META:: make a :meta rule (a hand-written simplifier)

* REFINEMENT:: record that one equivalence relation refines another

* REWRITE:: make some :rewrite rules (possibly conditional ones)

* TAU-SYSTEM:: make a rule for the ACL2 ``type checker''

* TYPE-PRESCRIPTION:: make a rule that specifies the type of a term

* TYPE-SET-INVERTER:: exhibit a new decoding for an ACL2 type-set

* WELL-FOUNDED-RELATION:: show that a relation is well-founded on a set

See also force, case-split, syntaxp, and bind-free for "pragmas" one
can wrap around individual hypotheses of certain classes of rules to
affect how the hypothesis is relieved.

Before we get into the discussion of rule classes, let us return to an
important point.  In spite of the large variety of rule classes
available, at present we recommend that new ACL2 users rely almost
exclusively on (conditional) rewrite rules.  A reasonable but slightly
bolder approach is to use :type-prescription and :forward-chaining
rules for "type-theoretic" rules, especially ones whose top-level
function symbol is a common one like true-listp or consp; see *note
TYPE-PRESCRIPTION:: and see *note FORWARD-CHAINING::.  However, the
rest of the rule classes are really not intended for widespread use,
but rather are mainly for experts.

We expect that we will write more about the question of which kind of
rule to use.  For now: when in doubt, use a :rewrite rule.

:Rule-classes is an optional keyword argument of the defthm (and
defaxiom) event.  In the following, let name be the name of the event
and let thm be the formula to be proved or added as an axiom.

If :rule-classes is not specified in a defthm (or defaxiom) event, it
is as though what was specified was to make one or more :rewrite rules,
i.e., as though :rule-classes ((:rewrite)) had been used.  Use
:rule-classes nil to specify that no rules are to be generated.

If :rule-classes class is specified, where class is a non-nil symbol,
it is as though :rule-classes ((class)) had been used.  Thus,
:rule-classes :forward-chaining is equivalent to :rule-classes
((:forward-chaining)).

We therefore now consider :rule-classes as a true list.  If any element
of that list is a keyword, replace it by the singleton list containing
that keyword.  Thus, :rule-classes (:rewrite :elim) is the same as
:rule-classes ((:rewrite) (:elim)).

Each element of the expanded value of :rule-classes must be a true list
whose car is one of the rule class keyword tokens listed above, e.g.,
:rewrite, :elim, etc., and whose cdr is a "keyword alist" alternately
listing keywords and values.  The keywords in this alist must be taken
from those shown below.  They may be listed in any order and most may
be omitted, as specified below.

     :Corollary -- its value, term, must be a term.  If omitted, this
     field defaults to thm.  The :corollary of a rule class object is
     the formula actually used to justify the rule created and thus
     determines the form of the rule.  Nqthm provided no similar
     capability: each rule was determined by thm, the theorem or axiom
     added.  ACL2 permits thm to be stated "elegantly" and then allows
     the :corollary of a rule class object to specify how that elegant
     statement is to be interpreted as a rule.  For the rule class
     object to be well-formed, its (defaulted) :corollary, term, must
     follow from thm.  Unless term follows trivially from thm using
     little more than propositional logic, the formula (implies thm
     term) is submitted to the theorem prover and the proof attempt
     must be successful.  During that proof attempt the values of
     :hints, :instructions, and :otf-flg, as provided in the rule class
     object, are provided as arguments to the prover.  Such auxiliary
     proofs give the sort of output that one expects from the prover.
     However, as noted above, corollaries that follow trivially are not
     submitted to the prover; thus, such corollaries cause no prover
     output.

     Note that before term is stored, all calls of macros in it are
     expanded away.  See *note TRANS::.

     :Hints, :instructions, :otf-flg -- the values of these fields must
     satisfy the same restrictions placed on the fields of the same
     names in defthm.  These values are passed to the recursive call of
     the prover used to establish that the :corollary of the rule class
     object follows from the theorem or axiom thm.

     :Type-set -- this field may be supplied only if the :class is
     :type-set-inverter.  When provided, the value must be a type-set,
     an integer in a certain range.  If not provided, an attempt is
     made to compute it from the corollary.  See *note
     TYPE-SET-INVERTER::.

     :Typed-term -- this field may be supplied only if the :class is
     :type-prescription.  When provided, the value is the term for which
     the :corollary is a type-prescription lemma.  If no :typed-term is
     provided in a :type-prescription rule class object, we try to
     compute heuristically an acceptable term.  See *note
     TYPE-PRESCRIPTION::.

     :Trigger-terms -- this field may be supplied only if the :class is
     :forward-chaining or :linear.  When provided, the value is a list
     of terms, each of which is to trigger the attempted application of
     the rule.  If no :trigger-terms is provided, we attempt to compute
     heuristically an appropriate set of triggers.  See *note
     FORWARD-CHAINING:: or see *note LINEAR::.

     :Trigger-fns -- this field must (and may only) be supplied if the
     :class is :meta.  Its value must be a list of function symbols
     (except that a macro alias can stand in for a function symbol; see
     *note ADD-MACRO-ALIAS::).  Terms with these symbols trigger the
     application of the rule.  See *note META::.

     :Clique and :controller-alist -- these two fields may only be
     supplied if the :class is :definition.  If they are omitted, then
     ACL2 will attempt to guess them.  Suppose the :corollary of the
     rule is (implies hyp (equiv (fn a1 ... an) body)).  The value of
     the :clique field should be a true list of function symbols, and if
     non-nil must include fn.  These symbols are all the members of the
     mutually recursive clique containing this definition of fn.  That
     is, a call of any function in :clique is considered a "recursive
     call" for purposes of the expansion heuristics.  The value of the
     :controller-alist field should be an alist that maps each function
     symbol in the :clique to a list of t's and nil's of length equal
     to the arity of the function.  For example, if :clique consists of
     just two symbols, fn1 and fn2, of arities 2 and 3 respectively,
     then ((fn1 t nil) (fn2 nil t t)) is a legal value of
     :controller-alist.  The value associated with a function symbol in
     this alist is a "mask" specifying which argument slots of the
     function "control" the recursion for heuristic purposes.  Sloppy
     choice of :clique or :controller-alist can result in infinite
     expansion and stack overflow.

     :Install-body -- this field may only be supplied if the :class is
     :definition.  Its value must be t, nil, or the default,
     :normalize.  A value of t or :normalize will cause ACL2 to install
     this rule as the new body of the function being "defined" (fn in
     the paragraph just above); hence this definition will be installed
     for future :expand hints.  Furthermore, if this field is omitted
     or the value is :normalize, then this definition will be
     simplified using the so-called "normalization" procedure that is
     used when processing definitions made with defun.  You must
     explicitly specify :install-body nil in the following cases: fn
     (as above) is a member of the value of constant
     *definition-minimal-theory*, the arguments are not a list of
     distinct variables, equiv (as above) is not equal, or there are
     free variables in the hypotheses or right-hand side (see *note
     FREE-VARIABLES::).  However, supplying :install-body nil will not
     affect the rewriter's application of the :definition rule, other
     than to avoid using the rule to apply :expand hints.  If a
     definition rule equates (f a1 ... ak) with body but there are
     hypotheses, hyps, then :expand hints will replace terms (f term1
     ... termk) by corresponding terms (if hyps body (hide (f term1 ...
     termk))).

     :Loop-stopper -- this field may only be supplied if the class is
     :rewrite.  Its value must be a list of entries each consisting of
     two variables followed by a (possibly empty) list of functions,
     for example ((x y binary-+) (u v foo bar)).  It will be used to
     restrict application of rewrite rules by requiring that the list
     of instances of the second variables must be "smaller" than the
     list of instances of the first variables in a sense related to the
     corresponding functions listed; see *note LOOP-STOPPER::.  The
     list as a whole is allowed to be nil, indicating that no such
     restriction shall be made.  Note that any such entry that contains
     a variable not being instantiated, i.e., not occurring on the left
     side of the rewrite rule, will be ignored.  However, for
     simplicity we merely require that every variable mentioned should
     appear somewhere in the corresponding :corollary formula.

     :Pattern, :Condition, :Scheme -- the first and last of these
     fields must (and may only) be supplied if the class is :induction.
     :Condition is optional but may only be supplied if the class is
     :induction.  The values must all be terms and indicate,
     respectively, the pattern to which a new induction scheme is to be
     attached, the condition under which the suggestion is to be made,
     and a term which suggests the new scheme.  See *note INDUCTION::.

     :Match-free -- this field must be :all or :once and may be
     supplied only if the :class is either :rewrite, :linear, or
     :forward-chaining.  (This field is not implemented for other rule
     classes, including the :type-prescription rule class.)  See *note
     FREE-VARIABLES:: for a description of this field.  Note: Although
     this field is intended to be used for controlling retries of
     matching free variables in hypotheses, it is legal to supply it
     even if there are no such free variables.  This can simplify the
     automated generation of rules, but note that when :match-free is
     supplied, the warning otherwise provided for the presence of free
     variables in hypotheses will be suppressed.

     :Backchain-limit-lst -- this field may be supplied only if the
     :class is either :rewrite, :meta, :linear, or :type-prescription.
     It is further required either only one rule is generated from the
     formula or, at least, every such rule has the same list of
     hypotheses.  The value for :backchain-limit-lst must be nil; a
     non-negative integer; or, except in the case of :meta rules, a true
     list each element of which is either nil or a non-negative
     integer.  If it is a list, its length must be equal to the number
     of hypotheses of the rule and each item in the list is the
     "backchain limit" associated with the corresponding hypothesis.
     If backchain-limit-lst is a non-negative integer, it is defaulted
     to a list of the appropriate number of repetitions of that
     integer.  The backchain limit of a hypothesis is used to limit the
     effort that ACL2 will expend when relieving the hypothesis.  If it
     is NIL, no new limits are imposed; if it is an integer, the
     hypothesis will be limited to backchaining at most that many
     times.  Note that backchaining may be further limited by a global
     backchain-limit; see *note BACKCHAIN-LIMIT:: for details.  For
     different ways to reign in the rewriter, see *note
     REWRITE-STACK-LIMIT:: and see *note SET-PROVER-STEP-LIMIT::.
     Jared Davis has pointed out that you can set the
     :backchain-limit-lst to 0 to avoid any attempt to relieve forced
     hypotheses, which can lead to a significant speed-up in some cases.

Once thm has been proved (in the case of defthm) and each rule class
object has been checked for well-formedness (which might require
additional proofs), we consider each rule class object in turn to
generate and add rules.  Let :class be the class keyword token of the
ith class object (counting from left to right).  Generate the rune
(:class name . x), where x is nil if there is only one class and
otherwise x is i.  Then, from the :corollary of that object, generate
one or more rules, each of which has the name (:class name . x).  See
the :doc entry for each rule class to see how formulas determine rules.
Note that it is in principle possible for several rules to share the
same name; it happens whenever a :corollary determines more than one
rule.  This in fact only occurs for :rewrite, :linear, and
:forward-chaining class rules and only then if the :corollary is
essentially a conjunction.  (See the documentation for rewrite, linear,
or forward-chaining for details.)


File: acl2-doc-emacs.info,  Node: BUILT-IN-CLAUSE,  Next: CLAUSE-PROCESSOR,  Prev: RULE-CLASSES,  Up: RULE-CLASSES

BUILT-IN-CLAUSE    to build a clause into the simplifier

See *note 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.

     Example:
     (defthm acl2-count-abl
       (and (implies (and (true-listp x)
                          (not (equal x nil)))
                     (< (acl2-count (abl x))
                        (acl2-count x)))
            (implies (and (true-listp x)
                          (not (equal nil x)))
                     (< (acl2-count (abl x))
                        (acl2-count x))))
       :rule-classes :built-in-clause)

A :built-in-clause rule can be built from any formula other than
propositional tautologies.  Roughly speaking, the system uses the list
of built-in clauses as the first method of proof when attacking a new
goal.  Any goal that is subsumed by a built in clause is proved
"silently."

ACL2 maintains a set of "built-in" clauses that are used to
short-circuit certain theorem proving tasks.  We discuss this at length
below.  When a theorem is given the rule class :built-in-clause ACL2
flattens the implies and and structure of the :corollary formula so as
to obtain a set of formulas whose conjunction is equivalent to the given
corollary.  It then converts each of these to clausal form and adds each
clause to the set of built-in clauses.

The example above (regardless of the definition of abl) will build in
two clauses,

     {(not (true-listp x))
      (equal x nil)
      (< (acl2-count (abl x)) (acl2-count x))}

and

     {(not (true-listp x))
      (equal nil x)
      (< (acl2-count (abl x)) (acl2-count x))}.

We now give more background.

Recall that a clause is a set of terms, implicitly representing the
disjunction of the terms.  Clause c1 is "subsumed" by clause c2 if some
instance of c2 is a subset c1.

For example, let c1 be

     {(not (consp l))
      (equal a (car l))
      (< (acl2-count (cdr l)) (acl2-count l))}.

Then c1 is subsumed by c2, shown below,

     {(not (consp x))
      ; second term omitted here
      (< (acl2-count (cdr x)) (acl2-count x))}

because we can instantiate x in c2 with l to obtain a subset of c1.

Observe that c1 is the clausal form of

     (implies (and (consp l)
                   (not (equal a (car l))))
              (< (acl2-count (cdr l)) (acl2-count l))),

c2 is the clausal form of

     (implies (consp l)
              (< (acl2-count (cdr l)) (acl2-count l)))

and the subsumption property just means that c1 follows trivially from
c2 by instantiation.

The set of built-in clauses is just a set of known theorems in clausal
form.  Any formula that is subsumed by a built-in clause is thus a
theorem.  If the set of built-in theorems is reasonably small, this
little theorem prover is fast.  ACL2 uses the "built-in clause check"
in four places: (1) at the top of the iteration in the prover - thus if
a built-in clause is generated as a subgoal it will be recognized when
that goal is considered, (2) within the simplifier so that no built-in
clause is ever generated by simplification, (3) as a filter on the
clauses generated to prove the termination of recursively defun'd
functions and (4) as a filter on the clauses generated to verify the
guards of a function.

The latter two uses are the ones that most often motivate an extension
to the set of built-in clauses.  Frequently a given formalization
problem requires the definition of many functions which require
virtually identical termination and/or guard proofs.  These proofs can
be short-circuited by extending the set of built-in clauses to contain
the most general forms of the clauses generated by the definitional
schemes in use.

The attentive user might have noticed that there are some recursive
schemes, e.g., recursion by cdr after testing consp, that ACL2 just
seems to "know" are ok, while for others it generates measure clauses
to prove.  Actually, it always generates measure clauses but then
filters out any that pass the built-in clause check.  When ACL2 is
initialized, the clause justifying cdr recursion after a consp test is
added to the set of built-in clauses.  (That clause is c2 above.)

Note that only a subsumption check is made; no rewriting or
simplification is done.  Thus, if we want the system to "know" that cdr
recursion is ok after a negative atom test (which, by the definition of
atom, is the same as a consp test), we have to build in a second
clause.  The subsumption algorithm does not "know" about commutative
functions.  Thus, for predictability, we have built in commuted
versions of each clause involving commutative functions.  For example,
we build in both

     {(not (integerp x))
      (< 0 x)
      (= x 0)
      (< (acl2-count (+ -1 x)) (acl2-count x))}

and the commuted version

     {(not (integerp x))
      (< 0 x)
      (= 0 x)
      (< (acl2-count (+ -1 x)) (acl2-count x))}

so that the user need not worry whether to write (= x 0) or (= 0 x) in
definitions.

:built-in-clause rules added by the user can be enabled and disabled.


File: acl2-doc-emacs.info,  Node: CLAUSE-PROCESSOR,  Next: COMPOUND-RECOGNIZER,  Prev: BUILT-IN-CLAUSE,  Up: RULE-CLASSES

CLAUSE-PROCESSOR    make or apply a :clause-processor rule (goal-level simplifier)

See *note 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.

     Example (which we'll return to, below):
     (defthm correctness-of-note-fact-clause-processor
       (implies (and (pseudo-term-listp cl)
                     (alistp a)
                     (evl0 (conjoin-clauses
                            (note-fact-clause-processor cl term))
                           a))
                (evl0 (disjoin cl) a))
       :rule-classes :clause-processor)

Also see *note DEFINE-TRUSTED-CLAUSE-PROCESSOR:: for documentation of
an analogous utility that does not require the clause-processor to be
proved correct.  But please read the present documentation before
reading about that utility.  Both utilities designate functions
"clause-processors".  Such functions must be executable -- hence not
constrained by virtue of being introduced in the signature of an
encapsulate -- and must respect stobj and output arity restrictions.
For example, something like (car (mv ...)) is illegal; also see *note
SIGNATURE::.

We begin this documentation with an introduction, focusing on an
example, and then conclude with details.  You might find it most useful
simply to look at the examples in community books directory
books/clause-processors/; see file Readme.lsp in that directory.

A :clause-processor rule installs a simplifier at the level of goals,
where a goal is represented as a _clause_: a list of terms that is
implicitly viewed as a disjunction (the application of OR).  For
example, if ACL2 prints a goal in the form (implies (and p q) r), then
the clause might be the one-element list containing the internal
representation of this term -- (implies (if p q 'nil) r) -- but more
likely, the corresponding clause is ((not p) (not q) r).  Note that the
members of a clause are _translated_ terms; see *note TERM::.  For
example, they do not contains calls of the macro AND, and constants are
quoted.

Note that clause-processor simplifiers are similar to metafunctions, and
similar efficiency considerations apply.  See *note META::, in
particular the discussion on how to "make a metafunction maximally
efficient."

Unlike rules of class :meta, rules of class :clause-processor must be
applied by explicit :clause-processor hints; they are not applied
automatically (unless by way of computed hints; see *note
COMPUTED-HINTS::).  But :clause-processor rules can be useful in
situations for which it is more convenient to code a simplifier that
manipulates the entire goal clause rather than individual subterms of
terms in the clause.

We begin with a simple illustrative example: a clause-processor that
assumes an alleged fact (named term in the example) and creates a
separate goal to prove that fact.  We can extend the hypotheses of the
current goal (named cl in the example) with a term by adding the
negation of that term to the clause (disjunctive) representation of
that goal.  So the following returns a list of two clauses: the result
of adding term as a hypothesis to the input clause, as just described,
and a second clause consisting only of that term.  This list of two
clauses can be viewed as the conjunction of the first clause and the
second clause (where again, each clause is viewed as a disjunction).


     (defun note-fact-clause-processor (cl term)
       (declare (xargs :guard t)) ; optional, for better efficiency
       (list (cons (list 'not term)
                   cl)
             (list term)))

As with :meta rules, we need to introduce a suitable evaluator; see
*note DEFEVALUATOR:: if you want details.  Since we expect to reason
about the function NOT, because of its role in
note-fact-clause-processor as defined above, we include NOT in the set
of functions known to this evaluator.  We also include IF, as is often
a good idea.


     (defevaluator evl0 evl0-list
       ((not x) (if x y z)))

ACL2 can now prove the following theorem automatically.  (This is the
example displayed at the outset of this documentation topic.)  Of
course, :clause-processor rules about clause-processor functions less
trivial than note-fact-clause-processor may require lemmas to be proved
first!  The function disjoin takes a clause and returns its disjunction
(the result of applying OR to its members), and conjoin-clauses applies
disjoin to every element of a given list of clauses and then conjoins
(applies AND) to the corresponding list of resulting terms.


     (defthm correctness-of-note-fact-clause-processor
       (implies (and (pseudo-term-listp cl)
                     (alistp a)
                     (evl0 (conjoin-clauses
                            (note-fact-clause-processor cl term))
                           a))
                (evl0 (disjoin cl) a))
       :rule-classes :clause-processor)

Now let us submit a silly but illustrative example theorem to ACL2, to
show how a corresponding :clause-processor hint is applied.  The hint
says to apply the clause-processor function,
note-fact-clause-processor, to the current goal clause and a "user
hint" as the second argument of that function, in this case (equal a
a).  Thus, a specific variable, clause, is always bound to the current
goal clause for the evaluation of the :clause-processor hint, to
produce a list of clauses.  Since two subgoals are created below, we
know that this list contained two clauses.  Indeed, these are the
clauses returned when note-fact-clause-processor is applied to two
arguments:  the current clause, which is the one-element list ((equal
(car (cons x y)) x)), and the user hint, (equal a a).


     ACL2 !>(thm (equal (car (cons x y))
                        x)
                 :hints
                 (("Goal"
                   :clause-processor
                   (note-fact-clause-processor clause '(equal a a)))))

     [Note:  A hint was supplied for our processing of the goal above.
     Thanks!]

     We now apply the verified :CLAUSE-PROCESSOR function NOTE-FACT-CLAUSE-
     PROCESSOR to produce two new subgoals.

     Subgoal 2
     (IMPLIES (EQUAL A A)
              (EQUAL (CAR (CONS X Y)) X)).

     But we reduce the conjecture to T, by the :executable-counterpart of
     IF and the simple :rewrite rule CAR-CONS.

     Subgoal 1
     (EQUAL A A).

     But we reduce the conjecture to T, by primitive type reasoning.

     Q.E.D.

     Summary
     Form:  ( THM ...)
     Rules: ((:EXECUTABLE-COUNTERPART IF)
             (:EXECUTABLE-COUNTERPART NOT)
             (:FAKE-RUNE-FOR-TYPE-SET NIL)
             (:REWRITE CAR-CONS))
     Warnings:  None
     Time:  0.00 seconds (prove: 0.00, print: 0.00, other: 0.00)

     Proof succeeded.
     ACL2 !>

That concludes our introduction to clause-processor rules and hints.
We turn now to detailed documentation.

The signature of a clause-processor function, CL-PROC, must have one of
the following forms.  Here, each st_i is a stobj (possibly state) while
the other parameters and results are not stobjs (see *note STOBJ::).
Note that there need not be input stobjs in [3] -- i.e., k can be 0 --
and even if there are, there need not be output stobjs.

     [1]  ((CL-PROC cl) => cl-list)

     [2]  ((CL-PROC cl hint) => cl-list)

     [3]  ((CL-PROC cl hint st_1 ... st_k) => (mv erp cl-list st_i1 ... st_in))

In [3], we think of the first component of the result as an error flag.
Indeed, a proof will instantly abort if that error flag is not nil.

We next discuss the legal forms of :clause-processor rules, followed
below by a discussion of :clause-processor hints.  In the discussion
below, we use lower-case names to represent specific symbols, for
example implies, and we use upper-case names to represent more
arbitrary pieces of syntax (which we will describe), for example, CL.

If a :rule-classes specification includes :clause-processor, then the
corresponding term must have the following form.  (Additional
"meta-extract" hypotheses, not shown or discussed below, may be
included as desired in order to use facts from the logical world to
help prove the rule; see *note META-EXTRACT:: for explanation of this
advanced feature.)

     (implies (and (pseudo-term-listp CL)
                   (alistp A)
                   (EVL (conjoin-clauses <CL-LIST>)
                         B))
              (EVL (disjoin CL) A))

Here EVL is a known evaluator; CL and A are distinct non-stobj
variables; and <CL-LIST> is an expression representing the clauses
returned by the clause-processor function CL-PROC, whose form depends on
the signature of that function, as follows.  Typically B is A, but it
can be any term (useful when generalization is occurring; see the
example "Test generalizing alist" in community book
books/clause-processors/basic-examples.lisp).  For cases [1] and [2]
above, <CL-LIST> is of the form (CL-PROC CL) or (CL-PROC CL HINT),
respectively, where in the latter case HINT is a non-stobj variable
distinct from the variables CL and A.  For case [3], <CL-LIST> is of
the form

     (clauses-result (CL-PROC CL HINT st_1 ... st_k))

where the st_i are the specific stobj names mentioned in [3].
Logically, clauses-result returns the cadr if the car is NIL, and
otherwise (for the error case) returns a list containing the empty
(false) clause.  So in the non-error case, clauses-result picks out the
second result, denoted cl-list in [3] above, and in the error case the
implication above trivially holds.

In the above theorem, we are asked to prove (EVL (disjoin CL) A)
assuming that the conjunction of all clauses produced by the clause
processor evaluates to a non-nil value under some alist B.  In fact, we
can choose B so as to allow us to assume evaluations of the generated
clauses over many different alists.  This technique is discussed in the
community book books/clause-processors/multi-env-trick.lisp, which
introduces some macros that may be helpful in accomplishing proofs of
this type.

The clause-processor function, CL, must have a guard that ACL2 can
trivially prove from the hypotheses that the first argument of CL is
known to be a pseudo-term-listp and any stobj arguments are assumed to
satisfy their stobj predicates.

Next we specify the legal forms for :clause-processor hints.  These
depend on the signature as described in [1] through [3] above.  Below,
as above, CL-PROC is the clause-processor function, and references to
"clause" refer to that exact variable (not, for example, to cl).  In
each of the three cases, the forms shown for that case are equivalent;
in particular, the :function syntax is simply a convenience for the
final form in each case.

Signature [1], ((cl-proc cl) => cl-list):

     :clause-processor CL-PROC
     :clause-processor (:function CL-PROC)
     :clause-processor (CL-PROC clause)

or any term macroexpanding to (CL-PROC clause).

Signature [2], ((cl-proc cl hint) => cl-list):

     :clause-processor (:function CL-PROC :hint HINT)
     :clause-processor (CL-PROC clause HINT)

or any term macroexpanding to (CL-PROC clause HINT), where HINT is any
term with at most CLAUSE free.

Signature [3], ((CL-PROC cl hint ...) => (mv erp cl-list ...))

     :clause-processor (:function CL-PROC :hint HINT)
     :clause-processor (CL-PROC clause HINT st_1 ... st_k)

or any term macroexpanding to (CL-PROC clause HINT st_1 ... st_k), where
HINT is any term with at most CLAUSE free.

A :clause-processor hint causes the proof to abort if the result
returned by evaluating the suitable CL-PROC call, as above, is not a
list of clauses, i.e., a list of (translated) term lists.  The proof
also aborts if in case [3] the first (erp) value returned is not nil,
in which case erp is used for printing an error message as follows: if
it is a string, then that string is printed; but if it is a non-empty
true list whose first element is a string, then it is printed as though
by (fmt ~@0 (list (cons #\0 erp)) ...) (see *note FMT::).  Otherwise, a
non-nil erp value causes a generic error message to be printed.

If there is no error as above, but the CL-PROC call returns clause list
whose single element is equal to the input clause, then the hint is
ignored since we are left with the goal with which we started.  In that
case, the other prover processes are then applied as usual.

You can see all current :clause-processor rules by issuing the following
command: (print-clause-processor-rules).

The following paper discusses ACL2 clause-processors at a high level
suitable for a non-ACL2 audience:

     M. Kaufmann, J S. Moore, S. Ray, and E. Reeber, "Integrating
     External Deduction Tools with ACL2."  _Journal of Applied Logic_
     (Special Issue: Empirically Successful Computerized Reasoning),
     Volume 7, Issue 1, March 2009, pp. 3-25.  Also published online
     (DOI 10.1016/j.jal.2007.07.002).  Preliminary version in:
     Proceedings of the 6th International Workshop on the
     Implementation of Logics (IWIL 2006) (C. Benzmueller, B. Fischer,
     and G. Sutcliffe, editors), CEUR Workshop Proceedings Vol. 212,
     Phnom Penh, Cambodia, pp. 7-26, November 2006,
     `http://ceur-ws.org/Vol-212/'.


File: acl2-doc-emacs.info,  Node: COMPOUND-RECOGNIZER,  Next: CONGRUENCE,  Prev: CLAUSE-PROCESSOR,  Up: RULE-CLASSES

COMPOUND-RECOGNIZER    make a rule used by the typing mechanism

See *note 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.

     Examples:
     (defthm alistp-implies-true-listp-compound-recognizer
       (implies (alistp x)                 ; When (alistp x) is assumed true, add
                (true-listp x))            ; the additional hypothesis that x is
       :rule-classes :compound-recognizer) ; of primitive type true-listp.

     (defthm natp-compound-recognizer      ; See discussion below.
       (equal (natp x)
              (and (integerp x)
                   (<= 0 x)))
       :rule-classes :compound-recognizer)

Before presenting the General Forms, we start with a motivating
example: the second defthm form above, which provides a nice example of
a :compound-recognizer rule that is built into ACL2.  To see how this
rule might be useful, consider the following (admittedly very simple)
events.

     (defun triple (x)
       (* 3 x))

     (defthm triple-preserves-integerp
       (implies (integerp x)
                (integerp (triple x))))

     (in-theory (disable triple natp))

If the above :compound-recognizer rule is disabled, then the following
trivial theorem fails as shown; we explain below.

     (thm (implies (natp x)
                   (integerp (triple x)))
       :hints (("Goal" :in-theory (disable natp-compound-recognizer))))

The problem is that when ACL2 tries to rewrite the term (integerp
(triple x)) using the :rewrite rule triple-preserves-integerp, it needs
to rewrite the hypothesis (integerp x) to t, but instead what is known
is (natp x).  If we remove the hint, then the proof succeeds because
the above :compound-recognizer rule tells ACL2 that when assuming (natp
x) to be true, it should actually assume both (integerp x) and (<= 0 x)
to be true.

     General Forms:
     (implies (fn x) concl)               ; (1)
     (implies (not (fn x)) concl)         ; (2)
     (and (implies (fn x) concl1)         ; (3)
          (implies (not (fn x)) concl2))
     (if (fn x) concl1 concl2)            ; (4)
     (iff (fn x) concl)                   ; (5)
     (equal (fn x) concl)                 ; (6)

where fn is a Boolean valued function of one argument, x is a variable
symbol, and the system can deduce some restriction on the primitive
type of x from the assumption that concl holds.  The last restriction
is vague but one way to understand it is to weaken it a little to "and
concl is a non-tautological conjunction or disjunction of the primitive
type recognizers listed below."

The primitive ACL2 types and a suitable primitive recognizing
expression for each are listed below.

       type                suitable primitive recognizer

       zero                (equal x 0)
       negative integers   (and (integerp x) (< x 0))
       positive integers   (and (integerp x) (> x 0))
       negative ratio      (and (rationalp x)
                                (not (integerp x))
                                (< x 0))
       positive ratio      (and (rationalp x)
                                (not (integerp x))
                                (> x 0))
       complex rational    (complex-rationalp x)
       nil                 (equal x nil)
       t                   (equal x t)
       other symbols       (and (symbolp x)
                                (not (equal x nil))
                                (not (equal x t)))
       proper conses       (and (consp x)
                                (true-listp x))
       improper conses     (and (consp x)
                                (not (true-listp x)))
       strings             (stringp x)
       characters          (characterp x)

Thus, a suitable concl to recognize the naturals would be (or (equal x
0) (and (integerp x) (> x 0))) but it turns out that we also permit
(and (integerp x) (>= x 0)).  Similarly, the true-lists could be
specified by

     (or (equal x nil) (and (consp x) (true-listp x)))

but we in fact allow (true-listp x).  When time permits we will document
more fully what is allowed or implement a macro that permits direct
specification of the desired type in terms of the primitives.

There are essentially four forms of :compound-recognizer rules, as the
forms labeled (3) and (4) above are equivalent, as are those labeled (5)
and (6).  We explain how such rules are used by considering the
individual forms.

Consider form (1), (implies (fn x) concl).  The effect of such a rule is
that when the rewriter assumes (fn x) true, as it would while diving
through (if (fn x) xxx ...) to rewrite xxx, it restricts the type of x
as specified by concl.  For example, if concl is the term (integerp x),
then when rewriting xxx, x will be assumed to be an integer.  However,
when assuming (fn x) false, as necessary in (if (fn x) ... xxx), the
rule permits no additional assumptions about the type of x.  For
example, if fn is primep, i.e., the predicate that recognizes prime
numbers, then (implies (primep x) (and (integerp x) (>= x 0))) is a
compound recognizer rule of the first form.  When (primep x) is assumed
true, the rewriter gains the additional information that x is a natural
number.  When (primep x) is assumed false, no additional information is
gained -- since x may be a non-prime natural or may not even be a
natural.

Form (2) is the symmetric case, when assuming (fn x) false permits type
restrictions on x but assuming (fn x) true permits no such
restrictions.  For example, if we defined exprp to be the recognizer for
well-formed expressions for some language in which all symbols, numbers,
character objects and strings were well-formed -- e.g., the
well-formedness rules only put restrictions on expressions represented
by consps -- then the theorem (implies (not (exprp x)) (consp x)) is a
rule of the second form.  Assuming (exprp x) true tells us nothing
about the type of x; assuming it false tells us x is a consp.

Forms (3) and (4), which are really equivalent, address themselves to
the case where one type may be deduced from (fn x) and a generally
unrelated type may be deduced from its negation.  If we modified the
expression recognizer above so that character objects are illegal, then
rules of the forms (3) and (4) are

     (and (implies (exprp x) (not (characterp x)))
          (implies (not (exprp x)) (or (consp x) (characterp x)))).
     (if (exprp x)
         (not (characterp x))
       (or (consp x) (characterp x)))

Finally, rules of forms (5) and (6) address the case where fn recognizes
all and only the objects whose type is described.  In these cases, fn is
really just a new name for some "compound recognizers."  The classic
example is (booleanp x), which is just a handy combination of two
primitive types:

     (iff (booleanp x) (or (equal x t) (equal x nil))).

Often it is best to disable fn after proving that it is a compound
recognizer, since otherwise the term (fn x) will be expanded and thus
disappear.

Every time you prove a new compound recognizer rule about fn it
overrides all previously proved compound recognizer rules about fn.
Thus, if you want to establish the type implied by (fn x) and you want
to establish the type implied by (not (fn x)), you must prove a
compound recognizer rule of the third, fourth, fifth, or sixth forms.
Proving a rule of the first form followed by one of the second only
leaves the second fact in the database.

Compound recognizer rules can be disabled with the effect that older
rules about fn, if any, are exposed.

If you prove more than one compound recognizer rule for a function, you
may see a *warning* message to the effect that the new rule is not as
"restrictive" as the old.  That is, the new rules do not give the
rewriter strictly more type information than it already had.  The new
rule is stored anyway, overriding the old, if enabled.  You may be
playing subtle games with enabling or rewriting.  But two other
interpretations are more likely, we think.  One is that you have
forgotten about an earlier rule and should merely print it out to make
sure it says what you intend, and then discard your new rule.  The
other is that you meant to give the system more information and the
system has simply been unable to extract the intended type information
from the term you placed in the conclusion of the new rule.  Given our
lack of specificity in saying how type information is extracted from
rules, you can hardly blame yourself for this problem.  Sorry.  If you
suspect you've been burned this way, you should rephrase the new rule in
terms of the primitive recognizing expressions above and see if the
warning is still given.  It would also be helpful to let us see your
example so we can consider it as we redesign this stuff.

Compound recognizer rules are similar to :forward-chaining rules in
that the system deduces new information from the act of assuming
something true or false.  If a compound recognizer rule were stored as
a forward chaining rule it would have essentially the same effect as
described, when it has any effect at all.  The important point is that
:forward-chaining rules, because of their more general and expensive
form, are used "at the top level" of the simplification process: we
forward chain from assumptions in the goal being proved.  But compound
recognizer rules are built in at the bottom-most level of the
simplifier, where type reasoning is done.

All that said, compound recognizer rules are a rather fancy, specialized
mechanism.  It may be more appropriate to create :forward-chaining
rules instead of :compound-recognizer rules.


File: acl2-doc-emacs.info,  Node: CONGRUENCE,  Next: DEFINITION,  Prev: COMPOUND-RECOGNIZER,  Up: RULE-CLASSES

CONGRUENCE    the relations to maintain while simplifying arguments

See *note RULE-CLASSES:: for a general discussion of rule classes and
how they are used to build rules from formulas.  An example :corollary
formula from which a :congruence rule might be built is:

     Example:
     (defthm set-equal-implies-iff-memb-2
       (implies (set-equal x y)
                (iff (memb e x) (memb e y)))
       :rule-classes :congruence)

Also see *note DEFCONG:: and see *note EQUIVALENCE::.

     General Form:
     (implies (equiv1 xk xk-equiv)
              (equiv2 (fn x1... xk       ...xn)
                      (fn x1... xk-equiv ...xn)))

where equiv1 and equiv2 are known equivalence relations, fn is an n-ary
function symbol and the xi and xk-equiv are all distinct variables.
The effect of such a rule is to record that the equiv2-equivalence of
fn-expressions can be maintained if, while rewriting the kth argument
position, equiv1-equivalence is maintained.  See *note EQUIVALENCE::
for a general discussion of the issues.  We say that equiv2, above, is
the "outside equivalence" in the rule and equiv1 is the "inside
equivalence for the kth argument"

The macro form (defcong equiv1 equiv2 (fn x1 ... x1) k) is an
abbreviation for a defthm of rule-class :congruence that attempts to
establish that equiv2 is maintained by maintaining equiv1 in fn's kth
argument.  The defcong macro automatically generates the general
formula shown above.  See *note DEFCONG::.

The memb example above tells us that (memb e x) is propositionally
equivalent to (memb e y), provided x and y are set-equal.  The outside
equivalence is iff and the inside equivalence for the second argument
is set-equal.  If we see a memb expression in a propositional context,
e.g., as a literal of a clause or test of an if (but not, for example,
as an argument to cons), we can rewrite its second argument maintaining
set-equality.  For example, a rule stating the commutativity of append
(modulo set-equality) could be applied in this context.  Since equality
is a refinement of all equivalence relations, all equality rules are
always available.  See *note REFINEMENT::.

All known :congruence rules about a given outside equivalence and fn
can be used independently.  That is, consider two :congruence rules
with the same outside equivalence, equiv, and about the same function
fn.  Suppose one says that equiv1 is the inside equivalence for the
first argument and the other says equiv2 is the inside equivalence for
the second argument.  Then (fn a b) is equiv (fn a' b') provided a is
equiv1 to a' and b is equiv2 to b'.  This is an easy consequence of the
transitivity of equiv.  It permits you to think independently about the
inside equivalences.

Furthermore, it is possible that more than one inside equivalence for a
given argument slot will maintain a given outside equivalence.  For
example, (length a) is equal to (length a') if a and a' are related
either by list-equal or by string-equal.  You may prove two (or more)
:congruence rules for the same slot of a function.  The result is that
the system uses a new, "generated" equivalence relation for that slot
with the result that rules of both (or all) kinds are available while
rewriting.

:Congruence rules can be disabled.  For example, if you have two
different inside equivalences for a given argument position and you
find that the :rewrite rules for one are unexpectedly preventing the
application of the desired rule, you can disable the rule that
introduced the unwanted inside equivalence.

_Remark on Replacing IFF by EQUAL._ You may encounter a warning
suggesting that a congruence rule "can be strengthened by replacing the
second equivalence relation, IFF, by EQUAL."  Suppose for example that
this warning occurs when you submit the following rule:

     (defcong equiv1 iff (fn x y) 2)

which is shorthand for the following:

     (defthm equiv1-implies-iff-fn-2
            (implies (equiv1 y y-equiv)
                     (iff (fn x y) (fn x y-equiv)))
            :rule-classes (:congruence))

The warning is telling you that ACL2 was able to deduce that fn always
returns a Boolean, and hence a trivial but useful consequence is
obtained by replacing iff by equal --

     (defcong equiv1 equal (fn x y) 2)

-- which is shorthand for the following:

     (defthm equiv1-implies-equal-fn-2
            (implies (equiv1 y y-equiv)
                     (equal (fn x y) (fn x y-equiv)))
            :rule-classes (:congruence))

If you have difficulty proving the latter directly, you can derive it
from the former by giving a suitable hint, minimally as follows.

     (defcong equiv1 equal (fn x y) 2
       :hints (("Goal"
                :use equiv1-implies-iff-fn-2
                :in-theory
                (union-theories '((:type-prescription fn))
                                (theory 'minimal-theory)))))

By heeding this warning, you may avoid unnecessary double-rewrite
warnings later.  We now explain why, but see *note DOUBLE-REWRITE:: for
relevant background material.

For example, suppose you have proved the "iff" version of the
congruence rule above, and later you submit the following rewrite rule.

     (defthm equal-list-perm
       (implies (equiv1 x y)
                (fn x y)))

Since fn is known to return a Boolean, ACL2 performs an optimization
that stores this rule as though it were the following.

     (defthm equal-list-perm
       (implies (equiv1 x y)
                (equal (fn x y) t)))

Thus, if ACL2's rewriter sees a term (fn a b) in a context where the
equivalence relation iff is not being maintained, then it cannot use
rule equiv1-implies-iff-fn-2, so it rewrites argument a without the
benefit of knowing that it suffices to maintain equiv1; and then it
caches the result.  When ACL2 subsequently attempts to relieve the
hypothesis (equiv1 x y), it will rewrite x simply by returning the
rewritten value of a from the result cache.  This is unfortunate if a
could have been rewritten more completely under maintainance of the
equivalence relation equiv1 -- which is legal in the hypothesis since a
is an argument of equiv1, which is an equivalence relation.  The user
who observes the warning from rule equiv1-implies-iff-fn-2, and
replaces it with equiv1-implies-equal-fn-2, will avoid this unfortunate
case.


File: acl2-doc-emacs.info,  Node: DEFINITION,  Next: ELIM,  Prev: CONGRUENCE,  Up: RULE-CLASSES

DEFINITION    make a rule that acts like a function definition

See *note RULE-CLASSES:: for a general discussion of rule classes and
how they are used to build rules from formulas.  An example :corollary
formula from which a :definition rule might be built is:

     Examples:
     (defthm open-len-twice
       (implies (true-listp x)
                (equal (len x)
                       (if (null x)
                           0
                         (if (null (cdr x))
                             1
                           (+ 2 (len (cddr x)))))))
       :rule-classes :definition)

     ; Same as above, with :controller-alist made explicit:
     (defthm open-len-twice
       (implies (true-listp x)
                (equal (len x)
                       (if (null x)
                           0
                         (if (null (cdr x))
                             1
                           (+ 2 (len (cddr x)))))))
       :rule-classes ((:definition :controller-alist ((len t)))))

     General Form:
     (implies hyp (equiv (fn a1 ... an) body))

where equiv is an equivalence relation and fn is a function symbol
other than if, hide, force or case-split.  Such rules allow
"alternative" definitions of fn to be proved as theorems but used as
definitions.  These rules are not true "definitions" in the sense that
they (a) cannot introduce new function symbols and (b) do not have to be
terminating recursion schemes.  They are just conditional rewrite rules
that are controlled the same way we control recursive definitions.  We
call these "definition rules" or "generalized definitions".

Consider the general form above.  Generalized definitions are stored
among the :rewrite rules for the function "defined," fn above, but the
procedure for applying them is a little different.  During rewriting,
instances of (fn a1 ... an) are replaced by corresponding instances of
body provided the hyps can be established as for a :rewrite rule and
the result of rewriting body satisfies the criteria for function
expansion.  There are two primary criteria, either of which permits
expansion.  The first is that the "recursive" calls of fn in the
rewritten body have arguments that already occur in the goal
conjecture.  The second is that the "controlling" arguments to fn are
simpler in the rewritten body.

The notions of "recursive call" and "controllers" are complicated by the
provisions for mutually recursive definitions.  Consider a "clique" of
mutually recursive definitions.  Then a "recursive call" is a call to
any function defined in the clique and an argument is a "controller" if
it is involved in the measure that decreases in all recursive calls.
These notions are precisely defined by the definitional principle and
do not necessarily make sense in the context of generalized
definitional equations as implemented here.

But because the heuristics governing the use of generalized definitions
require these notions, it is generally up to the user to specify which
calls in body are to be considered recursive and what the controlling
arguments are.  This information is specified in the :clique and
:controller-alist fields of the :definition rule class.

The :clique field is the list of function symbols to be considered
recursive calls of fn.  In the case of a non-recursive definition, the
:clique field is empty; in a singly recursive definition, it should
consist of the singleton list containing fn; otherwise it should be a
list of all of the functions in the mutually recursive clique with this
definition of fn.

If the :clique field is not provided it defaults to nil if fn does not
occur as a function symbol in body and it defaults to the singleton
list containing fn otherwise.  Thus, :clique must be supplied by the
user only when the generalized definition rule is to be treated as one
of several in a mutually recursive clique.

The :controller-alist is an alist that maps each function symbol in the
:clique to a mask specifying which arguments are considered controllers.
The mask for a given member of the clique, fn, must be a list of t's
and nil's of length equal to the arity of fn.  A t should be in each
argument position that is considered a "controller" of the recursion.
For a function admitted under the principle of definition, an argument
controls the recursion if it is one of the arguments measured in the
termination argument for the function.  But in generalized definition
rules, the user is free to designate any subset of the arguments as
controllers.  Failure to choose wisely may result in the "infinite
expansion" of definitional rules but cannot render ACL2 unsound since
the rule being misused is a theorem.

If the :controller-alist is omitted it can sometimes be defaulted
automatically by the system.  If the :clique is nil, the
:controller-alist defaults to nil.  If the :clique is a singleton
containing fn, the :controller-alist defaults to the controller alist
computed by (defun fn args body).  (The user can obtain some control
over this analysis by setting the default ruler-extenders; see *note
RULER-EXTENDERS::.)  If the :clique contains more than one function,
the user must supply the :controller-alist specifying the controllers
for each function in the clique.  This is necessary since the system
cannot determine and thus cannot analyze the other definitional
equations to be included in the clique.

For example, suppose fn1 and fn2 have been defined one way and it is
desired to make "alternative" mutually recursive definitions available
to the rewriter.  Then one would prove two theorems and store each as a
:definition rule.  These two theorems would exhibit equations
"defining" fn1 and fn2 in terms of each other.  No provision is here
made for exhibiting these two equations as a system of equations.  One
is proved and then the other.  It just so happens that the user intends
them to be treated as mutually recursive definitions.  To achieve this
end, both :definition rules should specify the :clique (fn1 fn2) and
should specify a suitable :controller-alist.  If, for example, the new
definition of fn1 is controlled by its first argument and the new
definition of fn2 is controlled by its second and third (and they each
take three arguments) then a suitable :controller-alist would be ((fn1
t nil nil) (fn2 nil t t)).  The order of the pairs in the alist is
unimportant, but there must be a pair for each function in the clique.

Inappropriate heuristic advice via :clique and :controller-alist can
cause "infinite expansion" of generalized definitions, but cannot render
ACL2 unsound.

Note that the actual definition of fn1 has the runic name (:definition
fn1).  The runic name of the alternative definition is (:definition
lemma), where lemma is the name given to the event that created the
generalized :definition rule.  This allows theories to switch between
various "definitions" of the functions.

By default, a :definition rule establishes the so-called "body" of a
function.  The body is used by :expand hints, and it is also used
heuristically by the theorem prover's preprocessing (the initial
simplification using "simple" rules that is controlled by the
preprocess symbol in :do-not hints), induction analysis, and the
determination for when to warn about non-recursive functions in rules.
The body is also used by some heuristics involving whether a function is
recursively defined, and by the expand, x, and x-dumb commands of the
proof-checker.

See *note RULE-CLASSES:: for a discussion of the optional field
:install-body of :definition rules, which controls whether a
:definition rule is used as described in the paragraph above.  Note
that even if :install-body nil is supplied, the rewriter will still
rewrite with the :definition rule; in that case, ACL2 just won't
install a new body for the top function symbol of the left-hand side of
the rule, which for example affects the application of :expand hints as
described in the preceding paragraph.  Also see *note SET-BODY:: and
see *note SHOW-BODIES:: for how to change the body of a function symbol.

Note only that if you prove a definition rule for function foo, say,
foo-new-def, you will need to refer to that definition as foo-new-def
or as (:DEFINITION foo-new-def).  That is because a :definition rule
does not change the meaning of the symbol foo for :use hints, nor does
it change the meaning of the symbol foo in theory expressions; see
*note THEORIES::, in particular the discussion there of runic
designators.  Similarly :pe foo and :pf foo will still show the
original definition of foo.

The definitional principle, defun, actually adds :definition rules.
Thus the handling of generalized definitions is exactly the same as for
"real" definitions because no distinction is made in the implementation.
Suppose (fn x y) is defun'd to be body.  Note that defun (or defuns or
mutual-recursion) can compute the clique for fn from the syntactic
presentation and it can compute the controllers from the termination
analysis.  Provided the definition is admissible, defun adds the
:definition rule (equal (fn x y) body).


File: acl2-doc-emacs.info,  Node: ELIM,  Next: EQUIVALENCE,  Prev: DEFINITION,  Up: RULE-CLASSES

ELIM    make a destructor elimination rule

See *note 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.

The following example of an :elim rule is an important one, and is built
into ACL2.

     (defaxiom car-cdr-elim
       (implies (consp x)
                (equal (cons (car x) (cdr x)) x))
       :rule-classes :elim)

The class of :elim rules is fundamentally quite different from the more
common class of :rewrite rules.  Briefly put, a :rewrite rule replaces
instances of its left-hand side with corresponding instances of its
right-hand side.  But an :elim rule, on the other hand, has the effect
of generalizing so-called "destructor" function applications to
variables.  In essence, applicability of a :rewrite rule is based on
matching its left-hand side, while applicability of an :elim rule is
based on the presence of at least one destructor term.

For example, a conjecture about (car x) and (cdr x) can be replaced by
a conjecture about new variables x1 and x2, as shown in the following
example.  (Run the command :mini-proveall and search for CAR-CDR-ELIM
to see the full proof containing this excerpt.)

     Subgoal *1/1'
     (IMPLIES (AND (CONSP X)
                   (TRUE-LISTP (REV (CDR X))))
              (TRUE-LISTP (APP (REV (CDR X)) (LIST (CAR X))))).

     The destructor terms (CAR X) and (CDR X) can be eliminated by using
     CAR-CDR-ELIM to replace X by (CONS X1 X2), (CAR X) by X1 and (CDR X)
     by X2.  This produces the following goal.

     Subgoal *1/1''
     (IMPLIES (AND (CONSP (CONS X1 X2))
                   (TRUE-LISTP (REV X2)))
              (TRUE-LISTP (APP (REV X2) (LIST X1)))).

     This simplifies, using primitive type reasoning, to

     Subgoal *1/1'''
     (IMPLIES (TRUE-LISTP (REV X2))
              (TRUE-LISTP (APP (REV X2) (LIST X1)))).

The resulting conjecture is often simpler and hence more amenable to
proof.

The application of an :elim rule thus replaces a variable by a term that
contains applications of so-called "destructor" functions to that
variable.  The example above is typical: the variable x is replaced by
the term (cons (car x) (cdr x)), which applies a so-called "constructor"
function, cons, to applications (car x) and (cdr x) of destructor
functions car and cdr to that same variable, x.  But that is only part
of the story.  ACL2 then generalizes the destructor applications (car
x) and (cdr x) to new variables x1 and x2, respectively, and ultimately
the result is a simpler conjecture.

More generally, the application of an :elim rule replaces a variable by
a term containing applications of destructors; there need not be a
clear-cut notion of "constructor."  But the situation described above
is typical, and we will focus on it, giving full details when we
introduce the "General Form" below.

Notice that the situation can be complicated a bit by a rule's
hypotheses.  For example, the replacement specified by the rule
car-cdr-elim (shown near the beginning of this discussion) is only
valid if the variable being replaced is a cons structure.  Thus, when
ACL2 applies car-cdr-elim to replace a variable v, it will split into
two cases: one case in which (consp v) is true, in which v is replaced
by (cons (car v) (cdr v)) and then (car v) and (cdr v) are generalized
to new variables; and one case in which (consp v) is false.  In
practice, (consp v) is often provable, perhaps even literally present
as a hypotheses; then of course there is no need to introduce the second
case.  That is why there is no such second case in the example above.

You might find :elim rules to be useful whenever you have in mind a data
type that can be built up from its fields with a "constructor" function
and whose fields can be accessed by corresponding "destructor"
functions.  So for example, if you have a "house" data structure that
represents a house in terms of its address, price, and color, you might
have a rule like the following.

     Example:
     (implies (house-p x)
              (equal (make-house (address x)
                                 (price x)
                                 (color x))
                     x))

The application of such a rule is entirely analogous to the application
of the rule car-cdr-elim discussed above.  We discuss such rules and
their application more carefully below.

     General Form:
     (implies hyp (equiv lhs x))

where equiv is a known equivalence relation (see *note DEFEQUIV::); x
is a variable symbol; and lhs contains one or more terms (called
"destructor terms") of the form (fn v1 ... vn), where fn is a function
symbol and the vi are distinct variable symbols, v1, ..., vn include
all the variable symbols in the formula, no fn occurs in lhs in more
than one destructor term, and all occurrences of x in lhs are inside
destructor terms.

To use an :elim rule, the theorem prover waits until a conjecture has
been maximally simplified.  It then searches for an instance of some
destructor term (fn v1 ... vn) in the conjecture, where the instance for
x is some variable symbol, vi, and every occurrence of vi outside the
destructor terms is in an equiv-hittable position.  If such an instance
is found, then the theorem prover instantiates the :elim formula as
indicated by the destructor term matched; splits the conjecture into two
goals, according to whether the instantiated hypothesis, hyp, holds; and
in the case that it does hold, generalizes all the instantiated
destructor terms in the conjecture to new variables and then replaces
vi in the conjecture by the generalized instantiated lhs.  An
occurrence of vi is "equiv-hittable" if sufficient congruence rules
(see *note DEFCONG::) have been proved to establish that the
propositional value of the clause is not altered by replacing that
occurrence of vi by some equiv-equivalent term.

If an :elim rule is not applied when you think it should have been, and
the rule uses an equivalence relation, equiv, other than equal, it is
most likely that there is an occurrence of the variable that is not
equiv-hittable.  Easy occurrences to overlook are those in the
governing hypotheses.  If you see an unjustified occurrence of the
variable, you must prove the appropriate congruence rule to allow the
:elim to fire.

Further examples of how ACL2 :elim rules are used may be found in the
corresponding discussion of "Elimation of Destructors" for Nqthm, in
Section 10.4 of A Computational Logic Handbook.


File: acl2-doc-emacs.info,  Node: EQUIVALENCE,  Next: FORWARD-CHAINING,  Prev: ELIM,  Up: RULE-CLASSES

EQUIVALENCE    mark a relation as an equivalence relation

See *note 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.

     Example:
     (defthm r-equal-is-an-equivalence ; assumes that r-equal has been defined
       (and (booleanp (r-equal x y))
            (r-equal x x)
            (implies (r-equal x y) (r-equal y x))
            (implies (and (r-equal x y)
                          (r-equal y z))
                     (r-equal x z)))
       :rule-classes :equivalence)

Also see *note DEFEQUIV::.

     General Form:
     (and (booleanp (equiv x y))
          (equiv x x)
          (implies (equiv x y) (equiv y x))
          (implies (and (equiv x y)
                        (equiv y z))
                   (equiv x z)))

except that the order of the conjuncts and terms and the choice of
variable symbols is unimportant.  The effect of such a rule is to
identify equiv as an equivalence relation.  Note that only Boolean
2-place function symbols can be treated as equivalence relations.  See
*note CONGRUENCE:: and see *note REFINEMENT:: for closely related
concepts.

The macro form (defequiv equiv) is an abbreviation for a defthm of
rule-class :equivalence that establishes that equiv is an equivalence
relation.  It generates the formula shown above.  See *note DEFEQUIV::.

When equiv is marked as an equivalence relation, its reflexivity,
symmetry, and transitivity are built into the system in a deeper way
than via :rewrite rules.  More importantly, after equiv has been shown
to be an equivalence relation, lemmas about equiv, e.g.,

     (implies hyps (equiv lhs rhs)),

when stored as :rewrite rules, cause the system to rewrite certain
occurrences of (instances of) lhs to (instances of) rhs.  Roughly
speaking, an occurrence of lhs in the kth argument of some
fn-expression, (fn ... lhs' ...), can be rewritten to produce (fn ...
rhs' ...), provided the system "knows" that the value of fn is
unaffected by equiv-substitution in the kth argument.  Such knowledge
is communicated to the system via "congruence lemmas."

For example, suppose that r-equal is known to be an equivalence
relation.  The :congruence lemma

     (implies (r-equal s1 s2)
              (equal (fn s1 n) (fn s2 n)))

informs the rewriter that, while rewriting the first argument of
fn-expressions, it is permitted to use r-equal rewrite-rules.  See
*note CONGRUENCE:: for details about :congruence lemmas.
Interestingly, congruence lemmas are automatically created when an
equivalence relation is stored, saying that either of the equivalence
relation's arguments may be replaced by an equivalent argument.  That
is, if the equivalence relation is fn, we store congruence rules that
state the following fact:

     (implies (and (fn x1 y1)
                   (fn x2 y2))
              (iff (fn x1 x2) (fn y1 y2)))

Another aspect of equivalence relations is that of "refinement."  We
say equiv1 "refines" equiv2 iff (equiv1 x y) implies (equiv2 x y).
:refinement rules permit you to establish such connections between your
equivalence relations.  The value of refinements is that if the system
is trying to rewrite something while maintaining equiv2 it is permitted
to use as a :rewrite rule any refinement of equiv2.  Thus, if equiv1 is
a refinement of equiv2 and there are equiv1 rewrite-rules available,
they can be brought to bear while maintaining equiv2.  See *note
REFINEMENT::.

The system initially has knowledge of two equivalence relations,
equality, denoted by the symbol equal, and propositional equivalence,
denoted by iff.  Equal is known to be a refinement of all equivalence
relations and to preserve equality across all arguments of all
functions.

Typically there are five steps involved in introducing and using a new
equivalence relation, equiv.

     (1) Define equiv,

     (2) prove the :equivalence lemma about equiv,

     (3) prove the :congruence lemmas that show where equiv can be used
     to maintain known relations,

     (4) prove the :refinement lemmas that relate equiv to known
     relations other than equal, and

     (5) develop the theory of conditional :rewrite rules that drive
     equiv rewriting.

More will be written about this as we develop the techniques.  For now,
here is an example that shows how to make use of equivalence relations
in rewriting.

Among the theorems proved below is

     (defthm insert-sort-is-id
       (perm (insert-sort x) x))

Here perm is defined as usual with delete and is proved to be an
equivalence relation and to be a congruence relation for cons and
member.

Then we prove the lemma

     (defthm insert-is-cons
       (perm (insert a x) (cons a x)))

which you must think of as you would (insert a x) = (cons a x).

Now prove (perm (insert-sort x) x).  The base case is trivial.  The
induction step is

        (consp x)
      & (perm (insert-sort (cdr x)) (cdr x))

     -> (perm (insert-sort x) x).

Opening insert-sort makes the conclusion be

        (perm (insert (car x) (insert-sort (cdr x))) x).

Then apply the induction hypothesis (rewriting (insert-sort (cdr x)) to
(cdr x)), to make the conclusion be

     (perm (insert (car x) (cdr x)) x)

Then apply insert-is-cons to get (perm (cons (car x) (cdr x)) x).  But
we know that (cons (car x) (cdr x)) is x, so we get (perm x x) which is
trivial, since perm is an equivalence relation.

Here are the events.

     (encapsulate (((lt * *) => *))
       (local (defun lt (x y) (declare (ignore x y)) nil))
       (defthm lt-non-symmetric (implies (lt x y) (not (lt y x)))))

     (defun insert (x lst)
       (cond ((atom lst) (list x))
             ((lt x (car lst)) (cons x lst))
             (t (cons (car lst) (insert x (cdr lst))))))

     (defun insert-sort (lst)
       (cond ((atom lst) nil)
             (t (insert (car lst) (insert-sort (cdr lst))))))

     (defun del (x lst)
       (cond ((atom lst) nil)
             ((equal x (car lst)) (cdr lst))
             (t (cons (car lst) (del x (cdr lst))))))

     (defun mem (x lst)
       (cond ((atom lst) nil)
             ((equal x (car lst)) t)
             (t (mem x (cdr lst)))))

     (defun perm (lst1 lst2)
       (cond ((atom lst1) (atom lst2))
             ((mem (car lst1) lst2)
              (perm (cdr lst1) (del (car lst1) lst2)))
             (t nil)))

     (defthm perm-reflexive
       (perm x x))

     (defthm perm-cons
       (implies (mem a x)
                (equal (perm x (cons a y))
                       (perm (del a x) y)))
       :hints (("Goal" :induct (perm x y))))

     (defthm perm-symmetric
       (implies (perm x y) (perm y x)))

     (defthm mem-del
       (implies (mem a (del b x)) (mem a x)))

     (defthm perm-mem
       (implies (and (perm x y)
                     (mem a x))
                (mem a y)))

     (defthm mem-del2
       (implies (and (mem a x)
                     (not (equal a b)))
                (mem a (del b x))))

     (defthm comm-del
       (equal (del a (del b x)) (del b (del a x))))

     (defthm perm-del
       (implies (perm x y)
                (perm (del a x) (del a y))))

     (defthm perm-transitive
       (implies (and (perm x y) (perm y z)) (perm x z)))

     (defequiv perm)

     (in-theory (disable perm
                         perm-reflexive
                         perm-symmetric
                         perm-transitive))

     (defcong perm perm (cons x y) 2)

     (defcong perm iff (mem x y) 2)

     (defthm atom-perm
       (implies (not (consp x)) (perm x nil))
       :rule-classes :forward-chaining
       :hints (("Goal" :in-theory (enable perm))))

     (defthm insert-is-cons
       (perm (insert a x) (cons a x)))

     (defthm insert-sort-is-id
       (perm (insert-sort x) x))

     (defun app (x y) (if (consp x) (cons (car x) (app (cdr x) y)) y))

     (defun rev (x)
       (if (consp x) (app (rev (cdr x)) (list (car x))) nil))

     (defcong perm perm (app x y) 2)

     (defthm app-cons
       (perm (app a (cons b c)) (cons b (app a c))))

     (defthm app-commutes
       (perm (app a b) (app b a)))

     (defcong perm perm (app x y) 1
       :hints (("Goal" :induct (app y x))))

     (defthm rev-is-id (perm (rev x) x))

     (defun == (x y)
       (if (consp x)
           (if (consp y)
               (and (equal (car x) (car y))
                    (== (cdr x) (cdr y)))
               nil)
           (not (consp y))))

     (defthm ==-reflexive (== x x))

     (defthm ==-symmetric (implies (== x y) (== y x)))

     (defequiv ==)

     (in-theory (disable ==-symmetric ==-reflexive))

     (defcong == == (cons x y) 2)

     (defcong == iff (consp x) 1)

     (defcong == == (app x y) 2)

     (defcong == == (app x y) 1)

     (defthm rev-rev (== (rev (rev x)) x))


File: acl2-doc-emacs.info,  Node: FORWARD-CHAINING,  Next: FREE-VARIABLES,  Prev: EQUIVALENCE,  Up: RULE-CLASSES

FORWARD-CHAINING    make a rule to forward chain when a certain trigger arises

See *note 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.

     Examples:

     (defthm p-and-r-forward           ; When (p a) appears in a formula to be
      (implies (and (p x) (r x))       ; simplified, try to establish (p a) and
               (q (f x)))              ; (r a) and, if successful, add (q (f a))
      :rule-classes :forward-chaining) ; to the known assumptions.

     (defthm p-and-r-forward           ; as above with most defaults filled in
       (implies (and (p x) (r x))
                (q (f x)))
       :rule-classes ((:forward-chaining :trigger-terms ((p x))
                                         :corollary (implies (and (p x) (r x))
                                                             (q (f x)))
                                         :match-free :all)))

To specify the triggering terms provide a non-empty list of terms as
the value of the :trigger-terms field of the rule class object.

     General Form:
     Any theorem, provided an acceptable triggering term exists.

The structure of this documentation is as follows.  First we give a
brief overview of forward chaining and contrast it to backchaining
(rewriting).  Then we lay out the syntactic restrictions on
:forward-chaining rules.  Then we give more details about the process
and point to a tool to assist you in debugging your :forward-chaining
rules.

_Overview and When to Use Forward Chaining_

Forward chaining is performed as part of the simplification process:
before the goal is rewritten a _context_ is established.  The context
tells the theorem prover what may be assumed during rewriting, in
particular, to establish hypotheses of rewrite rules.  Forward chaining
is used to extend the context before rewriting begins.  For example,
the :forward-chaining rule (implies (p x) (p1 x)) would add (p1 A) to
the context, where A is some term, if (p A) is already in the context.

Forward chaining and backchaining are duals.  If a rewrite rule
requires that (p1 A) be established and (p A) is known, it could be
done either by making (implies (p x) (p1 x)) a :forward-chaining rule
or a :rewrite rule.  Which should you choose?

As a rule of thumb, if a conclusion like (p1 A) is expected to be
widely needed, it is better to derive it via forward chaining because
then it is available "for free" during the rewriting after paying the
one-time cost of forward chaining.  Alternatively, if (p1 A) is a rather
special hypothesis of key importance to only a few rewrite rules, it is
best to derive it only when needed.  Thus forward chaining is pro-active
and backward chaining (rewriting) is reactive.

_Syntactic Restrictions_

Forward chaining rules are generated from the corollary term (see *note
RULE-CLASSES::) as follows.  First, every let expression is expanded
away (hence, so is every let* and lambda expression), as is every call
of a so-called "guard holder," mv-list or return-last (the latter
resulting from macroexpansion of calls of prog2$, must-be-equal or
mbe), ec-call, and a few others), or `the'.  If the resulting term has
the form (implies hyp concl), then concl is treated as a conjunction,
with one forward chaining rule with hypothesis hyp created for each
conjunct.  In the other case, where the corollary term is not an
implies, we process it as we process the conclusion in the first case.

Note that unlike rewrite rules, a nested implication is not folded into
a single implication.  Consider for example the following term.

     (implies (p1 x)
              (implies (p2 x)
                       (p3 x)))

Although this term is parsed for a rewrite rule as (implies (and (p1 x)
(p2 x)) (p3 x)), that is not the case when this term is parsed for a
forward-chaining rule, in which case (p1 x) is treated as the
hypothesis and (implies (p2 x) (p3 x)) is treated as the conclusion.

The :trigger-terms field of a :forward-chaining rule class object
should be a non-empty list of terms, if provided, and should have
certain properties described below.  If the :trigger-terms field is not
provided, it defaults to the singleton list containing the "atom" of
the first hypothesis of the formula.  (The atom of (not x) is x; the
atom of any other term is the term itself.)  If there are no hypotheses
and no :trigger-terms were provided, an error is caused.

A triggering term is acceptable if it is not a variable, a quoted
constant, a lambda application, a let- (or let*-) expression, or a
not-expression, and every variable symbol in the conclusion of the
theorem either occurs in the hypotheses or occurs in the trigger.

_More Details about Forward Chaining_

:Forward-chaining rules are used by the simplifier _before_ it begins
to rewrite the literals of the goal.  (Forward chaining is thus carried
out from scratch for each goal.)  If any term in the goal is an
instance of a trigger of some forward chaining rule, we try to
establish the hypotheses of that forward chaining theorem (from the
negation of the goal).  To relieve a hypothesis we only use type
reasoning, evaluation of ground terms, and presence among our known
assumptions.  We do not use rewriting.  So-called free variables in
hypotheses are treated specially; see *note FREE-VARIABLES::.  If all
hypotheses are relieved, and certain heuristics approve of the newly
derived conclusion, we add the instantiated conclusion to our known
assumptions.  Since this might introduce new terms into the assumptions,
forward chaining is repeated.  Heuristic approval of each new addition
is necessary to avoid infinite looping as would happen with the rule
(implies (p x) (p (f x))), which might otherwise forward chain from (p
A) to (p (f A)) to (p (f (f A))), etc.

_Caution_.  Forward chaining does not actually add terms to the goals
displayed during proof attempts.  Instead, it extends an associated
_context_, called "assumptions" in the preceding paragraph, that ACL2
builds from the goal currently being proved.  (For insiders: forward
chaining extends the type-alist.)  The context starts out with "obvious"
consequences of the negation of the goal.  For example, if the goal is

     (implies (and (p A) (q (f A)))
              (c A))

then the context notes that (p A) and (q (f A)) are non-nil and (c A)
is nil.  Forward chaining is then used to expand the context.  For
example, if a forward chaining rule has (f x) as a trigger term and has
body (implies (p x) (r (f x))), then the context is extended by binding
(r (f A)) to non-nil, provided the heuristics approve of this
extension.  Note however that since (r (f A)) is put into the context,
not the goal, you will not see it in the goal formula.  Furthermore, the
assumption added to the context is just the instantiation of the
conclusion of the rule, with no simplification or rewriting applied.
Thus, for example, if it contains an enabled non-recursive function
symbol it is unlikely ever to match a (rewritten) term arising during
subsequent simplification of the goal.

However, forward-chaining does support the linear arithmetic reasoning
package.  For example, suppose that forward-chaining puts (< (f x) (g
x)) into the context.  Then this inequality also goes into the linear
arithmetic database, together with suitable instances of linear lemmas
whose trigger term is a call of g.  See *note LINEAR::.

Debugging :forward-chaining rules can be difficult since their effects
are not directly visible on the goal being simplified.  Tools are
available to help you discover what forward chaining has occurred see
*note FORWARD-CHAINING-REPORTS::.


File: acl2-doc-emacs.info,  Node: FREE-VARIABLES,  Next: GENERALIZE,  Prev: FORWARD-CHAINING,  Up: RULE-CLASSES

FREE-VARIABLES    free variables in rules

As described elsewhere (see *note RULE-CLASSES::), ACL2 rules are
treated as implications for which there are zero or more hypotheses hj
to prove.  In particular, rules of class :rewrite may look like this:

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

Variables of hi are said to occur _free_ in the above :rewrite rule if
they do not occur in lhs or in any hj with j<i.  (To be precise, here
we are only discussing those variables that are not in the scope of a
let/let*/lambda that binds them.)  We also refer to these as the _free
variables_ of the rule.  ACL2 may issue a warning or error when there
are free variables in a rule, as described below.  (Variables of rhs
may be considered free if they do not occur in lhs or in any hj.  But
we do not consider those in this discussion.)

In general, the _free variables_ of rules are those variables occurring
in their hypotheses (not let/let*/lambda-bound) that are not bound when
the rule is applied.  For rules of class :linear and :forward-chaining,
variables are bound by a trigger term.  (See *note RULE-CLASSES:: for a
discussion of the :trigger-terms field).  For rules of class
:type-prescription, variables are bound by the :typed-term field.

Let us discuss the method for relieving hypotheses of rewrite rules with
free variables.  Similar considerations apply to linear and
forward-chaining rules, and type-prescription rules.

See *note FREE-VARIABLES-EXAMPLES:: for more examples of how this all
works, including illustration of how the user can exercise some control
over it.  In particular, see *note FREE-VARIABLES-EXAMPLES-REWRITE::
for an explanation of output from the break-rewrite facility in the
presence of rewriting failures involving free variables, as well as an
example exploring "binding hypotheses" as described below.

Note that the :match-free mechanism discussed below does not apply to
type-prescription rules.  See *note FREE-VARIABLES-TYPE-PRESCRIPTION::
for a discussion of how to control free-variable matchng for
type-prescription rules.

* Menu:

* FREE-VARIABLES-EXAMPLES:: examples pertaining to free variables in rules

* FREE-VARIABLES-TYPE-PRESCRIPTION:: matching for free variable in type-prescription rules

We begin with an example.  Does the proof of the thm below succeed?

     (defstub p2 (x y) t)

     (defaxiom p2-trans
       (implies (and (p2 x y)
                     (p2 y z))
                (equal (p2 x z) t))
       :rule-classes ((:rewrite :match-free :all)))

     (thm (implies (and (p2 a c)
                        (p2 a b)
                        (p2 c d))
                   (p2 a d)))

Consider what happens when the proof of the thm is attempted.  The ACL2
rewriter attempts to apply rule p2-trans to the conclusion, (p2 a d).
So, it binds variables x and z from the left-hand side of the
conclusion of p2-trans to terms a and d, respectively, and then
attempts to relieve the hypotheses of p2-trans.  The first hypothesis of
p2-trans, (p2 x y), is considered first.  Variable y is free in that
hypothesis, i.e., it has not yet been bound.  Since x is bound to a,
the rewriter looks through the context for a binding of y such that (p2
a y) is true, and it so happens that it first finds the term (p2 a b),
thus binding y to b.  Now it goes on to the next hypothesis, (p2 y z).
At this point y and z have already been bound to b and d; but (p2 b d)
cannot be proved.

So, in order for the proof of the thm to succeed, the rewriter needs to
backtrack and look for another way to instantiate the first hypothesis
of p2-trans.  Because :match-free :all has been specified, backtracking
does take place.  This time y is bound to c, and the subsequent
instantiated hypothesis becomes (p2 c d), which is true.  The
application of rule (p2-trans) succeeds and the theorem is proved.

If instead :match-free :all had been replaced by :match-free :once in
rule p2-trans, then backtracking would not occur, and the proof of the
thm would fail.

Next we describe in detail the steps used by the rewriter in dealing
with free variables.

ACL2 uses the following sequence of steps to relieve a hypothesis with
free variables, except that steps (1) and (3) are skipped for
:forward-chaining rules and step (3) is skipped for :type-prescription
rules.  First, if the hypothesis is of the form (force hyp0) or
(case-split hyp0), then replace it with hyp0.

     (1) Suppose the hypothesis has the form (equiv var term) where var
     is free and no variable of term is free, and either equiv is equal
     or else equiv is a known equivalence relation and term is a call
     of double-rewrite.  We call this a "binding hypothesis."  Then bind
     var to the result of rewriting term in the current context.

     (2) Look for a binding of the free variables of the hypothesis so
     that the corresponding instance of the hypothesis is known to be
     true in the current context.

     (3) Search all enabled, hypothesis-free rewrite rules of the form
     (equiv lhs rhs), where lhs has no variables (other than those bound
     by let, let*, or lambda), rhs is known to be true in the current
     context, and equiv is typically equal but can be any equivalence
     relation appropriate for the current context (see *note
     CONGRUENCE::); then attempt to bind the free variables so that the
     instantiated hypothesis is lhs.

If all attempts fail and the original hypothesis is a call of force or
case-split, where forcing is enabled (see *note FORCE::) then the
hypothesis is relieved, but in the split-off goals, all free variables
are bound to unusual names that call attention to this odd situation.

When a rewrite or linear rule has free variables in the hypotheses, the
user generally needs to specify whether to consider only the first
instance found in steps (2) and (3) above, or instead to consider them
all.  Below we discuss how to specify these two options as ":once" or
":all" (the default), respectively.

Is it better to specify :once or :all?  We believe that :all is
generally the better choice because of its greater power, provided the
user does not introduce a large number of rules with free variables,
which has been known to slow down the prover due to combinatorial
explosion in the search (Steps (2) and (3) above).

Either way, it is good practice to put the "more substantial" hypotheses
first, so that the most likely bindings of free variables will be found
first (in the case of :all) or found at all (in the case of :once).  For
example, a rewrite rule like

     (implies (and (p1 x y)
                   (p2 x y))
              (equal (bar x) (bar-prime x)))

may never succeed if p1 is nonrecursive and enabled, since we may well
not find calls of p1 in the current context.  If however p2 is disabled
or recursive, then the above rule may apply if the two hypotheses are
switched.  For in that case, we can hope for a match of (p2 x y) in the
current context that therefore binds x and y; then the rewriter's full
power may be brought to bear to prove (p1 x y) for that x and y.

Moreover, the ordering of hypotheses can affect the efficiency of the
rewriter.  For example, the rule

     (implies (and (rationalp y)
                   (foo x y))
              (equal (bar x) (bar-prime x)))

may well be sub-optimal.  Presumably the intention is to rewrite (bar x)
to (bar-prime x) in a context where (foo x y) is explicitly known to be
true for some rational number y.  But y will be bound first to the
first term found in the current context that is known to represent a
rational number.  If the 100th such y that is found is the first one
for which (foo x y) is known to be true, then wasted work will have
been done on behalf of the first 99 such terms y -- unless :once has
been specified, in which case the rule will simply fail after the first
binding of y for which (rationalp y) is known to be true.  Thus, a
better form of the above rule is almost certainly the following.

     (implies (and (foo x y)
                   (rationalp y))
              (equal (bar x) (bar-prime x)))

_Specifying `once' or `all'._

As noted above, the following discussion applies only to rewrite,
linear, and forward-chaining rules.  See *note
FREE-VARIABLES-TYPE-PRESCRIPTION:: for a discussion of analogous
considerations for type-prescription rules.

One method for specifying :once or :all for free-variable matching is
to provide the :match-free field of the :rule-classes of the rule, for
example, (:rewrite :match-free :all).  See *note RULE-CLASSES::.
However, there are global events that can be used to specify :once or
:all; see *note SET-MATCH-FREE-DEFAULT:: and see *note
ADD-MATCH-FREE-OVERRIDE::.  Here are some examples.

     (set-match-free-default :once)    ; future rules without a :match-free field
                                       ; are stored as :match-free :once (but this
                                       ; behavior is local to a book)
     (add-match-free-override :once t) ; existing rules are treated as
                                       ; :match-free :once regardless of their
                                       ; original :match-free fields
     (add-match-free-override :once (:rewrite foo) (:rewrite bar . 2))
                                       ; the two indicated rules are treated as
                                       ; :match-free :once regardless of their
                                       ; original :match-free fields

_Some history._ Before Version  2.7 the ACL2 rewriter performed Step (2)
above first.  More significantly, it always acted as though :once had
been specified.  That is, if Step (2) did not apply, then the rewriter
took the first binding it found using either Steps (1) or (3), in that
order, and proceeded to relieve the remaining hypotheses without trying
any other bindings of the free variables of that hypothesis.


File: acl2-doc-emacs.info,  Node: FREE-VARIABLES-EXAMPLES,  Next: FREE-VARIABLES-TYPE-PRESCRIPTION,  Prev: FREE-VARIABLES,  Up: FREE-VARIABLES

FREE-VARIABLES-EXAMPLES    examples pertaining to free variables in rules

The examples in the two sub-topics of this topic illustrate the
handling of free variables in rules of class :rewrite (see *note
FREE-VARIABLES-EXAMPLES-REWRITE::) and of class :forward-chaining (see
*note FREE-VARIABLES-EXAMPLES-FORWARD-CHAINING::), respectively.  These
implicitly illustrate free-variables handling in rules of class :linear
as well.  Also see *note FREE-VARIABLES:: and see *note RULE-CLASSES::.

* Menu:

* FREE-VARIABLES-EXAMPLES-FORWARD-CHAINING:: examples pertaining to free variables in forward-chaining rules

* FREE-VARIABLES-EXAMPLES-REWRITE:: examples pertaining to free variables in rewrite rules


File: acl2-doc-emacs.info,  Node: FREE-VARIABLES-EXAMPLES-FORWARD-CHAINING,  Next: FREE-VARIABLES-EXAMPLES-REWRITE,  Prev: FREE-VARIABLES-EXAMPLES,  Up: FREE-VARIABLES-EXAMPLES

FREE-VARIABLES-EXAMPLES-FORWARD-CHAINING    examples pertaining to free variables in forward-chaining rules

The following examples illustrate ACL2's handling of free variables in
forward-chaining rules, as well as user control over how such free
variables are handled.  See *note FREE-VARIABLES:: for a background
discussion.

     ; First let us introduce a transitive operation, op, and prove a
     ; forward-chaining rule stating the transitivity of op.

     (encapsulate
      (((op * *) => *))
      (local (defun op (x y) (< x y)))
      (defthm transitivity-of-op
        (implies (and (op x y) (op y z)) (op x z))
        :rule-classes :forward-chaining))

     ; The following theorem is proved by forward chaining, using the above rule.

     (thm
      (implies (and (op u v) (op v w) (op v a))
               (op u w)))

     ; The proof of the theorem just above succeeds because the term (op u v)
     ; triggers the application of forward-chaining rule transitivity-of-op,
     ; binding x to u and y to v.  Free variable z of that rule is bound to both w
     ; and to a, resulting in the addition of both (op u w) and (op u a) to the
     ; context.  However, (op v a) happens to be at the front of the context, so
     ; if only one free-variable binding had been allowed, then z would have only
     ; been bound to a, not to w, as we now illustrate.

     (add-match-free-override :once (:forward-chaining transitivity-of-op))

     (thm ; FAILS!
      (implies (and (op u v) (op v w) (op v a))
               (op u w)))

     :ubt! 1

     ; Starting over, this time we prove transitivity-of-op as a :match-free :once
     ; forward-chaining rule.  Note that the presence of :match-free eliminates
     ; the free-variables warning that we got the first time.

     (encapsulate
      (((op * *) => *))
      (local (defun op (x y) (< x y)))
      (defthm transitivity-of-op
        (implies (and (op x y) (op y z)) (op x z))
        :rule-classes ((:forward-chaining :match-free :once))))

     (thm ; FAILS!
      (implies (and (op u v) (op v w) (op v a))
               (op u w)))

     ; Notice that if we swap the order of the last two hypotheses the theorem
     ; goes through, because this time (op v w) is first in the context.

     (thm ; SUCCEEDS!
      (implies (and (op u v) (op v a) (op v w))
               (op u w)))

     :u

     ; Now let's try setting the default to :once.

     (set-match-free-default :once)

     ; We still get a free-variables warning when we admit this forward-chaining rule.

     (encapsulate
      (((op * *) => *))
      (local (defun op (x y) (< x y)))
      (defthm transitivity-of-op
        (implies (and (op x y) (op y z)) (op x z))
        :rule-classes ((:forward-chaining))))

     ; This theorem fails--as it should.

     (thm ; FAILS!
      (implies (and (op u v) (op v w) (op v a))
               (op u w)))

     ; But if we convert this rule (or here, all possible rules) to :all rules,
     ; then the proof succeeds.

     (add-match-free-override :all t)

     (thm ; SUCCEEDS!
      (implies (and (op u v) (op v w) (op v a))
               (op u w)))

     ; Now let's test a relatively slow :all case (the next thm below).

     :ubt! 1

     (encapsulate
      (((op1 *) => *)
       ((op3 * * *) => *))
      (local (defun op1 (x) (declare (ignore x)) t))
      (local (defun op3 (x0 x1 x2)
               (declare (ignore x0 x1 x2))
               t))
      (defthm op1-op3-property
        (implies (and (op1 x0) (op1 x1) (op1 x2))
                 (op3 x0 x1 x2))
        :rule-classes ((:forward-chaining :match-free :all))))

     ; The following succeeds, but takes a little time (about a second in one run).

     (thm (implies
           (and (op1 a0) (op1 a1) (op1 a2) (op1 a3) (op1 a4) (op1 a5)
                (op1 a6) (op1 a7) (op1 a8) (op1 a9) (op1 a10) (op1 a11)
                (op1 a12) (op1 a13) (op1 a14) (op1 a15) (op1 a16)
                (op1 a17) (op1 a18) (op1 a19) (op1 a20))
           (op3 a5 a6 a0)))

     (add-match-free-override :once t)

     ; The same theorem now fails because of the add-match-free-override, but is
     ; more than an order of magnitude faster.

     (thm (implies
           (and (op1 a0) (op1 a1) (op1 a2) (op1 a3) (op1 a4) (op1 a5)
                (op1 a6) (op1 a7) (op1 a8) (op1 a9) (op1 a10) (op1 a11)
                (op1 a12) (op1 a13) (op1 a14) (op1 a15) (op1 a16)
                (op1 a17) (op1 a18) (op1 a19) (op1 a20))
           (op3 a5 a6 a0)))

     ; A slight variant succeeds in a negligible amount of time (still with the
     ; :once override above).

     (thm (implies
           (and (op1 a0) (op1 a1) (op1 a2) (op1 a3) (op1 a4) (op1 a5)
                (op1 a6) (op1 a7) (op1 a8) (op1 a9) (op1 a10) (op1 a11)
                (op1 a12) (op1 a13) (op1 a14) (op1 a15) (op1 a16)
                (op1 a17) (op1 a18) (op1 a19) (op1 a20))
           (op3 a5 a20 a20)))

     ; Reality check: This shouldn't give a free-variables warning, and everything
     ; should work great since there are no free variables with this trigger term.

     :ubt! 1

     (encapsulate
      (((op1 *) => *)
       ((op7 * * * * * * *) => *))
      (local (defun op1 (x)
               (declare (ignore x))
               t))
      (local (defun op7 (x0 x1 x2 x3 x4 x5 x6)
               (declare (ignore x0 x1 x2 x3 x4 x5 x6))
               t))
      (defthm op1-op7-property
        (implies (and (op1 x0) (op1 x1) (op1 x2)
                      (op1 x3) (op1 x4) (op1 x5) (op1 x6))
                 (op7 x0 x1 x2 x3 x4 x5 x6))
        :rule-classes ((:forward-chaining
                        :trigger-terms ((op7 x0 x1 x2 x3 x4 x5 x6))))))

     ; The following then succeeds, and very quickly.

     (thm (implies (and (op1 a0) (op1 a1) (op1 a2)
                        (op1 a3) (op1 a4) (op1 a5) (op1 a6))
                   (op7 a4 a6 a5 a6 a6 a6 a6)))


File: acl2-doc-emacs.info,  Node: FREE-VARIABLES-EXAMPLES-REWRITE,  Prev: FREE-VARIABLES-EXAMPLES-FORWARD-CHAINING,  Up: FREE-VARIABLES-EXAMPLES

FREE-VARIABLES-EXAMPLES-REWRITE    examples pertaining to free variables in rewrite rules

The following examples illustrate ACL2's handling of free variables in
rewrite rules, as well as user control over how such free variables are
handled.  See *note FREE-VARIABLES:: for a background discussion.

     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     ;;; Example 1
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     (defstub p2 (x y) t) ; introduce unconstrained function

     ; Get warning because of free variable.  This would be an error if you had
     ; first executed (set-match-free-error t) in order to force yourself to
     ; specify :match-free (illustrated later, below).
     (defaxiom p2-trans
       (implies (and (p2 x y)
                     (p2 y z))
                (p2 x z)))

     ; Succeeds.
     (thm (implies (and (p2 a c)
                        (p2 a b)
                        (p2 c d))
                   (p2 a d)))

     ; The following causes an error because p2-trans is not a rune.
     (add-match-free-override :once p2-trans)

     ; After the following, the rewrite rule p2-trans will only allow one
     ; attempt per hypothesis to bind free variables.
     (add-match-free-override :once (:rewrite p2-trans))

     ; Now this same theorem fails to be proved.  Here's why.  The
     ; context for proving (p2 a d) happens to include the hypotheses in
     ; reverse order.  So when the first hypothesis of p2-trans, namely
     ; (p2 x y), is relieved, where x is bound to a (as we are attempting
     ; to rewrite the current literal (p2 a d)), we find (p2 a b) in the
     ; context before (p2 a c) and hence y is bound to b.  The
     ; instantiated second hypothesis of p2-trans is thus (p2 b d), and
     ; the proof fails.  Before the add-match-free-override form above,
     ; the proof succeeded because the rewriter was allowed to backtrack
     ; and find the other binding for the first hypothesis of p2-trans,
     ; namely, y bound to c.  Then the instantiated second hypothesis of
     ; p2-trans is (p2 c d), which is known to be true in the current
     ; context.
     (thm (implies (and (p2 a c)
                        (p2 a b)
                        (p2 c d))
                   (p2 a d)))

     ; Return to original behavior for binding free variables.
     (add-match-free-override :all t)

     ; Succeeds once again.
     (thm (implies (and (p2 a c)
                        (p2 a b)
                        (p2 c d))
                   (p2 a d)))

     (u) ; undo (add-match-free-override :all t)

     ; This is an error, since no further arguments should appear after
     ; :clear.
     (add-match-free-override :clear t)

     ; Return all rules to original behavior for binding free variables,
     ; regardless of which previous add-match-free-override forms have
     ; been executed.
     (add-match-free-override :clear)

     ; This succeeds just as it did originally.
     (thm (implies (and (p2 a c)
                        (p2 a b)
                        (p2 c d))
                   (p2 a d)))

     (ubt! 'p2-trans) ; back to the start, except retain the defstub

     ; Require that :match-free be specified for :linear and :rewrite rules with
     ; free variables.
     (set-match-free-error t)

     ; Fails because :match-free is missing.
     (defaxiom p2-trans
       (implies (and (p2 x y)
                     (p2 y z))
                (p2 x z)))

     ; Fails because :match-free must be followed by :once or :all.
     (defaxiom p2-trans
       (implies (and (p2 x y)
                     (p2 y z))
                (p2 x z))
       :rule-classes ((:rewrite :match-free nil)))

     ; Succeeds, this time with no warning at all.
     (defaxiom p2-trans
       (implies (and (p2 x y)
                     (p2 y z))
                (p2 x z))
       :rule-classes ((:rewrite :match-free :once)))

     ; Fails because we only bind once (see earlier long comment).
     (thm (implies (and (p2 a c)
                        (p2 a b)
                        (p2 c d))
                   (p2 a d)))

     ; Treat p2-trans as though `:match-free :all' had been specified.
     (add-match-free-override :all (:rewrite p2-trans))

     ; Succeeds since more than one binding is allowed for p2-trans.
     (thm (implies (and (p2 a c)
                        (p2 a b)
                        (p2 c d))
                   (p2 a d)))

     (u)
     (u)

     ; Specify that future :linear and :rewrite rules with free variables
     ; that do not have :match-free specified are treated as though
     ; `:match-free :once' were specified.
     (set-match-free-default :once)

     ; Succeeds without error since `:match-free' is specified, as described
     ; above.  But there is a warning, since :match-free is not specified for this
     ; :rewrite rule.
     (defaxiom p2-trans
       (implies (and (p2 x y)
                     (p2 y z))
                (p2 x z)))

     ; Fails since only single bindings are allowed for p2-trans.
     (thm (implies (and (p2 a c)
                        (p2 a b)
                        (p2 c d))
                   (p2 a d)))

     ; Treat p2-trans as though `:match-free :all' had been specified.
     (add-match-free-override :all t)

     ; Succeeds.
     (thm (implies (and (p2 a c)
                        (p2 a b)
                        (p2 c d))
                   (p2 a d)))

     ; Test searching of ground units, i.e. rewrite rules without variables on the
     ; left side of the conclusion, for use in relieving hypotheses with free
     ; variables.  This is a very contrived example.

     (ubt! 1) ; back to the start

     (encapsulate
      (((p1 *) => *)
       ((p2 * *) => *)
       ((p3 *) => *)
       ((a) => *)
       ((b) => *))
      (local (defun p1 (x) x))
      (local (defun p2 (x y) (list x y)))
      (local (defun p3 (x) x))
      (local (defun a () 0))
      (local (defun b () 0)))

     ; Allow default of :match-free :all (form may be omitted).
     (set-match-free-error nil)

     (defaxiom ax1
       (implies (and (p2 x y)
                     (p1 y))
                (p3 x)))

     (defaxiom p2-a-b
       (p2 (a) (b)))

     (defaxiom p2-a-a
       (p2 (a) (a)))

     (defaxiom p1-b
       (p1 (b)))

     ; Succeeds; see long comment below on next attempt to prove this
     ; theorem.
     (thm (implies (p2 (a) y)
                   (p3 (a))))

     ; Now ax1 will only relieve hypothesis (p2 x y) for one binding of y:
     (add-match-free-override :once t)

     ; Fails when ax1 attempts to rewrite the conclusion to true, because
     ; the most recent ground unit for hypothesis (p2 x y) with x bound
     ; to (a) is rule p2-a-a, which binds y to (a).  If more than one ground
     ; unit could be used then we would backtrack and apply rule p2-a-b,
     ; which binds y to (b) and hence hypothesis (p1 y) of ax1 is
     ; relieved by rule p1-b.
     (thm (implies (p2 (a) y)
                   (p3 (a))))

     ; Return rules to original :match-free behavior.
     (add-match-free-override :clear)

     ; Succeeds once again.
     (thm (implies (p2 (a) y)
                   (p3 (a))))

     ; Just for kicks, change the behavior of a built-in rule irrelevant
     ; to the proof at hand.
     (add-match-free-override :once (:rewrite string<-l-trichotomy))

     ; Still succeeds.
     (thm (implies (p2 (a) y)
                   (p3 (a))))

     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     ;;; Example 2
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

The next example illustrates the use of the break-rewrite facility to
get information about handling of free variables by the rewriter.
Explanation is given after this (edited) transcript.  Input begins on
lines with a prompt (search for "ACL2"); the rest is output.

     ACL2 !>(encapsulate
             ((p1 (u x) t)
              (bad (x) t)
              (p2 (x y z) t)
              (bar (x y) t)
              (foo (x y) t)
              (poo (x y) t)
              (prop (u) t))

             (local (defun p1 (u x) (declare (ignore u x)) nil))
             (local (defun bad (x) (declare (ignore x)) nil))
             (local (defun p2 (x y z) (declare (ignore x y z)) nil))
             (local (defun bar (x y) (declare (ignore x y)) nil))
             (local (defun foo (x y) (declare (ignore x y)) nil))
             (local (defun poo (x y) (declare (ignore x y)) nil))
             (local (defun prop (u) (declare (ignore u)) t))

             (defthm foo-poo
               (implies (syntaxp (equal y 'y3))
                        (equal (foo x y)
                               (poo x y))))

             (defthm lemma-1
               (implies (and (p1 u x)
                             (bad x)
                             (p2 x y z)
                             (bar x y)
                             (equal x x) ; admittedly silly!
                             (foo x y))
                        (prop u))
               :rule-classes ((:rewrite :match-free :all))))

     ; [[ output omitted ]]

     Summary
     Form:  ( ENCAPSULATE ((P1 ...) ...) ...)
     Rules: NIL
     Warnings:  Subsume and Non-rec
     Time:  0.08 seconds (prove: 0.00, print: 0.01, other: 0.06)
      T
     ACL2 !>:brr t
     The monitored runes are:
     NIL
      T
     ACL2 !>:monitor (:rewrite lemma-1) t
     (((:REWRITE LEMMA-1) 'T))
     ACL2 !>(thm (implies (and (p1 u0 x1)
                               (bad x1)
                               (bad x3)
                               (bar x3 y1)
                               (bar x3 y3)
                               (p1 u0 x2)
                               (p1 u0 x3)
                               (p2 x3 y1 z1)
                               (p2 x3 y3 z1))
                          (prop u0)))

     (1 Breaking (:REWRITE LEMMA-1) on (PROP U0):
     1 ACL2 >:eval

     1x (:REWRITE LEMMA-1) failed because :HYP 1 contains free variables.
     The following display summarizes the attempts to relieve hypotheses
     by binding free variables; see :DOC free-variables.

         [1] X : X1
     Failed because :HYP 3 contains free variables Y and Z, for which no
     suitable bindings were found.
         [1] X : X2
     Failed because :HYP 2 rewrote to (BAD X2).
         [1] X : X3
             [3] Z : Z1
                 Y : Y1
     Failed because :HYP 6 rewrote to (FOO X3 Y1).
             [3] Z : Z1
                 Y : Y3
     Failed because :HYP 6 rewrote to (POO X3 Y3).

     1 ACL2 >:unify-subst
          U : U0
     1 ACL2 >

The :eval command above asks the rewriter to attempt to apply the
rewrite rule lemma-1 to the term (prop u0), shown just above the line
with :eval.  As we can see at the end, the variable u in the conclusion
of lemma-1 is being bound to the variable u0 in the conjecture.  The
first hypothesis of lemma-1 is (p1 u x), so the rewriter looks for some
x for which (p1 u0 x) is known to be true.  It finds x1, and then goes
on to consider the second hypothesis, (bad x).  Since the theorem we
are proving has (bad x1) in the hypothesis and x is currently bound to
x1, the rewriter is satisfied and moves on to the third hypothesis of
lemma-1, (p2 x y z).  However, x is bound to x1 and there are no
instances of y and z for which (p2 x1 y z) is known in the current
context.  All of the above analysis is summarized in the first part of
the output from :eval above:

         [1] X : X1
     Failed because :HYP 3 contains free variables Y and Z, for which no
     suitable bindings were found.

Thus, the binding of x to x1 on behalf of the first hypothesis has
failed.

The rewriter now backs up to look for other values of x that satisfy the
first hypothesis, and finds x2 because our current theorem has a
hypothesis of (p1 u0 x2).  But this time, the second hypothesis of
lemma-1, (bad x), is not known to be true for x; that is, (bad x2) does
not rewrite to t; in fact, it rewrites to itself.  That explains the
next part of the output from :eval above:

         [1] X : X2
     Failed because :HYP 2 rewrote to (BAD X2).

The rewriter now backs up again to look for other values of x that
satisfy the first hypothesis, and finds x3 because our current theorem
has a hypothesis of (p1 u0 x3).  This time, the second hypothesis of
lemma-1 is not a problem, and moreover, the rewriter is able to bind y
and z to y1 and z1, respectively, in order to satisfy the third
hypothesis, (p2 x y z): that is, (p2 x2 y1 z1) is known in the current
context.  That explains more of the above output from :eval:

         [1] X : X3
             [3] Z : Z1
                 Y : Y1

Unfortunately, the sixth hypothesis, (foo x y), rewrites to itself
under the above bindings:

     Failed because :HYP 6 rewrote to (FOO X3 Y1).

So the rewriter looks for other bindings to satisfy the third
hypothesis and finds these.

             [3] Z : Z1
                 Y : Y3

This time, the sixth hypothesis can be rewritten under the above
bindings, from (foo x3 y3) to (poo x3 y3) by lemma foo-poo, but still
not to t.

     Failed because :HYP 6 rewrote to (POO X3 Y3).

There are no more free variable bindings to try, so this concludes the
output from :eval.

     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     ;;; Example 3
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

The next pair of examples illustrates so-called "binding hypotheses"
(see *note FREE-VARIABLES::) and explores some of their subtleties.
The first shows binding hypotheses in action on a simple example.  The
second shows how binding hypotheses interact with equivalence relations
and explains the role of double-rewrite.

Our first example sets up a theory with two user-supplied rewrite
rules, one of which has a binding hypothesis.  Below we explain how
that binding hypothesis contributes to the proof.

     ; Define some unary functions.
     (defun f (x) (declare (ignore x)) t)
     (defun g (x) x)
     (defun h (x) x)
     (defun k (x) x)

     ; Prove some simple lemmas.  Note the binding hypothesis in g-rewrite.
     (defthm f-k-h
       (f (k (h x))))
     (defthm g-rewrite
            (implies (and (equal y (k x)) ; binding hypothesis
                          (f y))
                     (equal (g x) y)))

     ; Restrict to a theory that includes the above lemmas but avoids the above
     ; definitions.
     (in-theory (union-theories (theory 'minimal-theory)
                                '(f-k-h g-rewrite)))

     ; Prove a theorem.
     (thm (equal (g (h a)) (k (h a))))

Let us look at how ACL2 uses the above binding hypothesis in the proof
of the preceding thm form.  The rewriter considers the term (g (h a))
and finds a match with the left-hand side of the rule g-rewrite, binding
x to (h a).  The first hypothesis binds y to the result of rewriting (k
x) in the current context, where the variable x is bound to the term (h
a); thus y is bound to (k (h a)).  The second hypothesis, (f y), is
then rewritten under this binding, and the result is t by application
of the rewrite rule f-k-h.  The rule g-rewrite is then applied under
the already-mentioned binding of x to (h a).  This rule application
triggers a recursive rewrite of the right-hand side of g-rewrite, which
is y, in a context where y is bound (as discussed above) to (k (h a)).
The result of this rewrite is that same term, (k (h a)).  The original
call of equal then trivially rewrites to t.

We move on now to our second example, which is similar but involves a
user-defined equivalence relation.  You may find it helpful to review
:equivalence rules; see *note EQUIVALENCE::.

Recall that when a hypothesis is a call of an equivalence relation
other than equal, the second argument must be a call of double-rewrite
in order for the hypothesis to be treated as a binding hypothesis.
That is indeed the case below; an explanation follows.

     ; Define an equivalence relation.
     (defun my-equiv (x y) (equal x y))
     (defequiv my-equiv) ; introduces rule MY-EQUIV-IS-AN-EQUIVALENCE

     ; Define some unary functions
     (defun f (x) (declare (ignore x)) t)
     (defun g (x) x)
     (defun h1 (x) x)
     (defun h2 (x) x)

     ; Prove some simple lemmas.  Note the binding hypothesis in lemma-3.
     (defthm lemma-1
       (my-equiv (h1 x) (h2 x)))
     (defthm lemma-2
       (f (h2 x)))
     (defthm lemma-3
            (implies (and (my-equiv y (double-rewrite x)) ; binding hypothesis
                          (f y))
                     (equal (g x) y)))

     ; Restrict to a theory that includes the above lemmas but avoids the above
     ; definitions.
     (in-theory (union-theories (theory 'minimal-theory)
                                '(lemma-1 lemma-2 lemma-3
                                          my-equiv-is-an-equivalence)))

     ; Prove a theorem.
     (thm (equal (g (h1 a)) (h2 a)))

The proof succeeds much as in the first example, but the following
observation is key: when ACL2 binds y upon considering the first
hypothesis of lemma-3, it rewrites the term (double-rewrite x) in a
context where it need only preserve the equivalence relation my-equiv.
At this point, x is bound by applying lemma-3 to the term (g (h1 a));
so, x is bound to (h1 a).  The rule lemma-1 then applies to rewrite
this occurrence of x to (h2 a), but only because it suffices to
preserve my-equiv.  Thus y is ultimately bound to (h2 a), and the proof
succeeds as one would expect.

If we tweak the above example slightly by disabling the user's
equivalence rune, then the proof of the thm form fails because the
above rewrite of (double-rewrite x) is done in a context where it no
longer suffices to preserve my-equiv as we dive into the second
argument of my-equiv in the first hypothesis of lemma-3; so, lemma-1
does not apply this time.

     (in-theory (union-theories (theory 'minimal-theory)
                                '(lemma-1 lemma-2 lemma-3)))

     ; Proof fails in this case!
     (thm (equal (g (h1 a)) (h2 a)))


File: acl2-doc-emacs.info,  Node: FREE-VARIABLES-TYPE-PRESCRIPTION,  Prev: FREE-VARIABLES-EXAMPLES,  Up: FREE-VARIABLES

FREE-VARIABLES-TYPE-PRESCRIPTION    matching for free variable in type-prescription rules

We assume familiarity with the issue of dealing with free variables in
hypotheses; see *note FREE-VARIABLES::.

By default, starting with Version  4.3, ACL2 attempts all possible
matches for free variables.  Consider the following example.

     (defstub f1 (x) t)
     (defstub f2 (x y) t)
     (defstub f3 (y) t)

     (defaxiom f1-prop
       (implies (and (f2 x y) ; <-- y is free in this hypothesis
                     (f3 y))
                (f1 x))       ; <-- (f1 x) is the type-term (type is `non-nil')
       :rule-classes :type-prescription)

     ; Succeeds:
     (thm (implies (and (f2 a b)
                        (f3 b))
                   (f1 a)))

     ; The following fails unless we try more than one match for free variables in
     ; hypotheses.
     (thm (implies (and (f2 a b)
                        (f2 a c)
                        (f2 a d)
                        (f3 b))
                   (f1 a)))

There may be times when you want to match only the first free variable.
In that case, you can write a function of two arguments, the
type-prescription rune being applied and the current ACL2 world, that
prohibits multiple matching for those times.  Your function is then
`attached' to the built-in constrained function, oncep-ts.  The
following examples are intended to explain how this works.

First, let us disallow all mutliple matching of free variables (i.e.,
implement the behavior often referred to as ":match-free :once"; see
*note FREE-VARIABLES::).

     (defun oncep-tp-always (rune wrld)
       (declare (ignore rune wrld)
                (xargs :mode :logic :guard t))
       t)

     (defattach oncep-tp oncep-tp-always)

The second thm form above will now fail, because only one free-variable
match is permitted for the first hypothesis of rule f1-prop above.

Now suppose that instead, we want to disallow multiple matches for free
variables in hypotheses of type-prescription rules _except_ for the
rule f1-prop above.  With the following events, the second thm form
above once again succeeds.

     (defun oncep-tp-always-except-f1-prop (rune wrld)
       (declare (ignore wrld)
                (xargs :mode :logic :guard (and (consp rune)
                                                (consp (cdr rune))
                                                (symbolp (cadr rune)))))
       (not (eq (base-symbol rune) 'f1-prop)))

     (defattach oncep-tp oncep-tp-always-except-f1-prop)

In general, your defattach event will attach a function symbol to
oncep-tp.  The guard of that function symbol must be implied by the
tuard of oncep-tp:

     ACL2 !>:args oncep-tp

     Function         ONCEP-TP
     Formals:         (RUNE WRLD)
     Signature:       (ONCEP-TP * *)
                      => *
     Guard:           (AND (PLIST-WORLDP WRLD)
                           (CONSP RUNE)
                           (CONSP (CDR RUNE))
                           (SYMBOLP (CADR RUNE)))
     Guards Verified: T
     Defun-Mode:      :logic
     Type:            built-in (or unrestricted)

      ONCEP-TP
     ACL2 !>


File: acl2-doc-emacs.info,  Node: GENERALIZE,  Next: INDUCTION,  Prev: FREE-VARIABLES,  Up: RULE-CLASSES

GENERALIZE    make a rule to restrict generalizations

See *note 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.

     Example:
     (defthm integer-listp-rev
       (implies (integer-listp x)
                (integer-listp (rev x)))
       :rule-classes :generalize)

     General Form:
     any theorem

To use a :generalize rule, the system waits until it has decided to
generalize some term, term, by replacing it with some new variable v.
If any :generalize formula can be instantiated so that some non-variable
subterm becomes term, then that instance of the formula is added as a
hypothesis.  Thus for the example above, if the term (rev x2) is
generalized to the variable rv during a proof, then the following is
added as a hypothesis when generalizing to a new goal.

     (implies (integer-listp x2)
              (integer-listp rv))

At the moment, the best description of how ACL2 :generalize rules are
used may be found in the discussion of "Generalize Rules," page 248 of
A Computational Logic Handbook, or "Generalization," page 132 of
"Computer-Aided Reasoning: An Approach."  Also see *note
INTRODUCTION-TO-THE-THEOREM-PROVER:: for detailed tutorial on using ACL2
to prove theorems, which includes some discussion of generalization.


File: acl2-doc-emacs.info,  Node: INDUCTION,  Next: LINEAR,  Prev: GENERALIZE,  Up: RULE-CLASSES

INDUCTION    make a rule that suggests a certain induction

     Example:
     (defthm recursion-by-sub2-induction-rule
       t
       :rule-classes ((:induction :pattern (* 1/2 i)
                                  :condition (and (integerp i) (>= i 0))
                                  :scheme (recursion-by-sub2 i))))

In ACL2, as in Nqthm, the functions in a conjecture "suggest" the
inductions considered by the system.  Because every recursive function
must be admitted with a justification in terms of a measure that
decreases in a well-founded way on a given set of "controlling"
arguments, every recursive function suggests a dual induction scheme
that "unwinds" the function from a given application.

For example, since append (actually binary-append, but we'll ignore the
distinction here) decomposes its first argument by successive cdrs as
long as it is a non-nil true list, the induction scheme suggested by
(append x y) has a base case supposing x to be either not a true list
or to be nil and then has an induction step in which the induction
hypothesis is obtained by replacing x by (cdr x).  This substitution
decreases the same measure used to justify the definition of append.
Observe that an induction scheme is suggested by a recursive function
application only if the controlling actuals are distinct variables, a
condition that is sufficient to ensure that the "substitution" used to
create the induction hypothesis is indeed a substitution and that it
drives down a certain measure.  In particular, (append (foo x) y) does
not suggest an induction unwinding append because the induction scheme
suggested by (append x y) requires that we substitute (cdr x) for x and
we cannot do that if x is not a variable symbol.

Once ACL2 has collected together all the suggested induction schemes it
massages them in various ways, combining some to simultaneously unwind
certain cliques of functions and vetoing others because they "flaw"
others.  We do not further discuss the induction heuristics here; the
interested reader should see Chapter XIV of A Computational Logic
(Boyer and Moore, Academic Press, 1979) which represents a fairly
complete description of the induction heuristics of ACL2.

However, unlike Nqthm, ACL2 provides a means by which the user can
elaborate the rules under which function applications suggest induction
schemes.  Such rules are called :induction rules.  The definitional
principle automatically creates an :induction rule, named (:induction
fn), for each admitted recursive function, fn.  It is this rule that
links applications of fn to the induction scheme it suggests.  Disabling
(:induction fn) will prevent fn from suggesting the induction scheme
derived from its recursive definition.  It is possible for the user to
create additional :induction rules by using the :induction rule class in
defthm.

Technically we are "overloading" defthm by using it in the creation of
:induction rules because no theorem need be proved to set up the
heuristic link represented by an :induction rule.  However, since
defthm is generally used to create rules and rule-class objects are
generally used to specify the exact form of each rule, we maintain that
convention and introduce the notion of an :induction rule.  An
:induction rule can be created from any lemma whatsoever.

     General Form of an :induction Lemma or Corollary:
     T

     General Form of an :induction rule-class:
     (:induction :pattern pat-term
                 :condition cond-term
                 :scheme scheme-term)

where pat-term, cond-term, and scheme-term are all terms, pat-term is
the application of a function symbol, fn, scheme-term is the
application of a function symbol, rec-fn, that suggests an induction,
and, finally, every free variable of cond-term and scheme-term is a
free variable of pat-term.  We actually check that rec-fn is either
recursively defined -- so that it suggests the induction that is
intrinsic to its recursion -- or else that another :induction rule has
been proved linking a call of rec-fn as the :pattern to some scheme.

The induction rule created is used as follows.  When an instance of the
:pattern term occurs in a conjecture to be proved by induction and the
corresponding instance of the :condition term is known to be non-nil
(by type reasoning alone), the corresponding instance of the :scheme
term is created and the rule "suggests" the induction, if any,
suggested by that term.  (Analysis of that term may further involve
induction rules, though the applied rule is removed from consideration
during that further analysis, in order to avoid looping.)  If rec-fn is
recursive, then the suggestion is the one that unwinds that recursion.

Consider, for example, the example given above,

     (:induction :pattern (* 1/2 i)
                 :condition (and (integerp i) (>= i 0))
                 :scheme (recursion-by-sub2 i)).

In this example, we imagine that recursion-by-sub2 is the function:

     (defun recursion-by-sub2 (i)
       (if (and (integerp i)
                (< 1 i))
           (recursion-by-sub2 (- i 2))
           t))

Observe that this function recursively decomposes its integer argument
by subtracting 2 from it repeatedly and stops when the argument is 1 or
less.  The value of the function is irrelevant; it is its induction
scheme that concerns us.  The induction scheme suggested by
(recursion-by-sub2 i) is

     (and (implies (not (and (integerp i) (< 1 i)))   ; base case
                   (:p i))
          (implies (and (and (integerp i) (< 1 i))    ; induction step
                        (:p (- i 2)))
                   (:p i)))

We can think of the base case as covering two situations.  The first is
when i is not an integer.  The second is when the integer i is 0 or 1.
In the base case we must prove (:p i) without further help.  The
induction step deals with those integer i greater than 1, and
inductively assumes the conjecture for i-2 while proving it for i.  Let
us call this scheme "induction on i by twos."

Suppose the above :induction rule has been added.  Then an occurrence
of, say, (* 1/2 k) in a conjecture to be proved by induction would
suggest, via this rule, an induction on k by twos, provided k was known
to be a nonnegative integer.  This is because the induction rule's
:pattern is matched in the conjecture, its :condition is satisfied, and
the :scheme suggested by the rule is that derived from
(recursion-by-sub2 k), which is induction on k by twos.  Similarly, the
term (* 1/2 (length l)) would suggest no induction via this rule, even
though the rule "fires" because it creates the :scheme
(recursion-by-sub2 (length l)) which suggests no inductions unwinding
recursion-by-sub2 (since the controlling argument of recursion-by-sub2
in this :scheme is not a variable symbol).

Continuing this example one step further illustrates the utility of
:induction rules.  We could define the function recursion-by-cddr that
suggests the induction scheme decomposing its consp argument two cdrs
at a time.  We could then add the :induction rule linking (* 1/2
(length x)) to (recursion-by-cddr x) and arrange for (* 1/2 (length l))
to suggest induction on l by cddr.

Observe that :induction rules require no proofs to be done.  Such a rule
is merely a heuristic link between the :pattern term, which may occur in
conjectures to be proved by induction, and the :scheme term, from which
an induction scheme may be derived.  Hence, when an :induction
rule-class is specified in a defthm event, the theorem proved is
irrelevant.  The easiest theorem to prove is, of course, t.  Thus, we
suggest that when an :induction rule is to be created, the following
form be used:

     (defthm name T
       :rule-classes ((:induction :pattern pat-term
                                  :condition cond-term
                                  :scheme scheme-term)))

The name of the rule created is (:induction name).  When that rune is
disabled the heuristic link between pat-term and scheme-term is broken.


File: acl2-doc-emacs.info,  Node: LINEAR,  Next: META,  Prev: INDUCTION,  Up: RULE-CLASSES

LINEAR    make some arithmetic inequality rules

See *note 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.

     Example:
     (defthm length-member-leq-length       If inequality reasoning begins to
       (implies (and (eqlablep e)           consider how (length (member a b))
                     (true-listp x))        compares to any other term, add to
                (<= (length (member e x))   the set of known inequalities the fact
                    (length x)))            that it is no larger than (length b),
       :rule-classes :linear)               provided (eqlablep a) and
                                            (true-listp b) rewrite to t.

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

Note: One :linear rule class object might create many linear arithmetic
rules from the :corollary formula.  To create the rules, we first
flatten the and and implies structure of the formula, transforming it
into a conjunction of formulas, each of the form

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

where no hypothesis is a conjunction and rel is one of the inequality
relations <, <=, =, >, or >=.  If necessary, the hypothesis of such a
conjunct may be vacuous.  We create a :linear rule for each such
conjunct, if possible, and otherwise cause an error.

Each rule has one or more "trigger terms" which may be specified by the
user using the :trigger-terms field of the rule class or which may be
defaulted to values chosen by the system.  We discuss the determination
of trigger terms after discussing how linear rules are used.

:Linear rules are used by an arithmetic decision procedure during
rewriting.  See *note LINEAR-ARITHMETIC:: and see *note
NON-LINEAR-ARITHMETIC::.  Here we assume that the reader is familiar
with the material described in linear-arithmetic.

Recall that we eliminate the unknowns of an inequality in term-order,
largest unknowns first.  (See *note TERM-ORDER::.)  In order to
facilitate this strategy, we store the inequalities in "linear pots".
For purposes of the present discussion, let us say that an inequality
is "about" its largest unknown.  Then, all of the inequalities about a
particular unknown are stored in the same linear pot, and the pot is
said to be "labeled" with that unknown.  This storage layout groups all
of the inequalities which are potential candidates for cancellation
with each other into one place.  It is also key to the efficient
operation of :linear rules.

If the arithmetic decision procedure has stabilized and not yielded a
contradiction, we scan through the list of linear pots examining each
label as we go.  If the trigger term of some :linear rule can be
instantiated to match the label, we so instantiate that rule and
attempt to relieve the hypotheses with general-purpose rewriting.  If
we are successful, we add the rule's instantiated conclusion to our set
of inequalities.  This may let cancellation continue.

Note: Problems may arise if you explicitly store a linear lemma under a
trigger term that, when instantiated, is not the largest unknown in the
instantiated concluding inequality.  Suppose for example you store the
linear rule (<= (fn i j) (/ i (* j j))) under the trigger term (fn i j).
Then when the system "needs" an inequality about (fn a b), (i.e.,
because (fn a b) is the label of some linear pot, and hence the largest
unknown in some inequality), it will appeal to the rule and deduce (<=
(fn a b) (/ a (* b b))).  However, the largest unknown in this
inequality is (/ a (* b b)) and hence it will be stored in a linear pot
labeled with (/ a (* b b)).  The original, triggering inequality which
is in a pot about (fn a b) will therefore not be cancelled against the
new one.  It is generally best to specify as a trigger term one of the
"maximal" terms of the polynomial, as described below.

We now describe how the trigger terms are determined.  Most of the
time, the trigger terms are not specified by the user and are instead
selected by the system.  However, the user may specify the terms by
including an explicit :trigger-terms field in the rule class, e.g.,

     General Form of a Linear Rule Class:
     (:LINEAR :COROLLARY formula
              :TRIGGER-TERMS (term1 ... termk))

Each termi must be a term and must not be a variable, quoted constant,
lambda application, let-expression or if-expression.  In addition, each
termi must be such that if all the variables in the term are
instantiated and then the hypotheses of the corollary formula are
relieved (possibly instantiating additional free variables), then all
the variables in the concluding inequality are instantiated.  We
generate a linear rule for each conjuctive branch through the corollary
and store each rule under each of the specified triggers.  Thus, if the
corollary formula contains several conjuncts, the variable restrictions
on the termi must hold for each conjunct.

If :trigger-terms is omitted the system computes a set of trigger terms.
Each conjunct of the corollary formula may be given a unique set of
triggers depending on the variables that occur in the conjunct and the
addends that occur in the concluding inequality.  In particular, the
trigger terms for a conjunct is the list of all "maximal addends" in
the concluding inequality.

The "addends" of (+ x y) and (- x y) are the union of the addends of x
and y.  The addends of (- x) and (* n x), where n is a rational
constant, is just {x}.  The addends of an inequality are the union of
the addends of the left- and right-hand sides.  The addends of any
other term, x, is {x}.

A term is maximal for a conjunct (implies hyps concl) of the corollary
if (a) the term is a non-variable, non-quote, non-lambda application,
non-let and non-if expression, (b) the term contains enough variables
so that when they are instantiated and the hypotheses are relieved
(which may bind some free variables; see *note FREE-VARIABLES::) then
all the variables in concl are instantiated, and (c) no other addend is
always "bigger" than the term, in the technical sense described below.

The technical notion referenced above depends on the notion of
_fn-count_, the number of function symbols in a term, and
_pseudo-fn-count_, which is essentially the number of function symbols
implicit in a constant (see *note TERM-ORDER::, specifically the
discussion of "pseudo-function application count" at the end).  We say
term1 is always bigger than term2 if all instances of term1 have a
larger fn-count (actually lexicographic order of fn-count and
pseudo-fn-count) than the corresponding instances of term2.  This is
equivalent to saying that the fn-count of term1 is larger than that of
term2 (by "fn-count" here we mean the lexicographic order of fn-count
and pseudo-fn-count) and the variable bag for term2 is a subbag of that
for term1.  For example, (/ a (* b b)) is always bigger than (fn a b)
because the first has two function applications and {a b} is a subbag
of a b b, but (/ a (* b b)) is not always bigger than (fn a x).


File: acl2-doc-emacs.info,  Node: META,  Next: REFINEMENT,  Prev: LINEAR,  Up: RULE-CLASSES

META    make a :meta rule (a hand-written simplifier)

See *note 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.

Meta rules extend the ACL2 simplifier with hand-written code to
transform certain terms to equivalent ones.  To add a meta rule, the
:corollary formula must establish that the hand-written "metafunction"
preserves the meaning of the transformed term.

     Examples:
     (defthm fn-correct-1                ; Modify the rewriter to use fn to
       (equal (evl x a)                  ; transform terms that are calls of
              (evl (fn x) a))            ; nth or of foo.
       :rule-classes ((:meta :trigger-fns (nth foo))))

     (defthm fn-correct-2                ; As above, but this illustrates
       (implies (and (pseudo-termp x)    ; that without loss of generality we
                     (alistp a))         ; may restrict x to be shaped like a
                (equal (evl x a)         ; term and a to be an alist.
                       (evl (fn x) a)))
       :rule-classes ((:meta :trigger-fns (nth foo))))

     (defthm fn-correct-3                ; As above (with or without the
       (implies (and (pseudo-termp x)    ; hypotheses on x and a), with the
                     (alistp a)          ; additional restriction that the
                     (evl (hyp-fn x) a)) ; meaning of (hyp-fn x) is true in
                (equal (evl x a)         ; the current context.  That is, the
                       (evl (fn x) a)))  ; applicability of the transformation
       :rule-classes                     ; may be dependent upon some computed
       ((:meta :trigger-fns (nth foo)))) ; hypotheses.

While our intention is that the set of ACL2 documentation topics is
self-contained, readers might find it useful to see the following paper
for an introduction to meta reasoning in ACL2.

     W. A. Hunt, Jr., R. B. Krug, M. Kaufmann, J S. Moore and E. W.
     Smith, "Meta Reasoning in ACL2."  TPHOLs 2005, ed. J. Hurd and T.
     F. Melham, LNCS 3603, Springer-Verlag, Berlin, 2005, pp. 163-178.

A non-nil list of function symbols must be supplied as the value of the
:trigger-fns field in a :meta rule class object (except that a macro
alias can stand in for a function symbol; see *note ADD-MACRO-ALIAS::).

* Menu:

* EVALUATOR-RESTRICTIONS:: some restrictions on the use of evaluators in meta-level rules

     General Forms:
     (implies (and (pseudo-termp x)        ; this hyp is optional
                   (alistp a)              ; this hyp is optional
                   (ev (hyp-fn x ...) a)   ; this hyp is optional
                   ; meta-extract hyps may also be included (see below)
                   )
              (equiv (ev x a)
                     (ev (fn x ...) a)))

where equiv is a known equivalence relation, x and a are distinct
variable names, and ev is an evaluator function (see below), and fn is
a function symbol, as is hyp-fn when provided.  The arguments to fn and
hyp-fn should be identical.  In the most common case, both take a
single argument, x, which denotes the term to be simplified.  If fn
and/or hyp-fn are guarded, their guards should be trivially implied by
pseudo-termp.  We say the theorem above is a "metatheorem" or
"metalemma" and fn is a "metafunction", and hyp-fn is a "hypothesis
metafunction".

If "..." is empty, i.e., the metafunctions take just one argument, we
say they are "vanilla flavored."  If "..." is non-empty, we say the
metafunctions are "extended."  Extended metafunctions can access state
and context sensitive information to compute their results, within
certain limits.  We discuss vanilla metafunctions here and recommend a
thorough understanding of them before proceeding (at which time see
*note EXTENDED-METAFUNCTIONS::).

Additional hypotheses are supported, called "meta-extract hypotheses".
These allow metafunctions to depend on the validity of certain terms
extracted from the context or the logical world.  These hypotheses
provide a relatively advanced form of metatheorem so we explain them
elsewhere; see *note META-EXTRACT::.

One might think that metafunctions and (if supplied) hypothesis
metafunctions must be executable: that is, not constrained (i.e.,
introduced in the signature of encapsulate events), and not declared
:non-executable.  After all, there is no point in installing a
simplifier that cannot be run!  However, such a restriction is not
enforced, because one could introduce a metafunction using encapsulate
and then use defattach to attach it to an executable function; see
*note DEFATTACH::.

We defer discussion of the case in which there is a hypothesis
metafunction and for now address the case in which the other two
hypotheses are present.

In the discussion below, we refer to the argument, x, of fn and hyp-fn
as a "term."  When these metafunctions are executed by the simplifier,
they will be applied to (the quotations of) terms.  But during the
proof of the metatheorem itself, x may not be the quotation of a term.
If the pseudo-termp hypothesis is omitted, x may be any object.  Even
with the pseudo-termp hypothesis, x may merely "look like a term" but
use non-function symbols or function symbols of incorrect arity.  In
any case, the metatheorem is stronger than necessary to allow us to
apply the metafunctions to terms, as we do in the discussion below.  We
return later to the question of proving the metatheorem.

Suppose the general form of the metatheorem above is proved with the
pseudo-termp and alistp hypotheses.  Then when the simplifier
encounters a term, (h t1 ... tn), that begins with a function symbol,
h, listed in :trigger-fns, it applies the metafunction, fn, to the
quotation of the term, i.e., it evaluates (fn '(h t1 ... tn)) to obtain
some result, which can be written as 'val.  If 'val is different from
'(h t1 ... tn) and val is a term, then (h t1 ... tn) is replaced by
val, which is then passed along for further rewriting.  Because the
metatheorem establishes the correctness of fn for all terms (even
non-terms!), there is no restriction on which function symbols are
listed in the :trigger-fns.  Generally, of course, they should be the
symbols that head up the terms simplified by the metafunction fn.  See
*note TERM-TABLE:: for how one obtains some assistance towards
guaranteeing that val is indeed a term.

The "evaluator" function, ev, is a function that can evaluate a certain
class of expressions, namely, all of those composed of variables,
constants, and applications of a fixed, finite set of function symbols,
g1, ..., gk.  Generally speaking, the set of function symbols handled
by ev is chosen to be exactly the function symbols recognized and
manipulated by the metafunctions being introduced.  For example, if fn
manipulates expressions in which 'equal and 'binary-append occur as
function symbols, then ev is generally specified to handle equal and
binary-append.  The actual requirements on ev become clear when the
metatheorem is proved.  The standard way to introduce an evaluator is to
use the ACL2 macro defevaluator, though this is not strictly necessary.
See *note DEFEVALUATOR:: if you want details.

[Aside for the logic-minded.] Why are we justified in using
metafunctions this way?  Suppose (fn 'term1) is 'term2.  What justifies
replacing term1 by term2?  The first step is to assert that term1 is
(ev 'term1 a), where a is an alist that maps 'var to var, for each
variable var in term1.  This step is incorrect, because 'term1 may
contain function symbols other than the ones, g1, ..., gk, that ev
knows how to handle.  But we can grow ev to a "larger" evaluator, ev*,
an evaluator for all of the symbols that occur in term1 or term2.  We
can prove that ev* satisfies the constraints on ev, provided no
defaxiom events are adding constraints to ev (or callers of ev, and
recursively); ACL2 checks this additional property.  Hence, the
metatheorem holds for ev* in place of ev, by functional instantiation.
We can then carry out the proof of the equivalence of term1 and term2
as follows: Fix a to be an alist that maps the quotations of the
variables of term1 and term2 to themselves.  Then,

     term1 = (ev* 'term1 a)      ; (1) by construction of ev* and a
           = (ev* (fn 'term1) a) ; (2) by the metatheorem for ev*
           = (ev* 'term2 a)      ; (3) by evaluation of fn
           = term2               ; (4) by construction of ev* and a

Note that in line (2) above, where we appeal to the (functional
instantiation of the) metatheorem, we can relieve its (optional)
pseudo-termp and alistp hypotheses by appealing to the facts that term1
is a term and a is an alist by construction.  [End of Aside for the
logic-minded.]

There are subtleties related to the notion of "growing" ev to a
"larger" evaluator, as mentioned in the paragraph just above.  For
corresponding restrictions on :meta rules, see *note
EVALUATOR-RESTRICTIONS::.

Finally, we turn to the second case, in which there is a hypothesis
metafunction.  In that case, consider as before what happens when the
simplifier encounters a term, (h t1 ... tn), where h is listed in
:trigger-fns.  This time, after it applies fn to '(h t1 ... tn) to
obtain the quotation of some new term, 'val, it then applies the
hypothesis metafunction, hyp-fn.  That is, it evaluates (hyp-fn '(h t1
... tn)) to obtain some result, which can be written as 'hyp-val.  If
hyp-val is not in fact a term, the metafunction is not used.  Provided
hyp-val is a term, the simplifier attempts to establish (by
conventional backchaining) that this term is non-nil in the current
context.  If this attempt fails, then the meta rule is not applied.
Otherwise, (h t1...tn) is replaced by val as in the previous case
(where there was no hypothesis metafunction).

Why is it justified to make this extension to the case of hypothesis
metafunctions?  First, note that the rule

     (implies (and (pseudo-termp x)
                   (alistp a)
                   (ev (hyp-fn x) a))
              (equal (ev x a)
                     (ev (fn x) a)))

is logically equivalent to the rule

     (implies (and (pseudo-termp x)
                   (alistp a))
              (equal (ev x a)
                     (ev (new-fn x) a)))

where (new-fn x) is defined to be (list 'if (hyp-fn x) (fn x) x).  (If
we're careful, we realize that this argument depends on making an
extension of ev to an evaluator ev* that handles if and the functions
manipulated by hyp-fn.)  If we write 'term for the quotation of the
present term, and if (hyp-fn 'term) and (fn 'term) are both terms, say
hyp1 and term1, then by the previous argument we know it is sound to
rewrite term to (if hyp1 term1 term).  But since we have established in
the current context that hyp1 is non-nil, we may simplify (if hyp1
term1 term) to term1, as desired.

We now discuss the role of the pseudo-termp hypothesis.  (Pseudo-termp
x) checks that x has the shape of a term.  Roughly speaking, it ensures
that x is a symbol, a quoted constant, or a true list consisting of a
lambda expression or symbol followed by some pseudo-terms.  Among the
properties of terms not checked by pseudo-termp are that variable
symbols never begin with ampersand, lambda expressions are closed, and
function symbols are applied to the correct number of arguments.  See
*note PSEUDO-TERMP::.

There are two possible roles for pseudo-termp in the development of a
metatheorem: it may be used as the guard of the metafunction and/or
hypothesis metafunction and it may be used as a hypothesis of the
metatheorem.  Generally speaking, the pseudo-termp hypothesis is
included in a metatheorem only if it makes it easier to prove.  The
choice is yours.  (An extreme example of this is when the metatheorem
is invalid without the hypothesis!)  We therefore address ourselves the
question: should a metafunction have a pseudo-termp guard?  A
pseudo-termp guard for a metafunction, in connection with other
considerations described below, improves the efficiency with which the
metafunction is used by the simplifier.

To make a metafunction maximally efficient you should (a) provide it
with a pseudo-termp guard and exploit the guard when possible in coding
the body of the function (see *note GUARDS-AND-EVALUATION::, especially
the section on efficiency issues), (b) verify the guards of the
metafunction (see *note VERIFY-GUARDS::), and (c) compile the
metafunction (see *note COMP::).  When these three steps have been
taken the simplifier can evaluate (fn 'term1) by running the compiled
"primary code" (see *note GUARDS-AND-EVALUATION::) for fn directly in
Common Lisp.  (Note however that explicit compilation may be
suppressed; see *note COMPILATION::.)

Before discussing efficiency issues further, let us review for a moment
the general case in which we wish to evaluate (fn 'obj) for some :logic
function.  We must first ask whether the guards of fn have been
verified.  If not, we must evaluate fn by executing its logic
definition.  This effectively checks the guards of every subroutine and
so can be slow.  If, on the other hand, the guards of fn have been
verified, then we can run the primary code for fn, provided 'obj
satisfies the guard of fn.  So we must next evaluate the guard of fn on
'obj.  If the guard is met, then we run the primary code for fn,
otherwise we run the logic code.

Now in the case of a metafunction for which the three steps above have
been followed, we know the guard is (implied by) pseudo-termp and that
it has been verified.  Furthermore, we know without checking that the
guard is met (because term1 is a term and hence 'term1 is a
pseudo-termp).  Hence, we can use the compiled primary code directly.

We strongly recommend that you compile your metafunctions, as well as
all their subroutines (unless explicit compilation is suppressed; see
*note COMPILATION::).  Guard verification is also recommended.

Finally, we present a very simple example of the use of :meta rules,
based on one provided by Robert Krug.  This example illustrates a trick
for avoiding undesired rewriting after applying a metafunction or any
other form of rewriting.  To elaborate: in general, the term t2
obtained by applying a metafunction to a term t1 is then handed
immediately to the rewriter, which descends recursively through the
arguments of function calls to rewrite t2 completely.  But if t2 shares
a lot of structure with t1, then it might not be worthwhile to rewrite
t2 immediately.  (A rewrite of t2 will occur anyhow the next time a
goal is generated.)  The trick involves avoiding this rewrite by
wrapping t2 inside a call of hide, which in turn is inside a call of a
user-defined "unhiding" function, unhide.

     (defun unhide (x)
       (declare (xargs :guard t))
       x)

     (defthm unhide-hide
       (equal (unhide (hide x))
              x)
       :hints (("Goal" :expand ((hide x)))))

     (in-theory (disable unhide))

     (defun my-plus (x y)
       (+ x y))

     (in-theory (disable my-plus))

     (defevaluator evl evl-list
       ((my-plus x y)
        (binary-+ x y)
        (unhide x)
        (hide x)))

     (defun meta-fn (term)
       (declare (xargs :guard (pseudo-termp term)))
       (if (and (consp term)
                (equal (length term) 3)
                (equal (car term) 'my-plus))
           `(UNHIDE (HIDE (BINARY-+ ,(cadr term) ,(caddr term))))
         term))

     (defthm my-meta-lemma
       (equal (evl term a)
              (evl (meta-fn term) a))
       :hints (("Goal" :in-theory (enable my-plus)))
       :rule-classes ((:meta :trigger-fns (my-plus))))

Notice that in the following (silly) conjecture, ACL2 initially does
only does the simplification directed by the metafunction; a second
goal is generated before the commuativity of addition can be applied.
If the above calls of UNHIDE and HIDE had been stripped off, then Goal'
would have been the term printed in Goal" below.

     ACL2 !>(thm
             (equal (my-plus b a)
                    ccc))

     This simplifies, using the :meta rule MY-META-LEMMA and the :rewrite
     rule UNHIDE-HIDE, to

     Goal'
     (EQUAL (+ B A) CCC).

     This simplifies, using the :rewrite rule COMMUTATIVITY-OF-+, to

     Goal''
     (EQUAL (+ A B) CCC).

The discussion above probably suffices to make good use of this (UNHIDE
(HIDE ...)) trick.  However, we invite the reader who wishes to
understand the trick in depth to evaluate the following form before
submitting the thm form above.

     (trace$ (rewrite :entry (list (take 2 arglist))
                      :exit (list (car values)))
             (rewrite-with-lemma :entry (list (take 2 arglist))
                                 :exit (take 2 values)))

The following annotated subset of the trace output (which may appear a
bit different depending on the underlying Common Lisp implementation)
explains how the trick works.

         2> (REWRITE ((MY-PLUS B A) NIL))>
           3> (REWRITE-WITH-LEMMA
                   ((MY-PLUS B A)
                    (REWRITE-RULE (:META MY-META-LEMMA)
                                  1822
                                  NIL EQUAL META-FN NIL META NIL NIL)))>

     We apply the meta rule, then recursively rewrite the result, which is the
     (UNHIDE (HIDE ...)) term shown just below.

             4> (REWRITE ((UNHIDE (HIDE (BINARY-+ B A)))
                          ((A . A) (B . B))))>
               5> (REWRITE ((HIDE (BINARY-+ B A))
                            ((A . A) (B . B))))>

     The HIDE protects its argument from being touched by the rewriter.

               <5 (REWRITE (HIDE (BINARY-+ B A)))>
               5> (REWRITE-WITH-LEMMA
                       ((UNHIDE (HIDE (BINARY-+ B A)))
                        (REWRITE-RULE (:REWRITE UNHIDE-HIDE)
                                      1806 NIL EQUAL (UNHIDE (HIDE X))
                                      X ABBREVIATION NIL NIL)))>

     Now we apply UNHIDE-HIDE, then recursively rewrite its right-hand
     side in an environment where X is bound to (BINARY-+ B A).

                 6> (REWRITE (X ((X BINARY-+ B A))))>

     Notice that at this point X is cached, so REWRITE just returns
     (BINARY-+ B A).

                 <6 (REWRITE (BINARY-+ B A))>
               <5 (REWRITE-WITH-LEMMA T (BINARY-+ B A))>
             <4 (REWRITE (BINARY-+ B A))>
           <3 (REWRITE-WITH-LEMMA T (BINARY-+ B A))>
         <2 (REWRITE (BINARY-+ B A))>


File: acl2-doc-emacs.info,  Node: EVALUATOR-RESTRICTIONS,  Prev: META,  Up: META

EVALUATOR-RESTRICTIONS    some restrictions on the use of evaluators in meta-level rules

Note: This topic, which explains some subtleties for evaluators, can
probably be skipped by most readers.

Rules of class :meta and of class :clause-processor are stated using
so-called "evaluator" functions.  Here we explain some restrictions
related to evaluators.  Below we refer primarily to :meta rules, but
the discussion applies equally to :clause-processor rules.

In a nutshell, we require that a rule's evaluator does not support other
functions in the rule, and we require that the evaluator not be
introduced under a non-trivial encapsulate.  We also require that no
function has an attachment (see *note DEFATTACH::) that is both
ancestral in the evaluator and also ancestral in the meta or
clause-processor functions.  We explain these restrictions in detail
below.

An argument given elsewhere (see *note META::, in particular "Aside for
the logic-minded") explains that the correctness argument for applying
metatheoretic simplifiers requires that one be able to "grow" an
evaluator (see *note DEFEVALUATOR::) to handle all functions in the
current ACL2 world.  Then we may, in essence, functionally instantiate
the original evaluator to the new ("grown") evaluator, provided that
the new evaluator satisfies all of the axioms of the original.  We
therefore require that the evaluator function does not support the
formula of any defaxiom event.  This notion of "support" (sometimes
denoted "is an ancestor of") is defined recursively as follows: a
function symbol supports a formula if either it occurs in that formula,
or else it supports the definition or constraint for some function
symbol that occurs in that formula.  Moreover, we require that neither
the evaluator function nor its list version support the definition or
constraint for any other function symbol occurring in the proposed :meta
theorem.

We also require that the evaluator does not support the formula of a
:meta rule's metafunction (nor, if there is one, hypothesis
metafunction) or of a :clause-processor rule's clause-processor
function.  This requirement, along with with the analogous requirement
for defaxiom events stated above, are necessary in order to carry out
the functional instantiation argument alluded to above, as follows
(where the reader may find it useful to have some familiarity with the
paper "Structured Theory Development for a Mechanized Logic" (Journal
of Automated Reasoning 26, no. 2 (2001), pages 161-203).  By the usual
conservativity argument, we know that the rule follows logically from
the axiomatic events for its supporters.  This remains true if we
functionally instantiate the evaluator with one corresponding to all
the functions symbols of the current session, since none of the
definitions of supporters of defaxioms or metafunctions are hit by that
functional substitution.

Notice though that the argument above depends on knowing that the rule
is not itself an axiom about the evaluator!  Therefore, we also
restrict evaluators so that they are not defined in the scope of a
superior encapsulate event with non-empty signature, in order to avoid
an even more subtle problem.  The aforementioned correctness argument
depends on knowing that the rule is provable from the axioms on the
evaluator and metafunction (and hypothesis metafunction, if any).  The
additional restriction avoids unsoundness!  The following events, if
allowed, produce a proof that (f x) equals t even though, as shown
below, that does not follow logically from the axioms introduced.

     ; Introduce our metafunction.
     (defun my-cancel (term)
       (case-match term
         (('f ('g))
          *t*)
         (& term)))

     ; Introduce our evaluator and prove our meta rule, but in the same
     ; encapsulate!
     (encapsulate
      ((f (x) t))

      (local (defun f (x) (declare (ignore x)) t))

      (defevaluator evl evl-list
        ((f x)))

      (defthm correctness-of-my-cancel
        (equal (evl x a)
               (evl (my-cancel x) a))
        :rule-classes ((:meta :trigger-fns (f)))))

     ; Prove that (f x) = t.
     (encapsulate
      ()

      (local (defstub c () t))

      (local (encapsulate
              ()
              (local (defun g () (c)))
              (local (in-theory (disable g (g))))
              (local (defthm f-g
                       (equal (f (g)) t)
                       :rule-classes nil))
              (defthm f-c
                (equal (f (c)) t)
                :hints (("Goal" :use f-g
                         :in-theory (e/d (g) (correctness-of-my-cancel))))
                :rule-classes nil)))

      (defthm f-t
        (equal (f x) t)
        :hints (("Goal" :by (:functional-instance
                             f-c
                             (c (lambda () x)))))
        :rule-classes nil))

To see that the term (equal (f x) t) does not follow logically from the
axiomatic events above, consider following the above definition of
my-cancel with the following events instead.

     ; (defun my-cancel (term) ...) as before, then:

     (defun f (x)
       (not x))

     (defun g ()
       nil)

     (defevaluator evl evl-list
        ((f x) (g)))

These events imply the axiomatic events above, because we still have the
definition of my-cancel, we have a stronger defevaluator event, and we
can now prove correctness-of-my-cancel exactly as it is stated above.
So, the rule f-t is a logical consequence of the chronology of the
current session.  However, in the current session we can also prove the
following rule, which contradicts f-t.

     (defthm f-not-t
       (equal (f t) nil)
       :rule-classes nil)

It follows that the current session logically yields a contradiction!

Erik Reeber has taken the above example and modified it to prove nil in
ACL2 Version_3.1, as follows.


     (in-package "ACL2")

     (defun my-cancel (term)
        (case-match term
          (('f ('g))
           *t*)
          (('f2 ('g2))
           *t*)
          (& term)))

     (defun f2 (x)
        (not x))

     (defun g2 ()
        nil)

     (encapsulate
       ((f (x) t))

       (local (defun f (x) (declare (ignore x)) t))

       (defevaluator evl evl-list
         ((f x)
          (f2 x)
          (g2)))

       (defthm correctness-of-my-cancel
         (equal (evl x a)
                (evl (my-cancel x) a))
         :rule-classes ((:meta :trigger-fns (f)))))

     (encapsulate
       ()

       (local (defstub c () t))

       (local (encapsulate
               ()
               (local (defun g () (c)))
               (local (in-theory (disable g (g))))
               (local (defthm f-g
                        (equal (f (g)) t)
                        :rule-classes nil))
               (defthm f-c
                 (equal (f (c)) t)
                 :hints (("Goal" :use f-g
                          :in-theory (e/d (g) (correctness-of-my-cancel))))
                 :rule-classes nil)))

       (defthm f-t
         (equal (f x) t)
         :hints (("Goal" :by (:functional-instance
                              f-c
                              (c (lambda () x)))))
         :rule-classes nil))

     (defun g ()
        nil)

     ; Below is the expansion of the following defevaluator, changed slightly as
     ; indicated by comments.
     ; (defevaluator evl2 evl2-list ((f x) (f2 x) (g) (g2)))

     (ENCAPSULATE
       (((EVL2 * *) => *)
        ((EVL2-LIST * *) => *))
       (SET-INHIBIT-WARNINGS "theory")
       (LOCAL (IN-THEORY *DEFEVALUATOR-FORM-BASE-THEORY*))
       (LOCAL
        (MUTUAL-RECURSION (DEFUN EVL2 (X A)
                            (DECLARE (XARGS :VERIFY-GUARDS NIL
                                            :MEASURE (ACL2-COUNT X)
                                            :WELL-FOUNDED-RELATION O<
                                            :MODE :LOGIC))
                            (COND ((SYMBOLP X) (CDR (ASSOC-EQ X A)))
                                  ((ATOM X) NIL)
                                  ((EQ (CAR X) 'QUOTE) (CAR (CDR X)))
                                  ((CONSP (CAR X))
                                   (EVL2 (CAR (CDR (CDR (CAR X))))
                                         (PAIRLIS$ (CAR (CDR (CAR X)))
                                                   (EVL2-LIST (CDR X) A))))
                                  ((EQUAL (CAR X) 'F) ; changed f to f2 just below
                                   (F2 (EVL2 (CAR (CDR X)) A)))
                                  ((EQUAL (CAR X) 'F2)
                                   (F2 (EVL2 (CAR (CDR X)) A)))
                                  ((EQUAL (CAR X) 'G) (G))
                                  ((EQUAL (CAR X) 'G2) (G2))
                                  (T NIL)))
                          (DEFUN EVL2-LIST (X-LST A)
                            (DECLARE (XARGS :MEASURE (ACL2-COUNT X-LST)
                                            :WELL-FOUNDED-RELATION O<))
                            (COND ((ENDP X-LST) NIL)
                                  (T (CONS (EVL2 (CAR X-LST) A)
                                           (EVL2-LIST (CDR X-LST) A)))))))

       (DEFTHM EVL2-CONSTRAINT-1
         (IMPLIES (SYMBOLP X)
                  (EQUAL (EVL2 X A)
                         (CDR (ASSOC-EQ X A)))))
       (DEFTHM EVL2-CONSTRAINT-2
         (IMPLIES (AND (CONSP X) (EQUAL (CAR X) 'QUOTE))
                  (EQUAL (EVL2 X A) (CADR X))))
       (DEFTHM EVL2-CONSTRAINT-3
         (IMPLIES (AND (CONSP X) (CONSP (CAR X)))
                  (EQUAL (EVL2 X A)
                         (EVL2 (CADDAR X)
                               (PAIRLIS$ (CADAR X)
                                         (EVL2-LIST (CDR X) A))))))
       (DEFTHM EVL2-CONSTRAINT-4
         (IMPLIES (NOT (CONSP X-LST))
                  (EQUAL (EVL2-LIST X-LST A) NIL)))
       (DEFTHM EVL2-CONSTRAINT-5
         (IMPLIES (CONSP X-LST)
                  (EQUAL (EVL2-LIST X-LST A)
                         (CONS (EVL2 (CAR X-LST) A)
                               (EVL2-LIST (CDR X-LST) A)))))
       (DEFTHM EVL2-CONSTRAINT-6
         (IMPLIES (AND (CONSP X) (EQUAL (CAR X) 'F))
                  (EQUAL (EVL2 X A) ; changed f to f2 just below
                         (F2 (EVL2 (CADR X) A)))))
       (DEFTHM EVL2-CONSTRAINT-7
         (IMPLIES (AND (CONSP X) (EQUAL (CAR X) 'F2))
                  (EQUAL (EVL2 X A)
                         (F2 (EVL2 (CADR X) A)))))
       (DEFTHM EVL2-CONSTRAINT-8
         (IMPLIES (AND (CONSP X) (EQUAL (CAR X) 'G))
                  (EQUAL (EVL2 X A) (G))))
       (DEFTHM EVL2-CONSTRAINT-9
         (IMPLIES (AND (CONSP X) (EQUAL (CAR X) 'G2))
                  (EQUAL (EVL2 X A) (G2)))))

     (defthm f2-t
        (equal (f2 x) t)
        :hints (("Goal" :by (:functional-instance
                             f-t
                             (f f2)
                             (evl evl2)
                             (evl-list evl2-list)))))

     (defthm bug-implies-nil
        nil
        :hints (("Goal" :use ((:instance f2-t (x t)))))
        :rule-classes nil)

Finally, we also require that no function has an attachment (see *note
DEFATTACH::) that is both ancestral in the evaluator and also ancestral
in the meta or clause-processor functions.  (If you don't use defattach
then you can ignore this condition.)  Without this restriction, the
following events prove nil.

     (in-package "ACL2")
     (defstub f () t)
     (defevaluator evl evl-list
       ((f)))
     (defun my-meta-fn (x)
       (if (equal x '(f))
           (list 'quote (f))
         x))
     (defthm my-meta-fn-correct
       (equal (evl x a)
              (evl (my-meta-fn x) a))
       :rule-classes ((:meta :trigger-fns (f))))
     (defun constant-nil ()
       (declare (xargs :guard t))
       nil)
     (defattach f constant-nil)
     (defthm f-is-nil
     ; proved using my-meta-fn-correct
       (equal (f) nil)
       :rule-classes nil)
     (defthm contradiction
       nil
       :hints (("Goal" :use ((:functional-instance
                              f-is-nil
                              (f (lambda () t))))))
       :rule-classes nil)

To see why this restriction is sufficient, see a comment in the ACL2
source code entitled "; Essay on Correctness of Meta Reasoning."


File: acl2-doc-emacs.info,  Node: REFINEMENT,  Next: REWRITE,  Prev: META,  Up: RULE-CLASSES

REFINEMENT    record that one equivalence relation refines another

See *note 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.

     Example:
     (defthm bag-equal-refines-set-equal
       (implies (bag-equal x y)
                (set-equal y x))
       :rule-classes :refinement)

Also see *note DEFREFINEMENT::.

     General Form:
     (implies (equiv1 x y) (equiv2 x y))

Equiv1 and equiv2 must be known equivalence relations.  The effect of
such a rule is to record that equiv1 is a refinement of equiv2.  This
means that equiv1 :rewrite rules may be used while trying to maintain
equiv2.  See *note EQUIVALENCE:: for a general discussion of the issues.

The macro form (defrefinement equiv1 equiv2) is an abbreviation for a
defthm of rule-class :refinement that establishes that equiv1 is a
refinement of equiv2.  See *note DEFREFINEMENT::.

Suppose we have the :rewrite rule

     (bag-equal (append a b) (append b a))

which states that append is commutative modulo bag-equality.  Suppose
further we have established that bag-equality refines set-equality.
Then when we are simplifying append expressions while maintaining
set-equality we use append's commutativity property, even though it was
proved for bag-equality.

Equality is known to be a refinement of all equivalence relations.  The
transitive closure of the refinement relation is maintained, so if
set-equality, say, is shown to be a refinement of some third sense of
equivalence, then bag-equality will automatially be known as a
refinement of that third equivalence.

:refinement lemmas cannot be disabled.  That is, once one equivalence
relation has been shown to be a refinement of another, there is no way
to prevent the system from using that information.  Of course,
individual :rewrite rules can be disabled.

More will be written about this as we develop the techniques.


File: acl2-doc-emacs.info,  Node: REWRITE,  Next: TAU-SYSTEM,  Prev: REFINEMENT,  Up: RULE-CLASSES

REWRITE    make some :rewrite rules (possibly conditional ones)

See *note 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 *note
INTRODUCTION-TO-REWRITE-RULES-PART-1:: and then see *note
INTRODUCTION-TO-REWRITE-RULES-PART-2::.

     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)))))

     * Menu:


     Related topics other than immediate subtopics:
     * BIND-FREE:: to bind free variables of a rewrite, definition, or linear rule

     * CASE-SPLIT:: like force but immediately splits the top-level goal on the hypothesis

     * DOUBLE-REWRITE:: cause a term to be rewritten twice

     * FORCE:: identity function used to force a hypothesis

     * FREE-VARIABLES:: free variables in rules

     * SYNTAXP:: attach a heuristic filter on a rule

     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 *note TRANS::) and also
expanding away calls of all so-called "guard holders," mv-list and
return-last (the latter resulting for example from calls of prog2$,
mbe, or ec-call), as well as expansions of the macro `the'.  Next, we
eliminate all lambdas; one may think of this step as simply substituting
away every let, let*, and mv-let in the formula.  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)).)  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 equiv is a known equivalence relation, by replacing any
concl not of that form by (iff concl t).  A concl of the form (not
term) is considered to be of the form (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.  See *note 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 *note LOOP-STOPPER::.)

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, a lambda application, or an if-expression.

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 *note LOOP-STOPPER::), the
target is replaced by the instantiated rhs, which is then recursively
rewritten.

ACL2's rewriting process has undergone some optimization.  In
particular, 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 *note META::, near the end of that
documentation.

In another optimization, when the hypotheses and right-hand side are
rewritten, ACL2 does not really first apply the substitution and then
rewrite; instead, it 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 *note INTRODUCTION-TO-REWRITE-RULES-PART-1:: and see *note
INTRODUCTION-TO-REWRITE-RULES-PART-2:: for an extended discussion of how
to create effective rewrite rules.


File: acl2-doc-emacs.info,  Node: TAU-SYSTEM,  Next: TYPE-PRESCRIPTION,  Prev: REWRITE,  Up: RULE-CLASSES

TAU-SYSTEM    make a rule for the ACL2 "type checker"

This documentation topic describes the syntactic form of "tau-system"
rules; these rules extend ACL2's "type checker."  For an introduction to
the tau system, see *note INTRODUCTION-TO-THE-TAU-SYSTEM::.

There happens to be a function named tau-system, defined as the
identity function.  Its only role is to provide the rune
(:EXECUTABLE-COUNTERPART TAU-SYSTEM), which is used to enable and
disable the tau system.  Otherwise the function tau-system has no
purpose and we recommend that you avoid using it so you are free to
enable and disable the tau system.

When in the default ("greedy") mode (see set-tau-auto-mode), every
defun and every :corollary (see :rule-classes) of every defthm stored
as a rule of any :rule-class is inspected to determine if it is of one
of the forms below.  Rules of these forms are added to the tau
database, even if they are not labeled as :tau-system rules, e.g., a
:rewrite rule might contribute to the tau database!  To add a rule to
the tau database without adding any other kind of rule, tag it with
:rule-classes :tau-system.  If a theorem has :rule-classes nil, it is
not considered for the tau database.

     General Forms:
     Boolean:
     (booleanp (p v))

     Eval:
     (p 'const) or
     (p *const*)

     Simple:
     (implies (p v) (q v))

     Conjunctive:
     (implies (and (p1 v) ... (pk v)) (q v)), ; Here k must exceed 1.

     Signature Form 1:
     (implies (and (p1 x1) (p2 x2) ...)
              (q (fn x1 x2 ...)))

     Signature Form 2:
     (implies (and (p1 x1) (p2 x2) ...)
              (q (mv-nth 'n (fn x1 x2 ...))))

     Bounder Form 1 (or Form 2):
     (implies (and (tau-intervalp i1)
                   ...
                   (or (equal (tau-interval-dom i1) 'dom1-1)
                       ...)
                   ...
                   (in-tau-intervalp x1 i1)
                   ...)
              (and (tau-intervalp (bounder-fn i1 ...))
                   (in-tau-intervalp target
                                     (bounder-fn i1 ...))))

     where target is
     (fn x1 ... y1 ...)             in Form 1, and
     (mv-nth 'n (fn x1 ... y1 ...)) in Form 2

     Big Switch:
     (equal (fn . formals) body)

     MV-NTH Synonym:
     (equal (nth-alt x y) (mv-nth x y)) or
     (equal (mv-nth x y) (nth-alt x y))

The symbols p, q, p1, etc., denote monadic (one-argument)
Boolean-valued function symbols, or equalities in which one argument is
constant, arithmetic comparisons in which one argument is a rational or
integer constant, or the logical negations of such terms.  By
"equalities" we allow EQUAL, EQ, EQL, and =.  By "arithmetic
comparison" we mean <, <=, >=, or >.  Any of these tau predicates may
appear negated.

The notation (p v) above might stand for any one of:

     (INTEGERP X)
     (EQUAL V 'MONDAY)
     (<= I 16)
     (NOT (EQUAL X 'SUNDAY))

The different rule forms above affect different aspects of the tau
system.  We discuss each form in more detail below.

* Menu:

* BOUNDERS:: intervals, bounder functions, and bounder correctness

* IN-TAU-INTERVALP:: Boolean membership in a tau interval

* MAKE-TAU-INTERVAL:: make a tau interval

* TAU-INTERVAL-DOM:: access the domain of a tau interval

* TAU-INTERVAL-HI:: access the upper bound of a tau interval

* TAU-INTERVAL-HI-REL:: access the upper bound relation of a tau interval

* TAU-INTERVAL-LO:: access the lower bound of a tau interval

* TAU-INTERVAL-LO-REL:: access the lower bound relation of a tau interval

* TAU-INTERVALP:: Boolean recognizer for tau intervals

The documentation below is written as though the tau system is in auto
mode!  To insure that the only rules added to the tau system are those
explicitly assigned to :rule-class :tau-system, you should use
set-tau-auto-mode to select manual mode.

     General Form: Boolean:
     (booleanp (p v))

Here p must be a function symbol and v must be a variable.  Such a
:tau-system rule adds p to the list of tau predicates.  If p was
recognized as Boolean when it was defined, there is no need to state
this rule.  This form is needed if you define a monadic Boolean
function in such a way that the system does not recognize that it is
Boolean.

     General Form: Eval:
     (p 'const) or
     (p *const*)

Here p must be a function symbol.  In addition, recall that these
general tau predicate forms may appear negated.  So the form above
includes such theorems as (NOT (GOOD-STATEP *INITIAL-STATE*)).  A
theorem of this form thus records whether a named predicate is true or
false on the given constant.

Generally, when the tau system must determine whether an enabled tau
predicate is true or false on a constant, it simply evaluates the
predicate on the constant.  This can be impossible or very inefficient
if p is not defined but constrained, or if p is defined in a
hard-to-compute way (e.g., (defun p (x) (evenp (ack x x))) where ack is
the Ackermann function), or perhaps if the constant is very large.  By
proving a :tau-system rule of Eval form, you cause the tau system to
note the value of the predicate on the constant and henceforth to look
it up instead of evaluating the definition.

A difficulty, however, is determining that a slow down is due to the
evaluation of tau predicates and not some other reason.  The first step
is determining that tau is slowing the proof down.  See time-tracker-tau
for an explanation of TIME-TRACKER-NOTEs output during some proofs
involving tau reasoning.  These notes can alert you to the fact that
significant amounts of time are being spent in the tau system.
Time-tracker-tau gives some ways of determining whether tau predicate
evaluation is involved.  (If worse comes to worst, consider the
following hack: In the ACL2 source file tau.lisp, immediately after the
definition of the system function ev-fncall-w-tau-recog, there is a
comment which contains some raw Lisp code that can be used to
investigate whether tau's use of evaluation on constants is causing a
problem.)  However, once a recognizer and the constants on which it is
being evaluated are identified, the tau system can be sped up by
proving Eval rules to pre-compute and store the values of the
recognizer on those constants.  Alternatively, at the possible loss of
some completeness in the tau system, the executable counterpart of the
recognizer can be disabled.

     General Form: Simple:
     (implies (p v) (q v))

Here v must be a variable symbol.  This rule builds-in the information
that anything satisfying p must also satisfy q, i.e., the "type" q
includes the "type" p.  Recall that the forms may be negated.  Most of
the time, p and q will be predicate symbols but it is possible they
will be equalities- or inequalities-with-constants.  Examples of Simple
rules include the following, which are in fact built-in:

     (implies (natp x) (integerp x))
     (implies (integerp x) (rationalp x))
     (implies (integerp x) (not (true-listp x)))
     (implies (natp x) (not (< x 0)))
     (implies (symbol-alistp x) (alistp x))

Because the tau system records the transitive closure of the Simple
rules, any time a term is known to satisfy natp it is also known to
satisfy integerp and rationalp, and known not to satisfy true-listp,
and known to be non-negative.

     General Form: Conjunctive:
     (implies (and (p1 v) ... (pk v)) (q v)), ; Here k must exceed 1.

The pi and q may be any tau predicates or their negations, v must be a
variable symbol, and i must exceed 1 or else this is a Simple rule.  An
obvious operational interpretation of this rule is that if an object is
known to satisfy all of the pi, then it is known to satisfy q.
However, the actual interpretation is more general.  For example, if an
object is known to satisfy all but one of the pi and is known not to
satisfy q, then the object is known not to satisfy the "missing" pi.

For example, the following Conjunctive rule allows tau to conclude that
if weekday D is not MON, TUE, THU or FRI, then it is WED:

     (implies (and (weekdayp d)
                   (not (eq d 'MON))
                   (not (eq d 'TUE))
                   (not (eq d 'WED))
                   (not (eq d 'THU)))
              (eq d 'FRI))

The tau database is not closed under conjunctive rules; they are
applied dynamically.

     General Form: Signature Form 1:
     (implies (and (p1 x1) (p2 x2) ... (pn xn) dep-hyp)
              (q (fn x1 x2 ... xn)))

The pi and q may be any tau predicates or their negations, fn must be a
function symbol of arity n, the xi must be distinct variable symbols
and dep-hyp may be any term, provided it is not of the (pi xi) shape
and the only the variables in it are the xi.

The Signature form actually allows multiple tau predicates to be
applied to each variable, e.g., x1 might be required to be both an
INTEGERP and EVENP.  The Signature form allows there to be multiple
hypotheses classified as dep-hyps, i.e., not fitting any of the
previous shapes, and they are implicitly just conjoined.  The name
"dep-hyp" is an abbreviation of "dependent hypothesis" and stems from
the fact they often express relations between several of the function's
inputs rather than type-like constraints on individual inputs.

A Signature rule informs tau that the function fn returns an object
satisfying q provided that the arguments satisfy the respective pi and
provided that dep-hyp occurs in the current context.  Note: to be
precise, dependent hypotheses are relieved only by applying ACL2's most
primitive form of reasoning, type-set.  In particular, tau reasoning is
not used to establish dependent hypotheses.  The presence of a dep-hyp
in a signature rule may severely restrict its applicability.  We
discuss this after showing a few mundane examples.

An example Signature rule is

     (implies (and (integer-listp x)
                   (integer-listp y))
              (integer-listp (append x y)))

Of course, a function may have multiple signatures:

     (implies (and (symbol-listp x)
                   (symbol-listp y))
              (symbol-listp (append x y)))

Here is a Signature rule for the function pairlis$:

     (implies (and (symbol-listp x)
                   (integer-listp y))
              (symbol-alistp (pairlis$ x y)))

The tau system can consequently check this theorem by composing the
last two rules shown and exploiting Simple rule stating that
symbol-alists are also alists:

     (thm (implies (and (symbol-listp a)
                        (symbol-listp b)
                        (integer-listp y))
                   (alistp (pairlis$ (append a b) y))))

Since a and b are known to be lists of symbols and a signature for
append is that it preserves that predicate, the first argument to the
pairlis$ expression is known to be a list of symbols.  This means the
Signature rule for pairlis$ tells us the result is a symbol-alistp, but
the previously mentioned Simple rule, (implies (symbol-alistp x)
(alistp x)), tells us the result is also an alistp.

When a Signature rule has an dep-hyp, that hypothesis is not an
expression in the tau system.  Tau is not used to check that
hypothesis.  Instead, tau uses the more primitive type-set mechanism of
ACL2.  Here is an example of a Signature rule with a dep-hyp:

     (implies (and (natp n)
                   (integer-listp a)
                   (< n (len a)))
              (integerp (nth n a)))

Note that the last hypothesis is a dependent hypothesis: it is not a tau
predicate but a relationship between n and a.  It is relieved by
type-set.  If one is trying to compute the signature of an (nth n a)
expression in a context in which (< n (len a)) is explicitly assumed,
then this mechanism would establish the dependent hypothesis.  But one
can easily imagine an almost identical context where, say (< n (len
(rev a))) is explicitly assumed.  In that context, the Signature rule
would not be fired because type-set cannot establish (< n (len a)) from
(< n (len (rev a))), even though it would be easily proved by rewriting
using the theorem (equal (len (rev a)) (len a)).

Note also that if this signature could be phrased in a way that
eliminates the dependency between n and a it would be more effective.
For example, here is a related Signature rule without a dependent
hypothesis:

     (implies (and (natp n)
                   (register-filep a)
                   (< n 16))
              (integerp (nth n a)))

In this theorem we require only that n be less than 16, which is a tau
predicate and hence just an additional tau constraint on n.

     General Form: Signature Form 2:
     (implies (and (p1 x1) (p2 x2) ... (pn xn) dep-hyp)

              (q (mv-nth 'n (fn x1 x2 ... xn))))

This form of signature rule is just like form 1 except that it is
useful for functions that return multiple-values and allows us to
"type-check" their individual outputs.

     General Form: Bounder Forms 1 and 2:
     (implies (and (tau-intervalp i1)
                   ...
                   (or (equal (tau-interval-dom i1) 'dom1-1)
                       ...)
                   ...
                   (in-tau-intervalp x1 i1)
                   ...)
              (and (tau-intervalp (bounder-fn i1 ...))
                   (in-tau-intervalp target
                                     (bounder-fn i1 ...))))

where target is either (fn x1 ... y1 ...) in Form 1 or (mv-nth 'n (fn
x1 ... y1 ...)) in Form 2.

This form is for advanced users only and the schema given above is just
a reminder of the general shape.  A "bounder" for a given function
symbol, fn, is a function symbol bounder-fn that computes an interval
containing (fn x1 ... y1 ...) (or its nth component in the case of Form
2 rules) from the intervals containing certain of the arguments of fn.
The correctness theorem for a bounder function informs the tau system
that bounds for fn are computed by bounder-fn and sets up the
correspondence between the relevant arguments, xi, of fn and the
intervals containing those arguments, ii to which bounder-fn is
applied.  When the tau system computes the tau for a call of fn, it
computes the tau of the relevant arguments and applies the bounder to
the intervals of those tau.  This provides a domain and upper and/or
lower bounds for the value of the term.  The tau system then further
augments that with signature rules.  See *note BOUNDERS:: for details
on intervals, bounders, and bounder correctness theorems.

     General Form: Big Switch:
     (equal (fn . formals) body)

In the Big Switch form, fn must be a function symbol, formals must be a
list of distinct variable symbols, and body must be a "big switch"
term, i.e., one that case splits on tau predicates about a single
variable and produces a term not involving that variable.  An example
of a Big Switch rule is

     (equal (conditional-type x y)
            (if (consp x)
                (consp y)
                (integerp y)))

The idea is that the tau system can treat calls of conditional-type as
a tau-predicate after determining the tau of an argument.

Since equality-to-constants are tau predicates, a more common example
of a Big Switch rule is

     (equal (dtypep x expr)
            (case x
                  (STMT (stmt-typep expr))
                  (EXPR (expr-typep expr))
                  (MODULE (module-typep expr))
                  (otherwise nil)))

This is because (case x (STMT ...) ...) macroexpands in ACL2 to (if
(eql x 'STMT) ... ...) and (eql x 'STMT) is a tau predicate about x.

Big Switch rules are recognized when a function is defined (if tau is in
automatic mode).  They generally do not have to be proved explicitly,
though they might be when mutual recursion is involved.  Only the first
detected Big Switch rule about a function fn is recognized.

     General Form: MV-NTH Synonym:
     (equal (nth-alt x y) (mv-nth x y)) or
     (equal (mv-nth x y) (nth-alt x y))

Rules of this form just tell the tau system that the user-defined
function nth-alt is synonymous with the ACL2 primitive function mv-nth.
Because ACL2's rewriter gives special handling to mv-nth, users
sometimes define their own versions of that function so they can
disable them and control rewriting better.  By revealing to the tau
system that such a synonym has been introduced you allow Signature
rules of Form 2 to be used.


File: acl2-doc-emacs.info,  Node: BOUNDERS,  Next: IN-TAU-INTERVALP,  Prev: TAU-SYSTEM,  Up: TAU-SYSTEM

BOUNDERS    intervals, bounder functions, and bounder correctness

     Bounder Forms 1 and 2:
     (implies (and (tau-intervalp i1)
                   ...
                   (or (equal (tau-interval-dom i1) 'dom1-1)
                       ...)
                   ...
                   (in-tau-intervalp x1 i1)
                   ...)
              (and (tau-intervalp (bounder-fn i1 ...))
                   (in-tau-intervalp target
                                     (bounder-fn i1 ...))))

where target is either (fn x1 ... y1 ...) or (mv-nth 'n (fn x1 ... y1
...)), depending on whether we are in the Form 1 or Form 2 case,
respectively.  However, the shape above is meant just as a reminder.
Details are given below.

This topic first explains the basic shape of Bounder Form 1.  Then it
illustrates Bounder Form 2.  Finally, it deals briefly with proving
bounder correctness theorems.  The community book
tau-bounders/elementary-bounders contains bounders for various
elementary functions including +, *, /, FLOOR, MOD, LOGAND, LOGNOT,
LOGIOR, LOGORC1, LOGEQV, LOGXOR, and ASH.  You might look at or include
this book to see more example theorems, to see how proofs of such
theorems are managed, and to experiment with their effects on proving
theorems involving arithmetic over finite or half-finite intervals.

A bounder correctness theorem establishes that bounder-fn is a
"bounder" for the function fn.  That means that when trying to compute
a tau for a call of fn (or, in the case of Form 2, for the nth
component of the multiple-value vector returned by a call of fn) the tau
system can call bounder-fn on the intervals containing certain arguments
of fn.

Let us start with an example.  Let fn be the addition function, +
(actually, binary-+).  Consider the target term (+ x y) and contemplate
the question: if you know intervals containing x and y, say intx and
inty respectively, what is an interval containing their sum?  The
answer is pretty easy to state in English: the domain of the answer
interval is the less restrictive of the domains of intx and inty.  The
lower bound of the answer interval is the sum of the lower bounds of
intx and inty, and the lower relation is the stronger of the lower
relations of intx and inty.  Analogous comments define the upper bound
and relation of the answer interval.  So for example, if x is an
INTEGERP such that 0 <= x <= 10 and y is a RATIONALP such that 0 < y <=
20, then (+ x y) is a RATIONALP such that 0 < (+ x y) <= 30.

Defining this precisely is more tedious than describing it in English
because one must make precise the notions of "less restrictive"
domains, "weaker" relations, and the possibility that either or both of
the bounds could be "infinite."  But we can easily imagine defining the
function bounder-for-+ that returns the answer interval described,
given intx and inty.

Then the following Bounder Form 1 formula establishes the correctness of
bounder-for-+ and allows the tau system to use it to produce bounds in
the tau computed for +-expressions:

     (implies (and (tau-intervalp intx)
                   (tau-intervalp inty)
                   (in-tau-intervalp x intx)
                   (in-tau-intervalp y inty))
              (and (tau-intervalp (bounder-for-+ intx inty))
                   (in-tau-intervalp (+ x y)
                                     (bounder-for-+ intx inty))))

For example, suppose we have a formula with the following hypotheses

     (and (integerp a)
          (<= 0 a)
          (<= a 10)
          (rationalp b)
          (< 0 b)
          (<= b 20))

and suppose the tau system encounters the term (+ a b).  When the term
is enountered, the tau for a would include an INTEGERP interval such
that 0 <= a <= 10 and the tau for b would include a RATIONALP interval
such that 0 < b <= 20.  In its most primitive configuration, the tau
system would only know that the tau for (+ a b) includes the recognizer
RATIONALP (and all that it is known to imply).  But after the bounder
theorem above is proved and available as a :tau-system rule the tau
system would infer that (+ a b) was in the RATIONALP interval such that
0 < (+ a b) <= 30.

Thus, by defining bounder functions and proving them correct the user
can give the tau system the ability to compute the bounds on function
calls as a function of the known bounds on their actuals.

It is sometimes useful to restrict the domains of the intervals to be
considered.  For example, in bounding *-expressions it is simplifying
to restrict one's attention to intervals over the integers or rationals
(and thus exclude the complex rationals so one need not think about the
getting negative bounds by multiplying two "positive" complex rationals
or how to "round up" from complex bounds to the rationals required by
our intervals).

If we were to define bounder-for-* so that it works correctly to bound
*-expressions, but only for integer or rational arguments, its
correctness theorem would be:

     (implies (and (tau-intervalp intx)                             ; (a)
                   (tau-intervalp inty)
                   (or (equal (tau-interval-dom intx) 'INTEGERP)    ; (b)
                       (equal (tau-interval-dom intx) 'RATIONALP))
                   (or (equal (tau-interval-dom inty) 'INTEGERP)
                       (equal (tau-interval-dom inty) 'RATIONALP))
                   (in-tau-intervalp x intx)                        ; (c)
                   (in-tau-intervalp y inty))
              (and (tau-intervalp (bounder-for-* intx inty))       ; (d)
                   (in-tau-intervalp (* x y)                        ; (e)
                                     (bounder-for-* intx inty))))

In this case, bounder-for-* would be applied to the intervals for x and
y only if those intervals were over the integers or the rationals.

The above theorem for bounder-for-* begins to suggest the general form
of a bounder theorem and we will use it to explain the general form.

The hypotheses of a bounder theorem must be a conjunction and the
conjuncts must be partitionable into three parts, (a), (b), and (c).
The conclusion, must be a conjunction, must contain at least two
conjuncts, (d) and (e), and is allowed to contain others that are
simply ignored for purposes of bounders.  (See the note below about why
we allow but ignore additional conjuncts in the conclusion.)

Part (a) introduces some distinct "interval variables," here called
"ivars," that are known to denote intervals; for the example above, the
ivars are intx and inty.  Each hypothesis in part (a) is of the form
(TAU-INTERVALP ivar).

Part (b) allows us to restrict the domains of some of the intervals.
Each hypothesis in part (b) must be a disjunction and each of the
disjuncts must be of the form (EQUAL (TAU-INTERVAL-DOM ivar) 'dom),
where ivar is one of the interval variables and dom is one of INTEGERP,
RATIONALP, ACL2-NUMBERP, or NIL.  It is not necessary to restrict every
interval variable.  Indeed, part (b) may be empty, as in the theorem for
bounder-for-+ above.

Part (c) consists of a set of (IN-TAU-INTERVALP avar ivar) hypotheses
where each avar is a variable and no two hypotheses in part (c) use the
same avar or ivar.  We call the set of all such avar the "actual
variables" or "avars."  The avars and ivars must be distinct.  Part (c)
sets up a correspondence between the avars and the ivars, each avar is
in an interval denoted by one ivar.

Part (d) introduces the name of the bounder function, here
bounder-for-*, and the order of its ivar arguments.  We see that
bounder-for-* takes two arguments and they correspond, in order, to the
intervals containing x and y.  Part (d) also establishes that the
bounder function always returns an interval under hypotheses (a), (b),
and (c).  Note that it is sometimes useful to return the "universal
interval" (one that contains everything) if you don't want to compute a
better interval for some case; see tau-intervalp or in-tau-intervalp.

Part (e) introduces the name of the function being bounded, here *, and
the order of its arguments.  It establishes that the function being
bounded really is bounded by the interval computed by the bounder
function.  In general, the function being bounded may take additional
arguments.  It is possible that the function being bounded takes some
arguments that do not affect the bounds of its output.

Thus, parts (c) and (e) together establish a mapping between the
actuals of a call of the function being bounded and the intervals to be
supplied to the bounder.

The parts identified above may be presented in any order and the
literals constituting those parts may be mingled.  Thus, for example,
here is another version of the theorem above that generates the same
bounding information for the tau system.  In this version, the
hypotheses and conclusions are rearranged, bounder-for-* takes its
arguments in the opposite order, and the theorem includes an additional
conclusion.

     (implies (and (tau-intervalp intx)                             ; (a)
                   (or (equal (tau-interval-dom intx) 'INTEGERP)    ; (b)
                       (equal (tau-interval-dom intx) 'RATIONALP))
                   (in-tau-intervalp x intx)                        ; (c)

                   (tau-intervalp inty)                             ; (a)
                   (or (equal (tau-interval-dom inty) 'INTEGERP)    ; (b)
                       (equal (tau-interval-dom inty) 'RATIONALP))
                   (in-tau-intervalp y inty))
              (and (in-tau-intervalp (* x y)                        ; (e)
                                     (bounder-for-* inty intx))
                   (tau-intervalp (bounder-for-* inty intx))        ; (d)))

                   (or (equal (tau-interval-dom (bounder-for-* inty intx))
                              'INTEGERP)
                       (equal (tau-interval-dom (bounder-for-* inty intx))
                              'RATIONALP))

Note on why bounder forms allow additional conjuncts in the conclusion:
It is often the case that one creates bounders by composing other
bounders.  To prove compositional bounds correct one must often prove
more than the mere correctness of the components.  For example, one
might need to prove that the domain of the new bounding interval is
INTEGERP or otherwise restricted.  We allow such "unnecessary"
conclusions simply to save the user the burden of stating multiple
theorems.

An Illustration of Bounder Form 2: Suppose (quad i) is defined so that
truncates the integer i to the largest multiple of 4 weakly below i
and, additionally, returns the remainder.  For example, (quad 26)
returns (mv 24 2).  Then here are bounders for each of its return
values:

     (defun quad-bounds-0 (i)
       (cond ((and (tau-interval-lo i)
                   (<= 0 (tau-interval-lo i)))
              (make-tau-interval 'integerp nil 0 nil (tau-interval-hi i)))
             (t (make-tau-interval nil nil nil nil nil))))

     (defun quad-bounds-1 (i)
       (cond ((and (tau-interval-lo i)
                   (<= 0 (tau-interval-lo i)))
              (make-tau-interval 'integerp nil 0 nil 3))
             (t (make-tau-interval nil nil nil nil nil))))

Note that the bounders assume i is an INTEGERP and return the universal
interval when i is not a natural.

As noted in the discussion below about how to prove bounder correctness
theorems, proving these bounders correct will require an arithmetic
book, e.g.,

     (include-book "arithmetic-5/top" :dir :system)

Here then are two bounder correctness theorems of Form 2:

     (defthm quad-bounds-0-correct
       (implies (and (tau-intervalp i)
                     (equal (tau-interval-dom i) 'INTEGERP)
                     (in-tau-intervalp x i))
                (and (tau-intervalp (quad-bounds-0 i))
                     (in-tau-intervalp (mv-nth 0 (quad x))
                                       (quad-bounds-0 i))))
       :rule-classes :tau-system)

     (defthm quad-bounds-1-correct
       (implies (and (tau-intervalp i)
                     (equal (tau-interval-dom i) 'INTEGERP)
                     (in-tau-intervalp x i))
                (and (tau-intervalp (quad-bounds-1 i))
                     (in-tau-intervalp (mv-nth 1 (quad x)) (quad-bounds-1 i))))
       :rule-classes :tau-system)

As noted above, if these bounders are to be used in constructing other
bounders, we might include (in the first theorem) an additional
concluding conjunct, such as

     (equal (tau-interval-dom (quad-bounds-0 i)) 'INTEGERP)

so that we can keep quad-bounds-0 disabled to allow us to use
quad-bounds-0-correct as a :rewrite or other rule and still relieve
hypotheses about the domain of the interval it produces.  These
hypotheses would arise if some other verified bounder was called on the
produced interval.  In addition, as noted below, we might replace the
:rule-classes above with

     :rule-classes
      ((:rewrite)
       (:forward-chaining :trigger-terms ((quad-bounds-0 i))))

Since the theorem is being stored as some kind of rule and since it
satisfies the Bounder Form 2 shape, it will additionally be stored as a
:tau-system rule.

Note on proving bounder theorems: Proving bounder theorems is just like
proving any other arithmetic theorem and you will need whatever
libraries are appropriate for the problem domain you are working in.
Do not expect the tau system to be of much use in proving bounder
theorems.  A typical bounder theorem might require you to prove a
subgoal like  (< (fn x y) (g (tau-interval-hi int1) int2)).  But tau
deals with inequalities relating terms to constants, e.g., (< ... 16).
A bounder theorem is a sort of "metatheorem" about how to construct
bounded intervals from other bounded intervals.  So when you undertake
to define a bounder and prove it correct, go into the project with your
eyes open!

But bounder functions can be broadly divided into two classes, those
defined in terms of arithmetic on the interval bounds and those defined
in terms of other bounders.  For example, given that

     (LOGXOR x y) = (LOGNOT (LOGEQV x y))

an interval for bounding LOGXOR can be constructed by composing the
constructions of intervals for LOGEQV and LOGNOT.  So some bounder
correctness proofs will involve direct manipulation of arithmetic
inequalities and others might involve appeal to the correctness of other
bounders, depending on how the new bounder is defined.

Regardless of which style of bounder we are dealing with, we have found
it useful to prove the basic theorems relating the tau interval
accessors to MAKE-TAU-INTERVAL, e.g.,

     (equal (tau-interval-dom (make-tau-interval dom lo-rel lo hi-rel hi)) dom)

and then disable those functions to avoid seeing excessive cars and
cdrs.

When dealing with bounders defined in the direct, arithmetic style, we
tend to keep TAU-INTERVALP and IN-TAU-INTERVALP enabled so they unfold
and expose the algebra.

When dealing with bounders defined compositionally in terms of other
verified bounders, we tend to keep TAU-INTERVALP and IN-TAU-INTERVALP
disabled so we can rely on the previously proved bounder theorems as
rewrite and forward chaining rules.

Note that this last remark means that when you prove bounder correctness
theorems you should include corollaries that are useful :rewrite and
possibly :forward-chaining rules if you anticipate using that bounder in
more complex ones.  We tend to trigger the forward chaining with the
bounder expression itself, rather than one of the hypotheses.  For
example in the rule above for bounder-for-* we would include
(:forward-chaining :trigger-terms ((tau-bounder-expt2 int2))) and let
the in-tau-intervalp hypotheses select the free variables x and y.


File: acl2-doc-emacs.info,  Node: IN-TAU-INTERVALP,  Next: MAKE-TAU-INTERVAL,  Prev: BOUNDERS,  Up: TAU-SYSTEM

IN-TAU-INTERVALP    Boolean membership in a tau interval

     General Form:
     (in-tau-intervalp e x)

Here, x should be an interval (see tau-intervalp).  This function
returns t or nil indicating whether e, which is generally but not
necessarily a number, is an element of interval x.  By that is meant
that e satisfies the domain predicate of the interval and lies between
the two bounds.

Suppose x is an interval with the components dom, lo-rel, lo, hi-rel
and hi.  Suppose (<? rel u v) means (< u v) when rel is true and (<= u
v) otherwise, with appropriate treatment of infinities.

Then for e to be in interval x, it must be the case that e satisfies
the domain predicate dom (where where dom=nil means there is no
restriction on the domain) and (<? lo-rel lo e) and (<? hi-rel e hi).
[Note:  "Appropriate treatment of infinities" is slightly awkward if
both infinities are represented by the same object, nil.  However, this
is handled by coercing e to a number after checking that it is in the
domain.  By this trick, "<?"  is presented with at most one "infinity"
and it is always negative when in the first argument and positive when
in the second.]

Note that every element in an INTEGERP interval is contained in the
analogous RATIONALP interval (i.e., the interval obtained by just
replacing the domain INTEGERP by RATIONALP).  That is because every
integer is a rational.  Similarly, every rational is an ACL2 number.

Note that an interval in which the relations are weak and the bounds are
equal rationals is the "unit" or "identity" interval containing exactly
that rational.

Note that an interval in which the relations are strong and the bounds
are equal rationals is empty:  it contains no objects.

Note that the interval (make-tau-interval nil nil nil nil nil) is the
"universal interval:" it contains all ACL2 objects.  It contains all
numbers because they statisfy the non-existent domain restriction and
lie between minus infinity and plus infinity.  It contains all
non-numbers because the interval contains 0 and ACL2's inequalities
coerce non-numbers to 0.  The universal interval is useful if you are
defining a bounder (see *note BOUNDERS::) for a function and do not
wish to address a certain case: return the universal interval.

Recall that make-tau-interval constructs intervals.  Using
make-tau-interval we give several self-explanatory examples of
in-tau-intervalp:

     (in-tau-intervalp 3 (make-tau-interval 'INTEGERP nil 0 nil 10))           = t
     (in-tau-intervalp 3 (make-tau-interval 'RATIONALP nil 0 nil 10))          = t
     (in-tau-intervalp 3 (make-tau-interval NIL nil 0 nil 10))                 = t

     (in-tau-intervalp -3 (make-tau-interval 'INTEGERP nil 0 nil 10))          = nil
     (in-tau-intervalp 30 (make-tau-interval 'INTEGERP nil 0 nil 10))          = nil

     (in-tau-intervalp 3/5 (make-tau-interval 'INTEGERP nil 0 nil 10))         = nil
     (in-tau-intervalp 3/5 (make-tau-interval 'RATIONALP nil 0 nil 10))        = t

     (in-tau-intervalp #c(3 5) (make-tau-interval 'RATIONALP nil 0 nil 10))    = nil
     (in-tau-intervalp #c(3 5) (make-tau-interval 'ACL2-NUMBERP nil 0 nil 10)) = t

     (in-tau-intervalp 'ABC (make-tau-interval NIL nil 0 nil 10))              = t


File: acl2-doc-emacs.info,  Node: MAKE-TAU-INTERVAL,  Next: TAU-INTERVAL-DOM,  Prev: IN-TAU-INTERVALP,  Up: TAU-SYSTEM

MAKE-TAU-INTERVAL    make a tau interval

     General Form:
     (make-tau-interval doc lo-rel lo hi-rel hi)

An interval is a structure of the form: (dom (lo-rel .  lo) .  (hi-rel
. hi)).  Every tau contains an interval used to represent the domain,
the upper, and the lower bounds of the objects recognized by the tau.

make-tau-interval constructs well-formed intervals only if its five
arguments satisfy certain restrictions given below.  When these
restrictions are violated make-tau-interval can construct objects that
are not intervals!  make-tau-interval does not attempt to coerce or
adjust its arguments to make well-formed intervals.

For examples of intervals (and non-intervals!) constructed by
make-tau-interval see tau-intervalp.  For examples of what objects are
contained in certain intervals, see in-tau-intervalp.

The components of an interval are as follows:

dom ("domain") - must be one of four symbols: INTEGERP, RATIONALP,
ACL2-NUMBERP, or NIL denoting no restriction on the domain.

The two "relations," lo-rel and hi-rel are Booleans, where t denotes
less-than inequality (<) and nil represents less-than-or-equal
inequality (<=).  Think of t meaning "strong" and nil meaning "weak"
inequality.

Lo and hi must be either nil or explicit rational numbers.  If lo is
nil it denotes negative infinity; if hi is nil it denotes positive
infinity.  Lo must be no greater than hi.  Note:  Even though
ACL2-NUMBERP intervals may contain complex rationals, the lo and hi
bounds must be rational.  This is an arbitrary decision made by the
implementors to simplify coding.

Finally, if the dom is INTEGERP, then both relations should be weak and
lo and hi must be integers when they are non-nil.

For x to be "in" an interval it must be of the type described by the
domain predicate dom, lo must be smaller than x in the strong or weak
sense denoted by lo-rel, and x must be smaller than hi in the strong or
weak sense denoted by hi-rel.

The components of an interval may be accessed with the functions
tau-interval-dom, tau-interval-lo-rel, tau-interval-lo,
tau-interval-hi-rel, and tau-interval-hi.


File: acl2-doc-emacs.info,  Node: TAU-INTERVAL-DOM,  Next: TAU-INTERVAL-HI,  Prev: MAKE-TAU-INTERVAL,  Up: TAU-SYSTEM

TAU-INTERVAL-DOM    access the domain of a tau interval

It is the case that

     (tau-interval-dom (make-tau-interval dom lo-rel lo hi-rel hi)) = dom

For a well-formed interval, dom is one of the symbols INTEGERP,
RATIONALP, ACL2-NUMBERP, or NIL.  When the domain is NIL there is no
domain restriction.

When the domain is INTEGERP, there are additional constraints on the
other components.  See *note MAKE-TAU-INTERVAL::.


File: acl2-doc-emacs.info,  Node: TAU-INTERVAL-HI,  Next: TAU-INTERVAL-HI-REL,  Prev: TAU-INTERVAL-DOM,  Up: TAU-SYSTEM

TAU-INTERVAL-HI    access the upper bound of a tau interval

It is the case that

     (tau-interval-hi (make-tau-interval dom lo-rel lo hi-rel hi)) = hi

For a well-formed interval, hi is either nil, denoting positive
infinity, or a rational number giving the upper bound of the interval.
It must be the case that the upper bound is weakly above the lower bound
of a well-formed interval.

When the domain of an interval is INTEGERP, there are additional
constraints on the other components.  See *note MAKE-TAU-INTERVAL::.


File: acl2-doc-emacs.info,  Node: TAU-INTERVAL-HI-REL,  Next: TAU-INTERVAL-LO,  Prev: TAU-INTERVAL-HI,  Up: TAU-SYSTEM

TAU-INTERVAL-HI-REL    access the upper bound relation of a tau interval

It is the case that

     (tau-interval-hi-rel (make-tau-interval dom lo-rel lo hi-rel hi)) = hi-rel

For a well-formed interval, hi-rel is a Boolean, where t denotes the <
(strong inequality or "less-than") relation and nil denotes <= (weak
inequality or "less-than-or-equal") relation between the elements of
the interval and the upper bound.

When the domain of an interval is INTEGERP, there are additional
constraints on the other components.  See *note MAKE-TAU-INTERVAL::.


File: acl2-doc-emacs.info,  Node: TAU-INTERVAL-LO,  Next: TAU-INTERVAL-LO-REL,  Prev: TAU-INTERVAL-HI-REL,  Up: TAU-SYSTEM

TAU-INTERVAL-LO    access the lower bound of a tau interval

It is the case that

     (tau-interval-lo (make-tau-interval dom lo-rel lo hi-rel hi)) = lo

For a well-formed interval, lo is either nil, denoting negative
infinity, or a rational number giving the lower bound of the interval.
It must be the case that the lower bound is weakly below the upper bound
of a well-formed interval.

When the domain of an interval is INTEGERP, there are additional
constraints on the other components.  See *note MAKE-TAU-INTERVAL::.


File: acl2-doc-emacs.info,  Node: TAU-INTERVAL-LO-REL,  Next: TAU-INTERVALP,  Prev: TAU-INTERVAL-LO,  Up: TAU-SYSTEM

TAU-INTERVAL-LO-REL    access the lower bound relation of a tau interval

It is the case that

     (tau-interval-lo-rel (make-tau-interval dom lo-rel lo hi-rel hi)) = lo-rel

For a well-formed interval, lo-rel is a Boolean, where t denotes the <
(strong inequality or "less-than") relation and nil denotes <= (weak
inequality or "less-than-or-equal") relation between the lower bound
and the elements of the interval.

When the domain of an interval is INTEGERP, there are additional
constraints on the other components.  See *note MAKE-TAU-INTERVAL::.


File: acl2-doc-emacs.info,  Node: TAU-INTERVALP,  Prev: TAU-INTERVAL-LO-REL,  Up: TAU-SYSTEM

TAU-INTERVALP    Boolean recognizer for tau intervals

     General Form:
     (tau-intervalp x)

An interval is a structure of the form: (dom (lo-rel .  lo) .  (hi-rel
. hi)).  Every tau contains an interval used to represent the domain
and the upper and lower bounds of the objects recognized by the tau.

Restrictions on the components of an interval are as follows.  For an
interpretation of the meaning of the components, see in-tau-intervalp or
make-tau-interval.

dom ("domain") - must be one of four symbols: INTEGERP, RATIONALP,
ACL2-NUMBERP, or NIL.

The two "relations," lo-rel and hi-rel, must be Booleans.

Lo and hi must be either nil or explicit rational numbers.  Lo must be
no greater than hi (where nils represent negative or positive infinity
for lo and hi respectively.

Finally, if the dom is INTEGERP, then both relations must nil and lo
and hi must be integers when they are non-nil.

Recall that make-tau-interval constructs intervals.  The intervals it
constructs are well-formed only if the arguments to make-tau-interval
satisfy the rules above; make-tau-interval does not coerce or adjust its
arguments in any way.  Thus, it can be (mis-)used to create
non-intervals.  Here are examples of tau-intervalp using
make-tau-interval.

     ; integers: 0 <= x <= 10:
     (tau-intervalp (make-tau-interval 'INTEGERP nil 0 nil 10))      = t

     ; integers: 0 <= x (i.e., the natural numbers):
     (tau-intervalp (make-tau-interval 'INTEGERP nil 0 nil nil))     = t

     ; violations of domain rules:
     (tau-intervalp (make-tau-interval 'INTEGERP t 0 t 10))          = nil
     (tau-intervalp (make-tau-interval 'INTEGERP nil 0 nil 10/11))   = nil

     ; violation of rule that bounds must be rational if non-nil:
     (tau-intervalp (make-tau-interval 'ACL2-NUMBERP t 0 t #c(3 5))) = nil

     ; violation of rule that lo <= hi:
     (tau-intervalp (make-tau-interval 'ACL2-NUMBERP t 0 t -10))     = nil

     ; rationals: 0 < x <= 22/7:
     (tau-intervalp (make-tau-interval 'RATIONALP t 0 nil 22/7))     = t

     ; numbers: -10 < x < 10:
     (tau-intervalp (make-tau-interval 'ACL2-NUMBERP t -10 t 10))    = t

     ; any: -10 < x < 10:
     (tau-intervalp (make-tau-interval nil t -10 t 10))              = t

     : any:
     (tau-intervalp (make-tau-interval nil nil nil nil nil))         = t

Note that the second-to-last interval, with domain nil contains all
non-numbers as well as numbers strictly between -10 and 10.  The reason
is that the interval contains 0 and all non-numbers are coerced to 0 by
the inequality functions.

Note that the last interval contains all ACL2 objects.  It is called the
"universal interval."


File: acl2-doc-emacs.info,  Node: TYPE-PRESCRIPTION,  Next: TYPE-SET-INVERTER,  Prev: TAU-SYSTEM,  Up: RULE-CLASSES

TYPE-PRESCRIPTION    make a rule that specifies the type of a term

See *note 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.

     Examples:
     (defthm integerp-foo                       ; Assumes that foo has been
       (integerp (foo x y))                     ; defined; then, states that
       :rule-classes :type-prescription)        ; (foo x y) is of type integer.

     (defthm characterp-nth-type-prescription   ; (Nth n lst) is of type character
       (implies                                 ; provided the hypotheses can be
        (and (character-listp lst)              ; established by type reasoning.
             (<= 0 n)
             (< n (len lst)))
        (characterp (nth n lst)))
       :rule-classes :type-prescription)

     (defthm characterp-nth-type-prescription-alt ; equivalent to the above
       (implies
        (and (character-listp lst)
             (<= 0 n)
             (< n (len lst)))
        (characterp (nth n lst)))
       :rule-classes ((:type-prescription :typed-term (nth n lst))))

     (defthm demodulize-type-for-quote-value  ; (Demodulize a lst 'value ans) is
       (implies                               ; either a nonnegative integer or
        (and (atom a)                         ; of the same type as ans, provided
             (true-listp lst)                 ; the hyps can be established by type
             (member-equal a lst))            ; reasoning
        (or (and (integerp (demodulize a lst 'value ans))
                 (>= (demodulize a lst 'value ans) 0))
          (equal (demodulize a lst 'value ans) ans)))
       :rule-classes :type-prescription)

To specify the term whose type (see *note TYPE-SET::) is described by
the rule, provide that term as the value of the :typed-term field of
the rule class object.

     General Form (after preprocessing; see below):
     (implies hyps
              (or type-restriction1-on-pat
                  ...
                  type-restrictionk-on-pat
                  (equal pat var1)
                  ...
                  (equal pat varj)))

where pat is the application of some function symbol to some arguments,
each type-restrictioni-on-pat is a term involving pat and containing no
variables outside of the occurrences of pat, and each vari is one of
the variables of pat.  Generally speaking, the type-restriction terms
ought to be terms that inform us as to the type of pat.  Ideally, they
should be "primitive recognizing expressions" about pat; see *note
COMPOUND-RECOGNIZER::.  We describe preprocessing at the end of this
topic.

If the :typed-term is not provided in the rule class object, it is
computed heuristically by looking for a term in the conclusion whose
type is being restricted.  An error is caused if no such term is found.

Roughly speaking, the effect of adding such a rule is to inform the ACL2
typing mechanism that pat has the type described by the conclusion, when
the hypotheses are true.  In particular, the type of pat is within the
union of the types described by the several disjuncts.  The "type
described by" (equal pat vari) is the type of vari.

More operationally, when asked to determine the type of a term that is
an instance of pat, ACL2 will first attempt to establish the hypotheses.
*This is done by type reasoning alone, not rewriting!*  However, if some
hypothesis is a call of force, then forcing may occur, which may
ultimately invoke the rewriter; see *note FORCE:: and see *note
CASE-SPLIT::.  So-called free variables in hypotheses are treated
specially; see *note FREE-VARIABLES::.  Provided the hypotheses are
established by type reasoning, ACL2 then unions the types described by
the type-restrictioni-on-pat terms together with the types of those
subexpressions of pat identified by the vari.  The final type computed
for a term is the intersection of the types implied by each applicable
rule.  Type prescription rules may be disabled.

You can limit the recursive establishment of hypotheses of rules; see
*note SET-BACKCHAIN-LIMIT::.

Because only type reasoning is used to establish the hypotheses of
:type-prescription rules, some care must be taken with the hypotheses.
Suppose, for example, that the non-recursive function my-statep is
defined as

       (defun my-statep (x)
         (and (true-listp x)
              (equal (len x) 2)))

and suppose (my-statep s) occurs as a hypothesis of a
:type-prescription rule that is being considered for use in the proof
attempt for a conjecture with the hypothesis (my-statep s).  Since the
hypothesis in the conjecture is rewritten, it will become the
conjunction of (true-listp s) and (equal (len s) 2).  Those two terms
will be assumed to have type t in the context in which the
:type-prescription rule is tried.  But type reasoning will be unable to
deduce that (my-statep s) has type t in this context.  Thus, either
my-statep should be disabled (see *note DISABLE::) during the proof
attempt or else the occurrence of (my-statep s) in the
:type-prescription rule should be replaced by the conjunction into
which it rewrites.

While this example makes it clear how non-recursive predicates can cause
problems, non-recursive functions in general can cause problems.  For
example, if (mitigate x) is defined to be (if (rationalp x) (1- x) x)
then the hypothesis (pred (mitigate s)) in the conjecture will rewrite,
opening mitigate and splitting the conjecture into two subgoals, one in
which (rationalp s) and (pred (1- x)) are assumed and the other in
which (not (rationalp s)) and (pred x) are assumed.  But (pred
(mitigate s)) will not be typed as t in either of these contexts.  The
moral is: beware of non-recursive functions occuring in the hypotheses
of :type-prescription rules.

Because of the freedom one has in forming the conclusion of a
type-prescription, we have to use heuristics to recover the pattern,
pat, whose type is being specified.  In some cases our heuristics may
not identify the intended term and the :type-prescription rule will be
rejected as illegal because the conclusion is not of the correct form.
When this happens you may wish to specify the pat directly.  This may
be done by using a suitable rule class token.  In particular, when the
token :type-prescription is used it means ACL2 is to compute pat with
its heuristics; otherwise the token should be of the form
(:type-prescription :typed-term pat), where pat is the term whose type
is being specified.

The defun event may generate a :type-prescription rule.  Suppose fn is
the name of the function concerned.  Then (:type-prescription fn) is
the rune given to the type-prescription, if any, generated for fn by
defun.  (The trivial rule, saying fn has unknown type, is not stored,
but defun still allocates the rune and the corollary of this rune is
known to be t.)

We close with a discussion of how, before a term is parsed into a
:type-prescription rule, it is preprocessed.  We describe this
preprocessing in some detail below, but first consider the following
(contrived) example.

     (defthm append-tp-example
       (let ((result (append x y)))
         (implies (nat-listp x)
                  (implies (let ((second-hyp (integer-listp y)))
                             second-hyp)
                           (true-listp result))))
       :rule-classes :type-prescription)

This theorem is parsed into a type-prescription rule with the following
hypotheses and conclusion.

     (nat-listp x) ; first hypothesis
     ((lambda (second-hyp) second-hyp) (integer-listp y)) ; second hypothesis
     (true-listp (binary-append x y)) ; conclusion

Notice that the top-level LET was expanded, i.e., (append x y) was
substituted for result -- more accurately, (binary-append x y) was
substituted for result, since append is a macro that abbreviates
binary-append.  Also notice that the two hypotheses were "flattened" in
the sense that they were gathered up into a list.  Finally, notice that
the LET in the second hypothesis was not expanded (it was merely
translated to internal form, using LAMBDA).  If you actually submit the
theorem above, you will get warnings, which you may choose to ignore;
the application of type-prescription rules is somewhat subtle, so if
you use them then you may wish to experiment to see which forms work
best for you.

Here is the detail promised above, for parsing a term into a
:type-prescription rule.  There are two steps.  (1) ACL2 first
translates the term, expanding all macros (see *note TRANS::) and also
expanding away calls of all so-called "guard holders," mv-list and
return-last (the latter resulting for example from calls of prog2$,
mbe, or ec-call), as well as expansions of the macro `the'.  (2) Then
the the translated term is traversed top-down, expanding away lambdas
(let, let*, and mv-let expressions) and flattening the IMPLIES
structure, until the conclusion is exposed; then the conclusion's
lambdas are also expanded away.  The simplest way to understand (2) may
be to look at the definition of ACL2 source function unprettyify-tp,
which implements Step (2), say by evaluating :pe unprettyify-tp.


File: acl2-doc-emacs.info,  Node: TYPE-SET-INVERTER,  Next: WELL-FOUNDED-RELATION,  Prev: TYPE-PRESCRIPTION,  Up: RULE-CLASSES

TYPE-SET-INVERTER    exhibit a new decoding for an ACL2 type-set

See *note 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.

     Example Rule Class:
     (:type-set-inverter
       :corollary (equal (and (counting-number x) (not (equal x 0)))
                         (and (integerp x) (< 0 x)))
       :type-set 2)

     General Forms of Rule Class:
     :type-set-inverter, or
     (:type-set-inverter :type-set n)

     General Form of Theorem or Corollary:
     (EQUAL new-expr old-expr)

where n is a type-set (see *note TYPE-SET::) and old-expr is the term
containing x as a free variable that ACL2 currently uses to recognize
type-set n.  For a given n, the exact form of old-expr is generated by

     (convert-type-set-to-term 'x n (ens state) (w state) nil)].

If the :type-set field of the rule-class is omitted, we attempt to
compute it from the right-hand side, old-expr, of the corollary.  That
computation is done by type-set-implied-by-term (see *note TYPE-SET::).
However, it is possible that the type-set we compute from lhs does not
have the required property that when inverted with
convert-type-set-to-term the result is lhs.  If you omit :type-set and
an error is caused because lhs has the incorrect form, you should
manually specify both :type-set and the lhs generated by
convert-type-set-to-term.

The rule generated will henceforth make new-expr be the term used by
ACL2 to recognize type-set n.  If this rule is created by a defthm
event named name then the rune of the rule is (:type-set-inverter name)
and by disabling that rune you can prevent its being used to decode
type-sets.

Type-sets are inverted when forced assumptions are turned into formulas
to be proved.  In their internal form, assumptions are essentially
pairs consisting of a context and a goal term, which was forced.
Abstractly a context is just a list of hypotheses which may be assumed
while proving the goal term.  But actually contexts are alists which
pair terms with type-sets, encoding the current hypotheses.  For
example, if the original conjecture contained the hypothesis (integerp
x) then the context used while working on that conjecture will include
the assignment to x of the type-set *ts-integer*.


File: acl2-doc-emacs.info,  Node: WELL-FOUNDED-RELATION,  Prev: TYPE-SET-INVERTER,  Up: RULE-CLASSES

WELL-FOUNDED-RELATION    show that a relation is well-founded on a set

See *note 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.

     Example:
     (defthm lex2p-is-well-founded-relation
       (and (implies (pairp x) (o-p (ordinate x)))
            (implies (and (pairp x)
                          (pairp y)
                          (lex2p x y))
                     (o< (ordinate x) (ordinate y))))
       :rule-classes :well-founded-relation)

The example above creates a :well-founded-relation rule, where of course
the functions pairp, lex2p, and ordinate would have to be defined
first.  It establishes that lex2p is a well-founded relation on pairps.
We explain and give details below.

Exactly two general forms are recognized:

     General Forms
     (AND (IMPLIES (mp x) (O-P (fn x)))              ; Property 1
          (IMPLIES (AND (mp x)                       ; Property 2
                        (mp y)
                        (rel x y))
                   (O< (fn x) (fn y)))),

or

     (AND (O-P (fn x))                               ; Property 1
          (IMPLIES (rel x y)                         ; Property 2
                   (O< (fn x) (fn y))))

where mp, fn, and rel are function symbols, x and y are distinct
variable symbols, and no other :well-founded-relation theorem about fn
has been proved.  When the second general form is used, we act as
though the first form were used with mp being the function that ignores
its argument and returns t.  The discussion below therefore considers
only the first general form.

Note: We are very rigid when checking that the submitted formula is of
one of these forms.  For example, in the first form, we insist that all
the conjuncts appear in the order shown above.  Thus, interchanging the
two properties in the top-level conjunct or rearranging the hyptheses
in the second conjunct both produce unrecognized forms.  The
requirement that each fn be proved well-founded at most once ensures
that for each well-founded relation, fn, there is a unique mp that
recognizes the domain on which rel is well-founded.  We impose this
requirement simply so that rel can be used as a short-hand when
specifying the well-founded relations to be used in definitions;
otherwise the specification would have to indicate which mp was to be
used.

We also insist that the new ordering be embedded into the ordinals as
handled by o-p and o< and not some into previously admitted user-defined
well-founded set and relation.  This restriction should pose no
hardship.  If mp and rel were previously shown to be well-founded via
the embedding fn, and you know how to embed some new set and relation
into mp and rel, then by composing fn with your new embedding and using
the previously proved well-founded relation lemma you can embed the new
set and relation into the ordinals.

Mp is a predicate that recognizes the objects that are supposedly
ordered in a well-founded way by rel.  We call such an object an
"mp-measure" or simply a "measure" when mp is understood.  Property 1
tells us that every measure can be mapped into an ACL2 ordinal.  (See
*note O-P::.)  This mapping is performed by fn.  Property 2 tells us
that if the measure x is smaller than the measure y according to rel
then the image of x under fn is a smaller than that of y, according to
the well-founded relation o<.  (See *note O<::.)  Thus, the general
form of a :well-founded-relation formula establishes that there exists a
rel-order preserving embedding (namely via fn) of the mp-measures into
the ordinals.  We can thus conclude that rel is well-founded on
mp-measures.

Such well-founded relations are used in the admissibility test for
recursive functions, in particular, to show that the recursion
terminates.  To illustrate how such information may be used, consider a
generic function definition

     (defun g (x) (if (test x) (g (step x)) (base x))).

If rel has been shown to be well-founded on mp-measures, then g's
termination can be ensured by finding a measure, (m x), with the
property that m produces a measure:

     (mp (m x)),                                     ; Defun-goal-1

and that the argument to g gets smaller (when measured by m and
compared by rel) in the recursion,

     (implies (test x) (rel (m (step x)) (m x))).    ; Defun-goal-2

If rel is selected as the :well-founded-relation to be used in the
definition of g, the definitional principal will generate and attempt
to prove defun-goal-1 and defun-goal-2 to justify g.  We show later why
these two goals are sufficient to establish the termination of g.
Observe that neither the ordinals nor the embedding, fn, of the
mp-measures into the ordinals is involved in the goals generated by the
definitional principal.

Suppose now that a :well-founded-relation theorem has been proved for
mp and rel.  How can rel be "selected as the :well-founded-relation" by
defun?  There are two ways.  First, an xargs keyword to the defun event
allows the specification of a :well-founded-relation.  Thus, the
definition of g above might be written

     (defun g (x)
      (declare (xargs :well-founded-relation (mp . rel)))
      (if (test x) (g (step x)) (base x)))

Alternatively, rel may be specified as the
:default-well-founded-relation in acl2-defaults-table by executing the
event

     (set-well-founded-relation rel).

When a defun event does not explicitly specify the relation in its
xargs the default relation is used.  When ACL2 is initialized, the
default relation is o<.

Finally, though it is probably obvious, we now show that defun-goal-1
and defun-goal-2 are sufficient to ensure the termination of g provided
property-1 and property-2 of mp and rel have been proved.  To this end,
assume we have proved defun-goal-1 and defun-goal-2 as well as
property-1 and property-2 and we show how to admit g under the
primitive ACL2 definitional principal (i.e., using only the ordinals).
In particular, consider the definition event

     (defun g (x)
      (declare (xargs :well-founded-relation o<
                      :measure (fn (m x))))
      (if (test x) (g (step x)) (base x)))

Proof that g is admissible:  To admit the definition of g above we must
prove

     (o-p (fn (m x)))                        ; *1

and

     (implies (test x)                               ; *2
              (o< (fn (m (step x))) (fn (m x)))).

But *1 can be proved by instantiating property-1 to get

     (implies (mp (m x)) (o-p (fn (m x)))),

and then relieving the hypothesis with defun-goal-1, (mp (m x)).

Similarly, *2 can be proved by instantiating property-2 to get

     (implies (and (mp (m (step x)))
                   (mp (m x))
                   (rel (m (step x)) (m x)))
              (o< (fn (m (step x))) (fn (m x))))

and relieving the first two hypotheses by appealing to two instances of
defun-goal-1, thus obtaining

     (implies (rel (m (step x)) (m x))
              (o< (fn (m (step x))) (fn (m x)))).

By chaining this together with defun-goal-2,

     (implies (test x)
              (rel (m (step x)) (m x)))

we obtain *2.  Q.E.D.


File: acl2-doc-emacs.info,  Node: SERIALIZE,  Next: STOBJ,  Prev: RULE-CLASSES,  Up: Top

SERIALIZE    routines for saving ACL2 objects to files, and later restoring them

This documentation topic relates to an experimental extension of ACL2
that supports hons, memoization, and fast alists.  See *note
HONS-AND-MEMOIZATION::.  Thanks to Jared Davis for contributing the
"serialization" routines for saving ACL2 objects in files for later
loading.

We implement some routines for writing arbitrary ACL2 objects to files,
and for loading those files later.  We usually call these ".sao" files,
which stands for (S)erialized (A)CL2 (O)bject.

Our serialization scheme uses a compact, binary format that preserves
structure sharing in the original object.  We optimize for read
performance.

* Menu:

* SERIALIZE-ALTERNATIVES:: alternatives to the serialize routines

* SERIALIZE-IN-BOOKS:: using serialization efficiently in books

* SERIALIZE-READ:: read a serialized ACL2 object from a file

* SERIALIZE-WRITE:: write an ACL2 object into a file

* SET-SERIALIZE-CHARACTER:: See *note WITH-SERIALIZE-CHARACTER::.

* WITH-SERIALIZE-CHARACTER:: control output mode for print-object$


File: acl2-doc-emacs.info,  Node: SERIALIZE-ALTERNATIVES,  Next: SERIALIZE-IN-BOOKS,  Prev: SERIALIZE,  Up: SERIALIZE

SERIALIZE-ALTERNATIVES    alternatives to the serialize routines

Hons users could previously use the routines compact-print-file and
compact-read-file.  These are deprecated and are no longer built into
ACL2.  However, they are still available by loading the new community
book, serialize/compact-print.  Note that loading this book requires a
ttag, and these routines are still only available in raw lisp.

Another predecessor of the serialization routines were hons archives,
which are still available in the hons-archive library.  The
serialization routines are generally better and we recommend against
using hons archives for new projects.


File: acl2-doc-emacs.info,  Node: SERIALIZE-IN-BOOKS,  Next: SERIALIZE-READ,  Prev: SERIALIZE-ALTERNATIVES,  Up: SERIALIZE

SERIALIZE-IN-BOOKS    using serialization efficiently in books

Our serialize scheme was developed in order to allow very large ACL2
objects to be loaded into books.  Ordinarily this is carried out using
serialize-read within a make-event, e.g.,

       (make-event (mv-let (obj state)
                           (serialize-read "my-file")
                           (value `(defconst *my-file* ',obj))))

But this scheme is not particularly efficient.

During certify-book, the actual call of serialize-read is carried out,
and this is typically pretty fast.  But then a number of possibly
inefficient things occur.

     - The ACL2 function bad-lisp-object is run on the resulting
     object.  This is memoized for efficiency, but may still take
     considerable time when the file is very large.

     - The checksum of the resulting object is computed.  This is also
     memoized, but as before may still take some time.

     - The object that was just read is then written into book.cert,
     essentially with serialize-write.  This can take some time, and
     results in large certifiate files.

Then, during include-book, the make-event expansion of is loaded.  This
is now basically just a serialize-read.

The moral of the story is that using serialize will only help your
certify-book time, and it only impacts a portion of the overall time.

To avoid this overhead, we have developed an UNSOUND alternative to
serialize-read, which is available only by loading an additional book.
So, if the above scheme is not performing well for you, you may wish to
see the community book serialize/unsound-read.


File: acl2-doc-emacs.info,  Node: SERIALIZE-READ,  Next: SERIALIZE-WRITE,  Prev: SERIALIZE-IN-BOOKS,  Up: SERIALIZE

SERIALIZE-READ    read a serialized ACL2 object from a file

General form:

      (serialize-read filename
                      [:hons-mode {:always, :never, :smart}]   ; :smart by default
                      [:verbosep  {t, nil}])                   ; nil by default
       -->
      (mv obj state)

In the logic this is an oracle read.

Under the hood, we try to read and return a serialized object from a
file that was presumably created by serialize-write.  On success we
return the contents of the file.  Any failures (e.g., file not found,
bad file contents, etc.) will result in a hard Lisp error.

The filename should be a string that gives the path to the file.

The hons-mode controls how whether to use hons or cons to restore the
object.  The default mode is :smart, which means that conses that were
normed at the time of the file's creation should be restored with hons.
But you can override this and insist that hons is to :always or :never
be used, instead.

Why would you use :never?  If your object previously had a lot of
honses, but you no longer have any need for them to be normed, then
using :never may sometimes be a lot faster since it can avoid hons
calls.  On the other hand, if you are going to hons-copy some part of
the file's contents, then it is likely faster to use :smart or :always
instead of first creating normal conses and then copying them to build
honses.

The :verbosep flag just controls whether to print some low-level details
related to timing and memory usage as the file is being read.


File: acl2-doc-emacs.info,  Node: SERIALIZE-WRITE,  Next: SET-SERIALIZE-CHARACTER,  Prev: SERIALIZE-READ,  Up: SERIALIZE

SERIALIZE-WRITE    write an ACL2 object into a file

General form:

      (serialize-write filename obj
                       [:verbosep  {t, nil}])    ; nil by default
       -->
      state

In the logic this carries out an oracle read.

Under the hood, we try to save obj into the file indicated by filename,
which must be a string.  The object can later be recovered with
serialize-read.  We just return state, and any failures (e.g., file not
openable) will result in a hard Lisp error.

Writing objects to disk is generally slower than reading them back in
since some analysis is required to convert an object into our
serialized object format.

The verbosep flag just says whether to print some low-level details
related to timing and memory usage as the file is being read.


File: acl2-doc-emacs.info,  Node: SET-SERIALIZE-CHARACTER,  Next: WITH-SERIALIZE-CHARACTER,  Prev: SERIALIZE-WRITE,  Up: SERIALIZE

SET-SERIALIZE-CHARACTER    See *note WITH-SERIALIZE-CHARACTER::.


File: acl2-doc-emacs.info,  Node: WITH-SERIALIZE-CHARACTER,  Prev: SET-SERIALIZE-CHARACTER,  Up: SERIALIZE

WITH-SERIALIZE-CHARACTER    control output mode for print-object$

This documentation topic relates to an experimental extension of ACL2
that supports hons, memoization, and fast alists.  See *note
HONS-AND-MEMOIZATION::.  See *note SERIALIZE:: for a discussion of
"serialization" routines, contributed by Jared Davis for saving ACL2
objects in files for later loading.

The expression (with-serialize-character char form) evaluates to the
value of form, but with the serialize-character of the state assigned to
char, which should be one of nil, #\Y, or #\Z.  We describe the effect
of that assignment below.  But note that if you are doing this because
of one or more specific calls of print-object$, such as (print-object$
x channel state), then you may wish instead to evaluate
(print-object$-ser x serialize-character channel state), in which case
you will not need to use with-serialize-character.  (Note however that
serialize-character is treated as nil for other than a HONS version.)

     General forms:
     (with-serialize-character nil form)
     (with-serialize-character #Y form)
     (with-serialize-character #Z form)

where form should evaluate to an error triple (see *note
ERROR-TRIPLES::).

Note that if you prefer to obtain the same behavior (as described below)
globally, rather than only within the scope of with-serialize-character,
then use set-serialize-character in a corresponding manner:

     (set-serialize-character nil state)
     (set-serialize-character #Y state)
     (set-serialize-character #Z state)

In each case above, calls of print-object$ (see *note IO::) in form will
produce an object that can be read by the HONS version of ACL2.  In the
first case, that object is printed as one might expect at the terminal,
as an ordinary Lisp s-expression.  But in the other cases, the object
is printed by first laying down either #Y or #Z (as indicated) and then
calling serialize-write (or more precisely, the underlying function
called by serialize-write that prints to a stream).

Consider what happens when the ACL2 reader encounters an object
produced as described above (in the #Y or #Z case).  When the object
was written, information was recorded on whether that object was a
hons.  In the case of #Z, the object will be read as a hons if and only
if it was originally written as a hons.  But in the case of #Y, it will
never be read as a hons.  Thus, #Y and #Z will behave the same if the
original written object was not a hons, creating an object that is not
a hons.  For an equivalent explanation and a bit more discussion, see
*note SERIALIZE-READ::, in particular the discussion of the hons-mode.
The value :smart described there corresponds to #Z, while :never
corresponds to #Y.


File: acl2-doc-emacs.info,  Node: STOBJ,  Next: SWITCHES-PARAMETERS-AND-MODES,  Prev: SERIALIZE,  Up: Top

STOBJ    single-threaded objects or "von Neumann bottlenecks"

In ACL2, a "single-threaded object" is a data structure whose use is so
syntactically restricted that only one instance of the object need ever
exist and its fields can be updated by destructive assignments.

Note: Novices are advised to avoid using single-threaded objects,
perhaps instead using community book
books/data-structures/structures.lisp.  At the least, consider using
(set-verify-guards-eagerness 0) to avoid guard verification.

The documentation in this section is laid out in the form of a tour that
visits the documented topics in a reasonable order.  We recommend that
you follow the tour the first time you read about stobjs.  The list of
all stobj topics is shown below.  The tour starts immediately
afterwards.  Also see *note DEFSTOBJ:: and, for so-called abstract
stobjs, see *note DEFABSSTOBJ::.

* Menu:

* DECLARE-STOBJS:: declaring a formal parameter name to be a single-threaded object

* NESTED-STOBJS:: using stobjs that contain stobjs

* RESIZE-LIST:: list resizer in support of stobjs

* STOBJ-EXAMPLE-1:: an example of the use of single-threaded objects

* STOBJ-EXAMPLE-1-DEFUNS:: the defuns created by the counters stobj

* STOBJ-EXAMPLE-1-IMPLEMENTATION:: the implementation of the counters stobj

* STOBJ-EXAMPLE-1-PROOFS:: some proofs involving the counters stobj

* STOBJ-EXAMPLE-2:: an example of the use of arrays in single-threaded objects

* STOBJ-EXAMPLE-3:: another example of a single-threaded object

* STOBJ-LET:: See *note NESTED-STOBJS::.

* WITH-LOCAL-STATE:: locally bind state

* WITH-LOCAL-STOBJ:: locally bind a single-threaded object


Related topics other than immediate subtopics:
* DEFABSSTOBJ:: define a new abstract single-threaded object

* DEFSTOBJ:: define a new single-threaded object

As noted, a "single-threaded object" is a data structure whose use is so
syntactically restricted that only one instance of the object need ever
exist.  Updates to the object must be sequentialized.  This allows us to
update its fields with destructive assignments without wrecking the
axiomatic semantics of update-by-copy.  For this reason,
single-threaded objects are sometimes called "von Neumann bottlenecks."

From the logical perspective, a single-threaded object is an ordinary
ACL2 object, e.g., composed of integers and conses.  Logically
speaking, ordinary ACL2 functions are defined to allow the user to
"access" and "update" its fields.  Logically speaking, when fields in
the object, obj, are "updated" with new values, a new object, obj', is
constructed.

But suppose that by syntactic means we could ensure that there were no
more references to the "old" object, obj.  Then we could create obj' by
destructively modifying the memory locations involved in the
representation of obj.  The syntactic means is pretty simple but
draconian: the only reference to obj is in the variable named OBJ.

The consequences of this simple rule are far-reaching and require some
getting used to.  For example, if OBJ has been declared as a
single-threaded object name, then the following consequences ensue (but
see the discussion of congruent stobjs below for a slight relaxation).

o OBJ is a top-level global variable that contains the current object,
obj.

o If a function uses the formal parameter OBJ, the only "actual
expression" that can be passed into that slot is the variable OBJ, not
merely a term that "evaluates to an obj"; thus, such functions can only
operate on the current object.  So for example, instead of (FOO
(UPDATE-FIELD1 3 ST)) write (LET ((ST (UPDATE-FIELD1 3 ST))) (FOO ST)).

o The accessors and updaters have a formal parameter named OBJ, so by
the rule just above, those functions can only be applied to the current
object.  The recognizer is the one exception to the rule: it may be
applied either the OBJ or to an ordinary (non-stobj) object.

o The ACL2 primitives, such as CONS, CAR and CDR, may not be applied to
the variable OBJ.  Thus, for example, obj may not be consed into a list
(which would create another pointer to it) or accessed or copied via
"unapproved" means.

o The updaters return a "new OBJ object", i.e., obj'; thus, when an
updater is called, the only variable which can hold its result is OBJ.

o If a function calls an OBJ updater, it must return an OBJ object
(either as the sole value returned, or in (mv ... OBJ ...); see *note
MV::).

o When a top-level expression involving OBJ returns an OBJ object, that
object becomes the new current value of OBJ.

There are other functional languages supporting single-threadedness, for
example Haskell's "monads" and Clean's "uniqueness type system".  Of
course, ACL2 provides a theorem prover that can prove theorems that
involve such constructs.

Note that the syntactic restrictions noted above are enforced only when
single-threaded objects are encountered directly in the top-level loop
or are used in function definitions; the accessor and update functions
for single-threaded objects may be used without restriction in formulas
to be proved.  Since function evaluation is sometimes necessary during
proofs, ACL2 must be able to evaluate these functions on logical
constants representing the object, even when the constant is not "the
current object."  Thus, ACL2 supports both the efficient von Neumann
semantics and the clean applicative semantics, and uses the first in
contexts where execution speed is paramount and the second during
proofs.

Defstobj and defabsstobj events introduce stobjs.  See *note DEFSTOBJ::
for more details about stobjs.  In particular, a relatively advanced
notion of "congruent stobjs" is discussed there.  The idea is to allow
a stobj, st2, of the same "shape" as a given stobj, st1, to be used in
place of st1.  Other defstobj keywords allow inlining and renaming of
stobj accessors and updaters.

But we are getting ahead of ourselves.  To start the stobj tour, see
*note STOBJ-EXAMPLE-1::.


File: acl2-doc-emacs.info,  Node: DECLARE-STOBJS,  Next: NESTED-STOBJS,  Prev: STOBJ,  Up: STOBJ

DECLARE-STOBJS    declaring a formal parameter name to be a single-threaded object

When a defun uses one of its formals as a single-threaded object
(stobj), the defun _must_ include a declaration that the formal is to
be so used.  An exception is the formal "state," which if not declared
as explained below, may still be used provided an appropriate global
"declaration" is issued: see *note SET-STATE-OK::.

If the formal in question is counters then an appropriate declaration is

     (declare (xargs :stobjs counters))

or, more generally,

     (declare (xargs :stobjs (... counters ...)))

where all the single-threaded formals are listed.

For such a declaration to be legal it must be the case that all the
names have previously been defined as single-threaded objects with
defstobj.

When an argument is declared to be single-threaded the guard of the
function is augmented by conjoining to it the condition that the
argument satisfy the recognizer for the single-threaded object.
Furthermore, the syntactic checks done to enforce the legal use of
single-threaded objects are also sufficient to allow these guard
conjuncts to be automatically proved.

The obvious question arises:  Why does ACL2 insist that you declare
stobj names before using them in defuns if you can only declare names
that have already been defined with defstobj?  What would go wrong if a
formal were treated as a single-threaded object if and only if it had
already been so defined?

Suppose that one user, say Jones, creates a book in which counters is
defined as a single-threaded object.  Suppose another user, Smith,
creates a book in which counters is used as an ordinary formal
parameter.  Finally, suppose a third user, Brown, wishes to use both
books.  If Brown includes Jones' book first and then Smith's, then
Smith's function treats counters as single-threaded.  But if Brown
includes Smith's book first, the argument is treated as ordinary.

ACL2 insists on the declaration to ensure that the definition is
processed the same way no matter what the context.

