ACL2

by Matt Kaufmann and J Strother Moore

ACL2 Version 1.9 June 1997 Copyright \begin{matrix}c \\ ◯ \end{matrix} 1997 Computational Logic, Inc. (CLI). Distributed under the terms of the GNU General Public License.

This is documentation for ACL2 Version 1.9

Published by Computational Logic, Inc.

1717 West Sixth Street, Suite 290, Austin, TX 78703 USA NOTE: The ACL2 documentation is in hypertext form. It is best read with an appropriate browser and is available in both HTML and Emacs Texinfo formats. See the file doc/README. If you are using the documentation as an introduction to ACL2, start with the chapter entitled “ACL2-TUTORIAL”.

This is a Postscript version of the hypertext document. While somewhat awkward to use since the links are “dead”, it may serve as a reference manual. In this Postscript version, links to other nodes will be implicitly indicated with the mark ^. For example, you may see books (BOOKS^)

— this indicates that there is documentation present on BOOKS. The table of contents, as well as the index, will show you where to find the node named “BOOKS”.

Some links are followed by the sign “<>”. This is our way of denoting the “Warning Sign” used in the HTML version of the guided tours. Such links lead from material that is on a guided tour into material that is not on a guided tour. If you are trying to follow a guided tour with this Postscript version of the documentation, we advise you not to follow such links. The guided tours are best read with an appropriate hypertext browser.

2 ACL2 Version 1.9

1 ACL2-TUTORIAL

ACL2-TUTORIAL tutorial introduction to ACL2

This section contains a tutorial introduction (INTRODUCTION^) to ACL2, some examples of the use of ACL2, and pointers to additional information.

* INTRODUCTION:: introduction to ACL2

* STARTUP:: How to start using ACL2; the ACL2 command (COMMAND^) loop

* TIDBITS:: some basic hints for using ACL2

* TIPS:: some hints for using the ACL2 prover

* TUTORIAL-EXAMPLES:: examples of ACL2 usage

You might also find CLI Technical Report 101 helpful for a high-level view of the design goals of ACL2.

If you are already familiar with Nqthm, see Section 5.12 [NQTHM-TO-ACL2], page 156 for help in making the transition from Nqthm to ACL2.

If you would like more familiarity with Nqthm, we suggest CLI Technical Report 100, which works through a non-trivial example. A short version of that paper, which is entitled “Interaction with the Boyer-Moore Theorem Prover: A Tutorial Study Using the Arithmetic-Geometric Mean Theorem,” is to appear in the Journal of Automated Reasoning’s special issue on induction, probably in 1995 or 1996. Readers may well find that this paper indirectly imparts useful information about the effective use of ACL2.

1.1 INTRODUCTION

INTRODUCTION introduction to ACL2

This section contains introductory material on ACL2 including what ACL2 is, how to get started using the system, how to read the output, and other introductory topics. It was written almost entirely by Bill Young of Computational Logic, Inc.

You might also find CLI Technical Report 101 helpful, especially if you are familiar with Nqthm. If you would like more familiarity with Nqthm, we suggest CLI Technical Report 100.

OVERVIEW ACL2 is an automated reasoning system under development at Computational Logic, Inc. It is the successor to the Nqthm (or Boyer-Moore) logic and proof system and its Pc-Nqthm interactive enhancement. The acronym ACL2 actually stands for “A Computational Logic for Applicative Common Lisp”. This title suggests several distinct but related aspects of ACL2.

We assume that readers of the ACL2 documentation (DOCUMENTATION^) have at least a very slight familiarity with some Lisp-like language. We will address the issue of prerequisites further, in “ABOUT THIS TUTORIAL” below.

As a logic, ACL2 is a formal system with rigorously defined syntax and semantics. In mathematical parlance, the ACL2 logic is a first-order logic of total recursive functions providing mathematical induction on the ordinals up to epsilon-0 and two extension principles: one for recursive definition and one for constrained introduction of new function symbols, here called encapsulation. The syntax of ACL2 is that of Common Lisp; ACL2 specifications are “also” Common Lisp programs in a way that we will make clear later. In less formal language, the ACL2 logic is an integrated collection of rules for defining (or axiomatizing) recursive functions, stating properties of those functions, and rigorously establishing those properties. Each of these activities is mechanically supported.

As a specification language, ACL2 supports modeling of systems of various kinds. An ACL2 function can equally be used to express purely formal relationships among mathematical entities, to describe algorithms, or to capture the intended behavior of digital systems. For digital systems, an ACL2 specification is a mathematical model that is intended to formalize relevant aspects of system behavior. Just as physics allows us to model the behavior of continuous physical systems, ACL2 allows us to model digital systems, including many with physical realizations such as computer hardware. As early as the 1930’s Church, Kleene, Turing and others established that recursive functions provide an expressive formalism for modeling digital computation. Digital computation should be understood in a broad sense, covering a wide variety of activities including almost any systematic or algorithmic activity, or activity that can be reasonably approximated in that way. This ranges from the behavior of a digital circuit to the behavior of a programming language compiler to the behavior of a controller for a physical system (as long as the system can be adequately modeled discretely). All of these have been modeled using ACL2 or its predecessor Nqthm.

ACL2 is a computational logic in at least three distinct senses. First, the theory of recursive functions is often considered the mathematics of computation. Church conjectured that any “effective computation” can be modeled as a recursive function. Thus, ACL2 provides an expressive language for modeling digital systems. Second, many ACL2 specifications are executable. In fact, recursive functions written in ACL2 are Common Lisp functions that can be submitted to any compliant Common Lisp compiler and executed (in an environment where suitable ACL2-specific macros and functions are defined). Third, ACL2 is computational in the sense that calculation is heavily integrated into the reasoning process. Thus, an expression with explicit constant values but no free variables can be simplified by calculation rather than by complex logical manipulations.

ACL2 is a powerful, automated theorem prover or proof checker. This means that a competent user can utilize the ACL2 system to discover proofs of theorems stated in the ACL2 logic or to check previously discovered proofs. The basic deductive steps in an ACL2-checked proof are often quite large, due to the sophisticated combination of decision procedures, conditional rewriting, mathematical and structural induction, propositional simplification, and complex heuristics to orchestrate the interactions of these capabilities. Unlike some automated proof systems, ACL2 does not produce a formal proof. However, we believe that if ACL2 certifies the “theoremhood” of a given conjecture, then such a formal proof exists and, therefore, the theorem is valid. The ultimate result of an ACL2 proof session is a collection of “events (EVENTS^),” possibly grouped into “books (BOOKS^),” that can be replayed in ACL2. Therefore, a proof can be independently validated by any ACL2 user.

ACL2 may be used in purely automated mode in the shallow sense that conjectures are submitted to the prover and the user does not interact with the proof attempt (except possibly to stop it) until the proof succeeds or fails. However, any non-trivial proof attempt is actually interactive, since successful proof “events (EVENTS^)” influence the subsequent behavior of the prover. For example, proving a lemma may introduce a rule that subsequently is used automatically by the prover. Thus, any realistic proof attempt, even in “automatic” mode, is really an interactive dialogue with the prover to craft a sequence of events (EVENTS^) building an appropriate theory and proof rules leading up to the proof of the desired result. Also, ACL2 supports annotating a theorem with “hints (HINTS^)” designed to guide the proof attempt. By supplying appropriate hints (HINTS^), the user can suggest proof strategies that the prover would not discover automatically. There is a “proof-tree (PROOF-TREE^)” facility (see Chapter 12 [PROOF-TREE], page 617) that allows the user to monitor (MONITOR^) the progress and structure of a proof attempt in real-time. Exploring failed proof attempts is actually where heavy-duty ACL2 users spend most of their time.

ACL2 can also be used in a more explicitly interactive mode. The “proof-checker (PROOF-CHECKER^)” subsystem of ACL2 allows exploration of a proof on a fairly low level including expanding calls of selected function symbols, invoking specific rewrite (REWRITE^) rules, and selectively navigating around the proof. This facility can be used to gain sufficient insight into the proof to construct an automatic version, or to generate a detailed interactive-style proof that can be replayed in batch mode.

Because ACL2 is all of these things — computational logic, specification language, programming (PROGRAMMING^) system, and theorem prover — it is more than the sum of its parts. The careful integration of these diverse aspects has produced a versatile automated reasoning system suitable for building highly reliable digital systems. In the remainder of this tutorial, we will illustrate some simple uses of this automated reasoning system.

ABOUT THIS TUTORIAL

ACL2 is a complex system with a vast array of features, bells and whistles. However, it is possible to perform productive work with the system using only a small portion of the available functionality. The goals of this tutorial are to:

familiarize the new user with the most basic features of and modes of interaction with ACL2;

familiarize her with the form of output of the system; and

work through a graduated series of examples.

The more knowledge the user brings to this system, the easier it will be to become proficient. On one extreme: the ideal user of ACL2 is an expert Common Lisp programmer, has deep understanding of automated reasoning, and is intimately familiar with the earlier Nqthm system. Such ideal users are unlikely to need this tutorial. However, without some background knowledge, the beginning user is likely to become extremely confused and frustrated by this system. We suggest that a new user of ACL2 should:

(a) have a little familiarity with Lisp, including basic Lisp programming and prefix notation (a Lisp reference manual such as Guy Steele’s “Common Lisp: The Language” is also helpful);

(b) be convinced of the utility of formal modeling; and

(c) be willing to gain familiarity with basic automated theorem proving topics such as rewriting and algebraic simplification.

We will not assume any deep familiarity with Nqthm (the so-called “Boyer-Moore Theorem Prover”), though the book “A Computational Logic Handbook” by Boyer and Moore (Academic Press, 1988) is an extremely useful reference for many of the topics required to become a competent ACL2 user. We’ll refer to it as ACLH below.

As we said in the introduction, ACL2 has various facets. For example, it can be used as a Common Lisp programming (PROGRAMMING^) system to construct application programs. In fact, the ACL2 system itself is a large Common Lisp program constructed almost entirely within ACL2.

Another use of ACL2 is as a specification and modeling tool. That is the aspect we will concentrate on in the remainder of this tutorial.

GETTING STARTED

This section is an abridged version of what’s available elsewhere; feel free to see Section 1.2 [STARTUP], page 16 for more details.

How you start ACL2 will be system dependent, but you’ll probably type something like “acl2” at your operating system prompt. Consult your system administrator for details.

When you start up ACL2, you’ll probably find yourself inside the ACL2 command (COMMAND^) loop, as indicated by the following prompt (PROMPT^).

       ACL2 !>

If not, you should type (LP). See Section 8.65 [LP], page 350, which has a lot more information about the ACL2 command (COMMAND^) loop.

There are two “modes” for using ACL2, :logic (LOGIC^) and :program (PROGRAM^). When you begin ACL2, you will ordinarily be in the :logic (LOGIC^) mode. This means that any new function defined is not only executable but also is axiomatically defined in the ACL2 logic. (See Section 8.20 [DEFUN-MODE], page 275 and see Section 8.18 [DEFAULT-DEFUN-MODE], page 273.) Roughly speaking, :program (PROGRAM^) mode is available for using ACL2 as a programming (PROGRAMMING^) language without some of the logical burdens necessary for formal reasoning. In this tutorial we will assume that we always remain in :logic (LOGIC^) mode and that our purpose is to write formal models of digital systems and to reason about them.

Now, within the ACL2 command (COMMAND^) loop you can carry out various kinds of activities, including the folllowing. (We’ll see examples later of many of these.)

define new functions (see Section 6.16 [DEFUN], page 178);

execute functions on concrete data;

pose and attempt to prove conjectures about previously defined functions (see Section 6.15 [DEFTHM], page 176); query the ACL2 “world (WORLD^)” or database (e.g., see Section 7.7 [PE], page 222); and

numerous other things.

In addition, there is extensive on-line documentation (DOCUMENTATION^), of which this tutorial introduction is a part.

INTERACTING WITH ACL2

The standard means of interacting with ACL2 is to submit a sequence of forms for processing by the ACL2 system. These forms are checked for syntactic and semantic acceptability and appropriately processed by the system. These forms can be typed directly at the ACL2 prompt (PROMPT^). However, most successful ACL2 users prefer to do their work using the Emacs text editor, maintaining an Emacs “working” buffer in which forms are edited. Those forms are then copied to the ACL2 interaction buffer, which is often the "*shell*" buffer.

In some cases, processing succeeds and makes some change to the ACL2 “logical world (WORLD^),” which affects the processing of subsequent forms. How can this processing fail? For example, a proposed theorem will be rejected unless all function symbols mentioned have been previously defined. Also the ability of ACL2 to discover the proof of a theorem may depend on the user previously having proved other theorems. Thus, the order in which forms are submitted to ACL2 is quite important. Maintaining forms in an appropriate order in your working buffer will be helpful for re-playing the proof later.

One of the most common events (EVENTS^) in constructing a model is introducing new functions. New functions are usually introduced using the defun (DEFUN^) form; we’ll encounter some exceptions later. Proposed function definitions are checked to make sure that they are syntactically and semantically acceptable (e.g., that all mentioned functions have been previously defined) and, for recursive functions, that their recursive calls terminate. A recursive function definition is guaranteed to terminate if there is some some “measure” of the arguments and a “well-founded” ordering such that the arguments to the function get smaller in each recursive call. See Section 15.17 [WELL-FOUNDED-RELATION], page 769.

For example, suppose that we need a function that will append two lists together. (We already have one in the ACL2 append (APPEND^) function; but suppose perversely that we decide to define our own.) Suppose we submit the following definition (you should do so as well and study the system output):

(defun my-app (x y)
  (if (atom x)
      y
    (cons (car x) (my-app x y))))

The system responds with the following message:

ACL2 Error in ( DEFUN MY-APP ...):  No :MEASURE was supplied with
the definition of MY-APP.  Our heuristics for guessing one have not
made any suggestions.  No argument of the function is tested along
every branch and occurs as a proper subterm at the same argument
position in every recursive call.  You must specify a :MEASURE.  See
:DOC defun.

This means that the system could not find an expression involving the formal parameters x and y that decreases under some well-founded order in every recursive call (there is only one such call). It should be clear that there is no such measure in this case because the only recursive call doesn’t change the arguments at all. The definition is obviously flawed; if it were accepted and executed it would loop forever. Notice that a definition that is rejected is not stored in the system database; there is no need to take any action to have it “thrown away.” Let’s try again with the correct definition. The interaction now looks like (we’re also putting in the ACL2 prompt (PROMPT^); you don’t type that):

ACL2 !>(defun my-app (x y)
         (if (atom x)
             y
           (cons (car x) (my-app (cdr x) y))))
The admission of MY-APP is trivial, using the relation E0-ORD-<
(which is known to be well-founded on the domain recognized by
E0-ORDINALP) and the measure (ACL2-COUNT X).  We observe that the
type of MY-APP is described by the theorem
(OR (CONSP (MY-APP X Y)) (EQUAL (MY-APP X Y) Y)).
We used primitive type reasoning.
Summary
Form:  ( DEFUN MY-APP ...)
Rules: ((:FAKE-RUNE-FOR-TYPE-SET NIL))
Warnings:  None
Time:  0.07 seconds (prove: 0.00, print: 0.00, other: 0.07)

  MY-APP

Notice that this time the function definition was accepted. We didn’t have to supply a measure explicitly; the system inferred one from the form of the definition. On complex functions it may be necessary to supply a measure explicitly. (See Section 8.102 [XARGS], page 406.)

The system output provides several pieces of information.

The revised definition is acceptable. The system realized that there is a particular measure (namely, (acl2-count x)) and a well-founded relation (e0-ord-<) under which the arguments of my-app get smaller in recursion. Actually, the theorem prover proved several theorems to admit my-app. The main one was that when (atom x) is false

the acl2-count of (cdr x) is less than (in the e0-ord-< sense) the acl2-count of

x. Acl2-count (ACL2-COUNT^) is the most commonly used measure of the “size“ of an ACL2 object. E0-ord-< (E0-ORD-<^) is the ordering relation on ordinals less than epsilon-0. On the natural numbers it is just ordinary “<”.

The observation printed about “the type of MY-APP” means that calls of the function my-app will always return a value that is either a cons (CONS^) pair or is equal to the second parameter.

The summary provides information about which previously introduced definitions and lemmas were used in this proof, about some notable things to watch out for (the Warnings), and about how long this event took to process.

Usually, it’s not important to read this information. However, it is a good habit to scan it briefly to see if the type information is surprising to you or if there are Warnings. We’ll see an example of them later.

After a function is accepted, it is stored in the database and available for use in other function definitions or lemmas. To see the definition of any function use the :pe (PE^) command (see Section 7.7 [PE], page 222). For example,

  ACL2 !>:pe my-app
   L       73:x(DEFUN MY-APP (X Y)
                      (IF (ATOM X)
                          Y (CONS (CAR X) (MY-APP (CDR X) Y))))

This displays the definition along with some other relevant information. In this case, we know that this definition was processed in :logic (LOGIC^) mode (the “L”) and was the 73rd command (COMMAND^) processed in the current session.

We can also try out our newly defined function on some sample data. To do that, just submit a form to be evaluated to ACL2. For example,

       ACL2 !>(my-app '(0 1 2) '(3 4 5))
       (0 1 2 3 4 5)
       ACL2 !>(my-app nil nil)
       NIL
       ACL2 !>

Now suppose we want to prove something about the function just introduced. We conjecture, for example, that the length of the append (APPEND^) of two lists is the sum of their lengths. We can formulate this conjecture in the form of the following ACL2 defthm (DEFTHM^) form.

       (defthm my-app-length
         (equal (len (my-app x y))
                (+ (len x) (len y))))

First of all, how did we know about the functions len and + (+^), etc.? The answer to that is somewhat unsatisfying — we know them from our past experience in using Common Lisp and ACL2. It’s hard to know that a function such as len exists without first knowing some Common Lisp. If we’d guessed that the appropriate function was called length (LENGTH^) (say, from our knowledge of Lisp) and tried :pe length, we would have seen that length (LENGTH^) is defined in terms of len, and we could have explored from there. Luckily, you can write a lot of ACL2 functions without knowing too many of the primitive functions.

Secondly, why don’t we need some “type” hypotheses? Does it make sense to append things that are not lists? Well, yes. ACL2 and Lisp are both quite weakly typed. For example, inspection of the definition of my-app shows that if x is not a cons (CONS^) pair, then (my-app x y) always returns y, no matter what y is.

Thirdly, would it matter if we rewrote the lemma with the equality reversed, as follows?

  (defthm my-app-length2
    (equal (+ (len x) (len y))
           (len (my-app x y)))).

The two are logically equivalent, but...yes, it would make a big difference. Recall our remark that a lemma is not only a “fact” to be proved; it also is used by the system to prove other later lemmas. The current lemma would be stored as a rewrite (REWRITE^) rule. (See Chapter 15 [RULE-CLASSES], page 723.) For a rewrite (REWRITE^) rule, a conclusion of the form (EQUAL LHS RHS) means to replace instances of the LHS by the appropriate instance of the RHS. Presumably, it’s better to rewrite (REWRITE^) (len (my-app x y)) to (+ (len x) (len y)) than the other way around. The reason is that the system “knows” more about + (+^) than it does about the new function symbol my-app.

So let’s see if we can prove this lemma. Submitting our preferred defthm (DEFTHM^) to ACL2 (do it!), we get the following interaction:

          --------------------------------------------------
ACL2 !>(defthm my-app-length
  (equal (len (my-app x y))
         (+ (len x) (len y))))
Name the formula above *1.
Perhaps we can prove *1 by induction.  Three induction schemes are
suggested by this conjecture.  These merge into two derived
induction schemes.  However, one of these is flawed and so we are
left with one viable candidate.
We will induct according to a scheme suggested by (LEN X), but
modified to accommodate (MY-APP X Y).  If we let (:P X Y) denote *1
above then the induction scheme we'll use is
(AND (IMPLIES (NOT (CONSP X)) (:P X Y))
     (IMPLIES (AND (CONSP X) (:P (CDR X) Y))
              (:P X Y))).
This induction is justified by the same argument used to admit LEN,
namely, the measure (ACL2-COUNT X) is decreasing according to the
relation E0-ORD-< (which is known to be well-founded on the domain
recognized by E0-ORDINALP).  When applied to the goal at hand the
above induction scheme produces the following two nontautological
subgoals.
Subgoal *1/2
(IMPLIES (NOT (CONSP X))
         (EQUAL (LEN (MY-APP X Y))

                (+ (LEN X) (LEN Y)))).
But simplification reduces this to T, using the :definitions of FIX,
LEN and MY-APP, the :type-prescription rule LEN, the :rewrite rule
UNICITY-OF-0 and primitive type reasoning.
Subgoal *1/1
(IMPLIES (AND (CONSP X)
              (EQUAL (LEN (MY-APP (CDR X) Y))
                     (+ (LEN (CDR X)) (LEN Y))))
         (EQUAL (LEN (MY-APP X Y))
                (+ (LEN X) (LEN Y)))).
This simplifies, using the :definitions of LEN and MY-APP, primitive
type reasoning and the :rewrite rules COMMUTATIVITY-OF-+ and
CDR-CONS, to
Subgoal *1/1'
(IMPLIES (AND (CONSP X)
              (EQUAL (LEN (MY-APP (CDR X) Y))
                     (+ (LEN Y) (LEN (CDR X)))))
         (EQUAL (+ 1 (LEN (MY-APP (CDR X) Y)))
                (+ (LEN Y) 1 (LEN (CDR X))))).
But simplification reduces this to T, using linear arithmetic,
primitive type reasoning and the :type-prescription rule LEN.
That completes the proof of *1.
Q.E.D.
Summary
Form:  ( DEFTHM MY-APP-LENGTH ...)
Rules: ((:REWRITE UNICITY-OF-0)
        (:DEFINITION FIX)
        (:REWRITE COMMUTATIVITY-OF-+)
        (:DEFINITION LEN)
        (:REWRITE CDR-CONS)
        (:DEFINITION MY-APP)
        (:TYPE-PRESCRIPTION LEN)
        (:FAKE-RUNE-FOR-TYPE-SET NIL)
        (:FAKE-RUNE-FOR-LINEAR NIL))
Warnings:  None
Time:  0.30 seconds (prove: 0.13, print: 0.05, other: 0.12)
 MY-APP-LENGTH
          --------------------------------------------------

Wow, it worked! In brief, the system first tried to rewrite (REWRITE^) and simplify as much as possible. Nothing changed; we know that because it said “Name the formula above *1.” Whenever the system decides to name a formula in this way, we know that it has run out of techniques to use other than proof by induction.

The induction performed by ACL2 is structural or “Noetherian” induction. You don’t need to know much about that except that it is induction based on the structure of some object. The heuristics infer the structure of the object from the way the object is recursively decomposed by the functions used in the conjecture. The heuristics of ACL2 are reasonably good at selecting an induction scheme in simple cases. It is possible to override the heuristic choice by providing an :induction hint (see Section 8.43 [HINTS], page 319). In the case of the theorem above, the system inducts on the structure of x as suggested by the decomposition of x in both (my-app x y) and (len x). In the base case, we assume that x is not a consp (CONSP^). In the inductive case, we assume that it is a consp (CONSP^) and assume that the conjecture holds for (cdr x).

There is a close connection between the analysis that goes on when a function like my-app is accepted and when we try to prove something inductively about it. That connection is spelled out well in Boyer and Moore’s book “A Computational Logic,” if you’d like to look it up. But it’s pretty intuitive. We accepted my-app because the “size” of the first argument x decreases in the recursive call. That tells us that when we need to prove something inductively about my-app, it’s a good idea to try an induction on the size of the first argument. Of course, when you have a theorem involving several functions, it may be necessary to concoct a more complicated induction (INDUCTION^) schema, taking several of them into account. That’s what’s meant by “merging” the induction schemas.

The proof involves two cases: the base case, and the inductive case. You’ll notice that the subgoal numbers go down rather than up, so you always know how many subgoals are left to process. The base case (Subgoal *1/2) is handled by opening up the function definitions, simplifying, doing a little rewriting, and performing some reasoning based on the types of the arguments. You’ll often encounter references to system defined lemmas (like unicity-of-0). You can always look at those with :pe (PE^); but, in general, assume that there’s a lot of simplification power under the hood that’s not too important to understand fully.

The inductive case (Subgoal *1/1) is also dispatched pretty easily. Here we assume the conjecture true for the cdr (CDR^) of the list and try to prove it for the entire list. Notice that the prover does some simplification and then prints out an updated version of the goal (Subgoal *1/1'). Examining these gives you a pretty good idea of what’s going on in the proof.

Sometimes one goal is split into a number of subgoals, as happened with the induction above. Sometimes after some initial processing the prover decides it needs to prove a subgoal by induction; this subgoal is given a name and pushed onto a stack of goals. Some steps, like generalization (see ACLH), are not necessarily validity preserving; that is, the system may adopt a false subgoal while trying to prove a true one. (Note that this is ok in the sense that it is not “unsound.” The system will fail in its attempt to establish the false subgoal and the main proof attempt will fail.) As you gain facility with using the prover, you’ll get pretty good at recognizing what to look for when reading a proof script. The prover’s proof-tree (PROOF-TREE^) utility helps with monitoring an ongoing proof and jumping to designated locations in the proof (see Chapter 12 [PROOF-TREE], page 617). See Section 1.4 [TIPS], page 19 for a number of useful pointers on using the theorem prover effectively.

When the prover has successfully proved all subgoals, the proof is finished. As with a defun (DEFUN^), a summary of the proof is printed. This was an extremely simple proof, needing no additional guidance. More realistic examples typically require the user to look carefully at the failed proof log to find ways to influence the prover to do better on its next attempt. This means either: proving some rules that will then be available to the prover, changing the global state in ways that will affect the proof, or providing some hints (HINTS^) locally that will influence the prover’s behavior. Proving this lemma (my-app-length) is an example of the first. Since this is a rewrite (REWRITE^) rule, whenever in a later proof an instance of the form (LEN (MY-APP X Y)) is encountered, it will be rewritten to the corresponding instance of (+ (LEN X) (LEN Y)). Disabling the rule by executing the command (COMMAND^)

       (in-theory (disable my-app-length)),

is an example of a global change to the behavior of the prover since this rewrite (REWRITE^) will not be performed subsequently (unless the rule is again enable (ENABLE^)d). Finally, we can add a (local) disable (DISABLE^) “hint” to a defthm (DEFTHM^), meaning to disable (DISABLE^) the lemma only in the proof of one or more subgoals. For example:

       (defthm my-app-length-commutativity
         (equal (len (my-app x y))
                (len (my-app y x)))
         :hints (("Goal" :in-theory (disable my-app-length))))

In this case, the hint supplied is a bad idea since the proof is much harder with the hint than without it. Try it both ways.

By the way, to undo the previous event use :u (see Section 7.15 [U], page 229). To undo back to some earlier event use :ubt (see Section 7.16 [UBT], page 230). To view the current event use :pe :here. To list several events (EVENTS^) use :pbt (see Section 7.2 [PBT], page 217).

Notice the form of the hint in the previous example (see Section 8.43 [HINTS], page 319). It specifies a goal to which the hint applies. "Goal" refers to the top-level goal of the theorem. Subgoals are given unique names as they are generated. It may be useful to suggest that a function symbol be disable (DISABLE^)d only for Subgoal 1.3.9, say, and a different function enable (ENABLE^)d only on Subgoal 5.2.8. Overuse of such hints (HINTS^) often suggests a poor global proof strategy.

We now recommend that you visit documentation (DOCUMENTATION^) on additional examples. See Section 1.5 [TUTORIAL-EXAMPLES], page 31.

1.2 STARTUP

STARTUP How to start using ACL2; the ACL2 command (COMMAND^) loop

When you start up ACL2, you’ll probably find yourself inside the ACL2 command (COMMAND^) loop, as indicated by the following prompt (PROMPT^).

       ACL2 !>

If not, you should type (LP). See Section 8.65 [LP], page 350, which has a lot more information about the ACL2 command (COMMAND^) loop.

You should now be in ACL2. The current “default-defun-mode (DEFAULT-DEFUN-MODE^)” is :logic (LOGIC^); the other mode is :program (PROGRAM^), which would cause the letter p to be printed in the prompt (PROMPT^). :Logic (LOGIC^) means that any function we define is not only executable but also is axiomatically defined in the ACL2 logic. See Section 8.20 [DEFUN-MODE], page 275 and see Section 8.18 [DEFAULT-DEFUN-MODE], page 273. For example we can define a function my-cons as follows. (You may find it useful to start up ACL2 and submit this and other command (COMMAND^)s below to the ACL2 command (COMMAND^) loop, as we won’t include output below.)

       ACL2 !>(defun my-cons (x y) (cons x y))

An easy theorem may then be proved: the car (CAR^) of (my-cons a b) is A.

       ACL2 !>(defthm car-my-cons (equal (car (my-cons a b)) a))

Notice that unlike Nqthm, the theorem command (COMMAND^) is defthm (DEFTHM^) rather than prove-lemma. See Section 6.15 [DEFTHM], page 176, which explains (among other things) that the default is to turn theorems into rewrite (REWRITE^) rules.

Various keyword commands are available to query the ACL2 “world (WORLD^)”, or database. For example, we may view the definition of my-cons by invoking a command to print events (EVENTS^), as follows.

       ACL2 !>:pe my-cons

Also see Section 7.7 [PE], page 222. We may also view all the lemmas that rewrite (REWRITE^) term (TERM^)s whose top function symbol is car (CAR^) by using the following command, whose output will refer to the lemma car-my-cons proved above.

       ACL2 !>:pl car

Also see Section 7.10 [PL], page 223. Finally, we may print all the command (COMMAND^)s back through the initial world (WORLD^) as follows.

       ACL2 !>:pbt 0

See Chapter 7 [HISTORY], page 215 for a list of commands, including these, for viewing the current ACL2 world (WORLD^).

Continue with the documentation (DOCUMENTATION^) for tutorial-examples (TUTORIAL-EXAMPLES^) to see a simple but illustrative example in the use of ACL2 for reasoning about functions.

1.3 TIDBITS

TIDBITS some basic hints for using ACL2

See Chapter 3 [BOOKS], page 93 for a discussion of books. Briefly, a book is a file whose name ends in “.lisp” that contains ACL2 events (EVENTS^); see Chapter 6 [EVENTS], page 161.

See Chapter 7 [HISTORY], page 215 for a list of useful commands. Some examples:

       :pbt :here      ; print the current event
       :pbt (:here -3) ; print the last four events
       :u              ; undo the last event
       :pe append      ; print the definition of append

See Chapter 5 [DOCUMENTATION], page 137 to learn how to print documentation to the terminal. There are also versions of the documentation (DOCUMENTATION^) for Mosaic, Emacs Info, and hardcopy.

There are quite a few kinds of rules allowed in ACL2 besides :rewrite (REWRITE^) rules, though we hope that beginners won’t usually need to be aware of them. See Chapter 15 [RULE-CLASSES], page 723 for details. In particular, there is support for congruence (CONGRUENCE^) rewriting. See Section 16.10 [RUNE], page 784 (“RUle NamE”) for a description of the various kinds of rules in the system. Also see Chapter 16 [THEORIES], page 775 for a description of how to build theories (THEORIES^) of rune (RUNE^)s, which are often used in hints; see Section 8.43 [HINTS], page 319.

A “programming (PROGRAMMING^) mode” is supported; see Section 6.25 [PROGRAM], page 195, see Section 8.20 [DEFUN-MODE], page 275, and see Section 8.18 [DEFAULT-DEFUN-MODE], page 273. It can be useful to prototype functions after executing the command :program (PROGRAM^), which will cause definitions to be syntaxed-checked only.

ACL2 supports mutual recursion, though this feature is not tied into the automatic discovery of induction (INDUCTION^) schemas and is often not the best way to proceed when you expect to be reasoning about the functions. See Section 8.22 [DEFUNS], page 280; also see Section 6.24 [MUTUAL-RECURSION], page 194.

See Section 9.7 [LD], page 416 for discussion of how to load files of events (EVENTS^). There are many options to ld (LD^), including ones to suppress proofs and to control output.

The :otf-flg (OTF-FLG^) (Onward Thru the Fog FLaG) is a useful feature that Nqthm users have often wished for. It prevents the prover from aborting a proof attempt and inducting on the original conjecture. See Section 8.69 [OTF-FLG], page 353.

ACL2 supports redefinition and redundancy in events (EVENTS^); see Section 8.58 [LD-REDEFINITION-ACTION], page 336 and see Section 8.78 [REDUNDANT-EVENTS], page 361.

A proof-tree (PROOF-TREE^) display feature is available for use with Emacs. This feature provides a view of ACL2 proofs that can be much more useful than reading the stream of characters (CHARACTERS^) output by the theorem prover as its “proof.” See Chapter 12 [PROOF-TREE], page 617.

An interactive feature similar to Pc-Nqthm is supported in ACL2. See Section 11.101 [VERIFY], page 615 and see Chapter 11 [PROOF-CHECKER], page 553.

ACL2 allows you to monitor (MONITOR^) the use of rewrite (REWRITE^) rules. See Chapter 4 [BREAK-REWRITE], page 119.

See Section 8.6 [ARRAYS], page 241 to read about applicative, fast arrays (ARRAYS^) in ACL2.

To quit the ACL2 command (COMMAND^) loop, or (in akcl) to return to the ACL2 command (COMMAND^) loop after an interrupt, type :q (Q^). To continue (resume) after an interrupt (in akcl), type :r. To cause an interrupt (in akcl under Unix (trademark of AT&T)), hit control-C (twice, if inside Emacs). To exit ACL2 altogether, first type :q (Q^) to exit the ACL2 command (COMMAND^) loop, and then exit Lisp (by typing (user::bye) in akcl).

See Section 8.83 [STATE], page 368 to read about the von Neumannesque ACL2 state (STATE^) object. Also see Section 9.1 [@], page 409, and see Section 9.3 [ASSIGN], page 414, to learn about reading and setting global state (STATE^) variables.

1.4 TIPS

TIPS some hints for using the ACL2 prover

We present here some tips for using ACL2 effectively. Though this collection is somewhat ad hoc, we try to provide some organization, albeit somewhat artificial: for example, the sections overlap, and no particular order is intended. This material has been adapted by Bill Young from a very similar list for Nqthm that appeared in the conclusion of: “Interaction with the Boyer-Moore Theorem Prover: A Tutorial Study Using the Arithmetic-Geometric Mean Theorem,” by Matt Kaufmann and Paolo Pecchiari, CLI Technical Report 100, June, 1995. We also draw from a similar list in Chapter 13 of “A Computational Logic Handbook” by R.S. Boyer and J S. Moore (Academic Press, 1988). We’ll refer to this as “ACLH” below.

These tips are organized roughly as follows.

A. ACL2 Basics

B. Strategies for creating events

C. Dealing with failed proofs

D. Performance tips

E. Miscellaneous tips and knowledge

F. Some things you DON’T need to know

ACL2 BASICS

A1. The ACL2 logic.

This is a logic of total functions. For example, if A and B are less than or equal to each other, then we need to know something more in order to conclude that they are equal (e.g., that they are numbers). This kind of twist is important in writing definitions; for example, if you expect a function to return a number, you may want to apply the function fix (FIX^) or some variant (e.g., nfix (NFIX^) or ifix (IFIX^)) in case one of the formals is to be returned as the value.

ACL2’s notion of ordinals is important on occasion in supplying “measure hints (HINTS^)” for the acceptance of recursive definitions. Be sure that your measure is really an ordinal. Consider the following example, which ACL2 fails to admit (as explained below).

       (defun cnt (name a i x)
         (declare (xargs :measure (+ 1 i)))
         (cond ((zp (+ 1 i))

               ((equal x (aref1 name a i))
                (1+ (cnt name a (1- i) x)))
               (t (cnt name a (1- i) x))))

One might think that (+ 1 i) is a reasonable measure, since we know that (+ 1 i) is a positive integer in any recursive call of cnt, and positive integers are ACL2 ordinals (see Section 8.26 [E0-ORDINALP], page 283). However, the ACL2 logic requires that the measure be an ordinal unconditionally, not just under the governing assumptions that lead to recursive calls. An appropriate fix is to apply nfix (NFIX^) to (+ 1 i), i.e., to use

       (declare (xargs :measure (nfix (+ 1 i))))

in order to guarantee that the measure will always be an ordinal (in fact, a positive integer).

A2. Simplification.

The ACL2 simplifier is basically a rewriter, with some “linear (LINEAR^) arithmetic” thrown in. One needs to understand the notion of conditional rewriting. See Section 15.14 [REWRITE], page 764.

A3. Parsing of rewrite rules.

ACL2 parses rewrite (REWRITE^) rules roughly as explained in ACLH, except that it never creates “unusual” rule classes. In ACL2, if you want a :linear (LINEAR^) rule, for example, you must specify :linear (LINEAR^) in the :rule-classes (RULE-CLASSES^). See Chapter 15 [RULE-CLASSES], page 723, and also see Section 15.14 [REWRITE], page 764 and see Section 15.10 [LINEAR], page 749.

A4. Linear arithmetic.

On this subject, it should suffice to know that the prover can handle truths about + (+^) and - (-^), and that linear (LINEAR^) rules (see above) are somehow “thrown in the pot” when the prover is doing such reasoning. Perhaps it’s also useful to know that linear (LINEAR^) rules can have hypotheses, and that conditional rewriting is used to relieve those hypotheses.

A5. Events.

Over time, the expert ACL2 user will know some subtleties of its events (EVENTS^). For example, in-theory (IN-THEORY^) events (EVENTS^) and hints (HINTS^) are important, and they distinguish between a function and its executable counterpart.

B. STRATEGIES FOR CREATING EVENTS

In this section, we concentrate on the use of definitions and rewrite (REWRITE^) rules. There are quite a few kinds of rules allowed in ACL2 besides rewrite (REWRITE^) rules, though most beginning users probably won’t usually need to be aware of them. See Chapter 15 [RULE-CLASSES], page 723 for details. In particular, there is support for congruence (CONGRUENCE^) rewriting. Also see Section 16.10 [RUNE], page 784 (“RUle NamE”) for a description of the various kinds of rules in the system.

B1. Use high-level strategy.

Decompose theorems into “manageable” lemmas (admittedly, experience helps here) that yield the main result “easily.” It’s important to be able to outline non-trivial proofs by hand (or in your head). In particular, avoid submitting goals to the prover when there’s no reason to believe that the goal will be proved and there’s no “sense” of how an induction argument would apply. It is often a good idea to avoid induction in complicated theorems unless you have a reason to believe that it is appropriate.

B2. Write elegant definitions.

Try to write definitions in a reasonably modular style, especially recursive ones. Think of ACL2 as a programming (PROGRAMMING^) language whose procedures are definitions and lemmas, hence we are really suggesting that one follow good programming (PROGRAMMING^) style (in order to avoid duplication of “code,” for example).

When possible, complex functions are best written as compositions of simpler functions. The theorem prover generally performs better on primitive recursive functions than on more complicated recursions (such as those using accumulating parameters).

Avoid large non-recursive definitions which tend to lead to large case explosions. If such definitions are necessary, try to prove all relevant facts about the definitions and then disable (DISABLE^) them.

Whenever possible, avoid mutual recursion if you care to prove anything about your functions. The induction heuristics provide essentially no help with reasoning about mutually defined functions. Mutually recursive functions can usually be combined into a single function with a “flag” argument. (However, see Section 1.5.6.3 [MUTUAL-RECURSION-PROOF-EXAMPLE], page 66 for a small example of proof involving mutually recursive functions.)

B3. Look for analogies.

Sometimes you can easily edit sequences of lemmas into sequences of lemmas about analogous functions.

B4. Write useful rewrite rules.

As explained in A3 above, every rewrite (REWRITE^) rule is a directive to the theorem prover, usually to replace one term (TERM^) by another. The directive generated is determined by the syntax of the defthm (DEFTHM^) submitted. Never submit a rewrite (REWRITE^) rule unless you have considered its interpretation as a proof directive.

B4a. Rewrite rules should simplify.

Try to write rewrite (REWRITE^) rules whose right-hand sides are in some sense “simpler than” (or at worst, are variants of) the left-hand sides. This will help to avoid infinite loops in the rewriter.

B4b. Avoid needlessly expensive rules.

Consider a rule whose conclusion’s left-hand side (or, the entire conclusion) is a term (TERM^) such as (consp x) that matches many term (TERM^)s encountered by the prover. If in addition the rule has complicated hypotheses, this rule could slow down the prover greatly. Consider switching the conclusion and a complicated hypothesis (negating each) in that case.

B4c. The “Knuth-Bendix problem”.

Be aware that left sides of rewrite (REWRITE^) rules should match the “normalized forms”, where “normalization” (rewriting) is inside out. Be sure to avoid the use of nonrecursive function symbols on left sides of rewrite (REWRITE^) rules, except when those function symbols are disable (DISABLE^)d, because they tend to be expanded away before the rewriter would encounter an instance of the left side of the rule. Also assure that subexpressions on the left hand side of a rule are in simplified form.

B4d. Avoid proving useless rules.

Sometimes it’s tempting to prove a rewrite (REWRITE^) rule even before you see how it might find application. If the rule seems clean and important, and not unduly expensive, that’s probably fine, especially if it’s not too hard to prove. But unless it’s either part of the high-level strategy or, on the other hand, intended to get the prover past a particular unproved goal, it may simply waste your time to prove the rule, and then clutter the database of rules if you are successful.

B4e. State rules as strongly as possible, usually.

It’s usually a good idea to state a rule in the strongest way possible, both by eliminating unnecessary hypotheses and by generalizing subexpressions to variables.

Advanced users may choose to violate this policy on occasion, for example in order to avoid slowing down the prover by excessive attempted application of the rule. However, it’s a good rule of thumb to make the strongest rule possible, not only because it will then apply more often, but also because the rule will often be easier to prove (see also B6 below). New users are sometimes tempted to put in extra hypotheses that have a “type restriction” appearance, without realizing that the way ACL2 handles (total) functions generally lets it handle trivial cases easily.

B4f. Avoid circularity.

A stack overflow in a proof attempt almost always results from circular rewriting. Use brr (BRR^) to investigate the stack; see Section 4.1 [BREAK-LEMMA], page 124. Because of the complex heuristics, it is not always easy to define just when a rewrite (REWRITE^) will cause circularity. See the very good discussion of this topic in ACLH.

See Section 4.1 [BREAK-LEMMA], page 124 for a trick involving use of the forms brr t and (cw-gstack *deep-gstack* state) for inspecting loops in the rewriter.

B4g. Remember restrictions on permutative rules.

Any rule that permutes the variables in its left hand side could cause circularity. For example, the following axiom is automatically supplied by the system:

       (defaxiom commutativity-of-+
                 (equal (+ x y) (+ y x))).

This would obviously lead to dangerous circular rewriting if such “permutative” rules were not governed by a further restriction. The restriction is that such rules will not produce a term (TERM^) that is “lexicographically larger than” the original term (TERM^) (see Section 8.64 [LOOP-STOPPER], page 347). However, this sometimes prevents intended rewrites. See Chapter 13 of ACLH for a discussion of this problem.

B5. Conditional vs. unconditional rewrite rules.

It’s generally preferable to form unconditional rewrite (REWRITE^) rules unless there is a danger of case explosion. That is, rather than pairs of rules such as

     (implies p
              (equal term1 term2))

and

     (implies (not p)
              (equal term1 term3))

consider:

     (equal term1
            (if p term2 term3))

However, sometimes this strategy can lead to case explosions: IF (IF^) term (TERM^)s introduce cases in ACL2. Use your judgment. (On the subject of IF (IF^): COND (COND^), CASE (CASE^), AND (AND^), and OR (OR^) are macros that abbreviate IF (IF^) forms, and propositional functions such as IMPLIES (IMPLIES^) quickly expand into IF (IF^) term (TERM^)s.)

B6. Create elegant theorems.

Try to formulate lemmas that are as simple and general as possible. For example, sometimes properties about several functions can be “factored” into lemmas about one function at a time. Sometimes the elimination of unnecessary hypotheses makes the theorem easier to prove, as does generalizing first by hand.

B7. Use defaxiom (DEFAXIOM^)s temporarily to explore possibilities.

When there is a difficult goal that seems to follow immediately (by a :use hint or by rewriting) from some other lemmas, you can create those lemmas as defaxiom (DEFAXIOM^) events (EVENTS^) (or, the application of skip-proofs (SKIP-PROOFS^) to defthm (DEFTHM^) events (EVENTS^)) and then double-check that the difficult goal really does follow from them. Then you can go back and try to turn each defaxiom (DEFAXIOM^) into a defthm (DEFTHM^). When you do that, it’s often useful to disable (DISABLE^) any additional rewrite (REWRITE^) rules that you prove in the process, so that the “difficult goal” will still be proved from its lemmas when the process is complete.

Better yet, rather than disabling rewrite (REWRITE^) rules, use the local (LOCAL^) mechanism offered by encapsulate (ENCAPSULATE^) to make temporary rules completely local (LOCAL^) to the problem at hand. See Section 6.18 [ENCAPSULATE], page 185 and see Section 6.21 [LO-CAL], page 191.

B9. Use books.

Consider using previously certified books (BOOKS^), especially for arithmetic reasoning. This cuts down the duplication of effort and starts your specification and proof effort from a richer foundation.

See the file "doc/README" in the ACL2 distribution for information on books (BOOKS^) that come with the system.

C. DEALING WITH FAILED PROOFS

C1. Look in proof output for goals that can’t be further simplified.

Use the “proof-tree (PROOF-TREE^)” utility to explore the proof space. However, you don’t need to use that tool to use the “checkpoint” strategy. The idea is to think of ACL2 as a “simplifier” that either proves the theorem or generates some goal to consider. That goal is the first “checkpoint,” i.e., the first goal that does not further simplify. Exception: it’s also important to look at the induction scheme in a proof by induction, and if induction seems appropriate, then look at the first checkpoint after the induction has begun.

Consider whether the goal on which you focus is even a theorem. Sometimes you can execute it for particular values to find a counterexample.

When looking at checkpoints, remember that you are looking for any reason at all to believe the goal is a theorem. So for example, sometimes there may be a contradiction in the hypotheses.

Don’t be afraid to skip the first checkpoint if it doesn’t seem very helpful. Also, be willing to look a few lines up or down from the checkpoint if you are stuck, bearing in mind however that this practice can be more distracting than helpful.

C2. Use the “break rewrite” facility.

Brr (BRR^) and related utilities let you inspect the “rewrite stack.” These can be valuable tools in large proof efforts. See Section 4.1 [BREAK-LEMMA], page 124 for an introduction to these tools, and see Chapter 4 [BREAK-REWRITE], page 119 for more complete information.

The break facility is especially helpful in showing you why a particular rewrite rule is not being applied.

C3. Use induction hints when necessary. Of course, if you can define your functions so that they suggest the correct inductions to ACL2, so much the better! But for complicated inductions, induction hints (HINTS^) are crucial. See Section 8.43 [HINTS], page 319 for a description of :induct hints (HINTS^).

C4. Use the “Proof Checker” to explore.

The verify (VERIFY^) command supplied by ACL2 allows one to explore problem areas “by hand.” However, even if you succeed in proving a conjecture with verify (VERIFY^), it is useful to prove it without using it, an activity that will often require the discovery of rewrite (REWRITE^) rules that will be useful in later proofs as well.

C5. Don’t have too much patience.

Interrupt the prover fairly quickly when simplification isn’t succeeding.

C6. Simplify rewrite rules.

When it looks difficult to relieve the hypotheses of an existing rewrite (REWRITE^) rule that “should” apply in a given setting, ask yourself if you can eliminate a hypothesis from the existing rewrite (REWRITE^) rule. If so, it may be easier to prove the new version from the old version (and some additional lemmas), rather than to start from scratch.

C7. Deal with base cases first.

Try getting past the base case(s) first in a difficult proof by induction. Usually they’re easier than the inductive step(s), and rules developed in proving them can be useful in the inductive step(s) too. Moreover, it’s pretty common that mistakes in the statement of a theorem show up in the base case(s) of its proof by induction.

C8. Use :expand hints. Consider giving :expand hints (HINTS^). These are especially useful when a proof by induction is failing. It’s almost always helpful to open up a recursively defined function that is supplying the induction scheme, but sometimes ACL2 is too timid to do so; or perhaps the function in question is disable (DISABLE^)d.

D. PERFORMANCE TIPS D1. Disable rules.

There are a number of instances when it is crucial to disable (DISABLE^) rules, including (often) those named explicitly in :use hints (HINTS^). Also, disable (DISABLE^) recursively defined functions for which you can prove what seem to be all the relevant properties. The prover can spend significant time “behind the scenes” trying to open up recursively defined functions, where the only visible effect is slowness.

D2. Turn off the “break rewrite” facility. Remember to execute :brr nil after you’ve finished with the “break rewrite” utility (see Chapter 4 [BREAK-REWRITE], page 119), in order to bring the prover back up to full speed.

E. MISCELLANEOUS TIPS AND KNOWLEDGE

E1. Order of application of rewrite rules.

Keep in mind that the most recent rewrite (REWRITE^) rules in the history (HISTORY^) are tried first.

E2. Relieving hypotheses is not full-blown theorem proving.

Relieving hypotheses on rewrite (REWRITE^) rules is done by rewriting and linear (LINEAR^) arithmetic alone, not by case splitting or by other prover processes “below” simplification.

E3. “Free variables” in rewrite rules. The set of “free variables” of a rewrite (REWRITE^) rule is defined to contain those variables occurring in the rule that do not occur in the left-hand side of the rule. It’s often a good idea to avoid rules containing free variables because they are “weak,” in the sense that hypotheses containing such variables can generally only be proved when they are “obviously” present in the current context. This weakness suggests that it’s important to put the most “interesting” (specific) hypotheses about free variables first, so that the right instances are considered. For example, suppose you put a very general hypothesis such as (consp x) first. If the context has several term (TERM^)s around that are known to be consp (CONSP^)s, then x may be bound to the wrong one of them.

E4. Obtaining information Use :pl (PL^) foo to inspect rewrite (REWRITE^) rules whose left hand sides are applications of the function foo. Another approach to seeing which rewrite (REWRITE^) rules apply is to enter the proof-checker (PROOF-CHECKER^) with verify (VER-IFY^), and use the show-rewrites or sr command.

E5. Consider esoteric rules with care.

If you care to see Chapter 15 [RULE-CLASSES], page 723 and peruse the list of subtopics (which will be listed right there in most versions of this documentation (DOCUMENTATION^)), you’ll see that ACL2 supports a wide variety of rules in addition to :rewrite (REWRITE^) rules. Should you use them? This is a complex question that we are not ready to answer with any generality. Our general advice is to avoid relying on such rules as long as you doubt their utility. More specifically: be careful not to use conditional type prescription rules, as these have been known to bring ACL2 to its knees, unless you are conscious that you are doing so and have reason to believe that they are working well.

F. SOME THINGS YOU DON’T NEED TO KNOW

Most generally: you shouldn’t usually need to be able to predict too much about ACL2’s behavior. You should mainly just need to be able to react to it.

F1. Induction heuristics.

Although it is often important to read the part of the prover’s output that gives the induction scheme chosen by the prover, it is not necessary to understand how the prover made that choice. (Granted, advanced users may occasionally gain minor insight from such knowledge. But it’s truly minor in many cases.) What is important is to be able to tell it an appropriate induction when it doesn’t pick the right one (after noticing that it doesn’t). See C3 above.

F2. Heuristics for expanding calls of recursively defined functions.

As with the previous topic, the important thing isn’t to understand these heuristics but, rather, to deal with cases where they don’t seem to be working. That amounts to supplying :expand hints (HINTS^) for those calls that you want opened up, which aren’t. See also C8 above.

F3. The “waterfall”.

As discussed many times already, a good strategy for using ACL2 is to look for checkpoints (goals stable under simplification) when a proof fails, perhaps using the proof-tree (PROOF-TREE^) facility. Thus, it is reasonable to ignore almost all the prover output, and to avoid pondering the meaning of the other “processes” that ACL2 uses besides simplification (such as elimination, crossfertilization, generalization, and elimination of irrelevance). For example, you don’t need to worry about prover output that mentions “type reasoning” or “abbreviations,” for example.

1.5 TUTORIAL-EXAMPLES

TUTORIAL-EXAMPLES examples of ACL2 usage

Beginning users may find these examples at least as useful as the extensive documentation (DOC-UMENTATION^) on particular topics. We suggest that you read these in the following order:

Tutorial1-Towers-of-Hanoi (TUTORIAL1-TOWERS-OF-HANOI^) Tutorial2-Eights-Problem (TUTORIAL2-EIGHTS-PROBLEM^) Tutorial3-Phonebook-Example (TUTORIAL3-PHONEBOOK-EXAMPLE^) Tutorial4-Defun-Sk-Example (TUTORIAL4-DEFUN-SK-EXAMPLE^) Tutorial5-Miscellaneous-Examples (TUTORIAL5-MISCELLANEOUS-EXAMPLES^)

You may also wish to visit the other introductory sections, startup (STARTUP^) and tidbits (TIDBITS^). These contain further information related to the use of ACL2.

* SOLUTION-TO-SIMPLE-EXAMPLE:: solution to a simple example

* TUTORIAL1-TOWERS-OF-HANOI:: The Towers of Hanoi Example

* TUTORIAL2-EIGHTS-PROBLEM:: The Eights Problem Example

* TUTORIAL3-PHONEBOOK-EXAMPLE:: A Phonebook Specification

* TUTORIAL4-DEFUN-SK-EXAMPLE:: example of quantified notions

* TUTORIAL5-MISCELLANEOUS-EXAMPLES:: miscellaneous ACL2 examples

When you feel you have read enough examples, you might want to try the following very simple example on your own. First define the notion of the “fringe” of a tree, where we identify trees simply as cons (CONS^) structures, with atom (ATOM^)s at the leaves. For example:

       ACL2 !>(fringe '((a . b) c . d))
       (A B C D)

Next, define the notion of a “leaf” of a tree, i.e., a predicate leaf-p that is true of an atom if and only if that atom appears at the tip of the tree. Define this notion without referencing the function fringe. Finally, prove the following theorem, whose proof may well be automatic (i.e., not require any lemmas).

       (defthm leaf-p-iff-member-fringe
         (iff (leaf-p atm x)
              (member-equal atm (fringe x))))

For a solution, see Section 1.5.1 [SOLUTION-TO-SIMPLE-EXAMPLE], page 32.

1.5.1 SOLUTION-TO-SIMPLE-EXAMPLE

SOLUTION-TO-SIMPLE-EXAMPLE solution to a simple example

To see a statement of the problem solved below, see Section 1.5 [TUTORIAL-EXAMPLES], page 31.

Here is a sequence of ACL2 events (EVENTS^) that illustrates the use of ACL2 to make definitions and prove theorems. We will introduce the notion of the fringe of a tree, as well as the notion of a leaf of a tree, and then prove that the members of the fringe are exactly the leaves.

We begin by defining the fringe of a tree, where we identify trees simply as cons (CONS^) structures, with atom (ATOM^)s at the leaves. The definition is recursive, breaking into two cases. If x is a cons (CONS^), then the fringe of x is obtained by appending together the fringes of the car (CAR^) and cdr (CDR^) (left and right child) of x. Otherwise, x is an atom (ATOM^) and its fringe is the one-element list containing only x.

       (defun fringe (x)
         (if (consp x)
             (append (fringe (car x))
                     (fringe (cdr x)))
           (list x)))

Now that fringe has been defined, let us proceed by defining the notion of an atom appearing as a “leaf”, with the goal of proving that the leaves of a tree are exactly the members of its fringe.

       (defun leaf-p (atm x)
         (if (consp x)
             (or (leaf-p atm (car x))
                 (leaf-p atm (cdr x)))
           (equal atm x)))

The main theorem is now as follows. Note that the rewrite rule below uses the equivalence relation iff (IFF^) (see Section 15.6 [EQUIVALENCE], page 738) rather than equal (EQUAL^), since member (MEMBER^) returns the tail of the given list that begins with the indicated member, rather than returning a Boolean. (Use :pe member to see the definition of member (MEMBER^).)

       (defthm leaf-p-iff-member-fringe
         (iff (leaf-p atm x)
              (member-equal atm (fringe x))))

1.5.2 TUTORIAL1-TOWERS-OF-HANOI

TUTORIAL1-TOWERS-OF-HANOI The Towers of Hanoi Example

This example was written almost entirely by Bill Young of Computational Logic, Inc.

We will tackle the famous “Towers of Hanoi” problem. This problem is illustrated by the following picture.

               |        |        |
               |        |        |
              ---       |        |
             -----      |        |
            -------     |        |
               A        B        C

We have three pegs — a, b, and c — and n disks of different sizes. The disks are all initially on peg a. The goal is to move all disks to peg c while observing the following two rules.

1. Only one disk may be moved at a time, and it must start and finish the move as the topmost disk on some peg;

2. A disk can never be placed on top of a smaller disk.

Let’s consider some simple instances of this problem. If n = 1, i.e., only one disk is to be moved, simply move it from a to c. If n = 2, i.e., two disks are to be moved, the following sequence of moves suffices: move from a to b, move from a to c, move from b to c.

In general, this problem has a straightforward recursive solution. Suppose that we desire to move n disks from a to c, using b as the intermediate peg. For the basis, we saw above that we can always move a single disk from a to c. Now if we have n disks and assume that we can solve the problem for n-1 disks, we can move n disks as follows. First, move n-1 disks from a to b using c as the intermediate peg; move the single disk from a to c; then move n-1 disks from b to c using a as the intermediate peg.

In ACL2, we can write a function that will return the sequence of moves. One such function is as follows. Notice that we have two base cases. If (zp n) then n is not a positive integer; we treat that case as if n were 0 and return an empty list of moves. If n is 1, then we return a list containing the single appropriate move. Otherwise, we return the list containing exactly the moves dictated by our recursive analysis above.

       (defun move (a b)
         (list 'move a 'to b))
       (defun hanoi (a b c n)
         (if (zp n)
             nil
           (if (equal n 1)
               (list (move a c))
             (append (hanoi a c b (1- n))
                     (cons (move a c)
                           (hanoi b a c (1- n)))))))

Notice that we give hanoi four arguments: the three pegs, and the number of disks to move. It is necessary to supply the pegs because, in recursive calls, the roles of the pegs differ. In any execution of the algorithm, a given peg will sometimes be the source of a move, sometimes the destination, and sometimes the intermediate peg.

After submitting these functions to ACL2, we can execute the hanoi function on various specific arguments. For example:

       ACL2 !>(hanoi 'a 'b 'c 1)
       ((MOVE A TO C))
       ACL2 !>(hanoi 'a 'b 'c 2)
       ((MOVE A TO B)
        (MOVE A TO C)
        (MOVE B TO C))
       ACL2 !>(hanoi 'a 'b 'c 3)
       ((MOVE A TO C)
        (MOVE A TO B)
        (MOVE C TO B)
        (MOVE A TO C)
        (MOVE B TO A)
        (MOVE B TO C)
        (MOVE A TO C))

From the algorithm it is clear that if it takes m moves to transfer n disks, it will take (m + 1 + m) = 2m + 1 moves for n+1 disks. From some simple calculations, we see that we need the following number of moves in specific cases:

        Disks   0   1   2   3   4   5   6   7  ...
        Moves   0   1   3   7  15  31  63  127 ...

The pattern is fairly clear. To move n disks requires (2^n - 1) moves. Let’s attempt to use ACL2 to prove that fact.

First of all, how do we state our conjecture? Recall that hanoi returns a list of moves. The length of the list (given by the function len) is the number of moves required. Thus, we can state the following conjecture.

       (defthm hanoi-moves-required-first-try

         (equal (len (hanoi a b c n))
                (1- (expt 2 n))))

When we submit this to ACL2, the proof attempt fails. Along the way we notice subgoals such as:

       Subgoal *1/1'
       (IMPLIES (NOT (< 0 N))
                (EQUAL 0 (+ -1 (EXPT 2 N)))).

This tells us that the prover is considering cases that are uninteresting to us, namely, cases in which n might be negative. The only cases that are really of interest are those in which n is a non-negative natural number. Therefore, we revise our theorem as follows:

       (defthm hanoi-moves-required
         (implies (and (integerp n)
                       (<= 0 n))    ;; n is at least 0
                  (equal (len (hanoi a b c n))
                         (1- (expt 2 n)))))

and submit it to ACL2 again.

Again the proof fails. Examining the proof script we encounter the following text. (How did we decide to focus on this goal? Some information is provided in ACLH, and the ACL2 documentation on tips (TIPS^) may be helpful. But the simplest answer is: this was the first goal suggested by the “proof-tree (PROOF-TREE^)” tool below the start of the proof by induction. See Chapter 12 [PROOF-TREE], page 617.)

       Subgoal *1/5''
       (IMPLIES (AND (INTEGERP N)
                     (< 0 N)
                     (NOT (EQUAL N 1))
                     (EQUAL (LEN (HANOI A C B (+ -1 N)))
                            (+ -1 (EXPT 2 (+ -1 N))))
                     (EQUAL (LEN (HANOI B A C (+ -1 N)))
                            (+ -1 (EXPT 2 (+ -1 N)))))
                (EQUAL (LEN (APPEND (HANOI A C B (+ -1 N))
                                    (CONS (LIST 'MOVE A 'TO C)

                                          (HANOI B A C (+ -1 N)))))
                       (+ -1 (* 2 (EXPT 2 (+ -1 N))))))

It is difficult to make much sense of such a complicated goal. However, we do notice something interesting. In the conclusion is a term (TERM^) of the following shape.

        (LEN (APPEND ... ...))

We conjecture that the length of the append (APPEND^) of two lists should be the sum of the lengths of the lists. If the prover knew that, it could possibly have simplified this term (TERM^) earlier and made more progress in the proof. Therefore, we need a rewrite (REWRITE^) rule that will suggest such a simplification to the prover. The appropriate rule is:

       (defthm len-append
         (equal (len (append x y))
                (+ (len x) (len y))))

We submit this to the prover, which proves it by a straightforward induction. The prover stores this lemma as a rewrite (REWRITE^) rule and will subsequently (unless we disable (DISABLE^) the rule) replace term (TERM^)s matching the left hand side of the rule with the appropriate instance of the term (TERM^) on the right hand side.

We now resubmit our lemma hanoi-moves-required to ACL2. On this attempt, the proof succeeds and we are done.

One bit of cleaning up is useful. We needed the hypotheses that:

       (and (integerp n) (<= 0 n)).

This is an awkward way of saying that n is a natural number; natural is not a primitive data type in ACL2. We could define a function naturalp, but it is somewhat more convenient to define a macro as follows:

       (defmacro naturalp (x)
         (list 'and (list 'integerp x)
                       (list '<= 0 x)))

Subsequently, we can use (naturalp n) wherever we need to note that a quantity is a natural number. See Section 6.10 [DEFMACRO], page 171 for more information about ACL2 macros. With this macro, we can reformulate our theorem as follows:

       (defthm hanoi-moves-required
         (implies (naturalp n)
                  (equal (len (hanoi a b c n))
                         (1- (expt 2 n))))).

Another interesting (but much harder) theorem asserts that the list of moves generated by our hanoi function actually accomplishes the desired goal while following the rules. When you can state and prove that theorem, you’ll be a very competent ACL2 user.

By the way, the name “Towers of Hanoi” derives from a legend that a group of Vietnamese monks works day and night to move a stack of 64 gold disks from one diamond peg to another, following the rules set out above. We’re told that the world will end when they complete this task. From the theorem above, we know that this requires 18,446,744,073,709,551,615 moves:

       ACL2 !>(1- (expt 2 64))
       18446744073709551615
       ACL2 !>

We’re guessing they won’t finish any time soon.

1.5.3 TUTORIAL2-EIGHTS-PROBLEM

TUTORIAL2-EIGHTS-PROBLEM The Eights Problem Example

This example was written almost entirely by Bill Young of Computational Logic, Inc.

This simple example was brought to our attention as one that Paul Jackson has solved using the NuPrl system. The challenge is to prove the theorem:

       for all n > 7, there exist naturals i and j such that: n = 3i + 5j.

In ACL2, we could phrase this theorem using quantification. However we will start with a constructive approach, i.e., we will show that values of i and j exist by writing a function that will construct such values for given n. Suppose we had a function (split n) that returns an appropriate pair (i . j). Our theorem would be as follows:

       (defthm split-splits
         (let ((i (car (split n)))
               (j (cdr (split n))))
           (implies (and (integerp n)
                         (< 7 n))
                    (and (integerp i)
                         (<= 0 i)
                         (integerp j)
                         (<= 0 j)
                         (equal (+ (* 3 i) (* 5 j))
                                n)))))

That is, assuming that n is a natural number greater than 7, (split n) returns values i and j that are in the appropriate relation to n.

Let’s look at a few cases:

       8 = 3x1 + 5x1;    11 = 3x2 + 5x1;     14 = 3x3 + 5x1;   ...
       9 = 3x3 + 5x0;    12 = 3x4 + 5x0;     15 = 3x5 + 5x0;   ...
      10 = 3x0 + 5x2;    13 = 3x1 + 5x2;     16 = 3x2 + 5x2;   ...

Maybe you will have observed a pattern here; any natural number larger than 10 can be obtained by adding some multiple of 3 to 8, 9, or 10. This gives us the clue to constructing a proof. It is clear that we can write split as follows:

       (defun bump-i (x)

         ;; Bump the i component of the pair
         ;; (i . j) by 1.
         (cons (1+ (car x)) (cdr x)))
       (defun split (n)
         ;; Find a pair (i . j) such that
         ;; n = 3i + 5j.
         (if (or (zp n) (< n 8))
             nil ;; any value is really reasonable here
           (if (equal n 8)
               (cons 1 1)
             (if (equal n 9)
                 (cons 3 0)
               (if (equal n 10)
                   (cons 0 2)
                 (bump-i (split (- n 3))))))))

Notice that we explicitly compute the values of i and j for the cases of 8, 9, and 10, and for the degenerate case when n is not a natural or is less than 8. For all naturals greater than n, we decrement n by 3 and bump the number of 3’s (the value of i) by 1. We know that the recursion must terminate because any integer value greater than 10 can eventually be reduced to 8, 9, or 10 by successively subtracting 3.

Let’s try it on some examples:

       ACL2 !>(split 28)
       (6 . 2)
       ACL2 !>(split 45)
       (15 . 0)
       ACL2 !>(split 335)
       (110 . 1)

Finally, we submit our theorem split-splits, and the proof succeeds. In this case, the prover is “smart” enough to induct according to the pattern indicated by the function split.

For completeness, we’ll note that we can state and prove a quantified version of this theorem. We introduce the notion split-able to mean that appropriate i and j exist for n.

       (defun-sk split-able (n)
         (exists (i j)
                 (equal n (+ (* 3 i) (* 5 j)))))

Then our theorem is given below. Notice that we prove it by observing that our previous function split delivers just such an i and j (as we proved above).

       (defthm split-splits2
         (implies (and (integerp n)
                       (< 7 n))
                  (split-able n))
         :hints (("Goal" :use (:instance split-able-suff
                                         (i (car (split n)))
                                         (j (cdr (split n)))))))

Unfortunately, understanding the mechanics of the proof requires knowing something about the way defun-sk (DEFUN-SK^) works. See Section 6.17 [DEFUN-SK], page 182 or see Section 1.5.5 [TUTORIAL4-DEFUN-SK-EXAMPLE], page 57 for more on that subject.

1.5.4 TUTORIAL3-PHONEBOOK-EXAMPLE

TUTORIAL3-PHONEBOOK-EXAMPLE A Phonebook Specification

The other tutorial examples are rather small and entirely self contained. The present example is rather more elaborate, and makes use of a feature that really adds great power and versatility to ACL2, namely: the use of previously defined collections of lemmas, in the form of “books (BOOKS^).”

This example was written almost entirely by Bill Young of Computational Logic, Inc.

This example is based on one developed by Ricky Butler and Sally Johnson of NASA Langley for the PVS system, and subsequently revised by Judy Crow, et al, at SRI. It is a simple phone book specification. We will not bother to follow their versions closely, but will instead present a style of specification natural for ACL2.

The idea is to model an electronic phone book with the following properties.

Our phone book will store the phone numbers of a city.

It must be possible to retrieve a phone number, given a name.

It must be possible to add and delete entries.

Of course, there are numerous ways to construct such a model. A natural approach within the Lisp/ACL2 context is to use “association lists” or “alists.” Briefly, an alist is a list of pairs (key . value) associating a value with a key. A phone book could be an alist of pairs (name . pnum). To find the phone number associated with a given name, we merely search the alist until we find the appropriate pair. For a large city, such a linear list would not be efficient, but at this point we are interested only in modeling the problem, not in deriving an efficient implementation. We could address that question later by proving our alist model equivalent, in some desired sense, to a more efficient data structure.

We could build a theory of alists from scratch, or we can use a previously constructed theory (book) of alist definitions and facts. By using an existing book, we build upon the work of others, start our specification and proof effort from a much richer foundation, and hopefully devote more of our time to the problem at hand. Unfortunately, it is not completely simple for the new user to know what books (BOOKS^) are available and what they contain. We hope later to improve the documentation of the growing collection of books (BOOKS^) available with the ACL2 distribution; for now, the reader is encouraged to look in the README file in the books subdirectory. For present purposes, the beginning user can simply take our word that a book exists containing useful alist definitions and facts. On our local machine, these definitions and lemmas can be introduced into the current theory using the command (COMMAND^):

       (include-book "/slocal/src/acl2/v1-9/books/public/alist-defthms")

This book has been “certified,” which means that the definitions and lemmas have been mechanically checked and stored in a safe manner. (See Chapter 3 [BOOKS], page 93 and see Section 6.20 [INCLUDE-BOOK], page 189 for details.)

Including this book makes available a collection of functions including the following:

     (ALISTP A)    ; is A an alist (actually a primitive ACL2 function)
     (BIND X V A)  ; associate the key X with value V in alist A

     (BINDING X A) ; return the value associated with key X in alist A
     (BOUND? X A)  ; is key X associated with any value in alist A
     (DOMAIN A)    ; return the list of keys bound in alist A
     (RANGE A)     ; return the list of values bound to keys in alist A
     (REMBIND X A) ; remove the binding of key X in alist A

Along with these function definitions, the book also provides a number of proved lemmas that aid in simplifying expressions involving these functions. (See Chapter 15 [RULE-CLASSES], page 723 for the way in which lemmas are used in simplification and rewriting.) For example,

       (defthm bound?-bind
         (equal (bound? x (bind y v a))
                (or (equal x y)
                    (bound? x a))))

asserts that x will be bound in (bind y v a) if and only if: either x = y or x was already bound in a. Also,

       (defthm binding-bind
         (equal (binding x (bind y v a))
                (if (equal x y)
                    v
                  (binding x a))))

asserts that the resulting binding will be v, if x = y, or the binding that x had in a already, if not.

Thus, the inclusion of this book essentially extends our specification and reasoning capabilities by the addition of new operations and facts about these operations that allow us to build further specifications on a richer and possibly more intuitive foundation.

However, it must be admitted that the use of a book such as this has two potential limitations:

the definitions available in a book may not be ideal for your particular problem; it is (extremely) likely that some useful facts (especially, rewrite (REWRITE^) rules) are not available in the book and will have to be proved.

For example, what is the value of binding when given a key that is not bound in the alist? We can find out by examining the function definition. Look at the definition of the binding function (or any other defined function), using the :pe (PE^) command:

       ACL2 !>:pe binding
          d     33  (INCLUDE-BOOK
                         "/slocal/src/acl2/v1-9/books/public/alist-defthms")
       >V d          (DEFUN BINDING (X A)
                            "The value bound to X in alist A."
                            (DECLARE (XARGS :GUARD (ALISTP A)))
                            (CDR (ASSOC-EQUAL X A)))

This tells us that binding was introduced by the given include-book (INCLUDE-BOOK^) form, is currently disable (DISABLE^)d in the current theory, and has the definition given by the displayed defun (DEFUN^) form. We see that binding is actually defined in terms of the primitive assoc-equal (ASSOC-EQUAL^) function. If we look at the definition of assoc-equal (ASSOC-EQUAL^):

       ACL2 !>:pe assoc-equal
        V     -489  (DEFUN ASSOC-EQUAL (X ALIST)
                           (DECLARE (XARGS :GUARD (ALISTP ALIST)))
                           (COND ((ENDP ALIST) NIL)
                                 ((EQUAL X (CAR (CAR ALIST)))
                                  (CAR ALIST))
                                 (T (ASSOC-EQUAL X (CDR ALIST)))))

we can see that assoc-equal (ASSOC-EQUAL^) returns nil upon reaching the end of an unsuccessful search down the alist. So binding returns (cdr nil) in that case, which is nil. Notice that we could also have investigated this question by trying some simple examples.

       ACL2 !>(binding 'a nil)
       NIL
       ACL2 !>(binding 'a (list (cons 'b 2)))
       NIL

These definitions aren’t ideal for all purposes. For one thing, there’s nothing that keeps us from having nil as a value bound to some key in the alist. Thus, if binding returns nil we don’t always know if that is the value associated with the key in the alist, or if that key is not bound. We’ll have to keep that ambiguity in mind whenever we use binding in our specification. Suppose instead that we wanted binding to return some error string on unbound keys. Well, then we’d just have to write our own version of binding. But then we’d lose much of the value of using a previously defined book. As with any specification technique, certain tradeoffs are necessary.

Why not take a look at the definitions of other alist functions and see how they work together to provide the ability to construct and search alists? We’ll be using them rather heavily in what follows so it will be good if you understand basically how they work. Simply start up ACL2 and execute the form shown earlier, but substituting our directory name for the top-level ACL2 directory with yours. Alternatively, the following should work if you start up ACL2 in the directory of the ACL2 sources:

       (include-book (:relative "books" "public" "alist-defthms"))

Then, you can use :pe (PE^) to look at function definitions. You’ll soon discover that almost all of the definitions are built on definitions of other, more primitive functions, as binding is built on assoc-equal (ASSOC-EQUAL^). You can look at those as well, of course, or in many cases visit their documentation.

The other problem with using a predefined book is that it will seldom be “sufficiently complete,” in the sense that the collection of rewrite (REWRITE^) rules supplied won’t be adequate to prove everything we’d like to know about the interactions of the various functions. If it were, there’d be no real reason to know that binding is built on top of assoc-equal (ASSOC-EQUAL^), because everything we’d need to know about binding would be nicely expressed in the collection of theorems supplied with the book. However, that’s very seldom the case. Developing such a collection of rules is currently more art than science and requires considerable experience. We’ll encounter examples later of “missing” facts about binding and our other alist functions. So, let’s get on with the example.

Notice that alists are mappings of keys to values; but, there is no notion of a “type” associated with the keys or with the values. Our phone book example, however, does have such a notion of types; we map names to phone numbers. We can introduce these “types” by explicitly defining them, e.g., names are strings and phone numbers are integers. Alternatively, we can partially define or axiomatize a recognizer for names without giving a full definition. A way to safely introduce such “constrained” function symbols in ACL2 is with the encapsulate (ENCAPSULATE^) form. For example, consider the following form.

       (encapsulate
         ;; Introduce a recognizer for names with a ``type'' lemma.
         ((namep (x) t))
         ;;
         (local (defun namep (x)
                  ;; This declare is needed to tell
                  ;; ACL2 that we're aware that the
                  ;; argument x is not used in the body
                  ;; of the function.
                  (declare (ignore x))
                  t))
         ;;
         (defthm namep-booleanp
           (booleanp (namep x))))

This encapsulate (ENCAPSULATE^) form introduces the new function namep of one argument and one result and constrains (namep x) to be Boolean, for all inputs x. More generally, an encapsulation establishes an environment in which functions can be defined and theorems and rules added without necessarily introducing those functions, theorems, and rules into the environment outside the encapsulation. To be admissible, all the events in the body of an encapsulate must be admissible. But the effect of an encapsulate is to assume only the non-local events.

The first “argument” to encapsulate, ((namep (x) t)) above, declares the intended signature (SIGNATURE^)s of new function symbols that will be “exported” from the encapsulation without definition. The local (LOCAL^) defun (DEFUN^) of name defines name within the encapsulation always to return t. The defthm event establishes that namep is Boolean. By making the defun local but the defthm non-local this encapsulate constrains the undefined function namep to be Boolean; the admissibility of the encapsulation establishes that there exists a Boolean function (namely the constant function returning t).

We can subsequently use namep as we use any other Boolean function, with the proviso that we know nothing about it except that it always returns either t or nil. We use namep to “recognize” legal keys for our phonebook alist.

We wish to do something similar to define what it means to be a legal phone number. We submit the following form to ACL2:

       (encapsulate
         ;; Introduce a recognizer for phone numbers.
         ((pnump (x) t))
         ;;
         (local (defun pnump (x)
                  (not (equal x nil))))
         ;;
         (defthm pnump-booleanp
           (booleanp (pnump x)))
         ;;
         (defthm nil-not-pnump
           (not (pnump nil)))).

This introduces a Boolean-valued recognizer pnump, with the additional proviso that the constant nil is not a pnump. We impose this restriction to guarantee that we’ll never bind a name to nil in our phone book and thereby introduce the kind of ambiguity described above regarding the use of

binding.

Now a legal phone book is an alist mapping from nameps to pnumps. We can define this as follows:

       (defun name-phonenum-pairp (x)
         ;; Recognizes a pair of (name . pnum).
         (and (consp x)
              (namep (car x))
              (pnump (cdr x))))
       (defun phonebookp (l)
         ;; Recognizes a list of such pairs.
         (if (not (consp l))
             (null l)
           (and (name-phonenum-pairp (car l))
                (phonebookp (cdr l)))))

Thus, a phone book is really a list of pairs (name . pnum). Notice that we have not assumed that the keys of the phone book are distinct. We’ll worry about that question later. (It is not always desirable to insist that the keys of an alist be distinct. But it may be a useful requirement for our specific example.)

Now we are ready to define some of the functions necessary for our phonebook example. The functions we need are:

     (IN-BOOK? NM BK)          ; does NM have a phone number in BK
     (FIND-PHONE NM BK)        ; find NM's phone number in phonebook BK
     (ADD-PHONE NM PNUM BK)    ; give NM the phone number PNUM in BK
     (CHANGE-PHONE NM PNUM BK) ; change NM's phone number to PNUM in BK
     (DEL-PHONE NM PNUM)       ; remove NM's phone number from BK

Given our underlying theory of alists, it is easy to write these functions. But we must take care to specify appropriate “boundary” behavior. Thus, what behavior do we want when, say, we try to change the phone number of a client who is not currently in the book? As usual, there are numerous possibilities; here we’ll assume that we return the phone book unchanged if we try anything “illegal.”

Possible definitions of our phone book functions are as follows. (Remember, an include-book form such as the ones shown earlier must be executed in order to provide definitions for functions such

as bound?.)

       (defun in-book? (nm bk)
         (bound? nm bk))
       (defun find-phone (nm bk)
         (binding nm bk))
       (defun add-phone (nm pnum bk)
         ;; If nm already in-book?, make no change.
         (if (in-book? nm bk)
             bk
           (bind nm pnum bk)))
       (defun change-phone (nm pnum bk)
         ;; Make a change only if nm already has a phone number.
         (if (in-book? nm bk)
             (bind nm pnum bk)
           bk))
       (defun del-phone (nm bk)
         ;; Remove the binding from bk, if there is one.
         (rembind nm bk))

Notice that we don’t have to check whether a name is in the book before deleting, because rembind is essentially a no-op if nm is not bound in bk.

In some sense, this completes our specification. But we can’t have any real confidence in its correctness without validating our specification in some way. One way to do so is by proving some properties of our specification. Some candidate properties are:

1. A name will be in the book after we add it.

2. We will find the most recently added phone number for a client.

3. If we change a number, we’ll find the change.

4. Changing and then deleting a number is the same as just deleting.

5. A name will not be in the book after we delete it.

Let’s formulate some of these properties. The first one, for example, is:

       (defthm add-in-book
         (in-book? nm (add-phone nm pnum bk))).

You may wonder why we didn’t need any hypotheses about the “types” of the arguments. In fact, add-in-book is really expressing a property that is true of alists in general, not just of the particular variety of alists we are dealing with. Of course, we could have added some extraneous hypotheses and proved:

       (defthm add-in-book
         (implies (and (namep nm)
                       (pnump pnum)
                       (phonebookp bk))
                  (in-book? nm (add-phone nm pnum bk)))),

but that would have yielded a weaker and less useful lemma because it would apply to fewer situations. In general, it is best to state lemmas in the most general form possible and to eliminate unnecessary hypotheses whenever possible. The reason for that is simple: lemmas are usually stored as rules and used in later proofs. For a lemma to be used, its hypotheses must be relieved (proved to hold in that instance); extra hypotheses require extra work. So we avoid them whenever possible.

There is another, more important observation to make about our lemma. Even in its simpler form (without the extraneous hypotheses), the lemma add-in-book may be useless as a rewrite (REWRITE^) rule. Notice that it is stated in terms of the non-recursive functions in-book? and add-phone. If such functions appear in the left hand side of the conclusion of a lemma, the lemma may not ever be used. Suppose in a later proof, the theorem prover encountered a term (TERM^) of the form:

       (in-book? nm (add-phone nm pnum bk)).

Since we’ve already proved add-in-book, you’d expect that this would be immediately reduced to true. However, the theorem prover will often “expand” the non-recursive definitions of inbook? and add-phone using their definitions before it attempts rewriting with lemmas. After this expansion, lemma add-in-book won’t “match” the term (TERM^) and so won’t be applied. Look back at the proof script for add-in-proof and you’ll notice that at the very end the prover warned you of this potential difficulty when it printed:

       Warnings:  Non-rec
       Time:  0.18 seconds (prove: 0.05, print: 0.00, other: 0.13)
       ADD-IN-BOOK

The “Warnings” line notifies you that there are non-recursive function calls in the left hand side of the conclusion and that this problem might arise. Of course, it may be that you don’t ever plan to use the lemma for rewriting or that your intention is to disable (DISABLE^) these functions. Disable (DISABLE^)d functions are not expanded and the lemma should apply. However, you should always take note of such warnings and consider an appropriate response. By the way, we noted above that binding is disable (DISABLE^)d. If it were not, none of the lemmas about binding in the book we included would likely be of much use for exactly the reason we just gave.

For our current example, let’s assume that we’re just investigating the properties of our specifications and not concerned about using our lemmas for rewriting. So let’s go on. If we really want to avoid the warnings, we can add :rule-classes nil to each defthm event; see Chapter 15 [RULE-CLASSES], page 723.

Property 2 is: we always find the most recently added phone number for a client. Try the following formalization:

       (defthm find-add-first-cut
         (equal (find-phone nm (add-phone nm pnum bk))
                pnum))

and you’ll find that the proof attempt fails. Examining the proof attempt and our function definitions, we see that the lemma is false if nm is already in the book. We can remedy this situation by reformulating our lemma in at least two different ways:

       (defthm find-add1
         (implies (not (in-book? nm bk))
                  (equal (find-phone nm (add-phone nm pnum bk))
                         pnum)))
       (defthm find-add2
         (equal (find-phone nm (add-phone nm pnum bk))
                (if (in-book? nm bk)
                    (find-phone nm bk)
                    pnum)))

For technical reasons, lemmas such as find-add2, i.e., which do not have hypotheses, are usually slightly preferable. This lemma is stored as an “unconditional” rewrite (REWRITE^) rule (i.e., has no hypotheses) and, therefore, will apply more often than find-add1. However, for our current purposes either version is all right.

Property 3 says: If we change a number, we’ll find the change. This is very similar to the previous example. The formalization is as follows.

       (defthm find-change
         (equal (find-phone nm (change-phone nm pnum bk))
                (if (in-book? nm bk)
                    pnum
                  (find-phone nm bk))))

Property 4 says: changing and then deleting a number is the same as just deleting. We can model this as follows.

       (defthm del-change
         (equal (del-phone nm (change-phone nm pnum bk))
                (del-phone nm bk)))

Unfortunately, when we try to prove this, we encounter subgoals that seem to be true, but for which the prover is stumped. For example, consider the following goal. (Note: endp holds of lists that are empty.)

       Subgoal *1/4
       (IMPLIES (AND (NOT (ENDP BK))
                     (NOT (EQUAL NM (CAAR BK)))
                     (NOT (BOUND? NM (CDR BK)))
                     (BOUND? NM BK))
                (EQUAL (REMBIND NM (BIND NM PNUM BK))
                       (REMBIND NM BK))).

Our intuition about rembind and bind tells us that this goal should be true even without the hypotheses. We attempt to prove the following lemma.

       (defthm rembind-bind
         (equal (rembind nm (bind nm pnum bk))
                (rembind nm bk)))

The prover proves this by induction, and stores it as a rewrite rule. After that, the prover has no difficulty in proving del-change.

The need to prove lemma rembind-bind illustrates a point we made early in this example: the collection of rewrite (REWRITE^) rules supplied by a previously certified book will almost never be everything you’ll need. It would be nice if we could operate purely in the realm of names, phone numbers, and phone books without ever having to prove any new facts about alists. Unfortunately, we needed a fact about the relation between rembind and bind that wasn’t supplied with the alists theory. Hopefully, such omissions will be rare.

Finally, let’s consider our property 5 above: a name will not be in the book after we delete it. We formalize this as follows:

       (defthm in-book-del
         (not (in-book? nm (del-phone nm bk))))

This proves easily. But notice that it’s only true because del-phone (actually rembind) removes all occurrences of a name from the phone book. If it only removed, say, the first one it encountered, we’d need a hypothesis that said that nm occurs at most once in bk. Ah, maybe that’s a property you hadn’t considered. Maybe you want to ensure that any name occurs at most once in any valid phonebook.

To complete this example, let’s consider adding an invariant to our specification. In particular, suppose we want to assure that no client has more than one associated phone number. One way to ensure this is to require that the domain of the alist is a “set” (has no duplicates).

       (defun setp (l)
         (if (atom l)
             (null l)
           (and (not (member-equal (car l) (cdr l)))
                (setp (cdr l)))))
       (defun valid-phonebookp (bk)
         (and (phonebookp bk)
              (setp (domain bk))))

Now, we want to show under what conditions our operations preserve the property of being a valid-phonebookp. The operations in-book? and find-phone don’t return a phone book, so we don’t really need to worry about them. Since we’re really interested in the “types” of values preserved by our phonebook functions, let’s look at the types of those operations as well.

       (defthm in-book-booleanp
         (booleanp (in-book? nm bk)))
       (defthm in-book-namep
         (implies (and (phonebookp bk)
                       (in-book? nm bk))
                  (namep nm))

         :hints (("Goal" :in-theory (enable bound?))))
       (defthm find-phone-pnump
         (implies (and (phonebookp bk)
                       (in-book? nm bk))
                  (pnump (find-phone nm bk)))
         :hints (("Goal" :in-theory (enable bound? binding))))

Note the “:hints (HINTS^)” on the last two lemmas. Neither of these would prove without these hints (HINTS^), because once again there are some facts about bound? and binding not available in our current context. Now, we could figure out what those facts are and try to prove them. Alternatively, we can enable (ENABLE^) bound? and binding and hope that by opening up these functions, the conjectures will reduce to versions that the prover does know enough about or can prove by induction. In this case, this strategy works. The hints tell the prover to enable (ENABLE^) the functions in question when considering the designated goal.

Below we develop the theorems showing that add-phone, change-phone, and del-phone preserve our proposed invariant. Notice that along the way we have to prove some subsidiary facts, some of which are pretty ugly. It would be a good idea for you to try, say, add-phone-preserves-invariant without introducing the following four lemmas first. See if you can develop the proof and only add these lemmas as you need assistance. Then try change-phone-preserves-invariant and del-phone-preserves-invariant. They will be easier. It is illuminating to think about why del-phone-preserves-invariant does not need any “type” hypotheses.

       (defthm bind-preserves-phonebookp
         (implies (and (phonebookp bk)
                       (namep nm)
                       (pnump num))
                  (phonebookp (bind nm num bk))))
       (defthm member-equal-strip-cars-bind
         (implies (and (not (equal x y))
                       (not (member-equal x (strip-cars a))))
                  (not (member-equal x (strip-cars (bind y z a))))))
       (defthm bind-preserves-domain-setp
         (implies (and (alistp bk)
                       (setp (domain bk)))
                  (setp (domain (bind nm num bk))))
         :hints (("Goal" :in-theory (enable domain))))
       (defthm phonebookp-alistp

    (implies (phonebookp bk)
             (alistp bk)))
  (defthm ADD-PHONE-PRESERVES-INVARIANT
    (implies (and (valid-phonebookp bk)
                  (namep nm)
                  (pnump num))
             (valid-phonebookp (add-phone nm num bk)))
    :hints (("Goal" :in-theory (disable domain-bind))))
  (defthm CHANGE-PHONE-PRESERVES-INVARIANT
    (implies (and (valid-phonebookp bk)
                  (namep nm)
                  (pnump num))
             (valid-phonebookp (change-phone nm num bk)))
    :hints (("Goal" :in-theory (disable domain-bind))))
  (defthm remove-equal-preserves-setp
    (implies (setp l)
             (setp (remove-equal x l))))
  (defthm rembind-preserves-phonebookp
    (implies (phonebookp bk)
             (phonebookp (rembind nm bk))))
  (defthm DEL-PHONE-PRESERVES-INVARIANT
    (implies (valid-phonebookp bk)
             (valid-phonebookp (del-phone nm bk))))

As a final test of your understanding, try to formulate and prove an invariant that says that no phone number is assigned to more than one name. The following hints may help.

1. Define the appropriate invariant. (Hint: remember the function range.)

2. Do our current definitions of add-phone and change-phone necessarily preserve this property? If not, consider what hypotheses are necessary in order to guarantee that they do preserve this property.

3. Study the definition of the function range and notice that it is defined in terms of the function strip-cdrs (STRIP-CDRS^). Understand how this defines the range of an alist.

4. Formulate the correctness theorems and attempt to prove them. You’ll probably benefit from studying the invariant proof above. In particular, you may need some fact about the function strip-cdrs (STRIP-CDRS^) analogous to the lemma member-

equal-strip-cars-bind above.

Below is one solution to this exercise. Don’t look at the solution, however, until you’ve struggled a bit with it. Notice that we didn’t actually change the definitions of add-phone and change-phone, but added a hypothesis saying that the number is “new.” We could have changed the definitions to check this and return the phonebook unchanged if the number was already in use.

(defun pnums-in-use (bk)
(range bk))
(defun phonenums-unique (bk)
(setp (pnums-in-use bk)))
(defun new-pnump (pnum bk)
(not (member-equal pnum (pnums-in-use bk))))
(defthm member-equal-strip-cdrs-rembind
(implies (not (member-equal x (strip-cdrs y)))
         (not (member-equal x (strip-cdrs (rembind z y))))))
(defthm DEL-PHONE-PRESERVES-PHONENUMS-UNIQUE
(implies (phonenums-unique bk)
         (phonenums-unique (del-phone nm bk)))
:hints (("Goal" :in-theory (enable range))))
(defthm strip-cdrs-bind-non-member
(implies (and (not (bound? x a))
              (alistp a))
         (equal (strip-cdrs (bind x y a))
                (append (strip-cdrs a) (list y))))
:hints (("Goal" :in-theory (enable bound?))))
(defthm setp-append-list
(implies (setp l)
         (equal (setp (append l (list x)))
                (not (member-equal x l)))))
(defthm ADD-PHONE-PRESERVES-PHONENUMS-UNIQUE
(implies (and (phonenums-unique bk)
              (new-pnump pnum bk)
              (alistp bk))
         (phonenums-unique (add-phone nm pnum bk)))
:hints (("Goal" :in-theory (enable range))))
(defthm member-equal-strip-cdrs-bind
(implies (and (not (member-equal z (strip-cdrs a)))
              (not (equal z y)))
         (not (member-equal z (strip-cdrs (bind x y a))))))

  (defthm CHANGE-PHONE-PRESERVES-PHONENUMS-UNIQUE
    (implies (and (phonenums-unique bk)
                  (new-pnump pnum bk)
                  (alistp bk))
             (phonenums-unique (change-phone nm pnum bk)))
    :hints (("Goal" :in-theory (enable range))))

1.5.5 TUTORIAL4-DEFUN-SK-EXAMPLE

TUTORIAL4-DEFUN-SK-EXAMPLE example of quantified notions

This example illustrates the use of defun-sk (DEFUN-SK^) and defthm (DEFTHM^) events (EVENTS^) to reason about quantifiers. See Section 6.17 [DEFUN-SK], page 182.

Many users prefer to avoid the use of quantifiers, since ACL2 provides only very limited support for reasoning about quantifiers.

Here is a list of events (EVENTS^) that proves that if there are arbitrarily large numbers satisfying the disjunction (OR P R), then either there are arbitrarily large numbers satisfying P or there are arbitrarily large numbers satisfying R.

; Introduce undefined predicates p and r.
(defstub p (x) t)
(defstub r (x) t)
; Define the notion that something bigger than x satisfies p.
(defun-sk some-bigger-p (x)
  (exists y (and (< x y) (p y))))
; Define the notion that something bigger than x satisfies r.
(defun-sk some-bigger-r (x)
  (exists y (and (< x y) (r y))))
; Define the notion that arbitrarily large x satisfy p.
(defun-sk arb-lg-p ()
  (forall x (some-bigger-p x)))
; Define the notion that arbitrarily large x satisfy r.
(defun-sk arb-lg-r ()
  (forall x (some-bigger-r x)))

; Define the notion that something bigger than x satisfies p or r.
(defun-sk some-bigger-p-or-r (x)
  (exists y (and (< x y) (or (p y) (r y)))))
; Define the notion that arbitrarily large x satisfy p or r.
(defun-sk arb-lg-p-or-r ()
  (forall x (some-bigger-p-or-r x)))
; Prove the theorem promised above.  Notice that the functions open
; automatically, but that we have to provide help for some rewrite
; rules because they have free variables in the hypotheses.  The
; ``witness functions'' mentioned below were introduced by DEFUN-SK.
(thm
 (implies (arb-lg-p-or-r)
          (or (arb-lg-p)
              (arb-lg-r)))
 :hints (("Goal"
          :use
          ((:instance some-bigger-p-suff
                      (x (arb-lg-p-witness))
                      (y (some-bigger-p-or-r-witness
                          (max (arb-lg-p-witness)
                               (arb-lg-r-witness)))))
           (:instance some-bigger-r-suff
                      (x (arb-lg-r-witness))
                      (y (some-bigger-p-or-r-witness
                          (max (arb-lg-p-witness)
                               (arb-lg-r-witness)))))
           (:instance arb-lg-p-or-r-necc
                      (x (max (arb-lg-p-witness)
                              (arb-lg-r-witness))))))))
; And finally, here's a cute little example.  We have already
; defined above the notion (some-bigger-p x), which says that
; something bigger than x satisfies p.  Let us introduce a notion
; that asserts that there exists both y and z bigger than x which
; satisfy p.  On first glance this new notion may appear to be
; stronger than the old one, but careful inspection shows that y and
; z do not have to be distinct.  In fact ACL2 realizes this, and
; proves the theorem below automatically.
(defun-sk two-bigger-p (x)
  (exists (y z) (and (< x y) (p y) (< x z) (p z))))
(thm (implies (some-bigger-p x) (two-bigger-p x)))
; A technical point:  ACL2 fails to prove the theorem above

     ; automatically if we take its contrapositive, unless we disable
     ; two-bigger-p as shown below.  That is because ACL2 needs to expand
     ; some-bigger-p before applying the rewrite rule introduced for
     ; two-bigger-p, which contains free variables.  The moral of the
     ; story is:  Don't expect too much automatic support from ACL2 for
     ; reasoning about quantified notions.
     (thm (implies (not (two-bigger-p x)) (not (some-bigger-p x)))
          :hints (("Goal" :in-theory (disable two-bigger-p))))

1.5.6 TUTORIAL5-MISCELLANEOUS-EXAMPLES

TUTORIAL5-MISCELLANEOUS-EXAMPLES miscellaneous ACL2 examples

The following examples are more advanced examples of usage of ACL2. They are included largely for reference, in case someone finds them useful.

* FILE-READING-EXAMPLE:: example of reading files in ACL2

* GUARD-EXAMPLE:: a brief transcript illustrating guard (GUARD^)s in ACL2

* MUTUAL-RECURSION-PROOF-EXAMPLE:: a small proof about mutually recursive functions

1.5.6.1 FILE-READING-EXAMPLE

FILE-READING-EXAMPLE example of reading files in ACL2

This example illustrates the use of ACL2’s IO (IO^) primitives to read the forms in a file. See Section 10.135 [IO], page 493.

This example provides a solution to the following problem. Let’s say that you have a file that contains s-expressions. Suppose that you want to build a list by starting with nil, and updating it “appropriately” upon encountering each successive s-expression in the file. That is, suppose that

you have written a function update-list such that (update-list obj current-list) returns

the list obtained by “updating” current-list with the next object, obj, encountered in the file. The top-level function for processing such a file, returning the final list, could be defined as follows. Notice that because it opens a channel to the given file, this function modifies state (STATE^) and hence must return state (STATE^). Thus it actually returns two values: the final list and the new state (STATE^).

       (defun process-file (filename state)
         (mv-let
          (channel state)
          (open-input-channel filename :object state)
          (mv-let (result state)
                  (process-file1 nil channel state) ;see below
                  (let ((state (close-input-channel channel state)))
                    (mv result state)))))

The function process-file1 referred to above takes the currently constructed list (initially, nil), together with a channel to the file being read and the state (STATE^), and returns the final updated list. Notice that this function is tail recursive. This is important because many Lisp compilers will remove tail recursion, thus avoiding the potential for stack overflows when the file contains a large number of forms.

       (defun process-file1 (current-list channel state)
         (mv-let (eofp obj state)
                 (read-object channel state)
                 (cond
                  (eofp (mv current-list state))
                  (t (process-file1 (update-list obj current-list)
                                    channel state)))))

1.5.6.2 GUARD-EXAMPLE

GUARD-EXAMPLE a brief transcript illustrating guard (GUARD^)s in ACL2

This note addresses the question: what is the use of guard (GUARD^)s in ACL2? Although we recommend that beginners try to avoid guard (GUARD^)s for a while, we hope that the summary here is reasonably self-contained and will provide a reasonable introduction to guards in ACL2. For a more systematic discussion, see Section 8.41 [GUARD], page 305. For a summary of that topic, see Section 8.41.3 [GUARD-QUICK-REFERENCE], page 308.

Before we get into the issue of guard (GUARD^)s, let us note that there are two important “modes”:

defun-mode (DEFUN-MODE^) — “Does this defun (DEFUN^) add an axiom (‘:logic mode’) or not (‘:program mode’)?” (See Section 8.20 [DEFUN-MODE], page 275.) Only :logic (LOGIC^) mode functions can have their “guard (GUARD^)s verified” via mechanized proof; see Section 6.39 [VERIFY-GUARDS], page 210.

set-guard-checking (SET-GUARD-CHECKING^) — “Should runtime guard (GUARD^) violations signal an error (t) or go undetected (nil)? Equivalently, are expressions evaluated in Common Lisp or in the logic?” (See Section 9.12 [SET-GUARD-CHECKING], page 423.)

Prompt examples

Here some examples of the relation between the ACL2 prompt (PROMPT^) and the “modes” discussed above. Also see Section 8.19 [DEFAULT-PRINT-PROMPT], page 274. The first examples all have ld-skip-proofsp nil; that is, proofs are not skipped.

       ACL2 !>    ; logic mode with guard checking on
       ACL2 >     ; logic mode with guard checking off
       ACL2 p!>   ; program mode with guard checking on
       ACL2 p>    ; program mode with guard checking off

Here are some examples with default-defun-mode (DEFAULT-DEFUN-MODE^) of :logic (LOGIC^).

       ACL2 >     ; guard checking off, ld-skip-proofsp nil
       ACL2 s>    ; guard checking off, ld-skip-proofsp t
       ACL2 !>    ; guard checking on, ld-skip-proofsp nil
       ACL2 !s>   ; guard checking on, ld-skip-proofsp t

Sample session

     ACL2 !>(+ 'abc 3)
     ACL2 Error in TOP-LEVEL: The guard for the function symbol
     BINARY-+, which is (AND (ACL2-NUMBERP X) (ACL2-NUMBERP Y)),
     is violated by the arguments in the call (+ 'ABC 3).
     ACL2 !>:set-guard-checking nil
     ;;;; verbose output omitted here
     ACL2 >(+ 'abc 3)
     3
     ACL2 >(< 'abc 3)

T
ACL2 >(< 3 'abc)
NIL
ACL2 >(< -3 'abc)
T
ACL2 >:set-guard-checking t
Turning guard checking on.
ACL2 !>(defun sum-list (x)
        (declare (xargs :guard (integer-listp x)
                        :verify-guards nil))
        (cond ((endp x) 0)
              (t (+ (car x) (sum-list (cdr x))))))
The admission of SUM-LIST is trivial, using the relation
E0-ORD-< (which is known to be well-founded on the domain
recognized by E0-ORDINALP) and the measure (ACL2-COUNT X).
We observe that the type of SUM-LIST is described by the
theorem (ACL2-NUMBERP (SUM-LIST X)).  We used primitive type
reasoning.
Summary
Form:  ( DEFUN SUM-LIST ...)
Rules: ((:FAKE-RUNE-FOR-TYPE-SET NIL))
Warnings:  None
Time:  0.03 seconds
   (prove: 0.00, print: 0.00, proof tree: 0.00, other: 0.03)
 SUM-LIST
ACL2 !>(sum-list '(1 2 3))
6
ACL2 !>(sum-list '(1 2 abc 3))
ACL2 Error in TOP-LEVEL: The guard for the function symbol
BINARY-+, which is (AND (ACL2-NUMBERP X) (ACL2-NUMBERP Y)),
is violated by the arguments in the call (+ 'ABC 3).
ACL2 !>:set-guard-checking nil
;;;; verbose output omitted here
ACL2 >(sum-list '(1 2 abc 3))
6
ACL2 >(defthm sum-list-append
       (equal (sum-list (append a b))
              (+ (sum-list a) (sum-list b))))
<< Starting proof tree logging >>
Name the formula above *1.

Perhaps we can prove *1 by induction.  Three induction
schemes are suggested by this conjecture.  Subsumption
reduces that number to two.  However, one of these is flawed
and so we are left with one viable candidate.
...
That completes the proof of *1.
Q.E.D.

Guard verification vs. defun

      Declare Form                        Guards Verified?
  (declare (xargs :mode :program ...))          no
  (declare (xargs :guard g))                    yes
  (declare (xargs :guard g :verify-guards nil)) no
  (declare (xargs ...<no :guard>...))           no
ACL2 >:pe sum-list
 l        8  (DEFUN SUM-LIST (X)
              (DECLARE (XARGS :GUARD (INTEGER-LISTP X)
                              :VERIFY-GUARDS NIL))
              (COND ((ENDP X) 0)
                    (T (+ (CAR X) (SUM-LIST (CDR X))))))
ACL2 >(verify-guards sum-list)
The non-trivial part of the guard conjecture for SUM-LIST,
given the :type-prescription rule SUM-LIST, is
Goal
(AND (IMPLIES (AND (INTEGER-LISTP X) (NOT (CONSP X)))
              (EQUAL X NIL))
     (IMPLIES (AND (INTEGER-LISTP X) (NOT (ENDP X)))
              (INTEGER-LISTP (CDR X)))
     (IMPLIES (AND (INTEGER-LISTP X) (NOT (ENDP X)))
              (ACL2-NUMBERP (CAR X)))).
...
ACL2 >:pe sum-list
 lv       8  (DEFUN SUM-LIST (X)
              (DECLARE (XARGS :GUARD (INTEGER-LISTP X)
                              :VERIFY-GUARDS NIL))
ACL2 >:set-guard-checking t

ACL2 !>(sum-list '(1 2 abc 3))
ACL2 Error in TOP-LEVEL: The guard for the function symbol
SUM-LIST, which is (INTEGER-LISTP X), is violated by the
arguments in the call (SUM-LIST '(1 2 ABC ...)).
ACL2 !>:set-guard-checking nil
ACL2 >(sum-list '(1 2 abc 3))
6
ACL2 >:comp sum-list
Compiling gazonk0.lsp.
End of Pass 1.
End of Pass 2.
Finished compiling gazonk0.lsp.
Loading gazonk0.o
start address -T 1bbf0b4 Finished loading gazonk0.o
Compiling gazonk0.lsp.
End of Pass 1.
End of Pass 2.
Finished compiling gazonk0.lsp.
Loading gazonk0.o
start address -T 1bc4408 Finished loading gazonk0.o
 SUM-LIST
ACL2 >:q
Exiting the ACL2 read-eval-print loop.
ACL2>(trace sum-list)
(SUM-LIST)
ACL2>(lp)
ACL2 Version 1.8.  Level 1.  Cbd "/slocal/src/acl2/v1-9/".
Type :help for help.
ACL2 >(sum-list '(1 2 abc 3))
6
ACL2 >(sum-list '(1 2 3))
  1> (SUM-LIST (1 2 3))>
    2> (SUM-LIST (2 3))>
      3> (SUM-LIST (3))>
        4> (SUM-LIST NIL)>
        <4 (SUM-LIST 0)>
      <3 (SUM-LIST 3)>
    <2 (SUM-LIST 5)>
  <1 (SUM-LIST 6)>
6
ACL2 >:pe sum-list-append

          9  (DEFTHM SUM-LIST-APPEND
                     (EQUAL (SUM-LIST (APPEND A B))
                            (+ (SUM-LIST A) (SUM-LIST B))))
ACL2 >(verify-guards sum-list-append)
The non-trivial part of the guard conjecture for
SUM-LIST-APPEND, given the :type-prescription rule SUM-LIST,
is
Goal
(AND (TRUE-LISTP A)
     (INTEGER-LISTP (APPEND A B))
     (INTEGER-LISTP A)
     (INTEGER-LISTP B)).
...
****** FAILED ******* See :DOC failure ****** FAILED ******
ACL2 >(defthm common-lisp-sum-list-append
         (if (and (integer-listp a)
                  (integer-listp b))
             (equal (sum-list (append a b))
                    (+ (sum-list a) (sum-list b)))
             t)
         :rule-classes nil)
<< Starting proof tree logging >>
By the simple :rewrite rule SUM-LIST-APPEND we reduce the
conjecture to
Goal'
(IMPLIES (AND (INTEGER-LISTP A)
              (INTEGER-LISTP B))
         (EQUAL (+ (SUM-LIST A) (SUM-LIST B))
                (+ (SUM-LIST A) (SUM-LIST B)))).
But we reduce the conjecture to T, by primitive type
reasoning.
Q.E.D.
;;;; summary omitted here
ACL2 >(verify-guards common-lisp-sum-list-append)
The non-trivial part of the guard conjecture for
COMMON-LISP-SUM-LIST-APPEND, given the :type-prescription
rule SUM-LIST, is

Goal
(AND (IMPLIES (AND (INTEGER-LISTP A)
                   (INTEGER-LISTP B))
              (TRUE-LISTP A))
     (IMPLIES (AND (INTEGER-LISTP A)
                   (INTEGER-LISTP B))
              (INTEGER-LISTP (APPEND A B)))).
...
Q.E.D.
That completes the proof of the guard theorem for
COMMON-LISP-SUM-LIST-APPEND.  COMMON-LISP-SUM-LIST-APPEND
is compliant with Common Lisp.
;;;; Summary omitted here.
ACL2 >(defthm foo (consp (mv x y)))
...
Q.E.D.

ACL2 >(verify-guards foo)
ACL2 Error in (VERIFY-GUARDS FOO): The number of values we
need to return is 1 but the number of values returned by the
call (MV X Y) is 2.
> (CONSP (MV X Y))

ACL2 Error in (VERIFY-GUARDS FOO): The guards for FOO cannot
be verified because the theorem has the wrong syntactic
form.  See :DOC verify-guards.

1.5.6.3 MUTUAL-RECURSION-PROOF-EXAMPLE

MUTUAL-RECURSION-PROOF-EXAMPLE a small proof about mutually recursive functions

Sometimes one wants to reason about mutually recursive functions. Although this is possible in ACL2, it can be a bit awkward. This example is intended to give some ideas about how one can go about such proofs.

For an introduction to mutual recursion in ACL2, see Section 6.24 [MUTUAL-RECURSION], page 194.

We begin by defining two mutually recursive functions: one that collects the variables from a term (TERM^), the other that collects the variables from a list of term (TERM^)s. We actually imagine the term (TERM^) argument to be a pseudo-termp (PSEUDO-TERMP^); see Section 8.74 [PSEUDO-TERMP], page 358.

     (mutual-recursion
     (defun free-vars1 (term ans)
       (cond ((atom term)
              (add-to-set-eq term ans))
             ((fquotep term) ans)
             (t (free-vars1-lst (fargs term) ans))))
     (defun free-vars1-lst (lst ans)
       (cond ((atom lst) ans)
             (t (free-vars1-lst (cdr lst)
                                (free-vars1 (car lst) ans)))))
     )

The idea of the following function is that it suggests a proof by induction in two cases, according to the top-level if (IF^) structure of the body. In one case, (atom x) is true, and the theorem to be proved should be proved under no additional hypotheses except for (atom x). In the other case, (not (atom x)) is assumed together with three instances of the theorem to be proved, one for each recursive call in this case. So, one instance substitutes (car x) for x; one substitutes (cdr x) for x; and the third substitutes (cdr x) for x and (free-vars1 (car x) ans) for ans. If you think about how you would go about a hand proof of the theorem to follow, you’ll come up with a similar scheme.

     (defun symbol-listp-free-vars1-induction (x ans)
       (if (atom x)
     ; then we just make sure x and ans aren't considered irrelevant
           (list x ans)
         (list (symbol-listp-free-vars1-induction (car x) ans)
               (symbol-listp-free-vars1-induction (cdr x) ans)
               (symbol-listp-free-vars1-induction
                (cdr x)
                (free-vars1 (car x) ans)))))

We now prove the two theorems together as a conjunction, because the inductive hypotheses for one are sometimes needed in the proof of the other (even when you do this proof on paper!).

     (defthm symbol-listp-free-vars1
       (and (implies (and (pseudo-termp x)
                          (symbol-listp ans))
                     (symbol-listp (free-vars1 x ans)))
            (implies (and (pseudo-term-listp x)
                          (symbol-listp ans))
                     (symbol-listp (free-vars1-lst x ans))))
       :hints
       (("Goal" :induct (symbol-listp-free-vars1-induction x ans))))

The above works, but let’s try for a more efficient proof, which avoids cluttering the proof with irrelevant (false) inductive hypotheses.

     (ubt 'symbol-listp-free-vars1-induction)
     (defun symbol-listp-free-vars1-induction (flg x ans)
     ; Flg is non-nil (or t) if we are ``thinking'' of a single term.
       (if (atom x)
           (list x ans)
         (if flg
             (symbol-listp-free-vars1-induction nil (cdr x) ans)
           (list (symbol-listp-free-vars1-induction t (car x) ans)
                 (symbol-listp-free-vars1-induction
                  nil
                  (cdr x)
                  (free-vars1 (car x) ans))))))

We now state the theorem as a conditional, so that it can be proved nicely using the induction (INDUCTION^) scheme that we have just coded. The prover will not store an if (IF^) term (TERM^) as a rewrite (REWRITE^) rule, but that’s OK (as long as we tell it not to try), because we’re going to derive the corollaries of interest later and make them into rewrite (REWRITE^) rules.

     (defthm symbol-listp-free-vars1-flg
       (if flg
           (implies (and (pseudo-termp x)
                         (symbol-listp ans))
                    (symbol-listp (free-vars1 x ans)))
         (implies (and (pseudo-term-listp x)
                       (symbol-listp ans))

           (symbol-listp (free-vars1-lst x ans))))
:hints
(("Goal" :induct (symbol-listp-free-vars1-induction flg x ans)))
:rule-classes nil)

And finally, we may derive the theorems we are interested in as immediate corollaries.

(defthm symbol-listp-free-vars1
(implies (and (pseudo-termp x)
              (symbol-listp ans))
         (symbol-listp (free-vars1 x ans)))
:hints (("Goal" :by (:instance symbol-listp-free-vars1-flg
                               (flg t)))))
(defthm symbol-listp-free-vars1-lst
(implies (and (pseudo-term-listp x)
              (symbol-listp ans))
         (symbol-listp (free-vars1-lst x ans)))
:hints (("Goal" :by (:instance symbol-listp-free-vars1-flg
                               (flg nil)))))

70 ACL2 Version 1.9

2 BDD

BDD ordered binary decision diagrams with rewriting

Ordered binary decision diagrams (OBDDs, often simply called BDDs) are a technique, originally published by Randy Bryant, for the efficient simplification of Boolean expressions. In ACL2 we combine this technique with rewriting to handle arbitrary ACL2 terms that can represent not only Boolean values, but non-Boolean values as well. In particular, we provide a setting for deciding equality of bit vectors (lists of Boolean values).

* BDD-ALGORITHM:: summary of the BDD algorithm in ACL2

* BDD-INTRODUCTION:: examples illustrating the use of BDDs in ACL2

* IF*:: for conditional rewriting with BDDs

* SHOW-BDD:: inspect failed BDD proof attempts

An introduction to BDDs for the automated reasoning community may be found in “Introduction to the OBDD Algorithm for the ATP Community” by J Moore, Journal of Automated Reasoning (1994), pp. 33-45. (This paper also appears as Technical Report #84 from Computational Logic, Inc.)

Further information about BDDs in ACL2 can be found in the subtopics of this documentation (DOCUMENTATION^) section. In particular, see Section 2.2 [BDD-INTRODUCTION], page 81 for a good starting place that provides a number of examples.

See Section 8.43 [HINTS], page 319 for a description of :bdd hints. For quick reference, here is an example; but only the :vars part of the hint is required, as explained in the documentation for hints (HINTS^). The values shown are the defaults.

     (:vars nil :bdd-constructors (cons) :prove t :literal :all)

We suggest that you next visit the documentation topic BDD-INTRODUCTION (BDD-INTRODUCTION^).

2.1 BDD-ALGORITHM

BDD-ALGORITHM summary of the BDD algorithm in ACL2

The BDD algorithm in ACL2 uses a combination of manipulation of IF terms and unconditional rewriting. In this discussion we begin with some relevant mathematical theory. This is followed by a description of how ACL2 does BDDs, including concluding discussions of soundness, completeness, and efficiency. We recommend that you read the other documentation about BDDs in ACL2 before reading the rather technical material that follows. See Chapter 2 [BDD], page 71. Here is an outline of our presentation. Readers who want a user perspective, without undue mathematical theory, may wish to skip to Part (B), referring to Part (A) only on occasion if necessary. (A) Mathematical Considerations

(A1) BDD term order (A2) BDD-constructors and BDD terms, and their connection with aborting the BDD algorithm (A3) Canonical BDD terms (A4) A theorem stating the equivalence of provable and syntactic equality for canonical BDD terms

(B) Algorithmic Considerations (B1) BDD rules (rules used by the rewriting portion of the ACL2 BDD algorithm) (B2) Terms “known to be Boolean” (B3) An “IF-lifting” operation used by the algorithm, as well as an iterative version of that operation (B4) The ACL2 BDD algorithm (B5) Soundness and Completeness of the ACL2 BDD algorithm (B6) Efficiency considerations

(A) Mathematical Considerations (A1) BDD term order

Our BDD algorithm creates a total “BDD term order” on ACL2 terms, on the fly. We use this order in our discussions below of IF-lifting and of canonical BDD terms, and in the algorithm’s use of commutativity. The particular order is unimportant, except that we guarantee (for purposes of commutative functions) that constants are smaller in this order than non-constants.

(A2) BDD-constructors (assumed to be '(cons)) and BDD terms

We take as given a list of function symbols that we call the “BDD-constructors.” By default, the only BDD-constructor is cons (CONS^), although it is legal to specify any list of function symbols as the BDD-constructors, either by using the acl2-defaults-table (ACL2-DEFAULTS-TABLE^) (see Section 9.2 [ACL2-DEFAULTS-TABLE], page 410) or by supplying a :BDD-CONSTRUCTORS hint (see Section 8.43 [HINTS], page 319). Warning: this capability is largely untested and may produce undesirable results. Henceforth, except when explicitly stated to the contrary, we assume that BDD-constructors is '(cons).

Roughly speaking, a BDD (BDD^) term is the sort of term (TERM^) produced by our BDD algorithm, namely a tree with all cons (CONS^) nodes lying above all non-CONS nodes. More formally, a term (TERM^) is said to be a BDD (BDD^) term if it contains no subterm of either of the following forms, where f is not CONS.

     (f ... (CONS ...) ...)
     (f ... 'x ...)  ; where (consp x) = t

We will see that whenever the BDD algorithm attempts to create a term (TERM^) that is not a BDD (BDD^) term, it aborts instead. Thus, whenever the algorithm completes without aborting, it creates a BDD (BDD^) term.

(A3) Canonical BDD terms

We can strengthen the notion of “BDD term” to a notion of “canonical BDD term” by imposing the following additional requirements, for every subterm of the form (IF x y z):

(a) x is a variable, and it precedes (in the BDD term order) every variable occurring in y or z;

(b) y and z are syntactically distinct; and,

(c) it is not the case that y is t and z is nil.

We claim that it follows easily from our description of the BDD algorithm that every term it creates is a canonical BDD term, assuming that the variables occurring in all such terms are treated by the algorithm as being Boolean (see (B2) below) and that the terms contain no function symbols other than IF and CONS. Thus, under those assumptions the following theorem shows that the BDD algorithm never creates distinct terms that are provably equal, a property that is useful for completeness and efficiency (as we explain in (B5) and (B6) below).

(A4) Provably equal canonical BDD terms are identical

We believe that the following theorem and proof are routine extensions of a standard result and proof to terms that allow calls of CONS.

Theorem. Suppose that t1 and t2 are canonical BDD terms that contain no function symbols other than IF and CONS. Also suppose that (EQUAL t1 t2) is a theorem. Then t1 and t2 are syntactically identical.

Proof of theorem: By induction on the total number of symbols occurring in these two terms. First suppose that at least one term is a variable; without loss of generality let it be t1. We must prove that t2 is syntactically the same as t1. Now it is clearly consistent that (EQUAL t1 t2) is false if t2 is a call of CONS (to see this, simply let t1 be an value that is not a CONSP). Similarly, t2 cannot be a constant or a variable other than t1. The remaining possibility to rule out is that t2 is of the form (IF t3 t4 t5), since by assumption its function symbol must be IF or CONS and we have already handled the latter case. Since t2 is canonical, we know that t3 is a variable. Since (EQUAL t1 t2) is provable, i.e.,

     (EQUAL t1 (if t3 t4 t5))

is provable, it follows that we may substitute either t or nil for t3 into this equality to obtain two new provable equalities. First, suppose that t1 and t3 are distinct variables. Then these substitutions show that t1 is provably equal to both t4 and t5 (since t3 does not occur in t4 or t5 by property (a) above, as t2 is canonical), and hence t4 and t5 are provably equal to each other, which implies by the inductive hypothesis that they are the same term — and this contradicts the assumption that t2 is canonical (property (b)). Therefore t1 and t3 are the same variable, i.e., the equality displayed above is actually (EQUAL t1 (if t1 t4 t5)). Substituting t and then nil for t1 into this provable equality lets us prove (EQUAL t t4) and (EQUAL nil t5), which by the inductive hypothesis implies that t4 is (syntactically) the term t and t5 is nil. That is, t2 is (IF t1 t nil), which contradicts the assumption that t2 is canonical (property (c)).

Next, suppose that at least one term is a call of IF. Our first observation is that the other term is also a call of IF. For if the other is a call of CONS, then they cannot be provably equal, because the former has no function symbols other than IF and hence is Boolean when all its variables are assigned Boolean values. Also, if the other is a constant, then both branches of the IF term are provably equal to that constant and hence these branches are syntactically identical by the inductive hypothesis, contradicting property (b). Hence, we may assume for this case that both terms are calls of IF; let us write them as follows.

     t0:  (IF t1 t2 t3)
     u0:  (IF u1 u2 u3)

Note that t1 and u1 are variables, by property (a) of canonical BDD terms. First we claim that t1 does not strictly precede u1 in the BDD term order. For suppose t1 does strictly precede u1. Then property (a) of canonical BDD terms guarantees that t1 does not occur in u0. Hence, an argument much like one used above shows that u0 is provably equal to both t2 (substituting t for t1) and t3 (substituting nil for t1), and hence t2 and t3 are provably equal. That implies that they are identical terms, by the inductive hypothesis, which then contradicts property (b) for t0. Similarly, u1 does not strictly precede t1 in the BDD term order. Therefore, t1 and u1 are the same variable. By substituting t for this variable we see that t2 and u2 are provably equal, and hence they are equal by the inductive hypothesis. Similarly, by substituting nil for t1 (and u1) we see that t3 and u3 are provably, hence syntactically, equal.

We have covered all cases in which at least one term is a variable or at least one term is a call of IF. If both terms are constants, then provable and syntactic equality are clearly equivalent. Finally, then, we may assume that one term is a call of CONS and the other is a constant or a call of CONS. The constant case is similar to the CONS case if the constant is a CONSP, so we omit it; while if the constant is not a CONSP then it is not provably equal to a call of CONS; in fact it is provably not equal!

So, we are left with a final case, in which canonical BDD terms (CONS t1 t2) and (CONS u1 u2) are provably equal, and we want to show that t1 and u1 are syntactically equal as are t2 and u2. These conclusions are easy consequences of the inductive hypothesis, since the ACL2 axiom CONS-EQUAL (which you can inspect using :PE (PE^)) shows that equality of the given terms is equivalent to the conjunction of (EQUAL t1 t2) and (EQUAL u1 u2). Q.E.D.

(B) Algorithmic Considerations

(B1) BDD rules A rule of class :rewrite (REWRITE^) (see Chapter 15 [RULE-CLASSES], page 723) is said to be a “BDD (BDD^) rewrite rule” if and only if it satisfies the following criteria. (1) The rule is enable (ENABLE^)d. (2) Its equivalence (EQUIVALENCE^) relation is equal (EQUAL^). (3) It has no hypotheses. (4) Its :loop-stopper (LOOP-STOPPER^) field is nil, i.e., it is not a permutative rule. (5) All variables occurring in the rule occur in its left-hand side (i.e., there are no “free variables”; see Section 15.14 [REWRITE], page 764). A rule of class :definition (DEFINITION^) (see Chapter 15 [RULE-CLASSES], page 723) is said to be a “BDD (BDD^) definition rule” if it satisfies all the criteria above (except (4), which does not apply), and moreover the top function symbol of the left-hand side was not recursively (or mutually recursively) defined. Technical point: Note that this additional criterion is independent of whether or not the indicated function symbol actually occurs in the right-hand side of the rule.

Both BDD rewrite rules and BDD definition rules are said to be “BDD rules.”

(B2) Terms ”known to be Boolean”

We apply the BDD algorithm in the context of a top-level goal to prove, namely, the goal at which the :BDD hint is attached. As we run the BDD algorithm, we allow ourselves to say that a set of term (TERM^)s is “known to be Boolean” if we can verify that the goal is provable from the assumption that at least one of the terms is not Boolean. Equivalently, we allow ourselves to say that a set of terms is “known to be Boolean” if we can verify that the original goal is provably equivalent to the assertion that if all terms in the set are Boolean, then the goal holds. The notion “known to be Boolean” is conservative in the sense that there are generally sets of terms for which the above equivalent criteria hold and yet the sets of terms are not noted as as being “known to be Boolean.” However, ACL2 uses a number of tricks, including type-set (TYPE-SET^) reasoning and analysis of the structure of the top-level goal, to attempt to establish that a sufficiently inclusive set of terms is known to be Boolean.

From a practical standpoint, the algorithm determines a set of terms known to be Boolean; we allow ourselves to say that each term in this set is “known to be Boolean.” The algorithm assumes that these terms are indeed Boolean, and can make use of that assumption. For example, if t1 is known to be Boolean then the algorithm simplifies (IF t1 t nil) to t1; see (iv) in the discussion immediately below.

(B3) IF-lifting and the IF-lifting-for-IF loop

Suppose that one has a term (TERM^) of the form (f ... (IF test x y) ...), where f is a function symbol other than CONS. Then we say that “IF-lifting” test “from” this term produces the following term, which is provably equal to the given term.

     (if test
         (f ... x ...)  ; resulting true branch
         (f ... y ...)) ; resulting false branch

Here, we replace each argument of f of the form (IF test .. ..), for the same test, in the same way. In this case we say that “IF-lifting applies to” the given term, “yielding the test” test and with the “resulting two branches” displayed above. Whenever we apply IF-lifting, we do so for the available test that is least in the BDD term order (see (A1) above).

We consider arguments v of f that are “known to be Boolean” (see above) to be replaced by (IF v t nil) for the purposes of IF-lifting, i.e., before IF-lifting is applied.

There is one special case, however, for IF-lifting. Suppose that the given term is of the form (IF v y z) where v is a variable and is the test to be lifted out (i.e., it is least in the BDD term order among the potential tests). Moroever, suppose that neither y nor z is of the form (IF v W1 W2) for that same v. Then IF-lifting does not apply to the given term.

We may now describe the IF-lifting-for-IF loop, which applies to terms of the form (IF test tbr fbr) where the algorithm has already produced test, tbr, and fbr. First, if test is nil then we return fbr, while if test is a non-nil constant or a call of CONS then we return tbr. Otherwise, we see if IF-lifting applies. If IF-lifting does not apply, then we return (IF test tbr fbr). Otherwise, we apply IF-lifting to obtain a term of the form (IF x y z), by lifting out the appropriate test. Now we recursively apply the IF-lifting-for-IF loop to the term (IF x y z), unless any of the following special cases apply.

(i) If y and z are the same term, then return y.

(ii) Otherwise, if x and z are the same term, then replace z by nil before recursively applying IF-lifting-for-IF.

(iii) Otherwise, if x and y are the same term and y is known to be Boolean, then replace y by t before recursively applying IF-lifting-for-IF.

(iv) If z is nil and either x and y are the same term or x is “known to be Boolean” and y is t, then return x.

NOTE: When a variable x is known to be Boolean, it is easy to see that the form (IF x t nil) is always reduced to x by this algorithm.

(B4) The ACL2 BDD algorithm We are now ready to present the BDD algorithm for ACL2. It is given an ACL2 term (TERM^), x, as well as an association list va that maps variables to terms, including all variables occurring in x. We maintain the invariant that whenever a variable is mapped by va to a term, that term has already been constructed by the algorithm, except: initially va maps every variable occurring in the top-level term to itself. The algorithm proceeds as follows. We implicitly ordain that whenever the BDD algorithm attempts to create a term (TERM^) that is not a BDD (BDD^) term (as defined above in (A2)), it aborts instead. Thus, whenever the algorithm completes without aborting, it creates a BDD (BDD^) term.

If x is a variable, return the result of looking it up in va.

If x is a constant, return x.

If x is of the form (IF test tbr fbr), then first run the algorithm on test with the given va to obtain test'. If test' is nil, then return the result fbr' of running the algorithm on fbr with the given va. If test' is a constant other than nil, or is a call of CONS, then return the result tbr' of running the algorithm on tbr with the given va. If tbr is identical to fbr, return tbr. Otherwise, return the result of applying the IF-lifting-for-IF loop (described above) to the term (IF test' tbr' fbr').

If x is of the form (IF* test tbr fbr), then compute the result exactly as though IF (IF^) were used rather than IF* (IF*^), except that if test' is not a constant or a call of CONS (see paragraph above), then abort the BDD computation. Informally, the tests of IF* (IF*^) terms are expected to “resolve.” NOTE: This description shows how IF* (IF*^) can be used to implement conditional rewriting in the BDD algorithm.

If x is a LAMBDA expression ((LAMBDA vars body) . args) (which often corresponds to a LET (LET^) term; see Section 10.141 [LET], page 498), then first form an alist va' by binding each v in vars to the result of running the algorithm on the corresponding member of args, with the current alist va. Then, return the result of the algorithm on body in the alist va'.

Otherwise, x is of the form (f x1 x2 ... xn), where f is a function symbol other than IF (IF^) or IF* (IF*^). In that case, let xi' be the result of running the algorithm on xi, for i from 1 to n, using the given alist va. First there are a few special cases. If f is EQUAL (EQUAL^) then we return t if x1' is syntactically identical to x2' (where this test is very fast; see (B6) below); we return x1' if it is known to be Boolean and x2' is t; and similarly, we return x2' if it is known to be Boolean and x1' is t. Next, if each xi' is a constant and the :executable-counterpart (EXECUTABLE-COUNTERPART^) of f is enabled, then the result is obtained by computation. Next, if f is BOOLEANP (BOOLEANP^) and x1' is known to be Boolean, t is returned. Otherwise, we proceed as follows, first possibly swapping the arguments if they are out of (the BDD term) order and if f is known to be commutative (see below). If a BDD rewrite rule (as defined above) matches the term (f x1'... xn'), then the most recently stored such rule is applied. If there is no such match and f is a BDDconstructor, then we return (f x1'... xn'). Otherwise, if a BDD definition rule matches this term, then the most recently stored such rule (which will usually be the original definition for most users) is applied. If none of the above applies and neither does IF-lifting, then we return (f x1'... xn'). Otherwise we apply IF-lifting to (f x1'... xn') to obtain a term (IF test tbr fbr); but we aren’t done yet. Rather, we run the BDD algorithm (using the same alist) on tbr and fbr to obtain terms tbr' and fbr', and we return (IF test tbr' fbr') unless tbr' is syntactically identical to fbr', in which case we return tbr'.

When is it the case that, as said above, “f is known to be commutative”? This happens when an enabled rewrite rule is of the form (EQUAL (f X Y) (f Y X)). Regarding swapping the arguments in that case: recall that we may assume very little about the BDD term order, essentially only that we swap the two arguments when the second is a constant and the first is not, for example, in (+ x 1). Other than that situation, one cannot expect to predict accurately when the arguments of commutative operators will be swapped.

(B5) Soundness and Completeness of the ACL2 BDD algorithm

Roughly speaking, “soundness” means that the BDD algorithm should give correct answers, and “completeness” means that it should be powerful enough to prove all true facts. Let us make the soundness claim a little more precise, and then we’ll address completeness under suitable hypotheses.

Claim (Soundness). If the ACL2 BDD algorithm runs to completion on an input term t0, then it produces a result that is provably equal to t0.

We leave the proof of this claim to the reader. The basic idea is simply to check that each step of the algorithm preserves the meaning of the term under the bindings in the given alist.

Let us start our discussion of completeness by recalling the theorem proved above in (A4).

Theorem. Suppose that t1 and t2 are canonical BDD terms that contain no function symbols other than IF and CONS. Also suppose that (EQUAL t1 t2) is a theorem. Then t1 and t2 are syntactically identical.

Below we show how this theorem implies the following completeness property of the ACL2 BDD algorithm. We continue to assume that CONS is the only BDD-constructor.

Claim (Completeness). Suppose that t1 and t2 are provably equal terms, under the assumption that all their variables are known to be Boolean. Assume further that under this same assumption, top-level runs of the ACL2 BDD algorithm on these terms return terms that contain only the function symbols IF and CONS. Then the algorithm returns the same term for both t1 and t2, and the algorithm reduces (EQUAL t1 t2) to t.

Why is this claim true? First, notice that the second part of the conclusion follows immediately from the first, by definition of the algorithm. Next, notice that the terms u1 and u2 obtained by running the algorithm on t1 and t2, respectively, are provably equal to t1 and t2, respectively, by the Soundness Claim. It follows that u1 and u2 are provably equal to each other. Since these terms contain no function symbols other than IF or CONS, by hypothesis, the Claim now follows from the Theorem above together with the following lemma.

Lemma. Suppose that the result of running the ACL2 BDD algorithm on a top-level term t0 is a term u0 that contains only the function symbols IF and CONS, where all variables of t0 are known to be Boolean. Then u0 is a canonical BDD term.

Proof: left to the reader. Simply follow the definition of the algorithm, with a separate argument for the IF-lifting-for-IF loop.

Finally, let us remark on the assumptions of the Completeness Claim above. The assumption that all variables are known to be Boolean is often true; in fact, the system uses the forward-chaining rule boolean-listp-forward (you can see it using :pe (PE^)) to try to establish this assumption, if your theorem has a form such as the following.

     (let ((x (list x0 x1 ...))
           (y (list y0 y1 ...)))
       (implies (and (boolean-listp x)
                     (boolean-listp y))
                ...))

Moreover, the :BDD hint can be used to force the prover to abort if it cannot check that the indicated variables are known to be Boolean; see Section 8.43 [HINTS], page 319.

Finally, consider the effect in practice of the assumption that the terms resulting from application of the algorithm contain calls of IF and CONS only. Typical use of BDDs in ACL2 takes place in a theory (see Chapter 16 [THEORIES], page 775) in which all relevant non-recursive function symbols are enabled and all recursive function symbols possess enabled BDD rewrite rules that tell them how open up. For example, such a rule may say how to expand on a given function call’s argument that has the form (CONS a x), while another may say how to expand when that argument is nil). (See for example the rules append-cons and append-nil in the documentation for IF* (IF*^).) We leave it to future work to formulate a theorem that guarantees that the BDD algorithm produces terms containing calls only of IF and CONS assuming a suitably “complete” collection of rewrite rules.

(B6) Efficiency considerations

Following Bryant’s algorithm, we use a graph representation of term (TERM^)s created by the BDD algorithm’s computation. This representation enjoys some important properties.

(Time efficiency) The test for syntactic equality of BDD terms is very fast.

(Space efficiency) Equal BDD data structures are stored identically in memory.

Implementation note. The representation actually uses a sort of hash table for BDD terms that is implemented as an ACL2 1-dimensional array. See Section 8.6 [ARRAYS], page 241. In addition, we use a second such hash table to avoid recomputing the result of applying a function symbol to the result of running the algorithm on its arguments. We believe that these uses of hash tables are standard. They are also discussed in Moore’s paper on BDDs; see Chapter 2 [BDD], page 71 for the reference.

2.2 BDD-INTRODUCTION

BDD-INTRODUCTION examples illustrating the use of BDDs in ACL2

See Chapter 2 [BDD], page 71 for a brief introduction to BDDs in ACL2 and for pointers to other documentation on BDDs in ACL2. Here, we illustrate the use of BDDs in ACL2 by way of some examples. For a further example, see Section 2.3 [IF*], page 86.

Let us begin with a really simple example. (We will explain the :bdd hint (:vars nil) below.)

     ACL2 !>(thm (equal (if a b c) (if (not a) c b))
                 :hints (("Goal" :bdd (:vars nil)))) ; Prove with BDDs
     [Note:  A hint was supplied for our processing of the goal above.
     Thanks!]
     But simplification with BDDs (7 nodes) reduces this to T, using the

:definitions EQUAL and NOT.
Q.E.D.
Summary
Form:  ( THM ...)
Rules: ((:DEFINITION EQUAL) (:DEFINITION NOT))
Warnings:  None
Time:  0.18 seconds (prove: 0.05, print: 0.02, other: 0.12)
Proof succeeded.
ACL2 !>

The :bdd hint (:vars nil) indicates that BDDs are to be used on the indicated goal, and that any so-called “variable ordering” may be used: ACL2 may use a convenient order that is far from optimal. It is beyond the scope of the present documentation to address the issue of how the user may choose good variable orderings. Someday our implementation of BDDs may be improved to include heuristically-chosen variable orderings rather than rather random ones.

Here is a more interesting example.

(defun v-not (x)
; Complement every element of a list of Booleans.
  (if (consp x)
      (cons (not (car x)) (v-not (cdr x)))
    nil))
; Now we prove a rewrite rule that explains how to open up v-not on
; a consp.
(defthm v-not-cons
  (equal (v-not (cons x y))
         (cons (not x) (v-not y))))
; Finally, we prove for 7-bit lists that v-not is self-inverting.
(thm
 (let ((x (list x0 x1 x2 x3 x4 x5 x6)))
   (implies (boolean-listp x)
            (equal (v-not (v-not x)) x)))
 :hints (("Goal" :bdd
                 ;; Note that this time we specify a variable order.
                 (:vars (x0 x1 x2 x3 x4 x5 x6)))))

It turns out the the variable order doesn’t seem to matter in this example; using several orders we found that 30 nodes were created, and the proof time was about 1/10 of a second on a (somewhat enhanced) Sparc 2. The same proof took about a minute and a half without any :bdd hint! This observation is a bit misleading perhaps, since the theorem for arbitrary x,

     (thm
      (implies (boolean-listp x)
               (equal (v-not (v-not x)) x)))

only takes about 1.5 times as long as the :bdd proof for 7 bits, above! Nevertheless, BDDs can be very useful in reducing proof time, especially when there is no regular structure to facilitate proof by induction, or when the induction scheme is so complicated to construct that significant user effort is required to get the proof by induction to go through.

Finally, consider the preceding example, with a :bdd hint of (say) (:vars nil), but with the rewrite rule v-not-cons above disabled. In that case, the proof fails, as we see below. That is because the BDD algorithm in ACL2 uses hypothesis-free :rewrite (REWRITE^) rules, :executablecounterpart (EXECUTABLE-COUNTERPART^)s, and nonrecursive definitions, but it does not use recursive definitions.

Notice that when we issue the (show-bdd) command, the system’s response clearly shows that we need a rewrite rule for simplifying terms of the form (v-not (cons ...)).

     ACL2 !>(thm
             (let ((x (list x0 x1 x2 x3 x4 x5 x6)))
               (implies (boolean-listp x)
                        (equal (v-not (v-not x)) x)))
             :hints (("Goal" :bdd (:vars nil)
                      :in-theory (disable v-not-cons))))
     [Note:  A hint was supplied for our processing of the goal above.
     Thanks!]

     ACL2 Error in ( THM ...):  Attempted to create V-NOT node during BDD
     processing with an argument that is a call of a bdd-constructor,
     which would produce a non-BDD term (as defined in :DOC
     bdd-algorithm).  See :DOC show-bdd.

     Summary
     Form:  ( THM ...)
     Rules: NIL
     Warnings:  None
     Time:  0.58 seconds (prove: 0.13, print: 0.00, other: 0.45)

******** FAILED ********  See :DOC failure  ******** FAILED ********
ACL2 !>(show-bdd)
BDD computation on Goal yielded 17 nodes.
==============================
BDD computation was aborted on Goal, and hence there is no
falsifying assignment that can be constructed.  Here is a backtrace
of calls, starting with the top-level call and ending with the one
that led to the abort.  See :DOC show-bdd.
(LET ((X (LIST X0 X1 X2 X3 X4 X5 ...)))
     (IMPLIES (BOOLEAN-LISTP X)
              (EQUAL (V-NOT (V-NOT X)) X)))
  alist: ((X6 X6) (X5 X5) (X4 X4) (X3 X3) (X2 X2) (X1 X1) (X0 X0))
(EQUAL (V-NOT (V-NOT X)) X)
  alist: ((X (LIST X0 X1 X2 X3 X4 X5 ...)))
(V-NOT (V-NOT X))
  alist: ((X (LIST X0 X1 X2 X3 X4 X5 ...)))
(V-NOT X)
  alist: ((X (LIST X0 X1 X2 X3 X4 X5 ...)))
ACL2 !>

The term that has caused the BDD algorithm to abort is thus (V-NOT X), where X has the value

(LIST X0 X1 X2 X3 X4 X5 ...), i.e., (CONS X0 (LIST X1 X2 X3 X4 X5 ...)). Thus, we see

the utility of introducing a rewrite rule to simplify terms of the form (V-NOT (CONS ...)). The moral of this story is that if you get an error of the sort shown above, you may find it useful to execute the command (show-bdd) and use the result as advice that suggests the left hand side of a rewrite rule.

Here is another sort of failed proof. In this version we have omitted the hypothesis that the input is a bit vector. Below we use show-bdd to see what went wrong, and use the resulting information to construct a counterexample. This failed proof corresponds to a slightly modified input theorem, in which x is bound to the 4-bit list (list x0 x1 x2 x3).

ACL2 !>(thm
        (let ((x (list x0 x1 x2 x3)))
          (equal (v-not (v-not x)) x))
        :hints (("Goal" :bdd
                 ;; This time we do not specify a variable order.
                 (:vars nil))))

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

ACL2 Error in ( THM ...):  The :BDD hint for the current goal has
successfully simplified this goal, but has failed to prove it.
Consider using (SHOW-BDD) to suggest a counterexample; see :DOC
show-bdd.

Summary
Form:  ( THM ...)
Rules: NIL
Warnings:  None
Time:  0.18 seconds (prove: 0.07, print: 0.00, other: 0.12)
******** FAILED ********  See :DOC failure  ******** FAILED ********
ACL2 !>(show-bdd)
BDD computation on Goal yielded 73 nodes.
==============================
Falsifying constraints:
((X0 "Some non-nil value")
 (X1 "Some non-nil value")
 (X2 "Some non-nil value")
 (X3 "Some non-nil value")
 ((EQUAL 'T X0) T)
 ((EQUAL 'T X1) T)
 ((EQUAL 'T X2) T)
 ((EQUAL 'T X3) NIL))
==============================
Term obtained from BDD computation on Goal:
(IF X0
    (IF X1
        (IF X2 (IF X3 (IF # # #) (IF X3 # #))
            (IF X2 'NIL (IF X3 # #)))
        (IF X1 'NIL
            (IF X2 (IF X3 # #) (IF X2 # #))))
    (IF X0 'NIL
        (IF X1 (IF X2 (IF X3 # #) (IF X2 # #))
            (IF X1 'NIL (IF X2 # #)))))
ACL2 Query (:SHOW-BDD):  Print the term in full?  (N, Y, W or ?):
n ; I've seen enough.  The assignment shown above suggests

       ; that if we bind x3 to a non-nil value other than T,
       ; and bind x0, x1, and x2 to t, then we expect to get a
       ; counterexample.
     ACL2 !>(let ((x0 t) (x1 t) (x2 t) (x3 7))
              (let ((x (list x0 x1 x2 x3)))
                ;; Let's use LIST instead of EQUAL to see how the two
                ;; lists differ.
                (list (v-not (v-not x)) x)))
     ((T T T T) (T T T 7))
     ACL2 !>

See Section 2.3 [IF*], page 86 for another example.

2.3 IF*

IF* for conditional rewriting with BDDs

The function IF* is defined to be IF (IF^), but it is used in a special way by ACL2’s BDD (BDD^) package.

As explained elsewhere (see Section 2.1 [BDD-ALGORITHM], page 71), ACL2’s BDD (BDD^) algorithm gives special treatment to term (TERM^)s of the form (IF* TEST TBR FBR). In such cases, the algorithm simplifies TEST first, and the result of that simplification must be a constant (normally t or nil, but any non-nil explicit value is treated like t here). Otherwise, the algorithm aborts.

Thus, IF* may be used to implement a sort of conditional rewriting for ACL2’s BDD (BDD^) package, even though this package only nominally supports unconditional rewriting. The following contrived example should make this point clear.

Suppose that we want to prove that (nthcdr (length x) (append x y)) is equal to y, but that we would be happy to prove this only for lists having length 4. We can state such a theorem as follows.

     (let ((x (list x0 x1 x2 x3)))
       (equal (nthcdr (length x) (append x y))
              y))

If we want to prove this formula with a :BDD (BDD^) hint, then we need to have appropriate rewrite rules around. First, note that LENGTH is defined as follows (try :PE (PE^) LENGTH (LENGTH^)):

     (length x)
      =
     (if (stringp x)
         (len (coerce x 'list))
         (len x))

Since BDD (BDD^)-based rewriting is merely very simple unconditional rewriting (see Section 2.1 [BDD-ALGORITHM], page 71), we expect to have to prove a rule reducing STRINGP (STRINGP^) of a CONS (CONS^):

     (defthm stringp-cons
       (equal (stringp (cons x y))
              nil))

Now we need a rule to compute the LEN of X, because the definition of LEN is recursive and hence not used by the BDD (BDD^) package.

     (defthm len-cons
       (equal (len (cons a x))
              (1+ (len x))))

We imagine this rule simplifying (LEN (LIST X0 X1 X2 X3)) in terms of (LEN (LIST X1 X2 X3)), and so on, and then finally (LEN nil) should be computed by execution (see Section 2.1 [BDD-ALGORITHM], page 71).

We also need to imagine simplifying (APPEND X Y), where still X is bound to (LIST X0 X1 X2 X3). The following two rules suffice for this purpose (but are needed, since APPEND (APPEND^), actually BINARY-APPEND (BINARY-APPEND^), is recursive).

     (defthm append-cons
       (equal (append (cons a x) y)
              (cons a (append x y))))
     (defthm append-nil
       (equal (append nil x)
              x))

Finally, we imagine needing to simplify calls of NTHCDR (NTHCDR^), where the the first argument is a number (initially, the length of (LIST X0 X1 X2 X3), which is 4). The second lemma below is the traditional way to accomplish that goal (when not using BDDs), by proving a conditional rewrite rule. (The first lemma is only proved in order to assist in the proof of the second lemma.)

     (defthm fold-constants-in-+
       (implies (and (syntaxp (quotep x))
                     (syntaxp (quotep y)))
                (equal (+ x y z)
                       (+ (+ x y) z))))
     (defthm nthcdr-add1-conditional
       (implies (not (zp (1+ n)))
                (equal (nthcdr (1+ n) x)
                       (nthcdr n (cdr x)))))

The problem with this rule is that its hypothesis makes it a conditional rewrite (REWRITE^) rule, and conditional rewrite rules are not used by the BDD (BDD^) package. (See Section 2.1 [BDD-ALGORITHM], page 71 for a discussion of “BDD rules.”) (Note that the hypothesis cannot simply be removed; the resulting formula would be false for n = -1 and x = '(a), for example.) We can solve this problem by using IF*, as follows; comments follow.

     (defthm nthcdr-add1
       (equal (nthcdr (+ 1 n) x)
              (if* (zp (1+ n))
                   x
                   (nthcdr n (cdr x)))))

How is nthcdr-add1 applied by the BDD (BDD^) package? Suppose that the BDD (BDD^) computation encounters a term (TERM^) of the form (NTHCDR (+ 1 N) X). Then the BDD (BDD^) package will apply the rewrite (REWRITE^) rule nthcdr-add1. The first thing it will do when attempting to simplify the right hand side of that rule is to attempt to simplify the term (ZP (1+ N)). If N is an explicit number (which is the case in the scenario we envision), this test will reduce (assuming the executable counterparts of ZP (ZP^) and BINARY-+ (BINARY-+^) are enable (ENABLE^)d) to t or to nil. In fact, the lemmas above (not including the lemma nthcdr-add1-conditional) suffice to prove our goal:

     (thm (let ((x (list x0 x1 x2 x3)))
            (equal (nthcdr (length x) (append x y))
                   y))
          :hints (("Goal" :bdd (:vars nil))))

If we execute the following form that disables the definition and executable counterpart of the function ZP (ZP^)

(in-theory (disable zp (zp)))

before attempting the proof of the theorem above, we can see more clearly the point of using IF*. In this case, the prover makes the following report.

ACL2 Error in ( THM ...):  Unable to resolve test of IF* for term
(IF* (ZP (+ 1 N)) X (NTHCDR N (CDR X)))
under the bindings
((X (CONS X0 (CONS X1 (CONS X2 #)))) (N '3))
-- use SHOW-BDD to see a backtrace.

If we follow the advice above, we can see rather clearly what happened. See Section 2.4 [SHOW-BDD], page 90.

ACL2 !>(show-bdd)
BDD computation on Goal yielded 21 nodes.
==============================
BDD computation was aborted on Goal, and hence there is no
falsifying assignment that can be constructed.  Here is a backtrace
of calls, starting with the top-level call and ending with the one
that led to the abort.  See :DOC show-bdd.
(LET ((X (LIST X0 X1 X2 X3)))
     (EQUAL (NTHCDR (LENGTH X) (APPEND X Y)) Y))
  alist: ((Y Y) (X3 X3) (X2 X2) (X1 X1) (X0 X0))
(NTHCDR (LENGTH X) (APPEND X Y))
  alist: ((X (LIST X0 X1 X2 X3)) (Y Y))
(IF* (ZP (+ 1 N)) X (NTHCDR N (CDR X)))
  alist: ((X (LIST* X0 X1 X2 X3 Y)) (N 3))
ACL2 !>

Each of these term-alist pairs led to the next, and the test of the last one, namely (ZP (+ 1 N)) where N is bound to 3, was not simplified to t or to nil.

What would have happened if we had used IF (IF^) in place of IF* in the rule nthcdr-add1? In that case, if ZP and its executable counterpart were disabled then we would be put into an infinite loop! For, each time a term of the form (NTHCDR k V) is encountered by the BDD package (where k is an explicit number), it will be rewritten in terms of (NTHCDR k-1 (CDR V)). We would prefer that if for some reason the term (ZP (+ 1 N)) cannot be decided to be t or to be nil, then the BDD computation should simply abort.

Even if there were no infinite loop, this kind of use of IF* is useful in order to provide feedback of the form shown above whenever the test of an IF term fails to simplify to t or to nil.

2.4 SHOW-BDD

SHOW-BDD inspect failed BDD proof attempts

Attempts to use BDDs (see Chapter 2 [BDD], page 71), using :bdd (BDD^) hints (HINTS^), can fail for various reasons. Sometimes it is useful to explore such failures. To do so, one may simply execute the form

     (show-bdd)

inside the ACL2 loop. The system’s response is generally self-explanatory. Perhaps you have already seen show-bdd used in some examples (see Section 2.2 [BDD-INTRODUCTION], page 81 and see Section 2.3 [IF*], page 86). Here we give some details about show-bdd.

(Show-bdd) prints the goal to which the BDD procedure was applied and reports the number of nodes created during the BDD (BDD^) computation, followed by additional information depending on whether or not the computation ran to completion or aborted (for reasons explained elsewhere; see Section 2.1 [BDD-ALGORITHM], page 71). If the computation did abort, a backtrace is printed that should be useful in understanding where the problem lies. Otherwise, (show-bdd) prints out “falsifying constraints.” This list of pairs associates term (TERM^)s with values and suggests how to construct a binding list for the variables in the conjecture that will falsify the conjecture. It also prints out the term (TERM^) that is the result of simplifying the input term (TERM^). In each of these cases, parts of the object may be hidden during printing, in order to avoid creating reams of uninteresting output. If so, the user will be queried about whether he wishes to see the entire object (alist or term (TERM^)), which may be quite large. The following responses are legal:

w — Walk around the object with a structure editor

t — Print the object in full

nil — Do not print any more of the object

Show-bdd actually has four optional arguments, probably rarely used. The general form is

     (show-bdd goal-name goal-ans falsifying-ans term-ans)

where goal-name is the name of the goal on which the :bdd (BDD^) hint was used (or, nil if the system should find such a goal), goal-ans is the answer to be used in place of the query for whether to print the input goal in full, falsifying-ans is the answer to be used in place of the query for whether to print the falsifying constraints in full, and term-ans is the answer to be used in place of the query for whether to print the resulting term (TERM^) in full.

92 ACL2 Version 1.9

3 BOOKS

BOOKS files of ACL2 event forms

A “book” is a file of ACL2 events (EVENTS^) that have been certified as admissible. Using include-book (INCLUDE-BOOK^) you can construct a new logical world (WORLD^) by assuming the events (EVENTS^) in any number of mutually compatible books. Relevant documented topics are listed below. Following this list is a “guided tour” through the topics.

* BOOK-CONTENTS:: restrictions on the forms inside books (BOOKS^)

* BOOK-EXAMPLE:: how to create, certify, and use a simple book

* BOOK-NAME:: conventions associated with book names

* CBD:: connected book directory string

* CERTIFICATE:: how a book is known to be admissible and where its defpkg (DEFPKG^)s reside * CERTIFY-BOOK:: how to produce a certificate (CERTIFICATE^) for a book

* FULL-BOOK-NAME:: book naming conventions assumed by ACL2

* KEEP:: how we know if include-book (INCLUDE-BOOK^) read the correct files

* PATHNAME:: introduction to filename conventions in ACL2

* PORTCULLIS:: the gate guarding the entrance to a certified book

* SET-CBD:: to set the connected book directory

* UNCERTIFIED-BOOKS:: invalid certificate (CERTIFICATE^)s and uncertified books (BOOKS^)

Related topics other than immediate subtopics:

* INCLUDE-BOOK:: load the events (EVENTS^) in a file

Introduction.

A “book” is a file of ACL2 forms. Books are prepared entirely by the user of the system, i.e., they are “source” files not “object” files. Some of the forms in a book are marked local (LOCAL^) and the others are considered “non-local.”

Include-book (INCLUDE-BOOK^) lets you load a book into any ACL2 world (WORLD^). If completed without error, the inclusion of a book extends the logic of the host world (WORLD^) by the addition of just the non-local events (EVENTS^) in the book. You may extend the world (WORLD^) by successively including a variety of books to obtain the desired collection of definitions and rules. Unless name conflicts occur (which are detected and signalled) inclusion of a book is consistency preserving provided the book itself is consistent as discussed later. However, includebook (INCLUDE-BOOK^) merely assumes the validity of the events (EVENTS^) in a book; if you include a book that contains an inconsistency (e.g., an inadmissible definition) then the resulting theory is inconsistent.

It is possible to “certify” a book, with certify-book (CERTIFY-BOOK^), guaranteeing that the error-free inclusion of the certified forms will produce a consistent extension of a consistent logic. Certification processes both the local (LOCAL^) and non-local forms, so you can mark as local (LOCAL^) those events (EVENTS^) you need for certification that you want to hide from users of the book (e.g., hacks, crocks, and kludges on the way to a good set of :rewrite (REWRITE^) rules). Certification can also “compile” a book, thereby speeding up the execution of the functions defined within it. The desire to compile books is largely responsible for the restrictions we put on the forms allowed in books.

Extensive documentation (DOCUMENTATION^) is available on the various aspects of books. We recommend that you read it all before using books. It has been written so as to make sense when read in a certain linear sequence, called the “guided tour”, though in general you may browse through it randomly. If you are on the guided tour, you should next read the documentation (DOCUMENTATION^) on book-example (see Section 3.2 [BOOK-EXAMPLE], page 96).

3.1 BOOK-CONTENTS

BOOK-CONTENTS restrictions on the forms inside books (BOOKS^)

     Example Book:
     ; This book defines my app function and the theorem that it is
     ; associative.  One irrelevant help lemma is proved first but
     ; it is local and so not seen by include-book.  I depend on the
     ; inferior book "weird-list-primitives" from which I get
     ; definitions of hd and tl.
     (in-package "MY-PKG")
     (include-book "weird-list-primitives")
     (defun app (x y) (if (consp x) (cons (hd x) (app (tl x) y)) y))
     (local
      (defthm help-lemma
        (implies (true-listp x) (equal (app x nil) x))))
     (defthm app-is-associative
       (equal (app (app a b) c) (app a (app b c))))

The first form in a book must be (in-package "pkg") where "pkg" is some package name known to ACL2 whenever the book is certified. The rest of the forms in a book are embedded event forms, i.e., defun (DEFUN^)s, defthm (DEFTHM^)s, etc., some of which may be marked local (LOCAL^). See Section 8.27 [EMBEDDED-EVENT-FORM], page 286. The usual Common Lisp commenting conventions are provided. Note that since a book consists of embedded event forms, we can talk about the “local (LOCAL^)” and “non-local” events (EVENTS^) of a book.

Because in-package (IN-PACKAGE^) is not an embedded event form, the only in-package (IN-PACKAGE^) in a book is the initial one. Because defpkg (DEFPKG^) is not an embedded event form, a book can never contain a defpkg (DEFPKG^) form. Because include-book (INCLUDE-BOOK^) is an embedded event form, books (BOOKS^) may contain references to other books (BOOKS^). This makes books (BOOKS^) structured objects.

When the forms in a book are read from the file, they are read with current-package (CURRENT-PACKAGE^) set to the package named in the in-package (IN-PACKAGE^) form at the top of the file. The effect of this is that all symbols are intern (INTERN^)ed in that package, except those whose packages are given explicitly with the “::” notation. For example, if a book begins with (in-package "ACL2-X") and then contains the form

       (defun fn (x)
         (acl2::list 'car x))

then defun (DEFUN^), fn, x, and car (CAR^) are all intern (INTERN^)ed in the "ACL2-X" package. I.e., it is as though the following form were read instead:

       (acl2-x::defun acl2-x::fn (acl2-x::x)
           (acl2::list 'acl2-x::car acl2-x::x)).

Of course, acl2-x::defun would be the same symbol as acl2::defun if the "ACL2-X" package

imported acl2::defun.

If each book has its own unique package name and all the names defined within the book are in that package, then name clashes between books (BOOKS^) are completely avoided. This permits the construction of useful logical world (WORLD^)s by the successive inclusion of many books (BOOKS^). Although it is often too much trouble to manage multiple packages, their judicious use is a way to minimize name clashes. Often, a better way is to use local; see Section 6.21 [LOCAL], page 191.

How does include-book (INCLUDE-BOOK^) know the definitions of the packages used in a book, since defpkg (DEFPKG^)s cannot be among the forms? More generally, how do we know that the forms in a book will be admissible in the host logical world (WORLD^) of an include-book (INCLUDE-BOOK^)? See Section 3.5 [CERTIFICATE], page 104 for answers to these questions.

3.2 BOOK-EXAMPLE

BOOK-EXAMPLE how to create, certify, and use a simple book

Suppose you have developed a sequence of admissible events (EVENTS^) which you want to turn into a book. We call this “publishing” the book. This note explains how to do that.

A key idea of books (BOOKS^) is that they are “incremental” in the sense that when you include a book in a host logical world (WORLD^), the world (WORLD^) is incrementally extended by the results established in that book. This is allowed only if every name defined by the incoming book is either new or is already identically defined. See Section 8.78 [REDUNDANT-EVENTS], page 361. This is exactly the same problem faced by a programmer who wishes to provide a utility to other people: how can he make sure he doesn’t create name conflicts? The solution, in Common Lisp, is also the same: use packages. While books (BOOKS^) and packages have a very tenuous formal connection (every book must start with an in-package (IN-PACKAGE^)), the creation of a book is intimately concerned with the package issue. Having motivated what would otherwise appear as an unnecessary fascination with packages below, we now proceed with a description of how to publish a book.

Just to be concrete, let’s suppose you have already gotten ACL2 to accept the following sequence of command (COMMAND^)s, starting in the ACL2 initial state (STATE^).

        (defpkg "ACL2-MY-BOOK"
                (union-eq *common-lisp-symbols-from-main-lisp-package*
                          *acl2-exports*))
        (in-package "ACL2-MY-BOOK")
        (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))
        (defthm rev-app-hack
          (equal (rev (app a (list x))) (cons x (rev a))))
        (defthm rev-rev
          (implies (acl2::true-listp x) (equal (rev (rev x)) x)))

Observe that the first form above defines a package (which imports the symbols defined in CLTL such as if (IF^) and cons (CONS^) and the symbols used to command (COMMAND^) ACL2 such as defun (DEFUN^) and defthm (DEFTHM^)). The second form selects that package as the current one. All subsequent forms are read into that package. The remaining forms are just event forms: defun (DEFUN^)s and defthm (DEFTHM^)s in this case.

Typically you would have created a file with Emacs containing these forms and you will have submitted each of them interactively to ACL2 to confirm that they are all admissible. That interactive verification should start in ACL2’s initial world (WORLD^) — although you might, of course, start your sequence of events (EVENTS^) with some include-book (INCLUDE-BOOK^)s to build a more elaborate world (WORLD^).

The first step towards publishing a book containing the results above is to create a file that starts with the in-package (IN-PACKAGE^) and then contains the rest of the forms. Let’s call that file "my-book.lisp". The name is unimportant, except it must end with ".lisp". If there are events (EVENTS^) that you do not wish to be available to the user of the book — e.g., lemmas you proved on your way toward proving the main ones — you may so mark them by enclosing them in local (LOCAL^) forms. See Section 6.21 [LOCAL], page 191. Let us suppose you wish to hide rev-app-hack above. You may also add standard Lisp comments to the file. The final content of

"my-book.lisp" might be:
      ; This book contains my app and rev functions and the theorem
      ; that rev is its own inverse.
        (in-package "ACL2-MY-BOOK")
        (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))
      ; The following hack is not exported.
        (local (defthm rev-app-hack
          (equal (rev (app a (list x))) (cons x (rev a)))))
        (defthm rev-rev
          (implies (acl2::true-listp x) (equal (rev (rev x)) x)))

The file shown above is the book. By the time this note is done you will have seen how to certify that the book is correct, how to compile it, and how to use it in other host world (WORLD^)s. Observe that the defpkg (DEFPKG^) is not in the book. It cannot be: Common Lisp compilers disagree on how to treat new package definitions appearing in files to be compiled.

Since a book is just a source file typed by the user, ACL2 provides a mechanism for checking that the events (EVENTS^) are all admissible and then marking the file as checked. This is called certification. To certify "my-book.lisp" you should first get into ACL2 with an initial world (WORLD^). Then, define the package needed by the book, by typing the following defpkg (DEFPKG^) to the ACL2 prompt (PROMPT^):

     ACL2 !>(defpkg "ACL2-MY-BOOK"
                    (union-eq *common-lisp-symbols-from-main-lisp-package*
                              *acl2-exports*))

Then execute the command (COMMAND^):

     ACL2 !>(certify-book "my-book" 1 t) ; the `t' is in fact the default

Observe that you do not type the ".lisp" part of the file name. For purposes of books (BOOKS^), the book’s name is "my-book" and by the time all is said and done, there will be several extensions in addition to the ".lisp" extension associated with it.

The 1 tells certify-book (CERTIFY-BOOK^) that you acknowledge that there is one command in this “certification world (WORLD^)” (namely the defpkg (DEFPKG^)). To use the book, any prospective host world (WORLD^) must be extended by the addition of whatever command (COM-MAND^)s occurred before certification. It would be a pity to certify a book in a world (WORLD^) containing junk because that junk will become the “portcullis (PORTCULLIS^)” guarding entrance to the book. The t above tells certify-book (CERTIFY-BOOK^) that you wish to compile "mybook.lisp" also. Certify-book (CERTIFY-BOOK^) makes many checks but by far the most important and time-consuming one is that it “proves” every event in the file.

When certify-book (CERTIFY-BOOK^) is done it will have created two new files. The first will be called "my-book.cert" and contains the “certificate (CERTIFICATE^)” attesting to the admissibility of the events (EVENTS^) in "my-book.lisp". The certificate (CERTIFICATE^) contains the defpkg (DEFPKG^) and any other forms necessary to construct the certification world (WORLD^). It also contains various check sums used to help you keep track of which version of "my-book.lisp" was certified.

The second file created by certify-book (CERTIFY-BOOK^) is the compiled version of "mybook.lisp" and will have a name that is assigned by the host compiler (e.g., "my-book.o" in

AKCL, "my-book.lbin" or "my-book.sbin" in Lucid). Certify-book (CERTIFY-BOOK^) will

also load this object file. When certify-book (CERTIFY-BOOK^) is done, you may throw away the logical world (WORLD^) it created, for example by executing the command (COMMAND^)

:u.

To use the book later in any ACL2 session, just execute the event (include-book "my-book"). This will do the necessary defpkg (DEFPKG^), load the non-local (LOCAL^) events (EVENTS^) in "my-book.lisp" and then load the compiled code for the non-local functions defined in that file. Checks are made to insure that the certificate (CERTIFICATE^) file exists and describes the version of "my-book.lisp" that is read. The compiled code is loaded if and only if it exists and has a later write date than the source file.

Since include-book (INCLUDE-BOOK^) is itself an event, you may put such forms into other books (BOOKS^). Thus it is possible for the inclusion of a single book to lead to the inclusion of many others. The check sum information maintained in certificate (CERTIFICATE^)s helps deal with the version control problem of the referenced books (BOOKS^). I.e., if this version of "mybook" is used during the certification of "your-book", then the certificate (CERTIFICATE^) for "your-book" includes the check sum of this version of "my-book". If a later (include-book "yourbook") finds a version of "my-book" with a different check sum, an error is signalled. But check sums are not perfect and the insecurity of the host file system prevents ACL2 from guaranteeing the logical soundness of an include-book (INCLUDE-BOOK^) event, even for a book that appears to have a valid certificate (CERTIFICATE^) (they can be forged, after all). (See Section 3.5 [CERTIFICATE], page 104 for further discussion.)

This concludes the example of how to create, certify and use a book. If you wish, you could now review the documentation (DOCUMENTATION^) for book-related topics (see Chapter 3 [BOOKS], page 93) and browse through them. They’ll probably make sense in this context. Alternatively, you could continue the “guided tour” through the rest of the documentation (DOCUMENTATION^) of books (BOOKS^). See Section 3.3 [BOOK-NAME], page 99, following the pointer given at the conclusion.

3.3 BOOK-NAME

BOOK-NAME conventions associated with book names

     Examples:
     "list-processing"
     "/usr/home/smith/my-arith"

Book names are strings and lists that can be elaborated into file names. We elaborate book names by concatenating the “connected book directory” (see Section 3.4 [CBD], page 102) string on the left and some “extension,” such as ".lisp", on the right. However, the connected book directory is not added if the book name itself already represents an absolute file name. Furthermore, include-book (INCLUDE-BOOK^) and certify-book (CERTIFY-BOOK^) temporarily reset the connected book directory to be the directory of the book being processed. This allows include-book (INCLUDE-BOOK^) forms to use file names without explicit mention of the enclosing book’s directory. This in turn allows books (BOOKS^) (together with those that they include, using include-book (INCLUDE-BOOK^)) to be moved between directories while maintaining their certification and utility. (One does need to be careful about using absolute filenames (see Section 3.9 [PATHNAME], page 110) when of certifying books in worlds that have already included other books; see Section 3.10 [PORTCULLIS], page 113.)

You may wish to read elsewhere for details of ACL2 file name conventions (see Section 3.9 [PATH-NAME], page 110), for a discussion of the filename that is the result of the elaboration described here (see Section 3.7 [FULL-BOOK-NAME], page 108), and for details of the concept of the connected book directory (see Section 3.4 [CBD], page 102). For details of how include-book (INCLUDE-BOOK^) (see Section 6.20 [INCLUDE-BOOK], page 189) and certify-book (CERTIFY-BOOK^) (see Section 3.6 [CERTIFY-BOOK], page 106) use these concepts, see below.

Often a book name is simply the familiar name of the file. (See Section 3.7 [FULL-BOOK-NAME], page 108 for discussion of the notions of “directory string,” “familiar name,” and “extension”. These concepts are not on the guided tour through books (BOOKS^) and you should read them separately.) However, it is permitted for book names to include a directory or part of a directory name. Book names never include the extension, since ACL2 must routinely tack several different extensions onto the name during include-book (INCLUDE-BOOK^). For example, include-book (INCLUDE-BOOK^) uses the ".lisp", ".cert" and possibly the ".o" or ".lbin" extensions of the book name.

Book names are elaborated into full file names by include-book (INCLUDE-BOOK^) and certify-book (CERTIFY-BOOK^). This elaboration is sensitive to the “connected book directory.” The connected book directory is an absolute filename string (see Section 3.9 [PATHNAME], page 110) that is part of the ACL2 state (STATE^). (You may wish to see Section 3.4 [CBD], page 102 and to see Section 3.11 [SET-CBD], page 116 — note that these are not on the guided tour).

If a book name is an absolute filename string, ACL2 elaborates it simply by appending the desired extension to the right. If a book name is an absolute structured pathname, then it is first converted to an absolute pathname string (see Section 3.9 [PATHNAME], page 110) and ACL2 elaborates the result.

If a book name is a relative filename string, ACL2 appends the connected book directory on the left (eliminating the excess colon (:) character in the case of the Macintosh file system) and the desired extension on the right. If a book name is a relative structured pathname (PATHNAME^), it is first converted to a relative pathname (PATHNAME^) string and then ACL2 elaborates the result.

Note that it is possible that the book name includes some partial specification of the directory. For example, if the connected book directory is "/usr/home/smith/" then the book name "project/task-1/arith" is a book name that will be elaborated to

     "/usr/home/smith/project/task-1/arith.lisp".

Also, the structured book name

     (:relative "project" "task-1" "arith")

will be elaborated the same way. However, the directory separator (which is the character slash (/) in Unix (trademark of AT&T) and colon (:) on the Macintosh) may not appear in the final component of a structured book name; for example, (:relative "project" "task-1/arith") is illegal.

Observe that while the events (EVENTS^) in this "arith" book are being processed the connected book directory will temporarily be set to

     "/usr/home/smith/project/task-1/".

Thus, if the book requires other books (BOOKS^), e.g.,

     (include-book "naturals")

then it is not necessary to specify the directory on which they reside provided that directory is the same as the superior book.

This inheritance of the connected book directory and its use to elaborate the names of inferior books (BOOKS^) makes it possible to move books (BOOKS^) and their inferiors to new directories, provided they maintain the same relative relationship. Moreover, if all arguments to include-book (INCLUDE-BOOK^) command (COMMAND^)s are structured directories, then it is even possible to move with ease whole collections of books (BOOKS^) to different filesystems that use a different operating system than the one under which the original certification was performed.

The ".cert" extension of a book, if it exists, is presumed to contain the most recent certificate (CERTIFICATE^) for the book. See Section 3.5 [CERTIFICATE], page 104 (or, if you are on the guided tour, wait until the tour gets there).

See Section 3.1 [BOOK-CONTENTS], page 94 to continue the guided tour.

3.4 CBD

CBD connected book directory string

     Example:
     ACL2 !>:cbd
     "/usr/home/smith/"

The connected book directory is a nonempty string that specifies a directory as an absolute pathname. (See Section 3.9 [PATHNAME], page 110 for a discussion of file naming conventions. Note however that the cbd (CBD^) is always a string, even though :set-cbd (SET-CBD^) accepts structured directories.) When include-book (INCLUDE-BOOK^) is given a relative book name it elaborates it into a full book name, essentially by appending the connected book directory string to the left and ".lisp" to the right. (For details, see Section 3.3 [BOOK-NAME], page 99 and also see Section 3.7 [FULL-BOOK-NAME], page 108.) Furthermore, include-book (INCLUDE-BOOK^) temporarily sets the connected book directory to the directory string of the resulting full book name so that references to inferior books (BOOKS^) in the same directory may omit the directory. See Section 3.4 [CBD], page 102 for how to set the connected book directory string.

     General Form:
     (cbd)

This is a macro that expands into a term involving the single free variable state (STATE^). It returns the connected book directory string.

The connected book directory (henceforth called the “cbd”) is used by include-book (INCLUDE-BOOK^) to elaborate the supplied book name into a full book name (see Section 3.7 [FULL-BOOK-NAME], page 108). For example, in the Unix (trademark of AT&T) operating system, if the cbd is "/usr/home/smith/" then the elaboration of the book-name (BOOK-NAME^) "project/task-

1/arith" (to the ".lisp" extension) is "/usr/home/smith/project/task-1/arith.lisp". That

full-book-name (FULL-BOOK-NAME^) is what include-book (INCLUDE-BOOK^) opens to read the source text for the book.

The cbd may be changed using set-cbd (SET-CBD^) (see Section 3.11 [SET-CBD], page 116). Furthermore, during the processing of the events (EVENTS^) in a book, include-book (INCLUDE-BOOK^) sets the cbd to be the directory string of the full-book-name (FULL-BOOK-NAME^) of the book. Thus, if the cbd is "/usr/home/smith/" then during the processing of events (EVENTS^) by

     (include-book "project/task-1/arith")
the cbd will be set to "/usr/home/smith/project/task-1/". Note that if "arith" recursively

includes a subbook, say "naturals", that resides on the same directory, the include-book (INCLUDE-BOOK^) event for it may omit the specification of that directory. For example, "arith" might contain the event

       (include-book "naturals").

In general, suppose we have a superior book and several inferior books (BOOKS^) which are included by events (EVENTS^) in the superior book. Any inferior book residing on the same directory as the superior book may be referenced in the superior without specification of the directory.

We call this a “relative” as opposed to “absolute” naming. The use of relative naming is preferred because it permits books (BOOKS^) (and their accompanying inferiors) to be moved between directories while maintaining their certificate (CERTIFICATE^)s and utility. Certified books (BOOKS^) that reference inferiors by absolute file names are unusable (and rendered uncertified) if the inferiors are moved to new directories.

Technical Note and a Challenge to Users:

After elaborating the book name to a full book name, include-book (INCLUDE-BOOK^) opens a channel to the file to process the events (EVENTS^) in it. In some host Common Lisps, the actual file opened depends upon a notion of “connected directory” similar to our connected book directory. Our intention in always elaborating book names into absolute filename strings (see Section 3.9 [PATHNAME], page 110 for terminology) is to circumvent the sensitivity to the connected directory. But we may have insufficient control over this since the ultimate file naming conventions are determined by the host operating system rather than Common Lisp (though, we do check that the operating system “appears” to be one that we “know” about). Here is a question, which we’ll pose assuming that we have an operating system that calls itself “Unix.” Suppose we have a file name, filename, that begins with a slash, e.g., "/usr/home/smith/...". Consider two successive invocations of CLTL’s

     (open filename :direction :input)

separated only by a change to the operating system’s notion of connected directory. Must these two invocations produce streams to the same file? A candidate string might be something like

"/usr/home/smith/*/usr/local/src/foo.lisp" which includes some operating system-specific

special character to mean “here insert the connected directory” or, more generally, “here make the name dependent on some non-ACL2 aspect of the host’s state.” If such “tricky” name strings beginning with a slash exist, then we have failed to isolate ACL2 adequately from the operating system’s file naming conventions. Once upon a time, ACL2 did not insist that the cbd begin with a slash and that allowed the string "foo.lisp" to be tricky because if one were connected to "/usr/home/smith/" then with the empty cbd "foo.lisp" is a full book name that names the same file as "/usr/home/smith/foo.lisp". If the actual file one reads is determined by the operating system’s state then it is possible for ACL2 to have two distinct “full book names” for the same file, the “real” name and the “tricky” name. This can cause ACL2 to include the same book twice, not recognizing the second one as redundant.

3.5 CERTIFICATE

CERTIFICATE how a book is known to be admissible and where its defpkg (DEFPKG^)s reside

A book, say "arith", is said to have a “certificate” if there is a file named "arith.cert". Certificates are created by the function certify-book (CERTIFY-BOOK^) and inspected by includebook (INCLUDE-BOOK^). Check sums are used to help insure that certificates are legitimate and that the corresponding book has not been modified since certification. But because the file system is insecure and check sums are not perfect it is possible for the inclusion of a book to cause inconsistency even though the book carries an impeccable certificate.

The certificate includes the version number of the certifying ACL2. A book is considered uncertified if it is included in an ACL2 with a different version (VERSION^) number.

The presence of a “valid” certificate file for a book attests to two things: all of the events (EVENTS^) of the book are admissible in a certain extension of the initial ACL2 logic, and the non-local (LOCAL^) events (EVENTS^) of the book are independent of the local (LOCAL^) ones (see Section 8.62 [LOCAL-INCOMPATIBILITY], page 344). In addition, the certificate contains the command (COMMAND^)s used to construct the world (WORLD^) in which certification occurred. Among those command (COMMAND^)s, of course, are the defpkg (DEFPKG^)s defining the packages used in the book. When a book is included into a host world (WORLD^), that world (WORLD^) is first extended by the command (COMMAND^)s listed in the certificate for the book. Unless that causes an error due to name conflicts, the extension insures that all the packages used by the book are identically defined in the host world (WORLD^).

Security:

Because the host file system is insecure, there is no way ACL2 can guarantee that the current contents of a book is the same as it was when its certificate was written. That is, between the time a book is certified and the time it is used, it may be modified. Furthermore, certificates can be counterfeited. Check sums (see Section 8.9 [CHECK-SUM], page 259) are used to help detect such problems. But check sums provide imperfect security: two different files can have the same check sum.

Therefore, from the strictly logical point of view, one must consider even the inclusion of certified books (BOOKS^) as placing a burden on the user:

The non-erroneous inclusion of a certified book is consistency preserving provided (a) the objects read by include-book (INCLUDE-BOOK^) from the certificate were the objects written there by a certify-book (CERTIFY-BOOK^) and (b) the forms read by include-book (INCLUDE-BOOK^) from the book itself are the forms read by the corresponding certify-book (CERTIFY-BOOK^).

We say that a given execution of include-book (INCLUDE-BOOK^) is “certified” if a certificate file for the book is present and well-formed and the check sum information contained within it supports the conclusion that the events (EVENTS^) read by the include-book (INCLUDE-BOOK^) are the ones checked by certify-book (CERTIFY-BOOK^). When an uncertified include-book (INCLUDE-BOOK^) occurs, warnings are printed or errors are caused. But even if no warning is printed, you must accept burdens (a) and (b) if you use books (BOOKS^). These burdens are easier to live with if you protect your books (BOOKS^) so that other users cannot write to them, you abstain from running concurrent ACL2 jobs, and you abstain from counterfeiting certificates. But even on a single user uniprocessor, you can shoot yourself in the foot by using the ACL2 io (IO^) primitives to fabricate an inconsistent book and the corresponding certificate.

Note that part (a) of the burden described above implies, in particular, that there are no guarantees when a certificate is copied. When books (BOOKS^) are renamed (as by copying them), it is recommended that their certificates be removed and the books (BOOKS^) be recertified. The expectation is that recertification will go through without a hitch if relative pathname (PATH-NAME^)s are used, though if the books (BOOKS^) are moved to a file system with a different underlying operating system, things will go more easily if structured pathname (PATHNAME^)s are used as arguments to include-book (INCLUDE-BOOK^). See Section 3.9 [PATHNAME], page 110, which is not on the guided tour.

Certificate essentially contain two parts, a portcullis (PORTCULLIS^) and a keep (KEEP^). See Section 3.10 [PORTCULLIS], page 113 to continue the guided tour through books (BOOKS^).

3.6 CERTIFY-BOOK

CERTIFY-BOOK how to produce a certificate (CERTIFICATE^) for a book

     Examples:
     (certify-book "my-arith" 3)   ;certify in a world with 3 commands
     (certify-book "my-arith")     ;certify in a world with 0 commands
     (certify-book "my-arith" 0 nil) ;as above, but do not compile
     (certify-book (:relative "my-arith") 0 nil) ;as above
     (certify-book "my-arith" t)   ;certify from world of existing certificate
     General Form:
     (certify-book book-name k compile-flg)

where book-name is a book name (see Section 3.3 [BOOK-NAME], page 99), k is either t or an integer used to indicate your approval of the “certification world (WORLD^),” and compile-flg indicates whether you wish to compile the (functions in the) book. Compile-flg defaults to t, meaning to compile. The second argument k is actually optional as well; it defaults to 0.

For a general discussion of books, see Chapter 3 [BOOKS], page 93. Certify-book is akin to what we have historically called a “proveall”: all the forms in the book are “proved” to guarantee their admissibility. More precisely, certify-book (1) reads the forms in the book, confirming that the appropriate packages are defined in the certification world (WORLD^); (2) does the full admissibility checks on each form (proving termination of recursive functions, proving theorems, etc.), checking as it goes that each form is an embedded event form (see Section 8.27 [EMBEDDED-EVENT-FORM], page 286); (3) rolls the world (WORLD^) back to the initial certification world (WORLD^) and does an include-book (INCLUDE-BOOK^) of the book to check for local (LO-CAL^) incompatibilities (see Section 8.62 [LOCAL-INCOMPATIBILITY], page 344); (4) writes a certificate (CERTIFICATE^) recording not only that the book was certified but also recording the command (COMMAND^)s necessary to recreate the certification world (WORLD^) (so the appropriate packages can be defined when the book is included in other world (WORLD^)s) and the check sums of all the books (BOOKS^) involved (see Section 3.5 [CERTIFICATE], page 104);

(5) compiles the book if so directed (and then loads the object file in that case). The result of executing a certify-book command (COMMAND^) is the creation of a single new event, which is actually an include-book (INCLUDE-BOOK^) event. If you don’t want its included events (EVENTS^) in your present world (WORLD^), simply execute :ubt (UBT^) :here afterwards.

Certify-book requires that the default defun-mode (DEFUN-MODE^) (see Section 8.18 [DEFAULT-DEFUN-MODE], page 273) be :logic (LOGIC^) when certification is attempted. If the mode is not :logic (LOGIC^), an error is signalled.

An error will occur if certify-book has to deal with any uncertified book other than the one on which it was called. For example, if the book being certified includes another book, that subbook must already have been certified.

Certification occurs in some logical world (WORLD^), called the “certification world (WORLD^).” That world (WORLD^) must contain the defpkg (DEFPKG^)s needed to read and execute the forms in the book. The command (COMMAND^)s necessary to recreate that world (WORLD^) from the ACL2 initial world (WORLD^) will be copied into the certificate (CERTIFICATE^) created for the book. Those command (COMMAND^)s will be re-executed whenever the book is included, to insure that the appropriate packages (and all other names used in the certification world (WORLD^)) are correctly defined. The certified book will be more often usable if the certification world (WORLD^) is kept to a minimal extension of the ACL2 initial world (WORLD^). Thus, before you call certify-book for the first time on a book, you should get into the initial ACL2 world (WORLD^) (e.g., with :ubt 1 or just starting a new version of ACL2), defpkg (DEFPKG^) the desired packages, and then invoke certify-book.

The k argument to certify-book must be either a nonnegative integer or else the symbol t. If k is an integer, then it must be the number of command (COMMAND^)s that have been executed to create the world (WORLD^) in which certify-book was called. One way to obtain this number is by doing :pbt 1 to see all the command (COMMAND^)s back to the first one. The last command (COMMAND^) number printed in the :pbt (PBT^) display is the appropriate k. This number is just the maximum command (COMMAND^) number, :max (MAX^) — see Section 8.12 [COMMAND-DESCRIPTOR], page 261 — but unless :max (MAX^) is 0, certify-book requires that you actually input the number as a way of reminding you to inspect the world (WORLD^) before calling certify-book.

If k is t it means that certify-book should use the same world (WORLD^) used in the last certification of this book. K may be t only if you call certify-book in the initial ACL2 world (WORLD^) (:max = 0) and there is a certificate (CERTIFICATE^) on file for the book being certified. (Of course, the certificate (CERTIFICATE^) is probably invalid.) In this case, certify-book reads the old certificate (CERTIFICATE^) to obtain the portcullis (PORTCULLIS^) command (COM-MAND^)s and executes them to recreate the certification world (WORLD^).

If you have a certified book that has remained unchanged for some time you are unlikely even to remember the appropriate defpkg (DEFPKG^)s for it. If you begin to change the book, don’t throw away its certificate (CERTIFICATE^) file just because it has become invalid! It is an important historical document until the book is re-certified.

When certify-book is directed to produce a compiled file, it calls the Common Lisp function compile-file on the original source file. This creates a compiled file with an extension known to ACL2, e.g., if the book is named "my-book" then the source file is "my-book.lisp" and the compiled file under AKCL will be "my-book.o" while under Lucid it will be "my-book.lbin" or "my-book.sbin". The compiled file is then loaded. When include-book (INCLUDE-BOOK^) is used later on "my-book" it will automatically load the compiled file, provided the compiled file has a later write date than the source file. The only effect of such compilation (COMPILATION^) and loading is that the functions defined in the book execute faster. See Section 8.41 [GUARD], page 305 for a discussion of the issues.

When certify-book is directed not to produce a compiled file, it will delete any existing compiled file for the book, so as not to mislead include-book (INCLUDE-BOOK^) into loading the now outdated compiled file.

After execution of a certify-book form, the value of acl2-defaults-table (ACL2-DEFAULTS-TABLE^) is restored to what it was immediately before that certify-book form was executed. See Section 9.2 [ACL2-DEFAULTS-TABLE], page 410.

This completes the tour through the documentation (DOCUMENTATION^) of books (BOOKS^).

3.7 FULL-BOOK-NAME

FULL-BOOK-NAME book naming conventions assumed by ACL2

For this discussion we assume that the resident operating system is Unix (trademark of AT&T), but analogous remarks apply to other operating systems supported by ACL2, in particular, the Macintosh operating system where ‘:’ plays roughly the role of ‘/’ in Unix; see Section 3.9 [PATHNAME], page 110.

ACL2 defines a “full book name” to be an “absolute filename string,” that may be divided into contiguous sections: a “directory string”, a “familiar name” and an “extension”. See Section 3.9 [PATHNAME], page 110 for the definitions of “absolute,” “filename string,” and other notions pertaining to naming files. Below we exhibit the three sections of one such string:

     "/usr/home/smith/project/arith.lisp"

     "/usr/home/smith/project/"           ; directory string
                             "arith"      ; familiar name
                                  ".lisp" ; extension

The sections are marked by the rightmost slash and rightmost dot, as shown below.

     "/usr/home/smith/project/arith.lisp"
                             |     |
                             slash dot
                             |     |
     "/usr/home/smith/project/"           ; directory string
                             "arith"      ; familiar name
                                  ".lisp" ; extension

The directory string includes (and terminates with) the rightmost slash. The extension includes (and starts with) the rightmost dot. The dot must be strictly to the right of the slash so that the familiar name is well-defined and nonempty.

If you are using ACL2 on a system in which file names do not have this form, please contact the authors and we’ll see what we can do about generalizing ACL2’s conventions.

3.8 KEEP

KEEP how we know if include-book (INCLUDE-BOOK^) read the correct files

The certificate (see Section 3.5 [CERTIFICATE], page 104 for general information) of a certified file is divided into two parts, a portcullis (PORTCULLIS^) and a keep. These names come from castle lore. The keep is the strongest and usually tallest tower of a castle from which the entire courtyard can be surveyed by the defenders. The keep of a book is a list of file names and check sums used after the book has been included, to determine if the files read were (up to check sum) those certified.

Once the portcullis (PORTCULLIS^) is open, include-book (INCLUDE-BOOK^) can enter the book and read the event forms therein. The non-local (LOCAL^) event forms are in fact executed, extending the host theory. That may read in other books (BOOKS^). When that has been finished, the keep of the certificate (CERTIFICATE^) is inspected. The keep is a list of the book names which are included (heritarily through all subbooks) in the certified book (including the certified book itself) together with the check sums of the objects in those books (BOOKS^) at the time of certification. We compare the check sums of the books (BOOKS^) just included to the check sums of the books (BOOKS^) stored in the keep. If differences are found then we know that the book or one of its subbooks has been changed since certification.

See Section 6.20 [INCLUDE-BOOK], page 189 to continue the guided tour through books (BOOKS^).

3.9 PATHNAME

PATHNAME introduction to filename conventions in ACL2

Although the notion of pathname objects from Common Lisp is not supported in ACL2, nor is the function pathname, nevertheless ACL2 adopts conventions for naming files that are not so different from Common Lisp’s conventions, using strings that we’ll call “filename strings” and (for ACL2 books (BOOKS^)) certain lists that we’ll call “structured pathnames.” Some of these strings and lists correspond to “absolute,” i.e. complete, descriptions of a file or directory; others are “relative” to the current working directory or to the connected book directory (see Section 3.4 [CBD], page 102). The reason we support structured pathnames is to allow books (BOOKS^) to be transferred between machines running different operating systems (see Section 3.3 [BOOK-NAME], page 99).

Consider by way of introduction the following examples in the Unix (trademark of AT&T) operating system. The filename string

     "/home/smith/acl2/book-1.lisp"

corresponds to the structured pathname

     (:absolute "home" "smith" "acl2" "book-1.lisp")

and, relative to the connected book directory "/home/smith/" (see Section 3.4 [CBD], page 102), corresponds to the relative filename string

     "acl2/book1.lisp"

and to the relative structured pathname

     (:relative "acl2" "book-1.lisp")

The rest of the discussion focuses on filename strings vs. structured pathnames, with attention to directories vs. files and to absolute vs. relative pathnames.

Filename strings. One way to specify a file in ACL2 is by way of a nonempty string. The form of this string must conform to the requirements of the resident operating system. Thus in the Unix environment, slash (/) is the “directory separator”: a filename such as "/home/smith/acl2/book-1.lisp" may be read as “Inside the directory "/home", then inside the directory "smith", then inside the directory "acl2", consider the file "book-1.lisp".” On the Macintosh, the directory separator is colon (:). Such strings represent a directory when they terminate with the directory separator, and a file otherwise. The directory separator may be obtained as:

     (directory-separator (@ operating-system) 'top).

Filename strings may be referred to either as absolute pathnames, which are complete descriptions of the location of a file or directory, or as relative pathnames, which give the location of a file or directory relative to a given (implicit) directory. In Unix, filename strings starting with the directory separator (/) are absolute pathnames, such as the example in the preceding paragraph. All other filename strings are relative pathnames.

For example, the string

     "examples/my-book"

is a relative pathname. If the implicit directory (which for books (BOOKS^) is the connected book directory; see Section 3.4 [CBD], page 102) is "/home/smith/", then the corresponding absolute pathname is the filename string obtained by concatenating the implicit directory with the relative pathname,

     "/home/smith/examples/my-book"

On the Macintosh the convention is exactly reversed: a string represents an absolute pathname exactly when its first character is not the directory separator (:). Thus, the absolute pathname corresponding to the one displayed just above is

     "home:smith:examples:my-book"

which may be derived from the relative pathname

     ":examples:my-book"

and implicit directory

     "home:smith:"

Notice that on the Macintosh, when we concatenate (CONCATENATE^) an implicit directory string to a relative pathname string, we must drop the excess colon, since a colon terminates the implicit directory string and also starts the relative pathname.

Structured pathnames. In ACL2, books (BOOKS^) may be named with filename strings or with structured pathnames, which we now describe. (Note that structured pathnames are only used in the realm of books (BOOKS^): for example, although :set-cbd (SET-CBD^) accepts structured pathnames, ld (LD^) currently only accepts filename strings.) A structured pathname is a list beginning with one of the keywords :absolute or :relative and then continuing with strings, except that :back may appear any number of times between :relative and the first string in the list. Each of the strings represents a subdirectory, except that the last may represent a file. For example, the filename string (in Unix) "/home/smith/acl2/book-1.lisp" represents the same file as does the following structured pathname.

     (:absolute "home" "smith" "acl2" "book-1.lisp")

This is an absolute structured pathname, because it begins with the keyword :absolute. The other type of structured pathname is the relative structured pathname, which begins with the keyword :relative. For example, the following structured pathname corresponds to the relative filename

string (in Unix) "examples/my-book":
     (:relative "examples" "my-book")

As mentioned above, relative structured pathnames may also contain any number of occurrences of the keyword :back after the (initial element) :relative and before the first string. This keyword represents the notion of going up one level in the file system (just like ".." in Unix). For example, suppose that the connected book directory (see Section 3.4 [CBD], page 102) can be represented by the following structured pathname.

     (:absolute "home" "smith" "acl2" "examples")

Then the structured pathname

     (:relative :back :back "numbers" "book-2.lisp")

represents the same file as does the following absolute structured pathname.

     (:absolute "home" "smith" "numbers" "book-2.lisp")

Here, the first :back may be thought of as “cancelling” the subdirectory "examples" and the second :back may be thought of as “cancelling” its parent "acl2", after which we are to continue as specified by the given relative structured pathname.

There is no distinction between files and directories for structured pathnames, but the intention is clear from context. For example, the argument to :set-cbd (SET-CBD^) is a directory, while the argument to include-book (INCLUDE-BOOK^) is a file (but without the ".lisp" extension (see Section 3.3 [BOOK-NAME], page 99).

Finally, we note that our notion of structured pathname corresponds to a similar notion of structured directory described in the second edition of Guy Steele’s book “Common Lisp the Language.” The main difference is that we allow the trivial structured pathname (:relative), but Steele does not.

3.10 PORTCULLIS

PORTCULLIS the gate guarding the entrance to a certified book

The certificate (see Section 3.5 [CERTIFICATE], page 104 for general information) of a certified file is divided into two parts, a portcullis and a keep (KEEP^). These names come from castle lore. The portcullis of a castle is an iron grate that slides up through the ceiling of the tunnel-like entrance. The portcullis of a book insures that include-book (INCLUDE-BOOK^) does not start to read the book until the appropriate context has been created.

Technically, the portcullis consists of the version (VERSION^) number of the certifying ACL2, a list of command (COMMAND^)s used to create the “certification world (WORLD^)” and an alist specifying the check sums of all the books (BOOKS^) included in that world (WORLD^). The portcullis is constructed automatically by certify-book (CERTIFY-BOOK^) from the world (WORLD^) in which certify-book (CERTIFY-BOOK^) is called, but that world (WORLD^) must have certain properties described below. After listing the properties we discuss the issues more leisurely.

Each command (COMMAND^) in the portcullis must be either a defpkg (DEFPKG^) form or an embedded event form (see Section 8.27 [EMBEDDED-EVENT-FORM], page 286). In addition, we exclude include-book (INCLUDE-BOOK^) events (EVENTS^) unless the name of the included book is an absolute filename (see Section 3.9 [PATHNAME], page 110). For example, under Unix (trademark of AT&T) any string supplied to include-book (INCLUDE-BOOK^) in the portcullis must begin with a slash (/). Since the portcullis command (COMMAND^)s are recovered automatically by certify-book (CERTIFY-BOOK^), this restriction on the form of portcullis command (COMMAND^)s naturally becomes a restriction on the world (WORLD^) in which certify-book (CERTIFY-BOOK^) may be called. We explain the exclusion after discussing the general issues.

Consider a book to be certified. The book is a file containing event forms. Suppose the file contains references to such symbols as my-pkg::fn and acl2-arith::cancel, but that the book itself does not create the packages. Then a hard Lisp error would be caused merely by the attempt to read the expressions in the book. The corresponding defpkg (DEFPKG^)s cannot be written into the book itself because the book must be compilable and Common Lisp compilers differ on the rules concerning the inline definition of new packages. The only safe course is to make all defpkg (DEFPKG^)s occur outside of compiled files.

More generally, when a book is certified it is certified within some logical world (WORLD^). That “certification world (WORLD^)” contains not only the necessary defpkg (DEFPKG^)s but also, perhaps, function and constant definitions and maybe even references to other books (BOOKS^). When certify-book (CERTIFY-BOOK^) creates the certificate (CERTIFICATE^) for a file it recovers from the certification world (WORLD^) the command (COMMAND^)s used to create that world (WORLD^) from the initial ACL2 world (WORLD^). Those command (COMMAND^)s become part of the portcullis for the certified book. In addition, certify-book (CERTIFY-BOOK^) records in the portcullis the check sums (see Section 8.9 [CHECK-SUM], page 259) of all the books (BOOKS^) included in the certification world (WORLD^).

Include-book (INCLUDE-BOOK^) presumes that it is impossible even to read the contents of a certified book unless the portcullis can be “raised.” To raise the portcullis we must be able to execute (possibly redundantly, but certainly without error), all of the command (COMMAND^)s in the portcullis and then verify that the books (BOOKS^) thus included were identical to those used to build the certification world (WORLD^) (up to check sum). This raising of the portcullis must be done delicately since defpkg (DEFPKG^)s are present: we cannot even read a command (COM-MAND^) in the portcullis until we have successfully executed the previous ones, since packages are being defined.

Clearly, a book is most useful if it is certified in the most elementary extension possible of the initial logic. If, for example, your certification world (WORLD^) happens to contain a defpkg (DEFPKG^) for "MY-PKG" and the function foo, then those definitions become part of the portcullis for the book. Every time the book is included, those names will be defined and will have to be either new or redundant (see Section 8.78 [REDUNDANT-EVENTS], page 361). But if those names were not necessary to the certification of the book, their presence would unnecessarily restrict the utility of the book.

Recall that we disallow include-book (INCLUDE-BOOK^) events (EVENTS^) from the portcullis unless the included book’s name is an absolute filename (See Section 3.9 [PATHNAME], page 110). Thus, for example, under the Unix operating system it is impossible to certify a book if the certification world (WORLD^) was created with

     ACL2 !>(include-book (INCLUDE-BOOK^) "arith")

The problem here is that the file actually read on behalf of such an include-book (INCLUDE-BOOK^) depends upon the then current setting of the connected book directory (see Section 3.4 [CBD], page 102). That setting could be changed before the certification occurs. If we were to copy (include-book "arith") into the portcullis of the book being certified, there is no assurance that the "arith" book included would come from the correct directory. However, by requiring that the include-book (INCLUDE-BOOK^)s in the certification world (WORLD^) give book names that begin with slash we effectively require you to specify the full file name of each book involved in creating your certification world (WORLD^). Observe that the execution of

     (include-book (INCLUDE-BOOK^) "/usr/local/src/acl2/library/arith")

or equivalently (using structured pathname (PATHNAME^)s; see Section 3.9 [PATHNAME], page 110)

     (include-book (INCLUDE-BOOK^)
       (:absolute "usr" "local" "src" "acl2" "library" "arith"))

does not depend on the current book directory. On the other hand, this requirement — effectively that absolute file names be used in the certification world (WORLD^) — means that a book that requires another book in its certification world (WORLD^) will be rendered uncertified if the required book is removed to another directory. If possible, any include-book (INCLUDE-BOOK^) command (COMMAND^) required for a book ought to be placed in the book itself and not in the certification world (WORLD^). The only time this cannot be done is if the required book is necessary to some defpkg (DEFPKG^) required by your book. Of course, this is just the same advice we have been giving: keep the certification world (WORLD^) as elementary as possible.

See Section 3.8 [KEEP], page 109 to continue the guided tour of books (BOOKS^).

3.11 SET-CBD

SET-CBD to set the connected book directory

     Example Forms:
     ACL2 !>:set-cbd "/usr/home/smith/"
     ACL2 !>:set-cbd (:absolute "usr" "home" "smith")
     ACL2 !>:set-cbd (:relative :back "smith")

See Section 3.4 [CBD], page 102 for a description of the connected book directory.

     General Form:
     (set-cbd str)

where str is either a nonempty string that represents the absolute pathname for a directory, or a structured pathname that represents a directory (see Section 3.9 [PATHNAME], page 110). This command sets the connected book directory (see Section 3.4 [CBD], page 102) to the string representing the indicated directory. Thus, this command may determine which files are processed by include-book (INCLUDE-BOOK^) and certify-book (CERTIFY-BOOK^) command (COM-MAND^)s typed at the top-level. However, the cbd (CBD^) is also set by those two book processing command (COMMAND^)s; thus, the setting of the cbd (CBD^) is irrelevant to include-book (INCLUDE-BOOK^) command (COMMAND^)s in other books (BOOKS^).

Note that if a structured pathname (PATHNAME^) is used for :set-cbd, then it may be absolute or relative. (See Section 3.9 [PATHNAME], page 110 for relevant definitions.) However, if a string is used for :set-cbd, it must represent an absolute pathname (PATHNAME^). We do not support syntax for relative pathname (PATHNAME^)s for use with :set-cbd that is peculiar to particular operating systems, such as ".." in Unix (trademark of AT&T), because we want to be sure to be able to correctly identify the resulting absolute pathname of the :cbd (CBD^).

3.12 UNCERTIFIED-BOOKS

UNCERTIFIED-BOOKS invalid certificate (CERTIFICATE^)s and uncertified books (BOOKS^)

Include-book (INCLUDE-BOOK^) has a special provision for dealing with uncertified books (BOOKS^): If the file has no certificate (CERTIFICATE^) or an invalid certificate (CERTIFI-CATE^) (i.e., one whose check sums describe files other than the ones actually read), a warning is printed and the book is otherwise processed as though it were certified and had an open portcullis (PORTCULLIS^). (For details see Chapter 3 [BOOKS], page 93, see Section 3.5 [CERTIFICATE], page 104, and see Section 3.10 [PORTCULLIS], page 113.)

This can be handy, but it can have disastrous consequences.

The provision allowing uncertified books (BOOKS^) to be included can have disastrous consequences, ranging from hard lisp errors, to damaged memory, to quiet logical inconsistency.

It is possible for the inclusion of an uncertified book to render the logic inconsistent. For example, one of its non-local (LOCAL^) events (EVENTS^) might be (defthm t-is-nil (equal t nil)). It is also possible for the inclusion of an uncertified book to cause hard errors or breaks (BREAKS^) into raw Common Lisp. For example, if the file has been edited since it was certified, it may contain too many open parentheses, causing Lisp to read past “end of file.” Similarly, it might contain non-ACL2 objects such as 3.1415 or ill-formed event forms that cause ACL2 code to break.

Even if a book is perfectly well formed and could be certified (in a suitable extension of ACL2’s initial world (WORLD^)), its uncertified inclusion might cause Lisp errors or inconsistencies! For example, it might mention packages that do not exist in the host world (WORLD^). The portcullis (PORTCULLIS^) of a certified book insures that the correct defpkg (DEFPKG^)s have been admitted, but if a book is read without actually raising its portcullis (PORTCULLIS^), symbols in the file, e.g., acl2-arithmetic::fn, could cause “unknown package” errors in Common Lisp. Perhaps the most subtle disaster occurs if the host world (WORLD^) does have a defpkg (DEFPKG^) for each package used in the book but the host defpkg (DEFPKG^) imports different symbols than those required by the portcullis (PORTCULLIS^). In this case, it is possible that formulas which were theorems in the certified book are non-theorems in the host world (WORLD^), but those formulas can be read without error and will then be quietly assumed.

In short, if you include an uncertified book, all bets are off regarding the validity of the future behavior of ACL2.

That said, it should be noted that ACL2 is pretty tough and if errors don’t occur, the chances are that deductions after the inclusion of an uncertified book are probably justified in the (possibly inconsistent) logical extension obtained by assuming the admissibility and validity of the definitions and conjectures in the book.

118 ACL2 Version 1.9

4 BREAK-REWRITE

BREAK-REWRITE the read-eval-print loop entered to monitor (MONITOR^) rewrite rules

ACL2 allows the user to monitor (MONITOR^) the application of rewrite rules. When monitor (MONITOR^)ed rules are about to be tried by the rewriter, an interactive break occurs and the user is allowed to watch and, in a limited sense, control the attempt to apply the rule. This interactive loop, which is technically just a call of the standard top-level ACL2 read-eval-print loop, ld (LD^), on a “wormhole (WORMHOLE^) state (STATE^)” (see Section 8.101 [WORMHOLE], page 401), is called “break-rewrite.” While in break-rewrite, certain keyword commands are available for accessing information about the context in which the lemma is being tried. These keywords are called break-rewrite “commands.”

To abort from inside break-rewrite at any time, execute sharpsign-period (#.).

For further information, see the related :doc (DOC^) topics listed below.

* BREAK-LEMMA:: a quick introduction to breaking rewrite rules in ACL2

* BRR:: to enable or disable the breaking of rewrite rules

* BRR-COMMANDS:: Break-Rewrite (BREAK-REWRITE^) Commands

* BRRatsign:: (BRR@) to access context sensitive information within break-rewrite (BREAK-REWRITE^)

* MONITOR:: to monitor the attempted application of a rule name

* MONITORED-RUNES:: print the monitor (MONITOR^)ed rune (RUNE^)s and their break conditions * OK-IF:: conditional exit from break-rewrite

* UNMONITOR:: to stop monitoring a rule name

As explained in the documentation for monitor (MONITOR^), it is possible to cause the ACL2 rewriter to monitor (MONITOR^) the attempted application of selected rules. When such a rule is about to be tried, the rewriter evaluates its break condition and if the result is non-nil, breakrewrite is entered.

Break-rewrite permits the user to inspect the current state (STATE^) by evaluating break-rewrite commands. Type :help (HELP^) in break-rewrite to see what the break-rewrite commands are. However, break-rewrite is actually just a call of the general ACL2 read-eval-print loop, ld (LD^), on a certain state (STATE^) and the break-rewrite commands are simply aliases provided by the ld (LD^)-special ld-keyword-aliases (LD-KEYWORD-ALIASES^). See Section 9.7 [LD], page 416 for details about this read-eval-print loop. Thus, with a few exceptions, anything you can do at the ACL2 top-level can be done within break-rewrite. For example, you can evaluate arbitrary expressions, use the keyword command hack, access documentation (DOCUMENTATION^), print events (EVENTS^), and even define functions and prove theorems. However, the “certain state (STATE^)” upon which ld (LD^) was called is a “wormhole (WORMHOLE^) state (STATE^)” (see Section 8.101 [WORMHOLE], page 401) because break-rewrite is not allowed to have any effect upon the behavior of rewrite. What this means, very roughly but understandably, is that breakrewrite operates on a copy of the state (STATE^) being used by rewrite and when break-rewrite exits the wormhole (WORMHOLE^) closes and the state (STATE^) “produced” by break-rewrite disappears. Thus, break-rewrite lets you query the state of the rewriter and even do experiments involving proofs, etc., but these experiments have no effect on the ongoing proof attempt.

When you first enter break-rewrite a simple herald is printed such as:

     (3 Breaking (:rewrite lemma12) on (delta a (+ 1 j)):

The integer after the open parenthesis indicates the depth of nested break-rewrite calls. In this discussion we use 3 consistently for this integer. Unless you abort or somehow enter unbalanced parentheses into the script, the entire session at a given depth will be enclosed in balanced parentheses, making it easy to skip over them in Emacs.

You then will see the break-rewrite prompt (PROMPT^):

     3 ACL2 !>

The leading integer is, again, the depth. Because breaks often occur recursively it is convenient always to know the level with which you are interacting.

You may type arbitrary commands as in the top-level ACL2 loop. For example, you might type:

     3 ACL2 !>:help

or

     3 ACL2 !>:pe lemma12

More likely, upon entering break-rewrite you will determine the context of the attempted application. Here are some useful commands:

     3 ACL2 >:target           ; the term being rewritten
     3 ACL2 >:unify-subst      ; the unifying substitution
     3 ACL2 >:path             ; the stack of goals pursued by the rewriter

                               ; starting at the top-level clause being simplified
                               ; and ending with the current application

At this point in the interaction the system has not yet tried to apply the monitor (MONITOR^)ed rule. That is, it has not tried to establish the hypotheses, considered the heuristic cost of backchaining, rewritten the right-hand side of the conclusion, etc. When you are ready for it to try the rule you can type one of several different “proceed” commands. The basic proceed commands are :ok,

:go, and :eval.
     :ok

exits break-rewrite without further interaction. When break-rewrite exits it prints “3)”, closing the parenthesis that opened the level 3 interaction.

     :go

exits break-rewrite without further interaction, but prints out the result of the application attempt, i.e., whether the application succeeded, if so, what the :target term was rewritten to, and if not why the rule was not applicable.

     :eval

causes break-rewrite to attempt to apply the rule but interaction at this level of break-rewrite resumes when the attempt is complete. When control returns to this level of break-rewrite a message indicating the result of the application attempt (just as in :go) is printed, followed by the prompt (PROMPT^) for additional user input.

Generally speaking, :ok and :go are used when the break in question is routine or uninteresting and :eval is used when the break is one that the user anticipates is causing trouble. For example, if you are trying to determine why a lemma isn’t being applied to a given term and the :target of the current break-rewrite is the term in question, you would usually :eval the rule and if breakrewrite reports that the rule failed then you are in a position to determine why, for example by carefully inspecting the :type-alist of governing assumptions or why some hypothesis of the rule could not be established.

It is often the case that when you are in break-rewrite you wish to change the set of monitor (MON-ITOR^)ed rune (RUNE^)s. This can be done by using :monitor (MONITOR^) and :unmonitor (UNMONITOR^) as noted above. For example, you might want to monitor (MONITOR^) a certain rule, say hyp-reliever, just when it is being used while attempting to apply another rule, say main-lemma. Typically then you would monitor (MONITOR^) main-lemma at the ACL2 toplevel, start the proof-attempt, and then in the break-rewrite in which main-lemma is about to be tried, you would install a monitor (MONITOR^) on hyp-reliever. If during the ensuing :eval hyp-reliever is broken you will know it is being used under the attempt to apply main-lemma.

However, once hyp-reliever is being monitor (MONITOR^)ed it will be monitor (MONITOR^)ed even after main-lemma has been tried. That is, if you let the proof attempt proceed then you may see many other breaks on hyp-reliever, breaks that are not “under” the attempt to apply mainlemma. One way to prevent this is to :eval the application of main-lemma and then :unmonitor (UNMONITOR^) hyp-reliever before exiting. But this case arises so often that ACL2 supports several additional “flavors” of proceed commands.

:Ok!, :go!, and :eval! are just like their counterparts (:ok, :go, and :eval, respectively), except that while processing the rule that is currently broken no rune (RUNE^)s are monitor (MONI-TOR^)ed. When consideration of the current rule is complete, the set of monitor (MONITOR^)ed rune (RUNE^)s is restored to its original setting.

:Ok$, :go$, and :eval$ are similar but take an additional argument which must be a list of rune (RUNE^)s. An example usage of :eval$ is

     3 ACL2 !>:eval$ ((:rewrite hyp-reliever))

These three commands temporarily install unconditional breaks on the rune (RUNE^)s listed, proceed with the consideration of the currently broken rule, and then restore the set of monitor (MONITOR^)ed rules to its original setting.

Thus, there are nine ways to proceed from the initial entry into break-rewrite although we often speak as though there are two, :ok and :eval, and leave the others implicit. We group :go with :ok because in all their flavors they exit break-rewrite without further interaction (at the current level). All the flavors of :eval require further interaction after the rule has been tried.

To abort a proof attempt and return to the top-level of ACL2 you may at any time type #. (that is, number-sign followed by a period) followed by a carriage return.

We now address ourselves to the post-:eval interaction with break-rewrite. As noted, that interaction begins with break-rewrite’s report on the results of applying the rule: whether it worked and either what it produced or why it failed. This information is also printed by certain keyword commands available after :eval, namely :wonp, :rewritten-rhs, and :failure-reason. In addition, by using brr@ (BRR@^) (see Section 4.4 [BRR@], page 128) you can obtain this information in the form of ACL2 data objects. This allows the development of more sophisticated “break conditions”; see Section 4.5 [MONITOR], page 130 for examples. In this connection we point out the macro form (ok-if term). See Section 4.7 [OK-IF], page 133. This command exits break-rewrite if term evaluates to non-nil and otherwise does not exit. Thus it is possible to define macros that provide other kinds of exits from break-rewrite. The only way to exit break-rewrite after :eval is :ok (or, equivalently, the use of ok-if (OK-IF^)).

ACL2 users who wish to know more about break-rewrite so that they can develop more convenient ways to monitor (MONITOR^) rules are encouraged to speak to J Moore.

The rest of this documentation (DOCUMENTATION^) discusses a few implementation details of break-rewrite and may not be interesting to the typical user.

There is no ACL2 function named break-rewrite. It is an illusion created by appropriate calls to two functions named brkpt1 and brkpt2. As previously noted, break-rewrite is ld (LD^) operating on a wormhole (WORMHOLE^) state (STATE^). One might therefore wonder how break-rewrite can apply a rule and then communicate the results back to the rewriter running in the external state (STATE^). The answer is that it cannot. Nothing can be communicated through a wormhole (WORMHOLE^). In fact, brkpt1 and brkpt2 are each calls of ld (LD^) running on wormhole (WORMHOLE^) state (STATE^)s. Brkpt1 implements the pre-:eval break-rewrite and brkpt2 implements the post-:eval break-rewrite. The rewriter actually calls brkpt1 before attempting to apply a rule and calls brkpt2 afterwards. In both cases, the rewriter passes into the wormhole (WORMHOLE^) the relevant information about the current context. Logically brkpt1 and brkpt2 are no-ops and rewrite (REWRITE^) ignores the nil they return. But while control is in them the execution of rewrite (REWRITE^) is suspended and cannot proceed until the break-rewrite interactions complete.

This design causes a certain anomoly that might be troubling. Suppose that inside break-rewrite before :evaling a rule (i.e., in the brkpt1 wormhole (WORMHOLE^) state (STATE^)) you define some function, foo. Suppose then you :eval the rule and eventually control returns to breakrewrite (i.e., to brkpt2 on a wormhole (WORMHOLE^) state (STATE^) with the results of the application in it). You will discover that foo is no longer defined! That is because the wormhole (WORMHOLE^) state (STATE^) created during your pre-:eval interaction is lost when we exit the wormhole (WORMHOLE^) to resume the proof attempt. The post-:eval wormhole (WORM-HOLE^) state (STATE^) is in fact identical to the initial pre-:eval state (STATE^) (except for the results of the application) because rewrite (REWRITE^) did not change the external state (STATE^) and both wormhole (WORMHOLE^) state (STATE^)s are copies of it.

There is a lot more to know about break-rewrite, most of which is fairly easy to learn from looking at the code, since it is all expressed in ACL2. Feel free to ask questions of J Moore.

4.1 BREAK-LEMMA

BREAK-LEMMA a quick introduction to breaking rewrite rules in ACL2

     Example:
     :brr t                          ; if you haven't done that yet
     :monitor (:rewrite lemma12) t   ; to install a break point on the
                                     ; rule named (:rewrite lemma12)

ACL2 does not support Nqthm’s break-lemma but supports a very similar and more powerful break facility. Suppose some proof is failing; apparently some particular rule is not being used and you wish to learn why. Then you need the ACL2 break-rewrite (BREAK-REWRITE^) facility. See Chapter 4 [BREAK-REWRITE], page 119 and all of its associated :doc (DOC^) topics for details. The following basic steps are required.

(1) To enable the “break rewrite” feature, you must first execute

     ACL2 !>:brr t

at the top-level of ACL2. Equivalently, evaluate (brr t). Break-rewrite (BREAK-REWRITE^) stays enabled until you disable it with (brr nil). When break-rewrite (BREAK-REWRITE^) is enabled the ACL2 rewriter will run slower than normal but you will be able to monitor (MONI-TOR^) the attempts to apply specified rules.

(2) Decide what rune (RUNE^)s (see Section 16.10 [RUNE], page 784) you wish to monitor (MON-ITOR^). For example, you might want to know why (:rewrite lemma12 . 2) is not being used in the attempted proof. That, by the way, is the name of the second rewrite rule generated from the event named lemma12.

The command

     ACL2 !>:monitor (:rewrite lemma12 . 2) t

will install an “unconditional” break point on that rule. The “t” at the end of the command means it is unconditional, i.e., a break will occur every time the rule is tried. ACL2 supports conditional breaks also, in which case the t is replaced by an expression that evaluates to non-nil when you wish for a break to occur. See Section 4.5 [MONITOR], page 130. The above keyword command is, of course, equivalent to

     ACL2 !>(monitor '(:rewrite lemma12 . 2) t)

which you may also type. You may install breaks on as many rules as you wish. You must use monitor (MONITOR^) on each rule. You may also change the break condition on a rule with monitor (MONITOR^). Use unmonitor (UNMONITOR^) (see Section 4.8 [UNMONITOR], page 134) to remove a rule from the list of monitor (MONITOR^)ed rules.

(3) Then try the proof again. When a monitor (MONITOR^)ed rule is tried by the rewriter you will enter an interactive break, called break-rewrite (BREAK-REWRITE^). See Chapter 4 [BREAK-REWRITE], page 119 for a detailed description. Very simply, break-rewrite (BREAK-REWRITE^) lets you inspect the context of the attempted application both before and after the attempt. When break-rewrite (BREAK-REWRITE^) is entered it will print out the “target” term being rewritten. If you type :go break-rewrite (BREAK-REWRITE^) will try the rule and then exit, telling you (a) whether the rule was applied, (b) if so, how the target was rewritten, and (c) if not, why the rule failed. There are many other commands. See Section 4.3 [BRR-COMMANDS], page 127.

(4) When you have finished using the break-rewrite (BREAK-REWRITE^) feature you should disable it to speed up the rewriter. You can disable it with

     ACL2 !>:brr nil

The list of monitor (MONITOR^)ed rules and their break conditions persists but is ignored. If you enable break-rewrite (BREAK-REWRITE^) later, the list of monitor (MONITOR^)ed rules will be displayed and will be used again by rewrite.

You should disable the break-rewrite (BREAK-REWRITE^) feature whenever you are not intending to use it, even if the list of monitor (MONITOR^)ed rules is empty, because the rewriter is slowed down as long as break-rewrite (BREAK-REWRITE^) is enabled.

Finally, a wonderful trick is the following. When there is a stack overflow, abort the proof and then try it again after turning on rewrite stack monitoring with :brr t. Then, provoke the stack overflow again. Quit the ACL2 top-level loop and execute the following form in raw Lisp:

       (cw-gstack *deep-gstack* state)

The loop in the rewriter will probably be evident!

4.2 BRR

BRR to enable or disable the breaking of rewrite rules

     Example:
     :brr t       ; enable
     :brr nil     ; disable
     General Form:
     (brr flg)

where flg evaluates to t or nil. This function modifies state (STATE^) so that the attempted application of certain rewrite rules are “broken.” “Brr” stands for “break-rewrite” and can be thought of as a mode with two settings. The normal mode is “disabled.”

When brr mode is “enabled” the ACL2 rewriter monitors the attempts to apply certain rules and advises the user of those attempts by entering an interactive wormhole break. From within this break the user can watch selected application attempts. See Chapter 4 [BREAK-REWRITE], page 119.

The rules monitored are selected by using the monitor (MONITOR^) and unmonitor (UNMON-ITOR^) commands. It is possible to break a rune “conditionally” in the sense that an interactive break will occur only if a specified predicate is true of the environment at the time of the attempted application. See Section 4.5 [MONITOR], page 130 and see Section 4.8 [UNMONITOR], page 134.

Even if a non-empty set of rules has been selected, no breaks will occur unless brr mode is enabled. Thus, the first time in a session that you wish to monitor a rewrite rule, use :brr t to enable brr mode. Thereafter you may select runes to be monitored with monitor (MONITOR^) and unmonitor (UNMONITOR^) with the effect that whenever monitored rules are tried (and their break conditions are met) an interactive break will occur. Be advised that when brr mode is enabled the rewriter is somewhat slower than normal. Furthermore, that sluggishness persists even if no runes are monitored. You may regain normal performance — regardless of what runes are monitored — by disabling brr mode with :brr nil.

Why isn’t brr mode disabled automatically when no runes are monitored? More generally, why does ACL2 have brr mode at all? Why not just test whether there are monitored runes? If you care about the answers, see Section 8.99 [WHY-BRR], page 398.

4.3 BRR-COMMANDS

BRR-COMMANDS Break-Rewrite (BREAK-REWRITE^) Commands

#.              abort to ACL2 top-level
:target         term being rewritten
:unify-subst    substitution making :lhs equal :target
:hyps           hypotheses of the rule
:hyp i          ith hypothesis of the rule
:lhs            left-hand side of rule's conclusion
:rhs            right-hand side of rule's conclusion
:type-alist     type assumptions governing :target
:initial-ttree  ttree before :eval (see Section 8.89 [TTREE], page 382)
:ancestors      negations of backchaining hypotheses being pursued
:wonp           indicates if application succeed (after :eval)
:rewritten-rhs  rewritten :rhs (after :eval)
:final-ttree    ttree after :eval (see Section 8.89 [TTREE], page 382)
:failure-reason reason rule failed (after :eval)
:path           rewrite's path from top clause to :target
:frame i        ith frame in :path
:top            top-most frame in :path
:ok             exit break
:go             exit break, printing result
:eval           try rule and re-enter break afterwards
:ok!            :ok but no recursive breaks
:go!            :go but no recursive breaks
:eval!          :eval but no recursive breaks
:ok$ runes      :ok with runes monitored during recursion
:go$ runes      :go with runes monitored during recursion
:eval$ runes    :eval with runes monitored during recursion
:help           this message
:standard-help  :help message from ACL2 top-level

Break-rewrite (BREAK-REWRITE^) is just a call of the standard ACL2 read-eval-print loop, ld (LD^), on a “wormhole (WORMHOLE^)” state (STATE^). Thus, you may execute any command (COMMAND^) you might normally execute at the top-level of ACL2. However, all state (STATE^) changes you cause from within break-rewrite (BREAK-REWRITE^) are lost when you exit or :eval the rule. See Chapter 4 [BREAK-REWRITE], page 119 for more details and see Section 9.7 [LD], page 416 for general information about the standard ACL2 read-eval-print loop.

4.4 BRR@

BRR@ to access context sensitive information within break-rewrite (BREAK-REWRITE^)

Example:
(brr@ :target)      ; the term being rewritten
(brr@ :unify-subst) ; the unifying substitution
General Form:
(brr@ :symbol)

where :symbol is one of the following keywords. Those marked with * probably require an implementor’s knowledge of the system to use effectively. They are supported but not well documented. More is said on this topic following the table.

:symbol             (brr@ :symbol)
-------             ---------------------
:target             the term to be rewritten.  This term is an
instantiation of the left-hand side of the
conclusion of the rewrite-rule being broken.
This term is in translated form!  Thus, if
you are expecting (equal x nil) -- and your
expectation is almost right -- you will see
(equal x 'nil); similarly, instead of (cadr a)
you will see (car (cdr a)).  In translated
forms, all constants are quoted (even nil, t,
strings and numbers) and all macros are
expanded.
:unify-subst        the substitution that, when applied to :target,
produces the left-hand side of the rule being
broken.  This substitution is an alist pairing
variable symbols to translated (!) terms.
:wonp               t or nil indicating whether the rune was
successfully applied.  (brr@ :wonp) returns
nil if evaluated before :EVALing the rule.
:rewritten-rhs      the result of successfully applying the rule
or else nil if (brr@ :wonp) is nil.  The result
of successfully applying the rule is always a
translated (!) term and is never nil.
:failure-reason     some non-nil lisp object indicating why the rule
was not applied or else nil.  Before the rule is

:EVALed, (brr@ :failure-reason) is nil.  After
:EVALing the rule, (brr@ :failure-reason) is nil
if (brr@ :wonp) is t.  Rather than document the
various non-nil objects returned as the failure
reason, we encourage you simply to evaluate
(brr@ :failure-reason) in the contexts of interest.
Alternatively, study the ACL2 function tilde-@-
failure-reason-phrase.
:lemma           *  the rewrite rule being broken.  For example,
(access rewrite-rule (brr@ :lemma) :lhs) will
return the left-hand side of the conclusion
of the rule.
:type-alist      *  a display of the type-alist governing :target.
Elements on the displayed list are of the form
(term type), where term is a term and type
describes information about term assumed to hold
in the current context.  The type-alist may be
used to determine the current assumptions, e.g.,
whether A is a CONSP.
:ancestors       *  a list of translated terms each of which may be
assumed to be true because the rewriter is currently
trying to prove each nil.  When the rewriter
recursively rewrites a hypothesis of a rule it
adds the negation of the hypothesis to ancestors.
Ancestors is primarily used to prevent infinite
backchaining.
:gstack          *  the current goal stack.  The gstack is maintained
by rewrite and is the data structure printed as the
current ``path.''  Thus, any information derivable
from the :path brr command is derivable from gstack.
For example, from gstack one might determine that
the current term is the second hypothesis of a
certain rewrite rule.

In general brr@-expressions are used in break conditions, the expressions that determine whether interactive breaks occur when monitor (MONITOR^)ed rune (RUNE^)s are applied. See Section 4.5 [MONITOR], page 130. For example, you might want to break only those attempts in which one particular term is being rewritten or only those attempts in which the binding for the variable a is known to be a consp (CONSP^). Such conditions can be expressed using ACL2 system functions and the information provided by brr@. Unfortunately, digging some of this information out of the internal data structures may be awkward or may, at least, require intimate knowledge of the system functions. But since conditional expressions may employ arbitrary functions and macros, we anticipate that a set of convenient primitives will gradually evolve within the ACL2 community. It is to encourage this evolution that brr@ provides access to the *’d data.

4.5 MONITOR

MONITOR to monitor the attempted application of a rule name

     Example:
     (monitor '(:rewrite assoc-of-app) 't)
     :monitor (:rewrite assoc-of-app) t
     :monitor (:definition app) (equal (brr@ :target) '(app c d))
     General Form:
     (monitor rune term)

where rune is a rune (RUNE^) and term is a term, called the “break condition.” Rune must be either a :rewrite rune (RUNE^) (of subclass backchain) or a :definition rune (RUNE^). (Note: Some :rewrite rules are considered “simple abbreviations” — see Section 8.81 [SIMPLE], page 364 — and cannot be monitor (MONITOR^)ed. Monitoring is carried out by code inside the rewriter but abbreviation rules are applied by a special purpose simplifier.) When a rune (RUNE^) is monitor (MONITOR^)ed any attempt to apply it may result in an interactive break in an ACL2 “wormhole (WORMHOLE^) state (STATE^).” There you will get a chance to see how the application proceeds. See Chapter 4 [BREAK-REWRITE], page 119 for a description of the interactive loop entered. Whether an interactive break occurs depends on the value of the break condition expression associated with the monitor (MONITOR^)ed rune (RUNE^).

To remove a rune (RUNE^) from the list of monitor (MONITOR^)ed rune (RUNE^)s, use unmonitor. To see which rune (RUNE^)s are monitor (MONITOR^)ed and what their break conditions are, evaluate (monitored-runes).

Monitor, unmonitor and monitored-runes are macros that expand into expressions involving state. While these macros appear to return the list of monitor (MONITOR^)ed rune (RUNE^)s this is an illusion. They all print monitor (MONITOR^)ed rune (RUNE^) information to the comment window and then return error triples instructing ld to print nothing. It is impossible to return the list of monitor (MONITOR^)ed rune (RUNE^)s because it exists only in the wormhole (WORMHOLE^) state (STATE^) with which you interact when a break occurs. This allows you to change the monitor (MONITOR^)ed rune (RUNE^)s and their conditions during the course of a proof attempt without changing the state (STATE^) in which the the proof is being constructed.

Unconditional break points are obtained by using the break condition t. We now discuss conditional break points. The break condition, expr, must be a term that contains no free variables other than state and that returns a single non-state result. In fact, the result should be nil, t, or a true list of commands to be fed to the resulting interactive break. Whenever the system attempts to use the associated rule, expr is evaluated in the wormhole (WORMHOLE^) interaction state (STATE^). A break occurs only if the result of evaluating expr is non-nil. If the result is a true list, that list is appended to the front of standard-oi and hence is taken as the initial user commands issued to the interactive break.

In order to develop effective break conditions it must be possible to access context sensitive information, i.e., information about the context in which the monitor (MONITOR^)ed rune (RUNE^) is being tried. The brr@ macro may be used in break conditions to access such information as the term being rewritten and the current governing assumptions. This information is not stored in the proof state (STATE^) but is transferred into the wormhole (WORMHOLE^) state (STATE^) when breaks occur. The macro form is (brr@ :sym) where :sym is one of several keyword symbols, including :target (the term being rewritten), :unify-subst (the substitution that instantiates the left-hand side of the conclusion of the rule so that it is the target term), and :type-alist (the governing assumptions). See Section 4.4 [BRR@], page 128.

For example,

     ACL2 !>:monitor (:rewrite assoc-of-app)
                     (equal (brr@ :target) '(app a (app b c)))

will monitor (:rewrite assoc-of-app) but will cause an interactive break only when the target term, the term being rewritten, is (app a (app b c)).

Because break conditions are evaluated in the interaction environment, the user developing a break condition for a given rune (RUNE^) can test candidate break conditions before installing them. For example, suppose an unconditional break has been installed on a rune (RUNE^), that an interactive break has occurred and that the user has determined both that this particular application is uninteresting and that many more such applications will likely occur. An appropriate response would be to develop an expression that recognizes such applications and returns nil. Of course, the hard task is figuring out what makes the current application uninteresting. But once a candidate expression is developed, the user can evaluate it in the current context simply to confirm that it returns nil.

Recall that when a break condition returns a non-nil true list that list is appended to the front of standard-oi. For example,

     ACL2 !>:monitor (:rewrite assoc-of-app) '(:go)

will cause (:rewrite assoc-of-app) to be monitor (MONITOR^)ed and will make the break condition be '(:go). This break condition always evaluates the non-nil true list (:go). Thus, an interactive break will occur every time (:rewrite assoc-of-app) is tried. The break is fed the command :go. Now the command :go causes break-rewrite to (a) evaluate the attempt to apply the lemma, (b) print the result of that attempt, and (c) exit from the interactive break and let the proof attempt continue. Thus, in effect, the above :monitor merely “traces” the attempted applications of the rune (RUNE^) but never causes an interactive break requiring input from the user.

It is possible to use this feature to cause a conditional break where the effective break condition is tested after the lemma has been tried. For example:

     ACL2 !>:monitor (:rewrite lemma12)
                     '(:unify-subst
                       :eval$ nil
                       :ok-if (or (not (brr@ :wonp))
                                  (not (equal (brr@ :rewritten-rhs) '(foo a))))
                       :rewritten-rhs)

causes the following behavior when (:rewrite lemma12) is tried. A break always occurs, but it is fed the commands above. The first, :unify-subst, causes break-rewrite to print out the unifying substitution. Then in response to :eval$ nil the lemma is tried but with all rune (RUNE^)s temporarily unmonitor (UNMONITOR^)ed. Thus no breaks will occur during the rewriting of the hypotheses of the lemma. When the attempt has been made, control returns to break-rewrite (which will print the results of the attempt, i.e., whether the lemma was applied, if so what the result is, if not why it failed). The next command, the :ok-if with its following expression, is a conditional exit command. It means exit break-rewrite if either the attempt was unsuccessful, (not (brr@ :wonp)), or if the result of the rewrite is any term other than (foo a). If this condition is met, the break is exited and the remaining break commands are irrelevant. If this condition is not met then the next command, :rewritten-rhs, prints the result of the application (which in this contrived example is known to be (foo a)). Finally, the list of supplied commands is exhausted but break-rewrite expects more input. Therefore, it begins prompting the user for input. The end result, then, of the above :monitor command is that the rune (RUNE^) in question is elaborately traced and interactive breaks occur whenever it rewrites its target to (foo a).

We recognize that the above break condition is fairly arcane. We suspect that with experience we will develop some useful idioms. For example, it is straightforward now to define macros that monitor rune (RUNE^)s in the ways suggested by the following names: trace-rune, break-if-target-is, and break-if-result-is. For example, the last could be defined as

     (defmacro break-if-result-is (rune term)
       `(monitor ',rune
                 ''(:eval :ok-if
                          (not (equal (brr@ :rewritten-rhs) ',term)))))

(Note however that the submitted term must be in translated form.)

Since we don’t have any experience with this kind of control on lemmas we thought it best to provide a general (if arcane) mechanism and hope that the ACL2 community will develop the special cases that we find most convenient.

4.6 MONITORED-RUNES

MONITORED-RUNES print the monitor (MONITOR^)ed rune (RUNE^)s and their break conditions

     Example and General Form:
     :monitored-runes

This macro prints a list, each element of which is of the form (rune expr), showing each monitor (MONITOR^)ed rune (RUNE^) and its current break condition.

4.7 OK-IF

OK-IF conditional exit from break-rewrite

     Example Form:
     :ok-if (null (brr@ :wonp))
     General Form:
     :ok-if expr

where expr is a term involving no free variables other than state and returning one non-state result which is treated as Boolean. This form is intended to be executed from within break-rewrite (see Chapter 4 [BREAK-REWRITE], page 119).

Consider first the simple situation that the (ok-if term) is a command read by break-rewrite. Then, if the term is non-nil, break-rewrite exits and otherwise it does not.

More generally, ok-if returns an ACL2 error triple (mv erp val state). (See Section 9.7 [LD], page 416 for more on error triples.) If any form being evaluated as a command by break-rewrite returns the triple returned by (ok-if term) then the effect of that form is to exit break-rewrite (BREAK-REWRITE^) if term is non-nil. Thus, one might define a function or macro that returns the value of ok-if expressions on all outputs and thus create a convenient new way to exit break-

rewrite.

The exit test, term, generally uses brr@ to access context sensitive information about the attempted rule application. See Section 4.4 [BRR@], page 128. Ok-if is useful inside of command sequences produced by break conditions. See Section 4.5 [MONITOR], page 130. :ok-if is most useful after an :eval command has caused break-rewrite to try to apply the rule because in the resulting break environment expr can access such things as whether the rule succeeded, if so, what term it produced, and if not, why. There is no need to use :ok-if before :evaling the rule since the same effects could be achieved with the break condition on the rule itself. Perhaps we should replace this concept with :eval-and-break-if? Time will tell.

4.8 UNMONITOR

UNMONITOR to stop monitoring a rule name

     Examples:
     (unmonitor '(:rewrite assoc-of-app))
     :unmonitor (:rewrite assoc-of-app)
     :unmonitor :all
     General Forms:
     (unmonitor rune)
     (unmonitor :all)

Here, rune is a rune (RUNE^) that is currently among those with break points installed. This function removes the break.

Subtle point: Because you may want to unmonitor a “rune (RUNE^)” that is no longer a rune (RUNE^) in the current ACL2 world (WORLD^), we don’t actually check this about rune (RUNE^). Instead, we simply check that rune (RUNE^) is a consp beginning with a keywordp.

Chapter 4: BREAK-REWRITE 135 That way, you’ll know you’ve made a mistake if you try to :unmonitor binary-append instead of

:unmonitor (:definition binary-append), for example.

136 ACL2 Version 1.9

5 DOCUMENTATION

DOCUMENTATION functions that display documentation at the terminal

This section explains the ACL2 online documentation system. Thus, it assumes that you are typing at the terminal, inside an ACL2 session. If you are reading this description in another setting (for example, on paper), simply ignore the parts of this description that involve typing at the terminal.

For an introduction to the ACL2 online documentation system, type :more (MORE^) below. Whenever the documentation system concludes with “(cont’d)” you may type :more (MORE^) to see the next block of documentation.

Topics related to documentation are documented individually:

* *TERMINAL-MARKUP-TABLE*:: a markup (MARKUP^) table used for printing to the terminal * ARGS:: args, guard (GUARD^), type, constraint (CONSTRAINT^), etc., of a function symbol * DOC:: brief documentation (DOCUMENTATION^) (type :doc name)

* DOC!:: all the documentation (DOCUMENTATION^) for a name (type :doc! name)

* DOC-STRING:: formatted documentation (DOCUMENTATION^) strings

* DOCS:: available documentation (DOCUMENTATION^) topics (by section)

* HELP:: brief survey of ACL2 features

* MARKUP:: the markup language for ACL2 documentation (DOCUMENTATION^) strings

* MORE:: your response to :doc (DOC^) or :more-doc (MORE-DOC^)’s “(cont'd)”

* MORE!:: another response to “(cont’d)”

* MORE-DOC:: a continuation of the :doc (DOC^) documentation (DOCUMENTATION^)

* NQTHM-TO-ACL2:: ACL2 analogues of Nqthm functions and commands

The ACL2 online documentation feature allows you to see extensive documentation on many ACL2 functions and ideas. You may use the documentation facilities to document your own ACL2 functions and theorems.

If there is some name you wish to know more about, then type

     ACL2 !>:doc name

in the top-level loop. If the name is documented, a brief blurb will be printed. If the name is not documented, but is “similar” to some documented names, they will be listed. Otherwise, nil is returned.

Every name that is documented contains a one-line description, a few notes, and some details. :Doc (DOC^) will print the one-liner and the notes. When :doc (DOC^) has finished it stops with the message “(cont’d)” to remind you that details are available. If you then type

     ACL2 !>:more

a block of the continued text will be printed, again concluding with “(cont’d)” if the text continues further, or concluding with “*-” if the text has been exhausted. By continuing to type :more (MORE^) until exhausting the text you can read successive blocks. Alternatively, you can type :more! (MORE!^) to get all the remaining blocks.

If you want to get the details and don’t want to see the elementary stuff typed by :doc (DOC^) name, type:

     ACL2 !>:MORE-DOC name

We have documented not just function names but names of certain important ideas too. For example, see Section 15.14 [REWRITE], page 764 and see Section 15.12 [META], page 758 to learn about :rewrite (REWRITE^) rules and :meta (META^) rules, respectively. See Section 8.43 [HINTS], page 319 to learn about the structure of the :hints (HINTS^) argument to the prover. The deflabel (DEFLABEL^) event (see Section 6.9 [DEFLABEL], page 171) is a way to introduce a logical name for no reason other than to attach documentation to it; also see Section 6.6 [DEFDOC], page 167.

How do you know what names are documented? There is a documentation data base which is querried with the :docs (DOCS^) command.

The documentation data base is divided into sections. The sections are listed by

     ACL2 !>:docs *

Each section has a name, sect, and by typing

     ACL2 !>:docs sect

or equivalently

     ACL2 !>:doc sect

you will get an enumeration of the topics within that section. Those topics can be further explored by using :doc (DOC^) (and :more (MORE^)) on them. In fact the section name itself is just a documented name. :more (MORE^) generally gives an informal overview of the general subject of the section.

     ACL2 !>:docs **

will list all documented topics, by section. This fills several pages but might be a good place to start.

If you want documentation on some topic, but none of our names or brief descriptions seem to deal with that topic, you can invoke a command to search the text in the data base for a given string. This is like the GNU Emacs “apropos (APROPOS^)” command.

     ACL2 !>:docs "functional inst"

will list every documented topic whose :doc (DOC^) or :more-doc (MORE-DOC^) text includes the substring "functional inst", where case and the exact number of spaces are irrelevant.

If you want documentation on an ACL2 function or macro and the documentation data base does not contain any entries for it, there are still several alternatives.

     ACL2 !>:args fn

will print the arguments and some other relevant information about the named function or macro. This information is all gleaned from the definition (not from the documentation data base) and hence this is a definitive way to determine if fn is defined as a function or macro.

You might also want to type:

     ACL2 !>:pc fn

which will print the command (COMMAND^) which introduced fn. You should see Section 8.12 [COMMAND-DESCRIPTOR], page 261 for details on the kinds of input you can give the :pc (PC^) command.

The entire ACL2 documentation data base is user extensible. That is, if you document your function definitions or theorems, then that documentation is made available via the data base and its query commands.

The implementation of our online documentation system makes use of Common Lisp’s “documentation strings.” While Common Lisp permits a documentation string to be attached to any defined concept, Common Lisp assigns no interpretation to these strings. ACL2 attaches special significance to documentation strings that begin with the characters “:doc-section”. When such a documentation string is seen, it is stored in the data base and may be displayed via :doc (DOC^), :more (MORE^), :docs (DOCS^), etc. Such documentation strings must follow rigid syntactic rules to permit their processing by our commands. These are spelled out elsewhere; see Section 5.5 [DOC-STRING], page 143.

A description of the structure of the documentation data base may also be found; see Section 5.5 [DOC-STRING], page 143.

5.1 *TERMINAL-MARKUP-TABLE*

*TERMINAL-MARKUP-TABLE* a markup (MARKUP^) table used for printing to the terminal

The value of the ACL2 constant *terminal-markup-table* is an association list pairing markup (MARKUP^) keys with strings, to be used for printing to the terminal. See Section 5.8 [MARKUP], page 148 for a description of the ACL2 markup (MARKUP^) language.

The entries in *terminal-markup-table* are of the form

     (key . fmt-string)

where key is one of the doc-string (DOC-STRING^) tilde directives (see Section 5.8 [MARKUP], page 148), and fmt-string is a string as expected by the ACL2 printing function fmt (FMT^). The system arranges that for any arg, when an expression ~key[arg] is encountered by the documentation (DOCUMENTATION^) printer, fmt (FMT^) will print fmt-string in the association list where #\a is bound to arg and #\A is bound to the result of applying the function string-upcase (STRING-UPCASE^) to arg.

It is possible to implement tools in ACL2 for printing documentation (DOCUMENTATION^) to other than the terminal. In fact, such tools exist for Texinfo and for HTML. For now, discussion of this capability is beyond the scope of the present topic.

5.2 ARGS

ARGS args, guard (GUARD^), type, constraint (CONSTRAINT^), etc., of a function symbol

     Example:
     :args assoc-eq

Args takes one argument, a symbol which must be the name of a function or macro, and prints out the formal parameters, the guard (GUARD^) expression, the output signature (SIGNATURE^), the deduced type, the constraint (CONSTRAINT^) (if any), and whether documentation (DOCU-MENTATION^) about the symbol is available via :doc (DOC^). The output signature (SIGNA-TURE^) is either & indicating that the function returns one value; state (STATE^), indicating that it returns a state (STATE^), or an expression (mv & & ... state ... &) indicating how many multiple values it returns and which if any is a state (STATE^).

5.3 DOC

DOC brief documentation (DOCUMENTATION^) (type :doc name)

NOTE: The :doc command only makes sense at the terminal. Furthermore it only works at the terminal when a “full-size” image has been built. Most users will probably access the ACL2 documentation in other ways, as explained in the file "doc/README" that comes with the ACL2 distribution.

     Examples:
     ACL2 !>:doc DEFTHM          ; print documentation of DEFTHM
     ACL2 !>:doc logical-name    ; print documentation of LOGICAL-NAME
     ACL2 !>:doc "MY-PKG"      ; print documentation of "MY-PKG"
     Related Topics:
     :more                      ; continues last :doc or :more-doc text
     :more-doc name             ; prints more documentation for name
     :docs **                   ; lists all documented symbols
     :docs "compil"             ; documented symbols apropos "compil"
     :DOC documentation         ; describes how documentation works
     General Form:
     ACL2>:doc logical-name

where logical-name (LOGICAL-NAME^) is a logical name (see Section 8.63 [LOGICAL-NAME], page 346) for which you hope there is documentation (DOCUMENTATION^). Chances are there is no documentation (DOCUMENTATION^) at the moment, but we are working on adding documentation (DOCUMENTATION^) strings for all the user level ACL2 functions.

For a general discussion of our treatment of documentation strings, see Chapter 5 [DOCUMEN-TATION], page 137.

This is the first cut at online documentation (DOCUMENTATION^). Users can be particularly helpful by sending mail on the inadequacies of the system. Address it just to Moore and put Documentation (DOCUMENTATION^) in the subject line. There are several things that trouble me about what I’ve done here.

First, many concepts aren’t documented. Ultimately, I’d like to . document (a) every CLTL primitive (e.g., case (CASE^) and coerce (COERCE^)) and (b) every ACL2 extension (e.g., aref1 (AREF1^) and getprop). But so far I have focussed on documenting (c) the ACL2 system primitives (e.g., defthm (DEFTHM^) and what hints (HINTS^) look like). My priorities are (c), then (b), and then (a), following the philosophy that the most unstable features should get online documentation (DOCUMENTATION^) in these early releases. Having gotten the basic documentation (DOCUMENTATION^) in place, I’ll document new things as they are added, and in response to your pleas I’ll try to add documentation (DOCUMENTATION^) to old things that are widely regarded as important.

Second, I worry that the existing documentation (DOCUMENTATION^) is unhelpful because it provides too much or too little detail, or it provides the detail too far away from where it is needed. Please be on the lookout for this. Did you get what you needed when you appealed to :doc or :more-doc (MORE-DOC^)? If not, what was it you needed? Would more cross-references help (HELP^)? Did you get lost in maze of cross-references?

5.4 DOC!

DOC! all the documentation (DOCUMENTATION^) for a name (type :doc! name)

NOTE: The :doc! command only makes sense at the terminal.

     Examples:
     ACL2 !>:doc! defthm
     ACL2 !>:doc! certificate

This command is like :doc name followed by :more! (MORE!^). It prints all the documentation (DOCUMENTATION^) of name.

5.5 DOC-STRING

DOC-STRING formatted documentation (DOCUMENTATION^) strings

     Examples:
     ":Doc-Section name
     one-liner~/notes~/details"
     ":Doc-Section name
     one-liner~/
     notes~/
     details~/
     :cite old-name1
     :cited-by old-name2"
Use (get-doc-string 'name state) to see other examples.

Documentation (DOCUMENTATION^) strings not beginning with “:Doc-Section” (case is irrelevant) are ignored. See Section 5.8 [MARKUP], page 148 for how to supply formatting information (such as fonts and displayed text) in documentation (DOCUMENTATION^) strings.

ACL2 attaches special importance to documentation (DOCUMENTATION^) strings beginning with the header “:Doc-Section” (or any variant thereof obtained by changing case). Any documentation (DOCUMENTATION^) string that does not begin with such a header is considered unformatted and is ignored. For the rest of this discussion, we use the phrase “documentation (DOC-UMENTATION^) string” as though it read “formatted documentation (DOCUMENTATION^) string.”

Documentation (DOCUMENTATION^) strings are always processed in the context of some symbol, name, being defined. (Indeed, if an event defines no symbol, e.g., verify-guards (VERIFY-GUARDS^) or in-theory (IN-THEORY^), then it is not permitted to have a formatted documentation (DOCUMENTATION^) string.) The string will be associated with name in the “documentation (DOCUMENTATION^) data base.” The data base is divided into “sections” and each section is named by a symbol. Among the sections are events (EVENTS^), documentation (DOCUMENTATION^), history (HISTORY^), other (OTHER^), and miscellaneous (MIS-CELLANEOUS^). A complete list of the sections may be obtained by typing :docs * at the terminal. You can create new sections. The main purpose of sections is simply to partition the large set of names into smaller subsets whose contents can be enumerated separately. The idea is that the user may remember (or recognize) the relevant section name and then read its contents to find interesting items.

Within a section are “documentation (DOCUMENTATION^) tuples” which associate with each documented name its documentation (DOCUMENTATION^) string and a list of related documented names, called the “related names” of the name. When :doc (DOC^) prints the documentation (DOCUMENTATION^) for name, it always lists the related names.

When a formatted documentation (DOCUMENTATION^) string is submitted with the defining event of some name, the section name and an initial set of related names are parsed from the string. In addition, the formatted string contains various “levels” of detail that are printed out at different times. Finally, it is possible for a string to cause the newly documented name to be added to the related names of any previously documented name. Thus, as new names are introduced they can be grouped with old ones.

The general form of an ACL2 formatted documentation (DOCUMENTATION^) string is

     ":DOC-SECTION <section-name>
       <one-liner>~/
       <notes>~/
       <details>~/
       :CITE <n1>
       ...
       :CITE <nn>
       :CITED-BY <m1>
       ...
       :CITED-BY <mm>"

Before we explain this, let it be noted that (get-doc-string name state) will return the documentation (DOCUMENTATION^) string associated with name in the documentation (DOCUMEN-TATION^) data base. You may want to call get-doc-string on 'pe (PE^) and 'union-theories (UNION-THEORIES^) just to see some concrete documentation (DOCUMENTATION^) strings. This documentation (DOCUMENTATION^) string, which is rather long, is under 'doc-string.

A formatted documentation (DOCUMENTATION^) string has five parts: the header and sectionname (terminating in the first #\Newline), the <one-liner>, <notes>, and <details> (each terminating in a tilde-slash (“~/”) pair), and a citation part. These five parts are parsed into six components. <section-name> is read as the name of a symbol, section-name. <one-liner>, <notes>, and <details> are arbitrary sequences of characters (CHARACTERS^) (ignoring initial white space and not including the tilde-slash pairs which terminate them). The <ni> are read as symbols and assembled into a list called the “cite” symbols. The <mi> are read as symbols and assembled into a list called the “cited-by” symbols. See the warning below regarding the hackish nature of our symbol reader.

Section-name must either be a previously documented symbol or else be name, the symbol being documented. To open a new section of the data base, named section-name, you should define the logical name section-name (as by deflabel (DEFLABEL^) or any other event; also see Section 6.6 [DEFDOC], page 167) and attach to it a documentation (DOCUMENTATION^) string for section section-name. You might wish to print out the documentation (DOCUMENTATION^) string we use for some of our section names, e.g., (get-doc-string 'events state). By forcing section names to be documented symbols, we permit sections themselves to have one line descriptions and discussions, presented by the standard documentation (DOCUMENTATION^) facilities like the facilities :doc (DOC^) and :more-doc (MORE-DOC^) that may be used at the terminal.

Each of the ni’s and mi’s must be previously documented symbols.

Both <one-liner> and <details> must be non-empty, i.e., must contain some non-whitespace characters (CHARACTERS^). <notes> may be empty. The :cites and :cited-bys pairs may be intermingled and may be separated by either newlines or spaces. The citation part may be empty. When the citation part is empty, the tilde-slash pair terminating the <details> part may be omitted. Thus, the simplest form of a formatted documentation (DOCUMENTATION^) string is:

     ":Doc-Section <section-name>
      <one-liner>~/~/
      <details>"

Since white space at the front of <one-liner>, <notes> and <details> is ignored, we often precede those parts by #\Newlines to make the strings easier to read in our source files. We also typically indent all of the text in the string by starting each line with a few spaces. (The Emacs commands for formatting Lisp get confused if you have arbitrary characters (CHARACTERS^) on the left margin.) We assume that every line in <one-liner>, <notes>, and <details> starts with at least as many spaces as <one-liner> does, i.e., we assume they are all indented the same amount (or more). Let d be the number of spaces separating <one-liner> from the #\Newline preceding it. When the various parts are printed, we “de-indent” by stripping out the first d spaces following

each #\Newline.

However, we find that when documentation (DOCUMENTATION^) is printed flush against the left margin it is difficult to distinguish the documentation (DOCUMENTATION^) text from previous output. We therefore prefix each line we print by a special pad of characters (CHARACTERS^). By default, this pad is “| ” so that documentation (DOCUMENTATION^) text has a vertical bar running down the left margin. But the pad is just the value of the global variable doc-prefix and you may assign (ASSIGN^) it any string you wish.

To add such a string to the data base under the symbol name we make a new entry in the sectionname section of the data base. The entry associates name with the string and uses the string’s cites list as the initial value of the related names field. In addition, we add name to the related names field of each of the names listed in the string’s cited-by list. We also add name to the related names field of its section-name. Observe that the cites list in a string is only the initial value of the related names of the names. Future documentation (DOCUMENTATION^) strings may add to it via :cited-by or :doc-section. Indeed, this is generally the case. We discuss this further below.

When a brief description of name is required (as by :docs **), name and <one-liner> are printed. <one-liner> is usually printed starting in column 15 (however see Section 8.71 [PRINT-DOC-START-COLUMN], page 354). Despite its name, <one-liner> need not be one line. It usually is one line, however.

When you type :doc (DOC^) name at the terminal, the first response will be to print name and <one-liner>. Then :doc (DOC^) prints <notes>, if any. Then, if name is the name of a section, it prints the <one-liner>s for each of its related names. For example, try :doc events. If name is not a section name but does have some related names, they are merely listed but not explained.

Try :doc theory-functions. :more-doc name prints <details>.

Our style is to let each new concept add itself to the related names of old concepts. To do otherwise increases the chances that documentation (DOCUMENTATION^) gets outdated because one often forgets to update supposedly complete lists of the relevant topics when new topics are invented. For example, :doc theory-functions lists each available theory function. But get-doc-string of 'theory-functions (THEORY-FUNCTIONS^) just shows a few examples and has an empty cites list. From where do we get the names of the theory functions listed by :doc (DOC^)? The answer is that each theory function has its own documentation (DOCUMENTATION^) string and those strings each specify :cited-by theory-functions (THEORY-FUNCTIONS^). See for example get-doc-string of 'union-theories (UNION-THEORIES^). So by the time the entire system is assembled, the related names of 'theory-functions (THEORY-FUNCTIONS^) contains all the (documented) theory functions. This makes it easy to add new theory functions without changing the general discussion in 'theory-functions (THEORY-FUNCTIONS^).

When an event or command (COMMAND^) form is printed, as by :pe (PE^) or :pc (PC^), that contains a formatted documentation (DOCUMENTATION^) string, we do not print the actual documentation (DOCUMENTATION^) string (since they are usually large and distracting). Instead we print the string:

       "Documentation available via :doc"

inviting you to use :doc (DOC^) and :more-doc (MORE-DOC^) (or get-doc-string) if you wish to see the documentation (DOCUMENTATION^) at the terminal.

Warning on Reading Symbols from Strings: When we read a symbol, such as the section-symbol, from a documentation (DOCUMENTATION^) string, we use a quick and dirty imitation of the much more powerful CLTL read program. In particular, we scan past any whitespace, collect all the characters (CHARACTERS^) we see until we get to more whitespace or the end of the string, convert the characters (CHARACTERS^) to upper case, make a string out of them, and intern (INTERN^) that string. Thus, if you typed ":Doc-Section 123 ..." we would read the 123 as the symbol |123|. Observe that special characters (CHARACTERS^), such as parentheses and escape characters (CHARACTERS^), are not afforded their usual reverence by our hack. Furthermore, the question arises: in which package do we intern (INTERN^) the symbol? The answer is, usually, the package containing the name being defined. I.e., if you are documenting my-pkg::name and you attach a documentation (DOCUMENTATION^) string that begins ":Doc-Section: Machines ..." then the section-symbol will be my-pkg::machines. We recognize two special cases. If the first character read is a colon, we use the keyword package. If the first five characters (CHARACTERS^) read are acl2:: then we intern (INTERN^) in the "ACL2" package. Our own section names, e.g., events (EVENTS^), are in the "ACL2" package.

In a related area, when you ask for the documentation (DOCUMENTATION^) of a name, e.g., when you type :doc name at the terminal, that name is read with the full ACL2 reader, not the hack just described. That name is read into the current package. Thus, if you are operating

in-package (IN-PACKAGE^) "MY-PKG" and type :doc events, what is read is my-pkg::events.

The data base may not contain an entry for this symbol. Before reporting that no documentation (DOCUMENTATION^) exists, we try acl2::events.

One last note: defpkg (DEFPKG^) permits a formatted documentation (DOCUMENTATION^) string, which is associated in the data base with the name of the package. But the name of the package is a string, not a symbol. It is permitted to access the documentation (DOCUMENTATION^) of a string (i.e., package name). But there are no facilities for getting such a stringp (STRINGP^) name into the related names of another name nor of making such stringp (STRINGP^) names be section names. That is because we always read symbols from strings and never read strings from strings. I.e., if you did write "Doc-Section \"MY-PKG\" ..." it would read in as a weird symbol.

5.6 DOCS

DOCS available documentation (DOCUMENTATION^) topics (by section)

NOTE: The :docs command only makes sense at the terminal.

Examples:
ACL2 !>:docs *           ; lists documentation sections
ACL2 !>:docs **          ; lists all documented topics within all sections
ACL2 !>:docs events      ; lists all topics in section EVENTS
ACL2 !>:docs "compil"    ; lists topics ``apropos''

The data base of formatted documentation (DOCUMENTATION^) strings is structured into sections. Within a section are topics. Each topic has a one-liner, some notes, and some detailed discussions. The :docs command provides a view of the entire data base.

:docs takes one argument, as described below:

arg               effect
*                 list all section headings in the data base
**                list all section headings and all topics within
                  each section
name              list all topics in the section named name (where
                  name is some symbol other than * and **).  This
                  is always the same as :doc name.
pattern           list all topics whose :doc or :more-doc text
                  mentions the string pattern.  For purposes of this
                  string matching we ignore distinctions of case and
                  the amount and kind (but not presence) of white
                  space.  We also treat hyphen as whitespace.

5.7 HELP

HELP brief survey of ACL2 features

Example:
ACL2 !>:help

See Section 8.65 [LP], page 350 for general information about the top-level command (COM-MAND^) environment for ACL2.

5.8 MARKUP

MARKUP the markup language for ACL2 documentation (DOCUMENTATION^) strings

ACL2 documentation (DOCUMENTATION^) strings make special use of the tilde character (~). In particular, we describe here a “markup language” for which the tilde character plays a special role. The markup language is valuable if you want to write documentation (DOCUMENTATION^) that is to be displayed outside your ACL2 session. If you are not writing such documentation (DOCUMENTATION^), and if also you do not use the character ‘~’, then there is no need to read on.

Three uses of the tilde character (~) in documentation (DOCUMENTATION^) strings are as follows. Below we explain the uses that constitute the ACL2 markup language.

     ~/

Indicates the end of a documentation section; see Section 5.5 [DOC-STRING], page 143.

     ~~

Indicates the literal insertion of a tilde character (~).

     ~]

This directive in a documentation string is effective only during the processing of part 2, the details (see Section 5.5 [DOC-STRING], page 143), and controls how much is shown on each round of :more (MORE^) processing when printing to the terminal. If the system is not doing :more (MORE^) processing, then it acts as though the ~] is not present. Otherwise, the system put out a newline and halts documentation printing on the present topic, which can be resumed if the user types :more (MORE^) at the terminal.

The other uses of the tilde character are of the following form.

       ~key[arg]

Before launching into an explanation of how this works in detail, let us consider some small examples.

Here is a word that is code:

       ~c[function-name].

Here is a phrase with an “emphasized” word, “not”:

       Do ~em[not] do that.

Here is the same phrase, but where “not” receives stronger emphasis (presumably boldface in a printed version):

       Do ~st[not] do that.

Here is a passage that is set off as a display, in a fixed-width font:

       ~bv[]
       This passage has been set off as ``verbatim''.
       The present line starts just after a line break.  Normally, printed
       text is formatted, but inside ~bv[]...~ev[], line breaks are taken
       literally.
       ~ev[]

In general, the idea is to provide a “markup language” that can be reasonably interpreted not only at the terminal (via :doc (DOC^)), but also via translators into other languages. In fact, translators have been written into Texinfo and HTML.

Let us turn to a more systematic consideration of how to mark text in documentation (DOCU-MENTATION^) strings using expressions of the form ~key[arg], which we will call “doc-string (DOC-STRING^) tilde directives.” The idea is that key informs the documentation (DOCUMEN-TATION^) printer (which could be the terminal, a hardcopy printer, or some hypertext tool) about the “style” used to display arg. The intention is that each such printer should do the best it can. For example, we have seen above that ~em[arg] tells the printer to emphasize arg if possible, using an appropriate display to indicate emphasis (italics, or perhaps surrounding arg with some character like _, or ...). For another example, the directive for bold font, ~b[arg], says that printed text for arg should be in bold if possible, but if there is no bold font available (such as at the terminal), then the argument should be printed in some other reasonable manner (for example, as ordinary text). The key part is case-insensitive; for example, you can use ~BV[] or ~Bv[] or ~bV[] in place of ~bv[].

Every form below may have any string as the argument (inside [..]), as long as it does not contain a newline (more on that below). However, when an argument does not make much sense to us, we show it below as the empty string, e.g., “~bv[]” rather than “~bv[arg]”.

~-[]      Print the equivalent of a dash
~b[arg]   Print the argument in bold font, if available
~bid[arg]   ``Begin implementation dependent'' -- Ignores argument at
          terminal.
~bf[]     Begin formatted text (respecting spaces and line breaks),
          but in ordinary font (rather than, say, fixed-width font)
          if possible
~bq[]     Begin quotation (indented text, if possible)
~bv[]     Begin verbatim (print in fixed-width font, respecting
          spaces and line breaks)
~c[arg]   Print arg as ``code'', such as in a fixed-width font
~ef[]     End format; balances ~bf[]
~eid[arg]   ``End implementation dependent'' -- Ignores argument at
          terminal.
~em[arg]  Emphasize arg, perhaps using italics
~eq[]     End quotation; balances ~bq[]
~ev[]     End verbatim; balances ~bv[]
~i[arg]   Print arg in italics font
~id[arg]   ``Implementation dependent'' -- Ignores argument at
          terminal.
~il[arg]  Print argument as is, but make it a link (for true
          hypertext environments)
~ilc[arg] Same as ~il[arg], except that arg should be printed as
          with ~c[arg]
~l[arg]   Ordinary link; prints as ``See :DOC arg'' at the terminal
          (but also see ~pl below, which puts ``see'' in lower case)
~nl[]     Print a newline
~par[]    Paragraph mark, of no significance at the terminal
          (can be safely ignored; see also notes below)

     ~pl[arg]  Parenthetical link (borrowing from Texinfo):  same as
               ~l[arg], except that ``see'' is in lower case.  This is
               typically used at other than the beginning of a sentence.
     ~sc[arg]  Print arg in (small, if possible) capital letters
     ~st[arg]  Strongly emphasize arg, perhaps using a bold font
     ~t[arg]   Typewriter font; similar to ~c[arg], but leaves less
               doubt about the font that will be used.
     ~terminal[arg]  Terminal only; arg is to be ignored except when
               reading documentation at the terminal, using :DOC.

Style notes and further details

It is not a good idea to put doc-string (DOC-STRING^) tilde directives inside verbatim environ-

ments, ~bv[] ... ~ev[].

Do not nest doc-string (DOC-STRING^) tilde directives; that is, do not write

       The ~c[~il[append] function ...

but note that the “equivalent” expression

       The ~ilc[append] function ...

is fine. The following phrase is also acceptable:

~bf[]This is ~em[formatted] text. ~ef[]

because the nesting is only conceptual, not literal.

We recommend that for displayed text, ~bv[] and ~ev[] should usually each be on lines by themselves. That way, printed text may be less encumbered with excessive blank lines. Here is an example.

Here is some normal text. Now start a display: ~bv[] 2 + 2 = 4 ~ev[] And here is the end of that paragraph.

Here is the start of the next paragraph.

The analogous consideration applies to ~bf[] and ~ef[] as well as ~bq[] and ~eq[].

You may “quote” characters (CHARACTERS^) inside the arg part of ~key[arg], by preceding them with ~. This is, in fact, the only legal way to use a newline character or a right bracket (]) inside the argument to a doc-string (DOC-STRING^) tilde directive.

Write your documentation (DOCUMENTATION^) strings without hyphens. Otherwise, you may find your text printed on paper (via TeX, for example) like this —

Here is a hyphe- nated word.

even if what you had in mind was:

Here is a hyphenated word.

When you want to use a dash (as opposed to a hyphen), consider using ~-[], which is intended to be interpreted as a “dash.” For example:

This sentence ~-[] which is broken with dashes ~-[] is boring.

would be written to the terminal (using :doc (DOC^)) by replacing ~-[] with two hyphen characters (CHARACTERS^), but would presumably be printed on paper with a dash.

Be careful to balance the “begin” and “end” pairs, such as ~bv[] and ~ev[]. Also, do not use two “begin” directives (~bf[], ~bq[], or ~bv[]) without an intervening “end” directive. It is permissible (and perhaps this is not surprising) to use the doc-string (DOC-STRING^) part separator ~/ while between such a begin-end pair.

Because of a bug in texinfo (as of this writing), you may wish to avoid beginning a line with (any number of spaces followed by) the - (-^) character or ~-[].

The “paragraph” directive, ~par[], is rarely if ever used. There is a low-level capability, not presently documented, that interprets two successive newlines as though they were ~par[]. This is useful for the HTML driver. For further details, see the authors of ACL2.

Emacs code is available for manipulating documentation (DOCUMENTATION^) strings that contain doc-string (DOC-STRING^) tilde-directives (for example, for doing a reasonable job filling such documentation (DOCUMENTATION^) strings). See the authors if you are interested.

We tend to use ~em[arg] for “section headers,” such as “Style notes and further details” above. We tend to use ~st[arg] for emphasis of words inside text. This division seems to work well for our Texinfo driver. Note that ~st[arg] causes arg to be printed in upper-case at the terminal (using :doc (DOC^)), while ~em[arg] causes arg to be printed at the terminal as though arg were not marked for emphasis.

Our Texinfo and HTML drivers both take advantage of capabilities for indicating which characters (CHARACTERS^) need to be “escaped,” and how. Unless you intend to write your own driver, you probably do not need to know more about this issue; otherwise, contact the ACL2 authors. We should probably mention, however, that Texinfo makes the following requirement: when using ~l[arg], where arg contains one of the special characters (CHARACTERS^) @ (@^), {, or }, you must immediately follow this use with a period or comma. Also, the Emacs “info” documentation (DOCUMENTATION^) that we generate by using our Texinfo driver has the property that in node names, : has been replaced by | (because of quirks in info); so for example, the “proof-checker (PROOF-CHECKER^)” simplification command, s, is documented under acl2-pc||s rather than

under acl2-pc::s.

We have tried to keep this markup language fairly simple; in particular, there is no way to refer to a link by other than the actual name. So for example, when we want to make :doc (DOC^) an invisible link in “code” font, we write the following form, which indicates that : should be in that font and then doc (DOC^) should both be in that font and be an invisible link.

       ~c[:]~ilc[doc]

5.9 MORE

MORE your response to :doc (DOC^) or :more-doc (MORE-DOC^)’s “(cont'd)”

NOTE: The command :more only makes sense at the terminal.

     Example:
     ACL2 !>:more

will continue printing whatever documentation (DOCUMENTATION^) was started by :doc (DOC^) or :more-doc (MORE-DOC^).

When you type :doc name, for some documented name, the system responds by typing the oneliner and the notes sections of the documentation (DOCUMENTATION^) for name. It then types “(cont'd)” which stands for “continued”. If you then type

     ACL2 !>:more

the system will start to print the details section of name. The same thing could be achieved by typing :more-doc name, but that requires you to type name again.

Similarly, if you have typed :more-doc (MORE-DOC^) name, the system will print the first “block” of the details section and then print “(cont'd)”. Typing :more at that point will cause the next block of the details section to be printed. Eventually :more will conclude by printing “*-” which is the indicator that the text has been exhausted.

What is a “block” of text? :More looks for the end of a paragraph (two adjacent newlines) after printing n lines. If it doesn’t find one before it has printed k lines, it just stops there. N and k here are the values of the two state (STATE^) global variables 'more-doc-min-lines and 'more-doc-max-lines. You may use @ (@^) and assign (ASSIGN^) to inspect and set these variables, e.g., (@ more-doc-max-lines) will return the current maximum number of lines printed by :more and (assign more-doc-max-lines 19) will set it to 19. On terminals having only 24 lines, we find min and max settings of 12 and 19 the most pleasant.

If you want :more to print all of the details instead of feeding them to you one block at a time, type :more! (MORE!^) instead.

5.10 MORE!

MORE! another response to “(cont’d)”

NOTE: The command :more! only makes sense at the terminal.

     ACL2 !>:more!

will print all of the remaining documentation (DOCUMENTATION^) started by the last :doc (DOC^) or :more-doc (MORE-DOC^).

See Section 5.9 [MORE], page 154 for some background. Typing :more! will print all remaining blocks of documentation (DOCUMENTATION^).

:More! is like :more (MORE^) except that it prints all the text at once. For example, if you type :doc (DOC^) name you will see some text followed by “(cont'd)”. If you then type simply :more! you will see all of the details, while if you type :more (MORE^) you will be fed the next block of details.

5.11 MORE-DOC

MORE-DOC a continuation of the :doc (DOC^) documentation (DOCUMENTATION^)

NOTE: The :more-doc command only makes sense at the terminal.

     Examples:
     ACL2 !>:more-doc DEFTHM
     ACL2 !>:more-doc logical-name

Often it is assumed in the text provided by :more-doc name that you have read the text provided

by :doc name.

:More-doc just continues spewing out at you the documentation (DOCUMENTATION^) string provided with a definition. If the user has done his job, :doc (DOC^) will probably remind you of the basics and :more-doc, if read after :doc (DOC^), will address obscure details that are nevertheless worth noting.

When :more-doc types “(cont'd)” you can get the next block of the continuation by typing :more (MORE^) or all of the remaining blocks by typing :more! (MORE!^). See Section 5.9 [MORE], page 154.

5.12 NQTHM-TO-ACL2

NQTHM-TO-ACL2 ACL2 analogues of Nqthm functions and commands

Example Forms:
:nqthm-to-acl2 prove-lemma   ; Display ACL2 topic(s) and/or print
                             ; information corresponding to Nqthm
                             ; PROVE-LEMMA command.
(nqthm-to-acl2 'prove-lemma) ; Same as above.
General Form:
(nqthm-to-acl2 name)

where name is a notion documented for Nqthm: either a function in the Nqthm logic, or a command. If there is corresponding information available for ACL2, it will be printed in response to this command. This information is not intended to be completely precise, but rather, is intended to help those familiar with Nqthm to make the transition to ACL2.

We close with two tables that contain all the information used by this nqthm-to-acl2 command. The first shows the correspondence between functions in the Nqthm logic and corresponding ACL2 functions (when possible); the second is similar, but for commands rather than functions.

Nqthm functions  -->     ACL2
----------------------------------------
ADD1          -->  1+
ADD-TO-SET    -->  ADD-TO-SET-EQUAL and ADD-TO-SET-EQ
AND           -->  AND
APPEND        -->  APPEND and BINARY-APPEND
APPLY-SUBR    -->  No correspondent, but see the documentation for
                   DEFEVALUATOR and META.
APPLY$        -->  No correspondent, but see the documentation for
                   DEFEVALUATOR and META.
ASSOC         -->  ASSOC-EQUAL, ASSOC and ASSOC-EQ
BODY          -->  No correspondent, but see the documentation for
                   DEFEVALUATOR and META.
CAR           -->  CAR
CDR           -->  CDR
CONS          -->  CONS
COUNT         -->  ACL2-COUNT
DIFFERENCE    -->  -
EQUAL         -->  EQUAL, EQ, EQL and =
EVAL$         -->  No correspondent, but see the documentation for
                   DEFEVALUATOR and META.
FALSE         -->  Nqthm's F corresponds to the ACL2 symbol NIL.
FALSEP        -->  NOT and NULL
FORMALS       -->  No correspondent, but see the documentation for
                   DEFEVALUATOR and META.

GEQ           -->  >=
GREATERP      -->  >
IDENTITY      -->  IDENTITY
IF            -->  IF
IFF           -->  IFF
IMPLIES       -->  IMPLIES
LEQ           -->  <=
LESSP         -->  <
LISTP         -->  CONSP
LITATOM       -->  SYMBOLP
MAX           -->  MAX
MEMBER        -->  MEMBER-EQUAL, MEMBER and MEMBER-EQ
MINUS         -->  - and UNARY--
NEGATIVEP     -->  MINUSP
NEGATIVE-GUTS -->  ABS
NLISTP        -->  ATOM
NOT           -->  NOT
NUMBERP       -->  ACL2-NUMBERP, INTEGERP and RATIONALP
OR            -->  OR
ORDINALP      -->  E0-ORDINALP
ORD-LESSP     -->  E0-ORD-<
PACK          -->  See intern and coerce.
PAIRLIST      -->  PAIRLIS$
PLUS          -->  + and BINARY-+
QUOTIENT      -->  /
REMAINDER     -->  REM and MOD
STRIP-CARS    -->  STRIP-CARS
SUB1          -->  1-
TIMES         -->  * and BINARY-*
TRUE          -->  The symbol T.
UNION         -->  UNION-EQUAL and UNION-EQ
UNPACK        -->  See symbol-name and coerce.
V&C$          -->  No correspondent, but see the documentation for
                   DEFEVALUATOR and META.
V&C-APPLY$    -->  No correspondent, but see the documentation for
                   DEFEVALUATOR and META.
ZERO          -->  The number 0.
ZEROP         -->  ZEROP
========================================
Nqthm commands   -->     ACL2
----------------------------------------
ACCUMULATED-PERSISTENCE
              -->  ACCUMULATED-PERSISTENCE
ADD-AXIOM     -->  DEFAXIOM
ADD-SHELL     -->  There is no shell principle in ACL2.
AXIOM         -->  DEFAXIOM

BACKQUOTE-SETTING
              -->  Backquote is supported in ACL2, but not
                   currently documented.
BOOT-STRAP    -->  GROUND-ZERO
BREAK-LEMMA   -->  MONITOR
BREAK-REWRITE -->  BREAK-REWRITE
CH            -->  PBT
                   See also :DOC history.
CHRONOLOGY    -->  PBT
                   See also :DOC history.
COMMENT       -->  DEFLABEL
COMPILE-UNCOMPILED-DEFNS
              -->  COMP
CONSTRAIN     -->  See :DOC encapsulate and :DOC local.
DATA-BASE     -->  Perhaps the closest ACL2 analogue of DATA-BASE
                   is PROPS.  But see :DOC history for a collection
                   of commands for querying the ACL2 database
                   (``world'').  Note that the notions of
                   supporters and dependents are not supported in
                   ACL2.
DCL           -->  DEFSTUB
DEFN          -->  DEFUN and DEFMACRO
DEFTHEORY     -->  DEFTHEORY
DISABLE       -->  DISABLE
DISABLE-THEORY
              -->  See :DOC theories.  The Nqthm command
                   (DISABLE-THEORY FOO) corresponds roughly to the
                   ACL2 command
                   (in-theory (set-difference-theories
                                (current-theory :here)
                                (theory 'foo))).
DO-EVENTS     -->  LD
DO-FILE       -->  LD
ELIM          -->  ELIM
ENABLE        -->  ENABLE
ENABLE-THEORY -->  See :DOC theories.  The Nqthm command
                   (ENABLE-THEORY FOO) corresponds roughly to the
                   ACL2 command
                   (in-theory (union-theories
                                (theory 'foo)
                                (current-theory :here))).
EVENTS-SINCE  -->  PBT
FUNCTIONALLY-INSTANTIATE
              -->  ACL2 provides a form of the :USE hint that
                   corresponds roughly to the
                   FUNCTIONALLY-INSTANTIATE event of Nqthm. See
                   :DOC lemma-instance.
GENERALIZE    -->  GENERALIZE

HINTS         -->  HINTS
LEMMA         -->  DEFTHM
MAINTAIN-REWRITE-PATH
              -->  BRR
MAKE-LIB      -->  There is no direct analogue of Nqthm's notion of
                   ``library.''  See :DOC books for a description
                   of ACL2's mechanism for creating and saving
                   collections of events.
META          -->  META
NAMES         -->  NAME
NOTE-LIB      -->  INCLUDE-BOOK
PPE           -->  PE
PROVE         -->  THM
PROVEALL      -->  See :DOC ld and :DOC certify-book.  The latter
                   corresponds to Nqthm's PROVE-FILE,which may be
                   what you're interested in,really.
PROVE-FILE    -->  CERTIFY-BOOK
PROVE-FILE-OUT
              -->  CERTIFY-BOOK
PROVE-LEMMA   -->  DEFTHM
                   See also :DOC hints.
R-LOOP        -->  The top-level ACL2 loop is an evaluation loop as
                   well, so no analogue of R-LOOP is necessary.
REWRITE       -->  REWRITE
RULE-CLASSES  -->  RULE-CLASSES
SET-STATUS    -->  IN-THEORY
SKIM-FILE     -->  LD-SKIP-PROOFSP
TOGGLE        -->  IN-THEORY
TOGGLE-DEFINED-FUNCTIONS
              -->  EXECUTABLE-COUNTERPART-THEORY
TRANSLATE     -->  TRANS and TRANS1
UBT           -->  UBT and U
UNBREAK-LEMMA -->  UNMONITOR
UNDO-BACK-THROUGH
              -->  UBT
UNDO-NAME     -->  See :DOC ubt.  There is no way to undo names in
                   ACL2 without undoing back through such names.
                   However, see :DOC ld-skip-proofsp for
                   information about how to quickly recover the
                   state.

6 EVENTS

EVENTS functions that extend the logic

* ADD-MACRO-ALIAS:: associate a function name with a macro name

* DEFAXIOM:: add an axiom

* DEFCHOOSE:: define a Skolem (witnessing) function

* DEFCONG:: prove that one equivalence (EQUIVALENCE^) relation preserves another in a given argument position of a given function

* DEFCONST:: define a constant

* DEFDOC:: add a documentation (DOCUMENTATION^) topic

* DEFEQUIV:: prove that a function is an equivalence (EQUIVALENCE^) relation

* DEFEVALUATOR:: introduce an evaluator function

* DEFLABEL:: build a landmark and/or add a documentation (DOCUMENTATION^) topic

* DEFMACRO:: define a macro

* DEFPKG:: define a new symbol package

* DEFREFINEMENT:: prove that equiv1 refines equiv2

* DEFSTUB:: stub-out a function symbol

* DEFTHEORY:: define a theory (to enable (ENABLE^) or disable (DISABLE^) a set of rules)

* DEFTHM:: prove and name a theorem

* DEFUN:: define a function symbol

* DEFUN-SK:: define a function whose body has an outermost quantifier

* ENCAPSULATE:: constrain some functions and/or hide some events (EVENTS^)

* IN-THEORY:: designate “current” theory (enabling its rules)

* INCLUDE-BOOK:: load the events (EVENTS^) in a file

* LOCAL:: hiding an event in an encapsulation or book

* LOGIC:: to set the default defun-mode (DEFUN-MODE^) to :logic

* MACRO-ALIASES-TABLE:: a table (TABLE^) used to associate function names with macro names * MUTUAL-RECURSION:: define some mutually recursive functions

* PROGRAM:: to set the default defun-mode (DEFUN-MODE^) to :program

* REMOVE-MACRO-ALIAS:: remove the association of a function name with a macro name

* SET-COMPILE-FNS:: have each function compiled as you go along.

* SET-IGNORE-OK:: allow unused formals and locals without an ignore declaration

* SET-INHIBIT-WARNINGS:: control warnings

* SET-INVISIBLE-FNS-ALIST:: set the invisible functions alist

* SET-IRRELEVANT-FORMALS-OK:: allow irrelevant formals in definitions

* SET-MEASURE-FUNCTION:: set the default measure function symbol

* SET-STATE-OK:: allow the use of STATE as a formal parameter

* SET-VERIFY-GUARDS-EAGERNESS:: the eagerness with which guard (GUARD^) verification is tried.

* SET-WELL-FOUNDED-RELATION:: set the default well-founded relation

* TABLE:: user-managed tables

* TERM-TABLE:: a table used to validate meta rules

* THEORY-INVARIANT:: user-specified invariants on theories (THEORIES^)

* VERIFY-GUARDS:: verify the guard (GUARD^)s of a function

* VERIFY-TERMINATION:: convert a function from :program mode to :logic mode Any extension of the syntax of ACL2 (i.e., the definition of a new constant or macro), the axioms (i.e., the definition of a function), or the rule data base (i.e., the proof of a theorem), constitutes a logical “event.” Events change the ACL2 logical world (see Section 8.100 [WORLD], page 399). Indeed, the only way to change the ACL2 world (WORLD^) is via the successful evaluation of an event function. Every time the world (WORLD^) is changed by an event, a landmark is left on the world (WORLD^) and it is thus possible to identify the world (WORLD^) “as of” the evaluation of a given event. An event may introduce new logical names. Some events introduce no new names (e.g., verify-guards (VERIFY-GUARDS^)), some introduce exactly one (e.g., defmacro (DEFMACRO^) and defthm (DEFTHM^)), and some may introduce many (e.g., encapsulate (ENCAPSULATE^) ).

6.1 ADD-MACRO-ALIAS

ADD-MACRO-ALIAS associate a function name with a macro name

     Example:
     (add-macro-alias append binary-append)

This example associates the function symbol binary-append (BINARY-APPEND^) with the macro name append (APPEND^). As a result, the name append (APPEND^) may be used as a runic designator (see Chapter 16 [THEORIES], page 775) by the various theory functions. See Section 6.23 [MACRO-ALIASES-TABLE], page 192 for more details.

     General Form:
     (add-macro-alias macro-name function-name)

This is a convenient way to add an entry to macro-aliases-table (MACRO-ALIASES-TABLE^). See Section 6.23 [MACRO-ALIASES-TABLE], page 192 and also see Section 6.26 [REMOVE-MACRO-ALIAS], page 196.

6.2 DEFAXIOM

DEFAXIOM add an axiom

WARNING: We strongly recommend that you not add axioms. If at all possible you should use defun (DEFUN^) or mutual-recursion (MUTUAL-RECURSION^) to define new concepts recursively or use encapsulate (ENCAPSULATE^) to constrain them constructively. Adding new axioms frequently renders the logic inconsistent.

     Example:
     (defaxiom sbar (equal t nil)
               :rule-classes nil
               :doc ":Doc-Section ...")
     General Form:
     (defaxiom name term
              :rule-classes rule-classes
              :doc          doc-string)

where name is a new symbolic name (see Section 8.67 [NAME], page 352), term is a term intended to be a new axiom, and rule-classes (RULE-CLASSES^) and doc-string (DOC-STRING^) are as described in the corresponding documentation (DOCUMENTATION^) topics . The two keyword arguments are optional. If :rule-classes (RULE-CLASSES^) is not supplied, the list (:rewrite) is used; if you wish the axiom to generate no rules, specify :rule-classes (RULE-CLASSES^)

nil.

6.3 DEFCHOOSE

DEFCHOOSE define a Skolem (witnessing) function

     Examples:
     (defchoose choose-x-for-p-and-q (x) (y z)
       (and (p x y z)
            (q x y z)))
     (defchoose choose-x-for-p-and-q x (y z) ; equivalent to the above
       (and (p x y z)
            (q x y z)))
     (defchoose choose-x-and-y-for-p-and-q (x y) (z)
       (and (p x y z)
            (q x y z)))
     General Form:
     (defchoose fn
                (bound-var1 ... bound-varn)
                (free-var1 ... free-vark)
                doc-string ; optional
                body),

where fn is the symbol you wish to define and is a new symbolic name (see Section 8.67 [NAME], page 352), (bound-var1 ... bound-varn) is a list of distinct ‘bound’ variables (see below), (freevar1 ... free-vark) is the list of formal parameters of fn and is disjoint from the bound variables, and body is a term. The use of lambda-list keywords (such as &optional) is not allowed. The documentation (DOCUMENTATION^) string, doc-string (DOC-STRING^), is optional; for a description of its form, see Section 5.5 [DOC-STRING], page 143.

In the most common case, where there is only one bound variable, it is permissible to omit the enclosing parentheses on that variable. The effect is the same whether or not those parentheses are omitted. We describe this case first, where there is only one bound variable, and address the other case at the end.

The effect of the form

     (defchoose fn bound-var (free-var1 ... free-vark)
       body)

is to introduce a new function symbol, fn, with formal parameters (free-var1 ... free-vark), and the following axiom stating that fn picks a value of bound-var so that the body will be true, if such a value exists:

     (implies body
              (let ((bound-var (fn free-var1 ... free-vark)))
                body))

This axiom is “clearly” conservative under the conditions expressed above: the function fn merely picks out a “witnessing” value of bound-var if there is one. The system in fact treats fn very much as though it were declared in the signature (SIGNATURE^) of an encapsulate (ENCAP-SULATE^) event, with the axiom above as the only axiom exported.

If there is more than one bound variable, as in

     (defchoose fn
                (bound-var1 ... bound-varn)
                (free-var1 ... free-vark)
                body)

then fn returns n multiple values, and the defining axiom is expressed using mv-let (MV-LET^) (see Section 10.171 [MV-LET], page 510) as follows:

     (implies body
              (mv-let (bound-var1 ... bound-varn)
                      (fn free-var1 ... free-vark)
                      body))

It is illegal for the body to return multiple values. Also, note that the function introduced by a defchoose form will return ‘state’ if and only if the body returns ‘state’; see Section 8.83 [STATE], page 368.

Defchoose is only executed in defun-mode (DEFUN-MODE^) :logic (LOGIC^); see Section 8.20 [DEFUN-MODE], page 275.

Also see Section 6.17 [DEFUN-SK], page 182.

Comment for logicians: As we point out in the documentation for defun-sk (DEFUN-SK^), defchoose is “appropriate,” by which we mean that it is conservative, even in the presence of epsilon-0 induction. See Section 8.7 [BIBLIOGRAPHY], page 257 for a reference to the “story” that includes this argument.

6.4 DEFCONG

DEFCONG prove that one equivalence (EQUIVALENCE^) relation preserves another in a given argument position of a given function

     Example:
     (defcong set-equal iff (memb x y) 2)
     is an abbreviation for
     (defthm set-equal-implies-iff-memb-2
       (implies (set-equal y y-equiv)
                (iff (memb x y) (memb x y-equiv)))
       :rule-classes (:congruence))

See Section 15.3 [CONGRUENCE], page 733 and also see Section 15.6 [EQUIVALENCE], page 738.

     General Form:
     (defcong equiv1 equiv2 term k
       :rule-classes rule-classes
       :instructions instructions
       :hints hints
       :otf-flg otf-flg

       :event-name event-name
       :doc doc)

where equiv1 and equiv2 are known equivalence (EQUIVALENCE^) relations, term is a call of a function fn on the correct number of distinct variable arguments (fn x1 ... xn), k is a positive integer less than or equal to the arity of fn, and other arguments are as specified in the documentation for defthm (DEFTHM^). The defcong macro expands into a call of defthm (DEFTHM^). The

name of the defthm (DEFTHM^) event is equiv1-implies-equiv2-fn-k unless an :event-name

keyword argument is supplied for the name. The term of the theorem is

     (implies (equiv1 xk yk)
              (equiv2 (fn x1... xk ...xn)
                      (fn x1... yk ...xn))).

The rule-class :congruence (CONGRUENCE^) is added to the rule-classes (RULE-CLASSES^) specified, if it is not already there. All other arguments to the generated defthm (DEFTHM^) form are as specified by the keyword arguments above.

6.5 DEFCONST

DEFCONST define a constant

     Examples:
     (defconst *digits* '(0 1 2 3 4 5 6 7 8 9))
     (defconst *n-digits* (the unsigned-byte (length *digits*)))
     General Form:
     (defconst name term doc-string)

where name is a symbol beginning and ending with the character *, term is a variable-free term that is evaluated to determine the value of the constant, and doc-string (DOC-STRING^) is an optional documentation (DOCUMENTATION^) string (see Section 5.5 [DOC-STRING], page 143).

When a constant symbol is used as a term (TERM^), ACL2 replaces it by its value; see Section 8.87 [TERM], page 376.

It may be of interest to note that defconst is implemented at the lisp level using defparameter, as opposed to defconstant. (Implementation note: this is important for proper support of undoing and redefinition.)

6.6 DEFDOC

DEFDOC add a documentation (DOCUMENTATION^) topic

     Examples:
     (defdoc interp-section
        ":Doc-Section ...")
     General Form:
     (defdoc name doc-string)

where name is a symbol or string to be documented and doc-string (DOC-STRING^) is a documentation (DOCUMENTATION^) string (see Section 5.5 [DOC-STRING], page 143). This event adds the documentation (DOCUMENTATION^) string for symbol name to the :doc (DOC^) data base. It may also be used to change the documentation (DOCUMENTATION^) for name if name already has documentation (DOCUMENTATION^). The difference between this event and deflabel (DEFLABEL^) is that, unlike deflabel (DEFLABEL^) (but like table (TABLE^)), it does not mark the current history (HISTORY^) with the name. But like deflabel (DEFLABEL^), defdoc events (EVENTS^) are never considered redundant (see Section 8.78 [REDUNDANT-EVENTS], page 361).

See Section 6.9 [DEFLABEL], page 171 for a means of attaching a documentation (DOCUMEN-TATION^) string to a name that marks the current history (HISTORY^) with that name. We now elaborate further on how defdoc may be useful in place of deflabel (DEFLABEL^).

It is usually sufficient to use deflabel (DEFLABEL^) when you might be tempted to use defdoc. However, unlike deflabel (DEFLABEL^), defdoc does not mark the current history (HISTORY^) with name. Thus, defdoc is useful for introducing the documentation (DOCUMENTATION^) for a defun (DEFUN^) or deftheory (DEFTHEORY^) event, for example, several events (EVENTS^) before the function or theory is actually defined.

For example, suppose you want to define a theory (using deftheory (DEFTHEORY^)). You need to prove the lemmas in that theory before executing the deftheory (DEFTHEORY^) event. However, it is quite natural to define a :doc-section (see Section 5.5 [DOC-STRING], page 143) whose name is the name of the theory to be defined, and put the documentation (DOCUMENTATION^) for that theory’s lemmas into that :doc-section. Defdoc is ideal for this purpose, since it can be used to introduce the :doc-section, followed by the lemmas referring to that :doc-section, and finally concluded with a deftheory (DEFTHEORY^) event of the same name. If deflabel (DEFLABEL^) were used instead of defdoc, for example, then the deftheory (DEFTHEORY^) event would be disallowed because the name is already in use by the deflabel (DEFLABEL^) event.

We also imagine that some users will want to use defdoc to insert the documentation (DOCUMEN-TATION^) for a function under development. This defdoc event would be followed by definitions of all the subroutines of that function, followed in turn by the function definition itself.

Any time defdoc is used to attach documentation (DOCUMENTATION^) to an alreadydocumented name, the name must not be attached to a new :doc-section. We make this requirement as a way of avoiding loops in the documentation (DOCUMENTATION^) tree. When documentation (DOCUMENTATION^) is redefined, a warning will be printed to the terminal.

6.7 DEFEQUIV

DEFEQUIV prove that a function is an equivalence (EQUIVALENCE^) relation

     Example:
     (defequiv set-equal)
     is an abbreviation for
     (defthm set-equal-is-an-equivalence
       (and (booleanp (set-equal x y))
            (set-equal x x)
            (implies (set-equal x y) (set-equal y x))
            (implies (and (set-equal x y)
                          (set-equal y z))
                     (set-equal x z)))
       :rule-classes (:equivalence))

See Section 15.6 [EQUIVALENCE], page 738.

     General Form:
     (defequiv fn
       :rule-classes rule-classes
       :instructions instructions
       :hints hints
       :otf-flg otf-flg
       :event-name event-name
       :doc doc)

where fn is a function symbol of arity 2, event-name, if supplied, is a symbol, and all other arguments are as specified in the documentation for defthm (DEFTHM^). The defequiv macro expands into a call of defthm. The name of the defthm is fn-is-an-equivalence, unless eventname is supplied, in which case event-name is the name used. The term generated for the defthm event states that fn is Boolean, reflexive, symmetric, and transitive. The rule-class :equivalence is added to the rule-classes (RULE-CLASSES^) specified, if it is not already there. All other arguments to the generated defthm form are as specified by the other keyword arguments above.

6.8 DEFEVALUATOR

DEFEVALUATOR introduce an evaluator function

     Example:
     (defevaluator evl evl-list
       ((length x) (member x y)))

See Section 15.12 [META], page 758.

     General Form:
     (defevaluator ev ev-list
        ((g1 x1 ... xn_1)
         ...
         (gk x1 ... xn_k))

where ev and ev-list are new function symbols and g1, ..., gk are old function symbols with the indicated number of formals, i.e., each gi has n_i formals.

This function provides a convenient way to constrain ev and ev-list to be mutually-recursive evaluator functions for the symbols g1, ..., gk. Roughly speaking, an evaluator function for a fixed, finite set of function symbols is a restriction of the universal evaluator to terms composed of variables, constants, lambda expressions, and applications of the given functions. However, evaluator functions are constrained rather than defined, so that the proof that a given metafunction is correct vis-a-vis a particular evaluator function can be lifted (by functional instantiation) to a proof that it is correct for any larger evaluator function. See Section 15.12 [META], page 758 for a discussion of metafunctions.

Defevaluator executes an encapsulate (ENCAPSULATE^) after generating the appropriate defun (DEFUN^) and defthm (DEFTHM^) events. Perhaps the easiest way to understand what defevaluator does is to execute the keyword command

:trans1 (defevaluator evl evl-list ((length x) (member x y)))

and inspect the output.

Formally, ev is said to be an “evaluator function for g1, ..., gk, with mutually-recursive counterpart ev-list” iff ev and ev-list are constrained functions satisfying just the constraint (CON-STRAINT^)s discussed below.

Ev and ev-list must satisfy constraint (CONSTRAINT^)s (1)-(4) and (k):

(1) How to ev a variable symbol:
(implies (symbolp x)
         (equal (ev x a) (cdr (assoc-eq x a))))
(2) How to ev a constant:
(implies (and (consp x)
              (equal (car x) 'quote))
         (equal (ev x a) (cadr x)))
(3) How to ev a lambda application:
(implies (and (consp x)
              (consp (car x)))
         (equal (ev x a)
                (ev (caddar x)
                    (pairlis$ (cadar x)
                              (ev-list (cdr x) a)))))
(4) How to ev an argument list:
(implies (consp x-lst)
         (equal (ev-list x-lst a)
                (cons (ev (car x-lst) a)
                      (ev-list (cdr x-lst) a))))
(implies (not (consp x-lst))
         (equal (ev-list x-lst a)
                nil))
(k) For each i from 1 to k, how to ev an application of gi,
where gi is a function symbol of n arguments:
(implies (and (consp x)
              (equal (car x) 'gi))
         (equal (ev x a)
                (gi (ev x1 a)
                    ...
                    (ev xn a)))),
where xi is the (cad...dr x) expression equivalent to (nth i x).

Defevaluator defines suitable witnesses for ev and ev-list, proves the theorems about them, and constrains ev and ev-list appropriately. We expect defevaluator to work without assistance from you, though the proofs do take some time and generate a lot of output. The proofs are done in the context of a fixed theory, namely the result of applying union-theories (UNION-THEORIES^) to two lists: the function symbols supplied, and the value of the constant *defevaluator-form-

base-theory*.

6.9 DEFLABEL

DEFLABEL build a landmark and/or add a documentation (DOCUMENTATION^) topic

     Examples:
     (deflabel interp-section
        :doc
        ":Doc-Section ...")
     General Form:
     (deflabel name :doc doc-string)

where name is a new symbolic name (see Section 8.67 [NAME], page 352) and doc-string (DOC-STRING^) is an optional documentation (DOCUMENTATION^) string (see Section 5.5 [DOC-STRING], page 143). This event adds the documentation (DOCUMENTATION^) string for symbol name to the :doc (DOC^) data base. By virtue of the fact that deflabel is an event, it also marks the current history (HISTORY^) with the name. Thus, even undocumented labels are convenient as landmarks in a proof development. For example, you may wish to undo back through some label or compute a theory expression (see Chapter 16 [THEORIES], page 775) in terms of some labels. Deflabel events (EVENTS^) are never considered redundant. See Section 8.78 [REDUNDANT-EVENTS], page 361.

See Section 6.6 [DEFDOC], page 167 for a means of attaching a documentation (DOCUMENTA-TION^) string to a name without marking the current history (HISTORY^) with that name.

6.10 DEFMACRO

DEFMACRO define a macro

     Example Defmacros:
     (defmacro xor (x y)

       (list 'if x (list 'not y) y))
     (defmacro git (sym key)
       (list 'getprop sym key nil
             '(quote current-acl2-world)
             '(w state)))
     (defmacro one-of (x &rest rst)
       (declare (xargs :guard (symbol-listp rst)))
       (cond ((null rst) nil)
             (t (list 'or
                      (list 'eq x (list 'quote (car rst)))
                      (list* 'one-of x (cdr rst))))))
     Example Expansions:
     term                    macroexpansion
     (xor a b)              (if a (not b) b)
     (xor a (foo b))        (if a (not (foo b)) (foo b))
     (git 'car 'lemmas)     (getprop 'car 'lemmas nil
                                     'current-acl2-world
                                     (w state))
     (one-of x a b c)       (or (eq x 'a)
                                (or (eq x 'b)
                                    (or (eq x 'c) nil)))
     (one-of x 1 2 3)       ill-formed (guard violation)
     General Form:
     (defmacro name macro-args doc-string dcl ... dcl body)

where name is a new symbolic name (see Section 8.67 [NAME], page 352), macro-args (MACRO-ARGS^) specifies the formals of the macro (see Section 8.66 [MACRO-ARGS], page 351 for a description), and body is a term. Doc-string (DOC-STRING^) is an optional documentation (DOCUMENTATION^) string; see Section 5.5 [DOC-STRING], page 143. Each dcl is an optional declaration (see Section 10.94 [DECLARE], page 469) except that the only xargs (XARGS^) keyword permitted by defmacro is :guard (GUARD^).

Macroexpansion occurs when a form is read in, i.e., before the evaluation or proof of that form is undertaken. To experiment with macroexpansion, see Section 9.16 [TRANS], page 427. When a form whose car (CAR^) is name arises as the form is read in, the arguments are bound as described in CLTL pp. 60 and 145, the guard (GUARD^) is checked, and then the body is evaluated. The result is used in place of the original form.

In ACL2, macros do not have access to state (STATE^). That is, state (STATE^) is not allowed among the formal parameters. This is in part a reflection of CLTL, pp. 143, “More generally, an implementation of Common Lisp has great latitude in deciding exactly when to expand macro calls with a program. ... Macros should be written in such a way as to depend as little as possible on the execution environment to produce a correct expansion.” In ACL2, the product of macroexpansion is independent of the current environment and is determined entirely by the macro body and the functions and constants it references. It is possible, however, to define macros that produce expansions that refer to state (STATE^) or other variables not among the macro’s arguments. See the git example above.

6.11 DEFPKG

DEFPKG define a new symbol package

     Example:
     (defpkg "MY-PKG"
             (union-eq *acl2-exports*
                       *common-lisp-symbols-from-main-lisp-package*))
     General Form:
     (defpkg "name" term doc-string)

where "name" is a (case-sensitive) string that names the package to be created, term is a variablefree expression that evaluates to a list of symbols (no two of which have the same symbol-name (SYMBOL-NAME^)) to be imported into the newly created package, and doc-string (DOC-STRING^) is an optional documentation (DOCUMENTATION^) string; see Section 5.5 [DOC-STRING], page 143. The name of the new package must be “new”: the host lisp must not contain any package of that name. There are two exceptions to this newness rule, discussed at the end of this documentation.

defpkg forms can be entered at the top-level of the ACL2 command (COMMAND^) loop. They should occur in a file only if the file is not to be compiled and contains nothing besides defpkg and in-package (IN-PACKAGE^) forms.

After a successful defpkg it is possible to “intern” a string into the package using intern-in-package-of-symbol (INTERN-IN-PACKAGE-OF-SYMBOL^). The result is a symbol that is in the indicated package, provided the imports allow it. For example, suppose 'my-pkg::abc is a symbol whose symbol-package-name (SYMBOL-PACKAGE-NAME^) is "MY-PKG". Suppose further that the imports specified in the defpkg for "MY-PKG" do not include a symbol whose symbol-name (SYMBOL-NAME^) is "XYZ". Then

     (intern-in-package-of-symbol "XYZ" 'my-pkg::abc)

returns a symbol whose symbol-name (SYMBOL-NAME^) is "XYZ" and whose symbol-package-name (SYMBOL-PACKAGE-NAME^) is "MY-PKG". On the other hand, if the imports to the defpkg does include a symbol with the name "XYZ", say in the package "LISP", then

     (intern-in-package-of-symbol "XYZ" 'my-pkg::abc)

returns that symbol (which is uniquely determined by the restriction on the imports list above). See Section 10.132 [INTERN-IN-PACKAGE-OF-SYMBOL], page 491.

defpkg is the only means by which an ACL2 user can create a new package or specify what it imports. That is, ACL2 does not support the Common Lisp functions make-package or import. Currently, ACL2 does not support exporting at all.

The Common Lisp function intern (INTERN^) is weakly supported by ACL2. See Section 10.131 [INTERN], page 491.

We now explain the two exceptions to the newness rule for package names. The careful experimenter will note that if a package is created with a defpkg that is subsequently undone, the host lisp system will contain the created package even after the undo. Because ACL2 hangs onto world (WORLD^)s after they have been undone, e.g., to implement :oops (OOPS^) but, more importantly, to implement error recovery, we cannot actually destroy a package upon undoing it. Thus, the first exception to the newness rule is that name is allowed to be the name of an existing package if that package was created by an undone defpkg and the newly proposed imports list is identical to the old one. See Section 8.70 [PACKAGE-REINCARNATION-IMPORT-RESTRICTIONS], page 354. This exception does not violate the spirit of the newness rule, since one is disinclined to believe in the existence of undone packages. The second exception is that name is allowed to be the name of an existing package if the package was created by a defpkg with identical imports. That is, it is permissible to execute “redundant” defpkg command (COMMAND^)s. The redundancy test is based on the values of the two import forms, not on the forms themselves.

6.12 DEFREFINEMENT

DEFREFINEMENT prove that equiv1 refines equiv2

     Example:
     (defrefinement equiv1 equiv2)
     is an abbreviation for
     (defthm equiv1-refines-equiv2
       (implies (equiv1 x y) (equiv2 x y))
       :rule-classes (:refinement))

See Section 15.13 [REFINEMENT], page 763.

     General Form:
     (defrefinement equiv1 equiv2
       :rule-classes rule-classes
       :instructions instructions
       :hints hints
       :otf-flg otf-flg
       :event-name event-name
       :doc doc)

where equiv1 and equiv2 are known equivalence (EQUIVALENCE^) relations, event-name, if supplied, is a symbol and all other arguments are as specified in the documentation for defthm (DEFTHM^). The defrefinement macro expands into a call of defthm. The name supplied is equiv1-refines-equiv2, unless event-name is supplied, in which case it is used as the name. The term supplied states that equiv1 refines equiv2. The rule-class :refinement is added to the rule-classes specified, if it is not already there. All other arguments to the generated defthm form are as specified by the other keyword arguments above.

6.13 DEFSTUB

DEFSTUB stub-out a function symbol

     Examples:
     ACL2 !>(defstub subr1 (x y state) (mv t state))
     ACL2 !>(defstub subr2 (x y) t)
     General Forms:
     (defstub name formals output)
     (defstub name formals output :doc doc-string)

where name is the name of the function to be stubbed out, formals is its list of formal parameters, and output is either a symbol (indicating that the function returns one result) or a term of the form (mv s1 ... sn), where each si is a symbol (indicating that the function returns n results).

Whether and where the symbol state (STATE^) occurs in formals and output indicates how the function handles state (STATE^). It should be the case that (name formals output) is in fact a signature (see Section 8.80 [SIGNATURE], page 364).

Defstub actually generates an encapsulate (ENCAPSULATE^) event (see Section 6.18 [ENCAP-SULATE], page 185). Thus, no axioms are available about name but it may be used wherever a function of its arity, multiplicity, and state (STATE^) characteristics is permitted.

6.14 DEFTHEORY

DEFTHEORY define a theory (to enable (ENABLE^) or disable (DISABLE^) a set of rules)

     Example:
     (deftheory interp-theory
                (set-difference-theories
                  (universal-theory :here)
                  (universal-theory 'interp-section)))
     General Form:
     (deftheory name term :doc doc-string)

where name is a new symbolic name (see Section 8.67 [NAME], page 352), term is a term that when evaluated will produce a theory (see Chapter 16 [THEORIES], page 775), and doc-string (DOC-STRING^) is an optional documentation (DOCUMENTATION^) string (see Section 5.5 [DOC-STRING], page 143). Except for the variable world (WORLD^), term must contain no free variables. term is evaluated with world (WORLD^) bound to the current world (see Section 8.100 [WORLD], page 399) and the resulting theory is then converted to a runic theory (see Chapter 16 [THEORIES], page 775) and associated with name. Henceforth, this runic theory is returned as the value of the theory expression (theory name).

6.15 DEFTHM

DEFTHM prove and name a theorem

     Examples:
     (defthm assoc-of-app
             (equal (app (app a b) c)
                    (app a (app b c))))

The following nonsensical example illustrates all the optional arguments but is illegal because not all combinations are permitted. See Section 8.43 [HINTS], page 319 for a complete list of hints (HINTS^).

     (defthm main
             (implies (hyps x y z) (concl x y z))
            :rule-classes (:REWRITE :GENERALIZE)
            :instructions (induct prove promote (dive 1) x
                                  (dive 2) = top (drop 2) prove)
            :hints (("Goal"
                     :do-not '(generalize fertilize)
                     :in-theory (set-difference-theories
                                  (current-theory :here)
                                  '(assoc))
                     :induct (and (nth n a) (nth n b))
                     :use ((:instance assoc-of-append
                                      (x a) (y b) (z c))
                           (:functional-instance
                             (:instance p-f (x a) (y b))
                             (p consp)
                             (f assoc)))))
            :otf-flg t
            :doc "#0[one-liner/example/details]")
     General Form:
     (defthm name term
             :rule-classes rule-classes
             :instructions instructions
             :hints        hints
             :otf-flg      otf-flg
             :doc          doc-string)

where name is a new symbolic name (see Section 8.67 [NAME], page 352), term is a term alleged to be a theorem, and rule-classes (RULE-CLASSES^), instructions (INSTRUCTIONS^), hints (HINTS^), otf-flg (OTF-FLG^) and doc-string (DOC-STRING^) are as described in their respective documentation (DOCUMENTATION^). The five keyword arguments above are all optional, however you may not supply both :instructions (INSTRUCTIONS^) and :hints (HINTS^), since one drives the proof checker and the other drives the theorem prover. If :ruleclasses (RULE-CLASSES^) is not specified, the list (:rewrite) is used; if you wish the theorem to generate no rules, specify :rule-classes (RULE-CLASSES^) nil.

When ACL2 processes a defthm event, it first tries to prove the term (TERM^) using the indicated hints (see Section 8.43 [HINTS], page 319) or instructions (INSTRUCTIONS^) (see Chapter 11 [PROOF-CHECKER], page 553). If it is successful, it stores the rules described by the rule-classes (see Chapter 15 [RULE-CLASSES], page 723), proving the necessary corollaries.

6.16 DEFUN

DEFUN define a function symbol

     Examples:
     (defun app (x y)
       (if (consp x)
           (cons (car x) (app (cdr x) y))
           y))
     (defun fact (n)
       (declare (xargs :guard (and (integerp n)
                                   (>= n 0))))
       (if (zp n)
           1
           (* n (fact (1- n)))))
     General Form:
     (defun fn (var1 ... varn) doc-string dcl ... dcl body),

where fn is the symbol you wish to define and is a new symbolic name (see Section 8.67 [NAME], page 352), (var1 ... varn) is its list of formal parameters (see Section 8.67 [NAME], page 352), and body is its body. The definitional is logically admissible provided certain restrictions are met. These are sketched below.

Note that ACL2 does not support the use of lambda-list keywords (such as &optional) in the formals list of functions. We do support some such keywords in macros and often you can achieve the desired syntax by defining a macro in addition to the general version of your function. See Section 6.10 [DEFMACRO], page 171. The documentation (DOCUMENTATION^) string, docstring (DOC-STRING^), is optional; for a description of its form, see Section 5.5 [DOC-STRING], page 143.

The declarations (see Section 10.94 [DECLARE], page 469), dcl, are also optional. If multiple dcl forms appear, they are effectively grouped together as one. Perhaps the most commonly used ACL2 specific declaration is of the form (declare (xargs :guard g :measure m)). This declaration in the defun of some function fn has the effect of making the “guard (GUARD^)” for fn be the term g and the “measure” be the term m. The notion of “measure” is crucial to ACL2’s definitional principle.

We now briefly discuss the ACL2 definitional principle, using the following definition form which is offered as a more or less generic example.

     (defun fn (x y)
       (declare (xargs :guard (g x y)
                       :measure (m x y)))
       (if (test x y)
           (stop x y)
           (step (fn (d x) y))))

Note that in our generic example, fn has just two arguments, x and y, the guard (GUARD^) and measure terms involve both of them, and the body is a simple case split on (test x y) leading to a “non-recursive” branch, (stop x y), and a “recursive” branch. In the recursive branch, fn is called after “decrementing” x to (d x) and some step function is applied to the result. Of course, this generic example is quite specific in form but is intended to illustrate the more general case.

Provided this definition is admissible under the logic, as outlined below, it adds the following axiom to the logic.

     Defining Axiom:
     (fn x y)
       =
     (if (test x y)
         (stop x y)
       (step (fn (d x) y)))

Note that the guard (GUARD^) of fn has no bearing on this logical axiom.

This defining axiom is actually implemented in the ACL2 system by a :definition (DEFINI-TION^) rule, namely

     (equal (fn x y)
            (if (test a b)
                (stop a b)
              (step (fn (d a) b)))).

See Section 15.4 [DEFINITION], page 735 for a discussion of how definition rules are applied. Roughly speaking, the rule causes certain instances of (fn x y) to be replaced by the corresponding instances of the body above. This is called “opening up” (fn x y). The instances of (fn x y) opened are chosen primarily by heuristics which determine that the recursive calls of fn in the opened body (after simplification) are more desirable than the unopened call of fn.

This discussion has assumed that the definition of fn was admissible. Exactly what does that mean? First, fn must be a previously unaxiomatized function symbol (however, see Section 8.58 [LD-REDEFINITION-ACTION], page 336). Second, the formal parameters must be distinct variable names. Third, the guard (GUARD^), measure, and body should all be terms and should mention no free variables except the formal parameters. Thus, for example, body may not contain references to “global” or “special” variables; ACL2 constants or additional formals should be used instead.

The final conditions on admissibility concern the termination of the recursion. Roughly put, all applications of fn must terminate. In particular, there must exist a binary relation, rel, and some unary predicate mp such that rel is well-founded on objects satisfying mp, the measure term m must always produce something satisfying mp, and the measure term must decrease according to rel in each recursive call, under the hypothesis that all the tests governing the call are satisfied. By the meaning of well-foundedness, we know there are no infinitely descending chains of successively rel-smaller mp-objects. Thus, the recursion must terminate.

The only primitive well-founded relation in ACL2 is e0-ord-< (E0-ORD-<^) (see Section 8.25 [E0-ORD-<], page 282), which is known to be well-founded on the e0-ordinalp (E0-ORDINALP^)s (see Section 8.26 [E0-ORDINALP], page 283). For the proof of well-foundedness, see Section 8.73 [PROOF-OF-WELL-FOUNDEDNESS], page 355. However it is possible to add new well-founded relations. For details, see Section 15.17 [WELL-FOUNDED-RELATION], page 769. We discuss later how to specify which well-founded relation is selected by defun and in the present discussion we assume, without loss of generality, that it is e0-ord-< (E0-ORD-<^) on the e0-ordinalp (E0-ORDINALP^)s.

For example, for our generic definition of fn above, with measure term (m x y), two theorems must be proved. The first establishes that m produces an ordinal:

     (e0-ordinalp (m x y)).

The second shows that m decreases in the (only) recursive call of fn:

     (implies (not (test x y))
              (e0-ord-< (m (d x) y) (m x y))).

Observe that in the latter formula we must show that the “m-size” of (d x) and y is “smaller than” the m-size of x and y, provided the test, (test x y), in the body fails, thus leading to the recursive

call (fn (d x) y).

See Section 8.25 [E0-ORD-<], page 282 for a discussion of this notion of “smaller than.” It should be noted that the most commonly used ordinals are the natural numbers and that on natural numbers, e0-ord-< (E0-ORD-<^) is just the familiar “less than” relation (< (<^)). Thus, it is very common to use a measure m that returns a nonnegative integer, for then (e0-ordinalp (m x y)) becomes a simple conjecture about the type of m and the second formula above becomes a conjecture about the less-than relationship of nonnegative integer arithmetic.

The most commonly used measure function is acl2-count (ACL2-COUNT^), which computes a nonnegative integer size for all ACL2 objects. See Section 8.3 [ACL2-COUNT], page 239.

Probably the most common recursive scheme in Lisp programming (PROGRAMMING^) is when some formal is supposed to be a list and in the recursive call it is replaced by its cdr (CDR^). For example, (test x y) might be simply (atom x) and (d x) might be (cdr x). In that case, (acl2count x) is a suitable measure because the acl2-count (ACL2-COUNT^) of a cons (CONS^) is strictly larger than the acl2-count (ACL2-COUNT^)s of its car (CAR^) and cdr (CDR^). Thus, “recursion by car (CAR^)” and “recursion by cdr (CDR^)” are trivially admitted if acl2-count (ACL2-COUNT^) is used as the measure and the definition protects every recursive call by a test insuring that the decremented argument is a consp (CONSP^). Similarly, “recursion by 1- (1-^)” in which a positive integer formal is decremented by one in recursion, is also trivially admissible. See Section 15.1 [BUILT-IN-CLAUSES], page 727 to extend the class of trivially admissible recursive schemes.

We now turn to the question of which well-founded relation defun uses. It should first be observed that defun must actually select both a relation (e.g., e0-ord-< (E0-ORD-<^)) and a domain predicate (e.g., e0-ordinalp (E0-ORDINALP^)) on which that relation is known to be well-founded. But, as noted elsewhere (see Section 15.17 [WELL-FOUNDED-RELATION], page 769), every known well-founded relation has a unique domain predicate associated with it and so it suffices to identify simply the relation here.

The xargs (XARGS^) field of a declare (DECLARE^) permits the explicit specification of any known well-founded relation with the keyword :well-founded-relation (WELL-FOUNDED-RELATION^). An example is given below. If the xargs (XARGS^) for a defun specifies a well-founded relation, that relation and its associated domain predicate are used in generating the termination conditions for the definition.

If no :well-founded-relation (WELL-FOUNDED-RELATION^) is specified, defun uses the

:well-founded-relation (WELL-FOUNDED-RELATION^) specified in the acl2-defaults-

table (ACL2-DEFAULTS-TABLE^). See Section 6.35 [SET-WELL-FOUNDED-RELATION], page 203 to see how to set the default well-founded relation (and, implicitly, its domain predicate). The initial default well-founded relation is e0-ord-< (E0-ORD-<^) (with domain predicate e0-ordinalp (E0-ORDINALP^)).

This completes the brief sketch of the ACL2 definitional principle.

The following example illustrates all of the available declarations, xargs (XARGS^), and hints (HINTS^), but is completely nonsensical.

(defun example (x y z a b c i j)
(declare (ignore a b c)
(type integer i j)
(xargs :guard (symbolp x)
:measure (- i j)
:well-founded-relation my-wfr
:hints (("Goal"
:do-not-induct t
:do-not '(generalize fertilize)
:expand ((assoc x a) (member y z))
:restrict ((<-trans ((x x) (y (foo x)))))
:hands-off (length binary-append)
:in-theory (set-difference-theories
             (current-theory :here)
             '(assoc))
:induct (and (nth n a) (nth n b))
:use ((:instance assoc-of-append
                 (x a) (y b) (z c))
      (:functional-instance
        (:instance p-f (x a) (y b))
        (p consp)
        (f assoc)))))
:guard-hints (("Subgoal *1/3'"
      :use ((:instance assoc-of-append
                       (x a) (y b) (z c)))))
:mode :logic
:otf-flg t))
(example-body x y z i j))

6.17 DEFUN-SK

DEFUN-SK define a function whose body has an outermost quantifier

Examples:
(defun-sk forall-x-p-and-q (y z)

       (forall x
               (and (p x y z)
                    (q x y z))))
     (defun-sk forall-x-p-and-q (y z) ; equivalent to the above
       (forall (x)
               (and (p x y z)
                    (q x y z))))
     (defun-sk some-x-y-p-and-q (z)
       (exists (x y)
               (and (p x y z)
                    (q x y z))))

* EXISTS:: existential quantifier

* FORALL:: universal quantifier

General Form:

     (defun-sk fn (var1 ... varn) body
       &key doc quant-ok skolem-name thm-name)

where fn is the symbol you wish to define and is a new symbolic name (see Section 8.67 [NAME], page 352), (var1 ... varn) is its list of formal parameters (see Section 8.67 [NAME], page 352), and body is its body, which must be quantified as described below. The &key argument doc (DOC^) is an optional documentation (DOCUMENTATION^) string to be associated with fn; for a description of its form, see Section 5.5 [DOC-STRING], page 143. The other arguments are explained below. For a more elaborate example than those above, see Section 1.5.5 [TUTORIAL4-DEFUN-SK-EXAMPLE], page 57.

The third argument, body, must be of the form

     (Q bound-vars term)

where: Q is the symbol forall (FORALL^) or exists (EXISTS^) (in the "ACL2" package), bound-vars is a variable or true list of variables disjoint from (var1 ... varn) and not including state (STATE^), and term is a term. The case that bound-vars is a single variable v is treated exactly the same as the case that bound-vars is (v).

The result of this event is to introduce a “Skolem function,” whose name is the keyword argument skolem-name if that is supplied, and otherwise is the result of modifying fn by suffixing "-WITNESS" to its name. The following definition and and of the following two theorems are introduced for skolem-name and fn in the case that bound-vars (see above) is a single variable v. The name of the defthm (DEFTHM^) event may be supplied as the value of the keyword argument :thm-name; if it is not supplied, then it is the result of modifying fn by suffixing "-SUFF" to its name in the case that the quantifier is exists (EXISTS^), and "-NECC" in the case that the quantifier is forall (FORALL^).

     (defun fn (var1 ... varn)
       (let ((v (skolem-name var1 ... varn)))
         body))
     (defthm fn-suff ;in case the quantifier is EXISTS
       (implies body
                (fn var1 ... varn)))
     (defthm fn-necc ;in case the quantifier is FORALL
       (implies (not body)
                (not (fn var1 ... varn))))

In the case that bound-vars is a list of at least two variables, say (bv1 ... bvk), the definition above is the following instead, but the theorem remains unchanged.

     (defun fn (var1 ... varn)
       (mv-let (bv1 ... bvk)
               (skolem-name var1 ... varn)
               body))

In order to emphasize that the last element of the list body is a term, defun-sk checks that the symbols forall (FORALL^) and exists (EXISTS^) do not appear anywhere in it. However, on rare occasions one might deliberately choose to violate this convention, presumably because forall (FORALL^) or exists (EXISTS^) is being used as a variable or because a macro call will be eliminating “calls of” forall (FORALL^) and exists (EXISTS^). In these cases, the keyword argument quant-ok may be supplied a non-nil value. Then defun-sk will permit forall (FORALL^) and exists (EXISTS^) in the body, but it will still cause an error if there is a real attempt to use these symbols as quantifiers.

Those who want a more flexible version of defun-sk that allows nested quantifiers, should contact the implementors. In the meantime, if you want to represent nested quantifiers, you have to manage that yourself. For example, in order to represent

     (forall x (exists y (p x y z)))

you would use defun-sk twice, for example as follows.

     (defun-sk exists-y-p (x z)
       (exists y (p x y z)))
     (defun-sk forall-x-exists-y-p (z)
       (forall x (exists-y-p x z)))

Some distracting and unimportant warnings are inhibited during defun-sk.

Defun-sk is implemented using defchoose (DEFCHOOSE^), and hence should only be executed in defun-mode (DEFUN-MODE^) :logic (LOGIC^); see Section 8.20 [DEFUN-MODE], page 275 and see Section 6.3 [DEFCHOOSE], page 163.

Note that this way of implementing quantifiers is not a new idea. Hilbert was certainly aware of it 60 years ago! The “story” (see Section 8.7 [BIBLIOGRAPHY], page 257) explains why our use of defchoose (DEFCHOOSE^) is appropriate, even in the presence of epsilon-0 induction.

6.17.1 EXISTS

EXISTS existential quantifier

The symbol exists (in the ACL2 package) represents existential quantification in the context of a defun-sk (DEFUN-SK^) form. See Section 6.17 [DEFUN-SK], page 182 and see Section 6.17.2 [FORALL], page 185.

6.17.2 FORALL

FORALL universal quantifier

The symbol forall (in the ACL2 package) represents universal quantification in the context of a defun-sk (DEFUN-SK^) form. See Section 6.17 [DEFUN-SK], page 182 and see Section 6.17.1 [EXISTS], page 185.

6.18 ENCAPSULATE

ENCAPSULATE constrain some functions and/or hide some events (EVENTS^)

     Examples:
     (encapsulate ((an-element (lst) t))
       (local (defun an-element (lst)
                (if (consp lst) (car lst) nil)))
       (local (defthm member-equal-car
                 (implies (and lst (true-listp lst))
                          (member-equal (car lst) lst))))
       (defthm thm1
          (implies (null lst) (null (an-element lst))))
       (defthm thm2
          (implies (and (true-listp lst)
                        (not (null lst)))
                   (member-equal (an-element lst) lst))))
     (encapsulate
      ()
      (local (defthm hack
               (implies (and (syntaxp (quotep x))
                             (syntaxp (quotep y)))
                        (equal (+ x y z)
                               (+ (+ x y) z)))))
      (defthm nthcdr-add1-conditional
        (implies (not (zp (1+ n)))
                 (equal (nthcdr (1+ n) x)
                        (nthcdr n (cdr x))))))
     General Form:
     (encapsulate (signature ... signature)
       ev1
       ...
       evn)

where each signature (SIGNATURE^) is as described in the documentation for signature (SIGNA-TURE^), each signature (SIGNATURE^) describes a different function symbol, and each evi is an embedded event form as described in the documentation for embedded-event-form (EMBEDDED-EVENT-FORM^). There must be at least one evi. The evi inside local (LOCAL^) special forms are called “local” events (EVENTS^) below. Events (EVENTS^) that are not local (LOCAL^) are sometimes said to be “exported” by the encapsulation. We make the further restriction that no defaxiom event may be introduced in the scope of an encapsulate (not even by encapsulate or include-book (INCLUDE-BOOK^) events that are among the evi). Furthermore, no non-local (LOCAL^) include-book (INCLUDE-BOOK^) event is permitted in the scope of any encapsulate with a non-empty list of signatures.

To be well-formed, an encapsulate event must have the properties that each event in the body (including the local (LOCAL^) ones) can be successfully executed in sequence and that in the resulting theory, each function mentioned among the signature (SIGNATURE^)s was introduced via a local (LOCAL^) event and has the signature (SIGNATURE^) listed. In addition, the body may contain no “local incompatibilities” which, roughly stated, means that the events (EVENTS^) that are not local (LOCAL^) must not syntactically require symbols defined by local (LOCAL^) events (EVENTS^), except for the functions listed in the signature (SIGNATURE^)s. See Section 8.62 [LOCAL-INCOMPATIBILITY], page 344. Finally, no non-local (LOCAL^) recursive definition in the body may involve in its suggested induction scheme any function symbol listed among the signature (SIGNATURE^)s. See Section 8.84 [SUBVERSIVE-INDUCTIONS], page 371.

The result of an encapsulate event is an extension of the logic in which, roughly speaking, the functions listed in the signature (SIGNATURE^)s are constrained to have the signature (SIGNA-TURE^)s listed and to satisfy the non-local (LOCAL^) theorems proved about them. In fact, other functions introduced in the encapsulate event may be considered to have “constraint (CON-STRAINT^)s” as well. (See Section 8.14 [CONSTRAINT], page 265 for details, which are only relevant to functional instantiation.) Since the constraint (CONSTRAINT^)s were all theorems in the “ephemeral” or “local” theory, we are assured that the extension produced by encapsulate is sound. In essence, the local (LOCAL^) definitions of the constrained functions are just “witness functions” that establish the consistency of the constraint (CONSTRAINT^)s. Because those definitions are local (LOCAL^), they are not present in the theory produced by encapsulation. Encapsulate also exports all rules generated by its non-local (LOCAL^) events (EVENTS^), but rules generated by local (LOCAL^) events (EVENTS^) are not exported.

The default-defun-mode (DEFAULT-DEFUN-MODE^) for the first event in an encapsulation is the default defun-mode (DEFUN-MODE^) “outside” the encapsulation. But since events (EVENTS^) changing the defun-mode (DEFUN-MODE^) are permitted within the body of an encapsulate, the default defun-mode (DEFUN-MODE^) may be changed. However, defun-mode (DEFUN-MODE^) changes occurring within the body of the encapsulate are not exported. In particular, the acl2defaults-table (ACL2-DEFAULTS-TABLE^) after an encapsulate is always the same as it was before the encapsulate, even though the encapsulate body might contain defun-mode (DEFUN-MODE^) changing events (EVENTS^), :program (PROGRAM^) and :logic (LOGIC^). See Section 8.20 [DEFUN-MODE], page 275. More generally, after execution of an encapsulate event, the value of acl2-defaults-table (ACL2-DEFAULTS-TABLE^) is restored to what it was immediately before that event was executed. See Section 9.2 [ACL2-DEFAULTS-TABLE], page 410.

Theorems about the constrained function symbols may then be proved — theorems whose proofs necessarily employ only the constraint (CONSTRAINT^)s. Thus, those theorems may be later functionally instantiated, as with the :functional-instance lemma instance (see Section 8.61 [LEMMA-INSTANCE], page 342), to derive analogous theorems about different functions, provided the constraints (see Section 8.14 [CONSTRAINT], page 265) can be proved about the new functions.

Observe that if the signature (SIGNATURE^)s list is empty, encapsulate may still be useful for deriving theorems to be exported whose proofs require lemmas you prefer to hide (i.e., made local (LOCAL^)).

The order of the events (EVENTS^) in the vicinity of an encapsulate is confusing. We discuss it in some detail here because when logical names are being used with theory functions to compute sets of rules, it is sometimes important to know the order in which events (EVENTS^) were executed. (See Section 8.63 [LOGICAL-NAME], page 346 and see Section 16.13 [THEORY-FUNCTIONS], page 787.) What, for example, is the set of function names extant in the middle of an encapsulation?

If the most recent event is previous and then you execute an encapsulate constraining anelement with two non-local (LOCAL^) events (EVENTS^) in its body, thm1 and thm2, then the order of the events (EVENTS^) after the encapsulation is (reading chronologically forward):

previous, thm1, thm2, an-element (the encapsulate itself). Actually, between previous and

thm1 certain extensions were made to the world (WORLD^) by the superior encapsulate, to permit an-element to be used as a function symbol in thm1.

Finally, we note that an encapsulate (ENCAPSULATE^) event is redundant if and only if a syntactically identical encapsulate (ENCAPSULATE^) has already been executed under the same default-defun-mode (DEFAULT-DEFUN-MODE^). See Section 8.78 [REDUNDANT-EVENTS], page 361.

6.19 IN-THEORY

IN-THEORY designate “current” theory (enabling its rules)

     Example:
     (in-theory (set-difference-theories
                  (universal-theory :here)
                  '(flatten (:executable-counterpart flatten))))
     General Form:
     (in-theory term :doc doc-string)

where term is a term that when evaluated will produce a theory (see Chapter 16 [THEORIES], page 775), and doc-string (DOC-STRING^) is an optional documentation (DOCUMENTA-TION^) string not beginning with “:doc-section ...”. Except for the variable world (WORLD^), term must contain no free variables. Term is evaluated with the variable world (WORLD^) bound to the current world (WORLD^) to obtain a theory and the corresponding runic theory (see Chapter 16 [THEORIES], page 775) is then made the current theory. Thus, immediately after the in-theory, a rule is enable (ENABLE^)d iff its rule name is a member of the runic interpretation (see Chapter 16 [THEORIES], page 775) of some member of the value of term. See Section 16.13 [THEORY-FUNCTIONS], page 787 for a list of the commonly used theory manipulation functions.

Because no unique name is associated with an in-theory event, there is no way we can store the documentation (DOCUMENTATION^) string doc-string (DOC-STRING^) in our documentation (DOCUMENTATION^) data base. Hence, we actually prohibit doc-string (DOC-STRING^) from having the form of an ACL2 documentation (DOCUMENTATION^) string; see Section 5.5 [DOC-STRING], page 143.

6.20 INCLUDE-BOOK

INCLUDE-BOOK load the events (EVENTS^) in a file

     Examples:
     (include-book "my-arith")
     (include-book (:RELATIVE "my-arith"))
     (include-book "/home/smith/my-arith")
     (include-book (:ABSOLUTE "home" "smith" "my-arith"))
     General Form:
     (include-book file :load-compiled-file action :doc doc-string)

where file is a book name. See Chapter 3 [BOOKS], page 93 for general information, see Section 3.3 [BOOK-NAME], page 99 for information about book names, and see Section 3.9 [PATHNAME], page 110 for information about file names (including structured pathname (PATH-NAME^)s). Action is one of t, nil, :warn (the default), or :try; these values are explained below. Doc-string is an optional documentation (DOCUMENTATION^) string; see Section 5.5 [DOC-STRING], page 143. If the book has no certificate (CERTIFICATE^), if its certificate (CERTIFICATE^) is invalid or if the certificate was produced by a different version (VERSION^) of ACL2, a warning is printed and the book is included anyway; see Section 3.5 [CERTIFICATE], page 104. This can lead to serious errors; see Section 3.12 [UNCERTIFIED-BOOKS], page 116. If the portcullis of the certificate (CERTIFICATE^) (see Section 3.10 [PORTCULLIS], page 113) cannot be raised in the host logical world (WORLD^), an error is caused and no change occurs to the logic. Otherwise, the non-local (LOCAL^) events (EVENTS^) in file are assumed. Then the keep (KEEP^) of the certificate (CERTIFICATE^) is checked to insure that the correct files were read; see Section 3.8 [KEEP], page 109. A warning is printed if uncertified books (BOOKS^) were included. Even if no warning is printed, include-book places a burden on you; see Section 3.5 [CERTIFICATE], page 104.

If there is a compiled file for the book that was created more recently than the book itself and the value action of the :load-compiled-file argument is not nil, or is omitted, then the compiled file is automatically loaded; otherwise it is not loaded. If action is t then the compiled file must be loaded or an error will occur, while if action is :warn (the default) then a warning will be printed. Certify-book (CERTIFY-BOOK^) can be used to compile a book. The effect of compilation (COMPILATION^) is to speed up the execution of the functions defined within the book when those functions are applied to specific values. The presence of compiled code for the functions in the book should not otherwise affect the performance of ACL2. See Section 8.41 [GUARD], page 305 for a discussion.

Include-book is similar in spirit to encapsulate (ENCAPSULATE^) in that it is a single event that “contains” other events (EVENTS^), in this case the events (EVENTS^) listed in the file named. Include-book processes the non-local (LOCAL^) event forms in the file, assuming that each is admissible. Local (LOCAL^) events (EVENTS^) in the file are ignored. You may use include-book to load multiple books (BOOKS^), creating the logical world (WORLD^) that contains the definitions and theorems of all of them.

If any non-local (LOCAL^) event of the book attempts to define a name (NAME^) that has already been defined — and the book’s definition is not syntactically identical to the existing definition — the attempt to include the book fails, an error message is printed, and no change to the logical world (WORLD^) occurs. See Section 8.78 [REDUNDANT-EVENTS], page 361 for the details.

When a book is included, the default defun-mode (DEFUN-MODE^) (see Section 8.18 [DEFAULT-DEFUN-MODE], page 273) for the first event is always :logic (LOGIC^). That is, the default defun-mode (DEFUN-MODE^) “outside” the book — in the environment in which include-book was called — is irrelevant to the book. Events (EVENTS^) that change the defun-mode (DEFUN-MODE^) are permitted within a book (provided they are not in local (LOCAL^) forms). However, such changes within a book are not exported, i.e., at the conclusion of an include-book, the “outside” default defun-mode (DEFUN-MODE^) is always the same as it was before the include-

book.

Unlike every other event in ACL2, include-book puts a burden on you. Used improperly, includebook can be unsound in the sense that it can create an inconsistent extension of a consistent logical world (WORLD^). A certification mechanism is available to help you carry this burden — but it must be understood up front that even certification is no guarantee against inconsistency here. The fundamental problem is one of file system security. See Section 3.5 [CERTIFICATE], page 104 for a discussion of the security issues.

After execution of an include-book form, the value of acl2-defaults-table (ACL2-DEFAULTS-TABLE^) is restored to what it was immediately before that include-book form was executed. See Section 9.2 [ACL2-DEFAULTS-TABLE], page 410.

This concludes the guided tour through books (BOOKS^). See Section 6.27 [SET-COMPILE-FNS], page 197 for a subtle point about the interaction between include-book and on-the-fly compilation (COMPILATION^). See Section 3.6 [CERTIFY-BOOK], page 106 for a discussion of how to certify a book.

6.21 LOCAL

LOCAL hiding an event in an encapsulation or book

     Examples:
     (local (defthm hack1
              (implies (and (acl2-numberp x)
                            (acl2-numberp y)
                            (equal (* x y) 1))
                       (equal y (/ x)))))
     (local (defun double-naturals-induction (a b)
              (cond ((and (integerp a) (integerp b) (< 0 a) (< 0 b))
                     (double-naturals-induction (1- a) (1- b)))
                    (t (list a b)))))
     General Form:
     (local ev)

where ev is an event form. If the current default defun-mode (DEFUN-MODE^) (see Section 8.18 [DEFAULT-DEFUN-MODE], page 273) is :logic (LOGIC^) and ld-skip-proofsp (LD-SKIP-PROOFSP^) is nil or t, then (local ev) is equivalent to ev. But if the current default defun-mode (DEFUN-MODE^) is :program (PROGRAM^) or if ld-skip-proofsp (LD-SKIP-PROOFSP^) is 'include-book (INCLUDE-BOOK^), then (local ev) is a no-op. Thus, if such forms are in the event list of an encapsulate (ENCAPSULATE^) event or in a book, they are processed when the encapsulation or book is checked for admissibility in :logic (LOGIC^) mode but are skipped when extending the host world (WORLD^). Such events (EVENTS^) are thus considered “local” to the verification of the encapsulation or book. The non-local events (EVENTS^) are the ones “exported” by the encapsulation or book. See Section 6.18 [ENCAPSULATE], page 185 for a thorough discussion. Also see Section 8.62 [LOCAL-INCOMPATIBILITY], page 344 for a discussion of a commonly encountered problem with such event hiding: you can’t make an event local if its presence is required to make sense of a non-local one.

Note that events (EVENTS^) that change the default defun-mode (DEFUN-MODE^), and in fact any events (EVENTS^) that set the acl2-defaults-table (ACL2-DEFAULTS-TABLE^), are disallowed inside the scope of local. See Section 8.27 [EMBEDDED-EVENT-FORM], page 286.

6.22 LOGIC

LOGIC to set the default defun-mode (DEFUN-MODE^) to :logic

     Example:
     ACL2 p!>:logic
     ACL2 !>

Typing the keyword :logic sets the default defun-mode (DEFUN-MODE^) to :logic.

Functions defined in :logic mode are logically defined. See Section 8.20 [DEFUN-MODE], page 275.

Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

See Section 8.20 [DEFUN-MODE], page 275 for a discussion of the defun-mode (DEFUN-MODE^)s available and what their effects on the logic are. See Section 8.18 [DEFAULT-DEFUN-MODE], page 273 for a discussion of how the default defun-mode (DEFUN-MODE^) is used. This event

is equivalent to (table acl2-defaults-table :defun-mode :logic). See Section 9.2 [ACL2-

DEFAULTS-TABLE], page 410.

Recall that the top-level form :logic is equivalent to (logic); see Section 8.48 [KEYWORD-COMMANDS], page 328. Thus, to change the default defun-mode (DEFUN-MODE^) to :logic in a book, use (logic), which is an embedded event form, rather than :logic, which is not a legal form for books (BOOKS^). See Section 8.27 [EMBEDDED-EVENT-FORM], page 286.

6.23 MACRO-ALIASES-TABLE

MACRO-ALIASES-TABLE a table (TABLE^) used to associate function names with macro names

     Example:
     (table macro-aliases-table 'append 'binary-append)

This example associates the function symbol binary-append (BINARY-APPEND^) with the macro name append (APPEND^). As a result, the name append (APPEND^) may be used as a runic designator (see Chapter 16 [THEORIES], page 775) by the various theory functions. Thus, for example, it will be legal to write

     (in-theory (disable append))

as an abbreviation for

     (in-theory (disable binary-append))

which in turn really abbreviates

     (in-theory (set-difference-theories (current-theory :here)
                                         '(binary-append)))
     General Form:
     (table macro-aliases-table 'macro-name 'function-name)

or very generally

     (table macro-aliases-table macro-name-form function-name-form)

where macro-name-form and function-name-form evaluate, respectively, to a macro name and a function name in the current ACL2 world (WORLD^). See Section 6.36 [TABLE], page 204 for a general discussion of tables and the table event used to manipulate tables.

The table (TABLE^) macro-aliases-table (MACRO-ALIASES-TABLE^) is an alist that associates macro symbols with function symbols, so that macro names may be used as runic designators (see Chapter 16 [THEORIES], page 775). For a convenient way to add entries to this table (TABLE^), see Section 6.1 [ADD-MACRO-ALIAS], page 162. To remove entries from the table (TABLE^) with ease, see Section 6.26 [REMOVE-MACRO-ALIAS], page 196.

This table (TABLE^) is used by the theory functions. For example, in order that (disable append) be interpreted as (disable binary-append), it is necessary that the example form above has been executed. In fact, this table (TABLE^) does indeed associate many of the macros provided by the ACL2 system, including append (APPEND^), with function symbols. Loosely speaking, it only does so when the macro is “essentially the same thing as” a corresponding function; for example, (append x y) and (binary-append x y) represent the same term, for any expressions x and y.

6.24 MUTUAL-RECURSION

MUTUAL-RECURSION define some mutually recursive functions

     Example:
     (mutual-recursion
      (defun evenlp (x)
        (if (consp x) (oddlp (cdr x)) t))
      (defun oddlp (x)
        (if (consp x) (evenlp (cdr x)) nil)))
     General Form:
     (mutual-recursion def1 ... defn)
     where each defi is a DEFUN form.

When mutually recursive functions are introduced it is necessary to do the termination analysis on the entire clique of definitions. Each defun (DEFUN^) form specifies its own measure, either with the :measure keyword xarg (see Section 8.102 [XARGS], page 406) or by default to acl2-count (ACL2-COUNT^). When a function in the clique calls a function in the clique, the measure of the callee’s actuals must be smaller than the measure of the caller’s formals — just as in the case of a simply recursive function. But with mutual recursion, the callee’s actuals are measured as specified by the callee’s defun (DEFUN^) while the caller’s formals are measured as specified by the caller’s defun (DEFUN^). These two measures may be different but must be comparable in the sense that e0-ord-< (E0-ORD-<^) decreases through calls.

The guard (GUARD^) analysis must also be done for all of the functions at the same time. If any one of the defun (DEFUN^)s specifies the :verify-guards (VERIFY-GUARDS^) xarg to be nil, then guard (GUARD^) verification is omitted for all of the functions.

Technical Note: Each defi above must be of the form (defun ...). In particular, it is not permitted for a defi to be a form that will macroexpand into a defun (DEFUN^) form. This is because mutual-recursion is itself a macro, and since macroexpansion occurs from the outside in, at the time (mutual-recursion def1 ... defk) is expanded the defi have not yet been. But mutual-recursion must decompose the defi. We therefore insist that they be explicitly presented as defun (DEFUN^)s.

Suppose you have defined your own defun (DEFUN^)-like macro and wish to use it in a mutualrecursion expression. Well, you can’t. (!) But you can define your own version of mutualrecursion that allows your defun (DEFUN^)-like form. Here is an example. Suppose you define

     (defmacro my-defun (&rest args) (my-defun-fn args))

where my-defun-fn takes the arguments of the my-defun form and produces from them a defun (DEFUN^) form. As noted above, you are not allowed to write (mutual-recursion (my-defun ...) ...). But you can define the macro my-mutual-recursion so that

     (my-mutual-recursion (my-defun ...) ... (my-defun ...))

expands into (mutual-recursion (defun ...) ... (defun ...)) by applying my-defun-fn to

each of the arguments of my-mutual-recursion.

     (defun my-mutual-recursion-fn (lst)
       (declare (xargs :guard (alistp lst)))
     ; Each element of lst must be a consp (whose car, we assume, is always
     ; MY-DEFUN).  We apply my-defun-fn to the arguments of each element and
     ; collect the resulting list of DEFUNs.
       (cond ((atom lst) nil)
             (t (cons (my-defun-fn (cdr (car lst)))
                      (my-mutual-recursion-fn (cdr lst))))))
     (defmacro my-mutual-recursion (&rest lst)
     ; Each element of lst must be a consp (whose car, we assume, is always
     ; MY-DEFUN).  We obtain the DEFUN corresponding to each and list them
     ; all inside a MUTUAL-RECURSION form.
       (declare (xargs :guard (alistp lst)))
       (cons 'mutual-recursion (my-mutual-recursion-fn lst))).

6.25 PROGRAM

PROGRAM to set the default defun-mode (DEFUN-MODE^) to :program

     Example:
     ACL2 !>:program
     ACL2 p!>

Typing the keyword :program sets the default defun-mode (DEFUN-MODE^) to :program.

Functions defined in :program mode are logically undefined but can be executed on constants outside of deductive contexts. See Section 8.20 [DEFUN-MODE], page 275.

Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

See Section 8.20 [DEFUN-MODE], page 275 for a discussion of the defun-mode (DEFUN-MODE^)s available and what their effects on the logic are. See Section 8.18 [DEFAULT-DEFUN-MODE], page 273 for a discussion of how the default defun-mode (DEFUN-MODE^) is used. This event

is equivalent to (table acl2-defaults-table :defun-mode :program). See Section 9.2 [ACL2-

DEFAULTS-TABLE], page 410.

Recall that the top-level form :program is equivalent to (program); see Section 8.48 [KEYWORD-COMMANDS], page 328. Thus, to change the default defun-mode (DEFUN-MODE^) to :program in a book, use (program), which is an embedded event form, rather than :program, which is not a legal form for books (BOOKS^). See Section 8.27 [EMBEDDED-EVENT-FORM], page 286.

6.26 REMOVE-MACRO-ALIAS

REMOVE-MACRO-ALIAS remove the association of a function name with a macro name

     Example:
     (remove-macro-alias append)
     General Form:
     (remove-macro-alias macro-name)

See Section 6.23 [MACRO-ALIASES-TABLE], page 192 for a discussion of macro aliases; also see Section 6.1 [ADD-MACRO-ALIAS], page 162. This form sets macro-aliases-table (MACRO-ALIASES-TABLE^) to the result of deleting the key macro-name from that table (TABLE^). If the name does not occur in the table (TABLE^), then this form still generates an event, but the event has no real effect.

6.27 SET-COMPILE-FNS

SET-COMPILE-FNS have each function compiled as you go along.

     Example Forms:
     (set-compile-fns t)    ; new functions compiled after DEFUN
     (set-compile-fns nil)  ; new functions not compiled after DEFUN

Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

Also see Section 9.5 [COMP], page 415, because it may be more efficient in some Common Lisps to compile many functions at once rather than to compile each one as you go along.

     General Form:
     (set-compile-fns term)

where term is a variable-free term that evaluates to t or nil. This macro is equivalent to

     (table acl2-defaults-table :compile-fns term).

However, unlike that simple call of the table (TABLE^) event function (see Section 6.36 [TABLE], page 204), no output results from a set-compile-fns event.

Set-compile-fns may be thought of as an event that merely sets a flag to t or nil. The flag’s effect is felt when functions are defined, as with defun (DEFUN^). If the flag is t, functions are automatically compiled after they are defined, as are their executable counterparts (see Section 8.32 [EXECUTABLE-COUNTERPART], page 291). Otherwise, functions are not automatically compiled. Because set-compile-fns is an event, the old value of the flag is restored when a

set-compile-fns event is undone.

Even when :set-compile-fns t has been executed, functions are not individually compiled when processing an include-book (INCLUDE-BOOK^) event. If you wish to include a book of compiled functions, we suggest that you first certify it with the compilation (COMPILATION^) flag set; see Section 3.6 [CERTIFY-BOOK], page 106. More generally, compilation (COMPILATION^) via set-compile-fns is suppressed when the state (STATE^) global variable ld-skip-proofsp (LD-SKIP-PROOFSP^) has value 'include-book (INCLUDE-BOOK^).

6.28 SET-IGNORE-OK

SET-IGNORE-OK allow unused formals and locals without an ignore declaration

     Examples:
     (set-ignore-ok t)
     (set-ignore-ok nil)
     (set-ignore-ok :warn)

The first example above allows unused formals and locals, i.e., variables that would normally have to be declare (DECLARE^)d ignored. The second example disallows unused formals and locals; this is the default. The third example allows them, but prints an appropriate warning.

Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

     General Form:
     (set-ignore-ok flg)

where flg is either t, nil, or :warn.

One might find this event useful when one is generating function definitions by an automated procedure, when that procedure does not take care to make sure that all formals are actually used in the definitions that it generates.

6.29 SET-INHIBIT-WARNINGS

SET-INHIBIT-WARNINGS control warnings

     Examples:
     (set-inhibit-warnings "theory" "use")

Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

     General Form:
     (set-inhibit-warnings string1 string2 ...)

where each string is considered without regard to case. This macro is equivalent to (table acl2defaults-table :inhibit-warnings lst), where lst is the list of strings supplied. This macro is an event (see Section 6.36 [TABLE], page 204), but no output results from a set-inhibit-

warnings event.

The effect of this event is to suppress any warning whose label is a member of this list (where again, case is ignored). For example, the warning

       ACL2 Warning [Use] in ( THM ...):  It is unusual to :USE ....

will not be printed if "use" (or "USE", etc.) is a member of the given list of strings.

Of course, if warnings are inhibited overall — see Section 9.13 [SET-INHIBIT-OUTPUT-LST], page 424 — then the value of :inhibit-warnings is entirely irrelevant.

6.30 SET-INVISIBLE-FNS-ALIST

SET-INVISIBLE-FNS-ALIST set the invisible functions alist

     Examples:
     (set-invisible-fns-alist ((binary-+ unary--)
                               (binary-* unary-/)
                               (unary-- unary--)
                               (unary-/ unary-/)))

Among other things, the setting above has the effect of making unary-- (UNARY–^) “invisible” for the purposes of applying permutative :rewrite (REWRITE^) rules to binary-+ (BINARY-+^) trees. Thus, arg and (unary-- arg) will be given the same weight and will be permuted so as to be adjacent. The form (invisible-fns-alist (w state)) returns the current value of the invisible functions alist.

Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

     General Form:
     (set-invisible-fns-alist alist)

where alist is either t or a true list of pairs, each element of which is of the form (fn ufn1 ... ufnk), where fn is a function symbol and each ufni is a unary function symbol. When alist is t, the initial default alist is used in its place. Modulo the replacement of alist by the default setting when alist is t, this macro is equivalent to

     (table acl2-defaults-table :invisible-fns-alist 'alist),

which is also an event (see Section 6.36 [TABLE], page 204), but no output results from a set-

invisible-fns-alist event.

The “invisible functions alist” is an alist that associates with certain function symbols, e.g., fn above, a set of unary functions, e.g., the ufni above. The ufni associated with fn in the invisible functions alist are said to be “invisible with respect to fn.” If fn is not the car (CAR^) of any pair on the invisible functions alist, then no function is invisible for it. Thus, setting the invisible functions alist to nil completely eliminates the consideration of invisibility.

The notion of invisibility is involved in the use of the :loop-stopper (LOOP-STOPPER^) field of :rewrite (REWRITE^) rules to prevent the indefinite application of permutative rewrite rules. Roughly speaking, if rewrite rules are being used to permute arg and (ufni arg) inside of a nest of fn calls, and ufni is invisible with respect to fn, then arg and (ufni arg) are considered to have the same “weight” and will be permuted so as to end up as adjacent tips in the fn nest. See Section 8.64 [LOOP-STOPPER], page 347.

6.31 SET-IRRELEVANT-FORMALS-OK

SET-IRRELEVANT-FORMALS-OK allow irrelevant formals in definitions

     Examples:
     (set-irrelevant-formals-ok t)
     (set-irrelevant-formals-ok nil)
     (set-irrelevant-formals-ok :warn)

The first example above allows irrelevant formals in definitions; see Section 10.136 [IRRELEVANT-FORMALS], page 495. The second example disallows irrelevant formals; this is the default. The third example allows irrelevant formals, but prints an appropriate warning.

Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

     General Form:
     (set-irrelevant-formals-ok flg)

where flg is either t, nil, or :warn.

6.32 SET-MEASURE-FUNCTION

SET-MEASURE-FUNCTION set the default measure function symbol

     Examples:
     (set-measure-function nqthm::count)

Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

     General Form:
     (set-measure-function name)

where name is a function symbol of one argument. This macro is equivalent to (table acl2defaults-table :measure-function 'name), which is also an event (see Section 6.36 [TABLE], page 204), but no output results from a set-measure-function event.

This event sets the default measure function to name. Subsequently, if a recursively defined function is submitted to defun (DEFUN^) with no explicitly given :measure argument, defun (DEFUN^) “guesses” the measure (name var), where name is the then current default measure function and var is the first formal found to be tested along every branch and changed in every recursive call.

6.33 SET-STATE-OK

SET-STATE-OK allow the use of STATE as a formal parameter

Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

Because the variable symbol STATE (STATE^) denotes the “current ACL2 state,” ACL2 treats the symbol very restrictively when it occurs as a formal parameter of a defined function. The novice user, who is unlikely to be aware of the special status of that symbol, is likely to be confused when error messages about STATE are printed in response to the innocent choice of that symbol as a formal variable. Therefore the top-level ACL2 loop can operate in a mode in which STATE (STATE^) is simply disallowed as a formal parameter.

For a discussion of STATE, See Section 8.83 [STATE], page 368. Roughly speaking, at the top-level, the “current ACL2 state” is denoted by the variable symbol STATE. Only the current state may be passed into a function expecting a state as an argument. Furthermore, the name of the formal parameter into which the current state is passed must be STATE and nothing but the current state may be passed into a formal of that name. Therefore, only certain access and change functions can use that formal – namely with a STATE formal – and if any such function produces a new state it becomes the “current state” and must be passed along in the STATE position thereafter. Thus, ACL2 requires that the state be single-threaded. This, in turn, allows us to represent only one state at a time and to produce new states from it destructively in a von Neumaneque fashion. The syntactic restrictions on the variable STATE are enforced by the translate mechanism (see Section 9.16 [TRANS], page 427 and see Section 8.87 [TERM], page 376) when terms are read.

To prevent the novice user from seeing messages prohibiting certain uses of the variable symbol STATE ACL2 has a mode in which it simply disallows the use of that symbol as a formal parameter. Use of the symbol causes a simple error message. The system is initially in that mode.

To get out of that mode, execute:

     :set-state-ok t

It is not recommended that you do this until you have read the documentation of STATE (STATE^).

To enter the mode in which use of state is prohibited as a formal parameter, do:

     :set-state-ok nil

The mode is stored in the defaults table, See Section 9.2 [ACL2-DEFAULTS-TABLE], page 410. Thus, the mode may be set locally in books.

6.34 SET-VERIFY-GUARDS-EAGERNESS

SET-VERIFY-GUARDS-EAGERNESS the eagerness with which guard (GUARD^) verification is tried.

     Example Forms:                        try guard verification?
     (set-verify-guards-eagerness 0) ; no, unless :verify-guards t
     (set-verify-guards-eagerness 1) ; yes if a :guard is supplied
     (set-verify-guards-eagerness 2) ; yes, unless :verify-guards nil

Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

     General Form:
     (set-verify-guards-eagerness n)

where n is a variable-free term that evaluates to 0, 1, or 2. This macro is equivalent to

     (table acl2-defaults-table :verify-guards-eagerness term).

However, unlike that simple call of the table (TABLE^) event function (see Section 6.36 [TABLE], page 204), no output results from a set-verify-guards-eagerness event.

Set-verify-guards-eagerness may be thought of as an event that merely sets a flag to 0, 1, or 2. The flag is used by certain defun (DEFUN^) events (EVENTS^) to determine whether guard (GUARD^) verification is tried. The flag is irrelevant to those defun (DEFUN^) events (EVENTS^) in :program (PROGRAM^) mode and to those defun (DEFUN^) events (EVENTS^) in which an explicit :verify-guards (VERIFY-GUARDS^) setting is provided among the xargs (XARGS^). In the former case, guard (GUARD^) verification is not done because it can only be done when logical functions are being defined. In the latter case, the explicit :verify-guards (VERIFY-GUARDS^) setting determines whether guard (GUARD^) verification is tried. So consider a :logic (LOGIC^) mode defun (DEFUN^) in which no :verify-guards (VERIFY-GUARDS^) setting is provided. Is guard (GUARD^) verification tried? The answer depends on the eagerness setting as follows. If the eagerness is 0, guard (GUARD^) verification is not tried. If the eagerness is 1, it is tried iff a :guard (GUARD^) is explicitly provided in the defun (DEFUN^). If the eagerness is 2, guard (GUARD^) verification is tried.

The default behavior of the system is as though the :verify-guards-eagerness is 1.

6.35 SET-WELL-FOUNDED-RELATION

SET-WELL-FOUNDED-RELATION set the default well-founded relation

     Examples:

     (set-well-founded-relation lex2)

provided lex2 has been proved to be a well-founded relation (see Section 15.17 [WELL-FOUNDED-RELATION], page 769). Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical world (WORLD^) and is so recorded.

     General Form:
     (set-well-founded-relation rel)

where rel has been proved to be a well-founded relation on objects satisfying some predicate, mp, as described in the documentation (DOCUMENTATION^) for well-founded-relation (WELL-FOUNDED-RELATION^). This macro is equivalent to (table acl2-defaults-table :well-

founded-relation 'rel).

This event sets the default well-founded relation to be that imposed on mp-measures by the relation rel. Subsequently, if a recursively defined function is submitted to defun (DEFUN^) with no explicitly given :well-founded-relation (WELL-FOUNDED-RELATION^) argument, defun (DEFUN^) uses the default relation, rel, and the associated domain predicate mp used in its wellfoundedness theorem. That is, the termination conditions generated will require proving that the measure used by the defun (DEFUN^) is an mp-measure and that in every recursive call the measure of the arguments decreases according to rel.

6.36 TABLE

TABLE user-managed tables

     Examples:
     (table tests 1 '(...))               ; set contents of tests[1] to '(...)
     (table tests 25)                     ; get contents of tests[25]
     (table tests)                        ; return table tests as an alist
     (table tests nil nil :clear)         ; clear table tests
     (table tests nil (foo 7) :clear)     ; set table tests to (foo 7)
     (table tests nil nil :guard)         ; fetch the table guard
     (table tests nil nil :guard term)    ; set the table guard
     General Form:
     (table table-name key-term value-term op term)

where table-name is a symbol that is the name of a (possibly new) table, key-term and valueterm, if present, are arbitrary terms involving (at most) the single variable world (WORLD^), op, if present, is one of the table operations below, and term, if present, is a term. Table returns an acl2 “error triple.” The effect of table on state (STATE^) depends on op and how many arguments are presented. Some invocations actually have no effect on the ACL2 world (WORLD^) and hence an invocation of table is not always an “event”. We explain below, after giving some background information.

The ACL2 system provides “tables” by which the user can associate one object with another. Tables are in essence just conventional association lists — lists of pairs — but the ACL2 environment provides a means of storing these lists in the “ACL2 world” of the current state (STATE^). The ACL2 user could accomplish the same ends by using ACL2 “global variables;” however, limitations on global variable names are imposed to insure ACL2’s soundness. By convention, no table is important to ACL2’s soundness, even though some features of the system use tables, and the user is invited to make free use of tables. Because tables are stored in the ACL2 world (WORLD^) they are restored by include-book (INCLUDE-BOOK^) and undone by :ubt (UBT^). many users of Nqthm requested a facility by which user data could be saved in Nqthm “lib files” and tables are ACL2’s answer to that request.

Abstractly, each table is an association list mapping “keys” to “values.” In addition, each table has a “:guard,” which is a term that must be true of any key and value used. By setting the :guard on a table you may enforce an invariant on the objects in the table, e.g., that all keys are positive integers and all values are symbols. Each table has a “name,” which must be a symbol. Given a table name, there are six operations one might perform on the table.

:put — associate a value with a key (possibly changing the value currently associated with that key).

:get — retrieve the value associated with a key (or nil if no value has been associated with that key).

:alist — return an alist showing all keys and non-nil values in the table.

:clear — clear the table (so that every value is nil), or if val is supplied then set table to that value (which must be an alist).

:guard — fetch or set the :guard of the table.

When the operations above suggest that the table or its :guard are modified, what is actually meant is that the current state (STATE^) is redefined so that in it, the affected table name has the appropriate properties. in such cases, the table form is an event.

Table forms are commonly typed by the user while interacting with the system. :Put and :get forms are especially common. Therefore, we have adopted a positional syntax that is intended to be convenient for most applications. Essentially, some operations admit a “short form” of invocation.

     (table name key-term value-term :put)   ; long form
     (table name key-term value-term)        ; short form

evaluates the key- and value-terms, obtaining two objects that we call key and value, checks that the key and value satisfy the :guard on the named table and then “modifies” the named table so that the value associated with key is value. When used like this, table is actually an event in the sense that it changes the ACL2 world (WORLD^). In general, the forms evaluated to obtain the key and value may involve the variable world (WORLD^), which is bound to the then-current world (WORLD^) during the evaluation of the forms. However, in the special case that the table in question is named acl2-defaults-table (ACL2-DEFAULTS-TABLE^), the key and value terms may not contain any variables. Essentially, the keys and values used in events (EVENTS^) setting the acl2-defaults-table (ACL2-DEFAULTS-TABLE^) must be explicitly given constants. See Section 9.2 [ACL2-DEFAULTS-TABLE], page 410.

     (table name key-term nil :get)          ; long form
     (table name key-term)                   ; short form

evaluates the key-term (see note below), obtaining an object, key, and returns the value associated with key in the named table (or, nil if there is no value associated with key). When used like this, table is not an event; the value is simply returned.

     (table name nil nil :alist)             ; long form
     (table name)                            ; short form

returns an alist representing the named table; for every key in the table with a non-nil associated value, the alist pairs the key and its value. The order in which the keys are presented is unspecified. When used like this, table is not an event; the alist is simply returned.

     (table name nil val :clear)

sets the named table to the alist val, making the checks that :put makes for each key and value of val. When used like this, table is an event because it changes the ACL2 world (WORLD^).

     (table name nil nil :guard)

returns the translated form of the guard of the named table.

     (table name nil nil :guard term)

Provided the named table is empty and has not yet been assigned a :guard and term (which is not evaluated) is a term that mentions at most the variables key, val and world (WORLD^), this event sets the :guard of the named table to term. Whenever a subsequent :put occurs, term will be evaluated with key bound to the key argument of the :put, val bound to the val argument of the :put, and world (WORLD^) bound to the then current world (WORLD^). An error will be caused by the :put if the result of the evaluation is nil.

Note that it is not allowed to change the :guard on a table once it has been explicitly set. Before the :guard is explicitly set, it is effectively just t. After it is set it can be changed only by undoing the event that set it. The purpose of this restriction is to prevent the user from changing the :guards on tables provided by other people or the system.

The intuition behind the :guard mechanism on tables is to enforce invariants on the keys and values in a table, so that the values, say, can be used without run-time checking. But if the :guard of a table is sensitive to the ACL2 world (WORLD^), it may be possible to cause some value in the table to cease satisfying the :guard without doing any operations on the table. Consider for example the :guard “no value in this table is the name of an event.” As described, that is enforced each time a value is stored. Thus, 'bang can be :put in the table provided there is no event named bang. But once it is in the table, there is nothing to prevent the user from defining bang as a function, causing the table to contain a value that could not be :put there anymore. Observe that not all state-sensitive :guards suffer this problem. The :guard “every value is an event name” remains invariant, courtesy of the fact that undoing back through an event name in the table would necessarily undo the :put of the name into the table.

Table was designed primarily for convenient top-level use. Tables are not especially efficient. Each table is represented by an alist stored on the property list of the table name. :Get is just a getprop and assoc-equal (ASSOC-EQUAL^). :Put does a getprop to the get the table alist, a put-assoc-equal to record the new association, and a putprop to store the new table alist — plus the overhead associated with :guards and undoable events (EVENTS^). Note that there are never duplicate keys in the resulting alist; in particular, when the operation :clear is used to install new alist, duplicate keys are removed from that alist.

A table name may be any symbol whatsoever. Symbols already in use as function or theorem names, for example, may be used as table names. Symbols in use only as table names may be defined with defun (DEFUN^), etc. Because there are no restrictions on the user’s choice of table names, table names are not included among the logical names. Thus, :pe name will never display a table event (for a logical name other than :here). Either :pe name will display a “normal” event such as (defun name ...) or (defthm name ...) or else :pe name will cause an error indicating that name is not a logical name. This happens even if name is in use as a table name. Similarly, we do not permit table names to have documentation (DOCUMENTATION^) strings, since the same name might already have a documentation (DOCUMENTATION^) string. If you want to associate a documentation (DOCUMENTATION^) string with a table name that is being used no other way, define the name as a label and use the :doc (DOC^) feature of deflabel (DEFLABEL^) (see Section 6.9 [DEFLABEL], page 171); also see Section 6.6 [DEFDOC], page 167.

6.37 TERM-TABLE

TERM-TABLE a table used to validate meta rules

     Example:
     (table term-table t '((binary-+ x y) '3 'nil (car x)))

See Section 6.36 [TABLE], page 204 for a general discussion of tables and the table event used to manipulate tables.

The “term-table” is used at the time a meta rule is checked for syntactic correctness. Each proposed metafunction is run on each term in this table, and the result in each case is checked to make sure that it is a termp in the current world. In each case where this test fails, a warning is printed.

Whenever a metafunction is run in support of the application of a meta rule, the result must be a term in the current world. When the result is not a term, a hard error arises. The term-table is simply a means for providing feedback to the user at the time a meta rule is submitted, warning of the definite possibility that such a hard error will occur at some point in the future.

The key used in term-table is arbitrary. The top-most value is always the one that is used; it is the entire list of terms to be considered. Each must be a termp in the current ACL2 world.

6.38 THEORY-INVARIANT

THEORY-INVARIANT user-specified invariants on theories (THEORIES^)

     Example:
     (theory-invariant (not (and (member-equal '(:rewrite left-to-right)

                                                theory)
                                 (member-equal '(:rewrite right-to-left)
                                               theory))))
     General Forms:
     (theory-invariant term)     ; conjoin a new invariant term
     or
     (theory-invariant term key) ; change an existing invariant term

where term is a term that uses no variables other than theory (THEORY^) and world (WORLD^), and key is an arbitrary “name” for this invariant. If key is omitted, an integer is generated and used. Theory-invariant is an event that adds to or modifies the table (TABLE^) of user-supplied theory invariants that are checked each time a theory expression is evaluated.

The theory invariant mechanism is provided via a table (see Section 6.36 [TABLE], page 204) named theory-invariant-table. In fact, the theory-invariant “event” is just a macro that expands into a use of the table (TABLE^) event. More general access to the theory-invariant table (TABLE^) is provided by table (TABLE^) itself. For example, the table (TABLE^) can be inspected or cleared (setting the invariant to t) with table (TABLE^).

Theory-invariant-table maps arbitrary keys to terms mentioning, at most, the variables theory (THEORY^) and world (WORLD^). Every time an alleged theory expression is evaluated, e.g., in the in-theory (IN-THEORY^) event or :in-theory (IN-THEORY^) hint, each of the terms in theory-invariant-table is evaluated with theory (THEORY^) bound to the runic theory (see Chapter 16 [THEORIES], page 775) obtained from the theory expression and world (WORLD^) bound to the current ACL2 world (WORLD^) (see Section 8.100 [WORLD], page 399). If the result is nil, a warning message is printed. Thus, the table (TABLE^) can be thought of as a list of conjuncts. Each term in the table (TABLE^) has a “name,” which is just the key under which the term is stored. When a theory violates the restrictions specified by some term, both the name and the term are printed. By calling theory-invariant with a new term but the same name, you can overwrite that conjunct of the theory invariant.

Theory invariants are particularly useful in the context of large rule sets intended for re-use. Such sets often contain conflicting rules, e.g., rules that are to be enable (ENABLE^)d when certain function symbols are disable (DISABLE^)d, rules that rewrite in opposite directions and thus loop if simultaneously enable (ENABLE^)d, groups of rules which should be enable (ENABLE^)d in concert, etc. The developer of such rule sets understands these restrictions and probably documents them. The theory invariant mechanism allows the developer to codify his restrictions so that when they are violated the user is warned.

Since theory invariants are arbitrary terms, macros may be used to express commonly used restrictions. Because theory invariants are a new idea in ACL2, we have only defined one such macro for illustrative purposes. Executing the event

     (theory-invariant (incompatible (:rewrite left-to-right)
                                     (:rewrite right-to-left)))

would subsequently cause a warning message any time the current theory contained both of the two rune (RUNE^)s shown. Of course, incompatible (INCOMPATIBLE^) is just defined as a macro. Its definition may be inspected with :pe incompatible.

Note: If the table (TABLE^) event is used directly to :put a term into the theory invariant table (TABLE^), be aware that the term must be in translated form. This is enforced by the value invariant for theory-invariant-table. But the upshot of this is that you will be unable to use macros in theory invariants stored directly with the :put table (TABLE^) event.

6.39 VERIFY-GUARDS

VERIFY-GUARDS verify the guard (GUARD^)s of a function

     Examples:
     (verify-guards flatten)
     (verify-guards flatten
                    :hints (("Goal" :use (:instance assoc-of-app)))
                    :otf-flg t
                    :doc "string")
     General Form:
     (verify-guards name
             :hints        hints
             :otf-flg      otf-flg
             :doc          doc-string)

See Section 8.41 [GUARD], page 305 for a general discussion of guards. In the General Form above, name is the name of a :logic (LOGIC^) function (see Section 8.20 [DEFUN-MODE], page 275) that has not yet had its guard (GUARD^)s verified, each subroutine of which has had its guard (GUARD^)s verified; hints (HINTS^) and otf-flg (OTF-FLG^) are as described in the corresponding :doc (DOC^) entries; and doc-string (DOC-STRING^), if supplied, is a string not beginning with “:Doc-Section”. The three keyword arguments above are all optional. Verifyguards will attempt to prove that the guard (GUARD^) on the named function implies the guard (GUARD^)s of all of the subroutines called in the body of the function. If successful, name is considered to have had its guard (GUARD^)s verified.

If name is one of several functions in a mutually recursive clique, verify-guards will attempt to verify the guard (GUARD^)s of all of the functions.

Because name is not uniquely associated with the verify-guards event (it necessarily names a previously defined function) the documentation (DOCUMENTATION^) string, doc-string (DOC-STRING^), is not stored in the documentation (DOCUMENTATION^) data base. Thus, we actually prohibit doc-string (DOC-STRING^) from having the form of an ACL2 documentation (DOCUMENTATION^) string; see Section 5.5 [DOC-STRING], page 143.

Verify-guards must often be used when the value of a recursive call of a defined function is given as an argument to a subroutine that is guard (GUARD^)ed. An example of such a situation is given below. Suppose app (read “append”) has a guard (GUARD^) requiring its first argument to be a true-listp (TRUE-LISTP^). Consider

     (defun rev (x)
       (declare (xargs :guard (true-listp x)))
       (cond ((endp x) nil)
             (t (app (rev (cdr x)) (list (car x))))))

Observe that the value of a recursive call of rev is being passed into a guard (GUARD^)ed subroutine, app. In order to verify the guard (GUARD^)s of this definition we must show that (rev (cdr x)) produces a true-listp (TRUE-LISTP^), since that is what the guard (GUARD^) of app requires. How do we know that (rev (cdr x)) is a true-listp (TRUE-LISTP^)? The most elegant argument is a two-step one, appealing to the following two lemmas: (1) When x is a truelistp (TRUE-LISTP^), (cdr x) is a true-listp (TRUE-LISTP^). (2) When z is a true-listp (TRUE-LISTP^), (rev z) is a true-listp (TRUE-LISTP^). But the second lemma is a generalized property of rev, the function we are defining. This property could not be stated before rev is defined and so is not known to the theorem prover when rev is defined.

Therefore, we might break the admission of rev into three steps: define rev without addressing its guard (GUARD^) verification, prove some general properties about rev, and then verify the guard (GUARD^)s. This can be done as follows:

     (defun rev (x)
       (declare (xargs :guard (true-listp x)
                       :verify-guards nil))    ; Note this additional xarg.
       (cond ((endp x) nil)
             (t (app (rev (cdr x)) (list (car x))))))

     (defthm true-listp-rev
       (implies (true-listp x2)
                (true-listp (rev x2))))
     (verify-guards rev)

The ACL2 system can actually admit the original definition of rev, verifying the guard (GUARD^)s as part of the defun (DEFUN^) event. The reason is that, in this particular case, the system’s heuristics just happen to hit upon the lemma true-listp-rev. But in many more complicated functions it is necessary for the user to formulate the inductively provable properties before guard (GUARD^) verification is attempted.

6.40 VERIFY-TERMINATION

VERIFY-TERMINATION convert a function from :program mode to :logic mode

     Examples:
     (verify-termination fact)
     (verify-termination
      fact
      (declare (xargs :guard (and (integerp x) (>= x 0)))))
     General Forms:
     (verify-termination fn dcl ... dcl)
     (verify-termination (fn1 dcl ... dcl)
                         (fn2 dcl ... dcl)
                         ...)

where fn and the fni are function symbols having :program (PROGRAM^) mode (see Section 8.20 [DEFUN-MODE], page 275) and all of the dcls are either declare (DECLARE^) forms or documentation (DOCUMENTATION^) strings. The first form above is an abbreviation for

     (verify-termination (fn dcl ... dcl))

so we limit our discussion to the second form. Each of the fni must be in the same clique of mutually recursively defined functions, but not every function in the clique need be among the fni.

Verify-termination attempts to establish the admissibility of the fni. Verify-termination retrieves their definitions, creates modified definitions using the dcls supplied above, and resubmits these definitions. You could avoid using verify-termination by typing the new definitions yourself. So in that sense, verify-termination adds no new functionality. But if you have prototyped your system in :program (PROGRAM^) mode and tested it, you can use verify-termination to resubmit your definitions and change their defun-mode (DEFUN-MODE^)s to :logic (LOGIC^), addings hints (HINTS^) without having to retype or recopy the code. You can also add or modify guard (GUARD^)s at this time.

The defun (DEFUN^) command (COMMAND^) executed by verify-termination is obtained by retrieving the defun (DEFUN^) (or mutual-recursion (MUTUAL-RECURSION^)) command (COMMAND^) that introduced the clique in question and then possibly modifying each definition as follows. Consider a function, fn, in the clique. If fn is not among the fni above, its definition is left unmodified. Otherwise, fn is some fni and we modify its definition by inserting into it the corresponding dcls listed with fni in the arguments to verify-termination. In addition, we throw out from the old declarations in fn the :mode specification and anything that is specified in the new dcls.

For example, suppose that fact was introduced with:

     (defun fact (n)
       (declare (type integer n)
                (xargs :mode :program))
       (if (zp n) 1 (* n (fact (1- n))))).

Suppose later we do (verify-termination fact). Then the following definition is submitted.

     (defun fact (n)
       (declare (type integer n))
       (if (zp n) 1 (* n (fact (1- n))))).

Observe that this is the same definition as the original one, except the old specification of the :mode has been deleted so that the defun-mode (DEFUN-MODE^) now defaults to :logic (LOGIC^). Although the termination proof succeeds, ACL2 also tries to verify the guard (GUARD^), because we have (implicitly) provided a guard (GUARD^), namely (integerp n), for this function. (See Section 8.41 [GUARD], page 305 for a general discussion of guards, and see Section 10.252 [TYPE-SPEC], page 543 for a discussion of how type declarations are used in guards.) Unfortunately, the guard (GUARD^) verification fails, because the subterm (zp n) requires that n be nonnegative, as can be seen by invoking :args zp. (For a discussion of termination issues relating to recursion on the naturals, see Section 10.259 [ZERO-TEST-IDIOMS], page 547.) So we might want to submit

     (verify-termination
      fact

      (declare (xargs :guard (and (integerp n) (<= 0 n)))))

which will submit the definition

     (defun fact (n)
       (declare (xargs :guard (and (integerp n) (<= 0 n))))
       (if (zp n) 1 (* n (fact (1- n))))).

Observe that the declaration in the verify-termination command (COMMAND^) has been inserted into the definition. In fact, this command (COMMAND^) succeeds.

7 HISTORY

HISTORY functions that display or change history

* OOPS:: undo a :u or :ubt (UBT^)

* PBT:: print the command (COMMAND^)s back through a command (COMMAND^) descriptor

* PC:: print the command (COMMAND^) described by a command (COMMAND^) descriptor

* PCB:: print the command (COMMAND^) block described by a command (COMMAND^) descriptor

* PCB!:: print in full the command (COMMAND^) block described by a command (COMMAND^) descriptor * PCS:: print the sequence of command (COMMAND^)s between two command (COMMAND^) descriptors * PE:: print the event named by a logical name

* PE!:: print all the events (EVENTS^) named by a logical name

* PF:: print the formula corresponding to the given name

* PL:: print the rules whose top function symbol is the given name

* PR:: print the rules stored by the event with the given name

* PR!:: print rules stored by the command with a given command descriptor

* PUFF:: replace a compound command (COMMAND^) by its immediate subevents

* PUFF*:: replace a compound command (COMMAND^) by its subevents

* U:: undo last command (COMMAND^), without a query

* UBT:: undo the command (COMMAND^)s back through a command (COMMAND^) descriptor

* UBT!:: undo command (COMMAND^)s, without a query or an error

ACL2 keeps track of the command (COMMAND^)s that you have executed that have extended the logic or the rule data base, as by the definition of macros, functions, etc. Using the facilities in this section you can review the sequence of command (COMMAND^)s executed so far. For example, you can ask to see the most recently executed command (COMMAND^), or the command (COMMAND^) 10 before that, or the command (COMMAND^) that introduced a given function symbol. You can also undo back through some previous command (COMMAND^), restoring the logical world (WORLD^) to what it was before the given command (COMMAND^).

The annotations printed in the margin in response to some of these commands (such as ‘P’, ‘L’, and ‘V’) are explained in the documentation for :pc (PC^).

Several technical terms are used in the documentation of the history command (COMMAND^)s. You must understand these terms to use the command (COMMAND^)s. These terms are documented via :doc (DOC^) entries of their own. See Section 8.11 [COMMAND], page 261, see Chapter 6 [EVENTS], page 161, see Section 8.12 [COMMAND-DESCRIPTOR], page 261, and see Section 8.63 [LOGICAL-NAME], page 346.

7.1 OOPS

OOPS undo a :u or :ubt (UBT^)

The keyword command (COMMAND^) :oops will undo the most recent :ubt (UBT^) (or :u, which we here consider just another :ubt (UBT^)). A second :oops will undo the next most recent :ubt (UBT^), a third will undo the :ubt (UBT^) before that one, and a fourth :oops will return the logical world (WORLD^) to its configuration before the first :oops.

Consider the logical world (see Section 8.100 [WORLD], page 399) that represents the current extension of the logic and ACL2’s rules for dealing with it. The :ubt (UBT^) and :u command (COMMAND^)s “roll back” to some previous world (WORLD^) (see Section 7.16 [UBT], page 230). Sometimes these command (COMMAND^)s are used to inadvertently undo useful work and user’s wish they could “undo the last undo.” That is the function provided by :oops.

:Oops is best described in terms of an implementation. Imagine a ring of four world (WORLD^)s and a marker (*) indicating the current ACL2 world (WORLD^):

                  *
                w0
              /    \
            w3      w1
              \    /
                w2

This is called the “kill ring” and it is maintained as follows. When you execute an event the current world (WORLD^) is extended and the kill ring is not otherwise affected. When you execute :ubt (UBT^) or :u, the current world (WORLD^) marker is moved one step counterclockwise and that world (WORLD^) in the ring is replaced by the result, say w0', of the :ubt (UBT^) or :u.

                w0
              /    \
           *w0'     w1
              \    /
                w2

If you were to execute events (EVENTS^) at this point, w0' would be extended and no other changes would occur in the kill ring.

When you execute :oops, the marker is moved one step clockwise. Thus the kill ring becomes * w0 / \ w0' w1 \ / w2 and the current ACL2 world (WORLD^) is w0 once again. That is, :oops “undoes” the :ubt (UBT^) that produced w0' from w0. Similarly, a second :oops will move the marker to w1, undoing the undo that produced w0 from w1. A third :oops makes w2 the current world (WORLD^). Note however that a fourth :oops restores us to the configuration above.

In general, the kill ring contains the current world (WORLD^) and the three most recent world (WORLD^)s in which a :ubt (UBT^) or :u were done.

While :ubt (UBT^) may appear to discard the information in the events (EVENTS^) undone, we can see that the world (WORLD^) in which the :ubt (UBT^) occurred is still available. No information has been lost about that world (WORLD^). But :ubt (UBT^) does discard information! :Ubt (UBT^) discards the information necessary to recover from the third most recent ubt (UBT^)! An :oops, on the other hand, discards no information, it just selects the next available world (WORLD^) on the kill ring and doing enough :oopses will return you to your starting point.

We can put this another way. You can freely type :oops and inspect the world (WORLD^) that you thus obtain with :pe (PE^), :pc (PC^), and other history (HISTORY^) command (COM-MAND^)s. You can repeat this as often as you wish without risking the permanent loss of any information. But you must be more careful typing :ubt (UBT^) or :u. While :oops makes :ubt (UBT^) seem “safe” because the most recent :ubt (UBT^) can always be undone, information is lost when you execute :ubt (UBT^).

7.2 PBT

PBT print the command (COMMAND^)s back through a command (COMMAND^) descriptor

     Examples:
     :pbt :max      ; print back through the most recent command
     :pbt :x        ; print back through the most recent command
     :pbt fn        ; print back through the introduction of fn
     :pbt 5         ; print back through the fifth command executed
     :pbt (:x -4)   ; print back through the most recent five commands

See Section 8.12 [COMMAND-DESCRIPTOR], page 261.

Pbt takes one argument, a command (COMMAND^) descriptor, and prints the command (COM-MAND^)s from :max (MAX^) (aka :x) through the one described. See Section 8.12 [COMMAND-DESCRIPTOR], page 261 for a description of what a command (COMMAND^) descriptor is. See Section 7.3 [PC], page 218 for a description of the format used to display command (COMMAND^)s. Pbt will print the command (COMMAND^)s that ubt (UBT^) will undo.

7.3 PC

PC print the command (COMMAND^) described by a command (COMMAND^) descriptor

     Examples:
     :pc 3    ; print the third command executed
     :pc :max ; print the most recent command
     :pc :x   ; print the most recent command
     :pc fn   ; print the command that introduced fn

See Section 8.12 [COMMAND-DESCRIPTOR], page 261.

Pc takes one argument, a command (COMMAND^) descriptor, and prints the command (COM-MAND^) identified by that descriptor. See Section 8.12 [COMMAND-DESCRIPTOR], page 261. For example

     ACL2 !>:pc foo
      LVd     52 (DEFUN FOO (X) X)

Pc always prints a space first, followed by three (possibly blank) characters (CHARACTERS^) (“LVd” above) explained below. Then pc prints the command (COMMAND^) number, a number uniquely identifying the command (COMMAND^)’s position in the sequence of command (COM-MAND^)s since the beginning of the user’s session. Finally, the command (COMMAND^) itself is printed.

While pc always prints a space first, some history (HISTORY^) command (COMMAND^)s, for example :pcs (PCS^) and :pe (PE^), use the first column of output to delimit a region of command (COMMAND^)s or to point to a particular event within a command (COMMAND^).

For example, :pcs 52 54 will print something like

     /LVd     52 (DEFUN FOO (X) X)
      LV      53 (DEFUN BAR (X) (CONS X X))
     \        54 (DEFTHM FOO-BAR (EQUAL (CAR (BAR X)) (FOO X)))
               : ...
             127 (DEFUN LATEST (X) X)

Here, the two slash characters (CHARACTERS^) in the first column are intended to suggest a bracket delimiting command (COMMAND^)s 52 through 54. The last command (COMMAND^) printed by pcs (PCS^) is always the most recent command (COMMAND^), i.e., the command (COMMAND^) at :here, and is separated from the rest of the display by an elipsis if some command (COMMAND^)s are omitted.

Similarly, the :pe (PE^) command (COMMAND^) will print a particular event within a command (COMMAND^) block and will indicate that event by printing a “> (>^)” in the first column. The symbol is intended to be an arrow pointing at the event in question.

For example, :pe (PE^) true-listp-app might print:

              1 (INCLUDE-BOOK "list-book")
                 \
     >           (DEFTHM TRUE-LISTP-APP
                         (EQUAL (TRUE-LISTP (APP A B)) (TRUE-LISTP B)))

using the arrow to indicate the event itself. The slash printed to connect the command (COM-MAND^), include-book (INCLUDE-BOOK^), with the event, defthm (DEFTHM^), is intended to suggest a tree branch indicating that the event is inferior to (and part of) the command (COM-MAND^).

The mysterious three characters (CHARACTERS^) sometimes preceding a command (COM-MAND^) have the following interpretations. The first two have to do with the function symbols introduced by the command (COMMAND^) and are blank if no symbols were introduced.

At any time we can classify our function symbols into three disjoint sets, which we will here name with characters (CHARACTERS^). The “P” functions are those in :program (PROGRAM^) mode. The “L” functions are those in :logic (LOGIC^) mode whose guard (GUARD^)s have not been verified. The “V” functions are those in :logic (LOGIC^) mode whose guard (GUARD^)s have been verified. Note that verify-termination (VERIFY-TERMINATION^) and verify-guards (VERIFY-GUARDS^) cause function symbols to be reclassified. If a command (COMMAND^) introduces function symbols then the first mysterious character indicates the class of the symbols at the time of introduction and the second character indicates the current class of the symbols (if the current class is different from the introductory class).

Thus, the display

      PLd     52 (DEFUN FOO (X) X)

tells us that command (COMMAND^) 52 introduced a :program (PROGRAM^) function but that some command (COMMAND^) after 52 changed its mode to :logic (LOGIC^) and that the guard (GUARD^)s of foo have not been verified. That is, foo’s termination has been verified even though it was not verified as part of the command (COMMAND^) that introduced foo. Had a subsequent command (COMMAND^) verified the guard (GUARD^)s of foo, the display would contain a V where the L is.

The display

      P d     52 (DEFUN FOO (X) X)

indicates that foo was introduced in :program (PROGRAM^) mode and still is in that mode.

The third character indicates the enabled/disabled status of the rune (RUNE^)s introduced by the command (COMMAND^). If the status character is blank then all the rune (RUNE^)s (if any) introduced are enable (ENABLE^)d. If the status character is “D” then some rune (RUNE^)s were introduced and they are all disable (DISABLE^)d. If the status character is “d” then at least one, but not all, of the rune (RUNE^)s introduced is disable (DISABLE^)d. Thus, in the display

      L d     52 (DEFUN FOO (X) X)

we see that some rune (RUNE^) introduced by command (COMMAND^) 52 is disable (DIS-ABLE^)d. As noted in the documentation for rune (RUNE^), a defun (DEFUN^) command (COMMAND^) introduces many rune (RUNE^)s, e.g., the axiomatic definition rule, (:definition fn), the executable counterpart rule, (:executable-counterpart fn), and type-prescription (TYPE-PRESCRIPTION^)s, (:type-prescription fn). The display above does not say which of the rune (RUNE^)s based on foo is disable (DISABLE^)d, but it does tell us one of them is.

7.4 PCB

PCB print the command (COMMAND^) block described by a command (COMMAND^) descriptor

     Examples:
     :pcb :max ; print the most recent command block
     :pcb :x   ; print the most recent command block
     :pcb fn   ; print the command block that introduced fn
     :pcb 5    ; print the fifth command block

See Section 8.12 [COMMAND-DESCRIPTOR], page 261.

Pcb takes one argument, a command (COMMAND^) descriptor, and prints the command (COM-MAND^) block of the command (COMMAND^) described. See Section 8.12 [COMMAND-DESCRIPTOR], page 261 for details of command (COMMAND^) descriptors. See Section 7.3 [PC], page 218 for description of the format in which command (COMMAND^)s are displayed. The command (COMMAND^) block of a command (COMMAND^) consists of the command (COM-MAND^) itself and all of the events (EVENTS^) it created. If the command (COMMAND^) created a single event and that event is in fact the command (COMMAND^) (i.e., if the command (COMMAND^) typed was just an event such as a defun (DEFUN^) or defthm (DEFTHM^) rather than a macro that expanded to some event forms), then pcb just prints the command (COMMAND^). Pcb sketches command (COMMAND^) and all of the events (EVENTS^) it created, rather than printing them fully. If you wish to see just the command (COMMAND^), in its entirety, use pc (PC^). If you wish to see one of the events (EVENTS^) within the block, in its entirety, use pe (PE^). If you wish to see the command (COMMAND^) sketched and all of the events (EVENTS^) it created, in their entirety, use pcb! (PCB!^).

7.5 PCB!

PCB! print in full the command (COMMAND^) block described by a command (COMMAND^) descriptor

     Examples:
     :pcb! :max ; print the most recent command block
     :pcb! :x   ; print the most recent command block
     :pcb! fn   ; print the command block that introduced fn
     :pcb! 5    ; print the fifth command block

See Section 8.12 [COMMAND-DESCRIPTOR], page 261.

Pcb! takes one argument, a command (COMMAND^) descriptor, and prints the command (COM-MAND^) block of the command (COMMAND^) described. Unlike pcb (PCB^), pcb! prints the event forms in full; see Section 7.4 [PCB], page 220 for details.

7.6 PCS

PCS print the sequence of command (COMMAND^)s between two command (COMMAND^) descriptors

     Examples:
     :pcs 1 5              ; print commands 1 through 5
     :pcs 5 1              ; same as above

     :pcs :x (:x -3)       ; print the 3 most recently executed commands
     :pcs fn assoc-of-fn   ; print the commands between the one that introduced
                           ; fn and the one that introduced assoc-of-fn

Pcs takes two arguments, both of which are command (COMMAND^) descriptors, and prints the command (COMMAND^)s between them with pc (PC^). The order of the two descriptors is irrelevant. See Section 8.12 [COMMAND-DESCRIPTOR], page 261 for a description of command (COMMAND^) descriptors. See Section 7.3 [PC], page 218 for a description of the format in which command (COMMAND^)s are displayed.

7.7 PE

PE print the event named by a logical name

     Example:
     :pe fn   ; sketches the command that introduced fn and
              ; prints in full the event within it that created fn.

See Section 8.63 [LOGICAL-NAME], page 346.

Pe takes one argument, a logical name, and prints in full the most recent event corresponding to the name. Pe also sketches the command (COMMAND^) responsible for that event if the command (COMMAND^) is different from the event itself. See Section 7.3 [PC], page 218 for a description of the format used to display a command (COMMAND^). To remind you that the event is inferior to the command (COMMAND^), i.e., you can only undo the entire command (COMMAND^), not just the event, the event is indented slightly from the command (COMMAND^) and a slash (meant to suggest a tree branch) connects them.

Use pe! (PE!^) if you want all events (EVENTS^) corresponding to a given name; see Section 7.8 [PE!], page 222.

7.8 PE!

PE! print all the events (EVENTS^) named by a logical name

     Examples:
     :pe! name ; prints each event that corresponds to name.

Pe! takes one argument, a logical name other than :here, and prints in full all the events (EVENTS^) for that name. Pe! also sketches the command (COMMAND^) responsible for that event in each case that the command (COMMAND^) is different from the event itself. See Section 7.3 [PC], page 218 for a description of the format used to display a command (COMMAND^). To remind you that the event is inferior to the command (COMMAND^), i.e., you can only undo the entire command (COMMAND^), not just the event, the event is indented slightly from the command (COMMAND^) and a slash (meant to suggest a tree branch) connects them.

Use pe (PE^) if you want only the latest event corresponding to a given name, or if you want to use the logical name :here; see Section 7.7 [PE], page 222.

7.9 PF

PF print the formula corresponding to the given name

     Examples:
     :pf (:definition fn) ; prints the definition of fn as an equality
     :pf fn               ; same as above
     :pf (:rewrite foo)   ; prints the statement of the rewrite rule foo
     :pf foo              ; same as above

pf takes one argument, an event name or a rune (RUNE^), and prints the formula associated with name.

7.10 PL

PL print the rules whose top function symbol is the given name

     Examples:
     :pl foo ; prints the rewrite rules that rewrite some call of foo

Pl takes one argument, a function symbol, and displays the lemmas that rewrite some term whose top function symbol is the given one. Note that names of macros are not relevant here; for example, for the rules about + (+^) you should give the command :pl binary-+ (BINARY-+^).

In fact the kinds of rules printed by :pl are rewrite rules, definition rules, and meta (META^) rules.

7.11 PR

PR print the rules stored by the event with the given name

     Examples:
     :pr fn ; prints the rules from the definition of fn (including any
            ; :type-prescription rule and :definition rule)
     :pr assoc-append ; if assoc-append is a rewrite rule, prints that rule

Also see Section 7.12 [PR!], page 224, which is similar but works at the command level instead of at the event level.

Pr takes one argument, a logical name, and prints the rules associated with it. In each case it prints the rune, the current enabled/disabled status, and other appropriate fields from the rule. It may be helpful to read the documentation for various kinds of rules in order to understand the information printed by this command. For example, the information printed for a linear rule might be:

       Rune:     (:LINEAR ABC)
       Status:   Enabled
       Hyps:     ((CONSP X))
       Concl:    (< (ACL2-COUNT (CAR X)) (ACL2-COUNT X))
       Max-term: (ACL2-COUNT (CAR X))
       Fixer:    NIL

The hyps and concl fields for this rule are fairly self-explanatory, but it is useful to see Section 15.10 [LINEAR], page 749 to learn about maximal terms (which, as one might guess, are stored under “Max-term”). In order to learn about the “Fixer” one has to know to see Section 15.11 [LINEAR-ALIAS], page 753, which is quite unreasonable. The state of this documentation will surely improve.

Currently, this function does not print congruence rules or equivalence rules.

The expert user might also wish to use find-rules-of-rune (FIND-RULES-OF-RUNE^). See Section 8.36 [FIND-RULES-OF-RUNE], page 296.

7.12 PR!

PR! print rules stored by the command with a given command descriptor

     Examples:
     :pr! fn ; prints the rules from the definition of fn (including any
             ; :type-prescription rule and :definition rule), as well as all other
             ; rules created by the command that created by fn (which could be
             ; many rules if, for example, fn was defined by an include-book
             ; command).
     :pr! :max ; prints all the rules stored by the most recent command

Also see Section 7.11 [PR], page 224, which is similar but works at the event level instead of at the command level.

Pr (PR^) takes one argument, a command descriptor, and prints the rules created by the corresponding event. In each case it prints the rune, the current enabled/disabled status, and other appropriate fields from the rule. See Section 7.11 [PR], page 224 for further details.

7.13 PUFF

PUFF replace a compound command (COMMAND^) by its immediate subevents

     Example Forms:
     ACL2 !>:puff :max
     ACL2 !>:puff :x
     ACL2 !>:puff 15
     ACL2 !>:puff "book"
     General Form:
     :puff cd

where cd is a command (COMMAND^) descriptor (see Section 8.12 [COMMAND-DESCRIPTOR], page 261) for a “puffable” command (COMMAND^) (see below). Puff replaces the command (COMMAND^) at cd by the immediate subevents of the command (COMMAND^), executed as command (COMMAND^)s. Puff then prints, using pcs (PCS^), the puffed region.

A command (COMMAND^) is “puffable” if it is an encapsulate (ENCAPSULATE^) command (COMMAND^), an include-book (INCLUDE-BOOK^) command (COMMAND^), or any command (COMMAND^) other than those consisting of a single primitive event. For example, since defun (DEFUN^) is a primitive event, a defun (DEFUN^) command (COMMAND^) is not puffable. But a macro form that expands into several defun (DEFUN^) events (EVENTS^) is puffable.

The only primitive event command (COMMAND^)s that are puffable are encapsulate (ENCAP-SULATE^) and include-book (INCLUDE-BOOK^) command (COMMAND^)s. A puffable command (COMMAND^) contains (interesting) subevents, namely, the events (EVENTS^) in the body of the encapsulate (ENCAPSULATE^), in the file of the book included, or in the command (COMMAND^) block.

The puff command (COMMAND^) “lifts” the immediate subevents of the indicated command (COMMAND^) so that they become command (COMMAND^)s themselves. The command (COM-MAND^) puff* (PUFF*^) recursively puffs the newly introduced command (COMMAND^)s. See Section 7.14 [PUFF*], page 228, which also gives an example illustrating both puff and puff* (PUFF*^). Puff undoes the command (COMMAND^) at cd and replaces it by its immediate subevents. Thus, in general the length of the history (HISTORY^) grows when a puff command (COMMAND^) is executed. If puff causes an error (see below), the logical world (WORLD^) remains unchanged from its initial configuration.

The intended use of puff is to allow the user access to the events (EVENTS^) “hidden” inside compound command (COMMAND^)s. For example, while trying to prove some theorem, p, about a constrained function, fn, one might find that the encapsulate (ENCAPSULATE^), cd, that introduced fn failed to include an important constraint (CONSTRAINT^), q. Without puff, the only way to proceed is to undo back through cd, create a suitable encapsulate (ENCAPSULATE^) that proves and exports q as well as the old constraint (CONSTRAINT^)s, re-execute the new encapsulate (ENCAPSULATE^), re-execute the events (EVENTS^) since cd, and then try p again. Unfortunately, it may be hard to prove q and additional events (EVENTS^) may have to be inserted into the encapsulate (ENCAPSULATE^) to prove it. It may also be hard to formulate the “right” q, i.e., one that is provable in the encapsulate (ENCAPSULATE^) and provides the appropriate facts for use in the proof of p.

Using puff, the user can erase the encapsulate (ENCAPSULATE^) at cd, replacing it by the events (EVENTS^) in its body. Now the formerly constrained function, fn, is defined as its witness. The user can experiment with formulations and proofs of q suitable for p. Of course, to get into the ultimately desired state (STATE^) — where fn is constrained rather than defined and q is exported by an encapsulate (ENCAPSULATE^) at cd — the user must ultimately undo back to cd and carry out the more tedious program described above. But by using puff it is easier to experiment.

Similar applications of puff allow the user of a book to expose the innards of the book as though they had all be typed as command (COMMAND^)s. The user might then “partially undo” the book, keeping only some of the events (EVENTS^) in it.

Puff operates as follows. First, it determines the list of immediate subevents of the command (COMMAND^) indicated by cd. It causes an error if there is only one subevent and that subevent is identical to the command (COMMAND^) — i.e., if the command (COMMAND^) at cd is a primitive. Next, puff undoes back through the indicated command (COMMAND^). This not only erases the command (COMMAND^) at cd but all the command (COMMAND^)s executed after it. Finally, puff re-executes the subevents of (the now erased) cd followed by all the command (COMMAND^)s that were executed afterwards.

Observe that the command (COMMAND^)s executed after cd will generally have higher command (COMMAND^) numbers than they did before the puff. For example, suppose 100 command (COM-MAND^)s have been executed and that :puff 80 is then executed. Suppose command (COM-MAND^) 80 contains 5 immediate subevents (i.e., is an encapsulation of five events (EVENTS^)). Then, after puffing, command (COMMAND^) 80 is the first event of the puffed command (COM-MAND^), command (COMMAND^) 81 is the second, and so on; 104 command (COMMAND^)s appear to have been executed.

When puffing an encapsulate (ENCAPSULATE^) or include-book (INCLUDE-BOOK^), the local (LOCAL^) command (COMMAND^)s are executed. Note that this will replace constrained functions by their witnesses.

Finally, it is impossible to puff in the presence of include-book (INCLUDE-BOOK^) command (COMMAND^)s involving certified files that have been altered since they were included. To be specific, suppose "arith" is a certified book that has been included in a session. Suppose that after "arith" was included, the source file is modified. (This might happen if the user of "arith" is not its author and the author happens to be working on a new version of "arith" during the same time period.) Now suppose the user tries to puff the command (COMMAND^) that included "arith". The attempt to obtain the subevents in "arith" will discover that the check sum of "arith" has changed and an error will be caused. No change is made in the logical world (WORLD^). A similar error is caused if, in this same situation, the user tries to puff any command that occurred before the inclusion of "arith"! That is, puff may cause an error and leave the world (WORLD^) unchanged even if the command (COMMAND^) puffed is not one involving the modified book. This happens because in order to reconstruct the world (WORLD^) after the puffed command (COMMAND^), puff must obtain the events (EVENTS^) in the book and if the book’s source file has changed there is no assurance that the reconstructed world (WORLD^) is the one the user intends.

Warning: We do not detect changes to uncertified books (BOOKS^) that have been included and are then puffed or re-included! The act of including an uncertified book leaves no trace of the check sum of the book. Furthermore, the act prints a warning message disclaiming soundness. In light of this, :puff quietly “re-”executes the current contents of the book.

7.14 PUFF*

PUFF* replace a compound command (COMMAND^) by its subevents

     Example Forms:
     ACL2 !>:puff* :max
     ACL2 !>:puff* :x
     ACL2 !>:puff* 15
     ACL2 !>:puff* "book"
     General Form:
     :puff* cd

where cd is a command (COMMAND^) descriptor (see Section 8.12 [COMMAND-DESCRIPTOR], page 261) for a “puffable” command (COMMAND^). See Section 7.13 [PUFF], page 225 for the definition of “puffable” and for a description of the basic act of “puffing” a command (COM-MAND^). Puff* is just the recursive application of puff (PUFF^). Puff* prints the region puff (PUFF^)ed, using pcs (PCS^).

To puff (PUFF^) a command (COMMAND^) is to replace it by its immediate subevents, each of which is executed as a command (COMMAND^). To puff* a command (COMMAND^) is to replace the command (COMMAND^) by each of its immediate subevents and then to puff* each of the puffable command (COMMAND^)s among the newly introduced ones.

For example, suppose "ab" is a book containing the following

     (in-package "ACL2")
     (include-book "a")
     (include-book "b")

Suppose that book "a" only contained defun (DEFUN^)s for the functions a1 and a2 and that "b" only contained defun (DEFUN^)s for b1 and b2.

Now consider an ACL2 state (STATE^) in which only two command (COMMAND^)s have been executed, the first being (include-book "ab") and the second being (include-book "c"). Thus, the relevant part of the display produced by :pbt (PBT^) 1 would be:

     1 (INCLUDE-BOOK "ab")
     2 (INCLUDE-BOOK "c")

Call this state (STATE^) the “starting state (STATE^)” in this example, because we will refer to it several times.

Suppose :puff 1 is executed in the starting state (STATE^). Then the first command (COM-MAND^) is replaced by its immediate subevents and :pbt 1 would show:

     1 (INCLUDE-BOOK "a")
     2 (INCLUDE-BOOK "b")
     3 (INCLUDE-BOOK "c")

Contrast this with the execution of :puff* 1 in the starting state (STATE^). Puff* would first puff (PUFF^) (include-book "ab") to get the state (STATE^) shown above. But then it would recursively puff* the puffable command (COMMAND^)s introduced by the first puff (PUFF^). This continues recursively as long as any puff (PUFF^) introduced a puffable command (COM-MAND^). The end result of :puff* 1 in the starting state (STATE^) is

     1 (DEFUN A1 ...)
     2 (DEFUN A2 ...)
     3 (DEFUN B1 ...)
     4 (DEFUN B2 ...)
     5 (INCLUDE-BOOK "c")

Observe that when puff* is done, the originally indicated command (COMMAND^), (includebook "ab"), has been replaced by the corresponding sequence of primitive events (EVENTS^). Observe also that puffable command (COMMAND^)s elsewhere in the history (HISTORY^), for example, command (COMMAND^) 2 in the starting state (STATE^), are not affected (except that their command (COMMAND^) numbers grow as a result of the splicing in of earlier command (COMMAND^)s).

7.15 U

U undo last command (COMMAND^), without a query

     Example:
     :u

The keyword command (COMMAND^) :u is the same as :ubt (UBT^) :max (MAX^), but with related queries suppressed appropriately. :Oops (OOPS^) will undo the last :u. See Section 7.16 [UBT], page 230 and see Section 7.17 [UBT!], page 230.

7.16 UBT

UBT undo the command (COMMAND^)s back through a command (COMMAND^) descriptor

     Examples:
     :ubt :max      ; undo back through the most recent command
                    ; (which just means undo the most recent command)
     :ubt :x        ; same as :ubt :max
     :u             ; same as :ubt :max with no questions asked
     :ubt fn        ; undo back through the introduction of fn
                    ; (including all the other events in fn's block)
     :ubt 5         ; undo back through the fifth command executed
     :ubt (:max -4) ; undo back through the most recent five commands
     :ubt (:x -4)   ; undo back through the most recent five commands

See Section 8.12 [COMMAND-DESCRIPTOR], page 261.

ubt takes one argument, a command (COMMAND^) descriptor, and undoes the command (COM-MAND^)s from :max (MAX^) (aka :x) through the one described. See Section 8.12 [COMMAND-DESCRIPTOR], page 261. Pbt (PBT^) will print the command (COMMAND^)s that ubt will undo. :Oops (OOPS^) will undo the undo. See Section 7.1 [OOPS], page 215.

It is important to remember that a command (COMMAND^) may create several events (EVENTS^). That is, the command (COMMAND^) that introduces fn1 may also introduce fn2. Undoing the command (COMMAND^) that created either of these will undo them both. The events (EVENTS^) created by a command (COMMAND^) constitute the command (COMMAND^)’s “block” and we can only undo entire blocks. Use pcb (PCB^) to print the command (COMMAND^) block of a command (COMMAND^) if you wish to see what will be lost by undoing the command (COMMAND^).

Ubt will not undo into “prehistory”. :Ubt 1 will undo all of your command (COMMAND^)s. But :ubt -5 will cause an error, warning you that :ubt cannot undo system initialization.

7.17 UBT!

UBT! undo command (COMMAND^)s, without a query or an error

     Example:
     :ubt! :x-4

The keyword command (COMMAND^) :ubt! is the same as :ubt (UBT^), but with related queries suppressed appropriately, and with a guarantee that it is “error-free.” More precisely, the error triple returned by :ubt! will always have a first component of nil. :Oops (OOPS^) will undo the last :ubt!. See Section 7.16 [UBT], page 230 and see Section 7.15 [U], page 229.

232 ACL2 Version 1.9

8 MISCELLANEOUS

MISCELLANEOUS a miscellany of documented functions and concepts (often cited in more accessible documentation (DOCUMENTATION^))

* ACCUMULATED-PERSISTENCE:: to get statistics on which rune (RUNE^)s are being tried

* ACKNOWLEDGEMENTS:: some contributors to the well-being of ACL2

* ACL2-COUNT:: a commonly used measure for justifying recursion

* ACL2-CUSTOMIZATION:: customizing ACL2 for a particular user

* APROPOS:: searching :doc (DOC^) and :more-doc (MORE-DOC^) text

* ARRAYS:: an introduction to ACL2 arrays.

* BIBLIOGRAPHY:: reports about ACL2

* BREAKS:: Common Lisp breaks

* CHECK-SUM:: assigning “often unique” integers to files and objects

* CLAUSE-IDENTIFIER:: the internal form of a goal-spec (GOAL-SPEC^)

* COMMAND:: forms you type at the top-level, but...

* COMMAND-DESCRIPTOR:: an object describing a particular command (COMMAND^) typed by the user

* COMPUTED-HINTS:: computing advice to the theorem proving process

* CONSTRAINT:: restrictions on certain functions introduced in encapsulate (ENCAPSULATE^) events (EVENTS^)

* COPYRIGHT:: ACL2 copyright, license, sponsorship

* COROLLARY:: the corollary formula of a rune (RUNE^)

* CURRENT-PACKAGE:: the package used for reading and printing

* DEFAULT-DEFUN-MODE:: the default defun-mode (DEFUN-MODE^) of defun (DEFUN^)’d functions

* DEFAULT-PRINT-PROMPT:: the default prompt (PROMPT^) printed by ld (LD^)

* DEFUN-MODE:: determines whether a function definition is a logical act

* DEFUN-MODE-CAVEAT:: functions with defun-mode (DEFUN-MODE^) of :program (PRO-GRAM^) considered unsound

* DEFUNS:: an alternative to mutual-recursion (MUTUAL-RECURSION^)

* DISABLE-FORCING:: to disallow force (FORCE^)d case splits

* DISABLEDP:: determine whether a given name or rune is disabled

* E0-ORD-<:: the well-founded less-than relation on ordinals up to epsilon-0

* E0-ORDINALP:: a recognizer for the ordinals up to epsilon-0

* EMBEDDED-EVENT-FORM:: forms that may be embedded in other events (EVENTS^)

* ENABLE-FORCING:: to allow force (FORCE^)d case splits

* ENTER-BOOT-STRAP-MODE:: The first millisecond of the Big Bang

* ESCAPE-TO-COMMON-LISP:: escaping to Common Lisp

* EVISCERATE-HIDE-TERMS:: to print (hide ...) as <hidden>

* EXECUTABLE-COUNTERPART:: a rule for computing the value of a function

* EXIT-BOOT-STRAP-MODE:: the end of pre-history

* FAILED-FORCING:: how to deal with a proof failure (FAILURE^) in a forcing round

* FAILURE:: how to deal with a proof failure

* FIND-RULES-OF-RUNE:: find the rules named rune

* FORCE:: identity function used to force a case split

* FORCING-ROUND:: a section of a proof dealing with force (FORCE^)d assumptions

* GENERALIZED-BOOLEANS:: potential soundness issues related to ACL2 predicates

* GOAL-SPEC:: to indicate where a hint is to be used

* GUARD:: restricting the domain of a function * HIDE:: hide a term from the rewriter

* HINTS:: advice to the theorem proving process

* I-AM-HERE:: a convenient marker for use with rebuild (REBUILD^)

* IMMEDIATE-FORCE-MODEP:: when executable counterpart is enable (ENABLE^)d, force (FORCE^)d hypotheses are attacked immediately

* IN-PACKAGE:: select current package

* INVISIBLE-FNS-ALIST:: functions that are invisible to the loop-stopper (LOOP-STOPPER^) algorithm * KEYWORD-COMMANDS:: how keyword commands are processed

* LD-ERROR-ACTION:: determines ld (LD^)’s response to an error

* LD-ERROR-TRIPLES:: determines whether a form caused an error during ld (LD^)

* LD-EVISC-TUPLE:: determines whether ld (LD^) suppresses details when printing

* LD-KEYWORD-ALIASES:: allows the abbreviation of some keyword commands

* LD-POST-EVAL-PRINT:: determines whether and how ld (LD^) prints the result of evaluation

* LD-PRE-EVAL-FILTER:: determines which forms ld (LD^) evaluates

* LD-PRE-EVAL-PRINT:: determines whether ld (LD^) prints the forms to be eval’d

* LD-PROMPT:: determines the prompt (PROMPT^) printed by ld (LD^)

* LD-QUERY-CONTROL-ALIST:: how to default answers to queries

* LD-REDEFINITION-ACTION:: to allow redefinition without undoing

* LD-SKIP-PROOFSP:: how carefully ACL2 processes your command (COMMAND^)s

* LD-VERBOSE:: determines whether ld (LD^) prints “ACL2 Loading ...”

* LEMMA-INSTANCE:: an object denoting an instance of a theorem

* LOCAL-INCOMPATIBILITY:: when non-local events (EVENTS^) won’t replay in isolation

* LOGICAL-NAME:: a name created by a logical event

* LOOP-STOPPER:: limit application of permutative rewrite rules

* LP:: the Common Lisp entry to ACL2

* MACRO-ARGS:: the formals list of a macro definition

* NAME:: syntactic rules on logical names

* OBDD:: ordered binary decision diagrams with rewriting

* OTF-FLG:: pushing all the initial subgoals

* PACKAGE-REINCARNATION-IMPORT-RESTRICTIONS:: re-defining undone defpkg (DEFPKG^)s * PRINT-DOC-START-COLUMN:: printing the one-liner

* PROMPT:: the prompt printed by ld (LD^)

* PROOF-OF-WELL-FOUNDEDNESS:: a proof that e0-ord-< (E0-ORD-<^) is well-founded on e0ordinalp (E0-ORDINALP^)s

* PSEUDO-TERMP:: a predicate for recognizing term-like s-expressions

* REDEF:: a common way to set ld-redefinition-action (LD-REDEFINITION-ACTION^)

* REDEF!:: system hacker’s redefinition command (COMMAND^)

* REDEFINED-NAMES:: to collect the names that have been redefined

* REDUNDANT-EVENTS:: allowing a name to be introduced “twice”

* SAVING-AND-RESTORING:: saving and restoring your logical state

* SIGNATURE:: how to specify the arity of a constrained function

* SIMPLE:: :definition (DEFINITION^) and :rewrite (REWRITE^) rules used in preprocessing

* SPECIOUS-SIMPLIFICATION:: nonproductive proof steps

* STATE:: the von Neumannesque ACL2 state object

* SUBVERSIVE-INDUCTIONS:: why we restrict encapsulate (ENCAPSULATE^)d recursive functions * SYNTAX:: the syntax of ACL2 is that of Common Lisp

* SYNTAXP:: to attach a heuristic filter on a :rewrite (REWRITE^) rule

* TERM:: the three senses of well-formed ACL2 expressions or formulas * TERM-ORDER:: the ordering relation on terms used by ACL2

* TTREE:: tag trees

* TYPE-SET:: how type information is encoded in ACL2

* USING-COMPUTED-HINTS:: how to use computed hints

* USING-COMPUTED-HINTS-1:: Driving Home the Basics

* USING-COMPUTED-HINTS-2:: One Hint to Every Top-Level Goal in a Forcing Round

* USING-COMPUTED-HINTS-3:: Hints as a Function of the Goal (not its Name)

* USING-COMPUTED-HINTS-4:: Computing the Hints

* USING-COMPUTED-HINTS-5:: Debugging Computed Hints

* USING-COMPUTED-HINTS-6:: Some Final Comments

* VERSION:: ACL2 Version Number

* WHY-BRR:: an explanation of why ACL2 has an explicit brr (BRR^) mode

* WORLD:: ACL2 property lists and the ACL2 logical data base

* WORMHOLE:: ld (LD^) without state (STATE^) — a short-cut to a parallel universe

* XARGS:: giving hints (HINTS^) to defun (DEFUN^)

Perhaps as the system matures this section will become more structured.

8.1 ACCUMULATED-PERSISTENCE

ACCUMULATED-PERSISTENCE to get statistics on which rune (RUNE^)s are being tried

     Useful Forms:
     (accumulated-persistence t)             ; activate statistics gathering
     (show-accumulated-persistence :frames)  ; display statistics ordered by
     (show-accumulated-persistence :tries)   ; frames built, times tried,
     (show-accumulated-persistence :ratio)   ; or their ratio
     (accumulated-persistence nil)           ; deactivate

Generally speaking, the more ACL2 knows, the slower it runs. That is because the search space grows with the number of alternative rules. Often, the system tries to apply rules that you have forgotten were even there, if you knew about them in the first place! “Accumulated-persistence” is a statistic (originally developed for Nqthm) that helps you identify the rules that are causing ACL2’s search space to explode.

Accumulated persistence tracking can be turned on or off. It is generally off. When on, the system runs about 4 times slower than otherwise! But some useful numbers are collected. When it is turned on, by

     ACL2 !>(accumulated-persistence t)

an accumulation site is initialized and henceforth data about which rules are being tried is accumulated into that site. That accumulated data can be displayed with show-accumulated-persistence, as described in detail below. When accumulated persistence is turned off, with (accumulated-persistence nil), the accumulation site is wiped out and the data in it is lost.

The “accumulated persistence” of a rune (RUNE^) is the number of rune (RUNE^)s the system has attempted to apply (since accumulated persistence was last activated) while the given rune (RUNE^) was being tried.

Consider a :rewrite (REWRITE^) rule named rune (RUNE^). For simplicity, let us imagine that rune (RUNE^) is tried only once in the period during which accumulated persistence is being monitor (MONITOR^)ed. Recall that to apply a rewrite rule we must match the left-hand side of the conclusion to some term we are trying to rewrite, establish the hypotheses of rune (RUNE^) by rewriting, and, if successful, then rewrite the right-hand side of the conclusion. We say rune (RUNE^) is “being tried” from the time we have matched its left-hand side to the time we have either abandoned the attempt or rewritten its right-hand side. During that period of time other rules might be tried, e.g., to establish the hypotheses. The rules tried while rune (RUNE^) is being tried are “billed” to rune (RUNE^) in the sense that they are being considered here only because of the demands of rune (RUNE^). Thus, if no other rules are tried during that period, the accumulated persistence of rune (RUNE^) is 1 — we “bill” rune (RUNE^) once for its own application attempt. If, on the other hand, we tried 10 rules on behalf of that application of rune (RUNE^), then rune (RUNE^)’s accumulated persistence would be 11.

One way to envision accumulated persistence is to imagine that every time a rune (RUNE^) is tried it is pushed onto a stack. The rules tried on behalf of a given application of a rune (RUNE^) are thus pushed and popped on the stack above that rune (RUNE^). A lot of work might be done on its behalf — the stack above the rune (RUNE^) grows and shrinks repeatedly as the search continues for a way to use the rune (RUNE^). All the while, the rune (RUNE^) itself “persists” in the stack, until we finish with the attempt to apply it, at which time we pop it off. The accumulated persistence of a rune (RUNE^) is thus the number of stack frames built while the given rune (RUNE^) was on the stack.

Note that accumulated persistence is not concerned with whether the attempt to apply a rune (RUNE^) is successful. Each of the rules tried on its behalf might have failed and the attempt to apply the rune (RUNE^) might have also failed. The ACL2 proof script would make no mention of the rune (RUNE^) or the rules tried on its behalf because they did not contribute to the proof. But time was spent pursuing the possible application of the rune (RUNE^) and accumulated persistence is a measure of that time.

A high accumulated persistence might come about in two extreme ways. One is that the rule causes a great deal of work every time it is tried. The other is that the rule is “cheap” but is tried very often. We therefore keep track of the number of times each rule is tried as well as its persistence. The ratio between the two is the average amount of work done on behalf of the rule each time it is tried.

When the accumulated persistence totals are displayed by the function show-accumulated-persistence we sort them so that the most expensive rune (RUNE^)s are shown first. We can sort according to one of three keys:

     :frames - the number of frames built on behalf of the rune
     :tries  - the number of times the rune was tried
     :ratio  - frames built per try

The key simply determines the order in which the information is presented. If no argument is

supplied to show-accumulated-persistence, :frames is used.

Note that a rune (RUNE^) with high accumulated persistence may not actually be the “culprit.” For example, suppose rune1 is reported to have a :ratio of 101, meaning that on the average a hundred and one frames were built each time rune1 was tried. Suppose rune2 has a :ratio of 100. It could be that the attempt to apply rune1 resulted in the attempted application of rune2 and no other rune (RUNE^). Thus, in some sense, rune1 is “cheap” and rune2 is the “culprit” even though it costs less than rune1.

Users are encouraged to think about other meters we could install in ACL2 to help diagnose performance problems.

8.2 ACKNOWLEDGEMENTS

ACKNOWLEDGEMENTS some contributors to the well-being of ACL2

The development of ACL2 was made possible by funding from the U. S. Department of Defense, including ARPA and ONR.

ACL2 was started in August, 1989 by Boyer and Moore working together. They co-authored the first versions of axioms.lisp and basis.lisp, with Boyer taking the lead in the formalization of “state (STATE^)” and the most primitive io (IO^) functions. Boyer also had a significant hand in the development of the early versions of the files interface-raw.lisp and translate.lisp. For several years, Moore alone was responsible for developing the ACL2 system code, though he consulted often with both Boyer and Kaufmann. In August, 1993, Kaufmann became jointly responsible with Moore for developing the system. Boyer has continued to provide valuable consulting on an informal basis.

Bishop Brock was the heaviest early user of ACL2, and provided many suggestions for improvements. In particular, the :cases and :restrict hints (HINTS^) were his idea; he developed an early version of congruence-based reasoning for Nqthm; and he helped in the development of some early books (BOOKS^) about arithmetic.

John Cowles also helped in the development of some early books (BOOKS^) about arithmetic, and also provided valuable feedback and bug reports.

Other early users of ACL2 at Computational Logic, Inc. helped influence its development. In particular, Warren Hunt helped with the port to Macintosh Common Lisp, and Art Flatau and Mike Smith provided useful general feedback.

Mike Smith helped develop the Emacs portion of the implementation of proof trees.

Bill Schelter made some enhancements to akcl (now gcl) that helped to enhance ACL2 performance in that Common Lisp implementation, and more generally, responded helpfully to our bug reports.

Kent Pitman helped in our interaction with the ANSI Common Lisp standardization committee, X3J13.

Regarding the documentation:

Bill Young wrote significant portions of the ACL2-TUTORIAL (ACL2-TUTORIAL^) section of the ACL2 documentation, an important task for which we are grateful. He, Bishop Brock, Rich Cohen, and Noah Friedman read over considerable amounts of the documentation, and made many useful comments. Others, particularly Bill Bevier and John Cowles, have also made useful comments on the documentation (DOCUMENTATION^).

Art Flatau helped develop the ACL2 markup (MARKUP^) language and translators from that language to Texinfo and HTML.

Laura Lawless provided many hours of help in marking up appropriate parts of the documentation (DOCUMENTATION^) in typewriter font.

Noah Friedman developed an Emacs tool that helped us insert “invisible links” into the documentation (DOCUMENTATION^), which improve the usability of that documentation under HTML readers such as Mosaic.

Richard Stallman contributed a texinfo patch, to be found in the file doc/texinfo.tex.

8.3 ACL2-COUNT

ACL2-COUNT a commonly used measure for justifying recursion

(Acl2-count x) returns a nonnegative integer that indicates the “size” of its argument x.

All characters (CHARACTERS^) and symbols have acl2-count 0. The acl2-count of a string is the number of characters (CHARACTERS^) in it, i.e., its length. The acl2-count of a cons (CONS^) is one greater than the sum of the acl2-counts of the car (CAR^) and cdr (CDR^). The acl2-count of an integer is its absolute value. The acl2-count of a rational is the sum of the acl2-counts of the numerator and denominator. The acl2-count of a complex rational is one greater than the sum of the acl2-counts of the real and imaginary parts.

8.4 ACL2-CUSTOMIZATION

ACL2-CUSTOMIZATION customizing ACL2 for a particular user

The file "acl2-customization.lisp" is automatically loaded, via ld (LD^), the first time lp (LP^) is called in an ACL2 session, provided such a file exists on the current directory. Except for the fact that this ld (LD^) command is not typed explicitly by you, it is a standard ld (LD^) command, with one exception: any settings of ld (LD^) specials are remembered once this call of ld (LD^) has completed. For example, suppose that you start your customization file with (setld-skip-proofsp t state), so that proofs are skipped as it is loaded with ld (LD^). Then the ld (LD^) special ld-skip-proofsp (LD-SKIP-PROOFSP^) will remain t after the ld (LD^) has completed, causing proofs to be skipped in your ACL2 session, unless your customization file sets

this variable back to nil, say with (set-ld-skip-proofsp nil state).

The customization file "acl2-customization.lisp" actually resides on the connected book directory; see Section 3.4 [CBD], page 102. Except, if that file does not exist, then ACL2 looks for "acl2-customization.lisp" on your home directory. If ACL2 does not find that file either, then no customization occurs and lp (LP^) enters the standard ACL2 read-eval-print loop.

If the customization file exists, it is loaded with ld (LD^) using the usual default values for the ld (LD^) specials (see Section 9.7 [LD], page 416). Thus, if an error is encountered, no subsequent forms in the file will be evaluated.

To create a customization file it is recommended that you first give it a name other than "acl2customization.lisp" so that ACL2 does not try to include it prematurely when you next enter lp (LP^). Then, while in the uncustomized lp (LP^), explicitly invoke ld (LD^) on your evolving (but renamed) customization file until all forms are successfully evaluated. The same procedure is recommended if for some reason ACL2 cannot successfully evaluate all forms in your customization file: rename your customization file so that ACL2 does not try to ld (LD^) it automatically and then debug the new file by explicit calls to ld (LD^).

When you have created a file that can be loaded with ld (LD^) without error and that you wish to be your customization file, name it "acl2-customization.lisp" and put it on the current directory or in your home directory. The first time after starting up ACL2 that you invoke (lp), ACL2 will automatically load the "acl2-customization.lisp" file from the cbd (see Section 3.4 [CBD], page 102) if there is one, and otherwise will load it from your home directory.

Note that if you certify a book after the (automatic) loading of an acl2-customization file, the forms in that file will be part of the portcullis of the books (BOOKS^) you certify! That is, the forms in your customization file at certification time will be loaded whenever anybody uses the books (BOOKS^) you are certifying. Since customization files generally contain idiosyncratic command (COMMAND^)s, you may not want yours to be part of the books (BOOKS^) you create for others. Thus, if you have a customization file then you may want to invoke :ubt 1 before certifying any books (BOOKS^).

The conventions concerning ACL2 customization are liable to change as we get more experience with the interaction between customization, certification of books (BOOKS^) for others, and routine undoing. For example, at the moment it is regarded as a feature of customization that it can be undone but it might be regarded as a bug if you accidentally undo your customization.

8.5 APROPOS

APROPOS searching :doc (DOC^) and :more-doc (MORE-DOC^) text

NOTE: The :docs (DOCS^) command only makes sense at the terminal.

     :Docs "compile" will find all documented topics mentioning the
     string "compile"

When the :docs (DOCS^) command is given a stringp (STRINGP^) argument it searches the text produced by :doc (DOC^) and :more-doc (MORE-DOC^) and lists all the documented topics whose text contains the given string. For purposes of this string matching we ignore distinctions of case and the amount and kind (but not presence) of white space. We also treat hyphen as whitespace.

8.6 ARRAYS

ARRAYS an introduction to ACL2 arrays.

Below we begin a detailed presentation of ACL2 arrays. Related topics:

* AREF1:: access the elements of a 1-dimensional array

* AREF2:: access the elements of a 2-dimensional array

* ARRAY1P:: recognize a 1-dimensional array

* ARRAY2P:: recognize a 2-dimensional array

* ASET1:: set the elements of a 1-dimensional array

* ASET2:: set the elements of a 2-dimensional array

* COMPRESS1:: remove irrelevant pairs from a 1-dimensional array

* COMPRESS2:: remove irrelevant pairs from a 2-dimensional array

* DEFAULT:: return the :default from the header (HEADER^) of a 1- or 2-dimensional array * DIMENSIONS:: return the :dimensions from the header (HEADER^) of a 1- or 2-dimensional array * HEADER:: return the header of a 1- or 2-dimensional array

* MAXIMUM-LENGTH:: return the :maximum-length from the header (HEADER^) of an array * SLOW-ARRAY-WARNING:: a warning issued when arrays (ARRAYS^) are used inefficiently

ACL2 provides relatively efficient 1- and 2-dimensional arrays. Arrays are awkward to provide efficiently in an applicative language because the programmer rightly expects to be able to “modify” an array object with the effect of changing the behavior of the element accessing function on that object. This, of course, does not make any sense in an applicative setting. The element accessing function is, after all, a function, and its behavior on a given object is immutable. To “modify” an array object in an applicative setting we must actually produce a new array object. Arranging for this to be done efficiently is a challenge to the implementors of the language. In addition, the programmer accustomed to the von Neumann view of arrays must learn how to use immutable applicative arrays efficiently.

In this note we explain 1-dimensional arrays. In particular, we explain briefly how to create, access, and “modify” them, how they are implemented, and how to program with them. 2-dimensional arrays are dealt with by analogy.

The Logical Description of ACL2 Arrays

An ACL2 1-dimensional array is an object that associates arbitrary objects with certain integers, called “indices.” Every array has a dimension, dim, which is a positive integer. The indices of an array are the consecutive integers from 0 through dim-1. To obtain the object associated with the index i in an array a, one uses (aref1 name a i). Name is a symbol that is irrelevant to the semantics of aref1 (AREF1^) but affects the speed with which it computes. We will talk more about array “names” later. To produce a new array object that is like a but which associates val with index i, one uses (aset1 name a i val).

An ACL2 1-dimensional array is actually an alist. There is no special ACL2 function for creating arrays; they are generally built with the standard list processing functions list (LIST^) and cons (CONS^). However, there is a special ACL2 function, called compress1 (COMPRESS1^), for speeding up access to the elements of such an alist. We discuss compress1 (COMPRESS1^) later.

One element of the alist must be the “header” of the array. The header (HEADER^) of a 1dimensional array with dimension dim is of the form:

     (:HEADER :DIMENSIONS (dim)
              :MAXIMUM-LENGTH max
              :DEFAULT obj
              :NAME name).

Obj may be any object and is called the “default value” of the array. Max (MAX^) must be an integer greater than dim. Name must be a symbol. The :default (DEFAULT^) and :name entries are optional; if :default (DEFAULT^) is omitted, the default value is nil. The function header (HEADER^), when given a name and a 1- or 2-dimensional array, returns the header (HEADER^) of the array. The functions dimensions (DIMENSIONS^), maximum-length (MAXIMUM-LENGTH^), and default (DEFAULT^) are similar and return the corresponding fields of the header (HEADER^) of the array. The role of the :dimensions (DIMENSIONS^) field is obvious: it specifies the legal indices into the array. The roles played by the :maximum-length (MAXIMUM-LENGTH^) and :default (DEFAULT^) fields are described below.

Aside from the header (HEADER^), the other elements of the alist must each be of the form (i . val), where i is an integer and 0 <= i < dim, and val is an arbitrary object.

(Aref1 name a i) is guard (GUARD^)ed so that name must be a symbol, a must be an array and i must be an index into a. The value of (aref1 name a i) is either (cdr (assoc i a)) or else is the default value of a, depending on whether there is a pair in a whose car (CAR^) is i. Note that name is irrelevant to the value of an aref1 (AREF1^) expression. You might :pe aref1 to see how simple the definition is.

(Aset1 name a i val) is guard (GUARD^)ed analogously to the aref1 (AREF1^) expression. The value of the aset1 (ASET1^) expression is essentially (cons (cons i val) a). Again, name is irrelevant. Note (aset1 name a i val) is an array, a', with the property that (aref1 name a' i) is val and, except for index i, all other indices into a' produce the same value as in a. Note also that if a is viewed as an alist (which it is) the pair “binding” i to its old value is in a' but “covered up” by the new pair. Thus, the length of an array grows by one when aset1 (ASET1^) is done.

Because aset1 (ASET1^) covers old values with new ones, an array produced by a sequence of aset1 (ASET1^) calls may have many irrelevant pairs in it. The function compress1 (COMPRESS1^) removes these irrelevant pairs. Thus, (compress1 name a) returns an array that is equivalent (visa-vis aref1 (AREF1^)) to a but which may be shorter. For technical reasons, the alist returned by compress1 (COMPRESS1^) may also list the pairs in a different order than listed in a.

To prevent arrays from growing excessively long due to repeated aset1 (ASET1^) operations, aset1 (ASET1^) actually calls compress1 (COMPRESS1^) on the new alist whenever the length of the new alist exceeds the :maximum-length (MAXIMUM-LENGTH^) entry, max (MAX^), in the header (HEADER^) of the array. See the definition of aset1 (ASET1^) (for example by using :pe (PE^)). This is primarily just a mechanism for freeing up cons (CONS^) space consumed while doing aset1 (ASET1^) operations.

This completes the logical description of 1-dimensional arrays. 2-dimensional arrays are analogous. The :dimensions (DIMENSIONS^) entry of the header (HEADER^) of a 2-dimensional array should be (dim1 dim2). A pair of indices, i and j, is legal iff 0 <= i < dim1 and 0 <= j < dim2. The :maximum-length (MAXIMUM-LENGTH^) must be greater than dim1*dim2. Aref2 (AREF2^), aset2 (ASET2^), and compress2 (COMPRESS2^) are like their counterparts but take an additional index argument. Finally, the pairs in a 2-dimensional array are of the form ((i .

j) . val).

The Implementation of ACL2 Arrays Very informally speaking, the function compress1 (COMPRESS1^) “creates” an ACL2 array that provides fast access, while the function aref1 (AREF1^) “maintains” fast access. We now describe this informal idea more carefully.

Aref1 (AREF1^) is essentially assoc (ASSOC^). If aref1 (AREF1^) were implemented naively the time taken to access an array element would be linear in the dimension of the array and the number of “assignments” to it (the number of aset1 (ASET1^) calls done to create the array from the initial alist). This is intolerable; arrays are “supposed” to provide constant-time access and change.

The apparently irrelevant names associated with ACL2 arrays allow us to provide constant-time access and change when arrays are used in “conventional” ways. The implementation of arrays makes it clear what we mean by “conventional.”

Recall that array names are symbols. Behind the scenes, ACL2 associates two objects with each ACL2 array name. The first object is called the “semantic value” of the name and is an alist. The second object is called the “raw lisp array” and is a Common Lisp array.

When (compress1 name alist) builds a new alist, a', it sets the semantic value of name to that new alist. Furthermore, it creates a Common Lisp array and writes into it all of the index/value pairs of a', initializing unassigned indices with the default value. This array becomes the raw lisp array of name. Compress1 (COMPRESS1^) then returns a', the semantic value, as its result, as required by the definition of compress1 (COMPRESS1^).

When (aref1 name a i) is invoked, aref1 (AREF1^) first determines whether the semantic value of name is a (i.e., is eq (EQ^) to the alist a). If so, aref1 (AREF1^) can determine the ith element of a by invoking Common Lisp’s aref function on the raw lisp array associated with name. Note that no linear search of the alist a is required; the operation is done in constant time and involves retrieval of two global variables, an eq (EQ^) test and jump, and a raw lisp array access. In fact, an ACL2 array access of this sort is about 5 times slower than a C array access. On the other hand, if name has no semantic value or if it is different from a, then aref1 (AREF1^) determines the answer by linear search of a as suggested by the assoc-like definition of aref1 (AREF1^). Thus, aref1 (AREF1^) always returns the axiomatically specified result. It returns in constant time if the array being accessed is the current semantic value of the name used. The ramifications of this are discussed after we deal with aset1 (ASET1^).

When (aset1 name a i val) is invoked, aset1 (ASET1^) does two cons (CONS^)es to create the new array. Call that array a'. It will be returned as the answer. (In this discussion we ignore the case in which aset1 (ASET1^) does a compress1 (COMPRESS1^).) However, before returning, aset1 (ASET1^) determines if name’s semantic value is a. If so, it makes the new semantic value of name be a' and it smashes the raw lisp array of name with val at index i, before returning a' as the result. Thus, after doing an aset1 (ASET1^) and obtaining a new semantic value a', all aref1 (AREF1^)s on that new array will be fast. Any aref1 (AREF1^)s on the old semantic value, a, will be slow.

To understand the performance implications of this design, consider the chronological sequence in which ACL2 (Common Lisp) evaluates expressions: basically inner-most first, left-to-right, call-by-value. An array use, such as (aref1 name a i), is “fast” (constant-time) if the alist supplied, a, is the value returned by the most recently executed compress1 (COMPRESS1^) or aset1 (ASET1^) on the name supplied. In the functional expression of “conventional” array processing, all uses of an array are fast.

The :name field of the header (HEADER^) of an array is completely irrelevant. Our convention is to store in that field the symbol we mean to use as the name of the raw lisp array. But no ACL2 function inspects :name and its primary value is that it allows the user, by inspecting the semantic value of the array — the alist — to recall the name of the raw array that probably holds that value. We say “probably” since there is no enforcement that the alist was compressed under the name in the header (HEADER^) or that all asets used that name. Such enforcement would be inefficient.

Some Programming Examples

In the following examples we will use ACL2 “global variables” to hold several arrays. See Section 9.1 [@], page 409, and see Section 9.3 [ASSIGN], page 414.

Let the state (STATE^) global variable a be the 1-dimensional compressed array of dimension 5 constructed below.

     ACL2 !>(assign a (compress1 'demo
                                 '((:header :dimensions (5)
                                            :maximum-length 15
                                            :default uninitialized
                                            :name demo)
                                   (0 . zero))))
Then (aref1 'demo (@ a) 0) is zero and (aref1 'demo (@ a) 1) is uninitialized.

Now execute

     ACL2 !>(assign b (aset1 'demo (@ a) 1 'one))

Then (aref1 'demo (@ b) 0) is zero and (aref1 'demo (@ b) 1) is one.

All of the aref1 (AREF1^)s done so far have been “fast.”

Note that we now have two array objects, one in the global variable a and one in the global variable b. B was obtained by assigning to a. That assignment does not affect the alist a because this is an applicative language. Thus, (aref1 'demo (@ a) 1) must still be uninitialized. And if you execute that expression in ACL2 you will see that indeed it is. However, a rather ugly comment is printed, namely that this array access is “slow.” The reason it is slow is that the raw lisp array associated with the name demo is the array we are calling b. To access the elements of a, aref1 (AREF1^) must now do a linear search. Any reference to a as an array is now “unconventional;” in a conventional language like Ada or Common Lisp it would simply be impossible to refer to the value of the array before the assignment that produced our b.

Now let us define a function that counts how many times a given object, x, occurs in an array. For simplicity, we will pass in the name and highest index of the array:

     ACL2 !>(defun cnt (name a i x)
              (declare (xargs :guard
                              (and (array1p name a)
                                   (integerp i)
                                   (>= i -1)
                                   (< i (car (dimensions name a))))
                              :mode :logic
                              :measure (nfix (+ 1 i))))
              (cond ((zp (1+ i)) 0) ; return 0 if i is at most -1
                    ((equal x (aref1 name a i))
                     (1+ (cnt name a (1- i) x)))
                    (t (cnt name a (1- i) x))))

To determine how many times zero appears in (@ b) we can execute:

     ACL2 !>(cnt 'demo (@ b) 4 'zero)

The answer is 1. How many times does uninitialized appear in (@ b)?

     ACL2 !>(cnt 'demo (@ b) 4 'uninitialized)

The answer is 3, because positions 2, 3 and 4 of the array contain that default value.

Now imagine that we want to assign 'two to index 2 and then count how many times the 2nd element of the array occurs in the array. This specification is actually ambiguous. In assigning to b we produce a new array, which we might call c. Do we mean to count the occurrences in c of the 2nd element of b or the 2nd element of c? That is, do we count the occurrences of uninitialized or the occurrences of two? If we mean the former the correct answer is 2 (positions 3 and 4 are uninitialized in c); if we mean the latter, the correct answer is 1 (there is only one occurrence of two in c).

Below are ACL2 renderings of the two meanings, which we call [former] and [latter]. (Warning: Our description of these examples, and of an example [fast former] that follows, assumes that only one of these three examples is actually executed; for example, they are not executed in sequence. See “A Word of Warning” below for more about this issue.)

     (cnt 'demo (aset1 'demo (@ b) 2 'two) 4 (aref1 'demo (@ b) 2))  ; [former]
     (let ((c (aset1 'demo (@ b) 2 'two)))                           ; [latter]
       (cnt 'demo c 4 (aref1 'demo c 2)))

Note that in [former] we create c in the second argument of the call to cnt (although we do not give it a name) and then refer to b in the fourth argument. This is unconventional because the second reference to b in [former] is no longer the semantic value of demo. While ACL2 computes the correct answer, namely 2, the execution of the aref1 (AREF1^) expression in [former] is done slowly.

A conventional rendering with the same meaning is

     (let ((x (aref1 'demo (@ b) 2)))                           ; [fast former]
       (cnt 'demo (aset1 'demo (@ b) 2 'two) 4 x))

which fetches the 2nd element of b before creating c by assignment. It is important to understand that [former] and [fast former] mean exactly the same thing: both count the number of occurrences of uninitialized in c. Both are legal ACL2 and both compute the same answer, 2. Indeed, we can symbolically transform [fast former] into [former] merely by substituting the binding of x for x in the body of the let (LET^). But [fast former] can be evaluated faster than [former] because all of the references to demo use the then-current semantic value of demo, which is b in the first line and c throughout the execution of the cnt in the second line. [Fast former] is the preferred form, both because of its execution speed and its clarity. If you were writing in a conventional language you would have to write something like [fast former] because there is no way to refer to the 2nd element of the old value of b after smashing b unless it had been saved first.

We turn now to [latter]. It is both clear and efficient. It creates c by assignment to b and then it fetches the 2nd element of c, two, and proceeds to count the number of occurrences in c. The answer is 1. [Latter] is a good example of typical ACL2 array manipulation: after the assignment to b that creates c, c is used throughout.

It takes a while to get used to this because most of us have grown accustomed to the peculiar semantics of arrays in conventional languages. For example, in raw lisp we might have written something like the following, treating b as a “global variable”:

     (cnt 'demo (aset 'demo b 2 'two) 4 (aref 'demo b 2))

which sort of resembles [former] but actually has the semantics of [latter] because the b from which aref fetches the 2nd element is not the same b used in the aset! The array b is destroyed by the aset and b henceforth refers to the array produced by the aset, as written more clearly in

[latter].

A Word of Warning: Users must exercise care when experimenting with [former], [latter] and [fast former]. Suppose you have just created b with the assignment shown above,

     ACL2 !>(assign b (aset1 'demo (@ a) 1 'one))

If you then evaluate [former] in ACL2 it will complain that the aref1 (AREF1^) is slow and compute the answer, as discussed. Then suppose you evaluate [latter] in ACL2. From our discussion you might expect it to execute fast — i.e., issue no complaint. But in fact you will find that it complains repeatedly. The problem is that the evaluation of [former] changed the semantic value of demo so that it is no longer b. To try the experiment correctly you must make b be the semantic value of demo again before the next example is evaluated. One way to do that is to execute

     ACL2 !>(assign b (compress1 'demo (@ b)))

before each expression. Because of issues like this it is often hard to experiment with ACL2 arrays at the top-level. We find it easier to write functions that use arrays correctly and efficiently than to so use them interactively.

This last assignment also illustrates a very common use of compress1 (COMPRESS1^). While it was introduced as a means of removing irrelevant pairs from an array built up by repeated assignments, it is actually most useful as a way of insuring fast access to the elements of an array.

Many array processing tasks can be divided into two parts. During the first part the array is built. During the second part the array is used extensively but not modified. If your programming (PROGRAMMING^) task can be so divided, it might be appropriate to construct the array entirely with list processing, thereby saving the cost of maintaining the semantic value of the name while few references are being made. Once the alist has stabilized, it might be worthwhile to treat it as an array by calling compress1 (COMPRESS1^), thereby gaining constant time access to it.

ACL2’s theorem prover uses this technique in connection with its implementation of the notion of whether a rune (RUNE^) is disable (DISABLE^)d or not. Associated with every rune (RUNE^) is a unique integer index, called its “nume.” When each rule is stored, the corresponding nume is stored as a component of the rule. Theories (THEORIES^) are lists of rune (RUNE^)s and membership in the “current theory” indicates that the corresponding rule is enable (ENABLE^)d. But these lists are very long and membership is a linear-time operation. So just before a proof begins we map the list of rune (RUNE^)s in the current theory into an alist that pairs the corresponding numes with t. Then we compress this alist into an array. Thus, given a rule we can obtain its nume (because it is a component) and then determine in constant time whether it is enable (ENABLE^)d. The array is never modified during the proof, i.e., aset1 (ASET1^) is never used in this example. From the logical perspective this code looks quite odd: we have replaced a linear-time membership test with an apparently linear-time assoc (ASSOC^) after going to the trouble of mapping from a list of rune (RUNE^)s to an alist of numes. But because the alist of numes is an array, the “apparently linear-time assoc (ASSOC^)” is more apparent than real; the operation is constant-time.

8.6.1 AREF1

AREF1 access the elements of a 1-dimensional array

     Example Form:
     (aref1 'delta1 a (+ i k))
     General Form:
     (aref1 name alist index)

where name is a symbol, alist is a 1-dimensional array and index is a legal index into alist. This function returns the value associated with index in alist, or else the default value of the array. See Section 8.6 [ARRAYS], page 241 for details.

This function executes in virtually constant time if alist is in fact the “semantic value” associated with name (see Section 8.6 [ARRAYS], page 241). When it is not, aref1 must do a linear search through alist. In that case the correct answer is returned but a slow array comment is printed to the comment window. See Section 8.6.13 [SLOW-ARRAY-WARNING], page 255.

8.6.2 AREF2

AREF2 access the elements of a 2-dimensional array

     Example Form:
     (aref2 'delta1 a i j)
     General Form:
     (aref2 name alist i j)

where name is a symbol, alist is a 2-dimensional array and i and j are legal indices into alist. This function returns the value associated with (i . j) in alist, or else the default value of the array. See Section 8.6 [ARRAYS], page 241 for details.

This function executes in virtually constant time if alist is in fact the “semantic value” associated with name (see Section 8.6 [ARRAYS], page 241). When it is not, aref2 must do a linear search through alist. In that case the correct answer is returned but a slow array comment is printed to the comment window. See Section 8.6.13 [SLOW-ARRAY-WARNING], page 255.

8.6.3 ARRAY1P

ARRAY1P recognize a 1-dimensional array

     Example Form:
     (array1p 'delta1 a)
     General Form:
     (array1p name alist)

where name and alist are arbitrary objects. This function returns t if alist is a 1-dimensional ACL2 array. Otherwise it returns nil. The function operates in constant time if alist is the semantic value of name. See Section 8.6 [ARRAYS], page 241.

8.6.4 ARRAY2P

ARRAY2P recognize a 2-dimensional array

     Example Form:
     (array2p 'delta1 a)
     General Form:
     (array2p name alist)

where name and alist are arbitrary objects. This function returns t if alist is a 2-dimensional ACL2 array. Otherwise it returns nil. The function operates in constant time if alist is the semantic value of name. See Section 8.6 [ARRAYS], page 241.

8.6.5 ASET1

ASET1 set the elements of a 1-dimensional array

     Example Form:
     (aset1 'delta1 a (+ i k) 27)
     General Form:
     (aset1 name alist index val)

where name is a symbol, alist is a 1-dimensional array named name, index is a legal index into alist, and val is an arbitrary object. See Section 8.6 [ARRAYS], page 241 for details. Roughly speaking this function “modifies” alist so that the value associated with index is val. More precisely, it returns a new array, alist', of the same name and dimension as alist that, under aref1 (AREF1^), is everywhere equal to alist except at index where the result is val. That

is, (aref1 name alist' i) is (aref1 name alist i) for all legal indices i except index, where
(aref1 name alist' i) is val.

In order to “modify” alist, aset1 cons (CONS^)es a new pair onto the front. If the length of the resulting alist exceeds the :maximum-length (MAXIMUM-LENGTH^) entry in the array header (HEADER^), aset1 compresses the array as with compress1 (COMPRESS1^).

It is generally expected that the “semantic value” of name will be alist (see Section 8.6 [ARRAYS], page 241). This function operates in virtually constant time whether this condition is true or not (unless the compress1 (COMPRESS1^) operation is required). But the value returned by this function cannot be used efficiently by subsequent aset1 operations unless alist is the semantic value of name when aset1 is executed. Thus, if the condition is not true, aset1 prints a slow array warning to the comment window. See Section 8.6.13 [SLOW-ARRAY-WARNING], page 255.

8.6.6 ASET2

ASET2 set the elements of a 2-dimensional array

     Example Form:
     (aset2 'delta1 a i j 27)
     General Form:
     (aset2 name alist i j val)

where name is a symbol, alist is a 2-dimensional array named name, i and j are legal indices into alist, and val is an arbitrary object. See Section 8.6 [ARRAYS], page 241 for details. Roughly speaking this function “modifies” alist so that the value associated with (i . j) is val. More precisely, it returns a new array, alist', of the same name and dimension as alist that, under aref2 (AREF2^), is everywhere equal to alist except at (i . j) where the result is val. That

is, (aref2 name alist' x y) is (aref2 name alist x y) for all legal indices x y except i and
j where (aref2 name alist' i j) is val.

In order to “modify” alist, aset2 cons (CONS^)es a new pair onto the front. If the length of the resulting alist exceeds the :maximum-length (MAXIMUM-LENGTH^) entry in the array header (HEADER^), aset2 compresses the array as with compress2 (COMPRESS2^).

It is generally expected that the “semantic value” of name will be alist (see Section 8.6 [ARRAYS], page 241). This function operates in virtually constant time whether this condition is true or not (unless the compress2 (COMPRESS2^) operation is required). But the value returned by this function cannot be used efficiently by subsequent aset2 operations unless alist is the semantic value of name when aset2 is executed. Thus, if the condition is not true, aset2 prints a slow array warning to the comment window. See Section 8.6.13 [SLOW-ARRAY-WARNING], page 255.

8.6.7 COMPRESS1

COMPRESS1 remove irrelevant pairs from a 1-dimensional array

     Example Form:
     (compress1 'delta1 a)
     General Form:
     (compress1 name alist)

where name is a symbol and alist is a 1-dimensional array named name. See Section 8.6 [ARRAYS], page 241 for details. Logically speaking, this function removes irrelevant pairs from alist, possibly shortening it. The function returns a new array, alist', of the same name and dimension as alist, that, under aref1 (AREF1^), is everywhere equal to alist. That is, (aref1 name alist' i) is (aref1 name alist i), for all legal indices i. Alist' may be shorter than alist and the nonirrelevant pairs may occur in a different order than in alist.

Practically speaking, this function plays an important role in the efficient implementation of aref1 (AREF1^). In addition to creating the new array, alist', compress1 makes that array the “semantic value” of name and allocates a raw lisp array to name. For each legal index, i, that raw lisp array contains (aref1 name alist' i) in slot i. Thus, subsequent aref1 (AREF1^) operations can be executed in virtually constant time provided they are given name and the alist' returned by the most recently executed compress1 or aset1 (ASET1^) on name. See Section 8.6 [ARRAYS], page 241.

8.6.8 COMPRESS2

COMPRESS2 remove irrelevant pairs from a 2-dimensional array

     Example Form:
     (compress2 'delta1 a)
     General Form:
     (compress2 name alist)

where name is a symbol and alist is a 2-dimensional array named name. See Section 8.6 [ARRAYS], page 241 for details. Logically speaking, this function removes irrelevant pairs from alist, possibly shortening it. The function returns a new array, alist', of the same name and dimension as alist, that, under aref2 (AREF2^), is everywhere equal to alist. That is, (aref2 name alist' i j) is (aref2 name alist i j), for all legal indices i and j. Alist' may be shorter than alist and the non-irrelevant pairs may occur in a different order in alist' than in alist.

Practically speaking, this function plays an important role in the efficient implementation of aref2 (AREF2^). In addition to creating the new array, alist', compress2 makes that array the “semantic value” of name and allocates a raw lisp array to name. For all legal indices, i and j, that raw lisp array contains (aref2 name alist' i j) in slot i,j. Thus, subsequent aref2 (AREF2^) operations can be executed in virtually constant time provided they are given name and the alist' returned by the most recently executed compress2 or aset2 (ASET2^) on name. See Section 8.6 [ARRAYS], page 241.

8.6.9 DEFAULT

DEFAULT return the :default from the header (HEADER^) of a 1- or 2-dimensional array

     Example Form:
     (default 'delta1 a)
     General Form:
     (default name alist)

where name is an arbitrary object and alist is a 1- or 2-dimensional array. This function returns the contents of the :default field of the header (HEADER^) of alist. When aref1 (AREF1^) or aref2 (AREF2^) is used to obtain a value for an index (or index pair) not bound in alist, the default value is returned instead. Thus, the array alist may be thought of as having been initialized with the default value. default operates in virtually constant time if alist is the semantic value of name. See Section 8.6 [ARRAYS], page 241.

8.6.10 DIMENSIONS

DIMENSIONS return the :dimensions from the header (HEADER^) of a 1- or 2-dimensional array

     Example Form:
     (dimensions 'delta1 a)
     General Form:
     (dimensions name alist)

where name is arbitrary and alist is a 1- or 2-dimensional array. This function returns the dimensions list of the array alist. That list will either be of the form (dim1) or (dim1 dim2), depending on whether alist is a 1- or 2-dimensional array. Dim1 and dim2 will be integers and each exceed by 1 the maximum legal corresponding index. Thus, if dimensions returns, say, '(100) for an array

a named 'delta1, then (aref1 'delta1 a 99) is legal but (aref1 'delta1 a 100) violates the

guard (GUARD^)s on aref1 (AREF1^). Dimensions operates in virtually constant time if alist is the semantic value of name. See Section 8.6 [ARRAYS], page 241.

8.6.11 HEADER

HEADER return the header of a 1- or 2-dimensional array

     Example Form:
     (header 'delta1 a)
     General Form:
     (header name alist)

where name is arbitrary and alist is a 1- or 2-dimensional array. This function returns the header of the array alist. The function operates in virtually constant time if alist is the semantic value of name. See Section 8.6 [ARRAYS], page 241.

8.6.12 MAXIMUM-LENGTH

MAXIMUM-LENGTH return the :maximum-length from the header (HEADER^) of an array

     Example Form:
     (maximum-length 'delta1 a)
     General Form:
     (maximum-length name alist)

where name is an arbitrary object and alist is a 1- or 2-dimensional array. This function returns the contents of the :maximum-length field of the header (HEADER^) of alist. Whenever an aset1 (ASET1^) or aset2 (ASET2^) would cause the length of the alist to exceed its maximum length, a compress1 (COMPRESS1^) or compress2 (COMPRESS2^) is done automatically to remove irrelevant pairs from the array. Maximum-length operates in virtually constant time if alist is the semantic value of name. See Section 8.6 [ARRAYS], page 241.

8.6.13 SLOW-ARRAY-WARNING

SLOW-ARRAY-WARNING a warning issued when arrays (ARRAYS^) are used inefficiently

If you use ACL2 arrays (ARRAYS^) you may sometimes see a slow array warning. We here explain what that warning means and some likely “mistakes” it may signify.

The discussion in the documentation for arrays (ARRAYS^) defines what we mean by the semantic value of a name. As noted there, behind the scenes ACL2 maintains the invariant that with some names there is associated a pair consisting of an ACL2 array alist, called the semantic value of the name, and an equivalent raw lisp array. Access to ACL2 array elements, as in (aref1 name alist i), is executed in constant time when the array alist is the semantic value of the name, because we can just use the corresponding raw lisp array to obtain the answer. Aset1 (ASET1^) and compress1 (COMPRESS1^) modify the raw lisp array appropriately to maintain the invariant.

If aref1 (AREF1^) is called on a name and alist, and the alist is not the then-current semantic value of the name, the correct result is computed but it requires linear time because the alist must be searched. When this happens, aref1 (AREF1^) prints a slow array warning message to the comment window. Aset1 (ASET1^) behaves similarly because the array it returns will cause the slow array warning every time it is used.

From the purely logical perspective there is nothing “wrong” about such use of arrays (ARRAYS^) and it may be spurious to print a warning message. But because arrays (ARRAYS^) are generally used to achieve efficiency, the slow array warning often means the user’s intentions are not being realized. Sometimes merely performance expectations are not met; but the message may mean that the functional behavior of the program is different than intended.

Here are some “mistakes” that might cause this behavior. In the following we suppose the message was printed by aset1 (ASET1^) about an array named name. Suppose the alist supplied aset1 (ASET1^) is alist.

(1) Compress1 (COMPRESS1^) was never called on name and alist. That is, perhaps you created an alist that is an array1p (ARRAY1P^) and then proceeded to access it with aref1 (AREF1^) but never gave ACL2 the chance to create a raw lisp array for it. After creating an alist that is intended for use as an array, you must do (compress1 name alist) and pass the resulting alist' as the array.

(2) Name is misspelled. Perhaps the array was compressed under the name 'delta-1 but accessed

under 'delta1?

(3) An aset1 (ASET1^) was done to modify alist, producing a new array, alist', but you subsequently used alist as an array. Inspect all (aset1 name ...) occurrences and make sure that the alist modified is never used subsequently (either in that function or any other). It is good practice to adopt the following syntactic style. Suppose the alist you are manipulating is the value of the local variable alist. Suppose at some point in a function definition you wish to modify alist with aset1 (ASET1^). Then write

     (let ((alist (aset1 name alist i val))) ...)

and make sure that the subsequent function body is entirely within the scope of the let (LET^). Any uses of alist subsequently will refer to the new alist and it is impossible to refer to the old alist. Note that if you write

      (foo (let ((alist (aset1 name alist i val))) ...)  ; arg 1
           (bar alist))                                  ; arg 2

you have broken the rules, because in arg 1 you have modified alist but in arg 2 you refer to the old value. An appropriate rewriting is to lift the let (LET^) out:

      (let ((alist (aset1 name alist alist i val)))
        (foo ...                                         ; arg 1
             (bar alist)))                               ; arg 2

Of course, this may not mean the same thing.

(4) A function which takes alist as an argument and modifies it with aset1 (ASET1^) fails to return the modified version. This is really the same as (3) above, but focuses on function interfaces. If a function takes an array alist as an argument and the function uses aset1 (ASET1^) (or a subfunction uses aset1 (ASET1^), etc.), then the function probably “ought” to return the result produced by aset1 (ASET1^). The reasoning is as follows. If the array is passed into the function, then the caller is holding the array. After the function modifies it, the caller’s version of the array is obsolete. If the caller is going to make further use of the array, it must obtain the latest version, i.e., that produced by the function.

8.7 BIBLIOGRAPHY

BIBLIOGRAPHY reports about ACL2

Below is a list of notes and reports pertaining to ACL2.

[km94] M. Kaufmann and J S. Moore. Design Goals for ACL2, CLI Technical Report 101, August 1994. See reports/km94.ps. (Written about a year before ACL2 was first released, this document is now somewhat dated but does provide some perspective on the system, especially with respect to Nqthm.)

[bkm96] B. Brock, M. Kaufmann, and J S. Moore. ACL2 Theorems about Commercial Microprocessors. CLI Technical Report 117. August, 1996. See reports/bkm96.ps. (An overview of ACL2 and its use in two commercial projects, the Motorola CAP chip and the AMD5K86 floating-point division.)

[km97] M. Kaufmann and J S. Moore. An Industrial Strength Theorem Prover for a Logic Based on Common Lisp, IEEE TSE (to appear, 1997) (An early version appeared as “ACL2: An Industrial Strength Version of Nqthm,” in the Proceedings of the Eleventh Annual Conference on Computer Assurance (COMPASS-96), IEEE Computer Society Press, June, 1996, pp 23-34. See reports/km97.ps. (An explanation of our treatment of guards, why we choose to make logical functions total and how guards allow us to compute them via Common Lisp’s partial functions.)

[km97a] M. Kaufmann and J S. Moore. A Precise Description of the ACL2 Logic. See reports/km97a.ps. (The most complete description of the ACL2 logic available. This is a dry mathematical document describing the base logic – not the theorem prover or the system – from first principles. It is a working draft. At the moment it does not include multiple values, property lists, arrays, or STATE.)

[y96a] W. D. Young. Interactive Consistency in ACL2. CLI Technical Report 116. January, 1996 (essentially the same as Proceedings of the Eleventh Annual Conference on Computer Assurance (COMPASS-96), IEEE Computer Society Press, June, 1996, pp 35-45). See reports/y96a.ps. An ACL2 formalization of Rushby’s improvement to Bevier and Young’s Nqthm formalization of Pease, Shostak and Lamport’s Oral Messages (“Byzantine Generals) algorithm.

[y96b] W. D. Young. The Specification of a Simple Autopilot in ACL2. CLI Internal Note 327. July, 1996. See reports/y96b.ps. An ACL2 treatment of Butler’s autopilot example.

[bm96] R. S. Boyer and J S. Moore. Mechanized Formal Reasoning about Programs and Computing Machines. CLI Technical Report 119. August, 1996. See reports/bm96.ps. An explanation of how programming languages and computing machines are formalized in ACL2 in a way that enables mechanized reasoning and which has been shown to “scale up.”

M. Kaufmann. High-level Correctness of ACL2: A Story. See reports/story.txt. An explanation of the logical meaning of ACL2’s “worlds” with particular attention paid to the semantics of encapsulation and local events.

8.8 BREAKS

BREAKS Common Lisp breaks

     Example:
     Broken at PROVE.  Type :H for Help.
     >>:Q
     ACL2 !>

If a break occurs, e.g. because of a bug in ACL2 or a user interrupt, the break will run a Common Lisp read-eval-print loop, not an ACL2 read-eval-print loop. This may not be obvious if the prompt (PROMPT^)s in the two loops are similar. Because you are typing to a Common Lisp evaluator, you must be careful. It is possible to damage your ACL2 state in irreparable ways by executing non-ACL2 Common Lisp. It is even possible to disrupt and render inaccurate the interrupted evaluation of a simple ACL2 expression.

Quitting from the break (as with :q (Q^) in AKCL) will return to the innermost ACL2 read-eval-print loop. Before the loop is continued, any pending cleanup forms from acl2-unwind-protects are evaluated (unless acl2::*acl2-panic-exit-flg* is non-nil, in which case no cleanup is done).

If at any time you type the token #. to either a raw lisp break or to the ACL2 read-eval-print loop, an abort is executed. Control is passed to the outermost ACL2 read-eval-print loop (lp). Again, unwind-protection cleanup forms are executed first.

8.9 CHECK-SUM

CHECK-SUM assigning “often unique” integers to files and objects

A “check sum” is an integer in some fixed range computed from the printed representation of an object, e.g., the sum, modulo 2**32, of the ascii codes of all the characters (CHARACTERS^) in the printed representation.

Ideally, you would like the check sum of an object to be uniquely associated with that object, like a fingerprint. It could then be used as a convenient way to recognize the object in the future: you could remember the check sum (which is relatively small) and when an object is presented to you and alleged to be the special one you could compute its check sum and see if indeed it was. Alas, there are many more objects than check sums (after all, each check sum is an object, and then there’s t). So you try to design a check sum algorithm that maps similar looking objects far apart, in the hopes that corruptions and counterfeits — which appear to be similar to the object — have different check sums. Nevertheless, the best you can do is a many-to-one map. If an object with a different check sum is presented, you can be positive it is not the special object. But if an object with the same check sum is presented, you have no grounds for positive identification.

The basic check sum algorithm in ACL2 is called check-sum-obj, which computes the check sum of an ACL2 object. Roughly speaking, we scan the print representation of the object and, for each character encountered, we multiply the ascii code of the character times its position in the stream (modulo a certain prime) and then add (modulo a certain prime) that into the running sum. This is inaccurate in many senses (for example, we don’t always use the ascii code and we see numbers as though they were printed in base 127) but indicates the basic idea.

ACL2 uses check sums to increase security in the books (BOOKS^) mechanism; see Section 3.5 [CERTIFICATE], page 104.

8.10 CLAUSE-IDENTIFIER

CLAUSE-IDENTIFIER the internal form of a goal-spec (GOAL-SPEC^)

To each goal-spec, str, there corresponds a clause-identifier produced by (parse-clause-id str). For example,

     (parse-clause-id "[2]Subgoal *4.5.6/7.8.9'''")
returns ((2 4 5 6) (7 8 9) . 3).
The function string-for-tilde-@-clause-id-phrase inverts parse-clause-id in the sense that

given a clause identifier it returns the corresponding goal-spec.

As noted in the documentation for goal-spec (GOAL-SPEC^), each clause printed in the theorem prover’s proof attempt is identified by a name. When these names are represented as strings they are called “goal specs.” Such strings are used to specify where in the proof attempt a given hint is to be applied. The function parse-clause-id converts goal-specs into clause identifiers, which are cons-trees containing natural numbers.

Examples of goal-specs and their corresponding clause identifiers are shown below.

                  parse-clause-id
                        -->
     "Goal"                       ((0) NIL . 0)
     "Subgoal 3.2.1'"             ((0) (3 2 1) . 1)
     "[2]Subgoal *4.5.6/7.8.9'''" ((2 4 5 6) (7 8 9) . 3)

                        <--
           string-for-tilde-@-clause-id-phrase

The caar of a clause id specifies the forcing round, the cdar specifies the goal being proved by induction, the cadr specifies the particular subgoal, and the cddr is the number of primes in that subgoal.

Internally, the system maintains clause ids, not goal-specs. The system prints clause ids in the form shown by goal-specs. When a goal-spec is used in a hint, it is parsed (before the proof attempt begins) into a clause id. During the proof attempt, the system watches for the clause id and uses the corresponding hint when the id arises. (Because of the expense of creating and garbage collecting a lot of strings, this design is more efficient than the alternative.)

8.11 COMMAND

COMMAND forms you type at the top-level, but...

...the word “command” usually refers to a top-level form whose evaluation produces a new logical world (WORLD^).

     Typical commands are:
     (defun foo (x) (cons x x))
     (defthm consp-foo (consp (foo x)))
     (defrec pair (hd . tl) nil)

The first two forms are examples of commands that are in fact primitive events (EVENTS^). See Chapter 6 [EVENTS], page 161. defrec, on the other hand, is a macro that expands into a progn (PROGN^) of several primitive events (EVENTS^). In general, a world (WORLD^) extending command generates one or more events (EVENTS^).

Both events (EVENTS^) and commands leave landmarks on the world (WORLD^) that enable us to determine how the given world (WORLD^) was created from the previous one. Most of your interactions will occur at the command level, i.e., you type commands, you print previous commands, and you undo back through commands. Commands are denoted by command descriptors. See Section 8.12 [COMMAND-DESCRIPTOR], page 261.

8.12 COMMAND-DESCRIPTOR

COMMAND-DESCRIPTOR an object describing a particular command (COMMAND^) typed by the user

     Examples:
     :max      ; the command most recently typed by the user
     :x        ; synonymous with :max
     (:x -1)   ; the command before the most recent one
     (:x -2)   ; the command before that
     :x-2      ; synonymous with (:x -2)
     5         ; the fifth command typed by the user
     1         ; the first command typed by the user
     0         ; the last command of the system initialization
     -1        ; the next-to-last initialization command
     :min      ; the first command of the initialization
     fn        ; the command that introduced the logical name fn
     (:search (defmacro foo-bar))
               ; the first command encountered in a search from :max to
               ; 0 that either contains defmacro and foo-bar in the
               ; command form or contains defmacro and foo-bar in some
               ; event within its block.

The recorded history (HISTORY^) of your interactions with the top-level ACL2 command (COM-MAND^) loop is marked by the command (COMMAND^)s you typed that changed the logical world (WORLD^). Each such command (COMMAND^) generated one or more events (EVENTS^), since the only way for you to change the logical world (WORLD^) is to execute an event function. See Section 8.11 [COMMAND], page 261 and see Chapter 6 [EVENTS], page 161. We divide history (HISTORY^) into “command (COMMAND^) blocks,” grouping together each world (WORLD^) changing command (COMMAND^) and its events (EVENTS^). A “command (COMMAND^) descriptor” is an object that can be used to describe a particular command (COMMAND^) in the history (HISTORY^) of the ongoing session.

Each command (COMMAND^) is assigned a unique integer called its “command (COMMAND^) number” which indicates the command (COMMAND^)’s position in the chronological ordering of all of the command (COMMAND^)s ever executed in this session (including those executed to initialize the system). We assign the number 1 to the first command (COMMAND^) you type to ACL2. We assign 2 to the second and so on. The non-positive integers are assigned to “prehistoric” command (COMMAND^)s, i.e., the command (COMMAND^)s used to initialize the ACL2 system: 0 is the last command (COMMAND^) of the initialization, -1 is the one before that, etc.

The legal command (COMMAND^) descriptors are described below. We use n to denote any integer, sym to denote any logical name (see Section 8.63 [LOGICAL-NAME], page 346), and cd to denote, recursively, any command (COMMAND^) descriptor.

command                   command
descriptor                described
:max   -- the most recently executed command (i.e., the one with
the largest command number)
:x     -- synonymous with :max
:x-k   -- synonymous with (:x -k), if k is an integer and k>0
:min   -- the earliest command (i.e., the one with the smallest
command number and hence the first command of the system
initialization)
n      -- command number n  (If n is not in the
range :min<=n<=:max, n is replaced by the nearest of :min
and :max.)
sym    -- the command that introduced the logical name sym
(cd n) -- the command whose number is n plus the command number of
the command described by cd
(:search pat cd1 cd2)
In this command descriptor, pat must be either an atom or
a true list of atoms and cd1 and cd2 must be command
descriptors.  We search the interval from cd1 through cd2
for the first command that matches pat.  Note that if cd1
occurs chronologically after cd2, the search is
``backwards'' through history while if cd1 occurs
chronologically before cd2, the search is ``forwards''.  A
backwards search will find the most recent match; a
forward search will find the chronologically earliest
match.  A command matches pat if either the command form
itself or one of the events in the block contains pat (or
all of the atoms in pat if pat is a list).
(:search pat)
the command found by (:search pat :max 0), i.e., the most
recent command matching pat that was part of the user's
session, not part of the system initialization.

8.13 COMPUTED-HINTS

COMPUTED-HINTS computing advice to the theorem proving process

General Form of :hints:
(hint1 hint2 ... hintk)

Each element, hinti, must be either a common hint or a computed hint.

A common hint is of the form

     (goal-spec :key1 val1 ... :keyn valn)

where goal-spec is as specified in goal-spec (GOAL-SPEC^) and each :keyi and vali is as specified in hints (HINTS^).

A computed hint is either a function symbol, fn, of three arguments or is a term involving, at most, the three free variables ID, CLAUSE and WORLD. The function symbol case is treated as an abbreviation of the term (fn ID CLAUSE WORLD). (Note that this tells you which argument is which.) In the discussion below we assume all computed hints are of the term form.

The evaluation of the term (in a context in which its variables are bound as described below) should be either nil, indicating that the hint is not applicable to the clause in question, or else the value is an alternating list of :keyi vali “pairs” as specified in hints (HINTS^). The first applicable hint, if any, is used and deleted from the list of hints available to the descendants of the clause (see below).

The evaluation of a hint term is done with guard checking turned off (see Section 9.12 [SET-GUARD-CHECKING], page 423); e.g., the form (car 23) in a computed hint returns nil as per the axioms.

When a non-nil value is returned it is treated just as though it had been typed as part of the original input. That is, your job as the programmer of computed hints is to generate the form you would have typed had you supplied a common hint at that point. (In particular, any theory expressions in it are evaluated with respect to the global current-theory, not whatever theory is active on the subgoal in question.) If the generated list of keywords and values is illegal, an error will be signaled and the proof attempt will be aborted.

It remains only to describe the bindings of the three variables. Suppose the theorem prover is working on some clause, clause, named by some goal-spec (GOAL-SPEC^), e.g., "Subgoal *1/2”’" in some logical world, world. Corresponding to the printed goal-spec is an internal data structure called a “clause identifier” id. See Section 8.10 [CLAUSE-IDENTIFIER], page 260.

In the case of a common hint, the hint applies if the goal-spec of the hint is the same as the goal-spec of the clause in question.

In the case of a computed hint, the variable ID is bound to the clause id, the variable CLAUSE is bound to the (translated form of the) clause, and the variable WORLD is bound to the current ACL2 world.

When a computed hint applies, it is removed from the list of hints available to the children of the clause to which it applied. This prevents it from being reapplied (often infinitely). The goals produced by induction and the top-level goals of forcing rounds are not considered children; all original hints are available to them. Insert n copies of a computed hint into the :hints to allow the hint to be used “repeatedly” at n different levels.

For some instruction about how to use computed hints, see Section 8.91 [USING-COMPUTED-HINTS], page 386.

8.14 CONSTRAINT

CONSTRAINT restrictions on certain functions introduced in encapsulate (ENCAPSULATE^) events (EVENTS^)

Suppose that a given theorem, thm, is to be functionally instantiated using a given functional substitution, alist, as described in :DOC (DOC^) lemma-instance (LEMMA-INSTANCE^). What is the set of proof obligations generated? It is the set of all terms, tm, such that (a) tm mentions some function symbol in the domain of alist, and (b) either tm arises from the “constraint” on a function symbol ancestral in thm or some defaxiom (DEFAXIOM^) or (ii) tm is the body of a defaxiom (DEFAXIOM^). Here, a function symbol is “ancestral” in thm if either it occurs in thm, or it occurs in the definition of some function symbol that occurs in thm, and so on.

The remainder of this note explains what we mean by “constraint” in the words above.

In a certain sense, function symbols are introduced in essentially two ways. The most common way is to use defun (DEFUN^) (or when there is mutual recursion, mutual-recursion (MUTUAL-RECURSION^) or defuns (DEFUNS^)). There is also a mechanism for introducing “witness functions”; see Section 6.3 [DEFCHOOSE], page 163. The documentation for these events (EVENTS^) describes the axioms they introduce, which we will call here their “definitional axioms.” These definitional axioms are generally the constraints on the function symbols that these axioms introduce.

However, when a function symbol is introduced in the scope of an encapsulate (ENCAPSULATE^) event, its constraints may differ from the definitional axioms introduced for it. For example, suppose that a function’s definition is local (LOCAL^) to the encapsulate (ENCAPSULATE^); that is, suppose the function is introduced in the signature (SIGNATURE^) of the encapsulate (EN-CAPSULATE^). Then its constraints include, at the least, those non-local (LOCAL^) theorems and definitions in the encapsulate (ENCAPSULATE^) that mention the function symbol.

Actually, it will follow from the discussion below that if the signature (SIGNATURE^) is empty for an encapsulate (ENCAPSULATE^), then the constraint on each of its new function symbols is exactly the definitional axiom introduced for it. Intuitively, we view such encapsulates just as we view include-book (INCLUDE-BOOK^) events (EVENTS^). But the general case, where the signature (SIGNATURE^) is not empty, is more complicated.

In the discussion that follows we describe in detail exactly which constraints are associated with which function symbols that are introduced in the scope of an encapsulate (ENCAPSULATE^) event. In order to simplify the exposition we make two cuts at it. In the first cut we present an over-simplified explanation that nevertheless captures the main ideas. In the second cut we complete our explanation by explaining how we view certain events (EVENTS^) as being “lifted” out of the encapsulate (ENCAPSULATE^), resulting in a possibly smaller encapsulate (ENCAP-SULATE^), which becomes the target of the algorithm described in the first cut.

At the end of this note we present an example showing why a more naive approach is unsound.

Finally, before we start our “first cut,” we note that constrained functions always have guard (GUARD^)s of T. This makes sense when one considers that a constrained function’s “guard (GUARD^)” only appears in the context of a local (LOCAL^) defun (DEFUN^), which is skipped. Note also that any information you want “exported” outside an encapsulate (ENCAPSULATE^) event must be there as an explicit definition or theorem. For example, even if a function foo has output type (mv t t) in its signature (SIGNATURE^), the system will not know (truelistp (foo x)) merely on account of this information. Thus, if you are using functions like foo (constrained mv (MV^) functions) in a context where you are verifying guard (GUARD^)s, then you should probably provide a :type-prescription (TYPE-PRESCRIPTION^) rule for the constrained function, for example, the :type-prescription (TYPE-PRESCRIPTION^) rule

(true-listp (foo x)).

First cut at constraint-assigning algorithm. Quite simply, the formulas introduced in the scope of an encapsulate (ENCAPSULATE^) are conjoined, and each function symbol introduced by the encapsulate (ENCAPSULATE^) is assigned that conjunction as its constraint.

Clearly this is a rather severe algorithm. Let us consider two possible optimizations in an informal manner before presenting our second cut.

Consider the (rather artificial) event below. The function before1 does not refer at all, even indirectly, to the locally-introduced function sig-fn, so it is unfortunate to saddle it with constraints

about sig-fn.

     (encapsulate
      ((sig-fn (x) t))
      (defun before1 (x)
        (if (consp x)
            (before1 (cdr x))
          x))
      (local (defun sig-fn (x) (cons x x)))
      (defthm sig-fn-prop
        (consp (sig-fn x)))
      )

We would like to imagine moving the definition of before1 to just in front of this encapsulate (ENCAPSULATE^), as follows.

     (defun before1 (x)
       (if (consp x)
           (before1 (cdr x))
         x))
     (encapsulate
      ((sig-fn (x) t))
      (local (defun sig-fn (x) (cons x x)))
      (defthm sig-fn-prop
        (consp (sig-fn x)))
      )

Thus, we will only assign the constraint (consp (sig-fn x)), from the theorem sig-fn-prop, to the function sig-fn, not to the function before1.

More generally, suppose an event in an encapsulate (ENCAPSULATE^) event does not mention any function symbol in the signature (SIGNATURE^) of the encapsulate (ENCAPSULATE^), nor any function symbol that mentions any such function symbol, and so on. (We might say that no function symbol from the signature (SIGNATURE^) is an “ancestor” of any function symbol occurring in the event.) Then we imagine moving the event, so that it appears in front of the encapsulate (ENCAPSULATE^). We don’t actually move it, but we pretend we do when it comes time to assign constraints. Thus, such definitions only introduce definitional axioms as the constraints on the function symbols being defined, and such theorems introduce no constraints.

Once this first optimization is performed, we have in mind a set of “constrained functions.” These are the functions introduced in the encapsulate (ENCAPSULATE^) that would remain after moving some of them out, as indicated above. Consider the collection of all formulas introduced by the encapsulate (ENCAPSULATE^), except the definitional axioms, that mention these constrained functions. So for example, in the event below, no such formula mentions the function symbol

after1.

     (encapsulate
      ((sig-fn (x) t))
      (local (defun sig-fn (x) (cons x x)))
      (defthm sig-fn-prop
        (consp (sig-fn x)))
      (defun after1 (x)
        (sig-fn x))
      )

We can see that there is really no harm in imagining that we move the definition of after1 out of the encapsulate (ENCAPSULATE^), to just after the encapsulate (ENCAPSULATE^).

We may summarize the observations above as follows, after which we conclude with a more elaborate example.

Second cut at constraint-assigning algorithm. Given an encapsulate (ENCAPSULATE^) event, first move, to just in front of it and in the same order, all definitions and theorems for which none of the functions declared in the signature (SIGNATURE^) is ancestral. (In fact perform this process recursively, handling nested encapsulate (ENCAPSULATE^)s.) Now collect up all formulas introduced in the encapsulate (ENCAPSULATE^) other than the definitional axioms, and restrict the set of constrained functions to those that are ancestral in at least one such formula. Finally, assign all formulas introduced in the resulting encapsulate (ENCAPSULATE^) as the common constraint on all function symbols that are introduced in the resulting encapsulate (ENCAPSU-LATE^). (Thus, we imagine that the definitions of functions that are omitted from this list of function symbols, together with all non-definitional formulas omitted from this list of formulas, are moved outside the encapsulate (ENCAPSULATE^), to just after it.)

Implementation note. In the implementation we do not actually move events (EVENTS^), but we create constraints that pretend that we did.

Here is an example illustrating our constraint-assigning algorithm. It builds on the preceding examples.

(encapsulate
((sig-fn (x) t))
(defun before1 (x)
  (if (consp x)
      (before1 (cdr x))
    x))
(local (defun sig-fn (x) (cons x x)))
(defthm sig-fn-prop
  (consp (sig-fn x)))
(defun during (x)
  (if (consp x)
      x
    (cons (car (sig-fn x))
          17)))
(defun before2 (x)
  (before1 x))
(defthm before2-prop
  (atom (before2 x)))
(defthm during-prop
  (implies (and (atom x)
                (before2 x))
           (equal (car (during x))
                  (car (sig-fn x)))))
(defun after1 (x)
  (sig-fn x))
(defchoose after2 (x) (u)
  (and (< u x) (during x)))
)

Only the functions sig-fn and during receive extra constraints. The functions before1 and before2 are viewed as moving in front of the encapsulate (ENCAPSULATE^), as is the theorem before2-prop. The functions after1 and after2 are viewed as being moved past the encapsulate (ENCAPSULATE^). Notice that the formula (consp (during x)) is a conjunct of the constraint.

It comes from the :type-prescription (TYPE-PRESCRIPTION^) rule deduced during the definition of the function during. The implementation reports the following.

(SIG-FN X) is axiomatized to return one result.
In addition, we export AFTER2, AFTER1, DURING-PROP, BEFORE2-PROP, BEFORE2,
DURING, SIG-FN-PROP and BEFORE1.
The following constraint is associated with both of the functions DURING
and SIG-FN:
(AND (EQUAL (DURING X)
            (IF (CONSP X)
                X (CONS (CAR (SIG-FN X)) 17)))
     (CONSP (DURING X))
     (CONSP (SIG-FN X))
     (IMPLIES (AND (ATOM X) (BEFORE2 X))
              (EQUAL (CAR (DURING X))
                     (CAR (SIG-FN X)))))

We conclude by asking (and to a certain extent, answering) the following question: Isn’t there an approach to assigning constraints that avoids over-constraining more simply than our “second cut” above? Perhaps it seems that given an encapsulate (ENCAPSULATE^), we should simply assign to each locally defined function the theorems exported about that function. If we adopted that simple approach the events below would be admissible.

(encapsulate
 ((foo (x) t))
 (local (defun foo (x) x))
 (defun bar (x)
   (foo x))
 (defthm bar-prop
   (equal (bar x) x)
   :rule-classes nil))
(defthm foo-id
  (equal (foo x) x)
  :hints (("Goal" :use bar-prop)))
; The following event is not admissible in ACL2.
(defthm ouch!
  nil
  :rule-classes nil
  :hints
  (("Goal" :use

         ((:functional-instance foo-id
                                (foo (lambda (x) (cons x x))))))))

Under the simple approach we have in mind, bar is constrained to satisfy both its definition and bar-prop because bar mentions a function declared in the signatures of the encapsulation. In fact, bar is so-constrained in the ACL2 semantics of encapsulation and the first two events above (the encapsulate and the consequence that foo must be the identity function) are actually admissible. But under the simple approach to assigning constraints, foo is unconstrained because no theorem about it is exported. Under that approach, ouch! is proveable because foo can be instantiated in foo-id to a function other than the identity function.

It’s tempting to think we can fix this by including definitions, not just theorems, in constraints. But consider the following slightly more elaborate example. The problem is that we need to include as a constraint on foo not only the definition of bar, which mentions foo explicitly, but also abc, which has foo as an ancestor.

     (encapsulate
      ((foo (x) t))
      (local (defun foo (x) x))
      (local (defthm foo-prop
               (equal (foo x) x)))
      (defun bar (x)
        (foo x))
      (defun abc (x)
        (bar x))
      (defthm abc-prop
        (equal (abc x) x)
        :rule-classes nil))
     (defthm foo-id
       (equal (foo x) x)
       :hints (("Goal" :use abc-prop)))
     ; The following event is not admissible in ACL2.
     (defthm ouch!
       nil
       :rule-classes nil
       :hints
       (("Goal" :use
         ((:functional-instance foo-id
                                (foo (lambda (x) (cons x x)))
                                (bar (lambda (x) (cons x x))))))))

8.15 COPYRIGHT

COPYRIGHT ACL2 copyright, license, sponsorship

ACL2 Version 1.9 – A Computational Logic for Applicative Common Lisp Copyright (C) 1997 Computational Logic, Inc.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

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. See the file LICENSE. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Written by: Matt Kaufmann and J Strother Moore email: Matt Kaufmann@email.mot.com and Moore@cs.utexas.edu Computational Logic, Inc. 1717 West Sixth Street, Suite 290 Austin, TX 78703-4776 U.S.A.

Please also see Section 8.2 [ACKNOWLEDGEMENTS], page 237.

8.16 COROLLARY

COROLLARY the corollary formula of a rune (RUNE^)

This is a low-level system function at the present time. See Section 7.11 [PR], page 224 and see Section 7.12 [PR!], page 224 instead. Also see Chapter 15 [RULE-CLASSES], page 723 for the use of the symbol :corollary in specifying a rule class.

8.17 CURRENT-PACKAGE

CURRENT-PACKAGE the package used for reading and printing Current-package is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is

(current-package state) and the updater is (set-current-package val state), or more con-

ventionally, (in-package val). The value of current-package is actually the string that names the package. (Common Lisp’s “package” objects do not exist in ACL2.) The current package must be known to ACL2, i.e., it must be one of the initial packages or a package defined with defpkg (DEFPKG^) by the user.

When printing symbols, the package prefix is displayed if it is not the current-package and may be optionally displayed otherwise. Thus, if current-package is "ACL2" then the symbol 'ACL2::SYMB

may be printed as SYMB or ACL2::SYMB, while 'MY-PKG::SYMB must be printed as MY-PKG::SYMB.

But if current-package is "MY-PKG" then the former symbol must be printed as ACL2::SYMB while the latter may be printed as SYMB.

In Common Lisp, current-package also affects how objects are read from character streams. Roughly speaking, read and print are inverses if the current-package is fixed, so reading from a stream produced by printing an object must produce an equal object.

In ACL2, the situation is more complicated because we never read objects from character streams, we only read them from object “streams” (channels). Logically speaking, the objects in such a channel are fixed regardless of the setting of current-package. However, our host file systems do not support the idea of Lisp object files and instead only support character files. So when you open an object input channel to a given (character file) we must somehow convert it to a list of ACL2 objects. This is done by a deus ex machina (“a person or thing that appears or is introduced suddenly and unexpectedly and provides a contrived solution to an apparently insoluble difficulty,” Webster’s Ninth New Collegiate Dictionary). Roughly speaking, the deus ex machina determines what sequence of calls to read-object will occur in the future and what the currentpackage will be during each of those calls, and then produces a channel containing the sequence of objects produced by an analogous sequence of Common Lisp reads with *current-package* bound appropriately for each.

A simple rule suffices to make sane file io (IO^) possible: before you read an object from an object channel to a file created by printing to a character channel, make sure the current-package at read-time is the same as it was at print-time.

8.18 DEFAULT-DEFUN-MODE

DEFAULT-DEFUN-MODE the default defun-mode (DEFUN-MODE^) of defun (DEFUN^)’d functions When a defun (DEFUN^) is processed and no :mode xarg is supplied, the function defaultdefun-mode is used. To find the default defun-mode (DEFUN-MODE^) of the current ACL2 world (WORLD^), type (default-defun-mode (w state)). See Section 8.20 [DEFUN-MODE], page 275 for a discussion of defun-mode (DEFUN-MODE^)s. To change the default defun-mode (DEFUN-MODE^) of the ACL2 world (WORLD^), type one of the keywords :program (PRO-GRAM^) or :logic (LOGIC^).

The default ACL2 prompt (PROMPT^) displays the current default defun-mode (DEFUN-MODE^) by showing the character p for :program (PROGRAM^) mode, and omitting it for :logic (LOGIC^) mode; see Section 8.19 [DEFAULT-PRINT-PROMPT], page 274. The default defun-mode (DEFUN-MODE^) may be changed using the keyword command (COMMAND^)s :program (PROGRAM^) and :logic (LOGIC^), which are equivalent to the command (COM-MAND^)s (program) and (logic). Each of these names is documented separately: see Section 6.25 [PROGRAM], page 195 and see Section 6.22 [LOGIC], page 192. The default defun-mode (DEFUN-MODE^) is stored in the table (TABLE^) acl2-defaults-table (ACL2-DEFAULTS-TABLE^) and hence may also be changed by a table (TABLE^) command (COMMAND^). See Section 6.36 [TABLE], page 204 and also see Section 9.2 [ACL2-DEFAULTS-TABLE], page 410. Both mode-changing command (COMMAND^)s are events (EVENTS^).

While events (EVENTS^) that change the default defun-mode (DEFUN-MODE^) are permitted within an encapsulate (ENCAPSULATE^) or the text of a book, their effects are local in scope to the duration of the encapsulation or inclusion. For example, if the default defun-mode (DEFUN-MODE^) is :logic (LOGIC^) and a book is included that contains the event (program), then subsequent events (EVENTS^) within the book are processed with the default defun-mode (DEFUN-MODE^) :program (PROGRAM^); but when the include-book (INCLUDE-BOOK^) event completes, the default defun-mode (DEFUN-MODE^) will still be :logic (LOGIC^). Command (COMMAND^)s that change the default defun-mode (DEFUN-MODE^) are not permitted inside local (LOCAL^) forms.

8.19 DEFAULT-PRINT-PROMPT

DEFAULT-PRINT-PROMPT the default prompt (PROMPT^) printed by ld (LD^)

     Example prompt:
     ACL2 p!s>

The prompt (PROMPT^) printed by ACL2 displays the current package, followed by a space, followed by zero or more of the three characters (CHARACTERS^) as specified below, followed by the character > (>^) printed one or more times, reflecting the number of recursive calls of ld (LD^). The three characters (CHARACTERS^) in the middle are as follows:

     p     ; when (default-defun-mode (w state)) is :program
     !     ; when guard checking is on
     s     ; when (ld-skip-proofsp state) is t

See Section 8.18 [DEFAULT-DEFUN-MODE], page 273, see Section 9.12 [SET-GUARD-CHECKING], page 423, and see Section 8.59 [LD-SKIP-PROOFSP], page 339.

Also see Section 8.56 [LD-PROMPT], page 334 to see how to install your own prompt (PROMPT^).

Here are some examples with ld-skip-proofsp nil.

     ACL2 !>    ; logic mode with guard checking on
     ACL2 >     ; logic mode with guard checking off
     ACL2 p!>   ; program mode with guard checking on
     ACL2 p>    ; program mode with guard checking off

Here are some examples with default-defun-mode (DEFAULT-DEFUN-MODE^) of :logic (LOGIC^).

     ACL2 >     ; guard checking off, ld-skip-proofsp nil
     ACL2 s>    ; guard checking off, ld-skip-proofsp t
     ACL2 !>    ; guard checking on, ld-skip-proofsp nil
     ACL2 !s>   ; guard checking on, ld-skip-proofsp t

8.20 DEFUN-MODE

DEFUN-MODE determines whether a function definition is a logical act

Two “defun-mode (DEFUN-MODE^)s” are supported, :program (PROGRAM^) and :logic (LOGIC^). Roughly speaking, :program (PROGRAM^) mode allows you to prototype a function for execution without any proof burdens, while :logic (LOGIC^) mode allows you to add a new definitional axiom to the logic. The system comes up in :logic (LOGIC^) mode. Execution of functions whose defun-mode (DEFUN-MODE^) is :program (PROGRAM^) may render ACL2 unsound! See Section 8.21 [DEFUN-MODE-CAVEAT], page 278.

When you define a function in the ACL2 logic, that function can be run on concrete data. But it is also possible to reason deductively about the function because each definition extends the underlying logic with a definitional axiom. To insure that the logic is sound after the addition of this axiom, certain restrictions have to be met, namely that the recursion terminates. This can be quite challenging.

Because ACL2 is a programming (PROGRAMMING^) language, you often may wish simply to program in ACL2. For example, you may wish to define your system and test it, without any logical burden. Or, you may wish to define “utility” functions — functions that are executed to help manage the task of building your system but functions whose logical properties are of no immediate concern. Such functions might be used to generate test data or help interpret the results of tests. They might create files or explore the ACL2 data base. The termination arguments for such functions are an unnecessary burden provided no axioms about the functions are ever used in deductions.

Thus, ACL2 introduces the idea of the “defun-mode (DEFUN-MODE^)” of a function. The :mode keyword of defun (DEFUN^)’s declare (DECLARE^) xarg allows you to specify the defun-mode (DEFUN-MODE^) of a given definition. If no :mode keyword is supplied, the default defun-mode (DEFUN-MODE^) is used; see Section 8.18 [DEFAULT-DEFUN-MODE], page 273.

There are two defun-mode (DEFUN-MODE^)s, each of which is written as a keyword:

:program (PROGRAM^) — logically undefined but executable outside deductive contexts.

:logic (LOGIC^) — axiomatically defined as per the ACL2 definitional principle.

It is possible to change the defun-mode (DEFUN-MODE^) of a function from :program (PRO-GRAM^) to :logic (LOGIC^). We discuss this below.

We think of functions having :program (PROGRAM^) mode as “dangerous” functions, while functions having :logic (LOGIC^) mode are “safe.” The only requirement enforced on :program (PROGRAM^) mode functions is the syntactic one: each definition must be well-formed ACL2. Naively speaking, if a :program (PROGRAM^) mode function fails to terminate then no harm is done because no axiom is added (so inconsistency is avoided) and some invocations of the function may simply never return. This simplistic justification of :program (PROGRAM^) mode execution is faulty because it ignores the damage that might be caused by “mis-guarded” functions. See Section 8.21 [DEFUN-MODE-CAVEAT], page 278.

We therefore implicitly describe an imagined implementation of defun-mode (DEFUN-MODE^)s that is safe and, we think, effective. But please see Section 8.21 [DEFUN-MODE-CAVEAT], page 278.

The default defun-mode (DEFUN-MODE^) is :logic (LOGIC^). This means that when you defun (DEFUN^) a function the system will try to prove termination. If you wish to introduce a function of a different defun-mode (DEFUN-MODE^) use the :mode xargs (XARGS^) keyword. Below we show fact introduced as a function in :program (PROGRAM^) mode.

     (defun fact (n)
       (declare (xargs :mode :program))
       (if (or (not (integerp n)) (= n 0))
           1
         (* n (fact (1- n)))))

No axiom is added to the logic as a result of this definition. By introducing fact in :program (PROGRAM^) mode we avoid the burden of a termination proof, while still having the option of executing the function. For example, you can type

     ACL2 !>(fact 3)

and get the answer 6. If you type (fact -1) you will get a hard lisp error due to “infinite recursion.”

However, the ACL2 theorem prover knows no axioms about fact. In particular, if the term (fact 3) arises in a proof, the theorem prover is unable to deduce that it is 6. From the perspective of the theorem prover it is as though fact were an undefined function symbol of arity 1. Thus, modulo certain important issues (see Section 8.21 [DEFUN-MODE-CAVEAT], page 278), the introduction of this function in :program (PROGRAM^) mode does not imperil the soundness of the system — despite the fact that the termination argument for fact was omitted — because nothing of interest can be proved about fact. Indeed, we do not allow fact to be used in logical contexts such as conjectures submitted for proof.

It is possible to convert a function from :program (PROGRAM^) mode to :logic (LOGIC^) mode at the cost of proving that it is admissible. This can be done by invoking

     (verify-termination fact)

which is equivalent to submitting the defun (DEFUN^) of fact, again, but in :logic (LOGIC^) mode.

     (defun fact (n)
       (declare (xargs :mode :logic))
       (if (or (not (integerp n)) (= n 0))
           1
         (* n (fact (1- n)))))

This particular event will fail because the termination argument requires that n be nonnegative. A repaired defun (DEFUN^), for example with = (=^) replaced by <= (<=^), will succeed, and an axiom about fact will henceforth be available.

Technically, verify-termination (VERIFY-TERMINATION^) submits a redefinition of the :program (PROGRAM^) mode function. This is permitted, even when ld-redefinition-action (LD-REDEFINITION-ACTION^) is nil, because the new definition is identical to the old (except for its :mode and, possibly, other non-logical properties).

See Section 8.41 [GUARD], page 305 for a discussion of how to restrict the execution of functions. Guard (GUARD^)s may be “verified” for functions in :logic (LOGIC^) mode; see Section 6.39 [VERIFY-GUARDS], page 210.

8.21 DEFUN-MODE-CAVEAT

DEFUN-MODE-CAVEAT functions with defun-mode (DEFUN-MODE^) of :program (PRO-GRAM^) considered unsound

Technically speaking, in the current implementation, the execution of functions having defun-mode (DEFUN-MODE^) :program (PROGRAM^) may damage the ACL2 system in a way that renders it unsound. See Section 8.20 [DEFUN-MODE], page 275 for a discussion of defun-mode (DEFUN-MODE^)s. That discussion describes an imagined implementation that is slightly different from this one. This note explains that the current implementation is open to unsoundness.

For discussion of a different soundness issue that is also related to function execution, see Section 8.39 [GENERALIZED-BOOLEANS], page 302.

The execution of a function having defun-mode (DEFUN-MODE^) :program (PROGRAM^) may violate Common Lisp guard (GUARD^)s on the subroutines used. (This may be true even for calls of a function on arguments that satisfy its guard (GUARD^), because ACL2 has not verified that its guard (GUARD^) is sufficient to protect its subroutines.) When a guard (GUARD^) is violated at runtime all bets are off. That is, no guarantees are made either about the answer being “right” or about the continued rationality of the ACL2 system itself.

For example, suppose you make the following defun (DEFUN^):

     (defun crash (i)
       (declare (xargs :mode :program :guard (integerp i)))
       (car i))

Note that the declared guard does not in fact adequately protect the subroutines in the body of crash; indeed, satisfying the guard to crash will guarantee that the car (CAR^) expression is in violation of its guard. Because this function is admitted in :program (PROGRAM^)-mode, no checks are made concerning the suitability of the guard. Furthermore, in the current ACL2 implementation, crash is executed directly in Common Lisp. Thus if you call crash on an argument satisfying its guard you will cause an erroneous computation to take place.

     ACL2 !>(crash 7)
     Error: Caught fatal error [memory may be damaged]
     ...

There is no telling how much damage is done by this errant computation. In some lisps your ACL2 job may actually crash back to the operating system. In other lisps you may be able to recover from the “hard error” and resume ACL2 in a damaged but apparently functional image.

THUS, HAVING A FUNCTION WITH DEFUN-MODE (DEFUN-MODE^) :PROGRAM (PRO-GRAM^) IN YOUR SYSTEM ABSOLVES US, THE ACL2 IMPLEMENTORS, FROM RESPON-SIBILITY FOR THE SOUNDNESS OF OUR SYSTEM.

Furthermore

ACL2 DOES NOT YET PROVIDE ANY MEANS OF REGAINING ASSURANCES OF SOUND-NESS AFTER THE INTRODUCTION OF A FUNCTION IN :PROGRAM (PROGRAM^) MODE, EVEN IF IT IS ULTIMATELY CONVERTED TO :LOGIC (LOGIC^) MODE (since its execution could have damaged the system in a way that makes it possible to verify its termination and guard (GUARD^)s unsoundly).

Finally,

THE VAST MAJORITY OF ACL2 SYSTEM CODE IS IN :PROGRAM (PROGRAM^) MODE AND SO ALL BETS ARE OFF FROM BEFORE YOU START!

This hopeless state of current affairs will change, we think. We think we have defined our functions “correctly” in the sense that they can be converted, without “essential” modification, to :logic (LOGIC^) mode. We think it very unlikely that a mis-guarded function in :program (PROGRAM^) mode (whether ours or yours) will cause unsoundness without some sort of hard lisp error accompanying it. We think that ultimately we can make it possible to execute your functions (interpretively) without risk to the system, even when some have :program (PROGRAM^) mode. In that imagined implementation, code using functions having :program (PROGRAM^) mode would run more slowly, but safely. These functions could be introduced into the logic ex post facto, whereupon the code’s execution would speed up because Common Lisp would be allowed to execute it directly. We therefore ask that you simply pretend that this is that imagined implementation, introduce functions in :program (PROGRAM^) mode, use them as convenient and perhaps ultimately introduce some of them in :logic (LOGIC^) mode and prove their properties. If you use the system this way we can develop (or dismiss) this style of formal system development. BUT BE ON THE LOOKOUT FOR SCREWUPS DUE TO DAMAGE CAUSED BY THE EXECUTION OF YOUR FUNCTIONS HAVING :PROGRAM (PROGRAM^) MODE!

8.22 DEFUNS

DEFUNS an alternative to mutual-recursion (MUTUAL-RECURSION^)

     Example:
     (DEFUNS
      (evenlp (x)
        (if (consp x) (oddlp (cdr x)) t))
      (oddlp (x)
        (if (consp x) (evenlp (cdr x)) nil)))
     General Form:
     (DEFUNS defuns-tuple1 ... defuns-tuplen)

is equivalent to

     (MUTUAL-RECURSION
       (DEFUN . defuns-tuple1)
       ...
       (DEFUN . defuns-tuplen))

In fact, defuns is the more primitive of the two and mutual-recursion (MUTUAL-RECURSION^) is just a macro that expands to a call of defun (DEFUN^) after stripping off the defun (DEFUN^) at the car (CAR^) of each argument to mutual-recursion (MUTUAL-RECURSION^). We provide and use mutual-recursion (MUTUAL-RECURSION^) rather than defuns because by leaving the defun (DEFUN^)s in place, mutual-recursion (MUTUAL-RECURSION^) forms can be processed by the Emacs tags program. See Section 6.24 [MUTUAL-RECURSION], page 194.

8.23 DISABLE-FORCING

DISABLE-FORCING to disallow force (FORCE^)d case splits

     General Form:
     ACL2 !>:disable-forcing   ; disallow forced case splits

See Section 8.37 [FORCE], page 297 for a discussion of force (FORCE^)d case splits.

Disable-forcing is a macro that disable (DISABLE^)s the executable counterpart of the function symbol force (FORCE^); see Section 8.37 [FORCE], page 297. When you want to disable (DIS-ABLE^) forcing in hints (HINTS^), use a form such as:

     :in-theory (disable (:executable-counterpart force))

8.24 DISABLEDP

DISABLEDP determine whether a given name or rune is disabled

     Examples:
     :disabledp foo   ; returns a list of all disabled runes whose base
                      ; symbol is foo (see Section 16.10 [RUNE], page 784)
     (disabledp 'foo) ; same as above (i.e., :disabledp foo)
     :disabledp (:rewrite bar . 1) ; returns t if the indicated rune is
                                   ; disabled, else nil
     (disabledp (:rewrite bar . 1)); same as immediately above

Also see Section 7.11 [PR], page 224, which gives much more information about the rules associated with a given event.

Disabledp takes one argument, an event name or a rune. In the former case it returns the list of disabled runes associated with that name (in the sense that the rune’s “base symbol” is that name; see Section 16.10 [RUNE], page 784). In the latter case it returns t if the given rune is disabled, and nil otherwise.

8.25 E0-ORD-<

E0-ORD-< the well-founded less-than relation on ordinals up to epsilon-0

If x and y are both e0-ordinalp (E0-ORDINALP^)s (see Section 8.26 [E0-ORDINALP], page 283) then (e0-ord-< x y) is true iff x is strictly less than y. e0-ord-< is well-founded on the e0ordinalp (E0-ORDINALP^)s. When x and y are both nonnegative integers, e0-ord-< is just the familiar “less than” relation (< (<^)).

e0-ord-< plays a key role in the formal underpinnings of the ACL2 logic. In order for a recursive definition to be admissible it must be proved to “terminate.” By terminate we mean that the arguments to the function “get smaller” as the function recurses and this sense of size comparison must be such that there is no “infinitely descending” sequence of ever smaller arguments. That is, the relation used to compare successive arguments must be well-founded on the domain being measured.

The most basic way ACL2 provides to prove termination requires the user to supply (perhaps implicitly) a mapping of the argument tuples into the ordinals with some “measure” expression in such a way that the measures of the successive argument tuples produced by recursion decrease according to the relation e0-ord-<. The validity of this method rests on the well-foundedness of

e0-ord-< on the e0-ordinalp (E0-ORDINALP^)s.

Without loss of generality, suppose the definition in question introduces the function f, with one formal parameter x (which might be a list of objects). Then we require that there exist a measure expression, (m x), that always produces an e0-ordinalp (E0-ORDINALP^). Furthermore, consider any recursive call, (f (d x)), in the body of the definition. Let hyps be the conjunction terms (each of which is either the test of an if (IF^) in the body or else the negation of such a test) describing the path through the body to the recursive call in question. Then it must be a theorem that

       (IMPLIES hyps (E0-ORD-< (m (d x)) (m x))).

When we say e0-ord-< is “well-founded” on the e0-ordinalp (E0-ORDINALP^)s we mean that there is no infinite sequence of e0-ordinalp (E0-ORDINALP^)s such that each is smaller than its predecessor in the sequence. Thus, the theorems that must be proved about f when it is introduced establish that it cannot recur forever because each time a recursive call is taken (m x) gets smaller. From this, and the syntactic restrictions on definitions, it can be shown (as on page 44 in “A Computational Logic”, Boyer and Moore, Academic Press, 1979) that there exists a function satisfying the definition; intuitively, the value assigned to any given x by the alleged function is that computed by a sufficiently large machine. Hence, the logic is consistent if the axiom defining f is added.

See Section 8.26 [E0-ORDINALP], page 283 for a discussion of the ordinals and how to compare two ordinals.

The definitional principle permits the use of relations other than e0-ord-< but they must first be proved to be well-founded on some domain. See Section 15.17 [WELL-FOUNDED-RELATION], page 769. Roughly put, alternative relations are shown well-founded by providing an orderpreserving mapping from their domain into the ordinals. See Section 6.16 [DEFUN], page 178 for details on how to specify which well-founded relation is to be used.

8.26 E0-ORDINALP

E0-ORDINALP a recognizer for the ordinals up to epsilon-0

Using the nonnegative integers and lists we can represent the ordinals up to epsilon-0. The ACL2 notion of ordinal is the same as that found in nqthm-1992 and both are very similar to the development given in “New Version of the Consistency Proof for Elementary Number Theory” in The Collected Papers of Gerhard Gentzen, ed. M.E. Szabo, North-Holland Publishing Company, Amsterdam, 1969, pp 132-213.

The following essay is intended to provide intuition about ordinals. The truth, of course, lies simply in the ACL2 definitions of e0-ordinalp and e0-ord-< (E0-ORD-<^).

Very intuitively, think of each non-zero natural number as by being denoted by a series of the appropriate number of strokes, i.e.,

     0             0
     1             |
     2             ||
     3             |||
     4             ||||
     ...           ...

Then “omega,” here written as w, is the ordinal that might be written as

     w             |||||...,

i.e., an infinite number of strokes. Addition here is just concatenation. Observe that adding one to the front of w in the picture above produces w again, which gives rise to a standard definition of w: w is the least ordinal such that adding another stroke at the beginning does not change the ordinal.

We denote by w+w or w*2 the “doubly infinite” sequence that we might write as follows.

     w*2           |||||... |||||...

One way to think of w*2 is that it is obtained by replacing each stroke in 2 (||) by w. Thus, one can imagine w*3, w*4, etc., which leads ultimately to the idea of “w*w,” the ordinal obtained by replacing each stroke in w by w. This is also written as “omega squared” or w^2, or:

      2
     w             |||||... |||||... |||||... |||||... |||||... ...

We can analogously construct w^3 by replacing each stroke in w by w^2 (which, it turns out, is the same as replacing each stroke in w^2 by w). That is, we can construct w^3 as w copies of w^2,

      3              2       2       2       2
     w              w  ...  w  ...  w  ...  w ... ...

Then we can construct w^4 as w copies of w^3, w^5 as w copies of w^4, etc., ultimately suggesting w^w. We can then stack omegas, i.e., (w^w)^w etc. Consider the “limit” of all of those stacks, which we might display as follows.

            .
           .
          .
         w
        w
       w
      w
     w

That is epsilon-0.

Below we begin listing some ordinals up to epsilon-0; the reader can fill in the gaps at his or her leisure. We show in the left column the conventional notation, using w as “omega,” and in the right column the ACL2 object representing the corresponding ordinal.

ordinal            ACL2 representation
0                  0
1                  1
2                  2
3                  3
...                ...
w                 '(1 . 0)
w+1               '(1 . 1)
w+2               '(1 . 2)
...                ...
w*2               '(1 1 . 0)
(w*2)+1           '(1 1 . 1)
...                ...
w*3               '(1 1 1 . 0)
(w*3)+1           '(1 1 1 . 1)
...                ...
 2
w                 '(2 . 0)
...                ...
 2
w +w*4+3          '(2 1 1 1 1 . 3)
...                ...
 3
w                 '(3 . 0)
...                ...

 w
w                 '((1 . 0) . 0)
...                ...
 w  99
w +w  +4w+3       '((1 . 0) 99 1 1 1 1 . 3)
...                ...
  2
 w
w                 '((2 . 0) . 0)
...                ...

         w
        w
       w                 '(((1 . 0) . 0) . 0)
       ...                ...

Observe that the sequence of e0-ordinalps starts with the nonnegative integers. This is convenient because it means that if a term, such as a measure expression for justifying a recursive function (see Section 8.25 [E0-ORD-<], page 282) must produce an e0-ordinalp it suffices for it to produce a nonnegative integer.

The ordinals listed above are listed in ascending order. This is the ordering tested by e0-ord-< (E0-ORD-<^).

The “epsilon-0 ordinals” of ACL2 are recognized by the recursively defined function e0-ordinalp. The base case of the recursion tells us that nonnegative integers are epsilon-0 ordinals. Otherwise, an epsilon-0 ordinal is a cons (CONS^) pair (o1 . o2), where o1 is a non-0 epsilon-0 ordinal, o2 is an epsilon-0 ordinal, and if o2 is not an integer then its car (CAR^) (which, by the foregoing, must be an epsilon-0 ordinal) is no greater than o1. Thus, if you think of a (non-integer) epsilon-0 ordinal as a list, each element is an non-0 epsilon-0 ordinal, the ordinals are listed in weakly descending order, and the final cdr (CDR^) of the list is an integer.

The function e0-ord-< (E0-ORD-<^) compares two epsilon-0 ordinals, x and y. If both are integers, e0-ord-< (E0-ORD-<^) is just x<y. If one is an integer and the other is a cons (CONS^), the integer is the smaller. Otherwise, the ordinals in their car (CAR^)s are compared recursively and determines which is smaller unless the car (CAR^)s are equal, in which case the ordinals in their cdr (CDR^)s are compared.

Fundamental to ACL2 is the fact that e0-ord-< (E0-ORD-<^) is well-founded on epsilon-0 ordinals. That is, there is no “infinitely descending chain” of such ordinals. See Section 8.73 [PROOF-OF-WELL-FOUNDEDNESS], page 355.

8.27 EMBEDDED-EVENT-FORM

EMBEDDED-EVENT-FORM forms that may be embedded in other events (EVENTS^)

     Examples:
     (defun hd (x) (if (consp x) (car x) 0))
     (local (defthm lemma23 ...))

     (progn (defun fn1 ...)
            (local (defun fn2 ...))
            ...)
     General Form:
     An embedded event form is a term, x, such that
       x is a call of an event function other than DEFPKG (see the
       documentation for `events' for a listing of the event functions);
       x is of the form (LOCAL x1) where x1 is an embedded event form;
       x is of the form (PROGN x1 ... xn), where each xi is an embedded
       event form;
       x is of the form (VALUE &), where & is any term;
       x macroexpands to one of the forms above.

An exception: an embedded event form may not set the acl2-defaults-table (ACL2-DEFAULTS-TABLE^) when in the context of local (LOCAL^). Thus for example, the form

     (local (table acl2-defaults-table :defun-mode :program))

is not an embedded event form, nor is the form (local (program)), since the latter sets the acl2defaults-table (ACL2-DEFAULTS-TABLE^) implicitly. An example at the end of the discussion below illustrates why there is this restriction.

When an embedded event is executed while ld-skip-proofsp (LD-SKIP-PROOFSP^) is 'includebook (INCLUDE-BOOK^), those parts of it inside local (LOCAL^) forms are ignored. Thus,

        (progn (defun f1 () 1)
               (local (defun f2 () 2))
               (defun f3 () 3))

will define f1, f2, and f3 when ld-skip-proofsp (LD-SKIP-PROOFSP^) is nil but will define only f1 and f3 when ld-skip-proofsp (LD-SKIP-PROOFSP^) is 'include-book (INCLUDE-BOOK^).

Discussion:

Encapsulate (ENCAPSULATE^) and include-book (INCLUDE-BOOK^) place restrictions on the kinds of forms that may be processed. These restrictions insure that the non-local events (EVENTS^) (which will ultimately be processed with ld-skip-proofs t) are indeed admissible provided that the sequence of local (LOCAL^) and non-local events (EVENTS^) is admissible when

ld-skip-proofs is nil.

Local (LOCAL^) permits the hiding of an event or group of events (EVENTS^) in the sense that local (LOCAL^) events (EVENTS^) are processed when we are trying to establish the admissibility of a sequence of embedded events (EVENTS^) but are ignored when we are constructing the world (WORLD^) produced by assuming that sequence. Thus, for example, a particularly ugly and inefficient :rewrite (REWRITE^) rule might be made local (LOCAL^) to an encapsulate (ENCAPSULATE^) that “exports” a desirable theorem whose proof requires the ugly lemma.

To see why we can’t allow just anything in as an embedded event, consider allowing the form

     (if (ld-skip-proofsp state)
         (defun foo () 2)
         (defun foo () 1))

followed by

     (defthm foo-is-1 (equal (foo) 1)).

When we process the events (EVENTS^) with ld-skip-proofsp (LD-SKIP-PROOFSP^), nil the second defun (DEFUN^) is executed and the defthm (DEFTHM^) succeeds. But when we process the events (EVENTS^) with ld-skip-proofsp (LD-SKIP-PROOFSP^) 'include-book (INCLUDE-BOOK^), the second defun (DEFUN^) is executed, so that foo no longer has the same definition it did when we proved foo-is-1. Thus, an invalid formula is assumed when we process the defthm (DEFTHM^) while skipping proofs. Thus, the first form above is not a legal embedded event form.

Defpkg (DEFPKG^) is not allowed because it affects how things are read after it is executed. But all the forms embedded in an event are read before any are executed. That is,

     (encapsulate nil
                  (defpkg "MY-PKG" nil)
                  (defun foo () 'my-pkg::bar))

makes no sense since my-pkg::bar must have been read before the defpkg (DEFPKG^) for "MY-PKG" was executed.

Finally, let us elaborate on the restriction mentioned earlier related to the acl2-defaults-table (ACL2-DEFAULTS-TABLE^). Consider the following form.

     (encapsulate
      ()
      (local (program))
      (defun foo (x)
        (if (equal 0 x)
            0
          (1+ (foo (- x))))))

See Section 8.62 [LOCAL-INCOMPATIBILITY], page 344 for a discussion of how encapsulate (ENCAPSULATE^) processes event forms. Briefly, on the first pass through the events (EVENTS^) the definition of foo will be accepted in defun (DEFUN^) mode :program (PROGRAM^), and hence accepted. But on the second pass the form (local (program)) is skipped because it is marked as local (LOCAL^), and hence foo is accepted in defun (DEFUN^) mode :logic (LOGIC^). Yet, no proof has been performed in order to admit foo, and in fact, it is not hard to prove a contradiction from this definition!

8.28 ENABLE-FORCING

ENABLE-FORCING to allow force (FORCE^)d case splits

     General Form:
     ACL2 !>:enable-forcing    ; allowed forced case splits

See Section 8.37 [FORCE], page 297 for a discussion of force (FORCE^)d case splits.

Enable-forcing is a macro that enable (ENABLE^)s the executable counterpart of the function symbol force (FORCE^); see Section 8.37 [FORCE], page 297. When you want to enable (ENABLE^) forcing in hints (HINTS^), use a form such as:

     :in-theory (enable (:executable-counterpart force))

8.29 ENTER-BOOT-STRAP-MODE

ENTER-BOOT-STRAP-MODE The first millisecond of the Big Bang ACL2 functions, e.g., if (IF^), that show enter-boot-strap-mode as their defining command (COMMAND^) are in fact primitives. It is impossible for the system to display defining axioms about these symbols.

Enter-boot-strap-mode is a Common Lisp function but not an ACL2 function. It magically creates from nil an ACL2 property list world (WORLD^) that lets us start the boot-strapping process. That is, once enter-boot-strap-mode has created its world (WORLD^), it is possible to process the defconst (DEFCONST^)s, defun (DEFUN^)s, and defaxiom (DEFAXIOM^)s, necessary to bring up the rest of the system. Before that world (WORLD^) is created, the attempt by ACL2 even to translate a defun (DEFUN^) form, say, would produce an error because defun (DEFUN^) is undefined.

Several ACL2 functions show enter-boot-strap-mode as their defining command (COMMAND^). Among them are if (IF^), cons (CONS^), car (CAR^), and cdr (CDR^). These functions are characterized by axioms rather than definitional equations — axioms that in most cases are built into our code and hence do not have any explicit representation among the rules and formulas in the system.

8.30 ESCAPE-TO-COMMON-LISP

ESCAPE-TO-COMMON-LISP escaping to Common Lisp

     Example:
     ACL2 !>:Q

There is no Common Lisp escape feature in the lp (LP^). This is part of the price of purity. To execute a form in Common Lisp as opposed to ACL2, exit lp (LP^) with :q (Q^), submit the desired forms to the Common Lisp read-eval-print loop, and reenter ACL2 with (lp).

8.31 EVISCERATE-HIDE-TERMS

EVISCERATE-HIDE-TERMS to print (hide ...) as <hidden>

     Example:
     (assign eviscerate-hide-terms t)
     (assign eviscerate-hide-terms nil)

Eviscerate-hide-terms is a state (STATE^) global variable whose value is either t or nil. The variable affects how terms are displayed. If t, terms of the form (hide ...) are printed as <hidden>. Otherwise, they are printed normally.

8.32 EXECUTABLE-COUNTERPART

EXECUTABLE-COUNTERPART a rule for computing the value of a function

     Examples:
     (:executable-counterpart length)

which may be abbreviated in theories (THEORIES^) as

     (length)

Every defun (DEFUN^) introduces at least two rules used by the theorem prover. Suppose fn is the name of a defun (DEFUN^)’d function. Then (:definition fn) is the rune (see Section 16.10 [RUNE], page 784) naming the rule that allows the simplifier to replace calls of fn by its instantiated body. (:executable-counterpart fn) is the rune (RUNE^) for the rule for how to evaluate the function on known constants.

When typing theories (THEORIES^) it is convenient to know that (fn) is a runic designator that denotes (:executable-counterpart fn). See Chapter 16 [THEORIES], page 775.

If (:executable-counterpart fn) is enable (ENABLE^)d, then when applications of fn to known constants are seen by the simplifier they are computed out by executing the Common Lisp code for fn (with the appropriate handling of guard (GUARD^)s). Suppose fact is defined as the factorial function. If the executable counterpart rune (RUNE^) of fact, (:executable-counterpart fact), is enable (ENABLE^)d when the simplifier encounters (fact 12), then that term will be “immediately” expanded to 479001600.

Such one-step expansions are sometimes counterproductive because they prevent the anticipated application of certain lemmas about the subroutines of the expanded function. Such computed expansions can be prevented by disabling the executable counterpart rune (RUNE^) of the relevant function. For example, if (:executable-counterpart fact) is disable (DISABLE^)d, (fact 12) will not be expanded by computation. In this situation, (fact 12) may be rewritten to (* 12 (fact 11)), using the rule named (:definition fact), provided the system’s heuristics permit the introduction of the term (fact 11). Note that lemmas about multiplication may then be applicable (while such lemmas would be inapplicable to 479001600). In many proofs it is desirable to disable (DISABLE^) the executable counterpart rune (RUNE^)s of certain functions to prevent their expansion by computation. See Section 16.4 [EXECUTABLE-COUNTERPART-THEORY], page 780.

Finally: What do we do about functions that are “constrained” rather than defined, such as the following? (See Section 6.18 [ENCAPSULATE], page 185.)

     (encapsulate ((foo (x) t))
                  (local (defun foo (x) x)))

Does foo have an executable counterpart? Yes: since the vast majority of functions have sensible executable counterparts, it was decided that all functions, even such “constrained” ones, have executable counterparts. We essentially “trap” when such calls are inappropriate. Thus, consider for example:

     (defun bar (x)
       (if (rationalp x)
           (+ x 1)
         (foo x)))

If the term (bar '3) is encountered by the ACL2 rewriter during a proof, and if the :executablecounterpart of bar is enable (ENABLE^)d, then it will be invoked to reduce this term to '4. However, if the term (bar 'a) is encountered during a proof, then since 'a is not a rationalp (RATIONALP^) and since the :executable-counterpart of foo is only a “trap,” then this call of the :executable-counterpart of bar will result in a “trap.” In that case, the rewriter will return the term (hide (bar 'a)) so that it never has to go through this process again. See Section 8.42 [HIDE], page 317.

8.33 EXIT-BOOT-STRAP-MODE

EXIT-BOOT-STRAP-MODE the end of pre-history

Exit-boot-strap-mode is the last step in creating the ACL2 world (WORLD^) in which the user lives. It has command (COMMAND^) number 0. Command (COMMAND^)s before it are part of the system initialization and extend all the way back to :min (MIN^). Command (COMMAND^)s after it are those of the user.

Exit-boot-strap-mode is a Common Lisp function but not an ACL2 function. It is called when every defconst (DEFCONST^), defun (DEFUN^), etc., in our source code has been processed under ACL2 and the world (WORLD^) is all but complete. exit-boot-strap-mode has only one job: to signal the completion of the boot-strapping.

8.34 FAILED-FORCING

FAILED-FORCING how to deal with a proof failure (FAILURE^) in a forcing round

See Section 8.38 [FORCING-ROUND], page 299 for a background discussion of the notion of forcing rounds. When a proof fails during a forcing round it means that the “gist” of the proof succeeded but some “technical detail” failed. The first question you must ask yourself is whether the force (FORCE^)d goals are indeed theorems. We discuss the possibilities below.

If you believe the force (FORCE^)d goals are theorems, you should follow the usual methodology for “fixing” failed ACL2 proofs, e.g., the identification of key lemmas and their timely and proper use as rules. See Section 8.35 [FAILURE], page 296 and see Chapter 12 [PROOF-TREE], page 617.

The rules designed for the goals of forcing rounds are often just what is needed to prove the force (FORCE^)d hypothesis at the time it is force (FORCE^)d. Thus, you may find that when the system has been “taught” how to prove the goals of the forcing round no forcing round is needed. This is intended as a feature to help structure the discovery of the necessary rules.

If a hint must be provided to prove a goal in a forcing round, the appropriate “goal specifier” (the string used to identify the goal to which the hint is to be applied) is just the text printed on the line above the formula, e.g., "[1]Subgoal *1/3''". See Section 8.40 [GOAL-SPEC], page 304.

If you solve a forcing problem by giving explicit hints (HINTS^) for the goals of forcing rounds, you might consider whether you could avoid forcing the assumption in the first place by giving those hints (HINTS^) in the appropriate places of the main proof. This is one reason that we print out the origins of each force (FORCE^)d assumption. An argument against this style, however, is that an assumption might be force (FORCE^)d in hundreds of places in the main goal and proved only once in the forcing round, so that by delaying the proof you actually save time.

We now turn to the possibility that some goal in the forcing round is not a theorem.

There are two possibilities to consider. The first is that the original theorem has insufficient hypotheses to insure that all the force (FORCE^)d hypotheses are in fact always true. The “fix” in this case is to amend the original conjecture so that it has adequate hypotheses.

A more difficult situation can arise and that is when the conjecture has sufficient hypotheses but they are not present in the forcing round goal. This can be caused by what we call “premature” forcing.

Because ACL2 rewrites from the inside out, it is possible that it will force (FORCE^) hypotheses while the context is insufficient to establish them. Consider trying to prove (p x (foo x)). We first rewrite the formula in an empty context, i.e., assuming nothing. Thus, we rewrite (foo x) in an empty context. If rewriting (foo x) force (FORCE^)s anything, that force (FORCE^)d assumption will have to be proved in an empty context. This will likely be impossible.

On the other hand, suppose we did not attack (foo x) until after we had expanded p. We might find that the value of its second argument, (foo x), is relevant only in some cases and in those cases we might be able to establish the hypotheses force (FORCE^)d by (foo x). Our premature forcing is thus seen to be a consequence of our “over eager” rewriting.

Here, just for concreteness, is an example you can try. In this example, (foo x) rewrites to x but has a force (FORCE^)d hypothesis of (rationalp x). P does a case split on that very hypothesis and uses its second argument only when x is known to be rational. Thus, the hypothesis for the (foo x) rewrite is satisfied. On the false branch of its case split, p simplies to (p1 x) which can be proved under the assumption that x is not rational.

     (defun p1 (x) (not (rationalp x)))
     (defun p (x y)(if (rationalp x) (equal x y) (p1 x)))
     (defun foo (x) x)
     (defthm foo-rewrite (implies (force (rationalp x)) (equal (foo x) x)))
     (in-theory (disable foo))

The attempt then to do (thm (p x (foo x))) force (FORCE^)s the unprovable goal (rationalp

x).

Since all “formulas” are presented to the theorem prover as single terms with no hypotheses (e.g., since implies (IMPLIES^) is a function), this problem would occur routinely were it not for the fact that the theorem prover expands certain “simple” definitions immediately without doing anything that can cause a hypothesis to be force (FORCE^)d. See Section 8.81 [SIMPLE], page 364. This does not solve the problem, since it is possible to hide the propositional structure arbitrarily deeply. For example, one could define p, above, recursively so that the test that x is rational and the subsequent first “real” use of y occurred arbitrarily deeply.

Therefore, the problem remains: what do you do if an impossible goal is force (FORCE^)d and yet you know that the original conjecture was adequately protected by hypotheses?

One alternative is to disable forcing entirely. See Section 8.23 [DISABLE-FORCING], page 281. Another is to disable (DISABLE^) the rule that caused the force (FORCE^).

A third alternative is to prove that the negation of the main goal implies the force (FORCE^)d hypothesis. For example,

     (defthm not-p-implies-rationalp
       (implies (not (p x (foo x))) (rationalp x))
       :rule-classes nil)

Observe that we make no rules from this formula. Instead, we merely :use it in the subgoal where we must establish (rationalp x).

     (thm (p x (foo x))
          :hints (("Goal" :use not-p-implies-rationalp)))

When we said, above, that (p x (foo x)) is first rewritten in an empty context we were misrepresenting the situation slightly. When we rewrite a literal we know what literal we are rewriting and we implicitly assume it false. This assumption is “dangerous” in that it can lead us to simplify our goal to nil and give up — we have even seen people make the mistake of assuming the negation of what they wished to prove and then via a very complicated series of transformations convince themselves that the formula is false. Because of this “tail biting” we make very weak use of the negation of our goal. But the use we make of it is sufficient to establish the force (FORCE^)d hypothesis above.

A fourth alternative is to weaken your desired theorem so as to make explicit the required hypotheses, e.g., to prove

     (defthm rationalp-implies-main
       (implies (rationalp x) (p x (foo x)))
       :rule-classes nil)

This of course is unsatisfying because it is not what you originally intended. But all is not lost. You can now prove your main theorem from this one, letting the implies (IMPLIES^) here provide the necessary case split.

     (thm (p x (foo x))
          :hints (("Goal" :use rationalp-implies-main)))

8.35 FAILURE

FAILURE how to deal with a proof failure

When ACL2 gives up it does not mean that the submitted conjecture is invalid, even if the last formula ACL2 printed in its proof attempt is manifestly false. Since ACL2 sometimes generalize (GENERALIZE^)s the goal being proved, it is possible it adopted an invalid subgoal as a legitimate (but doomed) strategy for proving a valid goal. Nevertheless, conjectures submitted to ACL2 are often invalid and the proof attempt often leads the careful reader to the realization that a hypothesis has been omitted or that some special case has been forgotten. It is good practice to ask yourself, when you see a proof attempt fail, whether the conjecture submitted is actually a theorem.

If you think the conjecture is a theorem, then you must figure out from ACL2’s output what you know that ACL2 doesn’t about the functions in the conjecture and how to impart that knowledge to ACL2 in the form of rules. Books could be written about this, but they haven’t been yet. However, see Chapter 12 [PROOF-TREE], page 617 for a utility that may be very helpful in locating parts of the failed proof that are of particular interest. See also the discussion of how to read Nqthm proofs and how to use Nqthm rules in “A Computational Logic Handbook” by Boyer and Moore (Academic Press, 1988).

If the failure occurred during a forcing round, see Section 8.34 [FAILED-FORCING], page 293.

8.36 FIND-RULES-OF-RUNE

FIND-RULES-OF-RUNE find the rules named rune

     General Form:
     (find-rules-of-rune rune wrld)

This function finds all the rules in wrld with :rune (RUNE^) rune. It returns a list of rules in their internal form (generally as described by the corresponding defrec). Decyphering these rules is difficult since one cannot always look at a rule object and decide what kind of record it is without exploiting many system invariants (e.g., that :rewrite (REWRITE^) runes only name rewrite-rules).

At the moment this function returns nil if the rune in question is a :refinement (REFINEMENT^) rune, because there is no object representing :refinement (REFINEMENT^) rules. (:refinement (REFINEMENT^) rules cause changes in the 'coarsenings properties.) In addition, if the rune is an :equivalence (EQUIVALENCE^) rune, then congruence rules with that rune will be returned — because :equivalence (EQUIVALENCE^) lemmas generate some congruence rules — but the fact that a certain function is now known to be an equivalence relation is not represented by any rule object and so no such rule is returned. (The fact that the function is an equivalence relation is encoded entirely in its presence as a 'coarsening of equal (EQUAL^).)

8.37 FORCE

FORCE identity function used to force a case split

When a hypothesis of a conditional rule has the form (force hyp) it is logically equivalent to hyp but has a pragmatic effect. In particular, when the rule is considered, the needed instance of the hypothesis, hyp', is assumed and a special case is generated, requiring the system to prove that hyp' is true in the current context. The proofs of all such “forced assumptions” are delayed until the successful completion of the main goal. See Section 8.38 [FORCING-ROUND], page 299.

Forcing should only be used on hypotheses that are always expected to be true, such as the guard (GUARD^)s of functions. All the power of the theorem prover is brought to bear on a forced hypothesis and no backtracking is possible. If the :executable-counterpart (EXECUTABLE-COUNTERPART^) of the function force is disable (DISABLE^)d, then no hypothesis is forced. See Section 8.28 [ENABLE-FORCING], page 289 and see Section 8.23 [DISABLE-FORCING], page 281.

It sometimes happens that a conditional rule is not applied because some hypothesis, hyp, could not be relieved, even though the required instance of hyp, hyp', can be shown true in the context. This happens when insufficient resources are brought to bear on hyp' at the time we try to relieve it. A sometimes desirable alternative behavior is for the system to assume hyp', apply the rule, and to generate explicitly a special case to show that hyp' is true in the context. This is called “forcing” hyp. It can be arranged by restating the rule so that the offending hypothesis, hyp, is embedded in a call of force, as in (force hyp). By using the :corollary (COROLLARY^) field of the rule-classes (RULE-CLASSES^) entry, a hypothesis can be forced without changing the statement of the theorem from which the rule is derived.

Technically, force is just a function of one argument that returns that argument. It is generally enable (ENABLE^)d and hence evaporates during simplification. But its presence among the hypotheses of a conditional rule causes case splitting to occur if the hypothesis cannot be conventionally relieved.

Since a forced hypothesis must be provable whenever the rule is otherwise applicable, forcing should be used only on hypotheses that are expected always to be true. A common situation is when the hypothesis is in fact a guard (GUARD^) (or part of a guard (GUARD^)) of some function involved in the pattern that triggers the rule. Intuitively, if that pattern term occurs in the current conjecture, then its guard (GUARD^)s had better be true, since otherwise nothing is known about the term.

A particularly common situation in which some hypotheses should be forced is in “most general” type-prescription (TYPE-PRESCRIPTION^) lemmas. If a single lemma describes the “expected” type of a function, for all “expected” arguments, then it is probably a good idea to force the hypotheses of the lemma. Thus, every time a term involving the function arises, the term will be given the expected type and its arguments will be required to be of the expected type. In applying this advice it might be wise to avoid forcing those hypotheses that are in fact just type predicates on the arguments, since the routine that applies type-prescription (TYPE-PRESCRIPTION^) lemmas has fairly thorough knowledge of the types of all terms.

Force can have the additional benefit of causing the ACL2 typing mechanism to interact with the ACL2 rewriter to establish the hypotheses of type-prescription (TYPE-PRESCRIPTION^) rules. To understand this remark, think of the ACL2 type reasoning system as a rather primitive rule-based theorem prover for questions about Common Lisp types, e.g., “does this expression produce a consp (CONSP^)?” “does this expression produce some kind of ACL2 number, e.g., an

integerp (INTEGERP^), a rationalp (RATIONALP^), or a complex-rationalp (COMPLEX-

RATIONALP^)?” etc. It is driven by type-prescription (TYPE-PRESCRIPTION^) rules. To relieve the hypotheses of such rules, the type system recursively invokes itself. This can be done for any hypothesis, whether it is “type-like” or not, since any proposition, p, can be phrased as the type-like question “does p produce an object of type nil?” However, as you might expect, the type system is not very good at establishing hypotheses that are not type-like, unless they happen to be assumed explicitly in the context in which the question is posed, e.g., “If p produces a consp (CONSP^) then does p produce nil?” If type reasoning alone is insufficient to prove some instance of a hypothesis, then the instance will not be proved by the type system and a typeprescription (TYPE-PRESCRIPTION^) rule with that hypothesis will be inapplicable in that case.

But by embedding such hypotheses in force expressions you can effectively cause the type system to “punt” them to the rest of the theorem prover. Of course, as already noted, this should only be done on hypotheses that are “always true.” In particular, if rewriting is required to establish some hypothesis of a type-prescription (TYPE-PRESCRIPTION^) rule, then the rule will be found inapplicable because the hypothesis will not be established by type reasoning alone.

The ACL2 rewriter uses the type reasoning system as a subsystem. It is therefore possible that the type system will force a hypothesis that the rewriter could establish. Before a forced hypothesis is reported out of the rewriter, we try to establish it by rewriting.

This makes the following surprising behavior possible: A type-prescription (TYPE-PRESCRIPTION^) rule fails to apply because some true hypothesis is not being relieved. The user changes the rule so as to force the hypothesis. The system then applies the rule but reports no forcing. How can this happen? The type system “punted” the forced hypothesis to the rewriter, which established it.

Finally, we should mention that the rewriter is never willing to force when there is an if (IF^) term present in the goal being simplified. Since and (AND^) and or (OR^) terms are merely abbreviations for if (IF^) terms, they also prevent forcing.

8.38 FORCING-ROUND

FORCING-ROUND a section of a proof dealing with force (FORCE^)d assumptions

If ACL2 “force (FORCE^)s” some hypothesis of some rule to be true, it is obliged later to prove the hypothesis. See Section 8.37 [FORCE], page 297. ACL2 delays the consideration of force (FORCE^)d hypotheses until the main goal has been proved. It then undertakes a new round of proofs in which the main goal is essentially the conjunction of all hypotheses force (FORCE^)d in the preceding proof. Call this round of proofs the “Forcing Round.” Additional hypotheses may be force (FORCE^)d by the proofs in the Forcing Round. The attempt to prove these hypotheses is delayed until the Forcing Round has been successfully completed. Then a new Forcing Round is undertaken to prove the recently force (FORCE^)d hypotheses and this continues until no hypotheses are force (FORCE^)d. Thus, there is a succession of Forcing Rounds.

The Forcing Rounds are enumerated starting from 1. The Goals and Subgoals of a Forcing Round are printed with the round’s number displayed in square brackets. Thus, "[1]Subgoal 1.3" means that the goal in question is Subgoal 1.3 of the 1st forcing round. To supply a hint for use in the proof of that subgoal, you should use the goal specifier "[1]Subgoal 1.3". See Section 8.40 [GOAL-SPEC], page 304.

When a round is successfully completed — and for these purposes you may think of the proof of the main goal as being the 0th forcing round — the system collects all of the assumptions force (FORCE^)d by the just-completed round. Here, an assumption should be thought of as an implication, (implies context hyp), where context describes the context in which hyp was assumed true. Before undertaking the proofs of these assumptions, we try to “clean them up” in an effort to reduce the amount of work required. This is often possible because the force (FORCE^)d assumptions are generated by the same rule being applied repeatedly in a given context.

For example, suppose the main goal is about some term (pred (xtrans i) i) and that some rule rewriting pred contains a force (FORCE^)d hypothesis that the first argument is a good-inputp. Suppose that during the proof of Subgoal 14 of the main goal, (good-inputp (xtrans i)) is force (FORCE^)d in a context in which i is an integerp (INTEGERP^) and x is a consp (CONSP^). (Note that x is irrelevant.) Suppose finally that during the proof of Subgoal 28, (good-inputp (xtrans i)) is force (FORCE^)d “again,” but this time in a context in which i is a rationalp (RATIONALP^) and x is a symbolp (SYMBOLP^). Since the force (FORCE^)d hypothesis does not mention x, we deem the contextual information about x to be irrelevant and discard it from both contexts. We are then left with two force (FORCE^)d assumptions: (implies (integerp

i) (good-inputp (xtrans i))) from Subgoal 14, and (implies (rationalp i) (good-inputp

(xtrans i))) from Subgoal 28. Note that if we can prove the assumption required by Subgoal 28 we can easily get that for Subgoal 14, since the context of Subgoal 28 is the more general. Thus, in the next forcing round we will attempt to prove just

     (implies (rationalp i) (good-inputp (xtrans i)))

and “blame” both Subgoal 14 and Subgoal 28 of the previous round for causing us to prove this.

By delaying and collecting the forced assumptions until the completion of the “main goal” we gain two advantages. First, the user gets confirmation that the “gist” of the proof is complete and that all that remains are “technical details.” Second, by delaying the proofs of the force (FORCE^)d assumptions ACL2 can undertake the proof of each assumption only once, no matter how many times it was force (FORCE^)d in the main goal.

In order to indicate which proof steps of the previous round were responsible for which force (FORCE^)d assumptions, we print a sentence explaining the origins of each newly force (FORCE^)d goal. For example,

     [1]Subgoal 1, below, will focus on
     (GOOD-INPUTP (XTRANS I)),
     which was forced in
      Subgoal 14, above,

       by applying (:REWRITE PRED-CRUNCHER) to
       (PRED (XTRANS I) I),
      and
      Subgoal 28, above,
       by applying (:REWRITE PRED-CRUNCHER) to
       (PRED (XTRANS I) I).

In this entry, “[1]Subgoal 1” is the name of a goal which will be proved in the next forcing round. On the next line we display the force (FORCE^)d hypothesis, call it x, which is (good-inputp (xtrans i)) in this example. This term will be the conclusion of the new subgoal. Since the new subgoal will be printed in its entirety when its proof is undertaken, we do not here exhibit the context in which x was force (FORCE^)d. The sentence then lists (possibly a succession of) a goal name from the just-completed round and some step in the proof of that goal that force (FORCE^)d x. In the example above we see that Subgoals 14 and 28 of the just-completed proof

force (FORCE^)d (good-inputp (xtrans i)) by applying (:rewrite pred-cruncher) to the
term (pred (xtrans i) i).

If one were to inspect the theorem prover’s description of the proof steps applied to Subgoals 14 and 28 one would find the word “force (FORCE^)d” (or sometimes “forcibly”) occurring in the commentary. Whenever you see that word in the output, you know you will get a subsequent forcing round to deal with the hypotheses force (FORCE^)d. Similarly, if at the beginning of a forcing round a rune (RUNE^) is blamed for causing a force (FORCE^) in some subgoal, inspection of the commentary for that subgoal will reveal the word “force (FORCE^)d” after the rule name blamed.

Most force (FORCE^)d hypotheses come from within the prover’s simplifier. When the simplifier encounters a hypothesis of the form (force hyp) it first attempts to establish it by rewriting hyp to, say, hyp'. If the truth or falsity of hyp' is known, forcing is not required. Otherwise, the simplifier actually force (FORCE^)s hyp'. That is, the x mentioned above is hyp', not hyp, when the force (FORCE^)d subgoal was generated by the simplifier.

Once the system has printed out the origins of the newly force (FORCE^)d goals, it proceeds to the next forcing round, where those goals are individually displayed and attacked.

At the beginning of a forcing round, the enable (ENABLE^)d structure defaults to the global enable (ENABLE^)d structure. For example, suppose some rune (RUNE^), rune, is globally enable (ENABLE^)d. Suppose in some event you disable (DISABLE^) the rune (RUNE^) at "Goal" and successfully prove the goal but force (FORCE^) "[1]Goal". Then during the proof of "[1]Goal", rune (RUNE^) is enable (ENABLE^)d “again.” The right way to think about this is that the rune (RUNE^) is “still” enable (ENABLE^)d. That is, it is enable (ENABLE^)d globally and each forcing round resumes with the global enable (ENABLE^)d structure.

8.39 GENERALIZED-BOOLEANS

GENERALIZED-BOOLEANS potential soundness issues related to ACL2 predicates

The discussion below outlines a potential source of unsoundness in ACL2. Although to our knowledge there is no existing Lisp implementation in which this problem can arise, nevertheless we feel compelled to explain this situation.

Consider for example the question: What is the value of (equal 3 3)? According to the ACL2 axioms, it’s t. And as far as we know, based on considerable testing, the value is t in every Common Lisp implementation. However, according the Common Lisp draft proposed ANSI standard, any non-nil value could result. Thus for example, (equal 3 3) is allowed by the standard to be 17.

The Common Lisp standard specifies (or soon will) that a number of Common Lisp functions that one might expect to return Boolean values may, in fact, return arbitrary values. Examples of such functions are equal (EQUAL^), rationalp (RATIONALP^), and < (<^); a much more complete list is given below. Indeed, we dare to say that every Common Lisp function that one may believe returns only Booleans is, nevertheless, not specified by the standard to have that property, with the exceptions of the functions not and null. The standard refers to such arbitrary values as “generalized Booleans,” but in fact this terminology makes no restriction on those values. Rather, it merely specifies that they are to be viewed, in an informal sense, as being either nil or not nil.

This situation is problematic for ACL2, which axiomatizes these functions to return Booleans. The problem is that because (for efficiency and simplicity) ACL2 makes very direct use of compiled Common Lisp functions to support the execution of its functions, there is in principle a potential for unsoundness due to these “generalized Booleans.” For example, ACL2’s equal (EQUAL^) function is defined to be Common Lisp’s equal. Hence if in Common Lisp the form (equal 3 3) were to evaluate to 17, then in ACL2 we could prove (using the :executable-counterpart (EXECUTABLE-COUNTERPART^) of equal (EQUAL^)) (equal (equal 3 3) 17). However, ACL2 can also prove (equal (equal x x) t), and these two terms together are contradictory, since they imply (instantiating x in the second term by 3) that (equal 3 3) is both equal to 17 and to t.

To make matters worse, the standard allows (equal 3 3) to evaluate to different non-nil values every time. That is: equal need not even be a function!

Fortunately, no existing Lisp implementation takes advantage of the flexibility to have (most of) its predicates return generalized Booleans, as far as we know. We may implement appropriate safeguards in future releases of ACL2, in analogy to (indeed, probably extending) the existing safeguards by way of guards (see Section 8.41 [GUARD], page 305). For now, we’ll sleep a bit better knowing that we have been up-front about this potential problem.

The following list of functions contains all those that are defined in Common Lisp to return generalized Booleans but are assumed by ACL2 to return Booleans. In addition, the functions acl2numberp (ACL2-NUMBERP^) and complex-rationalp (COMPLEX-RATIONALP^) are directly defined in terms of respective Common Lisp functions numberp and complexp.

/=
<
=
alpha-char-p
atom
char-equal
char<
char<=
char>
char>=
characterp
consp
digit-char-p
endp
eq
eql
equal
evenp
integerp
keywordp
listp
logbitp
logtest
lower-case-p
minusp
oddp
plusp
rationalp
standard-char-p
string-equal
string<
string<=
string>
string>=
stringp

subsetp
symbolp
upper-case-p
zerop

8.40 GOAL-SPEC

GOAL-SPEC to indicate where a hint is to be used

Examples:
"Goal"
"goal"
"Subgoal *1/3''"
"subgoal *1/3''"
"[2]Subgoal *1/3''"

When hints (HINTS^) are given to the theorem prover, a goal-spec is provided to specify the goal to which the hints (HINTS^) are to be applied. The hints (HINTS^) provided are carried along innocuously until the named goal arises. When it arises, the hints (HINTS^) are “activated” for that goal and its descendents.

A legal goal specification may be extracted from the theorem prover’s output. Certain lines clearly label formulas, as in

Subgoal *1/3.2'
(IMPLIES ... ...)

and these lines all give rise to goal specifications. In general, these lines all start either with “Goal” or “Subgoal” or else with those words preceded by a number in square brackets, as in

[1]Subgoal *1/3.2'
(IMPLIES ... ...).

A goal specification may be obtained by deleting any surrounding whitespace from such a line and embedding the text in string quotation marks. Thus

"[1]Subgoal *1/3.2'"

is the goal specifier for the goal above.

As noted, a hint is applied to a goal when the hint’s goal specification matches the name ACL2 assigns to the goal. The matching algorithm is case-insensitive. Thus, alternative goal specifications

for the goal above are "[1]subgoal *1/3.2'" and "[1]SUBGOAL *1/3.2'". The matching algo-

rithm does not tolerate non-case discrepancies. Thus, "[1]Subgoal*1/3.2'" and " [1]Subgoal *1/3.2'" are unacceptable.

Sometimes a formula is given two names, e.g.,

     Subgoal *1/14.2'
     (IMPLIES ...
              ...)
     Name the formula above *1.1.

It is the first name (the one that starts with “Goal” or “Subgoal”) and not the second which constitutes a legal goal-spec. Roughly speaking, when the system prints the line containing the goal specification, it activates any hints (HINTS^) that are attached to that goal-spec. Consider the example above. Suppose Subgoal *1/14.2' could be proved by using a certain lemma instance. Then the appropriate entry in the hints (HINTS^) would be:

     ("Subgoal *1/14.2'" :use ...)

This might surprise you because the system appears to do nothing to *1/14.2' besides push it for a subsequent induction. But actually between the time the system printed the goal-spec line and the time it decides to push the goal, you can think of the system as trying everything it has. So a use hint activated when Subgoal *1/14.2' arises is just what you want.

But what if you want to give an :induct hint? By the time induction is tried, the formula has been given the name *1.1. Well, this is one you just have to remember:

     ("Subgoal *1/14.2'" :induct ...).

When the above hint is activated the :induct directive short-circuits the rest of the processing and sends immediately the formula into the pool of goals to prove by induction. The induct hint is attached to the formula in the pool and when the time comes to turn our attention to that goal, the induct advice is followed.

8.41 GUARD

GUARD restricting the domain of a function

The ACL2 system provides a mechanism for restricting a function definition to a particular domain. Although such restrictions, which are called “guards,” are actually ignored by the ACL2 logic, they can be useful as a specification device or as a means of causing the execution of definitions directly in Common Lisp. To make such a restriction, use the :guard xarg to defun (DEFUN^). See Section 8.102 [XARGS], page 406 for a discussion of how to use :guard. The general issue of guards and guard verification is discussed in the topics listed below.

* GUARD-INTRODUCTION:: introduction to guard (GUARD^)s in ACL2

* GUARD-MISCELLANY:: miscellaneous remarks about guards

* GUARD-QUICK-REFERENCE:: brief summary of guard checking and guard verification

* GUARDS-AND-EVALUATION:: the relationship between guards and evaluation

* GUARDS-FOR-SPECIFICATION:: guards as a specification device

Related topics other than immediate subtopics:

* GUARD-EXAMPLE:: a brief transcript illustrating guard (GUARD^)s in ACL2

* SET-GUARD-CHECKING:: control checking guard (GUARD^)s during execution of top-level forms * SET-VERIFY-GUARDS-EAGERNESS:: the eagerness with which guard (GUARD^) verification is tried.

* VERIFY-GUARDS:: verify the guard (GUARD^)s of a function

To begin further discussion of guards, see Section 8.41.1 [GUARD-INTRODUCTION], page 306. That section directs the reader to further sections for more details. To see just a summary of some command (COMMAND^)s related to guards, see Section 8.41.3 [GUARD-QUICK-REFERENCE], page 308.

8.41.1 GUARD-INTRODUCTION

GUARD-INTRODUCTION introduction to guard (GUARD^)s in ACL2

Most users can probably profit by avoiding dealing with guards most of the time. If they seem to get in the way, they can be “turned off” using the command :set-guard-checking (SET-GUARD-CHECKING^) nil; for more about this, see Section 9.12 [SET-GUARD-CHECKING], page 423. For more about guards in general, see Section 8.41 [GUARD], page 305.

The guard on a function symbol is a formula about the formals of the function. To see the guard on a function, use the keyword command :args (ARGS^). See Section 5.2 [ARGS], page 140. To specify the guard on a function at defun-time, use the :guard (GUARD^) xarg. See Section 8.102 [XARGS], page 406.

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. Briefly: If the guards of a function definition are “verified” (see Section 6.39 [VERIFY-GUARDS], page 210), then the evaluation of a call of that function on arguments satisfying its guard will have the following property:

All subsequent function calls during that evaluation will be on arguments satisfying the guard of the called function.

The consequence of this fact for (a) is that your specification function is well-formed, in the sense that the values returned by this function on appropriate arguments only depend on the restrictions of the called functions to their intended domains. The consequence of this fact for (b) is that in the ACL2 system, when a function whose guards have been verified is called on arguments that satisfy its guard, then the raw lisp function defined by this functions’s defun (DEFUN^) event is used to evaluate the call. Note however that even when the user-supplied defun (DEFUN^) is not used, ACL2 uses a corresponding “executable counterpart” that generally performs, we expect, nearly as well as the raw lisp function. See Section 9.5 [COMP], page 415 to see how compilation (COMPILATION^) can speed up both kinds of execution.

Let us turn next to the issue of the relationship between guards and evaluation. See Section 8.41.4 [GUARDS-AND-EVALUATION], page 310.

8.41.2 GUARD-MISCELLANY

GUARD-MISCELLANY miscellaneous remarks about guards

The discussion of guards concludes here with a few miscellaneous remarks. (Presumably you found this documentation by following a link; see Section 8.41.5 [GUARDS-FOR-SPECIFICATION], page 316.) For further information related to guards other than what you find under “guard (GUARD^),” see any of the following documentation topics: guard-example (GUARD-EXAMPLE^),

set-verify-guards-eagerness (SET-VERIFY-GUARDS-EAGERNESS^), set-guard-checking

(SET-GUARD-CHECKING^), and verify-guards (VERIFY-GUARDS^).

Defun (DEFUN^) can be made to try to verify the guards on a function. This is controlled by the “defun-mode (DEFUN-MODE^)” of the defun (DEFUN^); see Section 8.20 [DEFUN-MODE], page 275. The defun-mode (DEFUN-MODE^) is either as specified with the :mode xarg of the defun (DEFUN^) or else defaults to the default defun-mode (DEFUN-MODE^). See Section 8.18 [DEFAULT-DEFUN-MODE], page 273. If the defun-mode (DEFUN-MODE^) of the defun (DE-FUN^) is :logic (LOGIC^) and either a :guard (GUARD^) is specified or :verify-guards (VERIFY-GUARDS^) t is specified in the xargs (XARGS^), then we attempt to verify the guards of the function. Otherwise we do not.

It is sometimes impossible for the system to verify the guards of a recursive function at definition time. For example, the guard conjectures might require the invention and proof of some inductively derived property of the function (as often happens when the value of a recursive call is fed to a guarded subroutine). So sometimes it is necessary to define the function using :verify-guards nil then to state and prove key theorems about the function, and only then have the system attempt guard verification. Post-defun (DEFUN^) guard verification is achieved via the event verify-guards (VERIFY-GUARDS^). See Section 6.39 [VERIFY-GUARDS], page 210.

It should be emphasized that guard verification affects only two things: how fast ACL2 can evaluate the function and whether the function is executed correctly by raw Common Lisp, without guard violations. Since ACL2 does not use the raw Common Lisp definition of a function to evaluate its calls unless that function’s guards have been verified, the latter effect is felt only if you run functions in raw Common Lisp rather than via ACL2’s command loop.

Guard verification does not otherwise affect the theorem prover or the semantics of a definition. If you are not planning on running your function on “big” inputs and you don’t care if your function runs correctly in raw Common Lisp (e.g., you have formalized some abstract mathematical property and just happened to use ACL2 as your language), there is no need to suffer through guard verification. Often users start by not doing guard verification and address that problem later. Sometimes you are driven to it, even in mathematical projects, because you find that you want to run your functions particularly fast or in raw Common Lisp.

If certify-book (CERTIFY-BOOK^) is used to compile a file, and the file contains functions with unverified guard conjectures, then you will be warned that the compiled file cannot be loaded into raw Common Lisp with the expectation that the functions will run correctly. This is just the same point we have been making: ACL2 and Common Lisp agree only on the restricted domains specified by our guards. When guards are violated, Common Lisp can do anything. When you call a compiled function on arguments violating its guards, the chances are only increased that Common Lisp will go berserk, because compiled functions generally check fewer things at runtime and tend to be more fragile than interpreted ones.

8.41.3 GUARD-QUICK-REFERENCE

GUARD-QUICK-REFERENCE brief summary of guard checking and guard verification For a careful introduction to guards, see Section 8.41 [GUARD], page 305. I. GUARD CHECKING DURING EXECUTION Effect Guards on definitions are checked at execution time (except for guards on subsidiary calls of recursive or mutually recursive functions). When does it happen By default, guards are checked for all forms submitted at the top level. To disable

:set-guard-checking nil

To (re-)enable

:set-guard-checking t

II. GUARD VERIFICATION Effect A proof is attempted of the obligations arising from the guards of subsidiary functions in a defun (DEFUN^), defthm (DEFTHM^), or defaxiom (DEFAXIOM^) event. When does it happen Only names of defined functions, defthm (DEFTHM^)s, and defaxiom (DEFAXIOM^)s are subject to guard verification. Guard verification may occur when functions are defined (using defun (DEFUN^)), but it requires an explicit call of verify-guards (VERIFY-GUARDS^) in order to verify guards for defthm (DEFTHM^)s and defaxiom (DEFAXIOM^)s. Constrained functions (see Section 6.18 [ENCAPSULATE], page 185) may not have their guards verified.

(verify-guards foo ...)

causes guard verification for the defun (DEFUN^), defthm (DEFTHM^), or defaxiom (DEFAX-IOM^) named by foo, if it has not already been successfully done. The default defun-mode (DEFUN-MODE^) (see Section 8.18 [DEFAULT-DEFUN-MODE], page 273) must be :logic (LOGIC^), or else this event is ignored.

(defun foo ...)

causes guard verification of foo if and only if the following conditions are both met. (However, see Section 6.34 [SET-VERIFY-GUARDS-EAGERNESS], page 202 for how to change this behavior.)

1. Foo is processed in :logic (LOGIC^) mode (either by setting mode :logic (LOGIC^) globally, or by including :mode :logic in the xargs (XARGS^) declaration).

2. The xargs (XARGS^) declaration (see Section 8.102 [XARGS], page 406) either specifies :guard (GUARD^) or specifies :verify-guards (VERIFY-GUARDS^) t (or both).

(verify-termination foo ...)

causes guard verification of foo if foo is a function currently defined in :program (PROGRAM^) mode and the appropriate xargs (XARGS^) are supplied, as discussed for the case of defun (DE-FUN^) above. The default defun-mode (DEFUN-MODE^) (see Section 8.18 [DEFAULT-DEFUN-MODE], page 273) must be :logic (LOGIC^), or else this event is ignored.

8.41.4 GUARDS-AND-EVALUATION

GUARDS-AND-EVALUATION the relationship between guards and evaluation

The guard has no effect on the logical axiom added by the definition of a function. It does, however, have consequences for how calls of that function are evaluated in ACL2. We begin by explaining those consequences, when ACL2 is in its default “mode,” i.e., as originally brought up. In subsequent discussion we’ll consider other ways that guards can interact with evaluation. For more about guards in general, see Section 8.41 [GUARD], page 305. Also see Section 8.39 [GENERALIZED-BOOLEANS], page 302 for discussion about a subtle issue in the evaluation of certain Common Lisp functions.

Guards and evaluation I: the default

Consider the following very simple definition.

     (defun foo (x) (cons 1 (cdr x)))

First consider how raw Common Lisp behaves when evaluating calls of this function. To evaluate (foo x) for some expression x, first x is evaluated to some value v, and then (cons 1 (cdr x)) is evaluated with x bound to v. For example, if v is (cons 'a 3), then Common Lisp computes (cons 1 3). But if (for example) v is a number, e.g., 7, then there is no way to predict what Common Lisp might do. Some implementations would cause “sensible” errors, others might return nonsense, still others might crash the host machine. The results tend toward the catastrophic if the call of foo in question is in compiled code.

Now by default, ACL2 evaluates calls of foo exactly as Common Lisp does, except that it uses guards to check the “legality” of each function call. So for example, since (cdr x) has a guard of (or (consp x) (equal x nil)), the call (foo 7) would cause a “guard violation,” as illustrated below.

     ACL2 !>(foo 7)
     ACL2 Error in TOP-LEVEL:  The guard for the function symbol CDR, which
     is (OR (CONSP X) (EQUAL X NIL)), is violated by the arguments in the
     call (CDR 7).
     ACL2 !>

Thus, the relation between evaluation in ACL2 and evaluation in Common Lisp is that the two produce the very same results, provided there is no guard violation.

Guards and evaluation II: :set-guard-checking (SET-GUARD-CHECKING^).

The ACL2 logic is a logic of total functions. That is, every application of a function defined has a completely specified result. See the documentation (DOCUMENTATION^) for each individual primitive for the specification of what it returns when its guard is violated; for example, see Section 10.70 [CDR], page 459.

The presence of guards thus introduces a choice in the sense of evaluation. When you type a form for evaluation do you mean for guards to be checked or not? Put another way, do you mean for the form to be evaluated in Common Lisp (if possible) or in the ACL2 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, the ACL2 logic definition of cdr (CDR^) implies that the cdr (CDR^) of an atom (ATOM^) is nil; see Section 10.70 [CDR], page 459. So: should (cdr 7) cause a guard violation error or return nil?

The top-level ACL2 loop has a variable which controls which sense of execution is provided. By default, “guard checking” is on, by which we mean that guards are checked at runtime, in the sense already described. To turn it off, do :set-guard-checking nil. To turn “guard checking” back on, execute the top-level form :set-guard-checking t. The status of this variable is reflected in the prompt (PROMPT^); guard-checking is “on” when the prompt (PROMPT^) contains an exclamation mark (also see Section 8.19 [DEFAULT-PRINT-PROMPT], page 274). For example,

     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. To return to our previous example: with guard checking off, (foo 7) evaluates to

(cons 1 nil).

Guards and evaluation III: guard verification

Consider the defininition of foo given above, but modified so that a reasonable guard of (consp x) is specified, as shown below.

     (defun foo (x)
       (declare (xargs :guard (consp x)))
       (cons 1 (cdr x)))

We say “reasonable guard” above because if x is such that (consp x) holds, then the call of cdr (CDR^) in the evaluation of (foo x) will not cause a guard violation. Thus, it “should” be legal to evaluate (foo x), for any such x, simply by evaluating this form in raw Common Lisp.

The verify-guards (VERIFY-GUARDS^) event has been provided for this purpose. Details may be found elsewhere; see Section 6.39 [VERIFY-GUARDS], page 210. Briefly, for any defined function fn, the event (verify-guards fn) attempts to check the condition discussed above, that whenever fn is called on arguments that satisfy its guard, the evaluation of this call will proceed without any guard violation. If this check is successful, then future calls of this sort will be evaluated in raw Common Lisp.

Returning to our example above, the (verify-guards foo) will succeed because the guard (consp x) of foo implies the guard generated from the call (cdr x) in the body of the definition, namely, (or (consp x) (equal x nil)) (see Section 10.70 [CDR], page 459). Then the evaluation of (foo (cons 'a 3)) will take place in raw Common Lisp, because (cons 'a 3) satisfies the guard

of foo.

This ability to dive into raw Common Lisp hinges on the proof that the guards you attach to your own functions are sufficient to insure that the guards encountered in the body are satisfied. This is called “guard verification.” Once a function has had its guards verified, then ACL2 can evaluate the function somewhat faster (but see “Guards and evaluation V: efficiency issues” below). Perhaps more importantly, ACL2 can also guarantee that the function will be evaluated correctly by any implementation of Common Lisp (provided the guard of the function is satisfied on the input). That is, if you have verified the guards of a system of functions and you have determined that they work as you wish in your host ACL2 (perhaps by proving it, perhaps by testing), then they will work identically in any Common Lisp.

There is a subtlety to our treatment of evaluation of calls of functions whose guards have been verified. If the function’s guard is not satisfied by such a call, then no further attempt is made to evaluate any call of that function in raw lisp during the course of evaluation of that call. This is obvious if guard checking is on, because an error is signalled the first time its guard is violated; but in fact it is also true when guard checking is off. See Section 1.5.6.2 [GUARD-EXAMPLE], page 60 for an example.

Guards and evaluation IV: functions having :program mode Strictly speaking, functions in :program (PROGRAM^) mode (see Section 8.20 [DEFUN-MODE], page 275) do not have definitions in the ACL2 logic. So what does it mean to evaluate calls of such functions in ACL2? Our decision is to treat :program (PROGRAM^) functions exactly as we treat :logic (LOGIC^) functions whose guards have been verified, except that when there is a guard violation we signal an error regardless of whether guard checking is currently on or off. Note that when the guard of a function in :logic (LOGIC^) mode is violated, there is still a value that the ACL2 logic proves is equal to the given call. But the same cannot be said for a function in :program (PROGRAM^) mode, so we really have no choice but to signal an error when there is a guard violation for such a function.

To summarize: as with :logic (LOGIC^) functions, when a guard has been satisfied on a call of a function with :program (PROGRAM^) mode, no subsidiary guard checking will be done.

Consider the same example foo as above, but where foo is submitted in :program (PROGRAM^) mode. Then even with guard checking off, top-level calls of foo will signal a guard violation when the arguments do not satisfy the guard of foo, e.g., (foo 7).

Notice that by treating functions in :program (PROGRAM^) mode like functions whose guards have been verified, we are using raw lisp to compute their values when their guards are met. We do not check guards any further once raw lisp is invoked. This can lead to hard lisp errors if the guards are not appropriate, as illustrated below.

     ACL2 >:program
     ACL2 p>(defun foo (x)
             (declare (xargs :guard t))
             (cons 1 (cdr x)))
     Summary
     Form:  ( DEFUN FOO ...)
     Rules: NIL
     Warnings:  None
     Time:  0.02 seconds (prove: 0.00, print: 0.00, proof tree: 0.00, other: 0.02)
      FOO
     ACL2 p>(foo 3)
     Error: 3 is not of type LIST.
     Fast links are on: do (use-fast-links nil) for debugging
     Error signalled by CDR.
     Broken at COND.  Type :H for Help.
     ACL2>>

See Section 8.21 [DEFUN-MODE-CAVEAT], page 278.

Guards and evaluation V: efficiency issues

We have seen that by verifying the guards for a :logic (LOGIC^) function, we arrange that raw lisp is used for evaluation of calls of such functions when the arguments satisfy its guard.

This has several apparent advantages over the checking of guards as we go. First, the savings is magnified as your system of functions gets deeper: the guard is checked upon the top-level entry to your system and then raw Common Lisp does all the computing. Second, if the raw Common Lisp is compiled, enormous speed-ups are possible. Third, if your Common Lisp or its compiler does such optimizations as tail-recursion removal, raw Common Lisp may be able to compute your functions on input much “bigger” than ACL2 can.

The first of these advantages is quite important if you have complicated guards. However, the other two advantages are probably not very important, as we now explain.

When a function is defined in :logic (LOGIC^) mode, its defun (DEFUN^) is executed in raw Common Lisp. (We might call this the “primary” raw lisp definition of the function.) However, a corresponding “logic definition” is also executed. The “logic definition” is a defun (DEFUN^) in raw lisp that checks guards at runtime and escapes to the primary raw lisp definition if the guard holds of the arguments and the function has already had its guards verified. Otherwise the logic definition executes the body of the function by calling the logic definitions of each subroutine. Now it is true that compilation (COMPILATION^) generally speeds up execution enormously. However, the :comp (COMP^) command (see Section 9.5 [COMP], page 415) compiles both of the raw lisp definitions associated with a :logic (LOGIC^) function. Also, we have attempted to arrange that for every tail recursion removal done on the actual defun (DEFUN^), a corresonding tail recursion removal is done on the “logic definition.”

We believe that in most cases, the logic definition executes almost as fast as the primary raw lisp definition, at least if the evaluation of the guards is fast. So, the main advantage of guard verification is probably that it lets you know that the function may be executed safely in raw lisp, returning the value predicted by the ACL2 logic, whenever its arguments satisfy its guard. We envision the development of systems of applicative lisp functions that have been developed and reasoned about using ACL2 but which are intended for evaluation in raw Common Lisp (perhaps with only a small “core” of ACL2 loaded), so this advantage of guard verification is important.

Nevertheless, guard verification might be important for optimal efficiency when the functions make use of type declarations. For example, at this writing, the GCL implementation of Common Lisp can often take great advantage of declare (DECLARE^) forms that assign small integer types to formal parameters.

To continue the discussion of guards, see Section 8.41.5 [GUARDS-FOR-SPECIFICATION], page 316 to read about the use of guards as a specification device.

8.41.5 GUARDS-FOR-SPECIFICATION

GUARDS-FOR-SPECIFICATION guards as a specification device

A use of guard verification that has nothing to do with efficiency is as a way to gain confidence in specifications. This use has the feel of “types” in many traditional programming (PROGRAM-MING^) languages, though guards allow much greater expressiveness than most systems of types (and unfortunately, as a result they are not syntactically checkable).

For more discussion of guards in general, see Section 8.41 [GUARD], page 305.

Suppose you have written a collection of function definitions that are intended to specify the behavior of some system. Perhaps certain functions are only intended to be called on certain sorts of inputs, so you attach guards to those functions in order to “enforce” that requirement. And then, you verify the guards for all those functions.

Then what have you gained, other than somewhat increased efficiency of execution (as explained above), which quite possibly isn’t your main concern? You have gained the confidence that when evaluating any call of a (specification) function whose arguments satisfy that function’s guard, all subsequent function calls during the course of evaluation will have this same property, that the arguments satisfy the guard of the calling function. In logical terms, we can say that the equality of the original call with the returned value is provable from weakened versions of the definitions, where each definitional axiom is replaced by an implication whose antecedent is the requirement that the arguments satisfy the guard and whose consequent is the original axiom. For example,

     (defun foo (x)
       (declare (xargs :guard (consp x)))
       (cons 1 (cdr x)))

originally generates the axiom

     (equal (foo x)
            (cons 1 (cdr x)))

but in fact, when evaluation involves no guard violation then the following weaker axiom suffices in the justification of the evaluation.

     (implies (consp x)
              (equal (foo x)
                     (cons 1 (cdr x))))

If you are following links to read this documentation as a hypertext style document, then please see Section 8.41.2 [GUARD-MISCELLANY], page 307. This concludes our discussion of guards with miscellaneous remarks, and also contains pointers to related topics.

8.42 HIDE

HIDE hide a term from the rewriter

Hide is actually the identity (IDENTITY^) function: (hide x) = x for all x. However, terms of the form (hide x) are ignored by the ACL2 rewriter, except when explicit :expand hints (HINTS^) are given for such terms (see Section 8.43 [HINTS], page 319) or when rewrite rules explicitly about hide are available. Hide terms are also ignored by the induction heuristics.

Sometimes the ACL2 simplifier inserts hide terms into a proof attempt out of the blue, as it were. Why and what can you do about it? Suppose you have a constrained function, say constrained-fn, and you define another function, say another-fn, in terms of it, as in:

     (defun another-fn (x y z)
       (if (big-hairy-test x y z)
           (constrained-fn x y z)
           t))

Suppose the term (another-fn 'a 'b 'c) arises in a proof. Since the arguments are all constants, ACL2 will try to reduce such a term to a constant by executing the definition of another-fn. However, after a possibly extensive computation (because of big-hairy-test) the execution fails because of the unevaluable call of constrained-fn. To avoid subsequent attempts to evaluate the term, ACL2 embeds it in a hide expression, i.e., rewrites it to (hide (another-fn 'a 'b 'c)).

You might think this rarely occurs since all the arguments of another-fn must be constants. You would be right except for one special case: if another-fn takes no arguments, i.e., is a constant function, then every call of it fits this case. Thus, if you define a function of no arguments in terms of a constrained function, you will often see (another-fn) rewrite to (hide (another-fn)).

We do not hide the term if the executable counterpart of the function is disabled – because we do not try to evaluate it in the first place. Thus, to prevent the insertion of a hide term into the proof attempt, you can globally disable the executable counterpart of the offending defined function, e.g.,

     (in-theory (disable (:executable-counterpart another-fn))).

It is conceivable that you cannot afford to do this: perhaps some calls of the offending function must be computed while others cannot be. One way to handle this situation is to leave the executable counterpart enabled, so that hide terms are introduced on the calls that cannot be computed, but prove explicit :rewrite (REWRITE^) rules for each of those hide terms. For example, suppose that in the proof of some theorem, thm, it is necessary to leave the executable counterpart of anotherfn enabled but that the call (another-fn 1 2 3) arises in the proof and cannot be computed. Thus the proof attempt will introduce the term (hide (another-fn 1 2 3)). Suppose that you can show that (another-fn 1 2 3) is (contrained-fn 1 2 3) and that such a step is necessary to the proof. Unfortunately, proving the rewrite rule

     (defthm thm-helper
       (equal (another-fn 1 2 3) (constrained-fn 1 2 3)))

would not help the proof of thm because the target term is hidden inside the hide. However,

     (defthm thm-helper
       (equal (hide (another-fn 1 2 3)) (constrained-fn 1 2 3)))

would be applied in the proof of thm and is the rule you should prove.

Now to prove thm-helper you need to use the two “tricks” which have already been discussed. First, to eliminate the hide term in the proof of thm-helper you should include the hint :expand (hide (another-fn 1 2 3)). Second, to prevent the hide term from being reintroduced when the system tries and fails to evaluate (another-fn 1 2 3) you should include the hint :in-theory

(disable (:executable-counterpart another-fn)). Thus, thm-helper will actually be:
     (defthm thm-helper
       (equal (hide (another-fn 1 2 3)) (constrained-fn 1 2 3))
       :hints
       (("Goal" :expand (hide (another-fn 1 2 3))
                :in-theory (disable (:executable-counterpart another-fn)))))

See Section 8.31 [EVISCERATE-HIDE-TERMS], page 290 for how to affect the printing of hide terms.

8.43 HINTS

HINTS advice to the theorem proving process

     Examples:
     The following :hints value is nonsensical.  Nevertheless, it
     illustrates all of the available hint keywords:
     :hints (("Goal"
              :do-not-induct t
              :do-not '(generalize fertilize)
              :expand ((assoc x a) (member y z))
              :restrict ((<-trans ((x x) (y (foo x)))))
              :hands-off (length binary-append)
              :in-theory (set-difference-theories
                           (current-theory :here)
                           '(assoc))
              :induct (and (nth n a) (nth n b))
              :use ((:instance assoc-of-append
                               (x a) (y b) (z c))
                    (:functional-instance
                      (:instance p-f (x a) (y b))
                      (p consp)
                      (f assoc)))
              :bdd (:vars (c a0 b0 a1 b1) :prove nil :bdd-constructors (cons))
              :cases ((true-listp a) (consp a))
              :by (:instance rev-rev (x (cdr z)))))

A very common hint is the :use hint, which in general takes as its value a list of “lemma instances” (see Section 8.61 [LEMMA-INSTANCE], page 342) but which allows a single lemma name as a special case:

     :hints (("[1]Subgoal *1/1.2'" :use lemma23))

ACL2 also provides “computed hints” for the advanced user. See Section 8.13 [COMPUTED-HINTS], page 263

Background: Hints are allowed in all events (EVENTS^) that use the theorem prover. During defun (DEFUN^) events (EVENTS^) there are two different uses of the theorem prover: one to prove termination and another to verify the guard (GUARD^)s. To pass a hint to the theorem prover during termination proofs, use the :hints keyword in the defun (DEFUN^)’s xargs (XARGS^) declaration. To pass a hint to the theorem prover during the guard (GUARD^) verification of defun (DEFUN^), use the :guard-hints keyword in the defun (DEFUN^)’s xargs (XARGS^) declaration. The verify-guards (VERIFY-GUARDS^) event and the defthm (DEFTHM^) event also use the theorem prover. To pass hints to them, use the :hints keyword argument to the event.

     General Form of Common :hints:
       ((goal-spec :key1 val1 ... :keyn valn)
        ...
        (goal-spec :key1 val1 ... :keyn valn))

where goal-spec (GOAL-SPEC^) is as described in the documentation for goal-spec (GOAL-SPEC^) and the keys and their respective values are shown below with their interpretations. (We also provide “computed hints” but discuss them separately; see Section 8.13 [COMPUTED-HINTS], page 263.)

:DO-NOT-INDUCT

Value is t, name or nil, indicating whether induction (INDUCTION^) is permitted under the specified goal. If value is t, then the attempt to apply induction (INDUCTION^) to the indicated goal or any subgoal under the indicated goal will immediately cause the theorem prover to report failure (FAILURE^). Thus, the indicated goal must be proved entirely by simplification, destructor elimination, and the other “waterfall” processes. Induction (INDUCTION^) to prove the indicated goal (or any subgoal) is not permitted. See however the :induct hint below. If value is a symbol other than t or nil, the theorem prover will give a “bye” to any subgoal that would otherwise be attacked with induction. This will cause the theorem prover to fail eventually but will collect the necessary subgoals. If value is nil, this hint means induction (INDUCTION^) is permitted. Since that is the default, there is no reason to use the value nil.

:DO-NOT

Value is a term having at most the single free variable world (WORLD^), which when evaluated (with world (WORLD^) bound to the current ACL2 logical world (WORLD^)) produces a list of symbols that is a subset of the list

     (preprocess ;propositional logic, simple rules
      simplify   ;as above plus rewriting, linear arithmetic
      eliminate-destructors
      fertilize  ;use of equalities
      generalize
      eliminate-irrelevance).

The hint indicates that the “processes” named should not be used at or below the goal in question. Thus, to prevent generalization and fertilization, say, include the hint

     :do-not '(generalize fertilize)

If value is a single symbol, as in

     :do-not generalize,

it is taken to be '(value).

:EXPAND

Value is a true list of terms, each of which is of one of the forms (let ((v1 t1)...) b) or (fn t1 ... tn), where fn is a defined function symbol with formals v1, ..., vn, and body b. Such a term is said to be “expandable:” it can be replaced by the result of substituting the ti’s for the vi’s in b. The terms listed in the :expand hint are expanded when they are encountered by the simplifier while working on the specified goal or any of its subgoals. We permit value to be a single such term instead of a singleton list. Note: Also allowed are “terms” of the form (:free (var1 var2 ... varn) pattern) where the indicated variables are distinct and pattern is a term. Such “terms” indicate that we consider the indicated variables to be instantiatable, in the following sense: whenever the simplifier encounters a term that can be obtained from pattern by instantiating the variables (var1 var2 ... varn), then it expands that term.

:HANDS-OFF

Value is a true list of function symbols or lambda expressions, indicating that under the specified goal applications of these functions are not to be rewritten. value may also be a single function symbol or lambda expression instead of a list.

:IN-THEORY (IN-THEORY^)

Value is a “theory expression,” i.e., a term having at most the single free variable world (WORLD^) which when evaluated (with world (WORLD^) bound to the current ACL2 logical world (see Section 8.100 [WORLD], page 399)) will produce a theory to use as the current theory for the goal specified. See Chapter 16 [THEORIES], page 775.

:INDUCT

Value is either t or a term containing at least one recursively defined function symbol; if t, this hint indicates that the system should proceed to apply its induction heuristic to the specified goal produced (without trying simplification, etc.); if value is a term other than t, then not only should the system apply induction immediately, but it should analyze value rather than the goal to generate its induction (INDUCTION^) scheme. Merging and the other induction (INDUCTION^) heuristics are applied. Thus, if value contains several mergeable induction (INDUCTION^)s, the “best” will be created and chosen. E.g., the :induct hint

      (and (nth i a) (nth j a))

suggests simultaneous induction (INDUCTION^) on i, j, and a.

If both an :induct and a :do-not-induct hint are supplied for a given goal then the indicated induction (INDUCTION^) is applied to the goal and the :do-not-induct hint is inherited by all subgoals generated.

:USE

Value is a lemma-instance (LEMMA-INSTANCE^) or a true list of lemma-instance (LEMMA-INSTANCE^)s, indicating that the propositions denoted by the instances be added as hypotheses to the specified goal. See Section 8.61 [LEMMA-INSTANCE], page 342. Note that :use makes the given instances available as ordinary hypotheses of the formula to be proved. The :instance form of a lemma-instance (LEMMA-INSTANCE^) permits you to instantiate the free variables of previously proved theorems any way you wish; but it is up to you to provide the appropriate instantiations because once the instances are added as hypotheses their variables are no longer instantiable. These new hypotheses participate fully in all subsequent rewriting, etc. If the goal in question is in fact an instance of a previously proved theorem, you may wish to use :by below.

:BDD (BDD^)

This hint indicates that ordered binary decision diagrams (BDDs) with rewriting are to be used to prove or simplify the goal. See Chapter 2 [BDD], page 71 for an introduction to the ACL2 BDD algorithm.

Value is a list of even length, such that every other element, starting with the first, is one of the keywords :vars, :bdd-constructors, :prove, or :literal. Each keyword that is supplied should be followed by a value of the appropriate form, as shown below; for others, a default is used. Although :vars must always be supplied, we expect that most users will be content with the defaults used for the other values.

:vars — A list of ACL2 variables, which are to be treated as Boolean variables. The prover must be able to check, using trivial reasoning (see Section 8.90 [TYPE-SET], page 383), that each of these variables is Boolean in the context of the current goal. Note that the prover will use very simple heuristics to order any variables that do not occur in :vars (so that they are “greater than” the variables that do occur in :vars), and these heuristics are often far from optimal. In addition, any variables not listed may fail to be assumed Boolean by the prover, which is likely to seriously impede the effectiveness of ACL2’s BDD algorithm. Thus, users are encouraged not to rely on the default order, but to supply a list of variables instead. Finally, it is allowed to use a value of t for vars. This means the same as a nil value, except that the BDD algorithm is directed to fail unless it can guarantee that all variables in the input term are known to be Boolean (in a sense discussed elsewhere; see Section 2.1 [BDD-ALGORITHM], page 71).

:literal — An indication of which part of the current goal should receive BDD processing. Possible values are:

       :all     treat entire goal as a single literal (the default)
       :conc    process the conclusion
       n        process the hypothesis with index n (1, 2, ...)

:bdd-constructors — When supplied, this value should be a list of function symbols in the current ACL2 world (WORLD^); it is (cons) by default, unless :bdd-constructors has a value in the acl2-defaults-table (ACL2-DEFAULTS-TABLE^) by default, in which case that value is the default. We expect that most users will be content with the default. See Section 2.1 [BDD-ALGORITHM], page 71 for information about how this value is used.

:prove — When supplied, this value should be t or nil; it is t by default. When the goal is not proved and this value is t, the entire proof will abort. Use the value nil if you are happy to the proof to go on with the simplified term.

:CASES

Value is a non-empty list of terms. For each term in the list, a new goal is created from the current goal by assuming that term; and also, in essence, one additional new goal is created by assuming all the terms in the list false. We say “in essence” because if the disjunction of the terms supplied is a tautology, then that final goal will be a tautology and hence will in fact never actually be created.

:BY

Value is a lemma-instance (LEMMA-INSTANCE^), nil, or a new event name. If the value is a lemma-instance (LEMMA-INSTANCE^) (see Section 8.61 [LEMMA-INSTANCE], page 342), then it indicates that the goal (when viewed as a clause) is subsumed by the proposition denoted by the instance (when viewed as a clause). To view a formula as a clause, union together the negations of the hypotheses and add the conclusion. For example,

     (IMPLIES (AND (h1 t1) (h2 t2)) (c t1))

may be viewed as the clause

     {~(h1 t1) ~(h2 t2) (c t1)}.

Clause c1 is “subsumed” by clause c2 iff some instance of c2 is a subset of c1. For example, the clause above is subsumed by {~(h1 x) (c x)}, which when viewed as a formula is (implies (h1

x) (c x)).

If the value is nil or a new name, the prover does not even attempt to prove the goal to which this hint is attached. Instead the goal is given a “bye”, i.e., it is skipped and the proof attempt continues as though the goal had been proved. If the prover terminates without error then it reports that the proof would have succeeded had the indicated goals been proved and it prints an appropriate defthm (DEFTHM^) form to define each of the :by names. The “name” nil means “make up a name.”

The system does not attempt to check the uniqueness of the :by names (supplied or made up), since by the time those goals are proved the namespace will be cluttered still further. Therefore, the final list of “appropriate” defthm (DEFTHM^) forms may be impossible to admit without some renaming by the user. If you must invent new names, remember to substitute the new ones for the old ones in the :by hints themselves.

:RESTRICT

(Warning: This is a sophisticated hint, intended for advanced users. This hint was suggested by Bishop Brock.)

Value is an association list. Its members are of the form (x subst1 subst2 ...), where: x is either (1) a rune (RUNE^) whose car (CAR^) is :rewrite (REWRITE^) or (2) an event name corresponding to one or more such rune (RUNE^)s; and (subst1 subst2 ...) is a nonempty list of substitutions, i.e., of association lists pairing variables with terms. First consider the case that x is a :rewrite (REWRITE^) rune (RUNE^). First recall that without this hint, the rewrite rule named x is used by matching its left-hand side (call it lhs) against the term currently being considered by the rewriter, that is, by attempting to find a substitution s such that the instantiation of lhs using s is equal to that term. If however the :restrict hint contains (x subst1 subst2 ...), then this behavior will be modified by restricting s so that it must extend subst1; and if there is no such s, then s is restricted so that it must extend subst2; and so on, until the list of substitutions is exhausted. If no such s is found, then the rewrite rule named x is not applied to that term. Finally, if x is an event name corresponding to one or more :rewrite (REWRITE^) rune (RUNE^)s (that is, x is the “base symbol” of such rune (RUNE^)s; see Section 16.10 [RUNE], page 784), say rune (RUNE^)s r1, ... rn, then the meaning is the same

except that (x subst1 subst2 ...) is replaced by (ri subst1 subst2 ...) for each i. Once

this replacement is complete, the hint may not contain two members whose car (CAR^) is the same rune (RUNE^).

Note that the substitutions in :restrict hints refer to the variables actually appearing in the goals, not to the variables appearing in the :rewrite (REWRITE^) rule being restricted.

Here is an example, supplied by Bishop Brock. Suppose that the database includes the following rewrite rule, which is probably kept disable (DISABLE^)d. (We ignore the question of how to prove this rule.)

     cancel-<-*$free:
     (implies (and (rationalp x)
                   (rationalp y)
                   (rationalp z))
              (equal (< y z)
                     (if (< x 0)
                         (> (* x y) (* x z))
                       (if (> x 0)
                           (< (* x y) (* x z))
                         (hide (< y z))))))

Then ACL2 can prove the following theorem (unless other rules get in the way), essentially by multiplying both sides by x.

(thm
  (implies (and (rationalp x)
                (< 1 x))
           (< (/ x) 1))
  :hints
  (("Goal"
    :in-theory (enable cancel-<-*$free)
    :restrict ((cancel-<-*$free ((x x) (y (/ x)) (z 1)))))))

The :restrict hint above says that the variables x, y, and z in the rewrite rule cancel-<-*$free above should be instantiated respectively by x, (/ x), and 1. Thus (< y z) becomes (< (/ x) 1), and this inequality is replaced by the corresponding instance of the right-hand-side of cancel- <-*$free. Since the current conjecture assumes (< 1 x), that instance of the right-hand side simplifies to

(< (* x (/ x)) (* x 1))

which in turn simplifies to (< 1 x), a hypothesis in the present theorem.

8.44 I-AM-HERE

I-AM-HERE a convenient marker for use with rebuild (REBUILD^)

Example Input File for Rebuild:
(defun fn1 (x y) ...)
(defthm lemma1 ...)
(defthm lemma2 ...)
(i-am-here)
The following lemma won't go through.  I started
typing the hint but realized I need to prove a
lemma first.  See the failed proof attempt in foo.bar.
I'm going to quit for the night now and resume tomorrow
from home.
(defthm lemma3 ...
  :hints (("Goal" :use (:instance ???
...

By putting an (i-am-here) form at the “frontier” of an evolving file of command (COMMAND^)s, you can use rebuild (REBUILD^) to load the file up to the (i-am-here). I-am-here simply returns an ld (LD^) error triple and any form that “causes an error” will do the same job. Note that the text of the file after the (i-am-here) need not be machine readable.

8.45 IMMEDIATE-FORCE-MODEP

IMMEDIATE-FORCE-MODEP when executable counterpart is enable (ENABLE^)d, force (FORCE^)d hypotheses are attacked immediately

This function symbol is defined simply to provide a rune (RUNE^) which can be enable (EN-ABLE^)d and disable (DISABLE^)d. Enabling

     (:executable-counterpart immediate-force-modep)

causes ACL2 to attack force (FORCE^)d hypotheses immediately instead of delaying them to the next forcing round.

     Example Hints
     :in-theory (disable (:executable-counterpart immediate-force-modep))
                ; delay forced hyps to forcing round
     :in-theory (enable (:executable-counterpart immediate-force-modep))
                ; split on forced hyps immediately

See Section 8.37 [FORCE], page 297 for background information. When a force (FORCE^)d hypothesis cannot be established a record is made of that fact and the proof continues. When the proof succeeds a “forcing round” is undertaken in which the system attempts to prove each of the force (FORCE^)d hypotheses explicitly. However, if the rune (RUNE^) (:executablecounterpart immediate-force-modep) is enable (ENABLE^)d at the time the hypothesis is force (FORCE^)d, then ACL2 does not delay the attempt to prove that hypothesis but undertakes the attempt more or less immediately.

8.46 IN-PACKAGE

IN-PACKAGE select current package

     (in-package "MY-PKG")
     General Form:
     (in-package str)

where str is a string that names an existing ACL2 package, i.e., one of the initial packages such as "KEYWORD" or "ACL2" or a package introduced with defpkg (DEFPKG^). For a complete list of the known packages created with defpkg (DEFPKG^), evaluate

     (strip-cars (known-package-alist state)).

See Section 6.11 [DEFPKG], page 173. In-package forms can only be typed at the top-level of the ACL2 loop and as the first form in a file being loaded or compiled.

8.47 INVISIBLE-FNS-ALIST

INVISIBLE-FNS-ALIST functions that are invisible to the loop-stopper (LOOP-STOPPER^) algorithm

     Examples:
     ACL2 !>(invisible-fns-alist (w state))
     ((binary-+ unary--)
      (binary-* unary-/)
      (unary-- unary--)
      (unary-/ unary-/))

Among other things, the setting above has the effect of making unary-- (UNARY–^) “invisible” for the purposes of applying permutative :rewrite (REWRITE^) rules to binary-+ (BINARY-+^) trees. See Section 6.30 [SET-INVISIBLE-FNS-ALIST], page 199.

The notion of “invisible functions” has to do with the control mechanism on permutative :rewrite (REWRITE^) rules. See Section 8.64 [LOOP-STOPPER], page 347 for a detailed discussion of the control mechanism. See Section 6.30 [SET-INVISIBLE-FNS-ALIST], page 199 for a discussion of how to set the invisible functions alist.

8.48 KEYWORD-COMMANDS

KEYWORD-COMMANDS how keyword commands are processed

     Examples:
     user type-in                 form evaluated
     :pc 5                        (ACL2::PC '5)
     :pcs app rev                 (ACL2::PCS 'app 'rev)
     :length (1 2 3)              (ACL2::LENGTH '(1 2 3))

When a keyword, :key, is read as a command, ACL2 determines whether the symbol with the same name in the "ACL2" package, acl2::key, is a function or simple macro of n arguments. If so, ACL2 reads n more objects, obj1, ..., objn, and then acts as though it had read the following form (for a given key):

     (ACL2::key 'obj1 ... 'objn)

Thus, by using the keyword command hack you avoid typing the parentheses, the "ACL2" package name, and the quotation marks.

Note the generality of this hack. Almost any function or macro in the "ACL2" package can be so invoked, not just “commands.” Indeed, there is no such thing as a distinguished class of commands. The one caveat is that the keyword hack can be used to invoke a macro only if that macro has a simple argument list — one containing no lambda keywords (such as &rest), since they complicate or render impossible the task of deciding how many objects to read. Users may take advantage of the keyword command hack by defining functions and macros in the "ACL2" package.

8.49 LD-ERROR-ACTION

LD-ERROR-ACTION determines ld (LD^)’s response to an error

Ld-error-action is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is

(ld-error-action state) and the updater is (set-ld-error-action val state). Ld-error-
action must be :continue, :return, or :error. The initial value of ld-error-action is

:continue, which means that the top-level ACL2 command (COMMAND^) loop will not exit when an error is caused by user-typein. But the default value for ld-error-action on calls of

ld (LD^) is :return.

The general-purpose ACL2 read-eval-print loop, ld (LD^), reads forms from standard-oi (STANDARD-OI^), evaluates them and prints the result to standard-co (STANDARD-CO^). However, there are various flags that control ld (LD^)’s behavior and ld-error-action is one of them. If, while ld-error-triples (LD-ERROR-TRIPLES^) is t, a form evaluates to three results, the first of which is non-nil and the third of which is state (STATE^), an error is said to have occurred. If an error occurs, ld (LD^)’s action depends on ld-error-action. If it is :continue, ld (LD^) just continues processing the forms in standard-oi (STANDARD-OI^). If it is :return, ld (LD^) stops and returns as though it had emptied the channel. If it is :error, ld (LD^) stops and returns, signalling an error to its caller.

8.50 LD-ERROR-TRIPLES

LD-ERROR-TRIPLES determines whether a form caused an error during ld (LD^)

Ld-error-triples is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is (ld-

error-triples state) and the updater is (set-ld-error-triples val state). Ld-error-

triples must be either t or nil. The initial value of ld-error-triples is t.

The general-purpose ACL2 read-eval-print loop, ld (LD^), reads forms from standard-oi (STANDARD-OI^), evaluates them and prints the result to standard-co (STANDARD-CO^). However, there are various flags that control ld (LD^)’s behavior and ld-error-triples is one of them. If this variable has the value t then when a form evaluates to 3 values, the first of which is non-nil and the third of which is state (STATE^), an error is deemed to have occurred. When an error occurs in evaluating a form, ld (LD^) rolls back the ACL2 world (WORLD^) to the configuration it had at the conclusion of the last error-free form. Then ld (LD^) takes the action determined by ld-error-action (LD-ERROR-ACTION^).

8.51 LD-EVISC-TUPLE

LD-EVISC-TUPLE determines whether ld (LD^) suppresses details when printing

Ld-evisc-tuple is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is (ld-

evisc-tuple state) and the updater is (set-ld-evisc-tuple val state). Ld-evisc-tuple

must be either nil or a list of the form

     (alist nil nil print-level print-length hiding-cars)

where alist is an alist that pairs objects to strings, print-level and print-length are either nil or non-negative integers, and hiding-cars is a list of symbols. The initial value of ld-evisc-tuple

is nil.

The general-purpose ACL2 read-eval-print loop, ld (LD^), reads forms from standard-oi (STANDARD-OI^), evaluates them and prints the result to standard-co (STANDARD-CO^). However, there are various flags that control ld (LD^)’s behavior and ld-evisc-tuple is one of them. Ld (LD^) may print the forms it is evaluating and/or the results of evaluation. If the value of ld-evisc-tuple is a list as shown above, then ld (LD^) “eviscerates” the objects it prints before printing them. To “eviscerate” an object we replace certain substructures within it by strings which are printed in their stead. Print-level and print-length, above, are used as described in CLTL (pp 372) to replace those substructures deeper than print-level by “#” and those longer than print-length by “...”. Alist is used to replace any substructure occuring as a key in alist by the corresponding string. Finally, any consp (CONSP^) x that starts with one of the symbols in hiding-cars is printed as <hidden>.

8.52 LD-KEYWORD-ALIASES

LD-KEYWORD-ALIASES allows the abbreviation of some keyword commands

     Example:
     (set-ld-keyword-aliases '((:q 0 q-fn)
                               (:e 0 exit-acl2-macro))
                             state)

Ld-keyword-aliases is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is

(ld-keyword-aliases state) and the updater is (set-ld-keyword-aliases val state). Ld-

keyword-aliases must be an alist, each element of which is of the form (:keyword n fn), where :keyword is a keyword, n is a nonnegative integer, and fn is a function symbol of arity n, a macro symbol, or a lambda expression of arity n. When keyword is typed as an ld (LD^) command, n more forms are read, x1, ..., xn, and the form (fn 'x1 ... 'xn) is then evaluated. The initial

value of ld-keyword-aliases is nil.

In the example above, :q (Q^) has been redefined to have the effect of executing (q-fn), so for example if you define

     (defmacro q-fn ()
       '(er soft 'q "You un-bound :q and now we have a soft error."))

then :q (Q^) will cause an error, and if you define

     (defmacro exit-acl2-macro () '(exit-ld state))

then :e will cause the effect (it so happens) that :q (Q^) normally has. If you prefer :e to :q (Q^) for exiting the ACL2 loop, you might even want to put such definitions of q-fn

and exit-acl2-macro together with the set-ld-keyword-aliases form above in your "acl2-

customization.lisp" file; see Section 8.4 [ACL2-CUSTOMIZATION], page 239.

The general-purpose ACL2 read-eval-print loop, ld (LD^), reads forms from standard-oi (STANDARD-OI^), evaluates them and prints the result to standard-co (STANDARD-CO^). However, there are various flags that control ld (LD^)’s behavior and ld-keyword-aliases is one of them. Ld-keyword-aliases affects how keyword commands are parsed. Generally speaking, ld (LD^)’s command interpreter reads “:fn x1 ... xn” as “(fn 'x1 ... 'xn)” when :fn is a keyword and fn is the name of an n-ary function. But this parse is overridden, as described above, for the keywords bound in ld-keyword-aliases.

8.53 LD-POST-EVAL-PRINT

LD-POST-EVAL-PRINT determines whether and how ld (LD^) prints the result of evaluation

Ld-post-eval-print is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is

(ld-post-eval-print state) and the updater is (set-ld-post-eval-print val state). Ld-
post-eval-print must be either t, nil, or :command-conventions. The initial value of ld-post-
eval-print is :command-conventions.

The general-purpose ACL2 read-eval-print loop, ld (LD^), reads forms from standard-oi (STANDARD-OI^), evaluates them and prints the result to standard-co (STANDARD-CO^). However, there are various flags that control ld (LD^)’s behavior and ld-post-eval-print is one of them. If this global variable is t, ld (LD^) prints the result. In the case of a form that produces multiple values, ld (LD^) prints the list containing them all (which, logically speaking, is what the form returned). If ld-post-eval-print is nil, ld (LD^) does not print the values. This is most useful when ld (LD^) is used to load a previously processed file.

Finally, if ld-post-eval-print is :command-conventions then ld (LD^) prints the result but

treats “error triples” specially. An “error triple” is a result, (mv erp val state), that consists of three values, the third of which is state (STATE^). Many ACL2 functions use such triples to signal errors. The convention is that if erp (the first value) is nil, then the function is returning val (the second value) as its conventional single result and possibly side-effecting state (STATE^) (as with some output). If erp is t, then an error has been caused, val is irrelevant and the error message has been printed in the returned state (STATE^). Example ACL2 functions that follow this convention include defun (DEFUN^) and in-package (IN-PACKAGE^). If such “error producing” functions are evaluated while ld-post-eval-print is set to t, then you would see them producing lists of length 3. This is disconcerting to users accustomed to Common Lisp (where these functions produce single results but sometimes cause errors or side-effect state (STATE^)).

When ld-post-eval-print is :command-conventions and a form produces an error triple (mv erp

val state) as its value, ld (LD^) prints nothing if erp is non-nil and otherwise ld (LD^) prints just val. Because it is a misrepresentation to suggest that just one result was returned, ld (LD^) prints the value of the global variable 'triple-print-prefix before printing val. 'triple-print-prefix is initially " ", which means that when non-erroneous error triples are being abbreviated to val, val appears one space off the left margin instead of on the margin.

In addition, when ld-post-eval-print is :command-conventions and the value component of an error triple is the keyword :invisible then ld (LD^) prints nothing. This is the way certain commands (e.g., :pc (PC^)) appear to return no value.

By printing nothing when an error has been signalled, ld (LD^) makes it appear that the error (whose message has already appeared in state (STATE^)) has “thrown” the computation back to load without returning a value. By printing just val otherwise, we suppress the fact that state (STATE^) has possibly been changed.

8.54 LD-PRE-EVAL-FILTER

LD-PRE-EVAL-FILTER determines which forms ld (LD^) evaluates

Ld-pre-eval-filter is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is

(ld-pre-eval-filter state) and the updater is (set-ld-pre-eval-filter val state). Ld-

pre-eval-filter must be either :all, :query, or a new name that could be defined (e.g., by defun (DEFUN^) or defconst (DEFCONST^)). The initial value of ld-pre-eval-filter is :all.

The general-purpose ACL2 read-eval-print loop, ld (LD^), reads forms from standard-oi (STANDARD-OI^), evaluates them and prints the result to standard-co (STANDARD-CO^). However, there are various flags that control ld (LD^)’s behavior and ld-pre-eval-filter is one of them. If the filter is :all, then every form read is evaluated. If the filter is :query, then after a form is read it is printed to standard-co (STANDARD-CO^) and the user is asked if the form is to be evaluated or skipped. If the filter is a new name, then all forms are evaluated until that name is introduced, at which time ld (LD^) terminates normally.

The :all filter is, of course, the normal one. :Query is useful if you want to replay selected the command (COMMAND^)s in some file. The new name filter is used if you wish to replay all the command (COMMAND^)s in a file up through the introduction of the given one.

8.55 LD-PRE-EVAL-PRINT

LD-PRE-EVAL-PRINT determines whether ld (LD^) prints the forms to be eval’d

Ld-pre-eval-print is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is

(ld-pre-eval-print state) and the updater is (set-ld-pre-eval-print val state). Ld-
pre-eval-print must be either t, nil, or :never. The initial value of ld-pre-eval-print is
nil.

The general-purpose ACL2 read-eval-print loop, ld (LD^), reads forms from standard-oi (STANDARD-OI^), evaluates them and prints the result to standard-co (STANDARD-CO^). However, there are various flags that control ld (LD^)’s behavior and ld-pre-eval-print is one of them. If this global variable is t, then before evaluating the form just read from standardoi (STANDARD-OI^), ld (LD^) prints the form to standard-co (STANDARD-CO^). If the variable is nil, no such printing occurs. The t option is useful if you are reading from a file of command (COMMAND^)s and wish to assemble a complete script of the session in standard-co (STANDARD-CO^).

The value :never of ld-pre-eval-print is rarely used. During the evaluation of encapsulate (ENCAPSULATE^) and of certify-book (CERTIFY-BOOK^) forms, subsidiary events are normally printed, even if ld-pre-eval-print is nil. Thus for example, when the user submits an encapsulate (ENCAPSULATE^) form, all subsidiary events are generally printed even in the default situation where ld-pre-eval-print is nil. But occasionally one may want to suppress such printing. In that case, ld-pre-eval-print should be set to :never.

8.56 LD-PROMPT

LD-PROMPT determines the prompt (PROMPT^) printed by ld (LD^)

Ld-prompt is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is (ld-prompt

state) and the updater is (set-ld-prompt val state). Ld-prompt must be either nil, t, or a

function symbol that, when given an open output character channel and state (STATE^), prints the desired prompt (PROMPT^) to the channel and returns two values: the number of characters (CHARACTERS^) printed and the state (STATE^). The initial value of ld-prompt is t.

The general-purpose ACL2 read-eval-print loop, ld (LD^), reads forms from standard-oi (STANDARD-OI^), evaluates them and prints the result to standard-co (STANDARD-CO^). However, there are various flags that control ld (LD^)’s behavior and ld-prompt is one of them. Ld-prompt determines whether ld (LD^) prints a prompt (PROMPT^) before reading the next form from standard-oi (STANDARD-OI^). If ld-prompt is nil, ld (LD^) prints no prompt (PROMPT^). If ld-prompt is t, the default prompt (PROMPT^) printer is used, which displays information that includes the current package, default defun-mode (DEFUN-MODE^), guard (GUARD^) checking status (on or off), and ld-skip-proofsp (LD-SKIP-PROOFSP^); see Section 8.19 [DEFAULT-PRINT-PROMPT], page 274.

If ld-prompt is neither nil nor t, then it should be a function name, fn, such that (fn channel state) will print the desired prompt (PROMPT^) to channel in state (STATE^) and return (mv col state), where col is the number of characters (CHARACTERS^) output (on the last line output). You may define your own prompt (PROMPT^) printing function.

If you supply an inappropriate prompt (PROMPT^) function, i.e., one that causes an error or does not return the correct number and type of results, the following odd prompt (PROMPT^) will be printed instead:

     Bad Prompt
     See :DOC ld-prompt>

which will lead you to this message. You should either call ld (LD^) appropriately next time or assign an appropriate value to ld-prompt.

8.57 LD-QUERY-CONTROL-ALIST

LD-QUERY-CONTROL-ALIST how to default answers to queries

Ld-query-control-alist is an ld (LD^) special (see Section 9.7 [LD], page 416). The acces-

sor is (ld-query-control-alist state) and the updater is (set-ld-query-control-alist val

state). Roughly speaking, ld-query-control-alist is either nil (meaning all queries should be interactive), t (meaning all should default to the first accepted response), or an alist that pairs query ids to keyword responses. The alist may end in either t or nil, indicating the default value for all ids not listed explicitly. Formally, the ld-query-control-alist must satisfy ld-query-control-alistp. The initial ld-query-control-alist is nil, which means all queries are handled interactively.

When an ACL2 query is raised, a unique identifying symbol is printed in parentheses after the word “Query”. This symbol, called the “query id,” can be used in conjunction with ld-query-control-alist to prevent the query from being handled interactively. By “handled interactively” we mean that the query is printed to *standard-co* (*STANDARD-CO*^) and a response is read from *standard-oi* (*STANDARD-OI*^). The alist can be used to obtain a “default value” for each query id. If this value is nil, then the query is handled interactively. In all other cases, the system handles the query without interaction (although text may be printed to standard-co (STANDARD-CO^) to make it appear that an interaction has occurred; see below). If the default value is t, the system acts as though the user responded to the query by typing the first response listed among the acceptable responses. If the default value is neither nil nor t, then it must be a keyword and one of the acceptable responses. In that case, the system acts as though the user responded with the given keyword.

Next, we discuss how the ld-query-control-alist assigns a default value to each query id. It assigns each id the first value paired with the id in the alist, or, if no such pair appears in the alist, it assigns the final cdr (CDR^) of the alist as the value. Thus, nil assigns all ids nil. T assigns

all ids t. '((:filter . nil) (:sysdef . :n) . t) assigns nil to the :filter query, :n to the

:sysdef query, and t to all others.

It remains only to discuss how the system prints text when the default value is not nil, i.e., when the query is handled without interaction. In fact, it is allowed to pair a query id with a singleton list containing a keyword, rather than a keyword, and this indicates that no printing is to be done. Thus for the example above, :sysdef queries would be handled noninteractively, with printing done to simulate the interaction. But if we change the example so that :sysdef is paired with

(:n), i.e., if ld-query-control-alist is '((:filter . nil) (:sysdef :n) . t), then no such

printing would take place for sysdef queries. Instead, the default value of :n would be assigned “quietly”.

8.58 LD-REDEFINITION-ACTION

LD-REDEFINITION-ACTION to allow redefinition without undoing

Ld-redefinition-action is an ld (LD^) special (see Section 9.7 [LD], page 416). The acces-

sor is (ld-redefinition-action state) and the updater is (set-ld-redefinition-action val

state). If ld-redefinition-action is non-nil then ACL2 is liable to be made unsafe or unsound by ill-considered definitions. The keyword command :redef (REDEF^) will set ld-redefinition-action to a convenient setting allowing unsound redefinition. See below.

When ld-redefinition-action is nil, redefinition is prohibited. In that case, an error message is printed upon any attempt to introduce a name that is already in use. There is one exception to this rule. It is permitted to redefine a function symbol in :program (PROGRAM^) mode to be a function symbol in :logic (LOGIC^) mode provided the formals and body remain the same. This is the standard way a function “comes into” logical existence.

Throughout the rest of this discussion we exclude from our meaning of “redefinition” the case in which a function in :program (PROGRAM^) mode is identically redefined in :logic (LOGIC^) mode. At one time, ACL2 freely permitted the signature (SIGNATURE^)-preserving redefinition of :program (PROGRAM^) mode functions but it no longer does. See Section 10.201 [REDEFINING-PROGRAMS], page 523.

When ld-redefinition-action is non-nil, you are allowed to redefine a name that is already in use. The system may be rendered unsound by such an act. It is important to understand how dangerous redefinition is. Suppose fn is a function symbol that is called from within some other function, say g. Suppose fn is redefined so that its arity changes. Then the definition of g is rendered syntactically ill-formed by the redefinition. This can be devastating since the entire ACL2 system assumes that terms in its data base are well-formed. For example, if ACL2 executes g by running the corresponding function in raw Common Lisp the redefinition of fn may cause raw lisp to break in irreparable ways. As Lisp programmers we live with this all the time by following the simple rule: after changing the syntax of a function don’t run any function that calls it via its old syntax. This rule also works in the context of the evaluation of ACL2 functions, but it is harder to follow in the context of ACL2 deductions, since it is hard to know whether the data base contains a path leading the theorem prover from facts about one function to facts about another. Finally, of course, even if the data base is still syntactically well-formed there is no assurance that all the rules stored in it are valid. For example, theorems proved about g survive the redefinition of fn but may have crucially depended on the properties of the old fn. In summary, we repeat the warning: all bets are off if you set ld-redefinition-action TO non-nil.

If at any point in a session you wish to see the list of all names that have been redefined, see Section 8.77 [REDEFINED-NAMES], page 360.

That said, we’ll give you enough rope to hang yourself. When ld-redefinition-action is nonnil, it must be a pair, (a . b). The value of a determines how the system interacts with you when a redefinition is submitted. The value of b allows you to specify how the property list of the redefined name is to be “renewed” before the redefinition.

There are several dimensions to the space of possibilities controlled by part a: Do you want to be queried each time you redefine a name, so you can confirm your intention? (We sometimes make typing mistakes or simply forget we have used that name already.) Do you want to see a warning stating that the name has been redefined? Do you want ACL2 system functions given special protection from possible redefinition? Below are the choices for part a:

:query — every attempt to redefine a name will produce a query. The query will allow you to abort the redefinition or proceed. It will will also allow you to specify the part b for this redefinition. :Query is the recommended setting for users who wish to dabble in redefinition.

:warn — any user-defined function may be redefined but a post-redefinition warning is printed. The attempt to redefine a system name produces a query. If you are prototyping and testing a big system in ACL2 this is probably the desired setting for part a.

:doit — any user-defined function may be redefined silently (without query or warning) but when an attempt is made to redefine a system function, a query is made. This setting is recommended when you start making massive changes to your prototyped system (and tire of even the warning messages issued by :warn).

In support of our own ACL2 systems programming (PROGRAMMING^) there are two other settings. We suggest ordinary users not use them.

:warn! — every attempt to redefine a name produces a warning but no query. Since ACL2 system functions can be redefined this way, this setting should be used by the only-slightly-less-than supremely confident ACL2 system hacker.

:doit! — this setting allows any name to be redefined silently (without query or warnings). ACL2 system functions are fair game. This setting is reserved for the supremely confident ACL2 system hacker. (Actually, this setting is used when we are loading massively modified versions of the ACL2 source files.)

Part b of ld-redefinition-action tells the system how to “renew” the property list of the name being redefined. There are two choices:

:erase — erase all properties stored under the name, or

:overwrite — preserve existing properties and let the redefining overwrite them.

It should be stressed that neither of these b settings is guaranteed to result in an entirely satisfactory state of affairs after the redefinition. Roughly speaking, :erase returns the property list of the name to the state it was in when the name was first introduced. Lemmas, type information, etc., stored under that name are lost. Is that what you wanted? Sometimes it is, as when the old definition is “completely wrong.” But other times the old definition was “almost right” in the sense that some of the work done with it is still (intended to be) valid. In that case, :overwrite might be the correct b setting. For example if fn was a function and is being re-defun (DEFUN^)’d with the same signature (SIGNATURE^), then the properties stored by the new defun (DEFUN^) should overwrite those stored by the old defun (DEFUN^) but the properties stored by defthm (DEFTHM^)s will be preserved.

The b setting is only used as the default action when no query is made. If you choose a setting for part a that produces a query then you will have the opportunity, for each redefinition, to specify whether the property list is to be erased or overwritten.

The keyword command :redef (REDEF^) sets ld-redefinition-action to the pair (:query . :overwrite). Since the resulting query will give you the chance to specify :erase instead of :overwrite, this setting is quite convenient. But when you are engaged in heavy-duty prototyping, you may wish to use a setting such as :warn or even :doit. For that you will have to invoke a form such as:

     (set-ld-redefinition-action '(:doit . :overwrite) state) .

Encapsulate (ENCAPSULATE^) causes somewhat odd interaction with the user if redefinition occurs within the encapsulation because the encapsulate (ENCAPSULATE^)d event list is processed several times. For example, if the redefinition action causes a query and a non-local definition is actually a redefinition, then the query will be posed twice, once during each pass. C’est la vie.

Finally, it should be stressed again that redefinition is dangerous because not all of the rules about a name are stored on the property list of the name. Thus, redefinition can render ill-formed terms stored elsewhere in the data base or can preserve now-invalid rules.

8.59 LD-SKIP-PROOFSP

LD-SKIP-PROOFSP how carefully ACL2 processes your command (COMMAND^)s

     Examples:
     ACL2 !>(set-ld-skip-proofsp t state)
      T
     ACL2 !s>(set-ld-skip-proofsp nil state)
      NIL

     ACL2 !>(set-ld-skip-proofsp 'include-book state)
      INCLUDE-BOOK
     ACL2 !s>

A global variable in the ACL2 state (STATE^), called 'ld-skip-proofsp, determines the thoroughness with which ACL2 processes your command (COMMAND^)s. This variable may take on one of three values: t, nil or 'include-book (INCLUDE-BOOK^). When ld-skip-proofsp is non-nil, the system assumes that which ought to be proved and is thus unsound. The form

(set-ld-skip-proofsp flg state) is the general-purpose way of setting ld-skip-proofsp. This

global variable is an “ld (LD^) special,” which is to say, you may call ld (LD^) in such a way as to “bind” this variable for the dynamic extent of the ld (LD^).

When ld-skip-proofsp is non-nil, the default prompt (PROMPT^) displays the character s. Thus, the prompt (PROMPT^)

     ACL2 !s>

means that the default defun-mode (DEFUN-MODE^) is :logic (LOGIC^) (otherwise the character p, for :program (PROGRAM^), would also be printed; see Section 8.19 [DEFAULT-PRINT-PROMPT], page 274) but “proofs are being skipped.”

Observe that there are two legal non-nil values, t and 'include-book (INCLUDE-BOOK^). When ld-skip-proofsp is t, ACL2 skips all proof obligations but otherwise performs all other required analysis of input events (EVENTS^). When ld-skip-proofsp is 'include-book (INCLUDE-BOOK^), ACL2 skips not only proof obligations but all analysis except that required to compute the effect of successfully executed events (EVENTS^). To explain the distinction, let us consider one particular event, say a defun (DEFUN^). Very roughly speaking, a defun (DEFUN^) event normally involves a check of the syntactic well-formedness of the submitted definition, the generation and proof of the termination conditions, and the computation and storage of various rules such as a :definition (DEFINITION^) rule and some :type-prescription (TYPE-PRESCRIPTION^) rules. By “normally” above we mean when ld-skip-proofsp is nil. How does a defun (DEFUN^) behave when ld-skip-proofsp is non-nil?

If ld-skip-proofsp is t, then defun (DEFUN^) performs the syntactic well-formedness checks and computes and stores the various rules, but it does not actually carry out the termination proofs. If ld-skip-proofsp is 'include-book (INCLUDE-BOOK^), defun (DEFUN^) does not do the syntactic well-formedness check nor does it carry out the termination proof. Instead, it merely computes and stores the rules under the assumption that the checks and proofs would all succeed. Observe that a setting of 'include-book (INCLUDE-BOOK^) is “stronger” than a setting of t in the sense that 'include-book (INCLUDE-BOOK^) causes defun (DEFUN^) to assume even more about the admissibility of the event than t does.

As one might infer from the choice of name, the include-book (INCLUDE-BOOK^) event sets ldskip-proofsp to 'include-book (INCLUDE-BOOK^) when processing the events (EVENTS^) in a book being loaded. Thus, include-book (INCLUDE-BOOK^) does the miminal work necessary to carry out the effects of every event in the book. The syntactic checks and proof obligations were, presumably, successfully carried out when the book was certified.

A non-nil value for ld-skip-proofsp also affects the system’s output messages. Event summaries (the paragraphs that begin “Summary” and display the event forms, rules used, etc.) are not printed when ld-skip-proofsp is non-nil. Warnings and observations are printed when ld-skip-proofsp is t but are not printed when it is 'include-book (INCLUDE-BOOK^).

Intuitively, ld-skip-proofsp t means skip just the proofs and otherwise do all the work normally required for an event; while ld-skip-proofsp 'include-book (INCLUDE-BOOK^) is “stronger” and means do as little as possible to process events (EVENTS^). In accordance with this intuition, local (LOCAL^) events (EVENTS^) are processed when ld-skip-proofsp is t but are skipped

when ld-skip-proofsp is 'include-book (INCLUDE-BOOK^).

The ACL2 system itself uses only two settings, nil and 'include-book (INCLUDE-BOOK^), the latter being used only when executing the events (EVENTS^) inside of a book being included. The ld-skip-proofsp setting of t is provided as a convenience to the user. For example, suppose one has a file of events (EVENTS^). By loading it with ld (LD^) with ld-skip-proofsp set to t, the events (EVENTS^) can all be checked for syntactic correctness and assumed without proof. This is a convenient way to recover a state lost by a system crash or to experiment with a modification of an events (EVENTS^) file.

The foregoing discussion is actually based on a lie. ld-skip-proofsp is allowed two other values,

'initialize-acl2 and 'include-book-with-locals. The first causes behavior similar to t but

skips local (LOCAL^) events (EVENTS^) and avoids some error checks that would otherwise prevent ACL2 from properly booting. The second is identical to 'include-book (INCLUDE-BOOK^) but also executes local (LOCAL^) events (EVENTS^). These additional values are not intended for use by the user, but no barriers to their use have been erected.

We close by reminding the user that ACL2 is potentially unsound if ld-skip-proofsp is ever set by the user. We provide access to it simply to allow experimentation and rapid reconstruction of lost or modified logical world (WORLD^)s.

8.60 LD-VERBOSE

LD-VERBOSE determines whether ld (LD^) prints “ACL2 Loading ...”

Ld-verbose is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is (ld-verbose

state) and the updater is (set-ld-verbose val state). Ld-verbose must be t, nil or a string

or consp (CONSP^) suitable for fmt (FMT^) printing via the ~@ command. The initial value of ld-verbose is a fmt (FMT^) message that prints the ACL2 version number, ld (LD^) level and connected book directory.

Before processing the forms in standard-oi (STANDARD-OI^), ld (LD^) may print a header. The printing of this header is controlled by ld-verbose. If ld-verbose is nil, no header is printed. If it is t, ld (LD^) prints the message

        ACL2 loading <file>

where <file> is the input channel supplied to ld (LD^). A similar message is printed when ld (LD^) completes. If ld-verbose is neither t nor nil then it is presumably a header and is printed with the ~@ fmt (FMT^) directive before ld (LD^) begins to read and process forms. In this case the ~@ fmt (FMT^) directive is interpreted in an environment in which #\v is the ACL2 version string, #\l is the level of the current recursion in ld (LD^) and/or wormhole (WORMHOLE^), and #\c is the connected book directory (cbd).

8.61 LEMMA-INSTANCE

LEMMA-INSTANCE an object denoting an instance of a theorem

Lemma instances are the objects one provides via :use and :by hints (HINTS^) (see Section 8.43 [HINTS], page 319) to bring to the theorem prover’s attention some previously proved or easily provable fact. A typical use of the :use hint is given below. The value specified is a list of five lemma instances.

     :use (reverse-reverse
           (:type-prescription app)
           (:instance assoc-of-app
                      (x a) (y b) (z c))
           (:functional-instance p-f
                                 (p consp) (f flatten))
           (:instance (:theorem (equal x x))

                      (x (flatten a))))

Observe that an event name can be a lemma instance. The :use hint allows a single lemma instance to be provided in lieu of a list, as in:

     :use reverse-reverse

or

     :use (:instance assoc-of-app (x a) (y b) (z c))

A lemma instance denotes a formula which is either known to be a theorem or which must be proved to be a theorem before it can be used. To use a lemma instance in a particular subgoal, the theorem prover adds the formula as a hypothesis to the subgoal before the normal theorem proving heuristics are applied.

A lemma instance, or lmi, is of one of the following five forms:

(1) name, where name names a previously proved theorem, axiom, or definition and denotes the formula (theorem) of that name.

(2) rune, where rune is a rune (RUNE^) (see Section 16.10 [RUNE], page 784) denoting the :corollary (COROLLARY^) justifying the rule named by the rune (RUNE^).

(3) (:theorem term), where term is any term alleged to be a theorem. Such a lemma instance denotes the formula term. But before using such a lemma instance the system will undertake to prove term.

(4) (:instance lmi (v1 t1) ... (vn tn)), where lmi is recursively a lemma instance, the vi’s are distinct variables and the ti’s are terms. Such a lemma instance denotes the formula obtained by instantiating the formula denoted by lmi, replacing each vi by ti.

(5) (:functional-instance lmi (f1 g1) ... (fn gn)), where lmi is recursively a lemma in-

stance and each fi is an “instantiable” function symbol of arity ni and gi is a function symbol or a pseudo-lambda expression of arity ni. An instantiable function symbol is any defined or constrained function symbol except the primitives not (NOT^), member (MEMBER^), implies (IMPLIES^), and e0-ord-< (E0-ORD-<^), and a few others, as listed by the constant *non-instantiable-primitives*. These are built-in in such a way that we cannot recover the constraint (CON-STRAINT^)s on them. A pseudo-lambda expression is an expression of the form (lambda (v1 ... vn) body) where the vi are distinct variable symbols and body is any term. No a priori relation is imposed between the vi and the variables of body, i.e., body may ignore some vi’s and may contain “free” variables. However, we do not permit v to occur freely in body if the functional substitution is to be applied to any formula (lmi or the constraint (CONSTRAINT^)s to be satisfied) that contains v as a variable. This is our draconian restriction to avoid capture. If you happen to violate this restriction by choosing a v that does occur, say in one of the relevant constraint (CONSTRAINT^)s, an informative error message will be printed. That message will list for you the illegal choices for v in the context in which the functional substitution is offered. A :functional-substitution lemma instance denotes the formula obtained by functionally instantiating the formula denoted by lmi, replacing fi by gi. However, before such a lemma instance can be used, the system will undertake to prove that the gi’s satisfy the constraints (see Section 8.14 [CONSTRAINT], page 265) on the fi’s. Any such constraint (CONSTRAINT^) that was generated and proved by ACL2 on behalf of a previously-proved event will be considered proved.

8.62 LOCAL-INCOMPATIBILITY

LOCAL-INCOMPATIBILITY when non-local events (EVENTS^) won’t replay in isolation

Sometimes a “local (LOCAL^) incompatibility” is reported while attempting to embed some events (EVENTS^), as in an encapsulate (ENCAPSULATE^) or include-book (INCLUDE-BOOK^). This is generally due to the use of a locally defined name in a non-local event or the failure to make a witnessing definition local (LOCAL^).

Local (LOCAL^) incompatibilities may be detected while trying to execute the strictly non-local events (EVENTS^) of an embedding. For example, encapsulate (ENCAPSULATE^) operates by first executing all the events (EVENTS^) (local (LOCAL^) and non-local) with ld-skip-proofsp (LD-SKIP-PROOFSP^) nil, to confirm that they are all admissible. Then it attempts merely to assume the non-local ones to create the desired theory, by executing the events (EVENTS^) with ld-skip-proofsp (LD-SKIP-PROOFSP^) set to 'include-book (INCLUDE-BOOK^). Similarly, include-book (INCLUDE-BOOK^) assumes the non-local ones, with the understanding that a previously successful certify-book (CERTIFY-BOOK^) has performed the admissiblity check.

How can a sequence of events (EVENTS^) admitted with ld-skip-proofsp (LD-SKIP-PROOFSP^) nil fail when ld-skip-proofsp (LD-SKIP-PROOFSP^) is 'include-book (INCLUDE-BOOK^)? The key observation is that in the latter case only the non-local events (EVENTS^) are processed. The local (LOCAL^) ones are skipped and so the non-local ones must not depend upon them.

Two typical mistakes are suggested by the detection of a local (LOCAL^) incompatibility: (1) a locally defined function or macro was used in a non-local (LOCAL^) event (and, in the case of encapsulate (ENCAPSULATE^), was not included among the signature (SIGNATURE^)s) and (2) the witnessing definition of a function that was included among the signature (SIGNATURE^)s of an encapsulate (ENCAPSULATE^) was not made local (LOCAL^).

An example of mistake (1) would be to include among your encapsulate (ENCAPSULATE^)d

events (EVENTS^) both (local (defun fn ...)) and (defthm lemma (implies (fn ...)

...)). Observe that fn is defined locally but a formula involving fn is defined non-locally. In this case, either the defthm (DEFTHM^) should be made local (LOCAL^) or the defun (DEFUN^) should be made non-local.

An example of mistake (2) would be to include (fn (x) t) among your signature (SIGNATURE^)s and then to write (defun fn (x) ...) in your events (EVENTS^), instead of (local (defun fn

...)).

One subtle aspect of encapsulate (ENCAPSULATE^) is that if you constrain any member of a mutually recursive clique you must define the entire clique locally and then you must constrain those members of it you want axiomatized non-locally.

Errors due to local (LOCAL^) incompatibility should never occur in the assumption of a fully certified book. Certification insures against it. Therefore, if include-book (INCLUDE-BOOK^) reports an incompatibility, we assert that earlier in the processing of the include-book (INCLUDE-BOOK^) a warning was printed advising you that some book was uncertified. If this is not the case — if include-book (INCLUDE-BOOK^) reports an incompatibility and there has been no prior warning about lack of certification — please report it to us.

When a local (LOCAL^) incompatibility is detected, we roll-back to the world (WORLD^) in which we started the encapsulate (ENCAPSULATE^) or include-book (INCLUDE-BOOK^). That is, we discard the intermediate world (WORLD^) created by trying to process the events (EVENTS^) skipping proofs. This is clean, but we realize it is very frustrating because the entire sequence of events (EVENTS^) must be processed from scratch. Assuming that the embedded events (EVENTS^) were, once upon a time, processed as top-level command (COMMAND^)s (after all, at some point you managed to create this sequence of command (COMMAND^)s so that the local (LOCAL^) and non-local ones together could survive a pass in which proofs were done), it stands to reason that we could define a predicate that would determine then, before you attempted to embed them, if local (LOCAL^) incompatibilities exist. We hope to do that, eventually.

8.63 LOGICAL-NAME

LOGICAL-NAME a name created by a logical event

     Examples:
     assoc
     caddr
     +
     "ACL2-USER"
     "arith"
     "project/task-1/arith.lisp"
     :here

A logical name is either a name introduced by some event, such as defun (DEFUN^), defthm (DEFTHM^), or include-book (INCLUDE-BOOK^), or else is the keyword :here, which refers to the most recent such event. See Chapter 6 [EVENTS], page 161. Every logical name is either a symbol or a string. For the syntactic rules on names, see Section 8.67 [NAME], page 352. The symbols name functions, macros, constants, axioms, theorems, labels, and theories (THEORIES^). The strings name packages or books (BOOKS^). We permit the keyword symbol :here to be used as a logical name denoting the most recently completed event.

The logical name introduced by an include-book (INCLUDE-BOOK^) is the full book name string for the book (see Section 3.7 [FULL-BOOK-NAME], page 108). Thus, under the appropriate setting for the current book directory (see Section 3.4 [CBD], page 102) the event (include-book "arith") may introduce the logical name

     "/usr/home/smith/project/task-1/arith.lisp" .

Under a different cbd (CBD^) setting, it may introduce a different logical name, perhaps

     "/local/src/acl2/library/arith.lisp" .

It is possible that identical include-book (INCLUDE-BOOK^) events forms in a session introduce two different logical names because of the current book directory.

A logical name that is a string is either a package name or a book name. If it is not a package name, we support various conventions to interpret it as a book name. If it does not end with the string ".lisp" we extend it appropriately. Then, we search for any book name that has the given logical name as a terminal substring. Suppose (include-book "arith") is the only include-

book (INCLUDE-BOOK^) so far and that "/usr/home/smith/project/task-1/arith.lisp"

is the source file it processed. Then "arith", "arith.lisp" and "task-1/arith.lisp" are

all logical names identifying that include-book (INCLUDE-BOOK^) event (unless they are package names). Now suppose a second (include-book "arith") is executed and processes

"/local/src/acl2/library/arith.lisp". Then "arith" is no longer a logical name, because it

is ambiguous. However, "task-1/arith" is a logical name for the first include-book (INCLUDE-BOOK^) and "library/arith" is a logical name for the second. Indeed, the first can be named

by "1/arith" and the second by "y/arith".

Logical names are used primarily in the theory manipulation functions, e.g., universal-theory (UNIVERSAL-THEORY^) and current-theory (CURRENT-THEORY^) with which you may obtain some standard theories (THEORIES^) as of some point in the historical past. The reference points are the introductions of logical names, i.e., the past is determined by the events (EVENTS^) it contains. One might ask, “Why not discuss the past with the much more flexible language of command (COMMAND^) descriptors?” (See Section 8.12 [COMMAND-DESCRIPTOR], page 261.) The reason is that inside of such events (EVENTS^) as encapsulate (ENCAPSULATE^) or macro command (COMMAND^)s that expand to progn (PROGN^)s of events (EVENTS^), command (COMMAND^) descriptors provide too coarse a grain.

When logical names are used as referents in theory expressions used in books (BOOKS^), one must consider the possibility that the defining event within the book in question becomes redundant by the definition of the name prior to the assumption of the book. See Section 8.78 [REDUNDANT-EVENTS], page 361.

8.64 LOOP-STOPPER

LOOP-STOPPER limit application of permutative rewrite rules

See Chapter 15 [RULE-CLASSES], page 723 for a discussion of the syntax of the :loop-stopper field of :rewrite (REWRITE^) rule-classes. Here we describe how that field is used, and also how that field is created when the user does not explicitly supply it.

For example, the built-in :rewrite (REWRITE^) rule commutativity-of-+,

     (implies (and (acl2-numberp x)
                   (acl2-numberp y))
              (equal (+ x y) (+ y x))),

creates a rewrite rule with a loop-stopper of ((x y binary-+)). This means, very roughly, that the term corresponding to y must be “smaller” than the term corresponding to x in order for this rule to apply. However, the presence of binary-+ (BINARY-+^) in the list means that certain functions that are “invisible” with respect to binary-+ (BINARY-+^) (by default, unary-- (UNARY–^) is the only such function) are more or less ignored when making this “smaller” test. We are much more precise below.

Our explanation of loop-stopping is in four parts. First we discuss ACL2’s notion of “term order.” Next, we bring in the notion of “invisibility”, and use it together with term order to define orderings on terms that are used in the loop-stopping algorithm. Third, we describe that algorithm. These topics all assume that we have in hand the :loop-stopper field of a given rewrite rule; the fourth and final topic describes how that field is calculated when it is not supplied by the user.

ACL2 must sometimes decide which of two terms is syntactically simpler. It uses a total ordering on terms, called the “term order.” Under this ordering constants such as '(a b c) are simpler than terms containing variables such as x and (+ 1 x). Terms containing variables are ordered according to how many occurrences of variables there are. Thus x and (+ 1 x) are both simpler than (cons x x) and (+ x y). If variable counts do not decide the order, then the number of function applications are tried. Thus (cons x x) is simpler than (+ x (+ 1 y)) because the latter has one more function application. Finally, if the number of function applications do not decide the order, a lexicographic ordering on Lisp objects is used. See Section 8.88 [TERM-ORDER], page 379 for details.

When the loop-stopping algorithm is controlling the use of permutative :rewrite (REWRITE^) rules it allows term1 to be moved leftward over term2 only if term1 is smaller, in a suitable sense. Note: The sense used in loop-stopping is not the above explained term order but a more complicated ordering described below. The use of a total ordering stops rules like commutativity from looping indefinitely because it allows (+ b a) to be permuted to (+ a b) but not vice versa, assuming a is smaller than b in the ordering. Given a set of permutative rules that allows arbitrary permutations of the tips of a tree of function calls, this will normalize the tree so that the smallest argument is leftmost and the arguments ascend in the order toward the right. Thus, for example, if the same argument appears twice in the tree, as x does in the binary-+ (BINARY-+^) tree denoted by the term (+ a x b x), then when the allowed permutations are done, all occurrences of the duplicated argument in the tree will be adjacent, e.g., the tree above will be normalized to (+ a b x x).

Suppose the loop-stopping algorithm used term order, as noted above, and consider the binary-+ (BINARY-+^) tree denoted by (+ x y (- x)). The arguments here are in ascending term order already. Thus, no permutative rules are applied. But because we are inside a +-expression it is very convenient if x and (- x) could be given virtually the same position in the ordering so that y is not allowed to separate them. This would allow such rules as (+ i (- i) j) = j to be applied. In support of this, the ordering used in the control of permutative rules allows certain unary functions, e.g., the unary minus function above, to be “invisible” with respect to certain “surrounding” functions, e.g., + (+^) function above.

Briefly, a unary function symbol fn1 is invisible with respect to a function symbol fn2 if fn2 belongs to the value of fn1 in invisible-fns-alist (INVISIBLE-FNS-ALIST^); also see Section 6.30 [SET-INVISIBLE-FNS-ALIST], page 199, which explains its format and how it can be set by the user. Roughly speaking, “invisible” function symbols are ignored for the purposes of the term-order test.

Consider the example above, (+ x y (- x)). The translated version of this term is (binary-+

x (binary-+ y (unary-- x))). The initial invisible-fns-alist (INVISIBLE-FNS-ALIST^)

makes unary-- (UNARY–^) invisible with repect to binary-+ (BINARY-+^). The commutativity rule for binary-+ (BINARY-+^) will attempt to swap y and (unary-- x) and the loop-stopping algorithm is called to approve or disapprove. If term order is used, the swap will be disapproved. But term order is not used. While the loop-stopping algorithm is permuting arguments inside a binary-+ (BINARY-+^) expression, unary-- (UNARY–^) is invisible. Thus, insted of comparing y with (unary-- x), the loop-stopping algorithm compares y with x, approving the swap because x comes before y.

Here is a more precise specification of the total order used for loop-stopping with respect to a list, fns, of functions that are to be considered invisible. Let x and y be distinct terms; we specify when “x is smaller than y with respect to fns.” If x is the application of a unary function symbol that belongs to fns, replace x by its argument. Repeat this process until the result is not the application of such a function; let us call the result x-guts. Similarly obtain y-guts from y. Now if x-guts is the same term as y-guts, then x is smaller than y in this order iff x is smaller than y in the standard term order. On the other hand, if x-guts is different than y-guts, then x is smaller than y in this order iff x-guts is smaller than y-guts in the standard term order.

Now we may describe the loop-stopping algorithm. Consider a rewrite rule with conclusion (equiv lhs rhs) that applies to a term x in a given context; see Section 15.14 [REWRITE], page 764. Suppose that this rewrite rule has a loop-stopper field (technically, the :heuristic-info field) of ((x1 y1 . fns-1) ... (xn yn . fns-n)). (Note that this field can be observed by using the command :pr (PR^) with the name of the rule; see Section 7.11 [PR], page 224.) We describe when rewriting is permitted. The simplest case is when the loop-stopper list is nil (i.e., n is 0); in that case, rewriting is permitted. Otherwise, for each i from 1 to n let xi' be the actual term corresponding to the variable xi when lhs is matched against the term to be rewritten, and similarly correspond yi' with y. If xi' and yi' are the same term for all i, then rewriting is not permitted. Otherwise, let k be the least i such that xi' and yi' are distinct. Let fns be the list of all functions that are invisible with respect to every function in fns-k, if fns-k is non-empty; otherwise, let fns be nil. Then rewriting is permitted if and only if yi' is smaller than xi' with respect to fns, in the sense defined in the preceding paragraph.

It remains only to describe how the loop-stopper field is calculated for a rewrite rule when this field is not supplied by the user. (On the other hand, to see how the user may specify the :loopstopper, see Chapter 15 [RULE-CLASSES], page 723.) Suppose the conclusion of the rule is of the form (equiv lhs rhs). First of all, if rhs is not an instance of the left hand side by a substitution whose range is a list of distinct variables, then the loop-stopper field is nil. Otherwise, consider all pairs (u . v) from this substitution with the property that the first occurrence of v appears in front of the first occurrence of u in the print representation of rhs. For each such u and v, form a list fns of all functions fn in lhs with the property that u or v (or both) appears as a top-level argument of a subterm of lhs with function symbol fn. Then the loop-stopper for this rewrite rule is a list of all lists (u v . fns).

8.65 LP

LP the Common Lisp entry to ACL2

To enter the ACL2 command (COMMAND^) loop from Common Lisp, call the Common Lisp program lp (which stands for “loop,” as in “read-eval-print loop” or “command (COMMAND^) loop.”) The ACL2 command (COMMAND^) loop is actually coded in ACL2 as the function ld (LD^) (which stands for “load”). The command (COMMAND^) loop is just what you get by loading from the standard object input channel, *standard-oi* (*STANDARD-OI*^). Calling ld (LD^) directly from Common Lisp is possible but fragile because hard lisp errors or aborts throw you out of ld (LD^) and back to the top-level of Common Lisp. Lp calls ld (LD^) in such a way as to prevent this and is thus the standard way to get into the ACL2 command (COMMAND^) loop. Also see Section 8.4 [ACL2-CUSTOMIZATION], page 239 for information on the loading of an initialization file.

All of the visible functionality of lp is in fact provided by ld (LD^), which is written in ACL2 itself. Therefore, you should see Section 9.7 [LD], page 416 for detailed documentation (DOC-UMENTATION^) of the ACL2 command (COMMAND^) loop. We sketch it below, for novice users.

Every expression typed to the ACL2 top-level must be an ACL2 expression.

Any ACL2 expression containing no variables may be evaluated. Because of the applicative nature of ACL2, we make a special exception for the variable state (STATE^). If this variable occurs in the form, it is taken to mean the “current” ACL2 state (STATE^) object. If the form returns a new state (STATE^) object as one of its values, then that is considered the new “current” state (STATE^) for the evaluation of the subsequent form. See Section 8.83 [STATE], page 368.

If the form read is a single keyword, e.g., :pe (PE^) or :ubt (UBT^), then special procedures are followed. See Section 8.48 [KEYWORD-COMMANDS], page 328.

The command (COMMAND^) loop keeps track of the command (COMMAND^)s you have typed and allows you to review them, display them, and roll the logical state (STATE^) back to that created by any command (COMMAND^). See Chapter 7 [HISTORY], page 215.

ACL2 makes the convention that if a top-level form returns three values, the last of which is an ACL2 state (STATE^), then the first is treated as a flag that means “an error occurred,” the second is the value to be printed if no error occurred, and the third is (of course) the new state (STATE^). When “an error occurs” no value is printed. Thus, if you execute a top-level form that happens to return three such values, only the second will be printed (and that will only happen if the first is nil!). See Section 9.7 [LD], page 416 for details.

8.66 MACRO-ARGS

MACRO-ARGS the formals list of a macro definition

     Examples:
     (x y z)
     (x y z &optional max (base '10 basep))
     (x y &rest rst)
     (x y &key max base)
     (&whole sexpr x y)

The “lambda-list” of a macro definition may include simple formal parameter names as well as appropriate uses of the following lambda-list keywords from CLTL (pp. 60 and 145):

       &optional,
       &rest,
       &key,
       &whole,
       &body, and
       &allow-other-keys.

ACL2 does not support &aux and &environment. In addition, we make the following restrictions:

(1) initialization forms in &optional and &key specifiers must be quoted values;

(2) &allow-other-keys may only be used once, as the last specifier; and

(3) destructuring is not allowed.

You are encouraged to experiment with the macro facility. One way to do so is to define a macro that does nothing but return the quotation of its arguments, e.g.,

(defmacro demo (x y &optional opt &key key1 key2)
  (list 'quote (list x y opt key1 key2)))

You may then execute the macro on some sample forms, e.g.,

  term                         value
(demo 1 2)                (1 2 NIL NIL NIL)
(demo 1 2 3)              (1 2 3 NIL NIL)
(demo 1 2 :key1 3)        error:  non-even key/value arglist
                          (because :key1 is used as opt)
(demo 1 2 3 :key2 5)      (1 2 3 NIL 5)

Also see Section 9.16 [TRANS], page 427.

8.67 NAME

NAME syntactic rules on logical names

Examples                 Counter-Examples
PRIMEP               91         (not a symbolp)
F-AC-23              :CHK-LIST  (in KEYWORD package)
1AX                  *PACKAGE*  (in the Lisp Package)
|Prime Number|       1E3        (not a symbolp)

Many different ACL2 entities have names, e.g., functions, macros, variables, constants, packages, theorems, theories (THEORIES^), etc. Package names are strings. All other names are symbols and may not be in the "KEYWORD" package. Moreover, names of functions, macros, constrained functions, and constants, other than those that are predefined, must not be in the “main Lisp package” (which is ("LISP" or "COMMON-LISP", according to whether we are following CLTL1 or CLTL2). An analogous restriction on variables is given below.

T, nil, and all names above except those that begin with ampersand (&) are names of variables or constants. T, nil, and those names beginning and ending with star (*) are constants. All other such names are variables.

Note that names that start with ampersand, such as &rest, may be lambda list keywords and are reserved for such use whether or not they are in the CLTL constant lambda-list-keywords. (See pg 82 of CLTL2.) That is, these may not be used as variables. Unlike constants, variables may be in the main Lisp package as long as they are in the original list of imports from that package

to ACL2, the list *common-lisp-symbols-from-main-lisp-package*, and do not belong to a list

of symbols that are potentially “global.” This latter list is the value of *common-lisp-specials-

and-constants*.

Our restrictions pertaining to the main Lisp package take into account that some symbols, e.g., lambda-list-keywords and boole-c2, are “special.” Permitting them to be bound could have harmful effects. In addition, the Common Lisp language does not allow certain manipulations with many symbols of that package. So, we stay away from them, except for allowing certain variables as indicated above.

8.68 OBDD

OBDD ordered binary decision diagrams with rewriting

See Chapter 2 [BDD], page 71 for information on this topic.

8.69 OTF-FLG

OTF-FLG pushing all the initial subgoals

The value of this flag is normally nil. If you want to prevent the theorem prover from abandoning its initial work upon pushing the second subgoal, set :otf-flg to t.

Suppose you submit a conjecture to the theorem prover and the system splits it up into many subgoals. Any subgoal not proved by other methods is eventually set aside for an attempted induction proof. But upon setting aside the second such subgoal, the system chickens out and decides that rather than prove n>1 subgoals inductively, it will abandon its initial work and attempt induction on the originally submitted conjecture. The :otf-flg (Onward Thru the Fog) allows you to override this chickening out. When :otf-flg is t, the system will push all the initial subgoals and proceed to try to prove each, independently, by induction.

Even when you don’t expect induction to be used or to succeed, setting the :otf-flg is a good way to force the system to generate and display all the initial subgoals.

8.70 PACKAGE-REINCARNATION-IMPORT-RESTRICTIONS

PACKAGE-REINCARNATION-IMPORT-RESTRICTIONS re-defining undone defpkg (DEFPKG^)s

Suppose (defpkg "pkg" imports) is the most recently executed successful definition of "pkg" in this ACL2 session and that it has since been undone, as by :ubt (UBT^). Any future attempt in this session to define "pkg" as a package must specify an identical imports list.

The restriction stems from the need to implement the reinstallation of saved logical world (WORLD^)s as in error recovery and the :oops (OOPS^) command (COMMAND^). Suppose that the new defpkg (DEFPKG^) attempts to import some symbol, a::sym, not imported by the previous definition of "pkg". Because it was not imported in the original package, the symbol pkg::sym, different from a::sym, may well have been created and may well be used in some saved world (WORLD^)s. Those saved world (WORLD^)s are Common Lisp objects being held for you “behind the scenes.” In order to import a::sym into "pkg" now we would have to unintern pkg::sym, rendering those saved world (WORLD^)s ill-formed. It is because of saved world (WORLD^)s that we do not actually clear out a package when it is undone.

At one point we thought it was sound to allow the new defpkg (DEFPKG^) to import a subset of the old. But that is incorrect. Suppose the old definition of "pkg" imported a::sym but the new one does not. Suppose we allowed that and implemented it simply by setting the imports of "pkg" to the new subset. Then consider the conjecture (eq a::sym pkg::sym). This ought not be a theorem because we did not import a::sym into "pkg". But in fact in AKCL it is a theorem because pkg::sym is read as a::sym because of the old imports.

8.71 PRINT-DOC-START-COLUMN

PRINT-DOC-START-COLUMN printing the one-liner

     Examples:
     (assign print-doc-start-column nil)

     (assign print-doc-start-column 17)

This state (STATE^) global variable controls the column in which the “one-liner” of a formatted documentation (DOCUMENTATION^) string is printed. Generally, when :doc (DOC^) is used to print a documentation (DOCUMENTATION^) string, the name of the documented concept is printed and then :doc (DOC^) tabs over to print-doc-start-column and prints the one-liner. If the name extends past the desired column, :doc (DOC^) outputs a carriage return and then tabs over to the column. If print-doc-start-column is nil, :doc (DOC^) just starts the one-liner two spaces from the end of the name, on the same line. The initial value of print-doc-start-column is 15.

8.72 PROMPT

PROMPT the prompt printed by ld (LD^)

The prompt printed by ACL2 conveys information about various “modes.” See Section 8.19 [DEFAULT-PRINT-PROMPT], page 274 and see Section 8.56 [LD-PROMPT], page 334 for details.

8.73 PROOF-OF-WELL-FOUNDEDNESS

PROOF-OF-WELL-FOUNDEDNESS a proof that e0-ord-< (E0-ORD-<^) is well-founded on e0ordinalp (E0-ORDINALP^)s

The soundness of ACL2 rests in part on the well-foundedness of e0-ord-< (E0-ORD-<^) on e0ordinalp (E0-ORDINALP^)s. This can be taken as obvious if one is willing to grant that those concepts are simply encodings of the standard mathematical notions of the ordinals below epsilon-0 and its natural ordering relation. But it is possible to prove that e0-ord-< (E0-ORD-<^) is well-founded on e0-ordinalp (E0-ORDINALP^)s without having to assert any connection to the ordinals and that is what we do here.

We first observe three facts about e0-ord-< (E0-ORD-<^) on ordinals that have been proved by ACL2 using only structural induction on lists.

     (defthm transitivity
       (implies (and (e0-ordinalp x)
                     (e0-ordinalp y)
                     (e0-ordinalp z)

              (e0-ord-< x y)
              (e0-ord-< y z))
         (e0-ord-< x z))
:rule-classes nil)
(defthm non-circularity
(implies (and (e0-ordinalp x)
              (e0-ordinalp y)
              (e0-ord-< x y))
         (not (e0-ord-< y x)))
:rule-classes nil)
(defthm trichotomy
(implies (and (e0-ordinalp x)
              (e0-ordinalp y))
         (or (equal x y)
             (e0-ord-< x y)
             (e0-ord-< y x)))
:rule-classes nil)

These three properties establish that e0-ord-< (E0-ORD-<^) orders the e0-ordinalp (E0-ORDINALP^)s. To put such a statement in the most standard mathematical nomenclature, we can define the function:

(defun e0-ord-<= (x y)
(or (equal x y) (e0-ord-< x y)))

and then establish that e0-ord-<= is a relation that is a simple, complete (i.e., total) order on ordinals by the following three lemmas, which have been proved:

(defthm antisymmetry
(implies (and (e0-ordinalp x)
              (e0-ordinalp y)
              (e0-ord-<= x y)
              (e0-ord-<= y x))
         (equal x y))
:rule-classes nil
:hints (("Goal" :use non-circularity)))
(defthm e0-ord-<=-transitivity
        (implies (and (e0-ordinalp x)
                      (e0-ordinalp y)
                      (e0-ordinalp z)
                      (e0-ord-<= x y)
                      (e0-ord-<= y z))
                 (e0-ord-<= x z))

       :rule-classes nil
       :hints (("Goal" :use transitivity)))
     (defthm trichotomy-of-e0-ord-<
       (implies (and (e0-ordinalp x)
                     (e0-ordinalp y))
                (or (e0-ord-<= x y)
                    (e0-ord-<= y x)))
       :rule-classes nil
       :hints (("Goal" :use trichotomy)))

Crucially important to the proof of the well-foundedness of e0-ord-< (E0-ORD-<^) on e0-ordinalp (E0-ORDINALP^)s is the concept of ordinal-depth, abbreviated od:

     (defun od (l) (if (atom l) 0 (1+ (od (car l)))))

If the od of an e0-ordinalp (E0-ORDINALP^) x is smaller than that of an e0-ordinalp (E0-ORDINALP^) y, then x is e0-ord-< (E0-ORD-<^) y:

     (defthm od-implies-ordlessp
       (implies (and (e0-ordinalp x) (e0-ordinalp y)
                     (< (od x) (od y)))
                (e0-ord-< x y)))

Remark. A consequence of this lemma is the fact that if s = s(1), s(2), ... is an infinite, e0ord-< (E0-ORD-<^) descending sequence, then od(s(1)), od(s(2)), ... is a “weakly” descending sequence of non-negative integers: od(s(i)) is greater than or equal to od(s(i+1)).

Lemma Main. For each non-negative integer n, e0-ord-< (E0-ORD-<^) well-orders the set of e0-ordinalp (E0-ORDINALP^)s with od less than or equal to n .

      Base Case.  n = 0.  The e0-ordinalps with 0 od are the non-negative
      integers.  On the non-negative integers, e0-ord-< is the same as <.
      Induction Step.  n > 0.  We assume that e0-ord-< well-orders the
      e0-ordinalps with od less than n.
        If e0-ord-< does not well-order the e0-ordinalps with od less
        than or equal to n, we may let O be the e0-ord-<-least
        e0-ordinalp which is the car of the first member of an infinite,
        e0-ord-< descending sequence of e0-ordinalps of od less than or
        equal to n.  The od of O is n-1.
         Let k be the least integer > 0 such that for some infinite,

e0-ord-< descending sequence s of e0-ordinalps with od less than
or equal to n, the first element of s begins with k occurrences
of O but not k+1 occurrences of O.
Having fixed O and k, let s = s(1), s(2), ... be an infinite,
e0-ord-< descending sequence of e0-ordinalps with od less than
or equal to n such that O occurs exactly k times at the
beginning of s(1).
O occurs exactly k times at the beginning of each s(i).
For suppose that s(j) is the first member of s with exactly
m occurrences of O at the beginning, m /= k.  If m = 0,
then the first member of s(j) must be e0-ord-< O,
contradicting the minimality of O.  If 0 < m < k, then the
fact that the sequence beginning at s(j) is infinitely
descending contradicts the minimality of k.  If m > k, then
s(j) is greater than its predecessor, which has only k
occurrences of O at the beginning; but this contradicts the
fact that s is descending.
Let t = t(1), t(2), ... be the sequence of e0-ordinalps
that is obtained by letting t(i) be the result of removing
O from the front of s(i) exactly k times.  t is infinitely
descending.  Furthermore, t(1) begins with an e0-ordinalp
O' that is e0-ord-< O, and hence has od at most N-1 by the
lemma od-implies-ordlessp.  But this contradicts the
minimality of O. Q.E.D.

Theorem. e0-ord-< (E0-ORD-<^) well-orders the e0-ordinalp (E0-ORDINALP^)s. Proof. Every infinite, e0-ord-< descending sequence of e0-ordinalp (E0-ORDINALP^)s has the property that each member has od less than or equal to the od, n, of the first member of the sequence. This contradicts Lemma Main. Q.E.D.

8.74 PSEUDO-TERMP

PSEUDO-TERMP a predicate for recognizing term-like s-expressions

Example Forms:
(pseudo-termp '(car (cons x 'nil)))      ; has value t
(pseudo-termp '(car x y z))              ; also has value t!
(pseudo-termp '(delta (h x)))            ; has value t
(pseudo-termp '(delta (h x) . 7))        ; has value nil (not a true-listp)
(pseudo-termp '((lambda (x) (car x)) b)) ; has value t
(pseudo-termp '(if x y 123))             ; has value nil (123 is not quoted)

     (pseudo-termp '(if x y '123))            ; has value t

If x is the quotation of a term, then (pseudo-termp x) is t. However, if x is not the quotation of a term it is not necessarily the case that (pseudo-termp x) is nil.

See Section 8.87 [TERM], page 376 for a discussion of the various meanings of the word “term” in ACL2. In its most strict sense, a term is either a legal variable symbol, a quoted constant, or the application of an n-ary function symbol or closed lambda-expression to n terms. By “legal variable symbol” we exclude constant symbols, such as t, nil, and *ts-rational*. By “quoted constants” we include 't (aka (quote t)), 'nil, '31, etc., and exclude constant names such as t, nil and *ts-rational*, unquoted constants such as 31 or 1/2, and ill-formed quote expressions such as (quote 3 4). By “closed lambda expression” we exclude expressions, such as (lambda (x) (cons x y)), containing free variables in their bodies. Terms typed by the user are translated into strict terms for internal use in ACL2.

The predicate termp checks this strict sense of “term” with respect to a given ACL2 logical world; See Section 8.100 [WORLD], page 399. Many ACL2 functions, such as the rewriter, require certain of their arguments to satisfy termp. However, as of this writing, termp is in :program (PRO-GRAM^) mode and thus cannot be used effectively in conjectures to be proved. Furthermore, if regarded simply from the perspective of an effective guard (GUARD^) for a term-processing function, termp checks many irrelevant things. (Does it really matter that the variable symbols encountered never start and end with an asterisk?) For these reasons, we have introduced the notion of a “pseudo-term” and embodied it in the predicate pseudo-termp, which is easier to check, does not require the logical world (WORLD^) as input, has :logic (LOGIC^) mode, and is often perfectly suitable as a guard (GUARD^) on term-processing functions.

A pseudo-termp is either a symbol, a true list of length 2 beginning with the word quote, the application of an n-ary pseudo-lambda expression to a true list of n pseudo-terms, or the application of a symbol to a true list of n pseudo-termps. By an “n-ary pseudo-lambda expression” we mean an expression of the form (lambda (v1 ... vn) pterm), where the vi are symbols (but not necessarily distinct legal variable symbols) and pterm is a pseudo-termp.

Metafunctions may use pseudo-termp as a guard (GUARD^).

8.75 REDEF

REDEF a common way to set ld-redefinition-action (LD-REDEFINITION-ACTION^)

     Example and General Form:
     ACL2 !>:redef

This command sets ld-redefinition-action (LD-REDEFINITION-ACTION^) to '(:query .

:overwrite).

As explained elsewhere (see Section 8.58 [LD-REDEFINITION-ACTION], page 336), this allows redefinition of functions and other events (EVENTS^) without undoing. A query will be made every time a redefinition is command (COMMAND^)ed; the user must explicitly acknowledge that the redefinition is intentional. It is possible to set ld-redefinition-action (LD-REDEFINITION-ACTION^) so that the redefinition of non-system functions occurs quietly. See Section 8.58 [LD-REDEFINITION-ACTION], page 336.

8.76 REDEF!

REDEF! system hacker’s redefinition command (COMMAND^)

     Example and General Form:
     ACL2 !>:redef!
     ACL2 p!>

This command (COMMAND^) sets ld-redefinition-action (LD-REDEFINITION-ACTION^) to '(:warn! . :overwrite) and sets the default defun-mode (DEFUN-MODE^) to :program (PROGRAM^).

This is the ACL2 system hacker’s redefinition command (COMMAND^). Note that even system functions can be redefined with a mere warning. Be careful!

8.77 REDEFINED-NAMES

REDEFINED-NAMES to collect the names that have been redefined

     Example and General Forms:
     (redefined-names state)

This function collects names that have been redefined in the current ACL2 state (STATE^). :Program (PROGRAM^) mode functions that were reclassified to :logic (LOGIC^) functions are not collected, since such reclassification cannot imperil soundness because it is allowed only when the new and old definitions are identical.

Thus, if (redefined-names state) returns nil then no unsafe definitions have been made, regardless of ld-redefinition-action (LD-REDEFINITION-ACTION^). See Section 8.58 [LD-REDEFINITION-ACTION], page 336.

8.78 REDUNDANT-EVENTS

REDUNDANT-EVENTS allowing a name to be introduced “twice”

Sometimes an event will announce that it is “redundant”. When this happens, no change to the logical world (WORLD^) has occurred. This happens when the logical name being defined is already defined and has exactly the same definition, from the logical point of view. This feature permits two independent books (BOOKS^), each of which defines some name, to be included sequentially provided they use exactly the same definition.

When are two logical-name (LOGICAL-NAME^) definitions considered exactly the same? It depends upon the kind of name being defined.

A deflabel (DEFLABEL^) event is never redundant. This means that if you have a deflabel (DEFLABEL^) in a book and that book has been included (without error), then references to that label denote the point in history (HISTORY^) at which the book introduced the label. See the note about shifting logical names, below.

A defun (DEFUN^) or mutual-recursion (MUTUAL-RECURSION^) (or defuns (DEFUNS^)) event is redundant if for each function to be introduced, there has already been introduced a function with the same name, the same formals, and syntactically identical guard (GUARD^), type declarations, and body (before macroexpansion).

A verify-guards (VERIFY-GUARDS^) event is redundant if the function has already had its guard (GUARD^)s verified.

A defaxiom (DEFAXIOM^) or defthm (DEFTHM^) event is redundant if there is already an axiom or theorem of the given name and both the formula (after macroexpansion) and the rule-classes (RULE-CLASSES^) are syntactically identical. Note that a defaxiom (DEFAXIOM^) can make a subsequent defthm (DEFTHM^) redundant, and a defthm (DEFTHM^) can make a subsequent defaxiom (DEFAXIOM^) redundant as well.

A defconst (DEFCONST^) is redundant if the name has been defined to have the same value.

A defmacro (DEFMACRO^) is redundant if there is already a macro defined with the same name and syntactically identical arguments, guard (GUARD^), and body.

A defpkg (DEFPKG^) is redundant if a package of the same name with exactly the same imports has been defined.

A deftheory (DEFTHEORY^) is never redundant. The “natural” notion of equivalent deftheory (DEFTHEORY^)s is that the names and values of the two theory expressions are the same. But since most theory expressions are sensitive to the context in which they occur, it seems unlikely to us that two deftheory (DEFTHEORY^)s coming from two sequentially included books (BOOKS^) will ever have the same values. So we prohibit redundant theory definitions. If you try to define the same theory name twice, you will get a “name in use” error.

An in-theory (IN-THEORY^) event is never redundant because it doesn’t define any name.

Table (TABLE^) and defdoc (DEFDOC^) events (EVENTS^) are never redundant because they don’t define any name.

An encapsulate (ENCAPSULATE^) event is redundant if and only if a syntactically identical encapsulate (ENCAPSULATE^) has already been executed under the same default-defun-mode (DEFAULT-DEFUN-MODE^).

An include-book (INCLUDE-BOOK^) is redundant if the book has already been included.

Note About Shifting Logical Names:

Suppose a book defines a function fn and later uses fn as a logical name in a theory expression. Consider the value of that theory expression in two different sessions. In session A, the book is included in a world (WORLD^) in which fn is not already defined, i.e., in a world (WORLD^) in which the book’s definition of fn is not redundant. In session B, the book is included in a world (WORLD^) in which fn is already identically defined. In session B, the book’s definition of fn is redundant. When fn is used as a logical name in a theory expression, it denotes the point in history (HISTORY^) at which fn was introduced. Observe that those points are different in the two sessions. Hence, it is likely that theory expressions involving fn will have different values in session A than in session B.

This may adversely affect the user of your book. For example, suppose your book creates a theory via deftheory (DEFTHEORY^) that is advertised just to contain the names generated by the book. But suppose you compute the theory as the very last event in the book using:

     (set-difference-theories (universal-theory :here)
                              (universal-theory fn))

where fn is the very first event in the book and happens to be a defun (DEFUN^) event. This expression returns the advertised set if fn is not already defined when the book is included. But if fn were previously (identically) defined, the theory is larger than advertised.

The moral of this is simple: when building books (BOOKS^) that other people will use, it is best to describe your theories (THEORIES^) in terms of logical names that will not shift around when the books (BOOKS^) are included. The best such names are those created by deflabel (DEFLABEL^).

8.79 SAVING-AND-RESTORING

SAVING-AND-RESTORING saving and restoring your logical state

     Examples:
     ACL2 !>:Q
     >(make-lib "file")
     ...
     >(note-lib "file")
     >(LP)
     ACL2 !>

To save the current ACL2 logical world (WORLD^) to a file, exit ACL2 with :q (Q^) and invoke (make-lib "file") in Common Lisp. This creates a file "file.lib" and a file "file.lisp". The latter will be compiled. It generally takes half an hour to save an ACL2 logical world (WORLD^) and creates a 20Mb file. All things considered it is probably better to just save your core image.

To restore such a saved ACL2 world (WORLD^), invoke (note-lib "file") from Common Lisp, and then enter ACL2 with (lp). We do not save the io (IO^) system, the stacks, or the global table, hence bindings of your globals will not be restored.

This save/restore mechanism is a temporary expedient. We know of faster mechanisms, mechanisms that consume less disk space, and mechanisms that provide more functionality. We don’t know of good compromises between these various desirable features.

8.80 SIGNATURE

SIGNATURE how to specify the arity of a constrained function

     Examples:
     (hd (x) t)
     (printer (x state) (mv t t state))
     (printer (x state) (mv er-flg val state))
     General Form:
     (fn formals result)

where fn is the constrained function symbol, formals is a suitable list of formal parameters for it, and result is either a symbol denoting that the function returns one result (which is a state (STATE^) object or not depending on whether the symbol is state (STATE^)) or else result is an mv (MV^) expression, (mv s1 ... sn), where n>1, each si is a symbol, and at most one of the si is the symbol state (STATE^). The latter form of result indicates that the function returns n results and indicates which of them (if any) is a state (STATE^) object. The non-state (STATE^) si are just place holders and may all be identical, e.g., t, though we often use symbols that suggest the type of the corresponding value. It is illegal for state (STATE^) to be used in result if state (STATE^) does not appear in formals.

8.81 SIMPLE

SIMPLE :definition (DEFINITION^) and :rewrite (REWRITE^) rules used in preprocessing

     Example of simple rewrite rule:
     (equal (car (cons x y)) x)
     Examples of simple definition:
     (defun file-clock-p (x) (integerp x))
     (defun naturalp (x)
       (and (integerp x) (>= x 0)))

The theorem prover output sometimes refers to “simple” definitions and rewrite rules. These rules can be used by the preprocessor, which is one of the theorem prover’s “processes” understood by the :do-not hint; see Section 8.43 [HINTS], page 319.

The preprocessor expands certain definitions and uses certain rewrite rules that it considers to be “fast”. There are two ways to qualify as fast. One is to be an “abbreviation”, where a rewrite rule with no hypotheses or loop stopper is an “abbreviation” if the right side contains no more variable occurrences than the left side, and the right side does not call the functions if (IF^), not (NOT^) or implies (IMPLIES^). Definitions and rewrite rules can both be abbreviations; the criterion for definitions is similar, except that the definition must not be recursive. The other way to qualify applies only to a non-recursive definition, and applies when its body is a disjunction or conjunction, according to a perhaps subtle criterion that is intended to avoid case splits.

8.82 SPECIOUS-SIMPLIFICATION

SPECIOUS-SIMPLIFICATION nonproductive proof steps

Occasionally the ACL2 theorem prover reports that the current goal simplifies to itself or to a set including itself. Such simplifications are said to be “specious” and are ignored in the sense that the theorem prover acts as though no simplification were possible and tries the next available proof technique. Specious simplifications are almost always caused by forcing.

The simplification of a formula proceeds primarily by the local application of :rewrite (REWRITE^), :type-prescription (TYPE-PRESCRIPTION^), and other rules to its various subterms. If no rewrite rules apply, the formula cannot be simplified and is passed to the next ACL2 proof technique, which is generally the elimination of destructors. The experienced ACL2 user pays special attention to such “maximally simplified” formulas; the presence of unexpected terms in them indicates the need for additional rules or the presence of some conflict that prevents existing rules from working harmoniously together.

However, consider the following interesting possibility: local rewrite rules apply but, when applied, reproduce the goal as one of its own subgoals. How can rewrite rules apply and reproduce the goal? Of course, one way is for one rule application to undo the effect of another, as when commutativity is applied twice in succession to the same term. Another kind of example is when rules conflict and undermine each other. For example, under suitable hypotheses, (length x) might be rewritten

to (+ 1 (length (cdr x))) by the :definition (DEFINITION^) of length (LENGTH^) and

then a :rewrite (REWRITE^) rule might be used to “fold” that back to (length x). Generally speaking the presence of such “looping” rewrite rules causes ACL2’s simplifier either to stop gracefully because of heuristics such as that described in the documentation for loop-stopper (LOOP-STOPPER^) or to cause a stack overflow because of indefinite recursion.

A more insidious kind of loop can be imagined: two rewrites in different parts of the formula undo each other’s effects “at a distance,” that is, without ever being applied to one another’s output. For example, perhaps the first hypothesis of the formula is simplified to the second, but then the second is simplified to the first, so that the end result is a formula propositionally equivalent to the original one but with the two hypotheses commuted. This is thought to be impossible unless forcing occurs, but if forcing is exploited (see Section 8.37 [FORCE], page 297) it can be made to happen relatively easily.

Here is a simple example. Declare foo to be a function of one argument returning one result:

     (defstub foo (x) t)

Add the following :type-prescription (TYPE-PRESCRIPTION^) rule about foo:

     (defaxiom forcer
      (implies (force (not (true-listp x)))
               (equal (foo x) t))
      :rule-classes :type-prescription)

Note that we could define a foo with this property; defstub (DEFSTUB^) and defaxiom (DE-FAXIOM^) are only used here to get to the gist of the problem immediately. Consider the proof attempt for the following formula.

     (thm (implies (and (consp x)              ; hyp 1
                        (true-listp (cdr x))   ; hyp 2
                        (true-listp x))        ; hyp 3
                   (foo x)))                   ; concl

When we simplify this goal, hyp 1 cannot be simplified. Hyp 2 simplifies to t, because x is known to be a non-nil true list so its cdr (CDR^) is a true list by type reasoning; because true hypotheses are dropped, hyp 2 simply disappears. Hyp 3 simplifies to (true-listp (cdr x)) by opening up the :definition (DEFINITION^) of true-listp (TRUE-LISTP^). Note that hyp 3 has simplified to the old hyp 2. So at this point, the “current (intermediate) goal” is

     (implies (and (consp x)                   ; rewritten hyp 1
                   (true-listp (cdr x)))       ; rewritten hyp 3
              (foo x))                         ; unrewritten concl

and we are working on (foo x). But the :type-prescription (TYPE-PRESCRIPTION^) rule above tells us that (foo x) is t if the hypothesis of the rule is true. Thus, in the case that the hypothesis of the rule is true, we are done. It remains to prove the current intermediate goal under the assumption that the hypothesis of the rule is false. This is done by adding the negation of the :type-prescription (TYPE-PRESCRIPTION^) rule’s hypothesis to the current intermediate goal. This is what force (FORCE^) does in this situation. The negation of the hypothesis is (true-listp x). Adding it to the current goal produces the subgoal

     (implies (and (consp x)                   ; rewritten hyp 1
                   (true-listp (cdr x))        ; rewritten hyp 3
                   (true-listp x))             ; FORCEd hyp
              (foo x)).                        ; unrewritten concl

Observe that this is just our original goal. Despite all the rewriting, no progress was made! In more common cases, the original goal may simplify to a set of subgoals, one of which includes the original goal.

If ACL2 were to adopt the new set of subgoals, it would loop indefinitely. Therefore, it checks whether the input goal is a member of the output subgoals. If so, it announces that the simplification is “specious” and pretends that no simplification occurred.

“Maximally simplified” formulas that produce specious simplifications are maximally simplified in a very technical sense: were ACL2 to apply every applicable rule to them, no progress would be made. Since ACL2 can only apply every applicable rule, it cannot make further progress with the formula. But the informed user can perhaps identify some rule that should not be applied and make it inapplicable by disabling it, allowing the simplifier to apply all the others and thus make progress.

When specious simplifications are a problem it might be helpful to disable (DISABLE^) all forcing and resubmit the formula to observe whether forcing is involved in the loop or not. See Section 8.37 [FORCE], page 297. The commands

     ACL2 !>:disable-forcing
     and
     ACL2 !>:enable-forcing

disable (DISABLE^) and enable (ENABLE^) forcing. If the loop is broken when forcing is disable (DISABLE^)d, then it is very likely some force (FORCE^)d hypothesis of some rule is “undoing” a prior simplification. The most common cause of this is when we force (FORCE^) a hypothesis that is actually false but whose falsity is somehow temporarily hidden (more below). To find the offending rule, compare the specious simplification with its non-specious counterpart and look for rules that were speciously applied that are not applied in the non-specious case. Most likely you will find at least one such rule and it will have a force (FORCE^)d hypothesis. By disabling that rule, at least for the subgoal in question, you may allow the simplifier to make progress on the subgoal.

To illustrate what we mean by the claim that specious simplifications often arise because the system force (FORCE^)s a false hypothesis, reconsider the example above. At the time we used the :type-prescription (TYPE-PRESCRIPTION^) rule, the known assumptions were (consp x) and (true-listp (cdr x)). Observe that this tells us that x is a true list. But the hypothesis force (FORCE^)d to be true was (not (true-listp x)). Why was the falsity of this hypothesis missed? The most immediate reason is that the encoding of the two assumptions above does not produce a context (“type-alist”) in which x is recorded to be a true-list. When we look up (not (true-listp x)) in that context, we are not told that it is false. More broadly, the problem stems from the fact that when we force (FORCE^) a hypothesis we do not bring to bear on it all of the resources of the theorem prover. Thus it could be — as here — that the hypothesis could be proved false in the current context but is not obviously so. No matter how sophisticated we made the forcing mechanism, the unavoidable incompleteness of the theorem prover would still permit the occasional specious simplification. While that does not excuse us from trying to avoid specious simplifications when we can — and we may well strengthen the type mechanism to deal with the problem illustrated here — specious simplifications will probably remain a problem deserving of the user’s attention.

8.83 STATE

STATE the von Neumannesque ACL2 state object

The ACL2 state object is used extensively in programming the ACL2 system, and has been used in other ACL2 programs as well. However, most users, especially those interested in specification and verification (as opposed to programming per se), need not be aware of the role of the state object in ACL2, and will not write functions that use it explicitly. We say more about this point at the end of this documentation topic.

The global table is perhaps the most visible portion of the state object. Using the interface functions @ and assign, a user will bind global variables to the results of function evaluations (much as an Nqthm user exploits the Nqthm utility r-loop). See Section 9.1 [@], page 409 and see Section 9.3 [ASSIGN], page 414.

ACL2 supports several facilities of a truly von Neumannesque state machine character, including file io (IO^) and global variables. Logically speaking, the state is a true list of the 14 components as described below. There is a “current” state object at the top-level of the ACL2 command (COMMAND^) loop. This object is understood to be the value of what would otherwise be the free variable state appearing in top-level input. When any command (COMMAND^) returns a state object as one of its values, that object becomes the new current state. But ACL2 provides von Neumann style speed for state operations by maintaining only one physical (as opposed to logical) state object. Operations on the state are in fact destructive. This implementation does not violate the applicative semantics because we enforce certain draconian syntactic rules regarding the use of state objects. For example, one cannot “hold on” to an old state, access the components of a state arbitrarily, or “modify” a state object without passing it on to subsequent state-sensitive functions.

Every routine that uses the state facilities (e.g. does io (IO^), or calls a routine that does io (IO^)), must be passed a “state object.” And a routine must return a state object if the routine modifies the state in any way. Rigid syntactic rules governing the use of state objects are enforced by the function translate, through which all ACL2 user input first passes. State objects can only be “held” in the formal parameter state, never in any other formal parameter and never in any structure (excepting a multiple-values return list field which is always a state object). State objects can only be accessed with the primitives we specifically permit. Thus, for example, one cannot ask, in code to be executed, for the length of state or the car (CAR^) of state. In the statement and proof of theorems, there are no syntactic rules prohibiting arbitrary treatment of state objects.

Logically speaking, a state object is a true list whose members are as follows:

Open-input-channels, an alist with keys that are symbols in package "ACL2-INPUT-CHANNEL". The value (cdr (CDR^)) of each pair has the form ((:header type file-

     name open-time) . elements), where type is one of :character, :byte, or :object

and elements is a list of things of the corresponding type, i.e. characters, integers of type (mod 255), or lisp objects in our theory. File-name is a string. Open-time is an integer. See Section 10.135 [IO], page 493.

Open-output-channels, an alist with keys that are symbols in package "ACL2-OUTPUT-

     CHANNEL". The value of a pair has the form ((:header type file-name open-time)

. current-contents). See Section 10.135 [IO], page 493.

Global-table, an alist associating symbols (to be used as “global variables”) with values. See Section 9.1 [@], page 409, and see Section 9.3 [ASSIGN], page 414.

T-stack, a list of arbitrary objects accessed and changed by the functions aref-t-

     stack and aset-t-stack.

32-bit-integer-stack, a list of arbitrary 32-bit-integers accessed and changed by the

functions aref-32-bit-integer-stack and aset-32-bit-integer-stack.

Big-clock-entry, an integer, that is used logically to bound the amount of effort spent to evaluate a quoted form.

Idates, a list of dates and times, used to implement the function print-current-idate, which prints the date and time.

Run-times, a list of integers, used to implement the functions that let ACL2 report how much time was used, but inaccessible to the user.

File-clock, an integer that is increased on every file opening and closing and used to maintain the consistency of the io (IO^) primitives.

Readable-files, an alist whose keys have the form (string type time), where string (STRING^) is a file name and time is an integer. The value associated with such a key is a list of characters, bytes, or objects, according to type. The time field is used in the following way: when it comes time to open a file for input, we will only look for a file of the specified name and type whose time field is that of file-clock. This permits us to have a “probe-file” aspect to open-file: one can ask for a file, find it does not exist, but come back later and find that it does now exist.

Written-files, an alist whose keys have the form (string type time1 time2),

where string (STRING^) is a file name, type is one of :character, :byte or :object, and time1 and time2 are integers. Time1 and time2 correspond to the file-clock time at which the channel for the file was opened and closed. This field is writeonly; the only operation that affects this field is close-output-channel, which cons (CONS^)es a new entry on the front.

Read-files, a list of the form (string type time1 time2), where string (STRING^)

is a file name and time1 and time2 were the times at which the file was opened for reading and closed. This field is write only.

Writeable-files, an alist whose keys have the form (string type time). To open a file for output, we require that the name, type, and time be on this list.

List-all-package-names-lst, a list of true-listps. Roughly speaking, the car

(CAR^) of this list is the list of all package names known to this Common Lisp right now and the cdr (CDR^) of this list is the value of this state variable after you look at its car (CAR^). The function, list-all-package-names, which takes the state as an argument, returns the car (CAR^) and cdr (CDR^)s the list (returning a new state too). This essentially gives ACL2 access to what is provided by CLTL’s list-all-packages. Defpkg (DEFPKG^) uses this feature to insure that the about-to-be-created package is new in this lisp. Thus, for example, in akcl it is impossible to create the package "COMPILER" with defpkg (DEFPKG^) because it is on the list, while in Lucid that package name is not initially on the list.

We recommend avoiding the use of the state object when writing ACL2 code intended to be used as a formal model of some system, for several reasons. First, the state object is complicated and contains many components that are oriented toward implementation and are likely to be irrelevant to the model in question. Second, there is currently not much support for reasoning about ACL2 functions that manipulate the state object. Third, the documentation about state is not as complete as one might wish for serious programming that uses state.

If a user is building a model that includes a system state, it is better to represent that state explicitly in the model rather than use the ACL2 state object. ACL2 functions that manipulate association lists (for example, see Section 10.27 [ASSOC], page 445) can be used in place of @ and assign to access and update the state component of the model. As of this writing, the "books" directory of the ACL2 distribution contains a number of theorems already proved about such functions.

A consequence of this recommendation is that ACL2 constructs like pprogn and er-progn that depend on the state object will not appear in user-built models.

8.84 SUBVERSIVE-INDUCTIONS

SUBVERSIVE-INDUCTIONS why we restrict encapsulate (ENCAPSULATE^)d recursive functions

It is illegal for one of the functions introduced in the signature (SIGNATURE^) of an encapsulate (ENCAPSULATE^) event to be involved in the induction (INDUCTION^) scheme suggested by a non-local (LOCAL^)ly defined recursive function in that encapsulate (ENCAPSULATE^). Such recursive functions can give rise to so-called “subversive” induction (INDUCTION^) schemes in the sense that when used outside the encapsulate (ENCAPSULATE^) the scheme is unsound. Normally, the induction (INDUCTION^) suggested by a function is justified by the termination proof for the recursion. But in the case of recursive functions defined within encapsulations, the termination proof is constructed in a context in which the functions are to be viewed as “constrained.” The termination proof might therefore take advantage of properties of the witnesses that are not exported from the encapsulate (ENCAPSULATE^). Hence, crucial restrictions on the constrained functions may be lost. We give examples and advice below.

The following (illegal) event illustrates the problem posed by subversive induction (INDUC-TION^)s.

     (encapsulate ((test (x) t) (d (x) t) (p (x) t))
      (local (defun test (x) (consp x)))
      (local (defun d (x)
               (declare (xargs :mode :logic))
               (cdr x)))
      (defun foo (x)
        (declare (xargs :mode :logic))
        (if (test x) (foo (d x)) t))
      (local (defun p (x) (declare (ignore x)) t))
      (defthm base-case (implies (not (test x)) (p x)))
      (defthm induction-step (implies (and (test x) (p (d x))) (p x))))

Consider just the first three events (EVENTS^) above: the local (LOCAL^) definitions of test and d and the non-local recursive function foo. Test and d will be constrained to have certain properties, but within the encapsulate (ENCAPSULATE^) they are locally witnessed by consp (CONSP^) and cdr (CDR^), respectively. Observe that foo recurses by stepping from x to (d x) when (test x) is true. This recursion terminates because of properties of the witnesses for test and d. These properties need not be exported from the encapsulation. But when foo is exported from the encapsulation, it suggests that it is permissible to recur/induct by stepping “down” to (d x) from x when (test x) is true. Since we do not constrain (d x) to be smaller than x when (test x) the induction (INDUCTION^) suggestion by foo can be used to prove non-theorems. Because foo uses test and d in its recursion we say the induction (INDUCTION^) suggested by foo is “subversive” outside the encapsulation and do not permit such a foo to be defined nonlocally. That is, the attempt to submit the encapsulate (ENCAPSULATE^) event above will cause an error and complain about foo.

We give some advice below on how to carry out such encapsulations as might have been intended by that above. But first we show how an inconsistency can be deduced when the above encapsulate (ENCAPSULATE^) is permitted.

Note that the encapsulate (ENCAPSULATE^) introduced one other function symbol, p. Furthermore, the only constraint (CONSTRAINT^)s on test, d, and p are the last two theorems above. These theorems are the base case and induction (INDUCTION^) step for a proof of (p x) based on the induction (INDUCTION^) suggested by foo. We arrange for these theorems to be provable simply by defining p locally to be t.

Once outside the encapsulate (ENCAPSULATE^) we can prove (p x) by the spurious induction (INDUCTION^) suggested by foo.

     (defthm p-true (p x) :hints (("Goal" :induct (foo x))))

The proof is immediate given the two theorems exported from the encapsulate (ENCAPSU-LATE^).

But then we can functionally instantiate p in the theorem above to be nil! We must, of course, satisfy the constraint (CONSTRAINT^)s on p, namely the two theorems about test, d, and p exported from the encapsulate (ENCAPSULATE^). We can satisfy the constraint (CONSTRAINT^)s by choosing test to be always t.

     (defthm subversion! nil
       :hints (("Goal" :use (:functional-instance p-true
                                (test (lambda (x) t))
                                (p (lambda (x) nil)))))
       :rule-classes nil)

This concludes our illustration of what can go wrong were we to permit recursive functions in encapsulations to use the constrained functions in their recursions. We now move on to our advice about how to achieve the (non-nefarious) ends intended by the disallowed encapsulations.

One often desires to define recursive functions such as foo, i.e., functions that use constrained functions in their recursion. However, one should not try to introduce such functions within the same encapsulation as the constrained functions. Instead, introduce the constrained functions, including among their constraint (CONSTRAINT^)s the measure theorems sufficient to justify the intended recursive uses, and define the recursive functions outside the encapsulation environment. Thus, the following pair of events (EVENTS^) achieves, perhaps, the intended effect of the original encapsulation:

     (encapsulate ((test (x) t) (d (x) t))
       (local (defun test (x) (consp x)))
       (local (defun d (x) (declare (xargs :mode :logic)) (cdr x)))
       (defthm d-decreases
         (implies (test x) (< (acl2-count (d x)) (acl2-count x)))))
     (defun foo (x) (if (test x) (foo (d x)) t))

Another alternative, depending on one’s original intentions, is to include the definition of foo in the encapsulation but to make it local (LOCAL^). This allows foo to be used in other local (LOCAL^) events (EVENTS^) of that encapsulation but does not export it and its subversive induction (INDUCTION^) scheme.

Finally, it may be that foo is needed outside the encapsulation environment but the user does not intend for foo to suggest any induction (INDUCTION^) schemes. If this is the case, one should include foo in the signature (SIGNATURE^) of the encapsulate (ENCAPSULATE^) (and so make its definition local (LOCAL^)) and prove a non-local :definition (DEFINITION^) rule which states the recurrence equation for foo without requiring a termination argument. The :clique and :controller-alist fields for the :definition (DEFINITION^) rule should be those for the recursive definition of foo. See Section 15.4 [DEFINITION], page 735.

Note that the functions introduced in the signature (SIGNATURE^) may not even occur ancestrally in the induction (INDUCTION^) scheme suggested by a non-local (LOCAL^)ly defined recursive function in the encapsulate (ENCAPSULATE^). That is, they may not occur in definitions of, or constraint (CONSTRAINT^)s on, functions that occur in such induction (INDUCTION^) schemes; and those functions may not occur in such induction (INDUCTION^) schemes; and so on.

8.85 SYNTAX

SYNTAX the syntax of ACL2 is that of Common Lisp

For the details of ACL2 syntax, see CLTL. For examples of ACL2 syntax, use :pe (PE^) to print some of the ACL2 system code. For example:

     :pe assoc-equal
     :pe dumb-occur
     :pe fn-var-count
     :pe add-linear-variable-to-alist

There is no comprehensive description of the ACL2 syntax yet, except that found in CLTL. Also see Section 8.87 [TERM], page 376.

8.86 SYNTAXP

SYNTAXP to attach a heuristic filter on a :rewrite (REWRITE^) rule

     Consider the :REWRITE rule created from
     (IMPLIES (SYNTAXP (NOT (AND (CONSP X) (EQ (CAR X) 'NORM))))
              (EQUAL (LXD X) (LXD (NORM X)))).

The syntaxp hypothesis in this rule will allow the rule to be applied to (lxd (trn a b)) but will not allow it to be applied to (lxd (norm a)).

     General Form:
     (SYNTAXP test)

may be used as the nth hypothesis in a :rewrite (REWRITE^) rule whose :corollary (COROL-

LARY^) is (implies (and hyp1 ... hypn ... hypk) (equiv lhs rhs)) provided test is a

term, test contains at least one variable, and every variable occuring freely in test occurs freely in lhs or in some hypi, i<n. Formally, syntaxp is a function of one argument; syntaxp always returns t and so may be added as a vacuous hypothesis. However, the test “inside” the syntaxp form is actually treated as a meta-level proposition about the proposed instantiation of the rule’s variables and that proposition must evaluate to true (non-nil) to “establish” the syntaxp hypothesis.

We illustrate this by slightly elaborating the example given above. Consider a :rewrite (REWRITE^) rule whose :corollary (COROLLARY^) is:

     (IMPLIES (AND (RATIONALP X)
                   (SYNTAXP (NOT (AND (CONSP X) (EQ (CAR X) 'NORM)))))
              (EQUAL (LXD X) (LXD (NORM X))))

How is this rule applied to (lxd (trn a b))? First, we form a substitution that instantiates the left-hand side of the conclusion of the rule so that it is identical to the target term. In the present case, the substitution replaces x with (trn a b). Then we backchain to establish the hypotheses, in order. Ordinarily this means that we instantiate each hypothesis with our substitution and then attempt to rewrite the resulting instance to true. Of course, most users are aware of some exceptions to this general rule. For example, if a hypothesis contains a “free-variable” — one not bound by the current substitution — we attempt to extend the substitution by searching for an instance of the hypothesis among known truths. Force (FORCE^)d hypotheses are another exception to the general rule of how hypotheses are relieved. Hypotheses marked with syntaxp, as in (syntaxp test), are also exceptions. Instead of instantiating the hypothesis and trying to establish it, we evaluate test in an environment in which its variable symbols are bound to the quotations of the terms to which those variables are bound in the instantiating substitution. In the case in point, we evaluate the test

      (NOT (AND (CONSP X) (EQ (CAR X) 'NORM)))

in an environment where x is bound to '(trn a b), i.e., the list of length three whose car (CAR^) is the symbol 'trn. Thus, the test returns t because x is a consp (CONSP^) and its car (CAR^) is not the symbol 'norm. When the syntaxp test evaluates to t, we consider the syntaxp hypothesis to have been established; this is sound because (syntaxp test) is t regardless of test. If the test evaluates to nil (or fails to evaluate because of guard (GUARD^) violations) we act as though we cannot establish the hypothesis and abandon the attempt to apply the rule; it is always sound to give up.

Note that the test of a syntaxp hypothesis does not deal with the meaning or semantics or values of the terms but with their syntactic forms. In the example above, the syntaxp hypothesis allows the rule to be applied to every target of the form (lxd u), provided (rationalp u) can be established and u is not of the form (norm v). Observe that without this syntactic restriction the rule above could loop producing a sequence of increasingly complex targets (lxd a), (lxd (norm a)), (lxd (norm (norm a))), etc. An intuitive reading of the rule might be “norm the argument of lxd (when it is rationalp (RATIONALP^)) unless it has already been normed.”

Another common syntactic restriction is

       (SYNTAXP (AND (CONSP X) (EQ (CAR X) 'QUOTE))).

A rule with such a hypothesis can be applied only if x is bound to a specific constant. Thus, if x is 23 (which is actually represented internally as (quote 23)), the test evaluates to t; but if x is (+ 11 12) it evaluates to nil (because (car x) is the symbol '+ (+^)). It is often desirable to delay the application of a rule until certain subterms are in some kind of normal form so that the application doesn’t produce excessive case splits.

8.87 TERM

TERM the three senses of well-formed ACL2 expressions or formulas

     Examples of Terms:
     (cond ((caar x) (cons t x)) (t 0))   ; an untranslated term
     (if (car (car x)) (cons 't x) '0)    ; a translated term
     (car (cons x y) 'nil v)              ; a pseudo-term

In traditional first-order predicate calculus a “term” is a syntactic entity denoting some object in the universe of individuals. Often, for example, the syntactic characterization of a term is that it is either a variable symbol or the application of a function symbol to the appropriate number of argument terms. Traditionally, “atomic formulas” are built from terms with predicate symbols such as “equal” and “member;” “formulas” are then built from atomic formulas with propositional “operators” like “not,” “and,” and “implies.” Theorems are formulas. Theorems are “valid” in the sense that the value of a theorem is true, in any model of the axioms and under all possible assignments of individuals to variables.

However, in ACL2, terms are used in place of both atomic formulas and formulas. ACL2 does not have predicate symbols or propositional operators as distinguished syntactic entities. The ACL2 universe of individuals includes a “true” object (denoted by t) and a “false” object (denoted by nil), predicates and propositional operators are functions that return these objects. Theorems in ACL2 are terms and the “validity” of a term means that, under no assignment to the variables does the term evaluate to nil.

We use the word “term” in ACL2 in three distinct senses. We will speak of “translated” terms, “untranslated” terms, and “pseudo-” terms.

Translated Terms: The Strict Sense and Internal Form

In its most strict sense, a “term” is either a legal variable symbol, a quoted constant, or the application of an n-ary function symbol or closed lambda expression to a true list of n terms.

The legal variable symbols are symbols other than t or nil which are not in the keyword package, do not start with ampersand, do not start and end with asterisks, and if in the main Lisp package, do not violate an appropriate restriction (see Section 8.67 [NAME], page 352).

Quoted constants are expressions of the form (quote x), where x is any ACL2 object. Such expressions may also be written 'x.

Closed lambda expressions are expressions of the form (lambda (v1 ... vn) body) where the vi are distinct legal variable symbols, body is a term, and the only free variables in body are among the vi.

The function termp, which takes two arguments, an alleged term x and a logical world w (see Section 8.100 [WORLD], page 399), recognizes terms of a given extension of the logic. Termp is defined in :program (PROGRAM^) mode. Its definition may be inspected with :pe (PE^) termp for a complete specification of what we mean by “term” in the most strict sense. Most ACL2 termprocessing functions deal with terms in this strict sense and use termp as a guard (GUARD^). That is, the “internal form” of a term satisfies termp, the strict sense of the word “term.”

Untranslated Terms: What the User Types

While terms in the strict sense are easy to explore (because their structure is so regular and simple) they can be cumbersome to type. Thus, ACL2 supports a more sugary syntax that includes uses of macros and constant symbols. Very roughly speaking, macros are functions that produce terms as their results. Constants are symbols that are associated with quoted objects. Terms in this sugary syntax are “translated” to terms in the strict sense; the sugary syntax is more often called “untranslated.” Roughly speaking, translation just implements macroexpansion, the replacement of constant symbols by their quoted values, and the checking of all the rules governing the strict sense of “term.”

More precisely, macro symbols are as described in the documentation for defmacro (DEF-MACRO^). A macro, mac, can be thought of as a function, mac-fn, from ACL2 objects to an ACL2 object to be treated as an untranslated term. For example, caar (CAAR^) is defined as a macro symbol; the associated macro function maps the object x into the object (car (car x)). A macro form is a “call” of a macro symbol, i.e., a list whose car (CAR^) is the macro symbol and whose cdr (CDR^) is an arbitrary true list of objects, used as a term. Macroexpansion is the process of replacing in an untranslated term every occurrence of a macro form by the result of applying the macro function to the appropriate arguments. The “appropriate” arguments are determined by the exact form of the definition of the macro; macros support positional, keyword, optional and other kinds of arguments. See Section 6.10 [DEFMACRO], page 171.

In addition to macroexpansion and constant symbol dereferencing, translation implements the mapping of let (LET^) and let* (LET*^) forms into applications of lambda expressions and closes lambda expressions containing free variables. Thus, the translation of

     (let ((x (1+ i))) (cons x k))

can be seen as a two-step process that first produces

     ((lambda (x) (cons x k)) (1+ i))

and then

     ((lambda (x k) (cons x k)) (1+ i) k) .

Observe that the body of the let (LET^) and of the first lambda expression contains a free k which is finally bound and passed into the second lambda expression.

When we say, of an event-level function such as defun (DEFUN^) or defthm (DEFTHM^), that some argument “must be a term” we mean an untranslated term. The event functions translate their term-like arguments.

To better understand the mapping between untranslated terms and translated terms it is convenient to use the keyword command :trans (TRANS^) to see examples of translations. See Section 9.16 [TRANS], page 427 and also see Section 9.17 [TRANS1], page 427.

Pseudo-Terms: A Common Guard for Metafunctions

Because termp is defined in :program (PROGRAM^) mode, it cannot be used effectively in conjectures to be proved. Furthermore, from the perspective of merely guarding a term processing function, termp often checks more than is required. Finally, because termp requires the logical world (WORLD^) as one of its arguments it is impossible to use termp as a guard (GUARD^) in places where the logical world (WORLD^) is not itself one of the arguments.

For these reasons we support the idea of “pseudo-terms.” A pseudo-term is either a symbol (but not necessarily one having the syntax of a legal variable symbol), a true list beginning with quote (but not necessarily well-formed), or the “application of” a symbol or pseudo lambda expression to a true list of pseudo-terms. A pseudo lambda expression is an expression of the form (lambda (v1 ... vn) body) where the vi are all symbols and body is a pseudo-term.

Pseudo-terms are recognized by the unary function pseudo-termp (PSEUDO-TERMP^). If (termp x w) is true, then (pseudo-termp x) is true. However, if x fails to be a (strict) term it may nevertheless still be a pseudo-term. For example, (car a b) is not a term, because car (CAR^) is applied to the wrong number of arguments, but it is a pseudo-term.

The structures recognized by pseudo-termp (PSEUDO-TERMP^) can be recursively explored with the same simplicity that terms can be. In particular, if x is not a variablep or an fquotep, then (ffn-symb x) is the function (symbol or lambda expression) and (fargs x) is the list of argument pseudo-terms. A metafunction may use pseudo-termp (PSEUDO-TERMP^) as the guard (GUARD^).

8.88 TERM-ORDER

TERM-ORDER the ordering relation on terms used by ACL2 ACL2 must occasionally choose which of two terms is syntactically smaller. The need for such a choice arises, for example, when using equality hypotheses in conjectures (the smaller term is substituted for the larger elsewhere in the formula), in stopping loops in permutative rewrite rules (see Section 8.64 [LOOP-STOPPER], page 347), and in choosing the order in which to try to cancel the addends in linear arithmetic inequalities. When this notion of syntactic size is needed, ACL2 uses “term order.” Popularly speaking, term order is just a lexicographic ordering on terms. But the situation is actually more complicated.

We define term order only with respect to terms in translated form. See Section 9.16 [TRANS], page 427.

Term1 comes before term2 in the term order iff

(a) the number of variable occurrences in term1 is less than that in term2, or

(b) the numbers of variable occurrences in the two terms are equal but the number of function applications in term1 is less than that in term2, or

(c) the numbers of variable occurrences in the two terms are equal, the numbers of functions applications in the two terms are equal, and term1 comes before term2 in a certain lexicographic ordering based their structure as Lisp objects.

The function term-order, when applied to the translations of two ACL2 terms, returns t iff the first is “less than or equal” to the second in the term order.

By “number of variable occurrences” we do not mean “number of distinct variables” but “number of times a variable symbol is mentioned.” (cons x x) has two variable occurrences, not one. Thus, perhaps counterintuitively, a large term that contains only one variable occurrence, e.g.,

(standard-char-p (car (reverse x))) comes before (cons x x) in the term order.

Since constants contain no variable occurrences and non-constant expressions must contain at least one variable occurrence, constants come before non-constants in the term order, no matter how large the constants. For example, the list constant

     '(monday tuesday wednesday thursday friday)

comes before x in the term order. Because term order is involved in the control of permutative rewrite rules and used to shift smaller terms to the left, a set of permutative rules designed to allow the permutation of any two tips in a tree representing the nested application of some function will always move the constants into the left-most tips. Thus,

     (+ x 3 (car (reverse klst)) (dx i j)) ,

which in translated form is

     (binary-+ x
               (binary-+ '3
                         (binary-+ (dx i j)
                                   (car (reverse klst))))),

will be permuted under the built-in commutativity rules to

     (binary-+ '3
               (binary-+ x
                         (binary-+ (car (reverse klst))
                                   (dx i j))))

or

     (+ 3 x (car (reverse klst)) (dx i j)).

Clearly, two constants are ordered using cases (b) and (c) of term order, since they each contain 0 variable occurrences. This raises the question “How many function applications are in a constant?” Because we regard the number of function applications as a more fundamental measure of the size of a constant than lexicographic considerations, we decided that for the purposes of term order, constants would be seen as being built by primitive constructor functions. These constructor functions are not actually defined in ACL2 but merely imagined for the purposes of term order. We here use suggestive names for these imagined functions, ignoring entirely the prior use of these names within ACL2.

The constant function z constructs 0. Positive integers are constructed from (z) by the successor function, s. Thus 2 is (s (s (z))) and contains three function applications. 100 contains one hundred and one applications. Negative integers are constructed from their positive counterparts by - (-^). Thus, -2 is (- (s (s (z)))) and has four applications. Ratios are constructed by the dyadic function / (/^). Thus, -1/2 is

     (/ (- (s (z))) (s (s (z))))

and contains seven applications. Complex rationals are similarly constructed from rationals. All character objects are considered primitive and are constructed by constant functions of the same name. Thus #\a and #\b both contain one application. Strings are built from the empty string, (o) by the “string-cons” function written cs. Thus "AB" is (cs (#\a) (cs (#\b) (o))) and contains five applications. Symbols are obtained from strings by “packing” the symbol-name (SYMBOL-NAME^) with the unary function p. Thus 'ab is

     (p (cs (#\a) (cs (#\b) (o))))

and has six applications. Note that packages are here ignored and thus 'acl2::ab and 'mypackage::ab each contain just six applications. Finally, cons (CONS^)es are built with cons (CONS^), as usual. So '(1 . 2) is (cons '1 '2) and contains six applications, since '1 contains two and '2 contains three. This, for better or worse, answers the question “How many function applications are in a constant?”

Two terms with the same numbers of variable occurrences and function applications are ordered by lexicographic means, based on their structures. In the lexicographic ordering, two atom (ATOM^)s are ordered “alphabetically” as described below, an atom (ATOM^) and a cons (CONS^) are ordered so that the atom (ATOM^) comes first, and two cons (CONS^)es are ordered so that the one with the recursively smaller car (CAR^) comes first, with the cdr (CDR^)s being compared only if the car (CAR^)s are equal. Thus, if two terms (member ...) and (reverse ...) contain the same numbers of variable occurrences and function applications, then the member (MEMBER^) term is first in the term order because member (MEMBER^) comes before reverse (REVERSE^) in the term order (which is here reduced to alphabetic ordering).

It remains only to define what we mean by the alphabetic ordering on Lisp atom (ATOM^)s. Within a single type, numbers are compared arithmetically, characters (CHARACTERS^) are compared via their (char) codes, and strings and symbols are compared with the conventional alphabetic ordering on sequences of characters (CHARACTERS^). Across types, numbers come before characters (CHARACTERS^), characters (CHARACTERS^) before strings, and strings before symbols.

8.89 TTREE

TTREE tag trees

Many low-level ACL2 functions take and return “tag trees” or “ttrees” (pronounced “tee-trees”) which contain various useful bits of information such as the lemmas used, the linearize assumptions made, etc.

Let a “tagged pair” be a list whose car is a symbol, called the “tag,” and whose cdr is an arbitrary object, called the “tagged object.” A “tag tree” is either nil, a tagged pair consed onto a tag tree, or a non-nil tag tree consed onto a tag tree.

Abstractly a tag tree represents a list of sets, each member set having a name given by one of the tags occurring in the ttree. The elements of the set named tag are all of the objects tagged tag in the tree. To cons a tagged pair (tag . obj) onto a tree is to add-to-set-equal obj to the set corresponding to tag. To cons two tag trees together is to union-equal the corresponding sets. The concrete representation of the union so produced has duplicates in it, but we feel free to ignore or delete duplicates.

The beauty of this definition is that to combine two non-nil tag trees you need do only one cons.

The following function accumulates onto ans the set associated with a given tag in a ttree:

     (defun tagged-objects (tag ttree ans)
      (cond
       ((null ttree) ans)
       ((symbolp (caar ttree))             ; ttree = ((tag . obj) . ttree)
        (tagged-objects tag (cdr ttree)
                        (cond ((eq (caar ttree) tag)
                               (add-to-set-equal (cdar ttree) ans))
                              (t ans))))
       (t                                  ; ttree = (ttree . ttree)
          (tagged-objects tag (cdr ttree)
                              (tagged-objects tag (car ttree) ans)))))

This function is defined as a :PROGRAM (PROGRAM^) mode function in ACL2.

The rewriter, for example, takes a term and a ttree (among other things), and returns a new term, term’, and new ttree, ttree’. Term’ is equivalent to term (under the current assumptions) and the ttree’ is an extension of ttree. If we focus just on the set associated with the tag LEMMA in the ttrees, then the set for ttree’ is the extension of that for ttree obtained by unioning into it all the runes used by the rewrite. The set associated with LEMMA can be obtained by (tagged-objects

'LEMMA ttree nil).

8.90 TYPE-SET

TYPE-SET how type information is encoded in ACL2 To help you experiment with type-sets we briefly note the following utility functions.

(type-set-quote x) will return the type-set of the object x. For example, (type-set-quote

"test") is 2048 and (type-set-quote '(a b c)) is 512.
(type-set 'term nil nil nil nil (ens state) (w state) nil) will return the type-set of

term. For example,

     (type-set '(integerp x) nil nil nil nil (ens state) (w state) nil)

will return (mv 192 nil). 192, otherwise known as *ts-boolean*, is the type-set containing t and nil. The second result may be ignored in these experiments. Term must be in the translated, internal form shown by :trans (TRANS^). See Section 9.16 [TRANS], page 427 and see Section 8.87 [TERM], page 376.

(type-set-implied-by-term 'x nil 'term (ens state)(w state) nil) will return the type-

set deduced for the variable symbol x assuming the translated term, term, true. The second result may be ignored in these experiments. For example,

     (type-set-implied-by-term 'v nil '(integerp v)
                               (ens state) (w state) nil)

returns 11.

(convert-type-set-to-term 'x ts (ens state) (w state) nil) will return a term whose

truth is equivalent to the assertion that the term x has type-set ts. The second result may be ignored in these experiments. For example

     (convert-type-set-to-term 'v 523 (ens state) (w state) nil)

returns a term expressing the claim that v is either an integer or a non-nil true-list. 523 is the logical-or of 11 (which denotes the integers) with 512 (which denotes the non-nil true-lists).

The “actual primitive types” of ACL2 are listed in *actual-primitive-types*. These primitive

types include such types as *ts-zero*, *ts-positive-integer*, *ts-nil* and *ts-proper-

consp*. Each actual primitive type denotes a set — sometimes finite and sometimes not — of ACL2 objects and these sets are pairwise disjoint. For example, *ts-zero* denotes the set containing 0 while *ts-positive-integer* denotes the set containing all of the positive integers.

The actual primitive types were chosen by us to make theorem proving convenient. Thus, for example, the actual primitive type *ts-nil* contains just nil so that we can encode the hypothesis “x is nil” by saying “x has type *ts-nil*” and the hypothesis “x is non-nil” by saying “x has type complement of *ts-nil*.” We similarly devote a primitive type to t, *ts-t*, and to a third type, *ts-non-t-non-nil-symbol*, to contain all the other ACL2 symbols.

Let *ts-other* denote the set of all Common Lisp objects other than those in the actual primitive types. Thus, *ts-other* includes such things as floating point numbers and CLTL array objects. The actual primitive types together with *ts-other* constitute what we call *universe*. Note that *universe* is a finite set containing one more object than there are actual primitive types; that is, here we are using *universe* to mean the finite set of primitive types, not the infinite set of all objects in all of those primitive types. *Universe* is a partitioning of the set of all Common Lisp objects: every object belongs to exactly one of the sets in *universe*.

Abstractly, a “type-set” is a subset of *universe*. To say that a term, x, “has type-set ts” means that under all possible assignments to the variables in x, the value of x is a member of

some member of ts. Thus, (cons x y) has type-set {*ts-proper-cons* *ts-improper-cons*}.

A term can have more than one type-set. For example, (cons x y) also has the type-set {*ts-

proper-cons* *ts-improper-cons* *ts-nil*}. Extraneous types can be added to a type-set

without invalidating the claim that a term “has” that type-set. Generally we are interested in the smallest type-set a term has, but because the entire theorem-proving problem for ACL2 can be encoded as a type-set question, namely, “Does p have type-set complement of *ts-nil*?,” finding the smallest type-set for a term is an undecidable problem. When we speak informally of “the” type-set we generally mean “the type-set found by our heuristics” or “the type-set assumed in the current context.”

Note that if a type-set, ts, does not contain *ts-other* as an element then it is just a subset of the actual primitive types. If it does contain *ts-other* it can be obtained by subtracting from *universe* the complement of ts. Thus, every type-set can be written as a (possibly complemented) subset of the actual primitive types.

By assigning a unique bit position to each actual primitive type we can encode every subset, s, of the actual primitive types by the nonnegative integer whose ith bit is on precisely if s contains the ith actual primitive type. The type-sets written as the complement of s are encoded as the twoscomplement of the encoding of s. Those type-sets are thus negative integers. The bit positions assigned to the actual primitive types are enumerated from 0 in the same order as the types are listed in *actual-primitive-types*. At the concrete level, a type-set is an integer between

*min-type-set* and *max-type-set*, inclusive.

For example, *ts-nil* has bit position 6. The type-set containing just *ts-nil* is thus represented by 64. If a term has type-set 64 then the term is always equal to nil. The type-set containing everything but *ts-nil* is the twos-complement of 64, which is -65. If a term has type-set -65, it is never equal to nil. By “always” and “never” we mean under all, or under no, assignments to the variables, respectively.

Here is a more complicated example. Let s be the type-set containing all of the symbols and the natural numbers. The relevant actual primitive types, their bit positions and their encodings are:

     actual primitive type       bit    value
     *ts-zero*                    0       1
     *ts-positive-integer*        1       2
     *ts-nil*                     6      64
     *ts-t*                       7     128
     *ts-non-t-non-nil-symbol*    8     256

Thus, the type-set s is represented by (+ 1 2 64 128 256) = 451. The complement of s, i.e., the set of all objects other than the natural numbers and the symbols, is -452.

8.91 USING-COMPUTED-HINTS

USING-COMPUTED-HINTS how to use computed hints

Computed hints are extraordinarily powerful. We show a few examples here to illustrate their use. We recommend that these be read in the following sequence:

Related topics other than immediate subtopics:

* USING-COMPUTED-HINTS-1:: Driving Home the Basics

* USING-COMPUTED-HINTS-2:: One Hint to Every Top-Level Goal in a Forcing Round

* USING-COMPUTED-HINTS-3:: Hints as a Function of the Goal (not its Name)

* USING-COMPUTED-HINTS-4:: Computing the Hints

* USING-COMPUTED-HINTS-5:: Debugging Computed Hints

* USING-COMPUTED-HINTS-6:: Some Final Comments

8.92 USING-COMPUTED-HINTS-1

USING-COMPUTED-HINTS-1 Driving Home the Basics The common hint

     ("Subgoal 3.2.1''" :use lemma42)

has the same effect as the computed hint

     (if (equal id '((0) (3 2 1) . 2))
         '(:use lemma42)
         nil)

which, of course, is equivalent to

     (and (equal id '((0) (3 2 1) . 2))
          '(:use lemma42))

which is also equivalent to the computed hint

     my-special-hint

provided the following defun has first been executed

     (defun my-special-hint (id clause world)
       (declare (xargs :mode :program)
                (ignore clause world))
       (if (equal id '((0) (3 2 1) . 2))
           '(:use lemma42)
           nil))

It is permitted for the defun to be in :LOGIC mode (see Section 8.20 [DEFUN-MODE], page 275) also.

Just to be concrete, the following three events all behave the same way (if my-special-hint is as above):

     (defthm main (big-thm a b c)
       :hints (("Subgoal 3.2.1''" :use lemma42)))
     (defthm main (big-thm a b c)
       :hints ((and (equal id '((0) (3 2 1) . 2)) '(:use lemma42))))
     (defthm main (big-thm a b c)
       :hints (my-special-hint))

8.93 USING-COMPUTED-HINTS-2

USING-COMPUTED-HINTS-2 One Hint to Every Top-Level Goal in a Forcing Round

Suppose the main proof completes with a forcing round on three subgoals, "[1]Subgoal 3", "[1]Subgoal 2", and "[1]Subgoal 1". Suppose you wish to :use lemma42 in all top-level goals of the first forcing round. This can be done supplying the hint

     (if test '(:use lemma42) nil),

where test is an expression that returns t when ID is one of the clause ids in question.

         goal-spec     (parse-clause-id goal-spec)
     "[1]Subgoal 3"        ((1) (3) . 0)
     "[1]Subgoal 2"        ((1) (2) . 0)
     "[1]Subgoal 1"        ((1) (1) . 0)

Recall (see Section 8.10 [CLAUSE-IDENTIFIER], page 260) that parse-clause-id maps from a goal spec to a clause id, so you can use that function on the goal specs printed in the failed proof attempt to determine the clause ids in question.

So one acceptable test is

     (member-equal id '(((1) (3) . 0)
                        ((1) (2) . 0)
                        ((1) (1) . 0)))

or you could use parse-clause-id in your computed hint if you don’t want to see clause ids in your script:

     (or (equal id (parse-clause-id "[1]Subgoal 3"))
         (equal id (parse-clause-id "[1]Subgoal 2"))
         (equal id (parse-clause-id "[1]Subgoal 1")))

or you could use the inverse function (see Section 8.10 [CLAUSE-IDENTIFIER], page 260):

     (member-equal (string-for-tilde-@-clause-id-phrase id)
                   '("[1]Subgoal 3"
                     "[1]Subgoal 2"
                     "[1]Subgoal 1"))

Recall that what we’ve shown above are the tests to use in the computed hint. The hint itself is

(if test '(:use lemma42) nil) or something equivalent like (and test '(:use lemma42)).

The three tests above are all equivalent. They suffer from the problem of requiring the explicit enumeration of all the goal specs in the first forcing round. A change in the script might cause more forced subgoals and the ones other than those enumerated would not be given the hint.

You could write a test that recognizes all first round top-level subgoals no matter how many there are. Just think of the programming problem: how do I recognize all the clause id’s of the form ((1)

(n) . 0)? Often you can come to this formulation of the problem by using parse-clause-id on a few of the candidate goal-specs to see the common structure. A suitable test in this case is:

     (and (equal (car id) '(1))     ; forcing round 1, top-level (pre-induction)
          (equal (len (cadr id)) 1) ; Subgoal n (not Subgoal n.i ...)
          (equal (cddr id) 0))      ; no primes

The test above is “overkill” because it recognizes precisely the clause ids in question. But recall that once a computed hint is used, it is removed from the hints available to the children of the clause. Thus, we can widen the set of clause ids recognized to include all the children without worrying that the hint will be applied to those children.

In particular, the following test supplies the hint to every top-level goal of the first forcing round:

     (equal (car id) '(1))

You might worry that it would also supply the hint to the subgoal produced by the hint – the cases we ruled out by the “overkill” above. But that doesn’t happen since the hint is unavailable to the children. You could even write:

     (equal (car (car id)) 1)

which would supply the hint to every goal of the form "[1]Subgoal ..." and again, because we see and fire on the top-level goals first, we will not fire on, say, "[1]Subgoal *1.3/2", i.e., the id ’((1 1 3) (2) . 0) even though the test recognizes that id.

Finally, the following test supplies the hint to every top-level goal of every forcing round (except the 0th, which is the “gist” of the proof, not “really” a forcing round):

     (not (equal (car (car id)) 0))

Recall again that in all the examples above we have exhibited the test in a computed hint of the

form (if test '(:key1 val1 ...) nil).

8.94 USING-COMPUTED-HINTS-3

USING-COMPUTED-HINTS-3 Hints as a Function of the Goal (not its Name)

Sometimes it is desirable to supply a hint whenever a certain term arises in a conjecture. For example, suppose we have proved

     (defthm all-swaps-have-the-property
        (the-property (swap x))
        :rule-classes nil)

and suppose that whenever (SWAP A) occurs in a goal, we wish to add the additional hypothesis that (THE-PROPERTY (SWAP A)). Note that this is equivalent supplying the hint

     (if test
         '(:use (:instance all-swaps-have-the-property (x A)))
         nil)

where test answers the question “does the clause contain (SWAP A)?” That question can be asked with (occur-lst '(SWAP A) clause). Briefly, occur-lst takes the representation of a translated term, x, and a list of translated terms, y, and determines whether x occurs as a subterm of any term in y. (By “subterm” here we mean proper or improper, e.g., the subterms of (CAR X) are X

and (CAR X).)

Thus, the computed hint:

     (if (occur-lst '(swap a) clause)
         '(:use (:instance all-swaps-have-the-property (x A)))
         nil)

will add the hypothesis (THE-PROPERTY (SWAP A)) to every goal containing (SWAP A) – except the children of goals to which the hypothesis was added.

A COMMON MISTAKE users are likely to make is to forget that they are dealing with translated terms. For example, suppose we wished to look for (SWAP (LIST 1 A)) with occur-lst. We would never find it with

     (occur-lst '(SWAP (LIST 1 A)) clause)

because that presentation of the term contains macros and other abbreviations. By using :trans (see Section 9.16 [TRANS], page 427) we can obtain the translation of the target term. Then we can look for it with:

     (occur-lst '(SWAP (CONS '1 (CONS A 'NIL))) clause)

Note in particular that you must

* eliminate all macros and

* explicitly quote all constants.

We recommend using :trans to obtain the translated form of the terms in which you are interested, before programming your hints.

An alternative is to use the expression (prettyify-clause clause) in your hint to convert the current goal clause into the s-expression that is actually printed. For example, the clause

     ((NOT (CONSP X)) (SYMBOLP Y) (EQUAL (CONS '1 (CAR X)) Y))

“prettyifies” to

     (IMPLIES (AND (CONSP X)
                   (NOT (SYMBOLP Y)))
              (EQUAL (CONS 1 (CAR X)) Y))

which is what you would see printed by ACL2 when the goal clause is that shown.

However, if you choose to convert your clauses to prettyified form, you will have to write your own explorers (like our occur-lst), because all of the ACL2 term processing utilities work on translated and/or clausal forms. This should not be taken as a terrible burden. You will, at least, gain the benefit of knowing what you are really looking for, because your explorers will be looking at exactly the s-expressions you see at your terminal. And you won’t have to wade through our still undocumented term/clause utilities. The approach will slow things down a little, since you will be paying the price of independently consing up the prettyified term.

We make one more note on this example. We said above that the computed hint:

     (if (occur-lst '(swap a) clause)
         '(:use (:instance all-swaps-have-the-property (x A)))
         nil)

will add the hypothesis (THE-PROPERTY (SWAP A)) to every goal containing (SWAP A) – except the children of goals to which the hypothesis was added.

It bears noting that the subgoals produced by induction and top-level forcing round goals are not children. For example, suppose the hint above fires on "Subgoal 3" and produces, say, "Subgoal 3’". Then the hint will not fire on "Subgoal 3’" even though it (still) contains (SWAP A) because "Subgoal 3’" is a child of a goal on which the hint fired.

But now suppose that "Subgoal 3’" is pushed for induction. Then the goals created by that induction, i.e., the base case and induction step, are not considered children of "Subgoal 3’". All of the original hints are available.

Alternatively, suppose that "Subgoal 3’ is proved but forces some other subgoal, "[1]Subgoal 1" which is attacked in Forcing Round 1. That top-level forced subgoal is not a child. All the original hints are available to it. Thus, if it contains (SWAP A), the hint will fire and supply the hypothesis, producing "[1]Subgoal 1’". This may be unnecessary, as the hypothesis might already be present in "[1]Subgoal 1". In this case, no harm is done. The hint won’t fire on "[1]Subgoal 1" because it is a child of "[1]Subgoal 1" and the hint fired on that.

8.95 USING-COMPUTED-HINTS-4

USING-COMPUTED-HINTS-4 Computing the Hints

So far we have used computed hints only to compute when a fixed set of keys and values are to be used as a hint. But computed hints can, of course, compute the set of keys and values. You might, for example, write a hint that recognizes when a clause “ought” to be provable by a :BDD hint and generate the appropriate hint. You might build in a set of useful lemmas and check to see if the clause is proveable :BY one of them. You can keep all function symbols disabled and use computed hints to compute which ones you want to :EXPAND. In general, you can write a theorem prover for use in your hints, provided you can get it do its job by directing our theorem prover.

Suppose for example we wish to find every occurrence of an instance of (SWAP x) and provide the corresponding instance of ALL-SWAPS-HAVE-THE-PROPERTY. Obviously, we must explore the clause looking for instances of (SWAP x) and build the appropriate instances of the lemma. We could do this in many different ways, but below we show a general purpose set of utilities for doing it. The functions are not defined in ACL2 but could be defined as shown.

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

(3) Generate a :use hint for those instances when instances are found.

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

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

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

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

     (:INSTANCE name (var1 term1) ... (vark termk))

as written in :use hints. In the code shown above, substitutions are lists of pairs of the form (var . term), but in lemma instances we must write “doublets.” So here we show how to convert from one to the other:

     (defun pairs-to-doublets (alist)
       (declare (xargs :mode :program))
       (cond ((null alist) nil)
             (t (cons (list (caar alist) (cdar alist))
                      (pairs-to-doublets (cdr alist))))))

Now we can make a list of lemma instances:

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

Finally, we can package it all together into a hint function. The function takes a pattern, pat, which must be a translated term, the name of a lemma, name, and a clause. If some instances of pat occur in clause, then the corresponding instances of name are :USEd in the computed hint. Otherwise, the hint does not apply.

     (defun add-corresponding-instances (pat name clause)
       (declare (xargs :mode :program))
       (let ((alists (find-all-instances-list pat clause nil)))
         (cond
          ((null alists) nil)
          (t (list :use (make-lemma-instances name alists))))))

The design of this particular hint function makes it important that the variables of the pattern be the variables of the named lemma and that all of the variables we wish to instantiate occur in the pattern. We could, of course, redesign it to allow “free variables” or some sort of renaming.

We could now use this hint as shown below:

     (defthm ... ...
       :hints ((add-corresponding-instances
                '(SWAP x)
                'ALL-SWAPS-HAVE-THE-PROPERTY
                clause)))

The effect of the hint above is that any time a clause arises in which any instance of (SWAP x) appears, we add the corresponding instance of ALL-SWAPS-HAVE-THE-PROPERTY. So for example, if Subgoal *1/3.5 contains the subterm (SWAP (SWAP A)) then this hint fires and makes the system behave as though the hint:

     ("Subgoal *1/3.5"
      :USE ((:INSTANCE ALL-SWAPS-HAVE-THE-PROPERTY (X A))
            (:INSTANCE ALL-SWAPS-HAVE-THE-PROPERTY (X (SWAP A)))))

had been present.

8.96 USING-COMPUTED-HINTS-5

USING-COMPUTED-HINTS-5 Debugging Computed Hints

We have found that it is sometimes helpful to define hints so that they print out messages to the terminal when they fire, so you can see what hint was generated and which of your computed hints did it.

To that end we have defined a macro we sometimes use. Suppose you have a :hints specification such as:

     :hints (computed-hint-fn (hint-expr id))

If you defmacro the macro below you could then write instead:

     :hints ((show-hint computed-hint-fn 1)
             (show-hint (hint-expr id) 2))

with the effect that whenever either hint is fired (i.e., returns non-nil), a message identifying the hint by the marker (1 or 2, above) and the non-nil value is printed.

     (defmacro show-hint (hint &optional marker)

       (cond
        ((and (consp hint)
              (stringp (car hint)))
         hint)
        (t
         `(let ((marker ,marker)
                (ans ,(if (symbolp hint)
                          `(,hint id clause world)
                        hint)))
            (if ans
                (prog2$
                 (cw "~%***** Computed Hint~#0~[~/ (from hint ~x1)~]~%~x2~%~%"
                     (if (null marker) 0 1)
                     marker
                     (cons (string-for-tilde-@-clause-id-phrase id)
                           ans))
                 ans)
              nil)))))

Putting a show-hint around a common hint has no effect. If you find yourself using this utility let us know and we’ll consider putting it into the system itself. But it does illustrate that you can use computed hints to do unusual things.

8.97 USING-COMPUTED-HINTS-6

USING-COMPUTED-HINTS-6 Some Final Comments

None of the examples show the use of the variable WORLD, which is allowed in computed hints. There are some (undocumented) ACL2 utilities that might be useful in programming hints, but these utilities need access to the ACL2 logical world (see Section 8.100 [WORLD], page 399).

Using these utilities to look at the WORLD one can, for example, determine whether a symbol is defined recursively or not, get the body and formals of a defined function, or fetch the statement of a given lemma. Because these utilities are not yet documented, we do not expect users to employ WORLD in computed hints. But experts might and it might lead to the formulation of a more convenient language for computed hints.

If you start using computed hints extensively, please contact the developers of ACL2 and let us know what you are doing with them and how we can help.

8.98 VERSION

VERSION ACL2 Version Number

To determine the version number of your copy of ACL2, evaluate the ACL2 constant *acl2version*. The value will be a string. For example,

     ACL2 !>*acl2-version*
     "ACL2 Version 1.9"

Books (BOOKS^) are considered certified only in the same version of ACL2 in which the certification was done. The certificate (CERTIFICATE^) file records the version number of the certifying ACL2 and include-book (INCLUDE-BOOK^) considers the book uncertified if that does not match the current version number. Thus, each time we release a new version of ACL2, previously certified books must be recertified.

One reason for this is immediately obvious from the fact that the version number is a logical constant in the ACL2 theory: changing the version number changes the axioms! For example, in version 1.8 you can prove

     (defthm version-8
       (equal *acl2-version* "ACL2 Version 1.8"))

while in version 1.9 you can prove

     (defthm version-9
       (equal *acl2-version* "ACL2 Version 1.9"))

Thus, if a book containing the former were included into version 1.9, one could prove a contradiction.

We could eliminate this particular threat of unsoundness by not making the version number part of the axioms. But there are over 150 constants in the system, most having to do with the fact that ACL2 is coded in ACL2, and “version number inconsistency” is just the tip of the iceberg. Other likely-to-change constants include *common-lisp-specials-and-constants*, which may change when we port ACL2 to some new implementation of Common Lisp, and *acl2-exports*, which lists commonly used ACL2 command names users are likely to import into new packages. Furthermore, it is possible that from one version of the system to another we might change, say, the default values on some system function or otherwise make “intentional” changes to the axioms. It is even possible one version of the system is discovered to be unsound and we release a new version to correct our error.

Therefore we adopted the draconian policy that books are certified by a given version of ACL2 and must be recertified to be used in other versions. While there are less draconian solutions to the problems illustrated above, we thought this was the simplest.

8.99 WHY-BRR

WHY-BRR an explanation of why ACL2 has an explicit brr (BRR^) mode

Why isn’t brr (BRR^) mode automatically disabled when there are no monitored runes? The reason is that the list of monitored runes is kept in a wormhole state.

See Section 8.101 [WORMHOLE], page 401 for more information on wormholes in general. But the fundamental property of the wormhole function is that it is a logical no-op, a constant function that does not take state as an argument. When entering a wormhole, arbitrary information can be passed in (including the external state). That information is used to construct a near copy of the external state and that “wormhole state” is the one with respect to which interactions occur during breaks. But no information is carried by ACL2 out of a wormhole — if that were allowed wormholes would not be logical no-ops. The only information carried out of a wormhole is in the user’s head.

Break-rewrite (BREAK-REWRITE^) interacts with the user in a wormhole state because the signature of the ACL2 rewrite function does not permit it to modify state (STATE^). Hence, only wormhole interaction is possible. (This has the additional desirable property that the correctness of the rewriter does not depend on what the user does during interactive breaks within it; indeed, it is logically impossible for the user to affect the course of rewrite (REWRITE^).)

Now consider the list of monitored runes. Is that kept in the external state as a normal state global or is it kept in the wormhole state? If it is in the external state then it can be inspected within the wormhole but not changed. This is unacceptable; it is common to change the monitor (MONITOR^)ed rules as the proof attempt progresses, installing monitors when certain rules are about to be used in certain contexts. Thus, the list of monitored runes must be kept as a wormhole variable. Hence, its value cannot be determined outside the wormhole, where the proof attempt is ongoing.

This raises another question: If the list of monitored runes is unknown to the rewriter operating on the external state, how does the rewriter know when to break? The answer is simple: it breaks every time, for every rune, if brr (BRR^) mode is enabled. The wormhole is entered (silently), computations are done within the wormhole state to determine if the user wants to see the break, and if so, interactions begin. For unmonitored runes and runes with false break conditions, the silent wormhole entry is followed by a silent wormhole exit and the user perceives no break.

Thus, the penalty for running with brr (BRR^) mode enabled when there are no monitored runes is high: a wormhole is entered on every application of every rune and the user is simply unware of it. The user who has finally unmonitored all runes is therefore strongly advised to carry this information out of the wormhole and to do :brr (BRR^) nil in the external state when the next opportunity arises.

8.100 WORLD

WORLD ACL2 property lists and the ACL2 logical data base

A “world” is a list of triples, each of the form (sym prop . val), implementing the ACL2 notion of property lists. ACL2 permits the simultaneous existence of many property list worlds. “The world” is often used as a shorthand for “the ACL2 logical world” which is the particular property list world used within the ACL2 system to maintain the data base of rules.

Common Lisp provides the notion of “property lists” by which one can attach “properties” and their corresponding “values” to symbols. For example, one can arrange for the 'color property of the symbol 'box-14 to be 'purple and the 'color property of the symbol 'triangle-7 to be 'yellow. Access to property lists is given via the Common Lisp function get. Thus, (get 'box-14 'color) might return 'purple. Property lists can be changed via the special form setf. Thus, (setf (get 'box-14 'color) 'blue) changes the Common Lisp property list configuration so that (get 'box-14 'color) returns 'blue. It should be obvious that ACL2 cannot provide this facility, because Common Lisp’s get “function” is not a function of its argument, but instead a function of some implicit state object representing the property list settings for all symbols.

ACL2 provides the functions getprop and putprop which allow one to mimic the Common Lisp property list facility. However, ACL2’s getprop takes as one of its arguments a list that is a direct encoding of what was above called the “state object representing the property list settings for all symbols.” Because ACL2 already has a notion of “state (STATE^)” that is quite distinct from that used here, we call this property list object a “world.” A world is just a true list of triples. Each triple is of the form (sym prop . val). This world can be thought of as a slightly elaborated form of association list and getprop is a slightly elaborated form of assoc (ASSOC^) that takes two keys. When getprop is called on a symbol, s, property p, and world, w, it scans w for the first triple whose sym is s and prop is p and returns the corresponding val. Getprop has two additional arguments, one of which that controls what it returns if no such sym and prop exist in w, and other other of which allows an extremely efficient implementation. To set some property’s value for some symbol, ACL2 provides putprop. (putprop sym prop val w) merely returns a new world, w', in which (sym prop . val) has been cons (CONS^)ed onto the front of w, thus “overwriting” the prop value of sym in w to val and leaving all other properties in w unchanged.

One aspect of ACL2’s property list arrangment is that it is possible to have many different property list worlds. For example, 'box-14 can have 'color'purple in one world and can have 'color'yes in another, and these two worlds can exist simultaneously because getprop is explicitly provided the world from which the property value is to be extracted.

The efficiency alluded to above stems from the fact that Common Lisp provides property lists. Using Common Lisp’s provisions behind the scenes, ACL2 can “install” the properties of a given world into the Common Lisp property list state so as to make retrieval via getprop very fast in the special case that the world provided to getprop has been installed. To permit multiple installed worlds, each of which is permitted to be changed via putprop, ACL2 requires that worlds be named and these names are used to distinquish installed versions of the various worlds. At the moment we do not further document getprop and putprop.

However, the ACL2 system uses a property list world, named 'current-acl2-world, in which to store the succession of user command (COMMAND^)s and their effects on the logic. This world is often referred to in our documentation (DOCUMENTATION^) as “the world” though it should be stressed that the user is permitted to have worlds and ACL2’s is in no way distinguished except that the user is not permitted to modify it except via event command (COMMAND^)s. The ACL2 world is part of the ACL2 state (STATE^) and may be obtained via (w state).

Warning: The ACL2 world is very large. Its length as of this writing (Version 1.5) is over 31,000 and it grows with each release. Furthermore, some of the values stored in it are pointers to old versions of itself. Printing (w state) is something you should avoid because you likely will not have the patience to await its completion. For these practical reasons, the only thing you should do with (w state) is provide it to getprop, as in the form

       (getprop sym prop default 'current-acl2-world (w state))

to inspect properties within it, or to pass it to ACL2 primitives, such as theory functions, where it is expected.

Some ACL2 command (COMMAND^) forms, such as theory expressions (see Chapter 16 [THE-ORIES], page 775) and the values to be stored in tables (see Section 6.36 [TABLE], page 204), are permitted to use the variable symbol world freely with the understanding that when these forms are evaluated that variable is bound to (w state). Theoretically, this gives those forms complete knowledge of the current logical configuration of ACL2. However, at the moment, few world scanning functions have been documented for the ACL2 user. Instead, supposedly convenient macro forms have been created and documented. For example, (current-theory :here), which is the theory expression which returns the currently enable (ENABLE^)d theory, actually macroexpands to (current-theory-fn :here world). When evaluated with world bound to (w state), current-theory-fn scans the current ACL2 world and computes the set of rune (RUNE^)s currently enable (ENABLE^)d in it.

8.101 WORMHOLE

WORMHOLE ld (LD^) without state (STATE^) — a short-cut to a parallel universe

     Example Form:
     (wormhole t 'interactive-break nil '(value 'hi!))
                                  ; Enters a recursive read-eval-print loop
                                  ; on a copy of the ``current state (STATE^)'' and
                                  ; returns nil!
     General Form:
     (wormhole pseudo-flg name input form
       :current-package    ...  ; known package name
       :ld-skip-proofsp    ...  ; t, nil or 'include-book
       :ld-redefinition-action  ; nil or '(:a . :b)
       :ld-prompt          ...  ; nil, t, or some prompt printer fn
       :ld-keyword-aliases ...  ; an alist pairing keywords to parse info
       :ld-pre-eval-filter ...  ; :all, :query, or some new name
       :ld-pre-eval-print  ...  ; nil, t, or :never
       :ld-post-eval-print ...  ; nil, t, or :command-conventions
       :ld-evisc-tuple     ...  ; nil or '(alist nil nil level length)
       :ld-error-triples   ...  ; nil or t
       :ld-error-action    ...  ; :continue, :return, or :error
       :ld-query-control-alist  ; alist supplying default responses
       :ld-verbose         ...) ; nil or t

The keyword arguments above are exactly those of ld (LD^) (see Section 9.7 [LD], page 416) except that three of ld (LD^)’s keyword arguments are missing: the three that specify the channels standard-oi (STANDARD-OI^), standard-co (STANDARD-CO^) and proofs-co (PROOFS-CO^). Essentially wormhole is just a call of ld (LD^) on the current state (STATE^) with the given keyword arguments. Wormhole always returns nil. The amazing thing about wormhole is that it calls ld (LD^) and interacts with the user even though state (STATE^) is not available as an argument!

Wormhole does this by manufacturing a “wormhole state (STATE^),” a copy of the “current state (STATE^)” (whatever that is) modified so as to contain some of the wormhole arguments. Ld (LD^) is called on that wormhole state (STATE^) with the three ld (LD^) channels directed to ACL2’s “comment window.” At the moment, the comment window is overlaid on the terminal and you cannot tell when output is going to *standard-co* (*STANDARD-CO*^) and when it is going to the comment window. But we imagine that eventually a different window will pop up on your screen. In any case, the interaction provided by this call of ld (LD^) does not modify the state (STATE^) “from which” wormhole was called, it modifies the copied state (STATE^). When ld (LD^) exits (e.g., in response to :q (Q^) being typed in the comment window) the wormhole state (STATE^) evaporates and wormhole returns nil. Logically and actually (from the perspective of the ongoing computation) nothing has happened except that a “no-op” function was called and returned nil.

The name wormhole is meant to suggest the idea that the function provides easy access to state (STATE^) in situations where it is apparently impossible to get state (STATE^). Thus, for example, if you define the factorial function, say, except that you sprinkled into its body appropriate calls of wormhole, then the execution of (factorial 6) would cause interactive breaks in the comment window. During those breaks you would apparently be able to inspect the “current state (STATE^)” even though factorial does not take state (STATE^) as an argument. The whole notion of there being a “current state (STATE^)” during the evaluation of (factorial 6) is logically ill-defined. And yet, we know from practical experience with the sequential computing machines upon which ACL2 is implemented that there is a “current state (STATE^)” (to which the factorial function is entirely insensitive) and that is the state (STATE^) to which wormhole “tunnels.” A call of wormhole from within factorial can pass factorial-specific information that is embedded in the wormhole state (STATE^) and made available for inspection by the user in an interactive setting. But no information ever flows out of a wormhole state (STATE^): wormhole always returns nil.

There are four arguments to wormhole that need further explanation: pseudo-flg, name, input, and form. Roughly speaking, the value of pseudo-flg should be t or nil and indicates whether we are actually to enter a wormhole or just return nil immediately. The actual handling of pseudo-flg is more sophisticated and is explained in detail at the end of this documentation (DOCUMENTATION^).

Name and input are used as follows. Recall that wormhole copies the “current state (STATE^)” and then modifies it slightly to obtain the state (STATE^) upon which ld (LD^) is called. We now describe the modifications. First, the state (STATE^) global variable 'wormhole-name is set to name, which may be any non-nil ACL2 object but is usually a symbol. Then, 'wormhole-input is set to input, which may be any ACL2 object. Finally, and inexplicably, 'wormhole-output is set to the value of 'wormhole-output the last time a wormhole named name was exited (or nil if this is the first time a wormhole named name was entered). this last aspect of wormholes, namely the preservation of 'wormhole-output, allows all the wormholes of a given name to communicate with each other.

We can now explain how form is used. The modified state (STATE^) described above is the state (STATE^) on which ld (LD^) is called. However, standard-oi (STANDARD-OI^) — the input channel from which ld (LD^) reads command (COMMAND^)s — is set so that the first command (COMMAND^) that ld (LD^) reads and evaluates is form. If form returns an error triple with value :q (Q^), i.e., form returns via (value :q), then no further command (COMMAND^)s are read, ld (LD^) exits, and the wormhole exits and returns nil. But if form returns any other value (or is not an error triple), then subsequent command (COMMAND^)s are read from the comment window.

As usual, the ld (LD^)-specials affect whether a herald is printed upon entry, whether form is printed before evaluation, whether a prompt (PROMPT^) is printed, how errors are handled, etc. The ld (LD^)-specials can be specified with the corresponding arguments to wormhole. It is standard practice to call wormhole so that the entry to ld (LD^) and the evaluation of form are totally silent. Then, tests in form can inspect the state (STATE^) and decide whether user interaction is desired. If so, form can appropriately set ld-prompt (LD-PROMPT^), ld-error-action (LD-ERROR-ACTION^), etc., print a herald, and then return (value :invisible). Recall (see Section 9.7 [LD], page 416) that (value :invisible) causes ld (LD^) not to print a value for the just executed form. The result of this arrangement is that whether interaction occurs can be based on tests that are performed on the wormhole state (STATE^) after (@ wormhole-input) and the last (@ wormhole-output) are available for inspection. This is important because outside the wormhole you can access wormhole-input (you are passing it into the wormhole) but you may not be able to access the current state (STATE^) (because you might be in factorial) and you definitely cannot access the wormhole-output of the last wormhole because it is not part of the ACL2 state (STATE^). Thus, if the condition under which you wish to interact depends upon the state (STATE^) or that part of it preserved from the last wormhole interaction, that condition can only be tested from within the wormhole, via form.

It is via this mechanism that break-rewrite (BREAK-REWRITE^) (see Chapter 4 [BREAK-REWRITE], page 119) is implemented. To be more precise, the list of monitor (MONITOR^)ed rune (RUNE^)s is maintained as part of the preserved wormhole-output of the break-rewrite (BREAK-REWRITE^) wormhole. Because it is not part of the normal state (STATE^), it may be changed by the user during proofs. That is what allows you to install new monitor (MONITOR^)s while debugging proofs. But that means that the list of monitor (MONITOR^)ed rune (RUNE^)s cannot be inspected from outside the wormhole. Therefore, to decide whether a break is to occur when a given rule is applied, the rewriter must enter the break-rewrite (BREAK-REWRITE^) wormhole, supplying a form that causes interaction if the given rule’s break condition is satisfied.

The user perceives this as though the wormhole was conditionally entered — a perception that is happily at odds with the informed user’s knowledge that the list of monitor (MONITOR^)ed rune (RUNE^)s is not part of the state (STATE^). In fact, the wormhole was unconditionally entered and the condition was checked from within the wormhole, that being the only state (STATE^) in which the condition is known.

Another illustrative example is available in the implemention of the monitor (MONITOR^) command. How can we add a new rune (RUNE^) to the list of monitor (MONITOR^)ed rune (RUNE^)s while in the normal ACL2 state (STATE^) (i.e., while not in a wormhole)? The answer is: by getting into a wormhole. In particular, when you type (monitor rune expr) at the top-level of ACL2, monitor (MONITOR^) enters the break-rewrite (BREAK-REWRITE^) wormhole with a cleverly designed first form. That form adds rune (RUNE^) and expr to the list of monitor (MONITOR^)ed rune (RUNE^)s — said list only being available in break-rewrite (BREAK-REWRITE^) wormhole state (STATE^)s. Then the first form returns (value :q), which causes us to exit the wormhole. By using ld (LD^)-specials that completely suppress all output during the process, it does not appear to the user that a wormhole was entered. The moral here is rather subtle: the first form supplied to wormhole may be the entire computation you want to perform in the wormhole; it need not just be a predicate that decides if interaction is to occur. Using wormholes of different names you can maintain a variety of “hidden” data structures that are always accessible (whether passed in or not). This appears to violate completely the applicative semantics of ACL2, but it does not: because these data structures are only accessible via wormholes, it is impossible for them to affect any ACL2 computation (except in the comment window).

As one might imagine, there is some overhead associated with entering a wormhole because of the need to copy the current state (STATE^). This brings us back to pseudo-flg. Ostensibly, wormhole is a function and hence all of its argument expressions are evaluated outside the function (and hence, outside the wormhole it creates) and then their values are passed into the function where an appropriate wormhole is created. In fact, wormhole is a macro that permits the pseudo-flg expression to peer dimly into the wormhole that will be created before it is created. In particular, pseudo-flg allows the user to access the wormhole-output that will be used to create the wormhole state (STATE^).

This is done by allowing the user to mention the (apparently unbound) variable wormhole-output in the first argument to wormhole. Logically, wormhole is a macro that wraps

     (let ((wormhole-output nil)) ...)

around the expression supplied as its first argument. So logically, wormhole-output is always nil when the expression is evaluated. However, actually, wormhole-output is bound to the value of (@ wormhole-output) on the last exit from a wormhole of the given name (or nil if this is the first entrance). Thus, the pseudo-flg expression, while having to handle the possibility that wormhole-output is nil, will sometimes see non-nil values. The next question is, of course, “But how can you get away with saying that logically wormhole-output is always nil but actually it is not? That doesn’t appear to be sound.” But it is sound because whether pseudo-flg evaluates to nil or non-nil doesn’t matter, since in either case wormhole returns nil. To make that point slightly more formal, imagine that wormhole did not take pseudo-flg as an argument. Then it could be implemented by writing

     (if pseudo-flg (wormhole name input form ...) nil).

Now since wormhole always returns nil, this expression is equivalent to (if pseudo-flg nil nil) and we see that the value of pseudo-flg is irrelevant. So we could in fact allow the user to access arbitrary information to decide which branch of this if to take. We allow access to wormholeoutput because it is often all that is needed. We don’t allow access to state (STATE^) (unless state (STATE^) is available at the level of the wormhole call) for technical reasons having to do with the difficulty of overcoming translate’s prohibition of the sudden appearance of the variable state (STATE^).

We conclude with an example of the use of pseudo-flg. This example is a simplification of our implementation of break-rewrite (BREAK-REWRITE^). To enter break-rewrite (BREAK-REWRITE^) at the beginning of the attempted application of a rule, rule, we use

     (wormhole
      (and (f-get-global 'brr-mode state)
           (member-equal (access rewrite-rule rule :rune)
                         (cdr (assoc-eq 'monitored-runes wormhole-output))))
      'break-rewrite
      ...)

The function in which this call of wormhole occurs has state (STATE^) as a formal. The pseudoflg expression can therefore refer to state (STATE^) to determine whether 'brr-mode is set. But the pseudo-flg expression above mentions the variable wormhole-output; this variable is not bound in the context of the call of wormhole; if wormhole were a simple function symbol, this expression would be illegal because it mentions a free variable.

However, it is useful to think of wormhole as a simple function that evaluates all of its arguments but to also imagine that somehow wormhole-output is magically bound around the first argument so that wormhole-output is the output of the last break-rewrite (BREAK-REWRITE^) wormhole. If we so imagine, then the pseudo-flg expression above evaluates either to nil or non-nil and we will enter the wormhole named break-rewrite (BREAK-REWRITE^) in the latter case.

Now what does the pseudo-flg expression above actually test? We know the format of our own wormhole-output because we are responsible for maintaining it. In particular, we know that the list of monitor (MONITOR^)ed rune (RUNE^)s can be obtained via

     (cdr (assoc-eq 'monitored-runes wormhole-output)).

Using that knowledge we can design a pseudo-flg expression which tests whether (a) we are in brrmode and (b) the rune (RUNE^) of the current rule is a member of the monitor (MONITOR^)ed rune (RUNE^)s. Question (a) is answered by looking into the current state (STATE^). Question (b) is answered by looking into that part of the about-to-be-created wormhole state (STATE^) that will differ from the current state (STATE^). To reiterate the reason we can make wormholeoutput available here even though it is not in the current state (STATE^): logically speaking the value of wormhole-output is irrelevant because it is only used to choose between two identical alternatives. This example also makes it clear that pseudo-flg provides no additional functionality. The test made in the pseudo-flg expression could be moved into the first form evaluated by the wormhole — changing the free variable wormhole-output to (@ wormhole-output) and arranging for the first form to return (value :q) when the pseudo-flg expression returns nil. The only reason we provide the pseudo-flg feature is because it allows the test to be carried out without the overhead of entering the wormhole.

Wormholes can be used not only in :program mode definitions but also in :logic mode definitions. Thus, it is possible (though somewhat cumbersome without investing in macro support) to annotate logical functions with output facilities that do not require STATE. These facilities do not complicate proof obligations. Suppose then that one doctored a simple function, e.g., APP, so as to do some printing and then proved that APP is associative. The proof may generate extraneous output due to the doctoring. Furthermore, contrary to the theorem proved, execution of the function appears to affect *standard-co*. To see what the function “really” does when evaluated, enter raw lisp and set the global variable *inhibit-wormhole-activityp* to t.

8.102 XARGS

XARGS giving hints (HINTS^) to defun (DEFUN^)

Common Lisp’s defun (DEFUN^) function does not easily allow one to pass extra arguments such as “hints (HINTS^)”. ACL2 therefore supports a peculiar new declaration (see Section 10.94 [DECLARE], page 469) designed explicitly for passing additional arguments to defun (DEFUN^) via a keyword-like syntax.

The following declaration is nonsensical but does illustrate all of the xargs (XARGS^) keywords:

     (declare (xargs :guard (symbolp x)
                     :measure (- i j)
                     :well-founded-relation my-wfr
                     :hints (("Goal" :in-theory (theory batch1)))
                     :guard-hints (("Goal" :in-theory (theory batch1)))
                     :mode :logic
                     :verify-guards t
                     :otf-flg t))
     General Form:
     (xargs :key1 val1 ... :keyn valn)

where the keywords and their respective values are as shown below. Note that once “inside” the xargs form, the “extra arguments” to defun (DEFUN^) are passed exactly as though they were keyword arguments.

:GUARD (GUARD^)

Value is a term involving only the formals of the function being defined. The actual guard (GUARD^) used for the definition is the conjunction of all the guard (GUARD^)s and types (see Section 10.94 [DECLARE], page 469) declare (DECLARE^)d.

:GUARD-HINTS

Value: hints (see Section 8.43 [HINTS], page 319), to be used during the guard (GUARD^) verification proofs as opposed to the termination proofs of the defun (DEFUN^).

:MEASURE

Value is a term involving only the formals of the function being defined. This term is indicates what is getting smaller in the recursion. The well-founded relation with which successive measures are compared is e0-ord-< (E0-ORD-<^).

:WELL-FOUNDED-RELATION (WELL-FOUNDED-RELATION^)

Value is a function symbol that is known to be a well-founded relation in the sense that a rule of class :well-founded-relation (WELL-FOUNDED-RELATION^) has been proved about it. See Section 15.17 [WELL-FOUNDED-RELATION], page 769.

:HINTS (HINTS^)

Value: hints (see Section 8.43 [HINTS], page 319), to be used during the termination proofs as opposed to the guard (GUARD^) verification proofs of the defun (DEFUN^).

:MODE

Value is :program (PROGRAM^) or :logic (LOGIC^), indicating the defun (DEFUN^) mode of the function introduced. See Section 8.20 [DEFUN-MODE], page 275. If unspecified, the defun (DEFUN^) mode defaults to the default defun (DEFUN^) mode of the current world (WORLD^). To convert a function from :program (PROGRAM^) mode to :logic (LOGIC^) mode, see Section 6.40 [VERIFY-TERMINATION], page 212.

:VERIFY-GUARDS (VERIFY-GUARDS^)

Value is t or nil, indicating whether or not guard (GUARD^)s are to be verified upon completion of the termination proof. This flag should only be t if the :mode is unspecified but the default defun (DEFUN^) mode is :logic (LOGIC^), or else the :mode is :logic (LOGIC^).

:OTF-FLG (OTF-FLG^)

Value is a flag indicating “onward through the fog” (see Section 8.69 [OTF-FLG], page 353).

9 OTHER

OTHER other commonly used top-level functions

* atsign:: (@) get the value of a global variable in state (STATE^)

* ACL2-DEFAULTS-TABLE:: a table (TABLE^) specifying certain defaults, e.g., the default defunmode (DEFUN-MODE^)

* ASSIGN:: assign to a global variable in state (STATE^)

* CERTIFY-BOOK!:: a variant of certify-book (CERTIFY-BOOK^)

* COMP:: compile some ACL2 functions

* GOOD-BYE:: quit entirely out of Lisp

* LD:: the ACL2 read-eval-print loop, file loader, and command (COMMAND^) processor

* PROPS:: print the ACL2 properties on a symbol

* Q:: quit ACL2 (type :q) — reenter with (lp)

* REBUILD:: a convenient way to reconstruct your old state (STATE^)

* RESET-LD-SPECIALS:: restores initial settings of the ld (LD^) specials

* SET-GUARD-CHECKING:: control checking guard (GUARD^)s during execution of top-level forms * SET-INHIBIT-OUTPUT-LST:: control output

* SKIP-PROOFS:: skip proofs for an event — a quick way to introduce unsoundness

* THM:: prove a theorem

* TRANS:: print the macroexpansion of a form

* TRANS1:: print the one-step macroexpansion of a form

Related topics other than immediate subtopics:

* CERTIFY-BOOK:: how to produce a certificate (CERTIFICATE^) for a book

This section contains an assortment of functions that fit into none of the other categories and yet are suffiently useful as to merit “advertisement” in the :help (HELP^) command.

9.1 @

@ get the value of a global variable in state (STATE^)

     Examples:
     (+ (@ y) 1)
     (assign a (aset1 'ascii-map-array (@ a) 66 'Upper-case-B))
     General Form:
     (@ symbol)

where symbol is any symbol to which you have assign (ASSIGN^)ed a global value. This macro expands into (f-get-global 'symbol state), which retrieves the stored value of the symbol.

The macro assign (ASSIGN^) makes it convenient to set the value of a symbol. The :ubt (UBT^) operation has no effect on the global-table of state (STATE^). Thus, you may use these globals to hang onto useful data structures even though you may undo back past where you computed and saved them.

9.2 ACL2-DEFAULTS-TABLE

ACL2-DEFAULTS-TABLE a table (TABLE^) specifying certain defaults, e.g., the default defunmode (DEFUN-MODE^)

     Example Forms:
     (table acl2-defaults-table :defun-mode) ; current default defun-mode
     (table acl2-defaults-table :defun-mode :program)
                ; set default defun-mode to :program

See Section 6.36 [TABLE], page 204 for a discussion of tables in general. The legal keys for this table (TABLE^) are shown below. They may be accessed and changed via the general mechanisms provided by table (TABLE^)s. However, there are often more convenient ways to access and/or change the defaults. (See also the note below.)

     :defun-mode

the default defun-mode (DEFUN-MODE^), which must be :program (PROGRAM^) or :logic (LOGIC^). See Section 8.20 [DEFUN-MODE], page 275 for a general discussion of defun-mode (DEFUN-MODE^)s. The :defun-mode (DEFUN-MODE^) key may be conveniently set by keyword commands naming the new defun-mode (DEFUN-MODE^), :program (PROGRAM^) and :logic (LOGIC^). See Section 6.25 [PROGRAM], page 195 and see Section 6.22 [LOGIC], page 192.

     :verify-guards-eagerness

an integer between 0 and 2 indicating how eager the system is to verify the guard (GUARD^)s of a defun (DEFUN^) event. See Section 6.34 [SET-VERIFY-GUARDS-EAGERNESS], page 202.

     :compile-fns

When this key’s value is t, functions are compiled when they are defun (DEFUN^)’d; otherwise, the value is nil. To set the flag, see Section 6.27 [SET-COMPILE-FNS], page 197.

     :measure-function

the default measure function used by defun (DEFUN^) when no :measure is supplied in xargs (XARGS^). The default measure function must be a function symbol of one argument. Let mfn be the default measure function and suppose no :measure is supplied with some recursive function definition. Then defun (DEFUN^) finds the first formal, var, that is tested along every branch and changed in each recursive call. The system then “guesses” that (mfn var) is the :measure for that defun (DEFUN^).

     :well-founded-relation

the default well-founded relation used by defun (DEFUN^) when no :well-founded-relation (WELL-FOUNDED-RELATION^) is supplied in xargs (XARGS^). The default well-founded relation must be a function symbol, rel, of two arguments about which a :well-founded-relation (WELL-FOUNDED-RELATION^) rule has been proved. See Section 15.17 [WELL-FOUNDED-RELATION], page 769.

     :invisible-fns-alist

an alist used in the control of permutative rewriting. Each entry in this alist must be of the form (fn ufn1 ufn2 ... ufnk), where fn and each ufni is a function symbol and the ufni are all unary functions. Such an entry makes each of the ufni “invisible” when ordering the arguments of fn via commutative rules. See Section 6.30 [SET-INVISIBLE-FNS-ALIST], page 199.

     :irrelevant-formals-ok

When this key’s value is t, the check for irrelevant formals is bypassed; otherwise, the value is the keyword nil (the default). See Section 10.136 [IRRELEVANT-FORMALS], page 495 and see Section 6.31 [SET-IRRELEVANT-FORMALS-OK], page 200.

     :ignore-ok

When this key’s value is t, the check for ignored variables is bypassed; otherwise, the value is the keyword nil (the default). See Section 6.28 [SET-IGNORE-OK], page 198.

     :inhibit-warnings

ACL2 prints warnings that may, from time to time, seem excessive to experienced users. Each warning is “labeled” with a string identifying the type of warning. Consider for example

     ACL2 Warning [Use] in ( THM ...):  It is unusual to :USE ....

Here, the label is "Use". The value of the key :inhibit-warnings is a list of such labels, where case is ignored. Any warning whose label is a member of this list (where again, case is ignored) is suppressed. See Section 6.29 [SET-INHIBIT-WARNINGS], page 198 and also see Section 9.13 [SET-INHIBIT-OUTPUT-LST], page 424.

     :bdd-constructors

This key’s value is a list of function symbols used to define the notion of “BDD normal form.” See Section 2.1 [BDD-ALGORITHM], page 71 and see Section 8.43 [HINTS], page 319.

     :state-ok

This key’s value is either t or nil and indicates whether the user is aware of the syntactic restrictions on the variable symbol STATE. See Section 6.33 [SET-STATE-OK], page 201.

Note: Unlike all other table (TABLE^)s, acl2-defaults-table can affect the soundness of the system. The table (TABLE^) mechanism therefore enforces on it a restriction not imposed on other table (TABLE^)s: when table (TABLE^) is used to update the acl2-defaults-table, the key and value must be variable-free forms. Thus, while

     (table acl2-defaults-table :defun-mode :program),
     (table acl2-defaults-table :defun-mode ':program), and
     (table acl2-defaults-table :defun-mode (compute-mode *my-data*))

are all examples of legal events (EVENTS^) (assuming compute-mode is a function of one non-state (STATE^) argument that produces a defun-mode (DEFUN-MODE^) as its single value),

     (table acl2-defaults-table :defun-mode (compute-mode (w state)))

is not legal because the value form is state (STATE^)-sensitive.

Consider for example the following three events (EVENTS^) which one might make into the text of a book.

     (in-package "ACL2")

     (table acl2-defaults-table
       :defun-mode
       (if (ld-skip-proofsp state) :logic :program))
     (defun crash-and-burn (x) (car x))

The second event is illegal because its value form is state (STATE^)-sensitive. If it were not illegal, then it would set the :defun-mode (DEFUN-MODE^) to :program (PROGRAM^) when the book was being certified but would set the defun-mode (DEFUN-MODE^) to :logic (LOGIC^) when the book was being loaded by include-book (INCLUDE-BOOK^). That is because during certification, ld-skip-proofsp (LD-SKIP-PROOFSP^) is nil (proof obligations are generated and proved), but during book inclusion ld-skip-proofsp (LD-SKIP-PROOFSP^) is non-nil (those obligations are assumed to have been satisfied.) Thus, the above book, when loaded, would create a function in :logic (LOGIC^) mode that does not actually meet the conditions for such status.

For similar reasons, table (TABLE^) events (EVENTS^) affecting acl2-defaults-table are illegal within the scope of local (LOCAL^) forms. That is, the text

     (in-package "ACL2")
     (local (table acl2-defaults-table :defun-mode :program))
     (defun crash-and-burn (x) (car x))

is illegal because acl2-defaults-table is changed locally. If this text were acceptable as a book, then when the book was certified, crash-and-burn would be processed in :program (PRO-GRAM^) mode, but when the certified book was included later, crash-and-burn would have :logic (LOGIC^) mode because the local (LOCAL^) event would be skipped.

The text

     (in-package "ACL2")
     (program) ;which is (table acl2-defaults-table :defun-mode :program)
     (defun crash-and-burn (x) (car x))

is acceptable and defines crash-and-burn in :program (PROGRAM^) mode, both during certification and subsequent inclusion.

We conclude with an important observation about the relation between acl2-defaults-table and

include-book (INCLUDE-BOOK^), certify-book (CERTIFY-BOOK^), and encapsulate (EN-

CAPSULATE^). Including or certifying a book never has an effect on the acl2-defaults-table, nor does executing an encapsulate (ENCAPSULATE^) event; we always restore the value of this table (TABLE^) as a final act. (Also see Section 6.20 [INCLUDE-BOOK], page 189, see Section 6.18 [ENCAPSULATE], page 185, and see Section 3.6 [CERTIFY-BOOK], page 106.) That is, no matter how a book fiddles with the acl2-defaults-table, its value immediately after including that book is the same as immediately before including that book. If you want to set the acl2-defaults-table in a way that persists, you need to do so using command (COMMAND^)s that are not inside books (BOOKS^). It may be useful to set your favorite defaults in your acl2-customization (ACL2-CUSTOMIZATION^) file; see Section 8.4 [ACL2-CUSTOMIZATION], page 239.

9.3 ASSIGN

ASSIGN assign to a global variable in state (STATE^)

     Examples:
     (assign x (expt 2 10))
     (assign a (aset1 'ascii-map-array (@ a) 66 'Upper-case-B))
     General Form:
     (assign symbol term)

where symbol is any symbol (with certain enforced exclusions to avoid overwriting ACL2 system “globals”) and term is any ACL2 term that could be evaluated at the top-level. Assign evaluates the term, stores the result as the value of the given symbol in the global-table of state (STATE^), and returns the result. (Note: the actual implementation of the storage of this value is much more efficient than this discussion of the logic might suggest.) Assign is a macro that effectively expands to the more complicated but understandable:

     (pprogn (f-put-global 'symbol term state)
             (mv nil (f-get-global 'symbol term state) state)).

The macro @ (@^) gives convenient access to the value of such globals. The :ubt (UBT^) operation has no effect on the global-table of state (STATE^). Thus, you may use these globals to hang onto useful data structures even though you may undo back past where you computed and saved them.

9.4 CERTIFY-BOOK!

CERTIFY-BOOK! a variant of certify-book (CERTIFY-BOOK^)

Examples:
(certify-book! "my-arith" 3)     ;Certify in a world with 3
                                   ; commands, starting in a world
                                   ; with at least 3 commands.
(certify-book! "my-arith")       ;Certify in the initial world.
(certify-book! "my-arith" 0 nil) ;As above, but do not compile.
General Form:
(certify-book! book-name k compile-flg)

where book-name is a book name (see Section 3.3 [BOOK-NAME], page 99), k is a nonnegative integer used to indicate the “certification world (WORLD^),” and compile-flg indicates whether you wish to compile the (functions in the) book.

This command (COMMAND^) is identical to certify-book (CERTIFY-BOOK^), except that the second argument k may not be t in certify-book! and if k exceeds the current command (COMMAND^) number, then an appropriate ubt! (UBT!^) will be executed first. See Section 3.6 [CERTIFY-BOOK], page 106 and see Section 7.17 [UBT!], page 230.

9.5 COMP

COMP compile some ACL2 functions

Examples:
:comp t          ; compile all uncompiled ACL2 functions
:comp foo        ; compile the defined function foo
:comp (foo bar)  ; compile the defined functions foo and bar
General Form:
:comp specifier
where specifier is one of the following:
  t                     compile all defined ACL2 functions that are currently
                          uncompiled
  (name-1 ... name-k)   a non-empty list of names of functions defined by
                          DEFUN in ACL2
  name                  same as (name)

Note: Unless a single function is specified (either as a symbol or as a one-element list containing its name), ACL2 will write out files "TMP.lisp" and "TMP1.lisp" (the latter is for the executable counterparts; see Section 8.32 [EXECUTABLE-COUNTERPART], page 291) that are subsequently compiled. Also see Section 6.27 [SET-COMPILE-FNS], page 197 for a way to get each function to be compiled as you go along.

9.6 GOOD-BYE

GOOD-BYE quit entirely out of Lisp

     Example:
     ACL2 !>:good-bye

Note: Your entire session will disappear forever when you type :good-bye.

The command :good-bye quits not only out of the ACL2 command (COMMAND^) loop, but in fact quits entirely out of the underlying Lisp. Thus, there is no going back! You will not be able to re-enter the command (COMMAND^) loop after typing :good-bye! All your work will be lost!!!

This command may not work in some underlying Common Lisp implementations. But we don’t expect there to be any harm in trying. It does work in AKCL and GCL, at least as of this writing.

If you merely want to exit the ACL2 command (COMMAND^) loop, use :q (Q^) instead (see Section 9.9 [Q], page 421).

9.7 LD

LD the ACL2 read-eval-print loop, file loader, and command (COMMAND^) processor

     Example:
     (LD standard-oi              ; open obj in channel, stringp file name
                                  ; to open and close, or list of forms
                                  ; Optional keyword arguments:
         :standard-co        ...  ; open char out or file to open and close
         :proofs-co          ...  ; open char out or file to open and close
         :current-package    ...  ; known package name
         :ld-skip-proofsp    ...  ; nil, 'include-book, t, or

                                  ;   see Section 8.59 [LD-SKIP-PROOFSP], page 339
         :ld-redefinition-action  ; nil or '(:a . :b)
         :ld-prompt          ...  ; nil, t, or some prompt printer fn
         :ld-keyword-aliases ...  ; an alist pairing keywords to parse info
         :ld-pre-eval-filter ...  ; :all, :query, or some new name
         :ld-pre-eval-print  ...  ; nil, t, or :never
         :ld-post-eval-print ...  ; nil, t, or :command-conventions
         :ld-evisc-tuple     ...  ; nil or '(alist nil nil level length)
         :ld-error-triples   ...  ; nil or t
         :ld-error-action    ...  ; :return (default), :continue or :error
         :ld-query-control-alist  ; alist supplying default responses
         :ld-verbose         ...) ; nil or t

Ld is the top-level ACL2 read-eval-print loop. (When you call lp (LP^), a little initialization is done in raw Common Lisp and then ld is called.) ld is also a general-purpose ACL2 file loader and a command (COMMAND^) interpreter. Ld is actually a macro that expands to a function call involving state (STATE^). Ld returns an “error/value/state” triple as explained below.

The arguments to ld all happen to be global variables in state (STATE^). For example, 'currentpackage (CURRENT-PACKAGE^) and 'ld-verbose (LD-VERBOSE^) are global variables, which may be accessed via (@ current-package) and (@ ld-verbose). When ld is called, it “binds” these variables. By “binds” we actually mean the variables are globally set but restored to their old values on exit. Because ld provides the illusion of state (STATE^) global variables being bound, they are called “ld specials” (after the Lisp convention of calling a variable “special” if it is referenced freely after having been bound).

Note that all arguments but the first are passed via keyword. Any variable not explicitly given a value in a call retains its pre-call value, with the exception of :ld-error-action (LD-ERROR-ACTION^), which defaults to :return if not explicitly specified.

Just as an example to drive the point home: If current-package (CURRENT-PACKAGE^) is "ACL2" and you typed

     (ld *standard-oi* :current-package "MY-PKG")

you would find yourself in (an inner) read-eval-print loop in which the current-package (CURRENT-PACKAGE^) was "MY-PKG". You could operate there as long as you wished, changing the current package at will. But when you typed :q (Q^) you would return to the outer read-eval-print loop where the current package would still be "ACL2".

Roughly speaking, ld repeatedly reads a form from standard-oi (STANDARD-OI^), evaluates it, and prints its result to standard-co (STANDARD-CO^). It does this until the form evaluates to an error triple whose value component is :q (Q^) or until the input channel or list is emptied. However, ld has many bells and whistles controlled by the ld specials. Each such special is documented individually. For example, see the documentation for standard-oi (STANDARD-OI^), currentpackage (CURRENT-PACKAGE^), ld-pre-eval-print (LD-PRE-EVAL-PRINT^), etc.

A more precise description of ld is as follows. In the description below we use the ld specials as variables, e.g., we say “a form is read from standard-oi (STANDARD-OI^).” By this usage we refer to the current value of the named state (STATE^) global variable, e.g., we mean “a form is read from the current value of 'standard-oi (STANDARD-OI^).” This technicality has an important implication: If while interacting with ld you change the value of one of the ld specials, e.g., 'standard-oi (STANDARD-OI^), you will change the behavior of ld, e.g., subsequent input will be taken from the new value.

Three ld specials are treated as channels: standard-oi (STANDARD-OI^) is treated as an object input channel and is the source of forms evaluated by ld; standard-co (STANDARD-CO^) and proofs-co (PROOFS-CO^) are treated as character output channels and various flavors of output are printed to them. However, the supplied values of these specials need not actually be channels; several special cases are recognized. If the supplied value of one of these is in fact an open channel of the appropriate type, that channel is used and is not closed by ld. If the supplied value of one of these specials is a string, the string is treated as a file name and a channel of the appropriate type is opened to/from that file. (Note that ld does not support structured pathname (PATHNAME^)s, as described in the documentation for pathname (PATHNAME^).) Any channel opened by ld during the binding of the ld specials is automatically closed by ld upon termination. If standard-co (STANDARD-CO^) and proofs-co (PROOFS-CO^) are equal strings, only one channel to that file is opened and is used for both.

Several other alternatives are allowed for standard-oi (STANDARD-OI^). If standard-oi (STANDARD-OI^) is a true list then it is taken as the list of forms to be processed. If standardoi (STANDARD-OI^) is a list ending in an open channel, then ld processes the forms in the list and then reads and processes the forms from the channel. Analogously, if standard-oi (STANDARD-OI^) is a list ending a string, an object channel from the named file is opened and ld processes the forms in the list followed by the forms in the file. That channel is closed upon termination of ld.

The remaining ld specials are handled more simply and generally have to be bound to one of a finite number of tokens described in the :doc (DOC^) entries for each ld special. Should any ld special be supplied an inappropriate value, an error message is printed.

Next, if ld-verbose (LD-VERBOSE^) is t, ld prints the message “ACL2 loading name” where name names the file or channel from which forms are being read. At the conclusion of ld, it will print “Finished loading name” if ld-verbose (LD-VERBOSE^) is t.

Finally, ld repeatedly executes the ACL2 read-eval-print step, which may be described as follows. A prompt (PROMPT^) is printed to standard-co (STANDARD-CO^) if ld-prompt (LD-PROMPT^) is non-nil. The format of the prompt (PROMPT^) is determined by ld-prompt (LD-PROMPT^). If it is t, the default ACL2 prompt (PROMPT^) is used. If it is any other nonnil value then it is treated as an ACL2 function that will print the desired prompt (PROMPT^). See Section 8.56 [LD-PROMPT], page 334. In the exceptional case where ld’s input is coming from the terminal (*standard-oi*) but its output is going to a different sink (i.e., standardco (STANDARD-CO^) is not *standard-co* (*STANDARD-CO*^)), we also print the prompt (PROMPT^) to the terminal.

Ld then reads a form from standard-oi (STANDARD-OI^). If the object read is a keyword, ld constructs a “keyword command form” by possibly reading several more objects. See Section 8.48 [KEYWORD-COMMANDS], page 328. This construction process is sensitive to the value of ldkeyword-aliases (LD-KEYWORD-ALIASES^). See Section 8.52 [LD-KEYWORD-ALIASES], page 331. Otherwise, the object read is treated as the command form.

Ld next decides whether to evaluate or skip this form, depending on ld-pre-eval-filter (LD-PRE-EVAL-FILTER^). Initially, the filter must be either :all, :query, or a new name. If it is :all, it means all forms are evaluated. If it is :query, it means each form that is read is displayed and the user is queried. Otherwise, the filter is a name and each form that is read is evaluated as long as the name remains new, but if the name is ever introduced then no more forms are read and ld terminates. See Section 8.54 [LD-PRE-EVAL-FILTER], page 333.

If the form is to be evaluated, first prints the form to standard-co (STANDARD-CO^), if ldpre-eval-print (LD-PRE-EVAL-PRINT^) is t. With this feature, ld can process an input file or form list and construct a script of the session that appears as though each form was typed in. See Section 8.55 [LD-PRE-EVAL-PRINT], page 334.

Ld then evaluates the form, with state (STATE^) bound to the current state (STATE^). The result is some list of multiple values. If a state (STATE^) is among the values, then ld uses that state (STATE^) as the subsequent current state (STATE^).

Depending on ld-error-triples (LD-ERROR-TRIPLES^), ld may interpret the result as an “error.” See Section 8.50 [LD-ERROR-TRIPLES], page 330. We first discuss ld’s behavior if no error signal is detected (either because none was sent or because ld is ignoring them as per ld-error-triples (LD-ERROR-TRIPLES^)).

In the case of a non-erroneous result, ld does two things: First, if the logical world (WORLD^) in the now current state (STATE^) is different than the world (WORLD^) before execution of the form, ld adds to the world (WORLD^) a “command (COMMAND^) landmark” containing the form evaluated. See Section 8.12 [COMMAND-DESCRIPTOR], page 261. Second, ld prints the result to standard-co (STANDARD-CO^), according to ld-post-eval-print (LD-POST-EVAL-PRINT^). If ld-post-eval-print (LD-POST-EVAL-PRINT^) is nil, no result is printed. If it is t, all of the results are printed as a list of multiple values. Otherwise, it is :command-conventions and only the non-erroneous “value” component of the result is printed. See Section 8.53 [LD-POST-EVAL-PRINT], page 332.

Whenever ld prints anything (whether the input form, a query, or some results) it “eviscerates” it if ld-evisc-tuple (LD-EVISC-TUPLE^) is non-nil. Essentially, evisceration is a generalization of Common Lisp’s use of *print-level* and *print-length* to hide large substructures. See Section 8.51 [LD-EVISC-TUPLE], page 330.

We now return to the case of a form whose evaluation signals an error. In this case, ld first restores the ACL2 logical world (WORLD^) to what it was just before the erroneous form was evaluated. Thus, a form that partially changes the world (WORLD^) (i.e., begins to store properties) and then signals an error, has no effect on the world (WORLD^). You may see this happen on command (COMMAND^)s that execute several events (EVENTS^) (e.g., an encapsulate (EN-CAPSULATE^) or a progn (PROGN^) of several defuns (DEFUNS^)): even though the output makes it appear that the initial events (EVENTS^) were executed, if an error is signalled by a later event the entire block of events (EVENTS^) is discarded.

After rolling back, ld takes an action determined by ld-error-action (LD-ERROR-ACTION^). If the action is :continue, ld merely iterates the read-eval-print step. Note that nothing suggestive of the value of the “erroneous” form is printed. If the action is :return, ld terminates normally. If the action is :error, ld terminates signalling an error to its caller. If its caller is in fact another instance of ld and that instance is watching out for error signals, the entire world (WORLD^) created by the erroneous inner ld will be discarded by the outer ld.

Ld returns an error triple, (mv erp val state). Erp is t or nil indicating whether an error is being signalled. If no error is signalled, val is the “reason” ld terminated and is one of :exit (meaning :q (Q^) was read), :eof (meaning the input source was exhausted), :error (meaning an error occurred but has been supressed) or :filter (meaning the ld-pre-eval-filter (LD-PRE-EVAL-FILTER^) terminated ld).

9.8 PROPS

PROPS print the ACL2 properties on a symbol

     Example:
     :props assoc-eq

Props takes one argument, a symbol, and prints all of the properties that are on that symbol in the ACL2 world (WORLD^).

9.9 Q

Q quit ACL2 (type :q) — reenter with (lp)

     Example:
     ACL2 !>:Q

The keyword command :q typed at the top-level of the ACL2 loop will terminate the loop and return control to the Common Lisp top-level (or, more precisely, to whatever program invoked lp (LP^)). To reenter the ACL2 loop, execute (acl2::lp) in Common Lisp. You will be in the same state as you were when you exited with :q, unless during your stay in Common Lisp you messed the data structures representating the ACL2 state (STATE^).

Unlike all other keyword commands, typing :q is not equivalent to invoking the function q. There is no function q.

9.10 REBUILD

REBUILD a convenient way to reconstruct your old state (STATE^)

     Examples:
     ACL2 !>(rebuild "project.lisp")
     ACL2 !>(rebuild "project.lisp" t)
     ACL2 !>(rebuild "project.lisp" :all)
     ACL2 !>(rebuild "project.lisp" :query)
     ACL2 !>(rebuild "project.lisp" 'lemma-22)

Rebuild allows you to assume all the command (COMMAND^)s in a given file or list, supplied in the first argument. Because rebuild processes an arbitrary sequence of command (COMMAND^)s with ld-skip-proofsp (LD-SKIP-PROOFSP^) t, it is unsound! However, if each of these command (COMMAND^)s is in fact admissible, then processing them with rebuild will construct the same logical state (STATE^) that you would be in if you typed each command (COMMAND^) and waited through the proofs again. Thus, rebuild is a way to reconstruct a state (STATE^) previously obtained by proving your way through the command (COMMAND^)s.

The second, optional argument to rebuild is a “filter” (see Section 8.54 [LD-PRE-EVAL-FILTER], page 333) that lets you specify which command (COMMAND^)s to process. You may specify t, :all, :query, or a new logical name. t and :all both mean that you expect the entire file or list to be processed. :query means that you will be asked about each command (COMMAND^) in turn. A new name means that all command (COMMAND^)s will be processed as long as the name is new, i.e., rebuild will stop processing command (COMMAND^)s immediately after executing a command (COMMAND^) that introduces name. Rebuild will also stop if any command (COMMAND^) causes an error. You may therefore wish to plant an erroneous form in the file, e.g., (mv t nil state), (see Section 8.50 [LD-ERROR-TRIPLES], page 330), to cause rebuild to stop there. The form (i-am-here) is such a pre-defined form. If you do not specify a filter, rebuild will query you for one.

Inspection of the definition of rebuild, e.g., via :pc (PC^) rebuild-fn, will reveal that it is just a glorified call to the function ld (LD^). See Section 9.7 [LD], page 416 if you find yourself wishing that rebuild had additional functionality.

9.11 RESET-LD-SPECIALS

RESET-LD-SPECIALS restores initial settings of the ld (LD^) specials

     Examples:
     (reset-ld-specials t)
     (reset-ld-specials nil)

Roughly speaking, the ld (LD^) specials are certain state (STATE^) global variables, such as

current-package (CURRENT-PACKAGE^), ld-prompt (LD-PROMPT^), and ld-pre-eval-

filter (LD-PRE-EVAL-FILTER^), which are managed by ld (LD^) as though they were local variables. These variables determine the channels on which ld (LD^) reads and prints and control many options of ld (LD^). See Section 9.7 [LD], page 416 for the details on what the ld (LD^) specials are.

This function, reset-ld-specials, takes one Boolean argument, flg. The function resets all of the ld (LD^) specials to their initial, top-level values, except for the three channel variables, standard-oi (STANDARD-OI^), standard-co (STANDARD-CO^), and proofs-co (PROOFS-CO^), which are reset to their initial values only if flg is non-nil. Of course, if you are in a recursive call of ld (LD^), then when you exit that call, the ld (LD^) specials will be restored to the values they had at the time ld (LD^) was called recursively. To see what the initial values are,

inspect the value of the constant *initial-ld-special-bindings*.

9.12 SET-GUARD-CHECKING

SET-GUARD-CHECKING control checking guard (GUARD^)s during execution of top-level forms

The top-level ACL2 loop has a variable which controls which sense of execution is provided. To turn “guard (GUARD^) checking on,” by which we mean that guard (GUARD^)s 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 (PROMPT^).

     ACL2 !>

means guard (GUARD^) checking is on and

     ACL2 >

means guard (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.

Whether guard (GUARD^)s are checked during evaluation is independent of the default-defun-mode (DEFAULT-DEFUN-MODE^). We note this simply because it is easy to confuse “:program (PROGRAM^) mode” with “evaluation in Common Lisp” and thus with “guard (GUARD^) checking on;” and it is easy to confuse “:logic (LOGIC^) mode” with “evaluation in the logic” and with “guard (GUARD^) checking off.” But the default-defun-mode (DEFAULT-DEFUN-MODE^) determines whether newly submitted definitions introduce programs or add logical axioms. That mode is independent of whether evaluation checks guard (GUARD^)s or not. You can operate in :logic (LOGIC^) mode with runtime guard (GUARD^) checking on or off. Analogously, you can operate in :program (PROGRAM^) mode with runtime guard (GUARD^) checking on or off.

However, one caveat is appropriate: functions introduced only as programs have no logical definitions and hence when they are evaluated their Common Lisp definitions must be used and thus their guard (GUARD^)s (if any) checked. That is, if you are defining functions in :program (PROGRAM^) mode and evaluating expressions containing only such functions, guard (GUARD^) checking may as well be on because guard (GUARD^)s are checked regardless. This same caveat applies to a few ACL2 system functions that take state (STATE^) as an argument. This list of functions includes all the keys of the alist *super-defun-wart-alist* and all function whose name (NAME^)s are members of the list *initial-untouchables*.

See Section 8.41 [GUARD], page 305 for a general discussion of guard (GUARD^)s.

9.13 SET-INHIBIT-OUTPUT-LST

SET-INHIBIT-OUTPUT-LST control output

     Examples:
     (set-inhibit-output-lst '(warning))
     (set-inhibit-output-lst '(proof-tree prove))
     :set-inhibit-output-lst (proof-tree prove)
     General Form:
     (set-inhibit-output-lst lst)

where lst is a form (which may mention state (STATE^)) that evaluates to a list of names, each of which is the name of one of the following “kinds” of output produced by ACL2.

       error          error messages
       warning        warnings
       observation    observations
       prove          commentary produced by the theorem prover
       event          non-proof commentary produced by events such as defun
                      and encapsulate

       summary        the summary at the successful conclusion of an event
       proof-tree     proof-tree output

It is possible to inhibit each kind of output by putting the corresponding name into lst. For example, if 'warning is included in (the value of) lst, then no warnings are printed. Note that proof-tree (PROOF-TREE^) output is affected by set-inhibit-output-lst; see Chapter 12 [PROOF-TREE], page 617.

9.14 SKIP-PROOFS

SKIP-PROOFS skip proofs for an event — a quick way to introduce unsoundness

     Example Form:
     (skip-proofs
       (defun foo (x)
         (if (atom x) nil (cons (car x) (foo (reverse (cdr x)))))))
     General Form:
     (skip-proofs event)

where event is an event; see Chapter 6 [EVENTS], page 161. Event is processed as usual except that the proof obligations usually generated are merely assumed.

WARNING: Skip-proofs allows inconsistent events (EVENTS^) to be admitted to the logic. Use it at your own risk!

Sometimes in the development of a formal model or proof it is convenient to skip the proofs required by a given event. By embedding the event in a skip-proofs form, you can avoid the proof burdens generated by the event, at the risk of introducing unsoundness. Below we list three illustrative situations in which you might find skip-proofs useful.

1. The termination argument for a proposed function definition is complicated. You presume you could admit it, but are not sure that your definition has the desired properties. By embedding the defun (DEFUN^) event in a skip-proofs you can “admit” the function and experiment with theorems about it before you pay the price of its admission.

2. You intend eventually to verify the guard (GUARD^)s for a definition but do not want to take the time now to pursue that. By embedding the verify-guards (VERIFY-GUARDS^) event in a skip-proofs you can get the system to behave as though the guard (GUARD^)s were verified.

3. You are repeatedly recertifying a book while making many experimental changes. A certain defthm (DEFTHM^) in the book takes a very long time to prove and you believe the proof is not affected by the changes you are making. By embedding the defthm (DEFTHM^) event in a skipproofs you allow the theorem to be assumed without proof during the experimental recertifications.

Unsoundness or Lisp errors may result if the presumptions underlying a use of skip-proofs are incorrect. Therefore, skip-proofs must be considered a dangerous (though useful) tool in system development.

Roughly speaking, a defthm (DEFTHM^) embedded in a skip-proofs is essentially a defaxiom (DEFAXIOM^), except that it is not noted as an axiom for the purposes of functional instantiation (see Section 8.61 [LEMMA-INSTANCE], page 342). But a skipped defun (DEFUN^) is much more subtle since not only is the definitional equation being assumed but so are formulas relating to termination and type. The situation is also difficult to characterize if the skip-proofs events (EVENTS^) are within the scope of an encapsulate (ENCAPSULATE^) in which constrained functions are being introduced. In such contexts no clear logical story is maintained; in particular, constraints aren’t properly tracked for definitions. A proof script involving skip-proofs should be regarded as work-in-progress, not as a completed proof with some unproved assumptions. A skip-proofs event represents a promise by the author to admit the given event without further axioms.

ACL2 allows the certification of books (BOOKS^) containing skip-proofs events (EVENTS^). This is contrary to the spirit of certified books (BOOKS^), since one is supposedly assured by a valid certificate (CERTIFICATE^) that a book has been “blessed.” But certification, too, takes the view of skip-proofs as “work-in-progress” and so allows the author of the book to promise to finish. When such books (BOOKS^) are certified, a warning to the author is printed, reminding him or her of the incurred obligation. When books (BOOKS^) containing skip-proofs are included into a session, a warning to the user is printed, reminding the user that the book is in fact incomplete and possibly inconsistent.

9.15 THM

THM prove a theorem

     Example:
     (thm (equal (app (app a b) c)
                 (app a (app b c))))

Also see Section 6.15 [DEFTHM], page 176. Unlike defthm (DEFTHM^), thm does not create an event; it merely causes the theorem prover to attempt a proof.

     General Form:
     (thm term
          :hints        hints
          :otf-flg      otf-flg
          :doc          doc-string)

where term is a term alleged to be a theorem, and hints (HINTS^), otf-flg (OTF-FLG^) and doc-string (DOC-STRING^) are as described in the corresponding :doc (DOC^) entries. The three keyword arguments above are all optional.

9.16 TRANS

TRANS print the macroexpansion of a form

     Examples:
     :trans (list a b c)
     :trans (caddr x)
     :trans (cond (p q) (r))

This function takes one argument, an alleged term, and translates it, expanding the macros in it completely. Either an error is caused or the formal meaning of the term is printed. We also print the “multiplicity” and “state-out” for the translated term. The multiplicity indicates how many values are returned (in the mv (MV^) sense) and is always 1 or greater. State-out indicates whether and where a state (STATE^) is returned. If state-out is nil, the form does not return a state (STATE^) (either as its value or among its multiple values). If t, the form returns one value and it is a state (STATE^). Otherwise, state-out is a number which indicates which of its multiple values is a state (STATE^).

It is sometimes more convenient to use trans1 (TRANS1^) which is like trans but which only does top-level macroexpansion.

For more, see Section 8.87 [TERM], page 376.

9.17 TRANS1

TRANS1 print the one-step macroexpansion of a form

     Examples:
     :trans1 (list a b c)
     :trans1 (caddr x)
     :trans1 (cond (p q) (r))

This function takes one argument, an alleged term, and expands the top-level macro in it for one step only. Either an error is caused, which happens when the form is not a call of a macro, or the result printed. Also see Section 9.16 [TRANS], page 427, which translates the given form completely.

10 PROGRAMMING

PROGRAMMING built-in ACL2 functions

The built-in ACL2 functions that one typically uses in writing programs are listed below. See their individual documentation (DOCUMENTATION^)s. We do not bother to document the some of the more obscure functions provided by ACL2 that do not correspond to functions of Common Lisp.

* *:: multiplication macro

* *STANDARD-CI*:: an ACL2 character-based analogue of CLTL’s *standard-input*

* *STANDARD-CO*:: the ACL2 analogue of CLTL’s *standard-output*

* *STANDARD-OI*:: an ACL2 object-based analogue of CLTL’s *standard-input*

* +:: addition macro

* -:: macro for subtraction and negation

* /:: macro for division and reciprocal

* /=:: test inequality of two numbers

* 1+:: increment by 1

* 1-:: decrement by 1

* <:: less-than

* <=:: less-than-or-equal test

* =:: test equality (of two numbers, symbols, or characters (CHARACTERS^))

* >:: greater-than test

* >=:: greater-than-or-equal test

* ABS:: the absolute value of a rational number

* ACL2-COMPLEX-RATIONALP:: recognizer for complex rationals

* ACL2-NUMBERP:: recognizer for numbers

* ACL2-USER:: a package the ACL2 user may prefer

* ACONS:: constructor for association lists

* ADD-TO-SET-EQ:: add a symbol to a list

* ALISTP:: recognizer for association lists

* ALPHA-CHAR-P:: recognizer for alphabetic characters

* AND:: conjunction

* APPEND:: concatenate (CONCATENATE^) two or more lists

* ASH:: arithmetic shift operation

* ASSOC:: look up key in association list, using eql (EQL^) as test

* ASSOC-EQ:: look up key in association list, using eq (EQ^) as test

* ASSOC-EQUAL:: look up key in association list

* ASSOC-KEYWORD:: look up key in a keyword-value-listp (KEYWORD-VALUE-LISTP^)

* ASSOC-STRING-EQUAL:: look up key, a string, in association list

* ATOM:: recognizer for atoms

* ATOM-LISTP:: recognizer for a true list of atom (ATOM^)s

* BINARY-*:: multiplication function

* BINARY-+:: addition function

* BINARY-APPEND:: concatenate (CONCATENATE^) two lists

* BOOLEANP:: recognizer for booleans * BUTLAST:: all but a final segment of a list

* CAAAAR:: car (CAR^) of the caaar (CAAAR^)

* CAAADR:: car (CAR^) of the caadr (CAADR^)

* CAAAR:: car (CAR^) of the caar (CAAR^)

* CAADAR:: car (CAR^) of the cadar (CADAR^)

* CAADDR:: car (CAR^) of the caddr (CADDR^)

* CAADR:: car (CAR^) of the cadr (CADR^)

* CAAR:: car (CAR^) of the car (CAR^)

* CADAAR:: car (CAR^) of the cdaar (CDAAR^)

* CADADR:: car (CAR^) of the cdadr (CDADR^)

* CADAR:: car (CAR^) of the cdar (CDAR^)

* CADDAR:: car (CAR^) of the cddar (CDDAR^)

* CADDDR:: car (CAR^) of the cdddr (CDDDR^)

* CADDR:: car (CAR^) of the cddr (CDDR^)

* CADR:: car (CAR^) of the cdr (CDR^)

* CAR:: returns the first element of a non-empty list, else nil

* CASE:: conditional based on if-then-else using eql (EQL^)

* CASE-MATCH:: pattern matching or destructuring

* CDAAAR:: cdr (CDR^) of the caaar (CAAAR^)

* CDAADR:: cdr (CDR^) of the caadr (CAADR^)

* CDAAR:: cdr (CDR^) of the caar (CAAR^)

* CDADAR:: cdr (CDR^) of the cadar (CADAR^)

* CDADDR:: cdr (CDR^) of the caddr (CADDR^)

* CDADR:: cdr (CDR^) of the cadr (CADR^)

* CDAR:: cdr (CDR^) of the car (CAR^)

* CDDAAR:: cdr (CDR^) of the cdaar (CDAAR^)

* CDDADR:: cdr (CDR^) of the cdadr (CDADR^)

* CDDAR:: cdr (CDR^) of the cdar (CDAR^)

* CDDDAR:: cdr (CDR^) of the cddar (CDDAR^)

* CDDDDR:: cdr (CDR^) of the cdddr (CDDDR^)

* CDDDR:: cdr (CDR^) of the cddr (CDDR^)

* CDDR:: cdr (CDR^) of the cdr (CDR^)

* CDR:: returns the second element of a cons (CONS^) pair, else nil

* CEILING:: division returning an integer by truncating toward positive infinity

* CHAR:: the nth (NTH^) element (zero-based) of a string

* CHAR-CODE:: the numeric code for a given character

* CHAR-DOWNCASE:: turn upper-case characters (CHARACTERS^) into lower-case characters (CHARACTERS^)

* CHAR-EQUAL:: character equality without regard to case

* CHAR-UPCASE:: turn lower-case characters (CHARACTERS^) into upper-case characters (CHARACTERS^)

* CHAR<:: less-than test for characters (CHARACTERS^)

* CHAR<=:: less-than-or-equal test for characters (CHARACTERS^)

* CHAR>:: greater-than test for characters (CHARACTERS^)

* CHAR>=:: greater-than-or-equal test for characters (CHARACTERS^)

* CHARACTER-LISTP:: recognizer for a true list of characters

* CHARACTERP:: recognizer for characters (CHARACTERS^)

* CHARACTERS:: characters in ACL2

* CODE-CHAR:: the character corresponding to a given numeric code * COERCE:: coerce a character list to a string and a string to a list

* COMPILATION:: compiling ACL2 functions

* COMPLEX:: create an ACL2 number

* COMPLEX-RATIONALP:: recognizes complex rational numbers

* CONCATENATE:: concatenate lists or strings together

* COND:: conditional based on if-then-else

* CONJUGATE:: complex number conjugate

* CONS:: pair and list constructor

* CONSP:: recognizer for cons (CONS^) pairs

* DECLARE:: declarations

* DENOMINATOR:: divisor of a ratio in lowest terms

* DIGIT-CHAR-P:: the number, if any, corresponding to a given character

* DIGIT-TO-CHAR:: map a digit to a character

* EIGHTH:: eighth member of the list

* ENDP:: recognizer for empty lists

* EQ:: equality of symbols

* EQL:: test equality (of two numbers, symbols, or characters (CHARACTERS^))

* EQLABLE-ALISTP:: recognizer for a true list of pairs whose car (CAR^)s are suitable for eql (EQL^)

* EQLABLE-LISTP:: recognizer for a true list of objects each suitable for eql (EQL^)

* EQLABLEP:: the guard (GUARD^) for the function eql (EQL^)

* EQUAL:: true equality

* ER-PROGN:: perform a sequence of state-changing “error triples”

* EVENP:: test whether an integer is even

* EXPLODE-NONNEGATIVE-INTEGER:: the list of characters (CHARACTERS^) in the decimal form of a number

* EXPT:: exponential function

* FIFTH:: fifth member of the list

* FIRST:: first member of the list

* FIX:: coerce to a number

* FIX-TRUE-LIST:: coerce to a true list

* FLOOR:: division returning an integer by truncating toward negative infinity

* FMS:: :(str alist co-channel state evisc) => state

* FMT:: formatted printing

* FMT1:: :(str alist col co-channel state evisc) => (mv col state)

* FOURTH:: fourth member of the list

* IDENTITY:: the identity function

* IF:: if-then-else function

* IFF:: logical “if and only if”

* IFIX:: coerce to an integer

* ILLEGAL:: cause a hard error

* IMAGPART:: imaginary part of a complex number

* IMPLIES:: logical implication

* IMPROPER-CONSP:: recognizer for improper (non-null-terminated) non-empty lists

* INT=:: test equality of two integers

* INTEGER-LENGTH:: number of bits in two’s complement integer representation

* INTEGER-LISTP:: recognizer for a true list of integers

* INTEGERP:: recognizer for whole numbers

* INTERN:: create a new symbol in a given package * INTERN-IN-PACKAGE-OF-SYMBOL:: create a symbol with a given name

* INTERSECTP-EQ:: test whether two lists of symbols intersect

* INTERSECTP-EQUAL:: test whether two lists intersect

* IO:: input/output facilities in ACL2

* IRRELEVANT-FORMALS:: formals that are used but only insignificantly

* KEYWORD-VALUE-LISTP:: recognizer for true lists whose even-position elements are keywords * KEYWORDP:: recognizer for keywords

* LAST:: the last cons (CONS^) (not element) of a list

* LENGTH:: length of a string or proper list

* LET:: binding of lexically scoped (local) variables

* LET*:: binding of lexically scoped (local) variables

* LIST:: build a list

* LIST*:: build a list

* LISTP:: recognizer for (not necessarily proper) lists

* LOGAND:: bitwise logical ‘and’ of two integers

* LOGANDC1:: bitwise logical ‘and’ of two ints, complementing the first

* LOGANDC2:: bitwise logical ‘and’ of two ints, complementing the second

* LOGBITP:: the ith bit of an integer

* LOGCOUNT:: number of “on” bits in a two’s complement number

* LOGEQV:: bitwise logical equivalence of two integers

* LOGIOR:: bitwise logical inclusive or of two integers

* LOGNAND:: bitwise logical ‘nand’ of two integers

* LOGNOR:: bitwise logical ‘nor’ of two integers

* LOGNOT:: bitwise not of a two’s complement number

* LOGORC1:: bitwise logical inclusive or of two ints, complementing the first

* LOGORC2:: bitwise logical inclusive or of two ints, complementing the second

* LOGTEST:: test if two integers share a ‘1’ bit

* LOGXOR:: bitwise logical exclusive or of two integers

* LOWER-CASE-P:: recognizer for lower case characters

* MAKE-CHARACTER-LIST:: coerce (COERCE^) to a list of characters

* MAKE-LIST:: make a list of a given size

* MAX:: the larger of two rational numbers

* MEMBER:: membership predicate, using eql (EQL^) as test

* MEMBER-EQ:: membership predicate, using eq (EQ^) as test

* MEMBER-EQUAL:: membership predicate

* MIN:: the smaller of two rational numbers

* MINUSP:: test whether a rational number is negative

* MOD:: remainder using floor (FLOOR^)

* MV:: returning multiple values

* MV-LET:: calling multi-valued ACL2 functions

* MV-NTH:: the mv-nth element (zero-based) of a list

* NFIX:: coerce to a natural number

* NINTH:: ninth member of the list

* NO-DUPLICATESP:: check for duplicates in a list (using eql for equality)

* NO-DUPLICATESP-EQUAL:: check for duplicates in a list (using equal for equality)

* NONNEGATIVE-INTEGER-QUOTIENT:: natural number division function

* NOT:: logical negation

* NTH:: the nth element (zero-based) of a list * NTHCDR:: final segment of a list

* NULL:: recognizer for the empty list

* NUMERATOR:: dividend of a ratio in lowest terms

* ODDP:: test whether an integer is odd

* OR:: conjunction

* PAIRLIS:: see pairlis$ (PAIRLIS$^)

* PAIRLIS$:: zipper together two lists

* PLUSP:: test whether a rational number is positive

* POSITION:: position of an item in a string or a list, using eql (EQL^) as test

* POSITION-EQ:: position of an item in a string or a list, using eq (EQ^) as test

* POSITION-EQUAL:: position of an item in a string or a list

* PPROGN:: evaluate a sequence of forms that return state (STATE^)

* PROGN:: see the documentation for er-progn (ER-PROGN^)

* PROOFS-CO:: the proofs character output channel

* PROPER-CONSP:: recognizer for proper (null-terminated) non-empty lists

* PUT-ASSOC-EQ:: modify an association list by associating a value with a key

* PUT-ASSOC-EQUAL:: modify an association list by associating a value with a key

* RASSOC:: look up value in association list, using eql (EQL^) as test

* RATIONAL-LISTP:: recognizer for a true list of rational numbers

* RATIONALP:: recognizer for whole numbers

* REALPART:: real part of a complex number

* REDEFINING-PROGRAMS:: an explanation of why we restrict redefinitions

* REM:: remainder using truncate (TRUNCATE^)

* REMOVE:: remove all occurrences, testing using eql (EQL^)

* REMOVE-DUPLICATES:: remove duplicates from a string or (using eql (EQL^)) a list

* REMOVE-DUPLICATES-EQUAL:: remove duplicates from a list

* REST:: rest (cdr (CDR^)) of the list

* REVAPPEND:: concatentate the reverse (REVERSE^) of one list to another

* REVERSE:: reverse a list

* RFIX:: coerce to a rational number

* ROUND:: division returning an integer by rounding off

* SECOND:: second member of the list

* SET-DIFFERENCE-EQUAL:: elements of one list that are not elements of another

* SEVENTH:: seventh member of the list

* SIGNUM:: indicator for positive, negative, or zero

* SIXTH:: sixth member of the list

* STANDARD-CHAR-LISTP:: recognizer for standard characters

* STANDARD-CHAR-P:: recognizer for standard characters

* STANDARD-CO:: the character output channel to which ld (LD^) prints

* STANDARD-OI:: the standard object input “channel”

* STRING:: coerce (COERCE^) to a string

* STRING-ALISTP:: recognizer for association lists with strings as keys

* STRING-APPEND:: concatenate (CONCATENATE^) two strings

* STRING-DOWNCASE:: in a given string, turn upper-case characters (CHARACTERS^) into lowercase

* STRING-EQUAL:: string equality without regard to case

* STRING-LISTP:: recognizer for a true list of strings * STRING-UPCASE:: in a given string, turn lower-case characters (CHARACTERS^) into uppercase

* STRING<:: less-than test for strings

* STRING<=:: less-than-or-equal test for strings

* STRING>:: greater-than test for strings

* STRING>=:: less-than-or-equal test for strings

* STRINGP:: recognizer for strings

* STRIP-CARS:: collect up all first components of pairs in a list

* STRIP-CDRS:: collect up all second components of pairs in a list

* SUBLIS:: substitute an alist into a tree

* SUBSEQ:: subsequence of a string or list

* SUBSETP:: test if every member (MEMBER^) of one list is a member (MEMBER^) of the other * SUBSETP-EQUAL:: check if all members of one list are members of the other

* SUBST:: a single substitution into a tree

* SYMBOL-<:: less-than test for symbols

* SYMBOL-ALISTP:: recognizer for association lists with symbols as keys

* SYMBOL-LISTP:: recognizer for a true list of symbols

* SYMBOL-NAME:: the name of a symbol (a string)

* SYMBOL-PACKAGE-NAME:: the name of the package of a symbol (a string)

* SYMBOLP:: recognizer for symbols

* TAKE:: initial segment of a list

* TENTH:: tenth member of the list

* THE:: run-time type check

* THIRD:: third member of the list

* TRUE-LIST-LISTP:: recognizer for true (proper) lists of true lists

* TRUE-LISTP:: recognizer for proper (null-terminated) lists

* TRUNCATE:: division returning an integer by truncating toward 0

* TYPE-SPEC:: type specifiers in declarations

* UNARY–:: arithmetic negation function

* UNARY-/:: reciprocal function

* UNION-EQ:: union of two lists of symbols

* UNION-EQUAL:: union of two lists

* UPDATE-NTH:: modify a list by putting the given value at the given position

* UPPER-CASE-P:: recognizer for upper case characters

* ZERO-TEST-IDIOMS:: how to test for 0

* ZEROP:: test an acl2-number against 0

* ZIP:: testing an “integer” against 0

* ZP:: testing a “natural” against 0

Related topics other than immediate subtopics:

* ACL2-CUSTOMIZATION:: customizing ACL2 for a particular user

* ARRAYS:: an introduction to ACL2 arrays.

* CERTIFY-BOOK:: how to produce a certificate (CERTIFICATE^) for a book

* COMP:: compile some ACL2 functions

* DEFCONST:: define a constant

* DEFPKG:: define a new symbol package

* DEFUN:: define a function symbol

* INCLUDE-BOOK:: load the events (EVENTS^) in a file * MUTUAL-RECURSION:: define some mutually recursive functions

* SET-COMPILE-FNS:: have each function compiled as you go along.

* SET-IGNORE-OK:: allow unused formals and locals without an ignore declaration

* SET-IRRELEVANT-FORMALS-OK:: allow irrelevant formals in definitions

* SET-STATE-OK:: allow the use of STATE as a formal parameter See any documentation for Common Lisp for more details on many of these functions.

10.1 *

* multiplication macro

* is really a macro that expands to calls of the function binary-* (BINARY-*^). So for example

     (* x y 4 z)

represents the same term as

     (binary-* x (binary-* y (binary-* 4 z))).

See Section 10.34 [BINARY-*], page 448.

* is a Common Lisp function. See any Common Lisp documentation for more information.

10.2 *STANDARD-CI*

*STANDARD-CI* an ACL2 character-based analogue of CLTL’s *standard-input* The value of the ACL2 constant *standard-ci* is an open character input channel that is synonymous to Common Lisp’s *standard-input*. ACL2 character input from *standard-ci* is actually obtained by reading characters (CHARAC-TERS^) from the stream named by Common Lisp’s *standard-input*. That is, by changing the setting of *standard-input* in raw Common Lisp you can change the source from which ACL2 reads on the channel *standard-ci*. See Section 10.3 [*STANDARD-CO*], page 436.

10.3 *STANDARD-CO*

*STANDARD-CO* the ACL2 analogue of CLTL’s *standard-output*

The value of the ACL2 constant *standard-co* is an open character output channel that is synonymous to Common Lisp’s *standard-output*.

ACL2 character output to *standard-co* will go to the stream named by Common Lisp’s *standard-output*. That is, by changing the setting of *standard-output* in raw Common Lisp you can change the actual destination of ACL2 output on the channel named by *standardco*. Observe that this happens without changing the logical value of *standard-co* (which is some channel symbol). Changing the setting of *standard-output* in raw Common Lisp essentially just changes the map that relates ACL2 to the physical world of terminals, files, etc.

To see the value of this observation, consider the following. Suppose you write an ACL2 function which does character output to the constant channel *standard-co*. During testing you see that the output actually goes to your terminal. Can you use the function to output to a file? Yes, if you are willing to do a little work in raw Common Lisp: open a stream to the file in question, set *standard-output* to that stream, call your ACL2 function, and then close the stream and restore *standard-output* to its nominal value. Similar observations can be made about the two ACL2 input channels, *standard-oi* (*STANDARD-OI*^) and *standard-ci* (*STANDARD-CI*^), which are analogues of *standard-input*.

Another reason you might have for wanting to change the actual streams associated with *standard-oi* (*STANDARD-OI*^) and *standard-co* is to drive the ACL2 top-level loop, ld (LD^), on alternative input and output streams. This end can be accomplished easily within ACL2 by either calling ld (LD^) on the desired channels or file names or by resetting the ACL2 state (STATE^) global variables 'standard-oi (STANDARD-OI^) and 'standard-co (STANDARD-CO^) which are used by ld (LD^). See Section 10.219 [STANDARD-OI], page 532 and see Section 10.218 [STANDARD-CO], page 531.

10.4 *STANDARD-OI*

*STANDARD-OI* an ACL2 object-based analogue of CLTL’s *standard-input*

The value of the ACL2 constant *standard-oi* is an open object input channel that is synonymous

to Common Lisp’s *standard-input*.

ACL2 object input from *standard-oi* is actually obtained by reading from the stream named by Common Lisp’s *standard-input*. That is, by changing the setting of *standard-input* in raw Common Lisp you can change the source from which ACL2 reads on the channel *standard-oi*. See Section 10.3 [*STANDARD-CO*], page 436.

10.5 +

+ addition macro + is really a macro that expands to calls of the function binary-+ (BINARY-+^). So for example

     (+ x y 4 z)

represents the same term as

     (binary-+ x (binary-+ y (binary-+ 4 z))).

See Section 10.35 [BINARY-+], page 448.

10.6 -

- macro for subtraction and negation See Section 10.35 [BINARY-+], page 448 for addition and see Section 10.253 [UNARY–], page 545 for negation. Note that - represents subtraction as follows:

     (- x y)

represents the same term as

     (+ x (- y))

which is really

     (binary-+ x (unary-- y)).

Also note that - represents arithmetic negation as follows:

     (- x)

expands to

     (unary-- x).

10.7 /

/ macro for division and reciprocal See Section 10.34 [BINARY-*], page 448 for multiplication and see Section 10.254 [UNARY-/], page 545 for reciprocal. Note that / represents division as follows:

     (/ x y)

represents the same term as

     (* x (/ y))

which is really

     (binary-* x (unary-/ y)).

Also note that / represents reciprocal as follows:

     (/ x)

expands to

     (unary-/ x).

/ is a Common Lisp macro. See any Common Lisp documentation for more information.

10.8 /=

/= test inequality of two numbers (/= x y) is logically equivalent to (not (equal x y)). Unlike equal (EQUAL^), /= has a guard (GUARD^) requiring both of its arguments to be numbers. Generally, /= is executed more efficiently than a combination of not (NOT^) and equal (EQUAL^). For a discussion of the various ways to test against 0, See Section 10.259 [ZERO-TEST-IDIOMS], page 547. /= is a Common Lisp function. See any Common Lisp documentation for more information.

10.9 1+

1+ increment by 1 (1+ x) is the same as (+ 1 x). See Section 10.5 [+], page 437. 1+ is a Common Lisp function. See any Common Lisp documentation for more information.

10.10 1-

1- decrement by 1 (1- x) is the same as (- x 1). See Section 10.6 [-], page 437. 1- is a Common Lisp function. See any Common Lisp documentation for more information.

10.11 <

< less-than

Basic axiom:

     (equal (< x y)
            (if (and (rationalp x)
                     (rationalp y))
                (< x y)
              (let ((x1 (if (acl2-numberp x) x 0))
                    (y1 (if (acl2-numberp y) y 0)))
                (or (< (realpart x1) (realpart y1))
                    (and (equal (realpart x1) (realpart y1))
                         (< (imagpart x1) (imagpart y1)))))))

Guard (GUARD^) for (< x y):

     (and (rationalp x) (rationalp y))

Notice that like all arithmetic functions, < treats non-numeric inputs as 0.

This function has the usual meaning on the rational numbers, but is extended to the complex rational numbers using the lexicographic order: first the real parts are compared, and if they are equal, then the imaginary parts are compared.

10.12 <=

<= less-than-or-equal test

<= is a macro, and (<= x y) expands to the same thing as (not (< y x)). See Section 10.11 [<], page 440.

<= is a Common Lisp function. See any Common Lisp documentation for more information.

10.13 =

= test equality (of two numbers, symbols, or characters (CHARACTERS^))

(= x y) is logically equivalent to (equal x y). Unlike equal (EQUAL^), = has a guard (GUARD^) requiring both of its arguments to be numbers. Generally, = is executed more efficiently than equal (EQUAL^). For a discussion of the various ways to test against 0, See Section 10.259 [ZERO-TEST-IDIOMS], page 547. = is a Common Lisp function. See any Common Lisp documentation for more information.

10.14 >

> greater-than test > is a macro, and (> x y) expands to the same thing as (< y x). See Section 10.11 [<], page 440. > is a Common Lisp function. See any Common Lisp documentation for more information.

10.15 >=

>= greater-than-or-equal test >= is a macro, and (>= x y) expands to the same thing as (not (< x y)). See Section 10.11 [<], page 440. >= is a Common Lisp function. See any Common Lisp documentation for more information.

10.16 ABS

ABS the absolute value of a rational number (Abs x) is -x if x is negative and is x otherwise. The guard (GUARD^) for abs requires its argument to be a rational numbers.

Abs is a Common Lisp function. See any Common Lisp documentation for more information.

From “Common Lisp the Language” page 205, we must not allow complex x as an argument to abs in ACL2, because if we did we would have to return a number that might not be a complex rational number (see Section 10.88 [COMPLEX-RATIONALP], page 467) and hence not an ACL2 object.

10.17 ACL2-COMPLEX-RATIONALP

ACL2-COMPLEX-RATIONALP recognizer for complex rationals

(acl2-complex-rationalp x) is true if and only if x is a complex rational number (and hence, not a rational number).

10.18 ACL2-NUMBERP

ACL2-NUMBERP recognizer for numbers

(acl2-numberp x) is true if and only if x is a number, i.e., a rational or complex rational number.

10.19 ACL2-USER

ACL2-USER a package the ACL2 user may prefer

This package imports the standard Common Lisp symbols that ACL2 supports and also a few symbols from package "ACL2" that are commonly used when interacting with ACL2. You may prefer to select this as your current package so as to avoid colliding with ACL2 system names.

This package imports the symbols listed in *common-lisp-symbols-from-main-lisp-package*,

which contains hundreds of CLTL function and macro names including those supported by ACL2 such as cons (CONS^), car (CAR^), and cdr (CDR^). It also imports the symbols in *acl2exports*, which contains a few symbols that are frequently used while interacting with the ACL2 system, such as implies (IMPLIES^), defthm (DEFTHM^), and rewrite (REWRITE^). It imports nothing else.

Thus, names such as alistp (ALISTP^), member-equal (MEMBER-EQUAL^), and type-set (TYPE-SET^), which are defined in the "ACL2" package are not present here. If you find yourself frequently colliding with names that are defined in "ACL2" you might consider selecting "ACL2-USER" as your current package (see Section 8.46 [IN-PACKAGE], page 327). If you select "ACL2-USER" as the current package, you may then simply type member-equal (MEMBER-EQUAL^) to refer to acl2-user::member-equal, which you may define as you see fit. Of course, should you desire to refer to the "ACL2" version of member-equal (MEMBER-EQUAL^), you will have to use

the "ACL2::" prefix, e.g., acl2::member-equal.

If, while using "ACL2-USER" as the current package, you find that there are symbols from "ACL2" that you wish we had imported into it (because they are frequently used in interaction), please bring those symbols to our attention. For example, should union-theories (UNION-THEORIES^) and universal-theory (UNIVERSAL-THEORY^) be imported? Except for stabilizing on the “frequently used” names from "ACL2", we intend never to define a symbol whose symbol-package-name (SYMBOL-PACKAGE-NAME^) is "ACL2-USER".

10.20 ACONS

ACONS constructor for association lists

(Acons key datum alist) equals the result of consing the pair (cons key datum) to the front of the association list alist.

(Acons key datum alist) has a guard (GUARD^) of (alistp alist). Acons is a Common Lisp

function. See any Common Lisp documentation for more information.

10.21 ADD-TO-SET-EQ

ADD-TO-SET-EQ add a symbol to a list

For a symbol x and a true list lst, (add-to-set-eq x lst) is the result of cons (CONS^)ing x on to the front of lst, unless x is already a member of lst, in which case it equals x.

(add-to-set-eq x lst) has a guard (GUARD^) that lst is a true list and moreover, either x is a symbol or lst is a list of symbols.

10.22 ALISTP

ALISTP recognizer for association lists (alistp x) is true if and only if x is a list of cons (CONS^) pairs. (alistp x) has a guard (GUARD^) of t.

10.23 ALPHA-CHAR-P

ALPHA-CHAR-P recognizer for alphabetic characters (Alpha-char-p x) is true if and only if x is a alphabetic character, i.e., one of the characters (CHARACTERS^) #a, #b, ..., #z, #A, #B, ..., #Z. The guard (GUARD^) for alpha-char-p requires its argument to be a character. Alpha-char-p is a Common Lisp function. See any Common Lisp documentation for more information.

10.24 AND

AND conjunction And is the macro for conjunctions. And takes any number of arguments. And returns nil if one of the arguments is nil, but otherwise returns the last argument. If there are no arguments, and returns t. And is a Common Lisp macro. See any Common Lisp documentation for more information.

10.25 APPEND

APPEND concatenate (CONCATENATE^) two or more lists Append, which takes two or more arguments, expects all the arguments except perhaps the last to be true (null-terminated) lists. It returns the result of concatenating all the elements of all the given lists into a single list. Actually, in ACL2 append is a macro that expands into calls of the binary function binary-append (BINARY-APPEND^).

Append is a Common Lisp function. See any Common Lisp documentation for more information.

10.26 ASH

ASH arithmetic shift operation

(ash i c) is the result of taking the two’s complement representation of the integer i and shifting it by c bits, padding with c 0 bits if c is positive, and dropping (abs c) bits if c is negative.

The guard (GUARD^) for ash requires that its arguments are integers.

Ash is a Common Lisp function. See any Common Lisp documentation for more information.

10.27 ASSOC

ASSOC look up key in association list, using eql (EQL^) as test

(Assoc x alist) is the first member of alist whose car (CAR^) is x, or nil if no such member exists.

(Assoc x alist) is provably the same in the ACL2 logic as (assoc-equal x alist). It has a stronger guard (GUARD^) than assoc-equal (ASSOC-EQUAL^) because it uses eql (EQL^) to test whether x is equal to the car (CAR^) of a given member of alist. Its guard (GUARD^) requires that alist is an alistp (ALISTP^), and moreover, either (eqlablep x) or all car (CAR^)s of members of alist are eqlablep (EQLABLEP^). See Section 10.29 [ASSOC-EQUAL], page 446 and see Section 10.28 [ASSOC-EQ], page 446.

Assoc is a Common Lisp function. See any Common Lisp documentation for more information. Since ACL2 functions cannot take keyword arguments (though macros can), the ACL2 functions assoc-equal (ASSOC-EQUAL^) and assoc-eq (ASSOC-EQ^) are defined to correspond to calls of the Common Lisp function assoc whose keyword argument :test is equal (EQUAL^) or eq (EQ^), respectively.

10.28 ASSOC-EQ

ASSOC-EQ look up key in association list, using eq (EQ^) as test

(Assoc-eq x alist) is the first member of alist whose car (CAR^) is x, or nil if no such member exists.

(Assoc-eq x alist) is provably the same in the ACL2 logic as (assoc x alist) and (assoc-

equal x alist), but it has a stronger guard (GUARD^) because it uses eq (EQ^) for a more efficient test for whether x is equal to a given key of alist. Its guard (GUARD^) requires that alist is an association list (see Section 10.22 [ALISTP], page 444), and moreover, either x is a symbol or all keys of alist are symbols, i.e., alist is a symbol-alistp (SYMBOL-ALISTP^).

10.29 ASSOC-EQUAL

ASSOC-EQUAL look up key in association list

(Assoc-equal x alist) is the first member of alist whose car (CAR^) is x, or nil if no such member exists.

(Assoc-equal x alist) has a guard (GUARD^) of (alistp alist), and returns the first member of alist whose car (CAR^) is x, or nil if no such member exists. Thus, assoc-equal has the same functionality as the Common Lisp function assoc (ASSOC^), except that it uses the equal (EQUAL^) function to test whether x is the same as each successive ‘key’ of alist. See Section 10.27 [ASSOC], page 445 and see Section 10.28 [ASSOC-EQ], page 446.

10.30 ASSOC-KEYWORD

ASSOC-KEYWORD look up key in a keyword-value-listp (KEYWORD-VALUE-LISTP^)

If l is a list of even length of the form (k1 a1 k2 a2 ... kn an), where each ki is a keyword, then (assoc-keyword key l) is the first tail of l starting with key if key is some ki, and is nil otherwise.

The guard (GUARD^) for (assoc-keyword key l) is (keyword-value-listp l).

10.31 ASSOC-STRING-EQUAL

ASSOC-STRING-EQUAL look up key, a string, in association list

(Assoc-string-equal x alist) is similar to assoc-equal (ASSOC-EQUAL^). However, for

string x and alist alist, the comparison of x with successive keys in alist is done using stringequal (STRING-EQUAL^) rather than equal (EQUAL^).

The guard (GUARD^) for assoc-string-equal requires that x is a string and alist is an alist.

10.32 ATOM

ATOM recognizer for atoms

(atom x) is true if and only if x is an atom, i.e., not a cons (CONS^) pair.

Atom has a guard (GUARD^) of t, and is a Common Lisp function. See any Common Lisp documentation for more information.

10.33 ATOM-LISTP

ATOM-LISTP recognizer for a true list of atom (ATOM^)s

The predicate atom-listp tests whether its argument is a true-listp (TRUE-LISTP^) of atom (ATOM^)s, i.e., of non-conses.

10.34 BINARY-*

BINARY-* multiplication function

Basic axiom:

     (equal (binary-* x y)
            (if (acl2-numberp x)
                (if (acl2-numberp y)
                    (binary-* x y)
                  0)
              0))

Guard (GUARD^) for (binary-* x y):

     (and (acl2-numberp x) (acl2-numberp y))

Notice that like all arithmetic functions, binary-* treats non-numeric inputs as 0.

Calls of the macro * (*^) expand to calls of binary-*; see Section 10.1 [*], page 435.

10.35 BINARY-+

BINARY-+ addition function

Basic axiom:

     (equal (binary-+ x y)
            (if (acl2-numberp x)
                (if (acl2-numberp y)
                    (binary-+ x y)
                  x)
              (if (acl2-numberp y)
                  y
                0)))

Guard (GUARD^) for (binary-* x y):

     (and (acl2-numberp x) (acl2-numberp y))

Notice that like all arithmetic functions, binary-+ treats non-numeric inputs as 0. Calls of the macro + (+^) expand to calls of binary-+; see Section 10.5 [+], page 437.

10.36 BINARY-APPEND

BINARY-APPEND concatenate (CONCATENATE^) two lists This binary function implements append (APPEND^), which is a macro in ACL2. See Section 10.25 [APPEND], page 444 The guard (GUARD^) for binary-append requires the first argument to be a true-listp (TRUE-LISTP^).

10.37 BOOLEANP

BOOLEANP recognizer for booleans (Booleanp x) is t if x is t or nil, and is nil otherwise. See Section 8.39 [GENERALIZED-BOOLEANS], page 302 for a discussion of a potential soundness problem for ACL2 related to the question: Which Common Lisp functions are known to return Boolean values?

10.38 BUTLAST

BUTLAST all but a final segment of a list (Butlast l n) is the list obtained by removing the last n elements from the true list l. The following is a theorem (though it takes some effort, including lemmas, to get ACL2 to prove it).

     (implies (and (integerp n)
                   (<= 0 n)
                   (true-listp l))
              (equal (length (butlast l n))

                     (if (< n (length l))
                         (- (length l) n)
                       0)))

For related functions, see Section 10.245 [TAKE], page 541 and see Section 10.180 [NTHCDR], page 515. The guard (GUARD^) for (butlast l n) requires that n is a nonnegative integer and lst is a true list. Butlast is a Common Lisp function. See any Common Lisp documentation for more information. Note: In Common Lisp the second argument of butlast is optional, but in ACL2 it is required.

10.39 CAAAAR

CAAAAR car (CAR^) of the caaar (CAAAR^) See any Common Lisp documentation for details.

10.40 CAAADR

CAAADR car (CAR^) of the caadr (CAADR^) See any Common Lisp documentation for details.

10.41 CAAAR

CAAAR car (CAR^) of the caar (CAAR^) See any Common Lisp documentation for details.

10.42 CAADAR

CAADAR car (CAR^) of the cadar (CADAR^) See any Common Lisp documentation for details.

10.43 CAADDR

CAADDR car (CAR^) of the caddr (CADDR^) See any Common Lisp documentation for details.

10.44 CAADR

CAADR car (CAR^) of the cadr (CADR^) See any Common Lisp documentation for details.

10.45 CAAR

CAAR car (CAR^) of the car (CAR^) See any Common Lisp documentation for details.

10.46 CADAAR

CADAAR car (CAR^) of the cdaar (CDAAR^) See any Common Lisp documentation for details.

10.47 CADADR

CADADR car (CAR^) of the cdadr (CDADR^) See any Common Lisp documentation for details.

10.48 CADAR

CADAR car (CAR^) of the cdar (CDAR^) See any Common Lisp documentation for details.

10.49 CADDAR

CADDAR car (CAR^) of the cddar (CDDAR^) See any Common Lisp documentation for details.

10.50 CADDDR

CADDDR car (CAR^) of the cdddr (CDDDR^) See any Common Lisp documentation for details.

10.51 CADDR

CADDR car (CAR^) of the cddr (CDDR^) See any Common Lisp documentation for details.

10.52 CADR

CADR car (CAR^) of the cdr (CDR^)

See any Common Lisp documentation for details.

10.53 CAR

CAR returns the first element of a non-empty list, else nil

Basic axiom:

     (equal (car x)
            (cond
             ((consp x)
              (car x))
             (t nil)))

Guard (GUARD^):

     (or (consp x) (equal x nil))

Notice that in the ACL2 logic, car returns nil for every atom (ATOM^).

10.54 CASE

CASE conditional based on if-then-else using eql (EQL^)

     Example Form:
     (case typ
       ((:character foo)
        (open file-name :direction :output))
       (bar (open-for-bar file-name))
       (otherwise
        (my-error "Illegal.")))

is the same as

(cond ((member typ '(:character foo))
     (open file-name :direction :output))
    ((eql typ 'bar)
     (open-for-bar file-name))
    (t (my-error "Illegal.")))

which in turn is the same as

(if (member typ '(:character foo))
  (open file-name :direction :output)
  (if (eql typ 'bar)
      (open-for-bar file-name)
      (my-error "Illegal.")))
General Forms:
(case expr
(x1 val-1)
...
(xk val-k)
(otherwise val-k+1))
(case expr
(x1 val-1)
...
(xk val-k)
(t val-k+1))

where each xi is either eqlablep (EQLABLEP^) or a true list of eqlablep (EQLABLEP^) objects.

Case is defined in Common Lisp. See any Common Lisp documentation for more information.

10.55 CASE-MATCH

CASE-MATCH pattern matching or destructuring

General Form:
(case-match x
(pat1 dcl1 body1)
...
(patk dclk bodyk))

where x is a variable symbol, the pati are structural patterns as described below, the dcli are optional declare (DECLARE^) forms and the bodyi are terms. Return the value(s) of the bodyi corresponding to the first pati matching x, or nil if none matches.

Pattern Language:

With the few special exceptions described below, matching requires that the cons (CONS^) structure of x be isomorphic to that of the pattern, down to the atom (ATOM^)s in the pattern. Nonsymbol atom (ATOM^)s in the pattern match only themselves. Symbols in the pattern denote variables which match anything and which are bound by a successful match to the corresponding substructure of x. Variables that occur more than once must match the same (EQUAL (EQUAL^)) structure in every occurrence.

     Exceptions:
     &               Matches anything and is not bound.  Multiple
                       occurrences of & in a pattern may match different
                       structures.
     nil, t, *sym*   These symbols cannot be bound and match only their
                       global values.
     !sym            where sym is a symbol that is already bound in the
                       context of the case-match, matches only the
                       current binding of sym.
     'obj            Matches only itself.

Some examples are shown below.

Below we show some sample patterns and examples of things they match and do not match.

     pattern       matches         non-matches
     (x y y)       (ABC 3 3)       (ABC 3 4)    ; 3 is not 4
     (fn x . rst)  (P (A I) B C)   (ABC)        ; NIL is not (x . rst)
                   (J (A I))                    ; rst matches nil
     ('fn (g x) 3) (FN (H 4) 3)    (GN (G X) 3) ; 'fn matches only itself
     (& t & !x)    ((A) T (B) (C))              ; provided x is '(C)

Consider the two binary trees that contain three leaves. They might be described as (x . (y . z)) and ((x . y) . z), where x, y, and z are atomic. Suppose we wished to recognize those trees. The following case-match would do:

     (case-match tree
       ((x . (y . z))

        (and (atom x) (atom y) (atom z)))
       (((x . y) . z)
        (and (atom x) (atom y) (atom z))))

Suppose we wished to recognize such trees where all three tips are identical. Suppose further we wish to return the tip if the tree is one of those recognized ones and to return the number 7 otherwise.

     (case-match tree
       ((x . (x . x))
        (if (atom x) x 7))
       (((x . x) . x)
        (if (atom x) x 7))
       (& 7))

Note that case-match returns nil if no pati matches. Thus if we must return 7 in that case, we have to add as the final pattern the &, which always matches anything.

10.56 CDAAAR

CDAAAR cdr (CDR^) of the caaar (CAAAR^)

See any Common Lisp documentation for details.

10.57 CDAADR

CDAADR cdr (CDR^) of the caadr (CAADR^)

See any Common Lisp documentation for details.

10.58 CDAAR

CDAAR cdr (CDR^) of the caar (CAAR^)

See any Common Lisp documentation for details.

10.59 CDADAR

CDADAR cdr (CDR^) of the cadar (CADAR^) See any Common Lisp documentation for details.

10.60 CDADDR

CDADDR cdr (CDR^) of the caddr (CADDR^) See any Common Lisp documentation for details.

10.61 CDADR

CDADR cdr (CDR^) of the cadr (CADR^) See any Common Lisp documentation for details.

10.62 CDAR

CDAR cdr (CDR^) of the car (CAR^) See any Common Lisp documentation for details.

10.63 CDDAAR

CDDAAR cdr (CDR^) of the cdaar (CDAAR^) See any Common Lisp documentation for details.

10.64 CDDADR

CDDADR cdr (CDR^) of the cdadr (CDADR^) See any Common Lisp documentation for details.

10.65 CDDAR

CDDAR cdr (CDR^) of the cdar (CDAR^) See any Common Lisp documentation for details.

10.66 CDDDAR

CDDDAR cdr (CDR^) of the cddar (CDDAR^) See any Common Lisp documentation for details.

10.67 CDDDDR

CDDDDR cdr (CDR^) of the cdddr (CDDDR^) See any Common Lisp documentation for details.

10.68 CDDDR

CDDDR cdr (CDR^) of the cddr (CDDR^) See any Common Lisp documentation for details.

10.69 CDDR

CDDR cdr (CDR^) of the cdr (CDR^)

See any Common Lisp documentation for details.

10.70 CDR

CDR returns the second element of a cons (CONS^) pair, else nil

Basic axiom:

(equal (cdr x)
       (cond
        ((consp x)
         (cdr x))
        (t nil)))

Guard (GUARD^):

(or (consp x) (equal x nil))

Notice that in the ACL2 logic, cdr returns nil for every atom (ATOM^).

10.71 CEILING

CEILING division returning an integer by truncating toward positive infinity

Example Forms:
ACL2 !>(ceiling 14 3)
5
ACL2 !>(ceiling -14 3)
-4
ACL2 !>(ceiling 14 -3)
-4
ACL2 !>(ceiling -14 -3)
5
ACL2 !>(ceiling -15 -3)

(Ceiling i j) is the result of taking the quotient of i and j and returning the smallest integer that is at least as great as that quotient. For example, the quotient of -14 by 3 is -4 2/3, and the smallest integer at least that great is -4. The guard (GUARD^) for (ceiling i j) requires that i and j are rational numbers and j is non-zero. Ceiling is a Common Lisp function. See any Common Lisp documentation for more information.

10.72 CHAR

CHAR the nth (NTH^) element (zero-based) of a string (Char s n) is the nth element of s, zero-based. If n is greater than or equal to the length of s, then char returns nil. (Char s n) has a guard (GUARD^) that n is a non-negative integer and s is a stringp (STRINGP^). Char is a Common Lisp function. See any Common Lisp documentation for more information.

10.73 CHAR-CODE

CHAR-CODE the numeric code for a given character Basic axiom:

     (equal (char-code x)
            (if (characterp x)
                (char-code x)
              0))

Guard (GUARD^) for (char-code x):

     (characterp x)

This function maps all non-characters to 0.

10.74 CHAR-DOWNCASE

CHAR-DOWNCASE turn upper-case characters (CHARACTERS^) into lower-case characters (CHARACTERS^) (Char-downcase x) is equal to #A when x is #a, #B when x is #b, ..., and #Z when x is #z, and is x for any other character. The guard (GUARD^) for char-downcase requires its argument to be a character. Char-downcase is a Common Lisp function. See any Common Lisp documentation for more information.

10.75 CHAR-EQUAL

CHAR-EQUAL character equality without regard to case For characters (CHARACTERS^) x and y, (char-equal x y) is true if and only if x and y are the same except perhaps for their case. The guard (GUARD^) on char-equal requires that its arguments are both characters (CHARAC-TERS^). Char-equal is a Common Lisp function. See any Common Lisp documentation for more information.

10.76 CHAR-UPCASE

CHAR-UPCASE turn lower-case characters (CHARACTERS^) into upper-case characters (CHARACTERS^) (Char-upcase x) is equal to #A when x is #a, #B when x is #b, ..., and #Z when x is #z, and is x for any other character. The guard (GUARD^) for char-upcase requires its argument to be a character.

Char-upcase is a Common Lisp function. See any Common Lisp documentation for more information.

10.77 CHAR<

CHAR< less-than test for characters (CHARACTERS^) (char< x y) is true if and only if the character code of x is less than that of y. See Section 10.73 [CHAR-CODE], page 460. The guard (GUARD^) for char< specifies that its arguments are characters (CHARACTERS^). Char< is a Common Lisp function. See any Common Lisp documentation for more information.

10.78 CHAR<=

CHAR<= less-than-or-equal test for characters (CHARACTERS^) (char<= x y) is true if and only if the character code of x is less than or equal to that of y. See Section 10.73 [CHAR-CODE], page 460. The guard (GUARD^) for char<= specifies that its arguments are characters (CHARACTERS^). Char<= is a Common Lisp function. See any Common Lisp documentation for more information.

10.79 CHAR>

CHAR> greater-than test for characters (CHARACTERS^) (char> x y) is true if and only if the character code of x is greater than that of y. See Section 10.73 [CHAR-CODE], page 460. The guard (GUARD^) for char> specifies that its arguments are characters (CHARACTERS^). Char> is a Common Lisp function. See any Common Lisp documentation for more information.

10.80 CHAR>=

CHAR>= greater-than-or-equal test for characters (CHARACTERS^) (char>= x y) is true if and only if the character code of x is greater than or equal to that of y. See Section 10.73 [CHAR-CODE], page 460. The guard (GUARD^) for char>= specifies that its arguments are characters (CHARACTERS^). Char>= is a Common Lisp function. See any Common Lisp documentation for more information.

10.81 CHARACTER-LISTP

CHARACTER-LISTP recognizer for a true list of characters The predicate character-listp tests whether its argument is a true list of characters (CHARAC-TERS^).

10.82 CHARACTERP

CHARACTERP recognizer for characters (CHARACTERS^) (characterp x) is true if and only if x is a character.

10.83 CHARACTERS

CHARACTERS characters in ACL2 ACL2 accepts 256 distinct characters, which are the characters obtained by applying the function code-char (CODE-CHAR^) to each integer from 0 to 255. Among these, Common Lisp designates certain ones as standard characters, namely those of the form (code-char n) where n is from 33 to 126, together with #\Newline and #\Space. The actual standard characters may be viewed by

evaluating the defconst (DEFCONST^) *standard-chars*.

To be more precise, Common Lisp does not specify the precise relationship between code-char (CODE-CHAR^) and the standard characters. However, we check that the underlying Common Lisp implementation uses a particular relationship that extends the usual ASCII coding of characters. We also check that Space, Tab, Newline, Page, and Rubout correspond to characters with respective char-code (CHAR-CODE^)s 32, 9, 10, 12, and 127.

Code-char (CODE-CHAR^) has an inverse, char-code (CHAR-CODE^). Thus, when char-code (CHAR-CODE^) is applied to an ACL2 character, c, it returns a number n between 0 and 255 inclusive such that (code-char n) = c.

The preceding paragraph implies that there is only one ACL2 character with a given character code. CLTL allows for “attributes” for characters, which could allow distinct characters with the same code, but ACL2 does not allow this.

The Character Reader

ACL2 support the ‘#\’ notation for characters provided by Common Lisp, with some restrictions. First of all, for every character c, the notation

     #\c

may be used to denote the character object c. That is, the user may type in this notation and ACL2 will read it as denoting the character object c. In this case, the character immediately following c must be one of the following “terminating characters”: a Tab, a Newline, a Page character, a space, or one of the characters:

     "  '  (  )  ;  `  ,

Other than the notation above, ACL2 accepts alternate notation for five characters.

     #\Space
     #\Tab
     #\Newline
     #\Page
     #\Rubout

Again, in each of these cases the next character must be from among the set of “terminating characters” described in the single-character case. Our implementation is consistent with IS0-8859, even though we don’t provide #\ syntax for entering characters other than that described above.

Finally, we note that it is our intention that any object printed by ACL2’s top-level-loop may be read back into ACL2. Please notify the implementors if you find a counterexample to this claim.

10.84 CODE-CHAR

CODE-CHAR the character corresponding to a given numeric code

Basic axiom:

     (equal (code-char x)
            (if (and (integerp x)
                     (>= x 0)
                     (< x 256))
                (code-char x)
              (code-char 0)))

Guard (GUARD^) for (code-char x):

     (and (integerp x)
          (>= x 0)
          (< x 256))

ACL2 supports 8-bit characters (CHARACTERS^). Inputs not between 0 and 255 are treated as

0.

10.85 COERCE

COERCE coerce a character list to a string and a string to a list

Basic axiom:

     (equal (coerce x y)
            (cond
             ((equal y 'list)
              (if (stringp x)
                  (coerce x 'list)
                nil))
             (t
              (coerce (make-character-list x) 'string))))

Guard (GUARD^) for (coerce x y):

     (if (equal y 'list)
         (stringp x)
       (if (equal y 'string)
           (character-listp x)
         nil))

10.86 COMPILATION

COMPILATION compiling ACL2 functions

     Example:
     ACL2 !>:comp app
     ACL2 !>:set-compile-fns t

See Section 9.5 [COMP], page 415 and see Section 6.27 [SET-COMPILE-FNS], page 197.

10.87 COMPLEX

COMPLEX create an ACL2 number

     Examples:
     (complex x 3) ; x + 3i, where i is the principal square root of -1
     (complex x y) ; x + yi
     (complex x 0) ; same as x, for rational numbers x

The function complex takes two rational number arguments and returns an ACL2 number. This number will be of type (complex rational) [as defined in the Common Lisp language], except that if the second argument is zero, then complex returns its first argument. The function complexrationalp (COMPLEX-RATIONALP^) is a recognizer for complex rational numbers, i.e. for ACL2 numbers that are not rational numbers.

The reader macro #C (which is the same as #c) provides a convenient way for typing in complex numbers. For explicit rational numbers x and y, #C(x y) is read to the same value as (complex x

y).

The functions realpart (REALPART^) and imagpart (IMAGPART^) return the real and imaginary parts (respectively) of a complex (possibly rational) number. So for example, (realpart

#C(3 4)) = 3, (imagpart #C(3 4)) = 4, (realpart 3/4) = 3/4, and (imagpart 3/4) = 0.

A basic axiom that shows what complex returns on arguments violating its guard (GUARD^) (which says that both arguments are rational numbers) is the following.

(equal (complex x y)
       (complex (if (rationalp x) x 0)
                (if (rationalp y) y 0)))

10.88 COMPLEX-RATIONALP

COMPLEX-RATIONALP recognizes complex rational numbers

Examples:
(complex-rationalp 3)       ; nil, as 3 is rational, not complex rational
(complex-rationalp #c(3 0)) ; nil, since #c(3 0) is the same as 3
(complex-rationalp t)       ; nil
(complex-rationalp #c(3 1)) ; t, as #c(3 1) is the complex number 3 + i

See Section 10.87 [COMPLEX], page 466 for more about complex rationals in ACL2.

10.89 CONCATENATE

CONCATENATE concatenate lists or strings together

Examples:
(concatenate 'string "ab" "cd" "ef")     ; equals "abcdef"
(concatenate 'string "ab")               ; equals "ab"
(concatenate 'list '(a b) '(c d) '(e f)) ; equals '(a b c d e f)
(concatenate 'list)                      ; equals nil
General Form:
(concatenate result-type x1 x2 ... xn)

where n >= 0 and either: result-type is 'string (STRING^) and each xi is a string; or resulttype is 'list (LIST^) and each xi is a true list. Concatenate simply concatenates its arguments to form the result string or list. Also see Section 10.25 [APPEND], page 444 and see Section 10.222 [STRING-APPEND], page 533, though concatenate is probably preferable to string-append (STRING-APPEND^) for efficiency.

Note: We do *not* try to comply with the Lisp language’s insistence that concatenate copies its arguments. Not only are we in an applicative setting, where this issue shouldn’t matter for the logic, but also we do not actually modify the underlying lisp implementation of concatenate; we merely provide a definition for it.

Concatenate is a Common Lisp function. See any Common Lisp documentation for more information.

10.90 COND

COND conditional based on if-then-else

Cond is the construct for IF, THEN, ELSE IF, ... The test is against nil. The argument list for cond is a list of “clauses”, each of which is a list. In ACL2, clauses must have length 1 or 2.

Cond is a Common Lisp macro. See any Common Lisp documentation for more information.

10.91 CONJUGATE

CONJUGATE complex number conjugate

Conjugate takes an ACL2 number as an argument, and returns its complex conjugate (i.e., the result of negating its imaginary part.).

Conjugate is a Common Lisp function. See any Common Lisp documentation for more information.

10.92 CONS

CONS pair and list constructor

(cons x y) is a pair whose first component is x and second component is y. If y is a list, then (cons x y) is a list that has an addtional element x on the front.

10.93 CONSP

CONSP recognizer for cons (CONS^) pairs

(consp x) is true if and only if x is a cons (CONS^) pair.

10.94 DECLARE

DECLARE declarations

Examples:
(declare (ignore x y z))
(declare (ignore x y z)
       (type integer i j k)
       (type (satisfies integerp) m1 m2))
(declare (xargs :guard (and (integerp i)
                          (<= 0 i))
              :guard-hints (("Goal" :use (:instance lemma3
                                            (x (+ i j)))))))
General Form:
(declare d1 ... dn)
where, in ACL2, each di is of one of the following forms:
(ignore v1 ... vn) -- where each vi is a variable introduced in
the immediately superior lexical environment.
(type type-spec v1 ... vn) -- where each vi is a variable
introduced in the immediately superior lexical environment and
type-spec is a type specifier (as described in the documentation
for type-spec).
(xargs :key1 val1 ... :keyn valn) -- where the legal values of the
keyi's and their respective vali's are described in the
documentation for xargs.

Declarations in ACL2 may occur only where dcl occurs below:

(DEFUN name args doc-string dcl ... dcl body)
(DEFMACRO name args doc-string dcl ... dcl body)
(LET ((v1 t1) ...) dcl ... dcl body)
(MV-LET (v1 ...) term dcl ... dcl body)

Of course, if a form macroexpands into one of these (as let* (LET*^) expands into nested let (LET^)s and our er-let* expands into nested mv-let (MV-LET^)s) then declarations are permitted as handled by the macros involved.

Declare is defined in Common Lisp. See any Common Lisp documentation for more information.

10.95 DENOMINATOR

DENOMINATOR divisor of a ratio in lowest terms

Basic axiom:

     (equal (denominator x)
            (if (rationalp x)
                (denominator x)
              1))

Guard (GUARD^) for (denominator x):

     (rationalp x)

10.96 DIGIT-CHAR-P

DIGIT-CHAR-P the number, if any, corresponding to a given character

(digit-char-p ch) is the integer corresponding to the character ch in base 10. For example, (digit-char-p #\3) is equal to the integer 3. More generally, an optional second argument specifies the radix (default 10, as indicated above).

The guard (GUARD^) for digit-char-p (more precisely, for the function our-digit-char-p that calls of this macro expand to) requires its second argument to be an integer between 2 and 36, inclusive, and its first argument to be a character.

Digit-char-p is a Common Lisp function, though it is implemented in the ACL2 logic as an ACL2 macro. See any Common Lisp documentation for more information.

10.97 DIGIT-TO-CHAR

DIGIT-TO-CHAR map a digit to a character

     Example:
     ACL2 !>(digit-to-char 8)
     #\8

For an integer n from 0 to 9, (digit-to-char n) is the character corresponding to n in decimal notation. The guard (GUARD^) for digit-to-char requires its argument to be an integer between 0 and 9, inclusive.

10.98 EIGHTH

EIGHTH eighth member of the list See any Common Lisp documentation for details.

10.99 ENDP

ENDP recognizer for empty lists In the ACL2 logic, (endp x) is the same as (atom x). See Section 10.32 [ATOM], page 447. Unlike atom (ATOM^), the guard (GUARD^) for endp requires that x is a cons (CONS^) pair or is nil. Thus, endp is typically used as a termination test for functions that recur on a true-listp (TRUE-LISTP^) argument. See Section 8.41 [GUARD], page 305 for general information about guard (GUARD^)s. Endp is a Common Lisp function. See any Common Lisp documentation for more information.

10.100 EQ

EQ equality of symbols

Eq is the function for determining whether two objects are identical (i.e., have the exact same store address in the current von Neumann implementation of Common Lisp). It is the same as equal (EQUAL^) in the ACL2 logic.

Eq is a Common Lisp function. In order to ensure conformance with Common Lisp, the ACL2 guard (GUARD^) on eq requires at least one of the arguments to eq to be a symbol. Common Lisp guarantees that if x is a symbol, then x is eq to y if and only if x is equal (EQUAL^) to y. Thus, the ACL2 user should think of eq as nothing besides a fast means for checking equal (EQUAL^) when one argument is known to be a symbol. In particular, it is possible that an eq test will not even require the cost of a function call but will be as fast as a single machine instruction.

10.101 EQL

EQL test equality (of two numbers, symbols, or characters (CHARACTERS^))

(eql x y) is logically equivalent to (equal x y).

Unlike equal (EQUAL^), eql has a guard (GUARD^) requiring at least one of its arguments to be a number, a symbol, or a character. Generally, eql is executed more efficiently than equal (EQUAL^).

For a discussion of the various ways to test against 0, See Section 10.259 [ZERO-TEST-IDIOMS], page 547.

Eql is a Common Lisp function. See any Common Lisp documentation for more information.

10.102 EQLABLE-ALISTP

EQLABLE-ALISTP recognizer for a true list of pairs whose car (CAR^)s are suitable for eql (EQL^)

The predicate eqlable-alistp tests whether its argument is a true-listp (TRUE-LISTP^) of consp (CONSP^) objects whose car (CAR^)s all satisfy eqlablep (EQLABLEP^).

10.103 EQLABLE-LISTP

EQLABLE-LISTP recognizer for a true list of objects each suitable for eql (EQL^) The predicate eqlable-listp tests whether its argument is a true-listp (TRUE-LISTP^) of objects satisfying eqlablep (EQLABLEP^).

10.104 EQLABLEP

EQLABLEP the guard (GUARD^) for the function eql (EQL^) The predicate eqlablep tests whether its argument is suitable for eql (EQL^), at least one of whose arguments must satisfy this predicate in Common Lisp. (Eqlablep x) is true if and only if its argument is a number, a symbol, or a character.

10.105 EQUAL

EQUAL true equality (equal x y) is equal to t or nil, according to whether or not x and y are the same value. For a discussion of the various idioms for testing against 0, See Section 10.259 [ZERO-TEST-IDIOMS], page 547.

10.106 ER-PROGN

ER-PROGN perform a sequence of state-changing “error triples”

     Example:
     (er-progn (check-good-foo-p (f-get-global 'my-foo state) state)
               (value (* (f-get-global 'my-foo state)
                         (f-get-global 'bar state))))

This sequencing primitive is only useful when programming with state (STATE^), something that very few users will probably want to do. See Section 8.83 [STATE], page 368.

Er-progn is used much the way that progn (PROGN^) is used in Common Lisp, except that it expects each form within it to evaluate to an “error triple” of the form (mv erp val state). The first such form, if any, that evaluates to such a triple where erp is not nil yields the error triple returned by the er-progn. If there is no such form, then the last form returns the value of the

er-progn form.

We intend to write more about this topic, especially if there are requests to do so.

10.107 EVENP

EVENP test whether an integer is even

(evenp x) is true if and only if the integer x is even. Actually, in the ACL2 logic (evenp x) is defined to be true when x/2 is an integer.

The guard (GUARD^) for evenp requires its argument to be an integer.

Evenp is a Common Lisp function. See any Common Lisp documentation for more information.

10.108 EXPLODE-NONNEGATIVE-INTEGER

EXPLODE-NONNEGATIVE-INTEGER the list of characters (CHARACTERS^) in the decimal form of a number

     Example:
     ACL2 !>(explode-nonnegative-integer 325 nil)
     (#3 #2 #5)

For a non-negative integer n, (explode-nonnegative-integer n nil) is the list of characters (CHARACTERS^) in the decimal representation of n.

The guard (GUARD^) for explode-nonnegative-integer requires the first argument to be a nonnegative integer.

10.109 EXPT

EXPT exponential function (Expt r i) is the result of raising the number r to the integer power i. The guard (GUARD^) for (expt r i) is that r is a number and i is an integer, and furthermore, if r is 0 then i is nonnegative. When the type requirements of the guard (GUARD^) aren’t met, (expt r i) first coerces r to a number and i to an integer. Expt is a Common Lisp function. See any Common Lisp documentation for more information. Note that r can be a complex number; this is consistent with Common lisp.

10.110 FIFTH

FIFTH fifth member of the list See any Common Lisp documentation for details.

10.111 FIRST

FIRST first member of the list See any Common Lisp documentation for details.

10.112 FIX

FIX coerce to a number Fix simply returns any numeric argument unchanged, returning 0 on a non-numeric argument. Also see Section 10.173 [NFIX], page 513, see Section 10.122 [IFIX], page 488, and see Section 10.209 [RFIX], page 528 for analogous functions that coerce to a natural number, an integer, and a rational number, respectively. Fix has a guard (GUARD^) of t.

10.113 FIX-TRUE-LIST

FIX-TRUE-LIST coerce to a true list

Fix-true-list is the identity function on true-listp (TRUE-LISTP^) objects. It converts every list to a true list by dropping the final cdr (CDR^), and it converts every atom (ATOM^) to nil.

10.114 FLOOR

FLOOR division returning an integer by truncating toward negative infinity

     Example Forms:
     ACL2 !>(floor 14 3)
     4
     ACL2 !>(floor -14 3)
     -5
     ACL2 !>(floor 14 -3)
     -5
     ACL2 !>(floor -14 -3)
     4
     ACL2 !>(floor -15 -3)
     5

(Floor i j) returns the result of taking the quotient of i and j and returning the greatest integer not exceeding that quotient. For example, the quotient of -14 by 3 is -4 2/3, and the largest integer not exceeding that rational number is -5.

The guard (GUARD^) for (floor i j) requires that i and j are rational numbers and j is nonzero.

Floor is a Common Lisp function. See any Common Lisp documentation for more information.

10.115 FMS

FMS  :(str alist co-channel state evisc) => state

See Section 10.116 [FMT], page 478 for further explanation.

The tilde-directives are
~xx  pretty print vx (maybe after printing a newline)
~yx  pretty print vx starting in current column; end with newline
~Xxy like ~xx but use vy as the evisceration tuple
~Yxy like ~yx but use vy as the evisceration tuple
~px  pretty print term (maybe with infix) vx
     (maybe after printing a newline)
~qx  pretty print term (maybe with infix) vx
     starting in current column; end with newline
~Pxy like ~px but use vy as the evisceration tuple
~Qxy like ~qx but use vy as the evisceration tuple
~@x  if vx is a string, "str",  recursively format "str"
     if vx is ("str" . a), recursively format "str" under a+
~#x~[...~/...~/ ... ~/...~] cases on vx
     ^^...   ^if 0<=vx<=k, choose vxth alternative
     0    1     ...   k  if vx is a list of length 1, case 0; else 1
~*x  iterator: vx must be of the form
     ("str0" "str1" "str2" "str3" lst . a);
     if lst is initially empty, format "str0" under a+; otherwise,
     bind #\* successively to the elements of lst and then
     recursively format "stri" under a+, where i=1 if there is one
     element left to process, i=2 if there are two left, and i=3
     otherwise.
~&x  print elements of vx with ~x, separated by commas and a
     final ``and''
~vx  print elements of vx with ~x, separated by commas and a
     final ``or''
~nx  if vx is a small positive integer, print it as a word, e.g.,
     seven;
     if vx is a singleton containing a small positive integer, print
       the corresponding ordinal as a word, e.g., seventh
~Nx  like ~nx but the word is capitalized, e.g., Seven or Seventh
~tx  tab out to column vx; newline first if at or past column vx
~cx  vx is (n . w), print integer n right justified in field of
     width w
~fx  print object vx flat over as many lines as necessary
~Fx  same as ~f, except that subsequent lines are indented to
     start one character to the right of the first character printed
~sx  if vx is a symbol, print vx, breaking on hyphens; if vx is a
     string, print the characters in it, breaking on hyphens
~    tilde space: print a space
~_x  print vx spaces
~
     tilde newline: skip following whitespace
~%   output a newline
~|   output a newline unless already on left margin
~~   print a tilde
~-   if close to rightmargin, output a hyphen and newline; else

          skip this char

10.116 FMT

FMT formatted printing

ACL2 provides the functions fmt, fmt1 (FMT1^), and fms (FMS^) as substitutes for Common Lisp’s format function.

All three print a given string under an alist pairing character objects with values, interpreting certain “tilde-directives” in the string. Channel must be a character output channel (e.g., *standardco* (*STANDARD-CO*^)).

     General Forms:                                            result
     (fms string alist channel state evisc-tuple)         ; state
     (fmt string alist channel state evisc-tuple)         ; (mv col state)
     (fmt1 string alist column channel state evisc-tuple) ; (mv col state)

Fms (FMS^) and fmt print an initial newline to put channel in column 0; Fmt1 (FMT1^) requires the current column as input. Columns are numbered from 0. The current column is the column into which the next character will be printed. (Thus, the current column number is also the number of characters (CHARACTERS^) printed since the last newline.) The col returned by fmt and fmt1 (FMT1^) is the current column at the conclusion of the formatting. Evisc-tuple must be either nil (meaning no abbreviations are used when objects are printed) or an “evisceration tuple” such

as that returned by (default-evisc-tuple state).

We list the tilde-directives below. The notation is explained after the chart.

     ~xx  pretty print vx (maybe after printing a newline)
     ~yx  pretty print vx starting in current column; end with newline
     ~Xxy like ~xx but use vy as the evisceration tuple
     ~Yxy like ~yx but use vy as the evisceration tuple
     ~px  pretty print term (maybe with infix) vx
          (maybe after printing a newline)
     ~qx  pretty print term (maybe with infix) vx
          starting in current column; end with newline
     ~Pxy like ~px but use vy as the evisceration tuple
     ~Qxy like ~qx but use vy as the evisceration tuple
     ~@x  if vx is a string, "str",  recursively format "str"
          if vx is ("str" . a), recursively format "str" under a+
     ~#x~[...~/...~/ ... ~/...~] cases on vx

^^...   ^if 0<=vx<=k, choose vxth alternative
0    1     ...   k  if vx is a list of length 1, case 0; else 1
~*x  iterator: vx must be of the form
("str0" "str1" "str2" "str3" lst . a);
if lst is initially empty, format "str0" under a+; otherwise,
bind #\* successively to the elements of lst and then
recursively format "stri" under a+, where i=1 if there is one
element left to process, i=2 if there are two left, and i=3
otherwise.
~&x  print elements of vx with ~x, separated by commas and a
final ``and''
~vx  print elements of vx with ~x, separated by commas and a
final ``or''
~nx  if vx is a small positive integer, print it as a word, e.g.,
seven;
if vx is a singleton containing a small positive integer, print
  the corresponding ordinal as a word, e.g., seventh
~Nx  like ~nx but the word is capitalized, e.g., Seven or Seventh
~tx  tab out to column vx; newline first if at or past column vx
~cx  vx is (n . w), print integer n right justified in field of
width w
~fx  print object vx flat over as many lines as necessary
~Fx  same as ~f, except that subsequent lines are indented to
start one character to the right of the first character printed
~sx  if vx is a symbol, print vx, breaking on hyphens; if vx is a
string, print the characters in it, breaking on hyphens
~    tilde space: print a space
~_x  print vx spaces
~
tilde newline: skip following whitespace
~%   output a newline
~|   output a newline unless already on left margin
~~   print a tilde
~-   if close to rightmargin, output a hyphen and newline; else
skip this char

If x is a character, then vx is the value of #\x under the current alist. When we say “format str under a+” we mean recursively process the given string under an alist obtained by appending a to the current alist.

ACL2’s formatting functions print to the indicated channel, keeping track of which column they are in. Fmt1 (FMT1^) can be used if the caller knows which column the channel is in (i.e., how many characters (CHARACTERS^) have been printed since the last newline). Otherwise, fmt or fms (FMS^) must be used, both of which output a newline so as to establish the column position at 0. Unlike Common Lisp’s format routine, fmt and its relatives break the output into lines so as to try to avoid printing past column 77. That number is built-into the definitions of ACL2’s formatting functions. Line breaks are automatically inserted as necessary in place of spaces and after hyphens in the text being printed.

The formatting functions scan the string from left to right, printing each successive character unless it is a tilde (~). Upon encountering tildes the formatters take action determined by the character or characters (CHARACTERS^) immediately following the tilde. The typical tilde-directive is a group of three successive characters (CHARACTERS^) from the string being printed. For example, ~x0 is a 3 character tilde-directive. The first character in a tilde-directive is always the tilde character itself. The next character is called the “command” character. The character after that is usually taken as the name of a “format variable” that is bound in the alist under which the string is being printed. Format variables are, by necessity, characters (CHARACTERS^). The objects actually printed by a tilde-directive are the objects obtained by looking up the command’s format variables in the alist. Typical format variable names are 0, 1, 2, ..., 9, a, b, c, etc., and if a tilde-directive uses the format variable 0, as in ~x0, then the character #\0 must be bound in the alist. Some tilde commands take no arguments and others take more than one, so some directives are of length two and others are longer.

It should be noted that this use of characters (CHARACTERS^) in the string to denote arguments is another break from Common Lisp’s format routine. In Common Lisp, the directives refer implicitly to the “next item to be printed.” But in ACL2 the directives name each item explicitly with our format variables.

The following text contains examples that can be evaluated. To make this process easier, we use a macro which is defined as part of ACL2 just for this documentation (DOCUMENTATION^). The macro is named fmx and it takes up to eleven arguments, the first of which is a format string, str, and the others of which are taken as the values of format variables. The variables used are #\0 through #\9. The macro constructs an appropriate alist, a, and then evaluates (fmt str a

*standard-co* state nil).

Thus,

     (fmx "Here is v0, ~x0, and here is v1, ~x1."
          (cons 'value 0)
          (cons 'value 1))

is just an abbreviation for

     (fmt "Here is v0, ~x0, and here is v1, ~x1."
          (list (cons #\0 (cons 'value 0))
                (cons #\1 (cons 'value 1)))

          *standard-co*
          state
          nil)

which returns (mv 53 state) after printing the line

        Here is v0, (VALUE . 0), and here is v1, (VALUE . 1).

We now devote special attention to three of the tilde-directives whose use is non-obvious. The Case Statement ~#x is essentially a “case statement” in the language of fmt. The proper form of the statement is

     ~#x~[case-0~/case-1~/ ... ~/case-k~],

where each of the case-i is a format string. In the most common use, the variable x has an integer value, vx, between 0 and k, inclusive. The effect of formatting the directive is to format case-vx. For example

     (fmx "Go ~#0~[North~/East~/South~/West~].~%" 1)

will print “Go East.” followed by a newline and will return (mv 0 state), while if you change the 1 above to 3 (the maximum legal value), it will print “Go West.” In order to make it easier to print such phrases as “there are seven cases” requiring agreement between subject and verb based on the number of elements of a list, the case statement allows its variable to take a list as its value and selects case-0 if the list has length 1 and case-1 otherwise.

     (let ((cases '(a b c)))
       (fmx "There ~#0~[is ~n1 case~/are ~n1 cases~]."
            cases
            (length cases)))

will print “There are three cases.” but if you change the '(a b c) above simply to '(a) it will print “There is one case.” and if you change it to nil it will print “There are zero cases.”

Indirection

Roughly speaking, ~@ will act as though the value of its argument is a format string and splice it into the current string at the current position. It is often used when the phrase to be printed must be computed. For example,

     (let ((ev 'DEFUN))
      (fmx "~x0 is an event~@1."
           'foo
           (if (member-eq ev '(defun defstub encapsulate))
               " that may introduce a function symbol"
               "")))

will print “foo is an event that may introduce a function symbol,” but if the value of ev is changed from 'defun (DEFUN^) to 'defthm (DEFTHM^), it prints “foo is an event.” The ~@ directive “splices” in the computed phrase (which might be empty). Of course, this particular example could be done with the case statement

     ~#1~[~/ that may introduce a function symbol~]

where the value of #\1 is appropriately computed to be 0 or 1.

If the argument to ~@ is a pair, it is taken to be a format string cons (CONS^)ed onto an alist, i.e., ("str" . a), and the alist, a, is used to extend the current one before "str" is recursively processed. This feature of fmt can be used to pass around “phrases” that contain computed contextual information in a. The most typical use is as “error messages.” For example, suppose you are writing a function which does not have access to state (STATE^) and so cannot print an error message. It may nevertheless be necessary for it to signal an error to its caller, say by returning two results, the first of which is interpreted as an error message if non-nil. Our convention is to use a ~@ pair to represent such messages. For example, the error value might be produced by the code:

     (cons
       "Error:  The instruction ~x0 is illegal when the stack is ~x1.~%"
       (list (cons #\0 (current-instruction st))
             (cons #\1 (i-stack st))))

If the current-instruction and i-stack (whatever they are) are '(popi 3) and '(a b) when

the cons (CONS^) above is evaluated, then it produces

     '("Error:  The instruction ~x0 is illegal when the stack is ~x1.~%"
       (#\0 POPI 3)
       (#\1 A B))

and if this pair is made the value of the fmt variable 0, then ~@0 will print

        Error:  The instruction (POPI 3) is illegal when the stack is (A B).

For example, evaluate

     (let
      ((pair
       '("Error:  The instruction ~x0 is illegal when the stack is ~x1.~%"
         (#\0 POPI 3)
         (#\1 A B))))
      (fmx "~@0" pair)).

Thus, even though the function that produced the “error” could not print it, it could specify exactly what error message and data are to be printed.

This example raises another issue. Sometimes it is desirable to break lines in your format strings so as to make your source code more attractive. That is the purpose of the tilde-newline directive. The following code produces exactly the same output as described above.

     (let ((pair '("Error:  The instruction ~x0 ~
                   is illegal when the stack is ~
                   ~x1.~%"
                   (#\0 POPI 3)
                   (#\1 A B))))
      (fmx "~@0" pair)).

Finally, observe that when ~@0 extends the current alist, alist, with the one, a, in its argument, the bindings from a are added to the front of alist, overriding the current values of any shared variables. This insures that the variable values seen by the recursively processed string, "str", are those from a, but if "str" uses variables not bound in a, their values are as specified in the original alist. Intuitively, variables bound in a are local to the processing of ("str" . a) but "str" may use “global variables.” The example above illustrates this because when the ~@0 is processed, #\0 is bound to the error message pair. But when the ~x0 in the error string is processed, #\0 is bound to the illegal instruction.

Iteration

The ~* directive is used to process each element of a list. For example,

     (let ((lst '(a b c d e f g h))) ; a true-list whose elements we exhibit
      (fmx "~*0"
           `("Whoa!"          ; what to print if there's nothing to print
             "~x*!"           ; how to print the last element
             "~x* and "       ; how to print the 2nd to last element
             "~x*, "          ; how to print all other elements
             ,lst)))          ; the list of elements to print

will print “A, B, C, D, E, F, G and H!”. Try this example with other true list values of lst, such as '(a b), '(a), and nil. The tilde-directives ~&0 and ~v0, which take a true list argument and display its elements separated by commas and a final “and” or “or,” are implemented in terms of the more general ~*.

The ~* directive allows the 5-tuple to specify in its final cdr (CDR^) an alist with which to extend the current one before processing the individual elements.

We often use ~* to print a series of phrases, separated by suitable punctuation, whitespace and noise words. In such use, the ~* handles the separation of the phrases and each phrase is generally printed by ~@.

Here is a complex example. In the let* (LET*^), below, we bind phrases to a list of ~@ pairs and then we create a ~* 5-tuple to print out the conjunction of the phrases with a parenthetical “finally!” if the series is longer than 3.

     (let* ((phrases
             (list (list "simplifying with the replacement rules ~&0"
                         (cons #\0 '(rewrite-rule1
                                     rewrite-rule2
                                     rewrite-rule3)))
                   (list "destructor elimination using ~x0"
                         (cons #\0 'elim-rule))
                   (list "generalizing the terms ~&0"
                         (cons #\0 '((rev x) (app u v))))
                   (list "inducting on ~x0"
                         (cons #\0 'I))))

    (5-tuple
     (list
      "magic"                            ; no phrases
      "~@*"                              ; last phrase
      "~@*, and~#f~[~/ (finally!)~] "    ; second to last phrase
      "~@*, "                            ; other phrases
      phrases                            ; the phrases themselves
      (cons #\f
            (if (>(length phrases) 3) 1 0))))) ;print ``finally''?
(fmx "We did it by ~*0." 5-tuple))

This let* (LET*^) prints

We did it by simplifying with the replacement rules REWRITE-RULE1,
REWRITE-RULE2 and REWRITE-RULE3, destructor elimination using ELIM-
RULE, generalizing the terms (REV X) and (APP U V), and (finally!)
inducting on I.

You might wish to try evaluating the let* (LET*^) after removing elements of phrases.

Most of the output produced by ACL2 is produced via fmt statements. Thus, inspection of the source code will yield many examples. A complicated example is the code that explains the simplifier’s work. See :pc (PC^) simplify-clause-msg1. An ad hoc example is provided by the function fmt-doc-example, which takes two arguments: an arbitrary true list and state (STATE^). To see

how fmt-doc-example works, :pe (PE^) fmt-doc-example.
(fmt-doc-example '(a b c d e f g h i j k l m n o p) state)

will produce the output

Here is a true list:  (A B C D E F G H I J K L M N O P).  It has 16
elements, the third of which is C.
We could print each element in square brackets:
([A], [B], [C], [D], [E], [F], [G], [H], [I], [J], [K], [L], [M], [N],
[almost there: O], [the end: P]).  And if we wished to itemize them
into column 15 we could do it like this
0123456789012345
    0 (zeroth) A
    1 (first)  B
    2 (second) C
    3 (third)  D
    4 (fourth) E
    5 (fifth)  F

       6 (sixth)  G
       7 (seventh)
                  H
       8 (eighth) I
       9 (ninth)  J
      10 (tenth)  K
      11 (eleventh)
                  L
      12 (twelfth)
                  M
      13 (thirteenth)
                  N
      14 (14th)   O
      15 (15th)   P
   End of example.

and return (mv 15 state).

Finally, we should remind the reader that fmt and its subfunctions, most importantly fmt0, are written entirely in ACL2. We make this comment for two reasons. First, it illustrates the fact that quite low level code can be efficiently written in the language. Second, it means that as a last resort for documentation purposes you can read the source code without changing languages.

10.117 FMT1

FMT1  :(str alist col co-channel state evisc) => (mv col state)

See Section 10.116 [FMT], page 478 for further explanation.

The tilde-directives are
~xx  pretty print vx (maybe after printing a newline)
~yx  pretty print vx starting in current column; end with newline
~Xxy like ~xx but use vy as the evisceration tuple
~Yxy like ~yx but use vy as the evisceration tuple
~px  pretty print term (maybe with infix) vx
     (maybe after printing a newline)
~qx  pretty print term (maybe with infix) vx
     starting in current column; end with newline
~Pxy like ~px but use vy as the evisceration tuple
~Qxy like ~qx but use vy as the evisceration tuple
~@x  if vx is a string, "str",  recursively format "str"
     if vx is ("str" . a), recursively format "str" under a+
~#x~[...~/...~/ ... ~/...~] cases on vx

^^...   ^if 0<=vx<=k, choose vxth alternative
0    1     ...   k  if vx is a list of length 1, case 0; else 1
~*x  iterator: vx must be of the form
("str0" "str1" "str2" "str3" lst . a);
if lst is initially empty, format "str0" under a+; otherwise,
bind #\* successively to the elements of lst and then
recursively format "stri" under a+, where i=1 if there is one
element left to process, i=2 if there are two left, and i=3
otherwise.
~&x  print elements of vx with ~x, separated by commas and a
final ``and''
~vx  print elements of vx with ~x, separated by commas and a
final ``or''
~nx  if vx is a small positive integer, print it as a word, e.g.,
seven;
if vx is a singleton containing a small positive integer, print
  the corresponding ordinal as a word, e.g., seventh
~Nx  like ~nx but the word is capitalized, e.g., Seven or Seventh
~tx  tab out to column vx; newline first if at or past column vx
~cx  vx is (n . w), print integer n right justified in field of
width w
~fx  print object vx flat over as many lines as necessary
~Fx  same as ~f, except that subsequent lines are indented to
start one character to the right of the first character printed
~sx  if vx is a symbol, print vx, breaking on hyphens; if vx is a
string, print the characters in it, breaking on hyphens
~    tilde space: print a space
~_x  print vx spaces
~
tilde newline: skip following whitespace
~%   output a newline
~|   output a newline unless already on left margin
~~   print a tilde
~-   if close to rightmargin, output a hyphen and newline; else
skip this char

10.118 FOURTH

FOURTH fourth member of the list

See any Common Lisp documentation for details.

10.119 IDENTITY

IDENTITY the identity function (Identity x) equals x; what else can we say? Identity is a Common Lisp function. See any Common Lisp documentation for more information.

10.120 IF

IF if-then-else function (if x y z) is equal to y if x is any value other than nil, and is equal to z if x is nil. Only one of y, z is evaluated when (if x y z) is evaluated. If has a guard (GUARD^) of t. If is part of Common Lisp. See any Common Lisp documentation for more information.

10.121 IFF

IFF logical “if and only if” Iff is the ACL2 biconditional, “if and only if”. (iff P Q) means that either P and Q are both false (i.e., nil) or both true (i.e., not nil).

10.122 IFIX

IFIX coerce to an integer Ifix simply returns any integer argument unchanged, returning 0 on a non-integer argument. Also see Section 10.173 [NFIX], page 513, see Section 10.209 [RFIX], page 528, and see Section 10.112 [FIX], page 475 for analogous functions that coerce to a natural number, a rational number, and a number, respectively. Ifix has a guard (GUARD^) of t.

10.123 ILLEGAL

ILLEGAL cause a hard error (illegal ctx str alist) causes evaluation to halt with a short message using the “context” ctx. An error message is printed using the string str and alist alist that are of the same kind as expected by fmt (FMT^). See Section 10.116 [FMT], page 478.

10.124 IMAGPART

IMAGPART imaginary part of a complex number Basic axiom:

     (equal (imagpart x)
            (if (acl2-numberp x)
                (imagpart x)
              0))

Guard (GUARD^) for (imagpart x):

     (acl2-numberp x)

10.125 IMPLIES

IMPLIES logical implication Implies is the ACL2 implication function. (implies P Q) means that either P is false (i.e., nil) or Q is true (i.e., not nil).

10.126 IMPROPER-CONSP

IMPROPER-CONSP recognizer for improper (non-null-terminated) non-empty lists Improper-consp is the function that checks whether its argument is a non-empty list that ends in other than nil. See Section 10.194 [PROPER-CONSP], page 520 and also see Section 10.250 [TRUE-LISTP], page 542.

10.127 INT=

INT= test equality of two integers

(int= x y) is logically equivalent to (equal x y).

Unlike equal (EQUAL^), int= requires its arguments to be numbers (or else causes a guard (GUARD^) violation; see Section 8.41 [GUARD], page 305). Generally, int= is executed more efficiently than equal (EQUAL^) or = (=^) on integers.

10.128 INTEGER-LENGTH

INTEGER-LENGTH number of bits in two’s complement integer representation

For non-negative integers, (integer-length i) is the minimum number of bits needed to represent the integer. Any integer can be represented as a signed two’s complement field with a minimum of

(+ (integer-length i) 1) bits.

The guard (GUARD^) for integer-length requires its argument to be an integer. Integerlength is defined in Common Lisp. See any Common Lisp documentation for more information.

10.129 INTEGER-LISTP

INTEGER-LISTP recognizer for a true list of integers

The predicate integer-listp tests whether its argument is a true list of integers.

10.130 INTEGERP

INTEGERP recognizer for whole numbers

(integerp x) is true if and only if x is an integer.

10.131 INTERN

INTERN create a new symbol in a given package

(intern symbol-name symbol-package-name) returns a symbol with the given symbol-name

(SYMBOL-NAME^) and the given symbol-package-name (SYMBOL-PACKAGE-NAME^). We restrict Common Lisp’s intern so that the second argument is either the symbol *main-lisp-package-name*, the value of that constant, or is one of "ACL2", "ACL2-INPUT-CHANNEL", "ACL2-OUTPUT-CHANNEL", or "KEYWORD".

In ACL2 intern is actually implemented as a macro that expands to a call of a similar function whose second argument is a symbol. Invoke :pe intern to see the definition, or see Section 10.132 [INTERN-IN-PACKAGE-OF-SYMBOL], page 491.

To see why is intern so restricted consider (intern "X" "P"). In particular, is it a symbol and if so, what is its symbol-package-name (SYMBOL-PACKAGE-NAME^)? One is tempted to say “yes, it is a symbol in the package "P".” But if package "P" has not yet been defined, that would be premature because the imports to the package are unknown. For example, if "P" were introduced with

     (defpkg "P" '(LISP::X))
then in Common Lisp (symbol-package-name (intern "X" "P")) returns "LISP".

The obvious restriction on intern is that its second argument be the name of a package known to ACL2. We cannot express such a restriction (except, for example, by limiting it to those packages known at some fixed time, as we do). Instead, we provide intern-in-package-of-symbol (INTERN-IN-PACKAGE-OF-SYMBOL^) which requires a “witness symbol” for the package instead of the package. The witness symbol is any symbol (expressible in ACL2) and uniquely specifies a package necessarily known to ACL2.

10.132 INTERN-IN-PACKAGE-OF-SYMBOL

INTERN-IN-PACKAGE-OF-SYMBOL create a symbol with a given name

Basic axiom:

     (equal (intern-in-package-of-symbol x y)
            (if (and (stringp x)
                     (symbolp y))
                (intern-in-package-of-symbol x y)
              nil))
Guard (GUARD^) for (intern-in-package-of-symbol x y):
     (and (stringp x) (symbolp y))
Intuitively, (intern-in-package-of-symbol x y) creates a symbol with symbol-name (SYMBOL-

NAME^) x intern (INTERN^)ed in the package containing y. More precisely, suppose x is a string, y is a symbol with symbol-package-name (SYMBOL-PACKAGE-NAME^) pkg and that the defpkg (DEFPKG^) event creating pkg had the list of symbols imports as the value of its second

argument. Then (intern-in-package-of-symbol x y) returns a symbol, ans, the symbol-name

(SYMBOL-NAME^) of ans is x, and the symbol-package-name (SYMBOL-PACKAGE-NAME^) of ans is pkg, unless x is the symbol-name (SYMBOL-NAME^) of some member of imports with symbol-package-name (SYMBOL-PACKAGE-NAME^) ipkg, in which case the symbol-package-name (SYMBOL-PACKAGE-NAME^) of ans is ipkg. Because defpkg (DEFPKG^) requires that there be no duplications among the symbol-name (SYMBOL-NAME^)s of the imports, intern-

in-package-of-symbol is uniquely defined.

For example, suppose "MY-PKG" was created by

     (defpkg "MY-PKG" '(ACL2::ABC LISP::CAR)).
Let w be 'my-pkg::witness. Observe that
     (symbolp w) is t                     ; w is a symbol
     (symbol-name w) is "WITNESS"         ; w's name is "WITNESS"
     (symbol-package-name w) is "MY-PKG"  ; w is in the package "MY-PKG"

The construction of w illustrates one way to obtain a symbol in a given package: write it down as a constant using the double-colon notation.

But another way to obtain a symbol in a given package is to create it with intern-in-package-

of-symbol.
     (intern-in-package-of-symbol "XYZ" w) is MY-PKG::XYZ
     (intern-in-package-of-symbol "ABC" w) is ACL2::ABC
     (intern-in-package-of-symbol "CAR" w) is LISP::CAR
     (intern-in-package-of-symbol "car" w) is MY-PKG::|car|

10.133 INTERSECTP-EQ

INTERSECTP-EQ test whether two lists of symbols intersect See Section 10.134 [INTERSECTP-EQUAL], page 493, which is logically the same function. (Intersectp-eq x y) has a guard (GUARD^) that x and y are lists of symbols.

10.134 INTERSECTP-EQUAL

INTERSECTP-EQUAL test whether two lists intersect (Intersectp-equal x y) returns t if x and y have a member in common, else it returns nil. Also see Section 10.133 [INTERSECTP-EQ], page 493, which is logically the same but can be more efficient since it uses eq (EQ^) instead of equal (EQUAL^) to look for members common to the two given lists. (Intersectp-equal x y) has a guard (GUARD^) that x and y are true lists.

10.135 IO

IO input/output facilities in ACL2

     Example:
     (mv-let

       (channel state)
       (open-input-channel "foo.lisp" :object state)
       (mv-let (eofp obj state)
               (read-object channel state)
               (.
                 .
                  (let ((state (close-input-channel channel state)))
                        (mv final-ans state))..)))

Also see Section 1.5.6.1 [FILE-READING-EXAMPLE], page 59.

ACL2 supports input and output facilities equivalent to a subset of those found in Common Lisp. ACL2 does not support random access files or bidirectional streams. In Common Lisp, input and output are to or from objects of type stream. In ACL2, input and output are to or from objects called “channels,” which are actually symbols. Although a channel is a symbol, one may think of it intuitively as corresponding to a Common Lisp stream. Channels are in one of two ACL2 packages,

"ACL2-INPUT-CHANNEL" and "ACL2-OUTPUT-CHANNEL". When one “opens” a file one gets back a

channel whose symbol-name (SYMBOL-NAME^) is the file name passed to “open,” postfixed with -n, where n is a counter that is incremented every time an open or close occurs.

There are three channels which are open from the beginning and which cannot be closed:

       acl2-input-channel::standard-character-input-0
       acl2-input-channel::standard-object-input-0
       acl2-input-channel::standard-character-output-0

All three of these are really Common Lisp’s *standard-input* or *standard-output*, appropriately.

For convenience, three global variables are bound to these rather tedious channel names:

       *standard-ci*
       *standard-oi*
       *standard-co*

Common Lisp permits one to open a stream for several different kinds of io, e.g. character or byte. ACL2 permits an additional type called “object”. In ACL2 an “io-type” is a keyword, either :character, :byte, or :object. When one opens a file, one specifies a type, which determines the kind of io operations that can be done on the channel returned. The types :character and :byte are familiar. Type :object is an abstraction not found in Common Lisp. An :object file is a file of Lisp objects. One uses read-object to read from :object files and print-object$ to print to :object files. (The reading and printing are really done with the Common Lisp read and print functions.)

File-names are strings. ACL2 does not support the Common Lisp type pathname (PATHNAME^).

Here are the signature (SIGNATURE^)s of the ACL2 io functions. See Section 8.80 [SIGNATURE], page 364.

Input Functions:
(open-input-channel (file-name io-type state) (mv channel state))
(open-input-channel-p (channel io-type state) boolean)
(close-input-channel (channel state) state)
(read-char$ (channel state) (mv char/nil state))
(peek-char$ (channel state) boolean)
(read-byte$ (channel state) (mv byte/nil state))
(read-object (channel state) (mv eof-read-flg obj-read state))
Output Functions:
(open-output-channel (file-name io-type state) (mv channel state))
(open-output-channel-p (channel io-type state) boolean)
(close-output-channel (channel state) state)
(princ$ (obj channel state) state)
(write-byte$ (byte channel state) state)
(print-object$ (obj channel state) state)
(fms (string alist channel state evisc-tuple) state)
(fmt (string alist channel state evisc-tuple) (mv col state))
(fmt1 (string alist col channel state evisc-tuple) (mv col state))

The “formatting” functions are particularly useful; see Section 10.116 [FMT], page 478.

When one enters ACL2 with (lp), input and output are taken from *standard-oi* (*STANDARD-OI*^) to *standard-co* (*STANDARD-CO*^). Because these are synonyms for *standardinput* and *standard-output*, one can drive ACL2 io off of arbitrary Common Lisp streams,

bound to *standard-input* and *standard-output* before entry to ACL2.

10.136 IRRELEVANT-FORMALS

IRRELEVANT-FORMALS formals that are used but only insignificantly Let fn be a function of n arguments. Let x be the ith formal of fn. We say x is “irrelevant in fn” if x is not involved in either the guard (GUARD^) or the measure for fn, x is used in the body, but the value of (fn a1...ai...an) is independent of ai.

The easiest way to define a function with an irrelevant formal is simply not to use the formal in the guard (GUARD^), measure, or body of the function. Such formals are said to be “ignored” by Common Lisp and a special declaration is provided to allow ignored formals. ACL2 makes a distinction between ignored and irrelevant formals.

An example of an irrelevant formal is x in the definition of fact below.

     (defun fact (i x)
       (declare (xargs :guard (and (integerp i) (<= 0 i))))
       (if (zerop i) 0 (* i (fact (1- i) (cons i x))))).

Observe that x is only used in recursive calls of fact; it never “gets out” into the result. ACL2 can detect some irrelevant formals by a closure analysis on how the formals are used. For example, if the ith formal is only used in the ith argument position of recursive calls, then it is irrelevant. This is how x is used above.

It is possible for a formal to appear only in recursive calls but still be relevant. For example, x is not irrelevant below, even though it only appears in the recursive call.

     (defun fn (i x) (if (zerop i) 0 (fn x (1- i))))

The key observation above is that while x only appears in a recursive call, it appears in an argument position, namely i’s, that is relevant. (The function above can be admitted with a :guard (GUARD^) requiring both arguments to be nonnegative integers and the :measure (+ i x).)

Establishing that a formal is irrelevant, in the sense defined above, can be an arbitrarily hard problem because it requires theorem proving. For example, is x irrelevant below?

     (defun test (i j k x) (if (cond i j k) x 0))

Note that the value of (test i j k x) is independent of x — thus making x irrelevant — precisely if (cond i j k) is a theorem. ACL2’s syntactic analysis of a definition does not guarantee to notice all irrelevant formals.

We regard the presence of irrelevant formals as an indication that something is wrong with the definition. We cause an error on such definitions and suggest that you recode the definition so as to eliminate the irrelevant formals. If you must have an irrelevant formal, one way to “trick” ACL2 into accepting the definition, without slowing down the execution of your function, is to use the formal in an irrelevant way in the guard (GUARD^). For example, to admit fact, above, with its irrelevant x one might use

     (defun fact (i x)
       (declare (xargs :guard (and (integerp i) (<= 0 i) (equal x x))))
       (if (zerop i) 0 (* i (fact (1- i) (cons i x)))))

For those who really want to turn off this feature, we have provided a way to use the acl2defaults-table (ACL2-DEFAULTS-TABLE^) for this purpose; see Section 6.31 [SET-IRRELEVANT-FORMALS-OK], page 200.

If you need to introduce a function with an irrelevant formal, please explain to the authors why this should be allowed.

10.137 KEYWORD-VALUE-LISTP

KEYWORD-VALUE-LISTP recognizer for true lists whose even-position elements are keywords

(keyword-value-listp l) is true if and only if l is a list of even length of the form (k1 a1 k2 a2 ... kn an), where each ki is a keyword.

10.138 KEYWORDP

KEYWORDP recognizer for keywords

(Keywordp x) is true if and only if x is a keyword, i.e., a symbol in the "KEYWORD" package. Such symbols are typically printed using a colon (:) followed by the symbol-name (SYMBOL-NAME^) of the symbol.

Keywordp has a guard (GUARD^) of t.

Keywordp is a Common Lisp function. See any Common Lisp documentation for more information.

10.139 LAST

LAST the last cons (CONS^) (not element) of a list (Last l) is the last cons (CONS^) of a list. Here are examples.

     ACL2 !>(last '(a b . c))
     (B . C)
     ACL2 !>(last '(a b c))
     (C)

(Last l) has a guard (GUARD^) of (listp l); thus, l need not be a true-listp (TRUE-LISTP^). Last is a Common Lisp function. See any Common Lisp documentation for more information. Unlike Common Lisp, we do not allow an optional second argument for last.

10.140 LENGTH

LENGTH length of a string or proper list Length is the function for determining the length of a sequence. In ACL2, the argument is required to be either a true-listp (TRUE-LISTP^) or a string. Length is a Common Lisp function. See any Common Lisp documentation for more information.

10.141 LET

LET binding of lexically scoped (local) variables

     Example LET Form:
     (let ((x (* x x))
           (y (* 2 x)))
      (list x y))

If the form above is executed in an environment in which x has the value -2, then the result is '(4 Let expressions bind variables so that their “local” values, the values they have when the “body” of the let is evaluated, are possibly different than their “global” values, the values they have in the context in which the let expression appears. In the let expression above, the local variables bound by the let are x and y. They are locally bound to the values delivered by the two forms (* x x) and (* 2 x), respectively, that appear in the “bindings” of the let. The body of the let is

(list x y).

Suppose that the let expression above occurs in a context in which x has the value -2. (The global value of y is irrelevant to this example.) For example, one might imagine that the let form above occurs as the body of some function, fn, with the formal parameter x and we are evaluating (fn

-2).

To evaluate the let above in a context in which x is -2, we first evaluate the two forms specifying the local values of the variables. Thus, (* x x) is evaluated and produces 4 (because x is -2) and (* 2 x) is evaluated and produces -4 (because x is -2). Then x and y are bound to these values and the body of the let is evaluated. Thus, when the body, (list x y) is evaluated, x is 4 and y is -4. Thus, the body produces '(4 -4).

Note that the binding of y, which is written after the binding of x and which mentions x, nevertheless uses the global value of x, not the new local value. That is, the local variables of the let are bound “in parallel” rather than “sequentially.” In contrast, if the

     Example LET* Form:
     (let* ((x (* x x))
            (y (* 2 x)))
      (list x y))

is evaluated when the global value of x is -2, then the result is '(4 8), because the local value of y is computed after x has been bound to 4. Let* (LET*^) binds its local variables “sequentially.”

     General LET Forms:
     (let ((var1 term1) ... (varn termn)) body)
     and
     (let ((var1 term1) ... (varn termn))
      (declare ...) ... (declare ...)
      body)

where the vari are distinct variables, the termi are terms involving only variables bound in the environment containing the let, and body is a term involving only the vari plus the variables bound in the environment containing the let. Each vari must be used in body or else declare (DECLARE^)d ignored.

A let form is evaluated by first evaluating each of the termi, obtaining for each a vali. Then, each vari is bound to the corresponding vali and body is evaluated.

Actually, let forms are just abbreviations for certain uses of lambda notation. In particular

     (let ((var1 term1) ... (varn termn)) (declare ...) body)

is equivalent to

     ((lambda (var1 ... varn)
        (declare ...)
        body)
      term1 ... termn).

Let* (LET*^) forms are used when it is desired to bind the vari sequentially, i.e., when the local values of preceding varj are to be used in the computation of the local value for vari.

     General LET* Forms:
     (let* ((var1 term1) ... (varn termn)) body)

where the vari are distinct variables, the termi are terms involving only variables bound in the environment containing the let* (LET*^) and those varj such that j<i, and body is a term involving only the vari plus the variables bound in the environment containing the let* (LET*^). Each vari must be used in either some subsequent termj or in body. Note that let* (LET*^) does not permit the inclusion of declare (DECLARE^) forms.

The above let* (LET*^) is equivalent to

     (let ((var1 term1))
      ...
      (let ((varn termn)) body)...)

Thus, the termi are evaluated successively and after each evaluation the corresponding vali is bound to the value of termi.

Each (vari termi) pair in a let or let* (LET*^) form is called a “binding” of vari and the vari are called the “local variables” of the let or let* (LET*^). The common use of let and let* (LET*^) is to save the values of certain expressions (the termi) so that they may be referenced several times in the body without suggesting their recomputation.

Let is part of Common Lisp. See any Common Lisp documentation for more information.

10.142 LET*

LET* binding of lexically scoped (local) variables

     Example LET* Form:
     (let* ((x (* x x))
            (y (* 2 x)))
      (list x y))

If the form above is executed in an environment in which x has the value -2, then the result is '(4 8). See Section 10.141 [LET], page 498 for a discussion of both let (LET^) and let*, or read on for a briefer discussion.

The difference between let (LET^) and let* is that the former binds its local variables in parallel while the latter binds them sequentially. Thus, in let*, the term evaluated to produce the local value of one of the locally bound variables is permitted to reference any locally bound variable occurring earlier in the binding list and the value so obtained is the newly computed local value of that variable. See Section 10.141 [LET], page 498.

Let* is a Common Lisp macro. See any Common Lisp documentation for more information.

10.143 LIST

LIST build a list

List is the macro for building a list of objects. For example, (list 5 6 7) returns a list of length 3 whose elements are 5, 6, and 7 respectively. Also see Section 10.144 [LIST*], page 501.

List is a Common Lisp function. See any Common Lisp documentation for more information.

10.144 LIST*

LIST* build a list List* is the Common Lisp macro for building a list of objects from given elements and a tail. For example, (list* 5 6 '(7 8 9)) equals the list '(5 6 7 8 9). Also see Section 10.143 [LIST], page 501. List* is a Common Lisp function. See any Common Lisp documentation for more information.

10.145 LISTP

LISTP recognizer for (not necessarily proper) lists (listp x) is true when x is either a cons (CONS^) pair or is nil. Listp has no guard (GUARD^), i.e., its guard (GUARD^) is t. Listp is a Common Lisp function. See any Common Lisp documentation for more information.

10.146 LOGAND

LOGAND bitwise logical ‘and’ of two integers When integers are viewed in their two’s complement representation, logand returns their bitwise logical ‘and’. The guard (GUARD^) for logand requires its arguments to be integers. Logand is defined in Common Lisp. See any Common Lisp documentation for more information.

10.147 LOGANDC1

LOGANDC1 bitwise logical ‘and’ of two ints, complementing the first When integers are viewed in their two’s complement representation, logandc1 returns the bitwise logical ‘and’ of the second with the bitwise logical ‘not’ of the first. The guard (GUARD^) for logandc1 requires its arguments to be integers. Logandc1 is defined in Common Lisp. See any Common Lisp documentation for more information.

10.148 LOGANDC2

LOGANDC2 bitwise logical ‘and’ of two ints, complementing the second When integers are viewed in their two’s complement representation, logandc2 returns the bitwise logical ‘and’ of the first with the bitwise logical ‘not’ of the second. The guard (GUARD^) for logandc2 requires its arguments to be integers. Logandc2 is defined in Common Lisp. See any Common Lisp documentation for more information.

10.149 LOGBITP

LOGBITP the ith bit of an integer For a nonnegative integer i and an integer j, (logbitp i j) is the value of the ith bit in the two’s complement representation of j. (Logbitp i j) has a guard (GUARD^) that i is a nonnegative integer and j is an integer. Logbitp is a Common Lisp function. See any Common Lisp documentation for more information.

10.150 LOGCOUNT

LOGCOUNT number of “on” bits in a two’s complement number (Logcount x) is the number of “on” bits in the two’s complement representation of x.

(Logcount x) has a guard (GUARD^) of (integerp x).

Logcount is a Common Lisp function. See any Common Lisp documentation for more information.

10.151 LOGEQV

LOGEQV bitwise logical equivalence of two integers When integers are viewed in their two’s complement representation, logeqv returns the bitwise logical equivalence of the first with the second.

The guard (GUARD^) for logeqv requires its arguments to be integers. Logeqv is defined in Common Lisp. See any Common Lisp documentation for more information.

10.152 LOGIOR

LOGIOR bitwise logical inclusive or of two integers

When integers are viewed in their two’s complement representation, logior returns their bitwise logical inclusive or.

The guard (GUARD^) for logior requires its arguments to be integers. Logior is defined in Common Lisp. See any Common Lisp documentation for more information.

10.153 LOGNAND

LOGNAND bitwise logical ‘nand’ of two integers

When integers are viewed in their two’s complement representation, lognand returns their bitwise logical ‘nand’.

The guard (GUARD^) for lognand requires its arguments to be integers. Lognand is defined in Common Lisp. See any Common Lisp documentation for more information.

10.154 LOGNOR

LOGNOR bitwise logical ‘nor’ of two integers

When integers are viewed in their two’s complement representation, lognor returns the bitwise logical ‘nor’ of the first with the second.

The guard (GUARD^) for lognor requires its arguments to be integers. Lognor is defined in Common Lisp. See any Common Lisp documentation for more information.

10.155 LOGNOT

LOGNOT bitwise not of a two’s complement number (lognot i) is the two’s complement bitwise `not' of the integer i. Lognot is actually defined by coercing its argument to an integer (see Section 10.122 [IFIX], page 488), negating the result, and then subtracting 1. The guard (GUARD^) for lognot requires its argument to be an integer. Lognot is a Common Lisp function. See any Common Lisp documentation for more information.

10.156 LOGORC1

LOGORC1 bitwise logical inclusive or of two ints, complementing the first When integers are viewed in their two’s complement representation, logorc1 returns the bitwise logical inclusive or of the second with the bitwise logical ‘not’ of the first. The guard (GUARD^) for logorc1 requires its arguments to be integers. Logorc1 is defined in Common Lisp. See any Common Lisp documentation for more information.

10.157 LOGORC2

LOGORC2 bitwise logical inclusive or of two ints, complementing the second When integers are viewed in their two’s complement representation, logorc2 returns the bitwise logical inclusive or of the first with the bitwise logical ‘not’ of the second. The guard (GUARD^) for logorc2 requires its arguments to be integers. Logorc2 is defined in Common Lisp. See any Common Lisp documentation for more information.

10.158 LOGTEST

LOGTEST test if two integers share a ‘1’ bit When integers x and y are viewed in their two’s complement representation, (logtest x y) is true if and only if there is some position for which both x and y have a ‘1’ bit in that position. The guard (GUARD^) for logtest requires its arguments to be integers. Logtest is defined in Common Lisp. See any Common Lisp documentation for more information.

10.159 LOGXOR

LOGXOR bitwise logical exclusive or of two integers When integers are viewed in their two’s complement representation, logxor returns the bitwise logical exclusive or of the first with the second. The guard (GUARD^) for logxor requires its arguments to be integers. Logxor is defined in Common Lisp. See any Common Lisp documentation for more information.

10.160 LOWER-CASE-P

LOWER-CASE-P recognizer for lower case characters (Lower-case-p x) is true if and only if x is a lower case character, i.e., a member of the list #A, #B, ..., #Z. The guard (GUARD^) for lower-case-p requires its argument to be a character. Lower-case-p is a Common Lisp function. See any Common Lisp documentation for more information.

10.161 MAKE-CHARACTER-LIST

MAKE-CHARACTER-LIST coerce (COERCE^) to a list of characters Non-characters in the given list are coerce (COERCE^)d to the character with code 0.

10.162 MAKE-LIST

MAKE-LIST make a list of a given size For a nonnegative integer size, (Make-list size) is a list of elements of length size, each of which is initialized to the :initial-element (which defaults to nil). Make-list is a macro in ACL2, defined in terms of a tail recursive function make-list-ac whose guard (GUARD^) requires size to be a nonnegative integer. Make-list is a Common Lisp function. See any Common Lisp documentation for more information.

10.163 MAX

MAX the larger of two rational numbers (Max x y) is the larger of the numbers x and y. The guard (GUARD^) for max requires its arguments to be rational numbers. Max is a Common Lisp function. See any Common Lisp documentation for more information.

10.164 MEMBER

MEMBER membership predicate, using eql (EQL^) as test (Member x l) equals the longest tail of l that begins with x, or else nil if no such tail exists. (Member x l) is provably the same in the ACL2 logic as (member-equal x l). It has a stronger guard (GUARD^) than member-equal (MEMBER-EQUAL^) because uses eql (EQL^) to test for whether x is equal to a given member of l. Its guard (GUARD^) requires that l is a true list, and moreover, either (eqlablep x) or all members of l are eqlablep (EQLABLEP^). See Section 10.166 [MEMBER-EQUAL], page 508 and see Section 10.165 [MEMBER-EQ], page 508.

Member is a Common Lisp function. See any Common Lisp documentation for more information. Since ACL2 functions cannot take keyword arguments (though macros can), the ACL2 functions member-equal (MEMBER-EQUAL^) and member-eq (MEMBER-EQ^) are defined to correspond to calls of the Common Lisp function member whose keyword argument :test is equal (EQUAL^) or eq (EQ^), respectively.

10.165 MEMBER-EQ

MEMBER-EQ membership predicate, using eq (EQ^) as test

(Member-eq x lst) equals the longest tail of lst that begins with x, or else nil if no such tail exists.

(Member-eq x lst) is provably the same in the ACL2 logic as (member x lst) and (memberequal x lst), but it has a stronger guard (GUARD^) because it uses eq (EQ^) for a more efficient test for whether x is equal to a given member of lst. Its guard (GUARD^) requires that lst is a true list, and moreover, either x is a symbol or lst is a list of symbols. See Section 10.166 [MEMBER-EQUAL], page 508 and see Section 10.164 [MEMBER], page 507.

10.166 MEMBER-EQUAL

MEMBER-EQUAL membership predicate

(Member-equal x lst) equals the longest tail of lst that begins with x, or else nil if no such tail exists.

(Member-equal x lst) has a guard (GUARD^) of (true-listp lst). Member-equal has the

same functionality as the Common Lisp function member (MEMBER^), except that it uses the equal (EQUAL^) function to test whether x is the same as each successive element of lst. See Section 10.164 [MEMBER], page 507 and see Section 10.165 [MEMBER-EQ], page 508.

10.167 MIN

MIN the smaller of two rational numbers

(Min x y) is the smaller of the numbers x and y.

The guard (GUARD^) for min requires its arguments to be rational numbers.

Min is a Common Lisp function. See any Common Lisp documentation for more information.

10.168 MINUSP

MINUSP test whether a rational number is negative

(Minusp x) is true if and only if x < 0.

The guard (GUARD^) of minusp requires its argument to be a rational number.

Minusp is a Common Lisp function. See any Common Lisp documentation for more information.

10.169 MOD

MOD remainder using floor (FLOOR^)

     ACL2 !>(mod 14 3)
     2
     ACL2 !>(mod -14 3)
     1
     ACL2 !>(mod 14 -3)
     -1
     ACL2 !>(mod -14 -3)
     -2
     ACL2 !>(mod -15 -3)
     0
     ACL2 !>

(Mod i j) is that number k that (* j (floor i j)) added to k equals i.

The guard (GUARD^) for (mod i j) requires that i and j are rational numbers and j is non-zero.

Mod is a Common Lisp function. See any Common Lisp documentation for more information.

10.170 MV

MV returning multiple values

Mv is the mechanism provided by ACL2 for returning two or more values. Logically, (mv x1 x2 ... xn) is the same as (list x1 x2 ... xn), a list of the indicated values. However, ACL2 avoids the cost of building this list structure, with the cost that mv may only be used in a certain style in definitions: if a function ever returns using mv (either directly, or by calling another function that returns multiple values), then this function must always return the same number of multiple values.

For more explanation of the multiple value mechanism, see Section 10.171 [MV-LET], page 510.

ACL2 does not support the Common Lisp construct values, whose logical meaning seems difficult to characterize. Mv is the ACL2 analogue of that construct.

10.171 MV-LET

MV-LET calling multi-valued ACL2 functions

     Example Form:
     (mv-let (x y z)              ; local variables
             (mv 1 2 3)           ; multi-valued expression
             (declare (ignore y)) ; optional declarations
             (cons x z))          ; body

The form above binds the three “local variables,” x, y, and z, to the three results returned by the multi-valued expression and then evaluates the body. The result is '(1 . 3). The second local, y, is declare (DECLARE^)d ignored. The multi-valued expression can be any ACL2 expression that returns k results, where k is the number of local variables listed. Often however it is simply the application of a k-valued function. Mv-let is the standard way to invoke a multi-valued function when the caller must manipulate the vector of results returned.

     General Form:
     (mv-let (var1 ... vark)
             term

             body)
     or
     (mv-let (var1 ... vark)
             term
             (declare ...) ... (declare ...)
             body)

where the vari are distinct variables, term is a term that returns k results and mentions only variables bound in the environment containing the mv-let expression, and body is a term mentioning only the vari and variables bound in the environment containing the mv-let. Each vari must occur in body unless it is declare (DECLARE^)d ignored in one of the optional declare (DECLARE^) forms, unless this requirement is turned off; see Section 6.28 [SET-IGNORE-OK], page 198. The value of the mv-let term is the result of evaluating body in an environment in which the vari are bound, in order, to the k results obtained by evaluating term in the environment containing the mv-let.

Here is an extended example that illustrates both the definition of a multi-valued function and the use of mv-let to call it. Consider a simple binary tree whose interior nodes are cons (CONS^)es and whose leaves are non-cons (CONS^)es. Suppose we often need to know the number, n, of interior nodes of such a tree; the list, syms, of symbols that occur as leaves; and the list, ints, of integers that occur as leaves. (Observe that there may be leaves that are neither symbols nor integers.) Using a multi-valued function we can collect all three results in one pass.

Here is the first of two definitions of the desired function. This definition is “primitive recursive” in that it has only one argument and that argument is reduced in size on every recursion.

     (defun count-and-collect (x)
     ; We return three results, (mv n syms ints) as described above.
       (cond ((atom x)
     ; X is a leaf.  Thus, there are 0 interior nodes, and depending on
     ; whether x is a symbol, an integer, or something else, we return
     ; the list containing x in as the appropriate result.
              (cond ((symbolp x) (mv 0 (list x) nil))
                    ((integerp x)(mv 0 nil      (list x)))
                    (t           (mv 0 nil      nil))))
             (t
     ; X is an interior node.  First we process the car, binding n1, syms1, and
     ; ints1 to the answers.

                (mv-let (n1 syms1 ints1)
                        (count-and-collect (car x))
     ; Next we process the cdr, binding n2, syms2, and ints2.
                        (mv-let (n2 syms2 ints2)
                                (count-and-collect (car x))
     ; Finally, we compute the answer for x from those obtained for its car
     ; and cdr, remembering to increment the node count by one for x itself.
                                (mv (1+ (+ n1 n2))
                                    (append syms1 syms2)
                                    (append ints1 ints2)))))))

This use of multiple values to “do several things at once” is very common in ACL2. However, the function above is inefficient because it append (APPEND^)s syms1 to syms2 and ints1 to ints2, copying the list structures of syms1 and ints1 in the process. By adding “accumulators” to the function, we can make the code more efficient.

     (defun count-and-collect1 (x n syms ints)
       (cond ((atom x)
              (cond ((symbolp x) (mv n (cons x syms) ints))
                    ((integerp x) (mv n syms (cons x ints)))
                    (t (mv n syms ints))))
             (t (mv-let (n2 syms2 ints2)
                        (count-and-collect1 (cdr x) (1+ n) syms ints)
                        (count-and-collect1 (car x) n2 syms2 ints2)))))

We claim that (count-and-collect x) returns the same triple of results as (count-and-collect1 x 0 nil nil). The reader is urged to study this claim until convinced that it is true and that the latter method of computing the results is more efficient. One might try proving the theorem

     (defthm count-and-collect-theorem
       (equal (count-and-collect1 x 0 nil nil) (count-and-collect x))).

Hint: the inductive proof requires attacking a more general theorem.

ACL2 does not support the Common Lisp construct multiple-value-bind, whose logical meaning seems difficult to characterize. Mv-let is the ACL2 analogue of that construct.

10.172 MV-NTH

MV-NTH the mv-nth element (zero-based) of a list (Mv-nth n l) is the nth element of l, zero-based. If n is greater than or equal to the length of l, then mv-nth returns nil. (Mv-nth n l) has a guard (GUARD^) that n is a non-negative integer and l is a true-listp (TRUE-LISTP^). Mv-nth is equivalent to the Common Lisp function nth (NTH^), but is used by ACL2 to access the nth value returned by a multiply valued expression. For an example of the use of mv-nth, try

     ACL2 !>:trans1 (mv-let (erp val state)
                            (read-object ch state)
                            (value (list erp val)))

10.173 NFIX

NFIX coerce to a natural number Nfix simply returns any natural number argument unchanged, returning 0 on an argument that is not a natural number. Also see Section 10.173 [NFIX], page 513, see Section 10.209 [RFIX], page 528, and see Section 10.112 [FIX], page 475 for analogous functions that coerce to an integer, a rational number, and a number, respectively. Nfix has a guard (GUARD^) of t.

10.174 NINTH

NINTH ninth member of the list See any Common Lisp documentation for details.

10.175 NO-DUPLICATESP

NO-DUPLICATESP check for duplicates in a list (using eql for equality) (no-duplicatesp l) is true if and only if no member of l occurs twice in l. (no-duplicatesp l) has a guard (GUARD^) of (eqlable-listp l). Membership is tested using member (MEMBER^), hence using eql (EQL^) as the test.

10.176 NO-DUPLICATESP-EQUAL

NO-DUPLICATESP-EQUAL check for duplicates in a list (using equal for equality) (no-duplicatesp-equal l) is true if and only if no member of l occurs twice in l.

(no-duplicatesp-equal l) has a guard (GUARD^) of (true-listp l). Membership is tested

using member-equal (MEMBER-EQUAL^), hence using equal (EQUAL^) as the test.

10.177 NONNEGATIVE-INTEGER-QUOTIENT

NONNEGATIVE-INTEGER-QUOTIENT natural number division function

     Example Forms:
     (nonnegative-integer-quotient 14 3) ; equals 4
     (nonnegative-integer-quotient 15 3) ; equals 5

(nonnegative-integer-quotient i j) returns the integer quotient of the integers i and (nonzero) j, i.e., the largest k such that (* j k) is less than or equal to i. Also see Section 10.114 [FLOOR], page 476, see Section 10.71 [CEILING], page 459 and see Section 10.251 [TRUNCATE], page 543, which are derived from this function and apply to rational numbers. The guard (GUARD^) of (nonnegative-integer-quotient i j) requires that i is a nonnegative integer and j is an integer.

10.178 NOT

NOT logical negation Iff (IFF^) is the ACL2 negation function. The negation of nil is t and the negation of anything else is nil. Not is a Common Lisp function. See any Common Lisp documentation for more information.

10.179 NTH

NTH the nth element (zero-based) of a list (Nth n l) is the nth element of l, zero-based. If n is greater than or equal to the length of l, then nth returns nil. (Nth n l) has a guard (GUARD^) that n is a non-negative integer and l is a true-listp (TRUE-LISTP^). Nth is a Common Lisp function. See any Common Lisp documentation for more information.

10.180 NTHCDR

NTHCDR final segment of a list (Nthcdr n l) removes the first n elements from the list l. The following is a theorem.

     (implies (and (integerp n)
                   (<= 0 n)
                   (true-listp l))
              (equal (length (nthcdr n l))
                     (if (<= n (length l))
                         (- (length l) n)
                       0)))

For related functions, see Section 10.245 [TAKE], page 541 and see Section 10.38 [BUTLAST], page 449. The guard (GUARD^) of (nthcdr n l) requires that n is a nonnegative integer and l is a true list. Nthcdr is a Common Lisp function. See any Common Lisp documentation for more information.

10.181 NULL

NULL recognizer for the empty list Null is the function that checks whether its argument is nil. For recursive definitions it is often preferable to test for the end of a list using endp (ENDP^) instead of null; see Section 10.99 [ENDP], page 471. Null is a Common Lisp function. See any Common Lisp documentation for more information.

10.182 NUMERATOR

NUMERATOR dividend of a ratio in lowest terms Basic axiom:

     (equal (numerator x)
            (if (rationalp x)
                (numerator x)
              0))

Guard (GUARD^) for (numerator x):

     (rationalp x)

10.183 ODDP

ODDP test whether an integer is odd (oddp x) is true if and only if x is odd, i.e., not even in the sense of evenp (EVENP^). The guard (GUARD^) for oddp requires its argument to be an integer. Oddp is a Common Lisp function. See any Common Lisp documentation for more information.

10.184 OR

OR conjunction Or is the macro for disjunctions. Or takes any number of arguments and returns the first that is non-nil, or nil if there is no non-nil element. Or is a Common Lisp macro. See any Common Lisp documentation for more information.

10.185 PAIRLIS

PAIRLIS see pairlis$ (PAIRLIS$^) The Common Lisp language allows its pairlis function to construct an alist in any order! So we have to define our own version: See Section 10.186 [PAIRLIS$], page 517.

10.186 PAIRLIS$

PAIRLIS$ zipper together two lists The Common Lisp language allows its pairlis (PAIRLIS^) function to construct an alist in any order! So we have to define our own version, pairlis$. It returns the list of pairs obtained by cons (CONS^)ing together successive respective members of the given lists. The guard (GUARD^) for pairlis$ requires that its arguments are true lists.

10.187 PLUSP

PLUSP test whether a rational number is positive

(Plusp x) is true if and only if x > 0.

The guard (GUARD^) of plusp requires its argument to be a rational number.

Plusp is a Common Lisp function. See any Common Lisp documentation for more information.

10.188 POSITION

POSITION position of an item in a string or a list, using eql (EQL^) as test

(Position item seq) is the least index (zero-based) of the element item in the string or list seq, if in fact item is an element of seq. Otherwise (position item seq) is nil.

(Position item lst) is provably the same in the ACL2 logic as (position-equal item lst).

It has a stronger guard (GUARD^) than position-equal (POSITION-EQUAL^) because uses eql (EQL^) to test equality of item with members of lst. Its guard (GUARD^) requires that lst is a true list, and moreover, either (eqlablep item) or all members of lst are eqlablep (EQLABLEP^). See Section 10.190 [POSITION-EQUAL], page 519 and see Section 10.189 [POSITION-EQ], page 518.

Position is a Common Lisp function. See any Common Lisp documentation for more information. Since ACL2 functions cannot take keyword arguments (though macros can), the ACL2 functions position-equal (POSITION-EQUAL^) and position-eq (POSITION-EQ^) are defined to correspond to calls of the Common Lisp function position whose keyword argument :test is equal (EQUAL^) or eq (EQ^), respectively.

10.189 POSITION-EQ

POSITION-EQ position of an item in a string or a list, using eq (EQ^) as test

(Position-eq item seq) is the least index (zero-based) of the element item in the string or list seq, if in fact item is an element of seq. Otherwise (position item seq) is nil.

(Position-eq item lst) is provably the same in the ACL2 logic as (position item lst) and

(position-equal item lst), but it has a stronger guard (GUARD^) because it uses eq (EQ^) for a more efficient test for whether item is equal to a given member of lst. Its guard (GUARD^) requires that lst is a true list, and moreover, either item is a symbol or lst is a list of symbols. See Section 10.190 [POSITION-EQUAL], page 519 and see Section 10.188 [POSITION], page 518.

10.190 POSITION-EQUAL

POSITION-EQUAL position of an item in a string or a list

(Position item seq) is the least index (zero-based) of the element item in the string or list seq, if in fact item is an element of seq. Otherwise (position item seq) is nil.

(Position-equal item lst) has a guard (GUARD^) of (true-listp lst). Position-equal

has the same functionality as the Common Lisp function position (POSITION^), except that it uses the equal (EQUAL^) function to test whether item is the same as each successive element of lst. See Section 10.188 [POSITION], page 518 and see Section 10.189 [POSITION-EQ], page 518.

10.191 PPROGN

PPROGN evaluate a sequence of forms that return state (STATE^)

     Example Form:
     (pprogn
      (cond ((or (equal (car l) #\) (equal (car l) slash-char))
             (princ$ #\ channel state))
            (t state))
      (princ$ (car l) channel state)
      (mv (cdr l) state))

The convention for pprogn usage is to give it a non-empty sequence of forms, each of which (except possibly for the last) returns state (see Section 8.83 [STATE], page 368) as its only value. The state (STATE^) returned by each but the last is passed on to the next. The value or values of the last form are returned as the value of the pprogn.

General Form:

     (PPROGN form1

             form2
             ...
             formk
             result-form)

This general form is equivalent, via macro expansion, to:

     (LET ((STATE form1))
          (LET ((STATE form2))
               ...
               (LET ((STATE formk))
                    result-form)))

10.192 PROGN

PROGN see the documentation for er-progn (ER-PROGN^)

ACL2 does not allow the use of progn in definitions. Instead, a function er-progn (ER-PROGN^) can be used for sequencing state (STATE^)-oriented operations; see Section 10.106 [ER-PROGN], page 473 and see Section 8.83 [STATE], page 368.

Progn is a Common Lisp function. See any Common Lisp documentation for more information.

10.193 PROOFS-CO

PROOFS-CO the proofs character output channel

Proofs-co is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is (proofs-co

state) and the updater is (set-proofs-co val state). Proofs-co must be an open character

output channel. It is to this channel that defun (DEFUN^), defthm (DEFTHM^), and the other event command (COMMAND^)s print their commentary.

“Proofs-co” stands for “proofs character output.” The initial value of proofs-co is the same as the value of *standard-co* (*STANDARD-CO*^) (see Section 10.3 [*STANDARD-CO*], page 436).

10.194 PROPER-CONSP

PROPER-CONSP recognizer for proper (null-terminated) non-empty lists

Proper-consp is the function that checks whether its argument is a non-empty list that ends in nil. Also see Section 10.250 [TRUE-LISTP], page 542.

10.195 PUT-ASSOC-EQ

PUT-ASSOC-EQ modify an association list by associating a value with a key

(Put-assoc-eq name val alist) returns an alist that is the same as the list alist, except that the first pair in alist with a car (CAR^) of name is replaced by (cons name val), if there is one. If there is no such pair, then (cons name val) is added at the end.

The guard (GUARD^) of (put-assoc-eq name val alist) requires that alist is an alistp

(ALISTP^), and moreover, either name is a symbol or alist is a symbol-alistp (SYMBOL-ALISTP^).

10.196 PUT-ASSOC-EQUAL

PUT-ASSOC-EQUAL modify an association list by associating a value with a key

(Put-assoc-equal name val alist) returns an alist that is the same as the list alist, except that the first pair in alist with a car (CAR^) of name is replaced by (cons name val), if there is one. If there is no such pair, then (cons name val) is added at the end.

The guard (GUARD^) of (put-assoc-equal name val alist) requires that alist is an alistp

(ALISTP^).

10.197 RASSOC

RASSOC look up value in association list, using eql (EQL^) as test

(Rassoc x alist) is similar to (assoc x alist), the difference being that it looks for the first pair in the given alist whose cdr (CDR^), rather than car (CAR^), is eql (EQL^) to x. See Section 10.27 [ASSOC], page 445.

The guard (GUARD^) of rassoc requires its second argument to be an alist, and in addition, that either its first argument is eqlablep (EQLABLEP^) or else all second components of pairs belonging to the second argument are eqlablep (EQLABLEP^). See Section 10.104 [EQLABLEP], page 473. Rassoc is a Common Lisp function. See any Common Lisp documentation for more information.

10.198 RATIONAL-LISTP

RATIONAL-LISTP recognizer for a true list of rational numbers The predicate rational-listp tests whether its argument is a true list of rational numbers.

10.199 RATIONALP

RATIONALP recognizer for whole numbers (rationalp x) is true if and only if x is an rational number.

10.200 REALPART

REALPART real part of a complex number Basic axiom:

     (equal (realpart x)
            (if (acl2-numberp x)
                (realpart x)
              0))

Guard (GUARD^) for (realpart x):

     (acl2-numberp x)

10.201 REDEFINING-PROGRAMS

REDEFINING-PROGRAMS an explanation of why we restrict redefinitions

ACL2 does not in general allow the redefinition of functions because logical inconsistency can result: previously stored theorems can be rendered invalid if the axioms defining the functions involved are changed. However, to permit prototyping of both :program (PROGRAM^) and :logic (LOGIC^) mode systems, ACL2 permits redefinition if the user has accepted logical responsibility for the consequences by setting ld-redefinition-action (LD-REDEFINITION-ACTION^) to an appropriate non-nil value. The refusal of ACL2 to support the unrestricted redefinition of :program (PROGRAM^) mode functions may appear somewhat capricious. After all, what are the logical consequences of changing a definition if no axioms are involved?

Three important points should be made before we discuss redefinition further.

The first is that ACL2 does support redefinition (of both :program (PROGRAM^) and :logic (LOGIC^) functions) when ld-redefinition-action (LD-REDEFINITION-ACTION^) is non-

nil.

The second is that a “redefinition” that does not change the mode, formals or body of a function is considered redundant and is permitted even when ld-redefinition-action (LD-REDEFINITION-ACTION^) is nil. We recognize and permit redundant definitions because it is not uncommon for two distinct books (BOOKS^) to share identical function definitions. When determining whether the body of a function is changed by a proposed redefinition, we actually compare the untranslated versions of the two bodies. See Section 8.87 [TERM], page 376. For example, redundancy is not recognized if the old body is (list a b) and the new body is (cons a (cons b nil)). We use the untranslated bodies because of the difficulty of translating the new body in the presence of the old syntactic information, given the possibility that the redefinition might attempt to change the signature (SIGNATURE^) of the function, i.e., the number of formals, the number of results, or the position of STATE (STATE^) in either.

The third important point is that a “redefinition” that preserves the formals and body but changes the mode from :program (PROGRAM^) to :logic (LOGIC^) is permitted even when ld-redefinition-action (LD-REDEFINITION-ACTION^) is nil. That is what verifytermination (VERIFY-TERMINATION^) does.

This note addresses the temptation to allow redefiniton of :program (PROGRAM^) functions in situations other than the three described above. Therefore, suppose ld-redefinition-action (LD-REDEFINITION-ACTION^) is nil and consider the cases.

Case 1. Suppose the new definition attempts to change the formals or more generally the signature (SIGNATURE^) of the function. Accepting such a redefinition would render ill-formed other :program (PROGRAM^) functions which call the redefined function. Subsequent attempts to evaluate those callers could arbitrarily damage the Common Lisp image. Thus, redefinition of :program (PROGRAM^) functions under these circumstances requires the user’s active approval, as would be sought with ld-redefinition-action (LD-REDEFINITION-ACTION^) '(:query

. :overwrite).

Case 2. Suppose the new definition attempts to change the body (even though it preserves the signature (SIGNATURE^)). At one time we believed this was acceptable and ACL2 supported the quiet redefinition of :program (PROGRAM^) mode functions in this circumstance. However, because such functions can be used in macros and redundancy checking is based on untranslated bodies, this turns out to be unsound! It is therefore now prohibited. We illustrate such an unsoundness below. Let foo-thm1.lisp be a book with the following contents.

     (in-package "ACL2")
     (defun p1 (x) (declare (xargs :mode :program)) (list 'if x 't 'nil))
     (defmacro p (x) (p1 x))
     (defun foo (x) (p x))
     (defthm foo-thm1 (iff (foo x) x) :rule-classes nil)

Note that the macro form (p x) translates to (if x t nil). The :program (PROGRAM^) function p1 is used to generate this translation. The function foo is defined so that (foo x) is (p x) and a theorem about foo is proved, namely, that (foo x) is true iff x is true.

Now let foo-thm2.lisp be a book with the following contents.

     (in-package "ACL2")
     (defun p1 (x) (declare (xargs :mode :program)) (list 'if x 'nil 't))
     (defmacro p (x) (p1 x))
     (defun foo (x) (p x))
     (defthm foo-thm2 (iff (foo x) (not x)) :rule-classes nil)

In this book, the :program (PROGRAM^) function p1 is defined so that (p x) means just the negation of what it meant in the first book, namely, (if x nil t). The function foo is defined identically — more precisely, the untranslated body of foo is identical in the two books (BOOKS^), but because of the difference between the two versions of the the :program (PROGRAM^) function p1 the axioms defining the two foos are different. In the second book we prove the theorem that (foo x) is true iff x is nil.

Now consider what would happen if the signature (SIGNATURE^)-preserving redefinition of :program (PROGRAM^) functions were permitted and these two books (BOOKS^) were included. When the second book is included the redefinition of p1 would be permitted since the signature (SIGNATURE^) is preserved and p1 is just a :program (PROGRAM^). But then when the redefinition of foo is processed it would be considered redundant and thus be permitted. The result would be a logic in which it was possible to prove that (foo x) is equivalent to both x and (not x). In particular, the following sequence leads to a proof of nil:

     (include-book "foo-thm1")
     (include-book "foo-thm2")
     (thm nil :hints (("Goal" :use (foo-thm1 foo-thm2))))

It might be possible to loosen the restrictions on the redefinition of :program (PROGRAM^) functions by allowing signature (SIGNATURE^)-preserving redefinition of :program (PROGRAM^) functions not involved in macro definitions. Alternatively, we could implement definition redundancy checking based on the translated bodies of functions (though that is quite problematic). Barring those two changes, we believe it is necessary simply to impose the same restrictions on the redefinition of :program (PROGRAM^) mode functions as we do on :logic (LOGIC^) mode functions.

10.202 REM

REM remainder using truncate (TRUNCATE^)

     ACL2 !>(rem 14 3)
     2
     ACL2 !>(rem -14 3)
     -2
     ACL2 !>(rem 14 -3)
     2
     ACL2 !>(rem -14 -3)
     -2
     ACL2 !>(rem -15 -3)
     0
     ACL2 !>

(Rem i j) is that number k that (* j (truncate i j)) added to k equals i.

The guard (GUARD^) for (rem i j) requires that i and j are rational numbers and j is non-zero.

Rem is a Common Lisp function. See any Common Lisp documentation for more information.

10.203 REMOVE

REMOVE remove all occurrences, testing using eql (EQL^)

(remove x l) is l if x is not a member of l, else is the result of removing all occurrences of x from

l.

The guard (GUARD^) for (remove x l) requires l to be a true list and moreover, either x is eqlablep (EQLABLEP^) or all elements of l are eqlablep (EQLABLEP^).

Remove is a Common Lisp function. See any Common Lisp documentation for more information. Note that we do not allow keyword arguments (such as test) in ACL2 functions, in particular, in

remove.

10.204 REMOVE-DUPLICATES

REMOVE-DUPLICATES remove duplicates from a string or (using eql (EQL^)) a list

Remove-duplicates returns the result of deleting duplicate elements from the beginning of the given string or true list, i.e., leaving the last element in place. For example,

     (remove-duplicates '(1 2 3 2 4))

is equal to '(1 3 2 4).

The guard (GUARD^) for Remove-duplicates requires that its argument is a string or a true-list of eqlablep (EQLABLEP^) objects. It uses the function eql (EQL^) to test for equality between elements of its argument.

Remove-duplicates is a Common Lisp function. See any Common Lisp documentation for more information. Note that we do not allow keyword arguments (such as test) in ACL2 functions, in particular, in remove-duplicates. But see Section 10.205 [REMOVE-DUPLICATES-EQUAL], page 527, which is similar but uses the function equal (EQUAL^) to test for duplicate elements.

10.205 REMOVE-DUPLICATES-EQUAL

REMOVE-DUPLICATES-EQUAL remove duplicates from a list

Remove-duplicates-equal is the same as remove-duplicates (REMOVE-DUPLICATES^), ex-

cept that its argument must be a true list (not a string), and equal (EQUAL^) is used to check membership rather than eql (EQL^). See Section 10.204 [REMOVE-DUPLICATES], page 526. The guard (GUARD^) for Remove-duplicates-equal requires that its argument is a true list. Note that unlike remove-duplicates (REMOVE-DUPLICATES^), it does not allow string arguments.

10.206 REST

REST rest (cdr (CDR^)) of the list In the logic, rest is just a macro for cdr (CDR^). Rest is a Common Lisp function. See any Common Lisp documentation for more information.

10.207 REVAPPEND

REVAPPEND concatentate the reverse (REVERSE^) of one list to another (Revappend x y) concatenate (CONCATENATE^)s the reverse (REVERSE^) of the list x to y, which is also typically a list. The following theorem characterizes this English description.

     (equal (revappend x y)
            (append (reverse x) y))

Hint: This lemma follows immediately from the definition of reverse (REVERSE^) and the following lemma.

     (defthm revappend-append
       (equal (append (revappend x y) z)

              (revappend x (append y z))))

The guard (GUARD^) for (revappend x y) requires that x is a true list. Revappend is defined in Common Lisp. See any Common Lisp documentation for more information.

10.208 REVERSE

REVERSE reverse a list (Reverse x) is the result of reversing the order of the elements of the list x. The guard (GUARD^) for reverse requires that its argument is a true list. Reverse is defined in Common Lisp. See any Common Lisp documentation for more information.

10.209 RFIX

RFIX coerce to a rational number Rfix simply returns any rational number argument unchanged, returning 0 on a non-rational argument. Also see Section 10.173 [NFIX], page 513, see Section 10.122 [IFIX], page 488, and see Section 10.112 [FIX], page 475 for analogous functions that coerce to a natural number, an integer, and a number, respectively. Rfix has a guard (GUARD^) of t.

10.210 ROUND

ROUND division returning an integer by rounding off

     Example Forms:
     ACL2 !>(round 14 3)
     5
     ACL2 !>(round -14 3)

-5
ACL2 !>(round 14 -3)
-5
ACL2 !>(round -14 -3)
5
ACL2 !>(round 13 3)
4
ACL2 !>(round -13 3)
-4
ACL2 !>(round 13 -3)
-4
ACL2 !>(round -13 -3)
4
ACL2 !>(round -15 -3)
5
ACL2 !>(round 15 -2)
-8

(Round i j) is the result of taking the quotient of i and j and rounding off to the nearest integer. When the quotient is exactly halfway between consecutive integers, it rounds to the even one.

The guard (GUARD^) for (round i j) requires that i and j are rational numbers and j is nonzero.

Round is a Common Lisp function. See any Common Lisp documentation for more information.

10.211 SECOND

SECOND second member of the list

See any Common Lisp documentation for details.

10.212 SET-DIFFERENCE-EQUAL

SET-DIFFERENCE-EQUAL elements of one list that are not elements of another

(Set-difference l1 l2) equals a list whose members (see Section 10.166 [MEMBER-EQUAL], page 508) contains the members of x that are not members of y. More precisely, the resulting list is the same as one gets by deleting the members of y from x, leaving the remaining elements in the same order as they had in x.

The guard (GUARD^) for set-difference-equal requires both arguments to be true lists. Essentially, set-difference-equal has the same functionality as the Common Lisp function setdifference, except that it uses the equal (EQUAL^) function to test membership rather than eql (EQL^). However, we do not include the function set-difference in ACL2, because the Common Lisp language does not specify the order of the elements in the list that it returns.

10.213 SEVENTH

SEVENTH seventh member of the list

See any Common Lisp documentation for details.

10.214 SIGNUM

SIGNUM indicator for positive, negative, or zero

(Signum x) is 0 if x is 0, -1 if x is negative, and is 1 otherwise.

The guard (GUARD^) for signum requires its argument to be rational.

Signum is a Common Lisp function. See any Common Lisp documentation for more information.

From “Common Lisp the Language” page 206, we see a definition of signum in terms of abs (ABS^). As explained elsewhere (see Section 10.16 [ABS], page 441), the guard (GUARD^) for abs (ABS^) requires its argument to be a rational number; hence, we make the same restriction for signum.

10.215 SIXTH

SIXTH sixth member of the list

See any Common Lisp documentation for details.

10.216 STANDARD-CHAR-LISTP

STANDARD-CHAR-LISTP recognizer for standard characters

(standard-char-listp x) is true if and only if x is a null-terminated list all of whose members are standard characters (CHARACTERS^). See Section 10.217 [STANDARD-CHAR-P], page 531.

Standard-char-listp has a guard (GUARD^) of t.

10.217 STANDARD-CHAR-P

STANDARD-CHAR-P recognizer for standard characters

(Standard-char-p x) is true if and only if x is a “standard” character, i.e., a member of the list *standard-chars*. This list includes #Newline and #Space characters (CHARACTERS^), as well as the usual punctuation and alphanumeric characters (CHARACTERS^).

Standard-char-p has a guard (GUARD^) requiring its argument to be a character.

Standard-char-p is a Common Lisp function. See any Common Lisp documentation for more information.

10.218 STANDARD-CO

STANDARD-CO the character output channel to which ld (LD^) prints

Standard-co is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is (standard-co

state) and the updater is (set-standard-co val state). Standard-co must be an open char-

acter output channel. It is to this channel that ld (LD^) prints the prompt (PROMPT^), the form to be evaluated, and the results. The event command (COMMAND^)s such as defun (DEFUN^), defthm (DEFTHM^), etc., which print extensive commentary do not print to standard-co but rather to a different channel, proofs-co (PROOFS-CO^), so that you may redirect this commentary while still interacting via standard-co. See Section 10.193 [PROOFS-CO], page 520.

“Standard-co” stands for “standard character output.” The initial value of standard-co is the same as the value of *standard-co* (*STANDARD-CO*^) (see Section 10.3 [*STANDARD-CO*], page 436).

10.219 STANDARD-OI

STANDARD-OI the standard object input “channel”

Standard-oi is an ld (LD^) special (see Section 9.7 [LD], page 416). The accessor is (standard-oi

state) and the updater is (set-standard-oi val state). Standard-oi must be an open object

input channel, a true list of objects, or a list of objects whose last cdr (CDR^) is an open object input channel. It is from this source that ld (LD^) takes the input forms to process. When ld (LD^) is called, if the value specified for standard-oi is a string or a list of objects whose last cdr (CDR^) is a string, then ld (LD^) treats the string as a file name and opens an object input channel from that file. The channel opened by ld (LD^) is closed by ld (LD^) upon termination.

“Standard-oi” stands for “standard object input.” The read-eval-print loop in ld (LD^) reads the objects in standard-oi and treats them as forms to be evaluated. The initial value of standard-oi is the same as the value of *standard-oi* (*STANDARD-OI*^) (see Section 10.4 [*STANDARD-OI*], page 436).

10.220 STRING

STRING coerce (COERCE^) to a string

(String x) coerce (COERCE^)s x to a string. If x is already a string, then it is returned unchanged; if x is a symbol, then its symbol-name (SYMBOL-NAME^) is returned; and if x is a character, the corresponding one-character string is returned.

The guard (GUARD^) for string requires its argument to be a string, a symbol, or a character.

String is a Common Lisp function. See any Common Lisp documentation for more information.

10.221 STRING-ALISTP

STRING-ALISTP recognizer for association lists with strings as keys (String-alistp x) is true if and only if x is a list of pairs of the form (cons key val) where key is a string. String-alistp has a guard (GUARD^) of t.

10.222 STRING-APPEND

STRING-APPEND concatenate (CONCATENATE^) two strings NOTE: It is probably more efficient to use the Common Lisp function concatenate (CONCATE-NATE^) in place of string-append. That is,

     (string-append str1 str2)

is equal to

     (concatenate 'string str1 str2).

At any rate, string-append takes two arguments, which are both strings (if the guard (GUARD^) is to be met), and returns a string obtained concatenating together the characters (CHARACTERS^) in the first string followed by those in the second. See Section 10.89 [CONCATENATE], page 467.

10.223 STRING-DOWNCASE

STRING-DOWNCASE in a given string, turn upper-case characters (CHARACTERS^) into lowercase For a string x, (string-downcase x) is the result of applying char-downcase (CHAR-DOWNCASE^) to each character in x. The guard (GUARD^) for string-downcase requires its argument to be a string. String-downcase is a Common Lisp function. See any Common Lisp documentation for more information.

10.224 STRING-EQUAL

STRING-EQUAL string equality without regard to case

For strings str1 and str2, (string-equal str1 str2) is true if and only str1 and str2 are the

same except perhaps for the cases of their characters (CHARACTERS^). The guard (GUARD^) on string-equal requires that its arguments are strings. String-equal is a Common Lisp function. See any Common Lisp documentation for more information.

10.225 STRING-LISTP

STRING-LISTP recognizer for a true list of strings The predicate string-listp tests whether its argument is a true-listp (TRUE-LISTP^) of strings.

10.226 STRING-UPCASE

STRING-UPCASE in a given string, turn lower-case characters (CHARACTERS^) into uppercase For a string x, (string-upcase x) is the result of applying char-upcase (CHAR-UPCASE^) to each character in x. The guard (GUARD^) for string-upcase requires its argument to be a string. String-upcase is a Common Lisp function. See any Common Lisp documentation for more information.

10.227 STRING<

STRING< less-than test for strings

(String< str1 str2) is non-nil if and only if the string str1 precedes the string str2 lexicographically, where character inequalities are tested using char< (CHAR<^). When non-nil, (string< str1 str2) is the first position (zero-based) at which the strings differ. Here are some examples.

     ACL2 !>(string< "abcd" "abu")
     2
     ACL2 !>(string< "abcd" "Abu")
     NIL
     ACL2 !>(string< "abc" "abcde")
     3
     ACL2 !>(string< "abcde" "abc")
     NIL

The guard (GUARD^) for string< specifies that its arguments are strings.

String< is a Common Lisp function. See any Common Lisp documentation for more information.

10.228 STRING<=

STRING<= less-than-or-equal test for strings

(String<= str1 str2) is non-nil if and only if the string str1 precedes the string str2 lexicographically or the strings are equal. When non-nil, (string<= str1 str2) is the first position (zero-based) at which the strings differ, if they differ, and otherwise is their common length. See Section 10.227 [STRING<], page 534.

The guard (GUARD^) for string<= specifies that its arguments are strings.

String<= is a Common Lisp function. See any Common Lisp documentation for more information.

10.229 STRING>

STRING> greater-than test for strings (String> str1 str2) is non-nil if and only if str2 precedes str1 lexicographically. When nonnil, (string> str1 str2) is the first position (zero-based) at which the strings differ. See Section 10.227 [STRING<], page 534. String> is a Common Lisp function. See any Common Lisp documentation for more information.

10.230 STRING>=

STRING>= less-than-or-equal test for strings (String>= str1 str2) is non-nil if and only if the string str2 precedes the string str1 lexicographically or the strings are equal. When non-nil, (string>= str1 str2) is the first position (zero-based) at which the strings differ, if they differ, and otherwise is their common length. See Section 10.229 [STRING>], page 535. The guard (GUARD^) for string>= specifies that its arguments are strings. String>= is a Common Lisp function. See any Common Lisp documentation for more information.

10.231 STRINGP

STRINGP recognizer for strings (stringp x) is true if and only if x is a string.

10.232 STRIP-CARS

STRIP-CARS collect up all first components of pairs in a list (strip-cars x) is the list obtained by walking through the list x and collecting up all first components (car (CAR^)s).

(strip-cars x) has a guard (GUARD^) of (alistp x).

10.233 STRIP-CDRS

STRIP-CDRS collect up all second components of pairs in a list

(strip-cdrs x) has a guard (GUARD^) of (alistp x), and returns the list obtained by walking through the list x and collecting up all second components (cdr (CDR^)s).

10.234 SUBLIS

SUBLIS substitute an alist into a tree

(Sublis alist tree) is obtained by replacing every leaf of tree with the result of looking that leaf up in the association list alist. However, a leaf is left unchanged if it is not found as a key in

alist.

Leaves are lookup up using the function assoc (ASSOC^). The guard (GUARD^) for (subsetp alist tree) requires (eqlable-alistp alist). This guard (GUARD^) ensures that the guard (GUARD^) for assoc (ASSOC^) will be met for each lookup generated by sublis.

Sublis is defined in Common Lisp. See any Common Lisp documentation for more information.

10.235 SUBSEQ

SUBSEQ subsequence of a string or list

For any natural numbers start and end, where start <= end <= (length seq), (subseq start

end) is the subsequence of seq from index start up to, but not including, index end. End may be nil, which which case it is treated as though it is (length seq), i.e., we obtain the subsequence of seq from index start all the way to the end.

The guard (GUARD^) for (subseq seq start end) is that seq is a true list or a string, start and end are integers (except, end may be nil, in which case it is treated as (length seq) for ther

rest of this discussion), and 0 <= start <= end <= (length seq).

Subseq is a Common Lisp function. See any Common Lisp documentation for more information. Note: In Common Lisp the third argument of subseq is optional, but in ACL2 it is required, though it may be nil as explained above.

10.236 SUBSETP

SUBSETP test if every member (MEMBER^) of one list is a member (MEMBER^) of the other

(Subsetp x y) is true if and only if every member of the list x is a member of the list y.

Membership is tested using the function member (MEMBER^). Thus, the guard (GUARD^) for subsetp requires that its arguments are true lists, and moreover, at least one satisfies eqlablelistp (EQLABLE-LISTP^). This guard (GUARD^) ensures that the guard (GUARD^) for member (MEMBER^) will be met for each call generated by subsetp.

Subsetp is defined in Common Lisp. See any Common Lisp documentation for more information.

10.237 SUBSETP-EQUAL

SUBSETP-EQUAL check if all members of one list are members of the other

(Subsetp-equal x y) returns t if every member of x is a member of y, where membership is tested using member-equal (MEMBER-EQUAL^).

The guard (GUARD^) for subsetp-equal requires both arguments to be true lists. Subsetpequal has the same functionality as the Common Lisp function subsetp (SUBSETP^), except that it uses the equal (EQUAL^) function to test membership rather than eql (EQL^).

10.238 SUBST

SUBST a single substitution into a tree

(Subst new old tree) is obtained by substituting new for every occurence of old in the given tree.

Equality to old is determined using the function eql (EQL^). The guard (GUARD^) for (subst new old tree) requires (eqlablep old), which ensures that the guard (GUARD^) for eql (EQL^) will be met for each comparison generated by subst.

Subst is defined in Common Lisp. See any Common Lisp documentation for more information.

10.239 SYMBOL-<

SYMBOL-< less-than test for symbols

(symbol-< x y) is non-nil if and only if either the symbol-name (SYMBOL-NAME^) of the symbol x lexicographially precedes the symbol-name (SYMBOL-NAME^) of the symbol y (in the sense of string< (STRING<^)) or else the symbol-name (SYMBOL-NAME^)s are equal and the symbol-package-name (SYMBOL-PACKAGE-NAME^) of x lexicographically precedes that of y

(in the same sense). So for example, (symbol-< 'abcd 'abce) and (symbol-< 'acl2::abcd
'foo::abce) are true.

The guard (GUARD^) for symbol specifies that its arguments are symbols.

10.240 SYMBOL-ALISTP

SYMBOL-ALISTP recognizer for association lists with symbols as keys

(Symbol-alistp x) is true if and only if x is a list of pairs of the form (cons key val) where key is a symbolp (SYMBOLP^).

10.241 SYMBOL-LISTP

SYMBOL-LISTP recognizer for a true list of symbols

The predicate symbol-listp tests whether its argument is a true list of symbols.

10.242 SYMBOL-NAME

SYMBOL-NAME the name of a symbol (a string) Basic axiom:

     (equal (symbol-name x)
            (if (symbolp x)
                (symbol-name x)
              ""))

Guard (GUARD^) for (symbol-name x):

     (symbolp x)

10.243 SYMBOL-PACKAGE-NAME

SYMBOL-PACKAGE-NAME the name of the package of a symbol (a string) Basic axiom:

     (equal (symbol-package-name x)
            (if (symbolp x)
                (symbol-package-name x)
              ""))
Guard (GUARD^) for (symbol-package-name x):
     (symbolp x)

10.244 SYMBOLP

SYMBOLP recognizer for symbols (symbolp x) is true if and only if x is a symbol.

10.245 TAKE

TAKE initial segment of a list For any natural number n not exceeding the length of l, (take n l) collects the first n elements of the list l. The following is a theorem (though it takes some effort, including lemmas, to get ACL2 to prove it):

     (equal (length (take n l)) (nfix n))

If n is is an integer greater than the length of l, then take pads the list with the appropriate number of nil elements. Thus, the following is also a theorem.

     (implies (and (integerp n)
                   (true-listp l)
                   (<= (length l) n))
              (equal (take n l)
                     (append l (make-list (- n (length l))))))

For related functions, see Section 10.180 [NTHCDR], page 515 and see Section 10.38 [BUTLAST], page 449. The guard (GUARD^) for (take n l) is that n is a nonnegative integer and l is a true list.

10.246 TENTH

TENTH tenth member of the list See any Common Lisp documentation for details.

10.247 THE

THE run-time type check (The typ val) checks that val satisfies the type specification typ (see Section 10.252 [TYPE-SPEC], page 543). An error is caused if the check fails, and otherwise, val is the value of this expression. Here are some examples.

     (the integer 3)       ; returns 3
     (the (integer 0 6) 3) ; returns 3
     (the (integer 0 6) 7) ; causes an error

See Section 10.252 [TYPE-SPEC], page 543 for a discussion of the legal type specifications. The is defined in Common Lisp. See any Common Lisp documentation for more information.

10.248 THIRD

THIRD third member of the list See any Common Lisp documentation for details.

10.249 TRUE-LIST-LISTP

TRUE-LIST-LISTP recognizer for true (proper) lists of true lists True-list-listp is the function that checks whether its argument is a list that ends in, or equals, nil, and furthermore, all of its elements have that property. Also see Section 10.250 [TRUE-LISTP], page 542.

10.250 TRUE-LISTP

TRUE-LISTP recognizer for proper (null-terminated) lists True-listp is the function that checks whether its argument is a list that ends in, or equals, nil.

10.251 TRUNCATE

TRUNCATE division returning an integer by truncating toward 0

Example Forms:
ACL2 !>(truncate 14 3)
4
ACL2 !>(truncate -14 3)
-4
ACL2 !>(truncate 14 -3)
-4
ACL2 !>(truncate -14 -3)
4
ACL2 !>(truncate -15 -3)
5

(Truncate i j) is the result of taking the quotient of i and j and dropping the fraction. For example, the quotient of -14 by 3 is -4 2/3, so dropping the fraction 2/3, we obtain a result for

(truncate -14 3) of -4.

The guard (GUARD^) for (truncate i j) requires that i and j are rational numbers and j is non-zero.

Truncate is a Common Lisp function. See any Common Lisp documentation for more information.

10.252 TYPE-SPEC

TYPE-SPEC type specifiers in declarations

Examples:
The symbol INTEGER in (declare (type INTEGER i j k)) is a type-spec.  Other
type-specs supported by ACL2 include RATIONAL, COMPLEX, (INTEGER 0 127),
(RATIONAL 1 *), CHARACTER, and ATOM.

The type-specs and their meanings (when applied to the variable x as in (declare (type typespec x)) are given below.

type-spec                 meaning
ATOM                 (ATOM X)
BIT                  (OR (EQUAL X 1) (EQUAL X 0))
CHARACTER            (CHARACTERP X)

COMPLEX,             (AND (COMPLEX-RATIONALP X)
(COMPLEX RATIONAL)        (RATIONALP (REALPART X))
                          (RATIONALP (IMAGPART X)))
(COMPLEX type)       (AND (COMPLEX-RATIONALP X)
                          (p (REALPART X))
                          (p (IMAGPART X)))
                     where (p x) is the meaning for type-spec type
CONS                 (CONSP X)
INTEGER              (INTEGERP X)
(INTEGER i j)        (AND (INTEGERP X)   ; See notes below
                          (<= i X)
                          (<= X j))
(MEMBER x1 ... xn)   (MEMBER X '(x1 ... xn))
(MOD i)              same as (INTEGER 0 i-1)
NIL                  NIL
NULL                 (EQ X NIL)
RATIO                (AND (RATIONALP X) (NOT (INTEGERP X)))
RATIONAL             (RATIONALP X)
(RATIONAL i j)       (AND (RATIONALP X)  ; See notes below
                          (<= i X)
                          (<= X j))
(SATISFIES pred)     (pred X)
SIGNED-BYTE          (INTEGERP X)
(SIGNED-BYTE i)      same as (INTEGER -2**i-1 (2**i-1)-1)
STANDARD-CHAR        (STANDARD-CHARP X)
STRING               (STRINGP X)
(STRING max)         (AND (STRINGP X) (EQUAL (LENGTH X) max))
SYMBOL               (SYMBOLP X)
T                    T
UNSIGNED-BYTE        same as (INTEGER 0 *)
(UNSIGNED-BYTE i)    same as (INTEGER 0 (2**i)-1)

Notes:

In general, (integerp i j) means

     (AND (INTEGERP X)
          (<= i X)
          (<= X j)).

But if i is the symbol *, the first inequality is omitted. If j is the symbol *, the second inequality is omitted. If instead of being an integer, the second element of the type specification is a list containing an integer, (i), then the first inequality is made strict. An analogous remark holds for the (j) case. The RATIONAL type specifier is similarly generalized.

10.253 UNARY–

UNARY– arithmetic negation function Basic axiom:

     (equal (unary-- x)
            (if (acl2-numberp x)
                (unary-- x)
              0))

Guard (GUARD^) for (unary-- x):

     (acl2-numberp x)

Notice that like all arithmetic functions, unary-- treats non-numeric inputs as 0. Calls of the macro - (-^) on one argument expand to calls of unary--; see Section 10.6 [-], page 437.

10.254 UNARY-/

UNARY-/ reciprocal function Basic axiom:

     (equal (unary-/ x)
            (if (and (acl2-numberp x)
                     (not (equal x 0)))
                (unary-/ x)
              0))

Guard (GUARD^) for (unary-/ x):

     (and (acl2-numberp x)
          (not (equal x 0)))

Notice that like all arithmetic functions, unary-/ treats non-numeric inputs as 0. Calls of the macro / (/^) on one argument expand to calls of unary-/; see Section 10.7 [/], page 438.

10.255 UNION-EQ

UNION-EQ union of two lists of symbols

(Union-eq x y) equals a list whose members (see Section 10.165 [MEMBER-EQ], page 508) contains the members of x and the members of y. More precisely, the resulting list is the same as one would get by first deleting the members of y from x, and then concatenating the result to the front of y.

The guard (GUARD^) for union-eq requires both arguments to be true lists, but in fact further requires the first list to contain only symbols, as the function member-eq (MEMBER-EQ^) is used to test membership (with eq (EQ^)). See Section 10.256 [UNION-EQUAL], page 546.

10.256 UNION-EQUAL

UNION-EQUAL union of two lists

(Union-equal x y) equals a list whose members (see Section 10.166 [MEMBER-EQUAL], page 508) contains the members of x and the members of y. More precisely, the resulting list is the same as one would get by first deleting the members of y from x, and then concatenating the result to the front of y.

The guard (GUARD^) for union-equal requires both arguments to be true lists. Essentially, union-equal has the same functionality as the Common Lisp function union, except that it uses the equal (EQUAL^) function to test membership rather than eql (EQL^). However, we do not include the function union in ACL2, because the Common Lisp language does not specify the order of the elements in the list that it returns.

10.257 UPDATE-NTH

UPDATE-NTH modify a list by putting the given value at the given position

(Update-nth key val l) returns a list that is the same as the list l, except that the value at the 0-based position key (a natural number) is val.

If key is an integer at least as large as the length of l, then l will be padded with the appropriate number of nil elements, as illustrated by the following example.

     ACL2 !>(update-nth 8 'z '(a b c d e))
     (A B C D E NIL NIL NIL Z)

We have the following theorem.

     (implies (and (true-listp l)
                   (integerp key)
                   (<= 0 key))
              (equal (length (update-nth key val l))
                     (if (< key (length l))
                         (length l)
                       (+ 1 key))))

The guard (GUARD^) of update-nth requires that its first (position) argument is a natural number and its last (list) argument is a true list.

10.258 UPPER-CASE-P

UPPER-CASE-P recognizer for upper case characters

(Upper-case-p x) is true if and only if x is an upper case character, i.e., a member of the list #A, #B, ..., #Z.

The guard (GUARD^) for upper-case-p requires its argument to be a character.

Upper-case-p is a Common Lisp function. See any Common Lisp documentation for more information.

10.259 ZERO-TEST-IDIOMS

ZERO-TEST-IDIOMS how to test for 0

Below are six commonly used idioms for testing whether x is 0. Zip (ZIP^) and zp (ZP^) are the preferred termination tests for recursions down the integers and naturals, respectively.

     idiom       logical              guard              primary
                 meaning                              compiled code*
     (equal x 0)(equal x 0)          t                (equal x 0)
     (eql x 0)  (equal x 0)          t                (eql x 0)
     (zerop x)  (equal x 0)          x is a number    (= x 0)
     (= x 0)    (equal x 0)          x is a number    (= x 0)
     (zip x)    (equal (ifix x) 0)   x is an integer  (= x 0)
     (zp x)     (equal (nfix x) 0)   x is a natural   (= x 0)

*See Section 8.41.4 [GUARDS-AND-EVALUATION], page 310, especially the subsection titled “Guards and evaluation V: efficiency issues”. Primary code is relevant only if guard (GUARD^)s are verified. The “compiled code” shown is only suggestive.

The first four idioms all have the same logical meaning and differ only with respect to their executability and efficiency. In the absence of compiler optimizing, (= x 0) is probably the most efficient, (equal x 0) is probably the least efficient, and (eql x 0) is in between. However, an optimizing compiler could always choose to compile (equal x 0) as (eql x 0) and, in situations where x is known at compile-time to be numeric, (eql x 0) as (= x 0). So efficiency considerations must, of course, be made in the context of the host compiler.

Note also that (zerop x) and (= x 0) are indistinguishable. They have the same meaning and the same guard (GUARD^), and can reasonably be expected to generate equally efficient code.

Note that (zip x) and (zp x) do not have the same logical meanings as the others or each other. They are not simple tests for equality to 0. They each coerce x into a restricted domain, zip (ZIP^) to the integers and zp (ZP^) to the natural numbers, choosing 0 for x when x is outside the domain. Thus, 1/2, #c(1 3), and 'abc, for example, are all “recognized” as zero by both zip (ZIP^) and zp (ZP^). But zip (ZIP^) reports that -1 is different from 0 while zp (ZP^) reports that -1 “is” 0. More precisely, (zip -1) is nil while (zp -1) is t.

Note that the last four idioms all have guard (GUARD^)s that restrict their Common Lisp executability. If these last four are used in situations in which guard (GUARD^)s are to be verified, then proof obligations are incurred as the price of using them. If guard verification is not involved in your project, then the first four can be thought of as synonymous.

Zip (ZIP^) and zp (ZP^) are not provided by Common Lisp but are ACL2-specific functions. Why does ACL2 provide these functions? The answer has to do with the admission of recursively defined functions and efficiency. Zp (ZP^) is provided as the zero-test in situations where the controlling formal parameter is understood to be a natural number. Zip (ZIP^) is analogously provided for the integer case. We illustrate below.

Here is an admissible definition of factorial

     (defun fact (n) (if (zp n) 1 (* n (fact (1- n)))))

Observe the classic recursion scheme: a test against 0 and recursion by 1- (1-^). Note however that the test against 0 is expressed with the zp (ZP^) idiom. Note also the absence of a guard (GUARD^) making explicit our intention that n is a natural number.

This definition of factorial is readily admitted because when (zp n)

is false (i.e., nil) then n is a natural number other than 0 and so (1- n) is less than n. The base case, where (zp n) is true, handles all the “unexpected” inputs, such as arise with (fact -1) and (fact 'abc). When calls of fact are evaluated, (zp n) checks (integerp n) and (> n 0). Guard (GUARD^) verification is unsuccessful for this definition of fact because zp (ZP^) requires its argument to be a natural number and there is no guard (GUARD^) on fact, above. Thus the primary raw lisp for fact is inaccessible and only the :logic (LOGIC^) definition (which does runtime “type” checking) is used in computation. In summary, this definition of factorial is easily admitted and easily manipulated by the prover but is not executed as efficiently as it could be.

Runtime efficiency can be improved by adding a guard (GUARD^) to the definition.

     (defun fact (n)
       (declare (xargs :guard (and (integerp n) (>= n 0))))
       (if (zp n) 1 (* n (fact (1- n)))))

This guard (GUARD^)ed definition has the same termination conditions as before – termination is not sensitive to the guard (GUARD^). But the guard (GUARD^)s can be verified. This makes the primary raw lisp definition accessible during execution. In that definition, the (zp n) above is compiled as (= n 0), because n will always be a natural number when the primary code is executed. Thus, by adding a guard (GUARD^) and verifying it, the elegant and easily used definition of factorial is also efficiently executed on natural numbers.

Now let us consider an alternative definition of factorial in which (= n 0) is used in place of (zp

n).
     (defun fact (n) (if (= n 0) 1 (* n (fact (1- n)))))

This definition does not terminate. For example (fact -1) gives rise to a call of (fact -2), etc. Hence, this alternative is inadmissible. A plausible response is the addition of a guard (GUARD^) restricting n to the naturals:

     (defun fact (n)
      (declare (xargs :guard (and (integerp n) (>= n 0))))
      (if (= n 0) 1 (* n (fact (1- n)))))

But because the termination argument is not sensitive to the guard (GUARD^), it is still impossible to admit this definition. To influence the termination argument one must change the conditions tested. Adding a runtime test that n is a natural number would suffice and allow both admission and guard (GUARD^) verification. But such a test would slow down the execution of the compiled function.

The use of (zp n) as the test avoids this dilemma. Zp (ZP^) provides the logical equivalent of a runtime test that n is a natural number but the execution efficiency of a direct = (=^) comparison with 0, at the expense of a guard (GUARD^) conjecture to prove. In addition, if guard (GUARD^) verification and most-efficient execution are not needed, then the use of (zp n) allows the admission of the function without a guard (GUARD^) or other extraneous verbiage.

While general rules are made to be broken, it is probably a good idea to get into the habit of using (zp n) as your terminating “0 test” idiom when recursing down the natural numbers. It provides the logical power of testing that n is a non-0 natural number and allows efficient execution.

We now turn to the analogous function, zip (ZIP^). Zip (ZIP^) is the preferred 0-test idiom when recursing through the integers toward 0. Zip (ZIP^) considers any non-integer to be 0 and otherwise just recognizes 0. A typical use of zip (ZIP^) is in the definition of integer-length (INTEGER-LENGTH^), shown below. (ACL2 can actually accept this definition, but only after appropriate lemmas have been proved.)

     (defun integer-length (i)
       (declare (xargs :guard (integerp i)))
       (if (zip i)
           0
         (if (= i -1)

           (+ 1 (integer-length (floor i 2))))))

Observe that the function recurses by (floor i 2). Hence, calling the function on 25 causes calls on 12, 6, 3, 1, and 0, while calling it on -25 generates calls on -13, -7, -4, -2, and -1. By making (zip i) the first test, we terminate the recursion immediately on non-integers. The guard (GUARD^), if present, can be verified and allows the primary raw lisp definition to check (= i 0) as the first terminating condition (because the primary code is executed only on integers).

10.260 ZEROP

ZEROP test an acl2-number against 0

(zerop x) is t if x is 0 and is nil otherwise. Thus, it is logically equivalent to (equal x 0).

(Zerop x) has a guard (GUARD^) requiring x to be numeric and can be expected to execute more efficiently than (equal x 0) in properly guard (GUARD^)ed compiled code.

In recursions down the natural numbers, (zp x) is preferred over (zerop x) because the former coerces x to a natural and allows the termination proof. In recursions through the integers, (zip x) is preferred. See Section 10.259 [ZERO-TEST-IDIOMS], page 547.

Zerop is a Common Lisp function. See any Common Lisp documentation for more information.

10.261 ZIP

ZIP testing an “integer” against 0

(Zip i) is logically equivalent to (equal (ifix i) 0) and is the preferred termination test for recursion through the integers. (Zip i) returns t if i is 0 or not an integer; it returns nil otherwise. Thus,

         i       (zp i)
        3         nil
        0         t
        -2        nil
        5/2       t
        #c(1 3)   t

        'abc      t

(Zip i) has a guard (GUARD^) requiring i to be an integer.

For a discussion of the various idioms for testing against 0, see Section 10.259 [ZERO-TEST-IDIOMS], page 547.

Zip is typically used as the termination test in recursions through the integers. It has the advantage of “coercing” its argument to an integer and hence allows the definition to be admitted without an explicit type check in the body. Guard (GUARD^) verification allows zip to be compiled as a direct = (=^)-comparision with 0.

10.262 ZP

ZP testing a “natural” against 0

(Zp n) is logically equivalent to (equal (nfix n) 0) and is the preferred termination test for recursion down the natural numbers. (Zp n) returns t if n is 0 or not a natural number; it returns nil otherwise. Thus, in the ACL2 logic (ignoring the issue of guard (GUARD^)s):

         n       (zp n)
        3         nil
        0         t
        -1        t
        5/2       t
        #c(1 3)   t
        'abc      t

(Zp n) has a guard (GUARD^) requiring n to be a natural number.

For a discussion of the various idioms for testing against 0, see Section 10.259 [ZERO-TEST-IDIOMS], page 547.

Zp is typically used as the termination test in recursions down the natural numbers. It has the advantage of “coercing” its argument to a natural and hence allows the definition to be admitted without an explicit type check in the body. Guard (GUARD^) verification allows zp to be compiled as a direct = (=^)-comparision with 0.

11 PROOF-CHECKER

PROOF-CHECKER support for low-level interaction

Call this up with (verify ...).

* ACL2-PC::=:: (atomic macro) attempt an equality (or equivalence) substitution

* ACL2-PC::ACL2-WRAP:: (macro)

same as (lisp x)

* ACL2-PC::ADD-ABBREVIATION:: (primitive) add an abbreviation

* ACL2-PC::BASH:: (atomic macro) call the ACL2 theorem prover’s simplifier

* ACL2-PC::BDD:: (atomic macro) prove the current goal using bdds

* ACL2-PC::BK:: (atomic macro) move backward one argument in the enclosing term

* ACL2-PC::BOOKMARK:: (macro) insert matching “bookends” comments

* ACL2-PC::CASESPLIT:: (primitive) split into two cases

* ACL2-PC::CG:: (macro) change to another goal.

* ACL2-PC::CHANGE-GOAL:: (primitive) change to another goal.

* ACL2-PC::CLAIM:: (atomic macro) add a new hypothesis

* ACL2-PC::COMM:: (macro) display instructions from the current interactive session

* ACL2-PC::COMMANDS:: (macro) display instructions from the current interactive session

* ACL2-PC::COMMENT:: (primitive) insert a comment

* ACL2-PC::CONTRADICT:: (macro)

same as contrapose

* ACL2-PC::CONTRAPOSE:: (primitive) switch a hypothesis with the conclusion, negating both

* ACL2-PC::DEMOTE:: (primitive) move top-level hypotheses to the conclusion

* ACL2-PC::DIVE:: (primitive) move to the indicated subterm

* ACL2-PC::DO-ALL:: (macro) run the given instructions

* ACL2-PC::DO-ALL-NO-PROMPT:: (macro) run the given instructions, halting once there is a “failure”

* ACL2-PC::DO-STRICT:: (macro) run the given instructions, halting once there is a “failure”

* ACL2-PC::DROP:: (primitive) drop top-level hypotheses

* ACL2-PC::DV:: (atomic macro) move to the indicated subterm

* ACL2-PC::ELIM:: (atomic macro) call the ACL2 theorem prover’s elimination process

* ACL2-PC::EQUIV:: (primitive) attempt an equality (or congruence-based) substitution

* ACL2-PC::EX:: (macro) exit after possibly saving the state

* ACL2-PC::EXIT:: (meta) exit the interactive proof-checker

* ACL2-PC::EXPAND:: (primitive) expand the current function call without simplification

* ACL2-PC::FAIL:: (macro) cause a failure

* ACL2-PC::FORWARDCHAIN:: (atomic macro) forward chain from an implication in the hyps

* ACL2-PC::FREE:: (atomic macro) create a “free variable”

* ACL2-PC::GENERALIZE:: (primitive) perform a generalization

* ACL2-PC::GOALS:: (macro) list the names of goals on the stack

* ACL2-PC::HELP:: (macro) proof-checker help facility

* ACL2-PC::HELP!:: (macro) proof-checker help facility

* ACL2-PC::HELP-LONG:: (macro) same as help!

* ACL2-PC::HYPS:: (macro) print the hypotheses

* ACL2-PC::ILLEGAL:: (macro) illegal instruction

* ACL2-PC::IN-THEORY:: (primitive) set the current proof-checker theory

* ACL2-PC::INDUCT:: (atomic macro) generate subgoals using induction

* ACL2-PC::LISP:: (meta) evaluate the given form in Lisp

* ACL2-PC::MORE:: (macro) proof-checker help facility

* ACL2-PC::MORE!:: (macro) proof-checker help facility

* ACL2-PC::NEGATE:: (macro) run the given instructions, and “succeed” if and only if they “fail”

* ACL2-PC::NIL:: (macro) used for interpreting control-d

* ACL2-PC::NOISE:: (meta) run instructions with output

* ACL2-PC::NX:: (atomic macro) move forward one argument in the enclosing term

* ACL2-PC::ORELSE:: (macro) run the first instruction; if (and only if) it “fails”, run the second

* ACL2-PC::P:: (macro) prettyprint the current term

* ACL2-PC::P-TOP:: (macro) prettyprint the conclusion, highlighting the current term

* ACL2-PC::PP:: (macro) prettyprint the current term

* ACL2-PC::PRINT:: (macro) print the result of evaluating the given form

* ACL2-PC::PRINT-ALL-GOALS:: (macro) print all the (as yet unproved) goals

* ACL2-PC::PRINT-MAIN:: (macro) print the original goal

* ACL2-PC::PRO:: (atomic macro) repeatedly apply promote

* ACL2-PC::PROMOTE:: (primitive) move antecedents of conclusion’s implies term to top-level hypotheses

* ACL2-PC::PROTECT:: (macro) run the given instructions, reverting to existing state upon failure

* ACL2-PC::PROVE:: (primitive) call the ACL2 theorem prover to prove the current goal

* ACL2-PC::PUT:: (macro) substitute for a “free variable”

* ACL2-PC::QUIET:: (meta) run instructions without output

* ACL2-PC::R:: (macro) same as rewrite

* ACL2-PC::REDUCE:: (atomic macro) call the ACL2 theorem prover’s simplifier

* ACL2-PC::REDUCE-BY-INDUCTION:: (macro) call the ACL2 prover without induction, after going into induction

* ACL2-PC::REMOVE-ABBREVIATIONS:: (primitive) remove one or more abbreviations

* ACL2-PC::REPEAT:: (macro) repeat the given instruction until it “fails”

* ACL2-PC::REPEAT-REC:: (macro) auxiliary to repeat * ACL2-PC::REPLAY:: (macro) replay one or more instructions

* ACL2-PC::RESTORE:: (meta) remove the effect of an UNDO command

* ACL2-PC::RETAIN:: (atomic macro) drop all but the indicated top-level hypotheses

* ACL2-PC::RETRIEVE:: (macro) re-enter the proof-checker

* ACL2-PC::REWRITE:: (primitive) apply a rewrite rule

* ACL2-PC::RUN-INSTR-ON-GOAL:: (macro) auxiliary toxae THEN

* ACL2-PC::RUN-INSTR-ON-NEW-GOALS:: (macro) auxiliary to then

* ACL2-PC::S:: (primitive) simplify the current subterm

* ACL2-PC::S-PROP:: (atomic macro) simplify propositionally

* ACL2-PC::SAVE:: (macro) save the proof-checker state (state-stack)

* ACL2-PC::SEQUENCE:: (meta) run the given list of instructions according to a multitude of options

* ACL2-PC::SHOW-ABBREVIATIONS:: (macro) display the current abbreviations

* ACL2-PC::SHOW-REWRITES:: (macro) display the applicable rewrite rules

* ACL2-PC::SKIP:: (macro) “succeed” without doing anything

* ACL2-PC::SL:: (atomic macro) simplify with lemmas

* ACL2-PC::SPLIT:: (atomic macro) split the current goal into cases

* ACL2-PC::SR:: (macro) same as SHOW-REWRITES

* ACL2-PC::SUCCEED:: (macro) run the given instructions, and “succeed”

* ACL2-PC::TH:: (macro) print the top-level hypotheses and the current subterm

* ACL2-PC::THEN:: (macro) apply one instruction to current goal and another to new subgoals

* ACL2-PC::TOP:: (atomic macro) move to the top of the goal

* ACL2-PC::TYPE-ALIST:: (macro) display the type-alist from the current context

* ACL2-PC::UNDO:: (meta) undo some instructions

* ACL2-PC::UNSAVE:: (macro) remove a proof-checker state

* ACL2-PC::UP:: (primitive) move to the parent (or some ancestor) of the current subterm

* ACL2-PC::USE:: (atomic macro) use a lemma instance

* ACL2-PC::X:: (atomic macro) expand and (maybe) simplify function call at the current subterm

* ACL2-PC::X-DUMB:: (atomic macro) expand function call at the current subterm, without simplifying

* DEFINE-PC-HELP:: define a macro command whose purpose is to print something

* INSTRUCTIONS:: instructions to the proof checker

* MACRO-COMMAND:: compound command for the proof-checker

* RETRIEVE:: re-enter a (specified) proof-checker (PROOF-CHECKER^) state

* TOGGLE-PC-MACRO:: change an ordinary macro command to an atomic macro, or vice-versa * UNSAVE:: remove a proof-checker (PROOF-CHECKER^) state

* VERIFY:: enter the interactive proof checker

This is an interactive system for checking theorems in ACL2. One enters it using VERIFY; see Section 11.101 [VERIFY], page 615. The result of an interactive session is a defthm (DEFTHM^) event with an :instructions (INSTRUCTIONS^) parameter supplied. Such an event can be replayed later in a new ACL2 session with the “proof-checker” loaded.

Individual proof-checker commands have already been listed above. Among them are proof-checker commands help (HELP^), help-long, more (MORE^), and more! (MORE!^), which behave respectively like the ACL2 functions :doc (DOC^), :doc! (DOC!^), :more (MORE^), and :more! (MORE!^).

11.1 ACL2-PC::=

ACL2-PC::= (atomic macro) attempt an equality (or equivalence) substitution

     Examples:
     =     -- replace the current subterm by a term equated to it in
              one of the hypotheses (if such a term exists)
     (= x) -- replace the current subterm by x, assuming that the prover
              can show that they are equal
     (= (+ x y) z)
           -- replace the term (+ x y) by the term z inside the current
              subterm, assuming that the prover can prove
              (equal (+ x y) z) from the current top-level hypotheses
              or that this term or (equal z (+ x y)) is among the
              current top-level hypotheses or the current governors

     (= & z)
           -- exactly the same as above, if (+ x y) is the current
              subterm
     (= (+ x y) z :hints :none)
           -- same as (= (+ x y) z), except that a new subgoal is
              created with the current goal's hypotheses and governors
              as its top-level hypotheses and (equal (+ x y) z) as its
              conclusion
     (= (+ x y) z 0)
           -- exactly the same as immediately above
     (= (p x)
        (p y)
        :equiv iff
        :otf-flg t
        :hints (("Subgoal 2" :BY FOO) ("Subgoal 1" :use bar)))
           -- same as (= (+ x y) z), except that the prover uses
              the indicated values for otf-flg and hints, and only
              propositional (iff) equivalence is used (however, it
              must be that only propositional equivalence matters at
              the current subterm)
     General Form:
     (= &optional x y &rest keyword-args)

If terms x and y are supplied, then replace x by y inside the current subterm if they are “known” to be “equal”. Here “known” means the following: the prover is called as in the prove command (using keyword-args) to prove (equal x y), except that a keyword argument :equiv is allowed, in which case (equiv x y) is proved instead, where equiv is that argument. (See below for how governors are handled.)

Actually, keyword-args is either a single non-keyword or is a list of the form ((kw-1 x-1) ...

(kw-n x-n)), where each kw-i is one of the keywords :equiv, :otf-flg, :hints. Here :equiv

defaults to equal if the argument is not supplied or is nil, and otherwise should be the name of an ACL2 equivalence relation. :Otf-flg and :hints give directives to the prover, as explained above and in the documentation for the prove command; however, no prover call is made if :hints is a non-nil atom or if keyword-args is a single non-keyword (more on this below).

Remarks on defaults

(1) If there is only one argument, say a, then x defaults to the current subterm, in the sense that x is taken to be the current subterm and y is taken to be a.

(2) If there are at least two arguments, then x may be the symbol &, which then represents the current subterm. Thus, (= a) is equivalent to (= & a). (Obscure point: actually, & can be in any package, except the keyword package.)

(3) If there are no arguments, then we look for a top-level hypothesis or a governor of the form (equal c u) or (equal u c), where c is the current subterm. In that case we replace the current subterm by u.

As with the prove command, we allow goals to be given “bye”s in the proof, which may be generated by a :hints keyword argument in keyword-args. These result in the creation of new subgoals.

A proof is attempted unless the :hints argument is a non-nil atom other than :none, or unless there is one element of keyword-args and it is not a keyword. In that case, if there are any hypotheses in the current goal, then what is attempted is a proof of the implication whose antecedent is the conjunction of the current hypotheses and governors and whose conclusion is the appropriate equal term.

Notes: (1) It is allowed to use abbreviations in the hints. (2) The keyword :none has the special role as a value of :hints that is shown clearly in an example above. (3) If there are governors, then the new subgoal has as additional hypotheses the current governors.

11.2 ACL2-PC::ACL2-WRAP

ACL2-PC::ACL2-WRAP (macro)

same as (lisp x)
     Example:
     (acl2-wrap (pe :here))
     General Form:
     (acl2-wrap form)

Same as (lisp form). This is provided for interface tools that want to be able to execute the same form in raw Lisp, in the proof-checker, or in the ACL2 top-level loop (lp).

11.3 ACL2-PC::ADD-ABBREVIATION

ACL2-PC::ADD-ABBREVIATION (primitive) add an abbreviation

Example: (add-abbreviation v (* x y)) causes future occurrences of (* x y) to be printed as (? v), until (unless) a corresponding invocation of remove-abbreviations occurs. In this case we say that v “abbreviates” (* x y).

     General Form:
     (add-abbreviation var &optional raw-term)

Let var be an abbreviation for raw-term, if raw-term is supplied, else for the current subterm. Note that var must be a variable that does not already abbreviate some term.

A way to think of abbreviations is as follows. Imagine that whenever an abbreviation is added, say v abbreviates expr, an entry associating v to expr is made in an association list, which we will call “*abbreviations-alist*”. Then simply imagine that ? is a function defined by something like:

     (defun ? (v)
       (let ((pair (assoc v *abbreviations-alist*)))
         (if pair (cdr pair)
           (error ...))))

Of course the implementation isn’t exactly like that, since the “constant” *abbreviations-alist* actually changes each time an add-abbreviation instruction is successfully invoked. Nevertheless, if one imagines an appropriate redefinition of the “constant” *abbreviations-alist* each time an add-abbreviation is invoked, then one will have a clear model of the meaning of such an instruction.

The effect of abbreviations on output is that before printing a term, each subterm that is abbreviated by a variable v is first replaced by (? v).

The effect of abbreviations on input is that every built-in proof-checker command accepts abbreviations wherever a term is expected as an argument, i.e., accepts the syntax (? v) whenever v abbreviates a term. For example, the second argument of add-abbreviation may itself use abbreviations that have been defined by previous add-abbreviation instructions.

See also remove-abbreviations and show-abbreviations.

11.4 ACL2-PC::BASH

ACL2-PC::BASH (atomic macro) call the ACL2 theorem prover’s simplifier

     Examples:
     bash -- attempt to prove the current goal by simplification alone
     (bash ("Subgoal 2" :by foo) ("Subgoal 1" :use bar))
          -- attempt to prove the current goal by simplification alone,
             with the indicated hints
     General Form:
     (bash &rest hints)

Call the theorem prover’s simplifier, creating a subgoal for each resulting goal.

Notice that unlike prove, the arguments to bash are spread out, and are all hints.

Note: All forcing rounds will be skipped (unless there are more than 15 subgoals generated in the first forcing round, an injustice that should be rectified by the next release).

11.5 ACL2-PC::BDD

ACL2-PC::BDD (atomic macro) prove the current goal using bdds

     Examples:
     bdd
     (bdd :vars nil :bdd-constructors (cons) :prove t :literal :all)

The general form is as shown in the latter example above, but with any keyword-value pairs omitted and with values as described for the :bdd (BDD^) hint; see Section 8.43 [HINTS], page 319.

This command simply calls the theorem prover with the indicated bdd hint for the top-level goal. Note that if :prove is t (the default), then the proof will succeed entirely using bdds or else it will fail immediately. See Chapter 2 [BDD], page 71.

11.6 ACL2-PC::BK

ACL2-PC::BK (atomic macro) move backward one argument in the enclosing term

     Example and General Form:
     bk

For example, if the conclusion is (= x (* (- y) z)) and the current subterm is (* (- y) z), then after executing bk, the current subterm will be x.

Move to the previous argument of the enclosing term.

This is the same as up followed by (dive n-1), where n is the position of the current subterm in its parent term in the conclusion. Thus in particular, the nx command fails if one is already at the top of the conclusion.

See also up, dive, top, and bk.

11.7 ACL2-PC::BOOKMARK

ACL2-PC::BOOKMARK (macro) insert matching “bookends” comments

     Example:
     (bookmark final-goal)
     General Form:
     (bookmark name &rest instruction-list)

Run the instructions in instruction-list (as though this were a call of do-all; see the documentation for do-all), but first insert a begin bookend with the given name and then, when the instructions have been completed, insert an end bookend with that same name. See the documentation of comm for an explanation of bookends and how they can affect the display of instructions.

11.8 ACL2-PC::CASESPLIT

ACL2-PC::CASESPLIT (primitive) split into two cases

     Example:
     (casesplit (< x y)) -- assuming that we are at the top of the
                            conclusion, add (< x y) as a new top-level
                            hypothesis in the current goal, and create a
                            subgoal identical to the current goal except
                            that it has (not (< x y)) as a new top-level
                            hypothesis
     General Form:
     (casesplit expr &optional use-hyps-flag do-not-flatten-flag)

When the current subterm is the entire conclusion, this instruction adds expr as a new top-level hypothesis, and create a subgoal identical to the existing current goal except that it has the negation of expr as a new top-level hypothesis. See also claim. The optional arguments control the use of governors and the “flattening” of new hypotheses, as we now explain.

The argument use-hyps-flag is only of interest when there are governors. (To read about governors, see the documentation for the command hyps). In that case, if use-hyps-flag is not supplied or is nil, then the description above is correct; but otherwise, it is not expr but rather it is (implies govs expr) that is added as a new top-level hypothesis (and whose negation is added as a top-level hypothesis for the new goal), where govs is the conjunction of the governors.

If do-not-flatten-flag is supplied and not nil, then that is all there is to this command. Otherwise (thus this is the default), when the claimed term (first argument) is a conjunction (and) of terms and the claim instruction succeeds, then each (nested) conjunct of the claimed term is added as a separate new top-level hypothesis. Consider the following example, assuming there are no governors.

     (casesplit (and (and (< x y) (integerp a)) (equal r s)) t)

Three new top-level hypotheses are added to the current goal, namely (< x y), (integerp a), and (equal r s). In that case, only one hypothesis is added to create the new goal, namely the negation of (and (< x y) (integerp a) (equal r s)). If the negation of this term had been claimed, then it would be the other way around: the current goal would get a single new hypothesis while the new goal would be created by adding three hypotheses.

Note: It is allowed to use abbreviations in the hints.

11.9 ACL2-PC::CG

ACL2-PC::CG (macro) change to another goal.

     Examples:
     (cg (main . 1)) -- change to the goal (main . 1)
     cg              -- change to the next-to-top goal
     General Form:
     (CG &OPTIONAL goal-name)

Same as (change-goal goal-name t), i.e. change to the indicated and move the current goal to the end of the goal stack.

11.10 ACL2-PC::CHANGE-GOAL

ACL2-PC::CHANGE-GOAL (primitive) change to another goal.

     Examples:
     (change-goal (main . 1)) -- change to the goal (main . 1)
     change-goal              -- change to the next-to-top goal
     General Form:
     (change-goal &optional goal-name end-flg)

Change to the goal with the name goal-name, i.e. make it the current goal. However, if goal-name is nil or is not supplied, then it defaults to the next-to-top goal, i.e., the second goal in the stack of goals. If end-flg is supplied and not nil, then move the current goal to the end of the goal stack; else merely swap it with the next-to-top goal. Also see documentation for cg.

11.11 ACL2-PC::CLAIM

ACL2-PC::CLAIM (atomic macro) add a new hypothesis

     Examples:
     (claim (< x y))   -- attempt to prove (< x y) from the current
                          top-level hypotheses and if successful, then
                          add (< x y) as a new top-level hypothesis in
                          the current goal

     (claim (< x y)
            :otf-flg t
            :hints (("Goal" :induct t)))
                       -- as above, but call the prover using the
                          indicated values for the otf-flg and hints
     (claim (< x y) 0) -- as above, except instead of attempting to
                          prove (< x y), create a new subgoal with the
                          same top-level hypotheses as the current goal
                          that has (< x y) as its conclusion
     (claim (< x y) :hints :none)
                       -- same as immediately above
     General Form:
     (claim expr &rest rest-args)

This command creates a new subgoal with the same top-level hypotheses as the current goal but with a conclusion of expr. If rest-args is a non-empty list headed by a non-keyword, then there will be no proof attempted for the new subgoal. With that possible exception, rest-args should consist of keyword arguments. The keyword argument :do-not-flatten controls the “flattening” of new hypotheses, just as with the casesplit command (as described in its documentation). The remaining rest-args are used with a call the prove command on the new subgoal, except that if :hints is a non-nil atom, then the prover is not called — rather, this is the same as the situation described above, where rest-args is a non-empty list headed by a non-keyword.

Notes: (1) Unlike the casesplit command, the claim command is completely insensitive to governors. (2) It is allowed to use abbreviations in the hints. (3) The keyword :none has the special role as a value of :hints that is shown clearly in an example above.

11.12 ACL2-PC::COMM

ACL2-PC::COMM (macro) display instructions from the current interactive session

     Examples:
     comm
     (comm 10)
     General Form:
     (comm &optional n)

Prints out instructions in reverse order. This is actually the same as (commands n t) — or, (commands nil t) if n is not supplied. As explained in the documentation for commands, the final argument of t causes suppression of instructions occurring between so-called “matching bookends,” which we now explain.

A “begin bookend” is an instruction of the form

     (COMMENT :BEGIN x . y).

Similarly, an “end bookend” is an instruction of the form

     (COMMENT :END x' . y').

The “name” of the first bookend is x and the “name” of the second bookend is x'. When such a pair of instructions occurs in the current state-stack, we call them “matching bookends” provided that they have the same name (i.e. x equals x') and if no other begin or end bookend with name x occurs between them. The idea now is that comm hides matching bookends together with the instructions they enclose. Here is a more precise explanation of this “hiding”; probably there is no value in reading on!

A comm instruction hides bookends in the following manner. (So does a comment instruction when its second optional argument is supplied and non-nil.) First, if the first argument n is supplied and not nil, then we consider only the last n instructions from the state-stack; otherwise, we consider them all. Now the resulting list of instructions is replaced by the result of applying the following process to each pair of matching bookends: the pair is removed, together with everything in between the begin and end bookend of the pair, and all this is replaced by the “instruction”

     ("***HIDING***" :COMMENT :BEGIN name ...)

where (comment begin name ...) is the begin bookend of the pair. Finally, after applying this process to each pair of matching bookends, each begin bookend of the form (comment begin name ...) that remains is replaced by

     ("***UNFINISHED***" :COMMENT :BEGIN name ...) .

11.13 ACL2-PC::COMMANDS

ACL2-PC::COMMANDS (macro) display instructions from the current interactive session

Examples:
commands
(commands 10 t)
General Forms:
commands or (commands nil)
Print out all the instructions (in the current state-stack) in
reverse order, i.e. from the most recent instruction to the starting
instruction.
(commands n) [n a positive integer]
Print out the most recent n instructions (in the current
state-stack), in reverse order.
(commands x abbreviate-flag)
Same as above, but if abbreviate-flag is non-NIL, then do not
display commands between ``matching bookends''.  See documentation
for comm for an explanation of matching bookends.

Note: If there are more than n instructions in the state-stack, then (commands n) is the same as

commands (and also, (commands n abb) is the same as (commands nil abb)).

11.14 ACL2-PC::COMMENT

ACL2-PC::COMMENT (primitive) insert a comment

Example:
(comment now begin difficult final goal)
General Form:
(comment &rest x)

This instruction makes no change in the state except to insert the comment instruction.

Some comments can be used to improve the display of commands; see documentation for comm.

11.15 ACL2-PC::CONTRADICT

ACL2-PC::CONTRADICT (macro)

same as contrapose

see documentation for contrapose

11.16 ACL2-PC::CONTRAPOSE

ACL2-PC::CONTRAPOSE (primitive) switch a hypothesis with the conclusion, negating both

     Example:
     (contrapose 3)
     General Form:
     (contrapose &optional n)

The (optional) argument n should be a positive integer that does not exceed the number of hypotheses. Negate the current conclusion and make it the nth hypothesis, while negating the current nth hypothesis and making it the current conclusion. If no argument is supplied then the effect is

the same as for (contrapose 1).

Note: By “negate” we mean an operation that replaces nil by t, x by nil for any other explicit value x, (not x) by x, and any other x by (not x).

11.17 ACL2-PC::DEMOTE

ACL2-PC::DEMOTE (primitive) move top-level hypotheses to the conclusion

     Examples:
     demote        -- demote all top-level hypotheses
     (demote 3 5)  -- demote hypotheses 3 and 5

For example, if the top-level hypotheses are x and y and the conclusion is z, then after execution of demote, the conclusion will be (implies (and x y) z) and there will be no (top-level) hypotheses.

     General Form:
     (demote &rest hyps-indices)

Eliminate the indicated (top-level) hypotheses, but replace the conclusion conc with (implies hyps conc) where hyps is the conjunction of the hypotheses that were eliminated. If no arguments are supplied, then all hypotheses are demoted, i.e. demote is the same as (demote 1 2 ... n) where n is the number of top-level hypotheses.

Note: You must be at the top of the conclusion in order to use this command. Otherwise, first invoke top. Also, demote fails if there are no top-level hypotheses or if indices are supplied that are out of range.

11.18 ACL2-PC::DIVE

ACL2-PC::DIVE (primitive) move to the indicated subterm

     Examples:
     (DIVE 1)    -- assign the new current subterm to be the first
                    argument of the existing current subterm
     (DIVE 1 2)  -- assign the new current subterm to be the result of
                    first taking the 1st argument of the existing
                    current subterm, and then the 2nd argument of that

For example, if the current subterm is

     (* (+ a b) c),

then after (dive 1) it is

     (+ a b).

If after that, then (dive 2) is invoked, the new current subterm will be

     b.

Instead of (dive 1) followed by (dive 2), the same current subterm could be obtained by instead submitting the single instruction (dive 1 2).

     General Form:
     (dive &rest naturals-list)

If naturals-list is a non-empty list (n_1 ... n_k) of natural numbers, let the new current subterm be the result of selecting the n_1-st argument of the current subterm, and then the n_2-th subterm of that, ..., finally the n_k-th subterm.

Note: Dive is related to the command pp, in that the diving is done according to raw (translated, internal form) syntax. Use the command dv if you want to dive according to the syntax displayed by the command p. Note that (dv n) can be abbreviated by simply n.

11.19 ACL2-PC::DO-ALL

ACL2-PC::DO-ALL (macro) run the given instructions

     Example:
     (do-all induct p prove)
     General Form:
     (do-all &rest instruction-list)

Run the indicated instructions until there is a hard “failure”. The instruction “succeeds” if and only if each instruction in instruction-list does. (See the documentation for sequence for an explanation of “success” and “failure.”) As each instruction is executed, the system will print the usual prompt followed by that instruction, unless the global state variable print-prompt-and-

instr-flg is nil.

Note: If do-all “fails”, then the failure is hard if and only if the last instruction it runs has a hard “failure”.

Obscure point: For the record, (do-all ins_1 ins_2 ... ins_k) is the same as (sequence

(ins_1 ins_2 ... ins_k)).

11.20 ACL2-PC::DO-ALL-NO-PROMPT

ACL2-PC::DO-ALL-NO-PROMPT (macro) run the given instructions, halting once there is a “failure”

     Example:
     (do-all-no-prompt induct p prove)

     General Form:
     (do-all-no-prompt &rest instruction-list)

Do-all-no-prompt is the same as do-all, except that the prompt and instruction are not printed each time, regardless of the value of print-prompt-and-instr-flg. Also, restoring is disabled. See the documentation for do-all.

11.21 ACL2-PC::DO-STRICT

ACL2-PC::DO-STRICT (macro) run the given instructions, halting once there is a “failure”

     Example:
     (do-strict induct p prove)
     General Form:
     (do-strict &rest instruction-list)

Run the indicated instructions until there is a (hard or soft) “failure”. In fact do-strict is identical in effect to do-all, except that do-all only halts once there is a hard “failure”. See the documentation for do-all.

11.22 ACL2-PC::DROP

ACL2-PC::DROP (primitive) drop top-level hypotheses

     Examples:
     (drop 2 3) -- drop the second and third hypotheses
     drop       -- drop all top-level hypotheses
     General Forms:
     (drop n1 n2 ...) -- Drop the hypotheses with the indicated indices.
     drop             -- Drop all the top-level hypotheses.

Note: If there are no top-level hypotheses, then the instruction drop will fail. If any of the indices is out of range, i.e. is not an integer between one and the number of top-level hypotheses (inclusive),

then (drop n1 n2 ...) will fail.

11.23 ACL2-PC::DV

ACL2-PC::DV (atomic macro) move to the indicated subterm

     Examples:
     (dv 1)    -- assign the new current subterm to be the first argument
                  of the existing current subterm
     (dv 1 2)  -- assign the new current subterm to be the result of
                  first taking the 1st argument of the existing
                  current subterm, and then the 2nd argument of that

For example, if the current subterm is

     (* (+ a b) c),

then after (dv 1) it is

     (+ a b).

If after that, then (dv 2) is invoked, the new current subterm will be

     b.

Instead of (dv 1) followed by (dv 2), the same current subterm could be obtained by instead submitting the single instruction (dv 1 2).

     General Form:
     (dv &rest naturals-list)

If naturals-list is a non-empty list (n_1 ... n_k) of natural numbers, let the new current subterm be the result of selecting the n_1-st argument of the current subterm, and then the n_2-th subterm of that, ..., finally the n_k-th subterm.

Note: (dv n) may be abbreviated by simply n, so we could have typed 1 instead of (dv 1) in the first example above.

Note: See also dive, which is related to the command pp, in that the diving is done according to raw (translated, internal form) syntax. Use the command dv if you want to dive according to the syntax displayed by the command p.

11.24 ACL2-PC::ELIM

ACL2-PC::ELIM (atomic macro) call the ACL2 theorem prover’s elimination process

     Example and General Form:
     elim

Upon running the elim command, the system will create a subgoal will be created for each goal that would have been pushed for proof by induction in an ordinary proof, where only elimination is used; not even simplification is used!

11.25 ACL2-PC::EQUIV

ACL2-PC::EQUIV (primitive) attempt an equality (or congruence-based) substitution

     Examples:
     (equiv (* x y) 3) -- replace (* x y) by 3 everywhere inside the
                          current subterm, if their equality is among the
                          top-level hypotheses or the governors
     (equiv x t iff)   -- replace x by t everywhere inside the current
                          subterm, where only propositional equivalence
                          needs to be maintained at each occurrence of x
     General form:
     (equiv old new &optional relation)

Substitute new for old everywhere inside the current subterm, provided that either (relation old new) or (relation new old) is among the top-level hypotheses or the governors (possibly by way of backchaining and/or refinement; see below). If relation is nil or is not supplied, then it defaults to equal. See also the command =, which is much more flexible. Note that this command fails if no substitution is actually made.

Note: No substitution takes place inside explicit values. So for example, the instruction (equiv 3 x) will cause 3 to be replaced by x if the current subterm is, say, (* 3 y), but not if the current subterm is (* 4 y) even though 4 = (1+ 3).

The following remarks are quite technical and mostly describe a certain weak form of “backchaining” that has been implemented for equiv in order to support the = command. In fact neither the term (relation old new) nor the term (relation new old) needs to be explicitly among the current “assumptions”, i.e., the top-level hypothesis or the governors. Rather, there need only be such an assumption that “tells us” (r old new) or (r new old), for some equivalence relation r that refines relation. Here, “tells us” means that either one of the indicated terms is among those assumptions, or else there is an assumption that is an implication whose conclusion is one of the indicated terms and whose hypotheses (gathered up by appropriately flattening the first argument of the implies term) are all among the current assumptions.

11.26 ACL2-PC::EX

ACL2-PC::EX (macro) exit after possibly saving the state

     Example and General Form:
     ex

Same as exit, except that first the instruction save is executed.

If save queries the user and is answered negatively, then the exit is aborted.

11.27 ACL2-PC::EXIT

ACL2-PC::EXIT (meta) exit the interactive proof-checker

     Examples:
     exit                        -- exit the interactive proof-checker
     (exit append-associativity) -- exit and create a defthm
                                    event named append-associativity
     General Forms:
     exit --  Exit without storing an event.
     (exit event-name &optional rule-classes do-it-flg)
     Exit, and store an event.

The command exit returns you to the ACL2 loop. At a later time, (verify) may be executed to get back into the same proof-checker state, as long as there hasn’t been an intervening use of the proof-checker (otherwise see save).

When given one or more arguments as shown above, exit still returns you to the ACL2 loop, but first, if the interactive proof is complete, then it attempts create a defthm event with the specified event-name and rule-classes (which defaults to (:rewrite) if not supplied). The event will be printed to the terminal, and then normally the user will be queried whether an event should really be created. However, if the final optional argument do-it-flg is supplied and not nil, then an event will be made without a query.

For example, the form

     (exit top-pop-elim (:elim :rewrite) t)

causes a defthm event named top-pop-elim to be created with rule-classes (:elim :rewrite), without a query to the user (because of the argument t).

Note: it is permitted for event-name to be nil. In that case, the name of the event will be the name supplied during the original call of verify. (See the documentation for verify and commands.) Also in that case, if rule-classes is not supplied then it defaults to the rule-classes supplied in the original call of verify.

Comments on “success” and “failure”. An exit instruction will always “fail”, so for example, if it appears as an argument of a do-strict instruction then none of the later (instruction) arguments will be executed. Moreover, the “failure” will be “hard” if an event is successfully created or if the instruction is simply exit; otherwise it will be “soft”. See the documentation for sequence for an explanation of hard and soft “failures”. An obscure but potentially important fact is that if the “failure” is hard, then the error signal is a special signal that the top-level interactive loop can interpret as a request to exit. Thus for example, a sequencing command that turns an error triple (mv erp val state) into (mv t val state) would never cause an exit from the interactive loop.

If the proof is not complete, then (exit event-name ...) will not cause an exit from the interactive loop. However, in that case it will print out the original user-supplied goal (the one that was supplied with the call to verify) and the current list of instructions.

11.28 ACL2-PC::EXPAND

ACL2-PC::EXPAND (primitive) expand the current function call without simplification

     Examples:
     expand -- expand and do not simplify.

For example, if the current subterm is (append a b), then after (expand t) the current subterm will be the term:

     (if (true-listp x)
         (if x
             (cons (car x) (append (cdr x) y))
           y)
       (apply 'binary-append (list x y)))

regardless of the top-level hypotheses and the governors.

     General Form:
     (expand &optional
             do-not-expand-lambda-flg new-goals-flg keep-all-guards-flg)

Expand the function call at the current subterm, and do not simplify. The options have the following meanings:

     do-not-expand-lambda-flg:   default is nil; otherwise, the result
                                 should be a lambda expression
     new-goals-flg:       default of nil means to introduce APPLY for guards
     keep-all-guards-flg: default of nil means that the system should make
                          a weak attempt to prove the guards from the
                          current context

See also x, which allows simplification.

11.29 ACL2-PC::FAIL

ACL2-PC::FAIL (macro) cause a failure

     Examples:

     fail
     (fail t)
     General Form:
     (fail &optional hard)

This is probably only of interest to writers of macro commands. The only function of fail is to fail to “succeed”.

The full story is that fail and (fail nil) simply return (mv nil nil state), while (fail

hard) returns (mv hard nil state) if hard-flag is not nil. See also do-strict, do-all, and
sequence.

11.30 ACL2-PC::FORWARDCHAIN

ACL2-PC::FORWARDCHAIN (atomic macro) forward chain from an implication in the hyps

     Example:
     (forwardchain 2) ; Second hypothesis should be of the form
                      ; (IMPLIES hyp concl), and the result is to replace
                      ; that hypothesis with concl.

     General Forms:
     (forwardchain hypothesis-number)
     (forwardchain hypothesis-number hints)
     (forwardchain hypothesis-number hints quiet-flg)

This command replaces the hypothesis corresponding to given index, which should be of the form (IMPLIES hyp concl), with its consequent concl. In fact, the given hypothesis is dropped, and the replacement hypothesis will appear as the final hypothesis after this command is executed.

The prover must be able to prove the indicated hypothesis from the other hypotheses, or else the command will fail. The :hints argument is used in this prover call, and should have the usual syntax of hints to the prover.

Output is suppressed if quiet-flg is supplied and not nil.

11.31 ACL2-PC::FREE

ACL2-PC::FREE (atomic macro) create a “free variable”

     Example:
     (free x)
     General Form:
     (free var)

Mark var as a “free variable”. Free variables are only of interest for the put command; see its documentation for an explanation.

11.32 ACL2-PC::GENERALIZE

ACL2-PC::GENERALIZE (primitive) perform a generalization

     Example:
     (generalize
      ((and (true-listp x) (true-listp y)) 0)
      ((append x y) w))
     General Form:
     (generalize &rest substitution)

Generalize using the indicated substitution, which should be a non-empty list. Each element of that list should be a two-element list of the form (term variable), where term may use abbreviations. The effect of the instruction is to replace each such term in the current goal by the corresponding variable. This replacement is carried out by a parallel substitution, outside-in in each hypothesis and in the conclusion. More generally, actually, the “variable” (second) component of each pair may be nil or a number, which causes the system to generate a new name of the form _or _n, with n a natural number; more on this below. However, when a variable is supplied, it must not occur in any goal of the current proof-checker state.

When the “variable” above is nil, the system will treat it as the variable |_| if that variable does not occur in any goal of the current proof-checker state. Otherwise it treats it as |_0|, or |_1|, or |_2|, and so on, until one of these is not among the variables of the current proof-checker state. If the “variable” is a non-negative integer n, then the system treats it as |_n| unless that variable already occurs among the current goals, in which case it increments n just as above until it obtains a new variable.

Note: The same variable may not occur as the variable component of two different arguments (though nil may occur arbitrarily many times, as may a positive integer).

11.33 ACL2-PC::GOALS

ACL2-PC::GOALS (macro) list the names of goals on the stack

     Example and General Form:
     goals

Goals lists the names of all goals that remain to be proved. They are listed in the order in which they appear on the stack of remaining goals, which is relevant for example to the effect of a change-goal instruction.

11.34 ACL2-PC::HELP

ACL2-PC::HELP (macro) proof-checker help facility

     Examples:
     (help rewrite) -- partial documentation on the rewrite command; the
                       rest is available using more or more!
     (help! rewrite) -- full documentation on the rewrite command
     help, help!     -- this documentation (in part, or in totality,
                        respectively)
     General Forms:
     (help &optional command)
     (help! &optional command)
     more
     more!

The proof checker supports the same kind of documentation as does ACL2 proper. The main difference is that you need to type

     (help command)

in a list rather than :doc command. So, to get all the documentation on command, type (help! command) inside the interactive loop, but to get only a one-line description of the command together with some examples, type (help command). In the latter case, you can get the rest of the help by typing more!; or type more if you don’t necessarily want all the rest of the help at once. (Then keep typing more if you want to keep getting more of the help for that command.)

To summarize: as with ACL2, you can type either of the following:

     more, more!
     -- to obtain more (or, all the rest of) the documentation last
        requested by help (or, outside the proof-checker's loop, :doc)

It has been arranged that the use of (help command) will tell you just about everything you could want to know about command, almost always by way of examples. For more details about a command, use help!, more, or more!.

We use the word “command” to refer to the name itself, e.g. rewrite. We use the word “instruction” to refer to an input to the interactive system, e.g. (rewrite foo) or (help split). Of course, we allow commands with no arguments as instructions in many cases, e.g. rewrite. In such cases, command is treated identically to (command).

11.35 ACL2-PC::HELP!

ACL2-PC::HELP! (macro) proof-checker help facility

Same as help, except that the entire help message is printed without any need to invoke more! or

more.

Invoke help for documentation about the proof-checker help facility.

11.36 ACL2-PC::HELP-LONG

ACL2-PC::HELP-LONG (macro) same as help!

See the documentation for help!.

Help-long has been included in addition to help! for historical reasons. (Such a command is included in Pc-Nqthm).

11.37 ACL2-PC::HYPS

ACL2-PC::HYPS (macro) print the hypotheses

     Examples:
     hyps               -- print all (top-level) hypotheses
     (hyps (1 3) (2 4)) -- print hypotheses 1 and 3 and governors 2 and 4
     (hyps (1 3) t)     -- print hypotheses 1 and 3 and all governors
     General Form:
     (hyps &optional hyps-indices govs-indices)

Print the indicated top-level hypotheses and governors. (The notion of “governors” is defined below.) Here, hyps-indices and govs-indices should be lists of indices of hypotheses and governors (respectively), except that the atom t may be used to indicate that one wants all hypotheses or governors (respectively).

The list of “governors” is defined as follows. Actually, we define here the notion of the governors for a pair of the form <term, address>]; we’re interested in the special case where the term is the conclusion and the address is the current address. If the address is nil, then there are no governors, i.e., the list of governors is nil. If the term is of the form (if x y z) and the address is of the form (2 . rest) or (3 . rest), then the list of governors is the result of consing x or its negation (respectively) onto the list of governors for the pair <y, rest> or the pair <z, rest> (respectively). If the term is of the form (implies x y) and the address is of the form (2 . rest), then the list of governors is the result of consing x onto the list of governors for the pair <y, rest>. Otherwise, the list of governors for the pair <term, (n . rest)> is exactly the list of governors for the pair <argn, rest> where argn is the nth argument of term.

If all goals have been proved, a message saying so will be printed. (as there will be no current hypotheses or governors!).

The hyps command never causes an error. It “succeeds” (in fact its value is t) if the arguments (when supplied) are appropriate, i.e. either t or lists of indices of hypotheses or governors, respectively. Otherwise it “fails” (its value is nil).

11.38 ACL2-PC::ILLEGAL

ACL2-PC::ILLEGAL (macro) illegal instruction

     Example:
     (illegal -3)
     General Form:
     (illegal instruction)

Probably not of interest to most users; always “fails” since it expands to the fail command.

The illegal command is used mainly in the implementation. For example, the instruction 0 is “read” as (illegal 0), since dive expects positive integers.

11.39 ACL2-PC::IN-THEORY

ACL2-PC::IN-THEORY (primitive) set the current proof-checker theory

     Example:
     (in-theory
        (union-theories *s-prop-theory* '(true-listp binary-append)))
     General Form:
     (in-theory &optional atom-or-theory-expression)

If the argument is not supplied, then this command sets the current proof-checker theory (see below for explanation) to agree with the current ACL2 theory. Otherwise, the argument should be a theory expression, and in that case the proof-checker theory is set to the value of that theory expression.

The current proof-checker theory is used in all calls to the ACL2 theorem prover and rewriter from inside the proof-checker. Thus, the most recent in-theory instruction in the current state-stack has an effect in the proof-checker totally analogous to the effect caused by an in-theory hint or event in ACL2. However, in-theory instructions in the proof-checker have no effect outside the proof-checker’s interactive loop.

If the most recent in-theory instruction in the current state of the proof-checker has no arguments, or if there is no in-theory instruction in the current state of the proof-checker, then the proofchecker will use the current ACL2 theory. This is true even if the user has interrupted the interactive loop by exiting and changing the global ACL2 theory. However, if the most recent in-theory instruction in the current state of the proof-checker had an argument, then global changes to the current theory will have no effect on the proof-checker state.

11.40 ACL2-PC::INDUCT

ACL2-PC::INDUCT (atomic macro) generate subgoals using induction

     Examples:
     induct, (induct t)
        -- induct according to a heuristically-chosen scheme, creating
           a new subgoal for each base and induction step
     (induct (append (reverse x) y))
        -- as above, but choose an induction scheme based on the term
           (append (reverse x) y) rather than on the current goal
     General Form:
     (induct &optional term)

Induct as in the corresponding :induct hint given to the theorem prover, creating new subgoals for the base and induction steps. If term is t or is not supplied, then use the current goal to determine the induction scheme; otherwise, use that term.

Note: As usual, abbreviations are allowed in the term.

Note: Induct actually calls the prove command with all processes turned off. Thus, you must be at top of the goal for an induct instruction.

11.41 ACL2-PC::LISP

ACL2-PC::LISP (meta) evaluate the given form in Lisp

     Example:
     (lisp (assign xxx 3))
     General Form:
     (lisp form)

Evaluate form. The lisp command is mainly of interest for side effects. See also print, skip, and

fail.

The rest of the documentation for lisp is of interest only to those who use it in macro commands. If the Lisp evaluation (by trans-eval) of form returns an “error triple” of the form (mv erp (cons 3 val) &), then val is of the form (erp-1 val-1 &), and the lisp command returns the appropriate error triple

     (mv (or erp erp-1)
         val-1
         state) .

Otherwise, the trans-eval of form must return an “error triple” of the form (mv erp (list* state-out mult val) &), and the lisp command returns the appropriate error triple

     (mv erp
         val
         state) .

11.42 ACL2-PC::MORE

ACL2-PC::MORE (macro) proof-checker help facility

Continues documentation of last proof-checker command visited with help.

Invoke help for documentation about the proof-checker help facility.

11.43 ACL2-PC::MORE!

ACL2-PC::MORE! (macro) proof-checker help facility Continues documentation of last proof-checker command visited with help, until all documentation on that command is printed out. Invoke help for documentation about the proof-checker help facility.

11.44 ACL2-PC::NEGATE

ACL2-PC::NEGATE (macro) run the given instructions, and “succeed” if and only if they “fail” Example: (negate prove)

     General form:
     (negate &rest instruction-list)

Run the indicated instructions exactly in the sense of do-all, and “succeed” if and only if they “fail”. Note: Negate instructions will never produce hard “failures”.

11.45 ACL2-PC::NIL

ACL2-PC::NIL (macro) used for interpreting control-d

     Example and General form:
     nil
(or, control-d).

The whole point of this command is that in some Lisps (including akcl), if you type control-d then it seems, on occasion, to get interpreted as nil. Without this command, one seems to get into an infinite loop.

11.46 ACL2-PC::NOISE

ACL2-PC::NOISE (meta) run instructions with output

     Example:
     (noise induct prove)
     General Form:
     (noise &rest instruction-list)

Run the instruction-list through the top-level loop with output.

In fact, having output is the default. Noise is useful inside a surrounding call of quiet, when one temporarily wants output. For example, if one wants to see output for a prove command immediately following an induct command but before an s command, one may want to submit an

instruction like (quiet induct (noise prove) s). See also quiet.

11.47 ACL2-PC::NX

ACL2-PC::NX (atomic macro) move forward one argument in the enclosing term

     Example and General Form:
     nx

For example, if the conclusion is (= x (* (- y) z)) and the current subterm is x, then after executing nx, the current subterm will be (* (- y) z).

This is the same as up followed by (dive n+1), where n is the position of the current subterm in its parent term in the conclusion. Thus in particular, the nx command fails if one is already at the top of the conclusion.

See also up, dive, top, and bk.

11.48 ACL2-PC::ORELSE

ACL2-PC::ORELSE (macro) run the first instruction; if (and only if) it “fails”, run the second

     Example:
     (orelse top (print "Couldn't move to the top"))
     General form:
     (orelse instr1 instr2)

Run the first instruction. Then if it “fails”, run the second instruction also; otherwise, stop after the first.

This instruction “succeeds” if and only if either instr1 “succeeds”, or else instr2 “succeeds”. If it “fails”, then the failure is soft.

11.49 ACL2-PC::P

ACL2-PC::P (macro) prettyprint the current term

     Example and General Form:
     p

Prettyprint the current term. The usual user syntax is used, so that for example one would see (and x y) rather than (if x y 'nil). (See also pp.) Also, abbreviations are inserted where

appropriate; see add-abbreviation.

The “current term” is the entire conclusion unless dive commands have been given, in which case it may be a subterm of the conclusion.

If all goals have been proved, a message saying so will be printed (as there will be no current term!).

11.50 ACL2-PC::P-TOP

ACL2-PC::P-TOP (macro) prettyprint the conclusion, highlighting the current term

     Example and General Form:

     p-top

For example, if the conclusion is (equal (and x (p y)) (foo z)) and the current subterm is (p

y), then p-top will print (equal (and x (*** (p y) ***)) (foo z)).

Prettyprint the the conclusion, highlighting the current term. The usual user syntax is used, as with the command p (as opposed to pp). This is illustrated in the example above, where one would

*not* see (equal (if x (*** (p y) ***) 'nil) (foo z)).

Note (obscure): In some situations, a term of the form (if x t y) occurring inside the current subterm will not print as (or x y), when x isn’t a call of a boolean primitive. There’s nothing incorrect about this, however.

11.51 ACL2-PC::PP

ACL2-PC::PP (macro) prettyprint the current term

     Example and General Form:
     pp

This is the same as p (see its documentation), except that raw syntax (internal form) is used. So for example, one would see (if x y 'nil) rather than (and x y). Abbreviations are however still inserted, as with p.

11.52 ACL2-PC::PRINT

ACL2-PC::PRINT (macro) print the result of evaluating the given form

     Example:
     (print (append '(a b) '(c d)))
     Print the list (a b c d) to the terminal
     General Form:
     (print form)

Prettyprints the result of evaluating form. The evaluation of form should return a single value that is not state. If the form you want to evaluate does not satisfy the criterion above, you should create an appropriate call of the lisp command instead. Notice that this command always returns (mv nil

state state).

11.53 ACL2-PC::PRINT-ALL-GOALS

ACL2-PC::PRINT-ALL-GOALS (macro) print all the (as yet unproved) goals Example and General Form: print-all-goals Prints all the goals that remain to be proved, in a pleasant format.

11.54 ACL2-PC::PRINT-MAIN

ACL2-PC::PRINT-MAIN (macro) print the original goal

     Example and General Form:
     print-main

Prints the goal as originally entered.

11.55 ACL2-PC::PRO

ACL2-PC::PRO (atomic macro) repeatedly apply promote

     Example and General Form:
     pro

Apply the promote command until there is no change. This command “succeeds” exactly when at least one call of promote “succeeds”. In that case, only a single new proof-checker state will be created.

11.56 ACL2-PC::PROMOTE

ACL2-PC::PROMOTE (primitive) move antecedents of conclusion’s implies term to top-level hypotheses

     Examples:
     promote
     (promote t)

For example, if the conclusion is (implies (and x y) z), then after execution of promote, the conclusion will be z and the terms x and y will be new top-level hypotheses.

     General Form:
     (promote &optional do-not-flatten-flag)

Replace conclusion of (implies hyps exp) or (if hyps exp t) with simply exp, adding hyps to the list of top-level hypotheses. Moreover, if hyps is viewed as a conjunction then each conjunct will be added as a separate top-level hypothesis. An exception is that if do-not-flatten-flag is supplied and not nil, then only one top-level hypothesis will be added, namely hyps.

Note: You must be at the top of the conclusion in order to use this command. Otherwise, first invoke top.

11.57 ACL2-PC::PROTECT

ACL2-PC::PROTECT (macro) run the given instructions, reverting to existing state upon failure

     Example:
     (protect induct p prove)
     General Form:
     (protect &rest instruction-list)

Protect is the same as do-strict, except that as soon as an instruction “fails”, the state-stack reverts to what it was before the protect instruction began, and restore is given the same meaning that it had before the protect instruction began. See the documentation for do-strict.

11.58 ACL2-PC::PROVE

ACL2-PC::PROVE (primitive) call the ACL2 theorem prover to prove the current goal

     Examples:
     prove -- attempt to prove the current goal
     (prove :otf-flg t
            :hints (("Subgoal 2" :by foo) ("Subgoal 1" :use bar)))
           -- attempt to prove the current goal, with the indicated hints
              and with OTF-FLG set
     General Form:
     (prove &rest rest-args)

Attempt to prove the current goal, where rest-args is as in the keyword arguments to defthm except that only :hints and :otf-flg are allowed. The command succeeds exactly when the corresponding defthm would succeed, except that it is all right for some goals to be given “bye”s. Each goal given a “bye” will be turned into a new subgoal. (See Section 8.43 [HINTS], page 319 for an explanation of :by hints.)

Note: Use (= t) instead if you are not at the top of the conclusion. Also note that if there are any hypotheses in the current goal, then what is actually attempted is a proof of (implies hyps conc), where hyps is the conjunction of the top-level hypotheses and conc is the goal’s conclusion.

Note: It is allowed to use abbreviations in the hints.

11.59 ACL2-PC::PUT

ACL2-PC::PUT (macro) substitute for a “free variable”

     Example:
     (put x 17)

     General Form:
     (put var expr)

Substitute expr for the “free variable” var, as explained below.

A “free variable” is, for our purposes, a variable var such that the instruction (free var) has been executed earlier in the state-stack. What (free var) really does is to let var be an abbreviation

for the term (hide var) (see documentation for add-abbreviation). What (put var expr)

really does is to unwind the state-stack, replacing that free instruction with the instruction (addabbreviation var expr), so that future references to (? var) become reference to expr rather than to (hide var), and then to replay all the other instructions that were unwound. Because hide was used, the expectation is that in most cases, the instructions will replay successfully and put will “succeed”. However, if any replayed instruction “fails”, then the entire replay will abort and “fail”, and the state-stack will revert to its value before the put instruction was executed.

If (put var expr) “succeeds”, then (remove-abbreviation var) will be executed at the end.

Note: The restore command will revert the state-stack to its value present before the put instruction was executed.

11.60 ACL2-PC::QUIET

ACL2-PC::QUIET (meta) run instructions without output

     Example:
     (quiet induct prove)
     General Form:
     (quiet &rest instruction-list)

Run the instruction-list through the top-level loop with no output.

See also noise.

11.61 ACL2-PC::R

ACL2-PC::R (macro) same as rewrite

     Example:
     (r 3)
     General Form:
     (rewrite &optional rule-id substitution
              ;; below are rare arguments, used for disambiguation:
              target-lhs target-rhs target-hyps target-equiv)

See the documentation for rewrite, as r and rewrite are identical.

11.62 ACL2-PC::REDUCE

ACL2-PC::REDUCE (atomic macro) call the ACL2 theorem prover’s simplifier

     Examples:
     reduce -- attempt to prove the current goal without using induction
     (reduce ("Subgoal 2" :by foo) ("Subgoal 1" :use bar))
            -- attempt to prove the current goal by without using
               induction, with the indicated hints
     General Form:
     (reduce &rest hints)

Attempt to prove the current goal without using induction, using the indicated hints (if any). A subgoal will be created for each goal that would have been pushed for proof by induction in an ordinary proof.

Notice that unlike prove, the arguments to reduce are spread out, and are all hints.

Note: Induction will be used to the extent that it is ordered explicitly in the hints.

11.63 ACL2-PC::REDUCE-BY-INDUCTION

ACL2-PC::REDUCE-BY-INDUCTION (macro) call the ACL2 prover without induction, after going into induction

     Examples:
     reduce-by-induction
       -- attempt to prove the current goal after going into induction,
          with no further inductions
     (reduce-by-induction ("Subgoal 2" :by foo) ("Subgoal 1" :use bar))
       -- attempt to prove the current goal after going into induction,
          with no further inductions, using the indicated hints
     General Form:
     (reduce-by-induction &rest hints)

A subgoal will be created for each goal that would have been pushed for proof by induction in an ordinary proof, except that the proof begins with a top-level induction.

Notice that unlike prove, the arguments to reduce-by-induction are spread out, and are all hints.

See also prove, reduce, and bash.

Note: Induction and the various processes will be used to the extent that they are ordered explicitly

in the :induct and :do-not hints.

11.64 ACL2-PC::REMOVE-ABBREVIATIONS

ACL2-PC::REMOVE-ABBREVIATIONS (primitive) remove one or more abbreviations

     Examples:
     remove-abbreviations -- remove all abbreviations
     (remove-abbreviations v w)
                          -- assuming that V and W currently abbreviate
                             terms, then they are ``removed'' in the
                             sense that they are no longer considered to
                             abbreviate those terms
     General Forms:
     (remove-abbreviations &rest vars)

If vars is not empty (i.e., not nil), remove the variables in vars from the current list of abbreviations, in the sense that each variable in vars will no longer abbreviate a term.

Note: The instruction fails if at least one of the arguments fails to be a variable that abbreviates a term.

See also the documentation for add-abbreviation, which contains a discussion of abbreviations in

general, and show-abbreviations.

11.65 ACL2-PC::REPEAT

ACL2-PC::REPEAT (macro) repeat the given instruction until it “fails”

     Example:
     (repeat promote)
     General Form:
     (repeat instruction)

The given instruction is run repeatedly until it “fails”.

Note: There is nothing here in general to prevent the instruction from being run after all goals have been proved, though this is indeed the case for primitive instructions.

11.66 ACL2-PC::REPEAT-REC

ACL2-PC::REPEAT-REC (macro) auxiliary to repeat

See documentation for repeat.

11.67 ACL2-PC::REPLAY

ACL2-PC::REPLAY (macro) replay one or more instructions

     Examples:
     REPLAY     -- replay all instructions in the current session

                   (i.e., state-stack)
     (REPLAY 5) -- replay the most recent 5 instructions
     (REPLAY 5
             (COMMENT deleted dive command here))
                -- replace the 5th most recent instruction with the
                   indicated comment instruction, and then replay it
                   followed by the remaining 4 instructions
     General Form:
     (REPLAY &OPTIONAL n replacement-instruction)

Replay the last n instructions if n is a positive integer; else n should be nil or not supplied, and replay all instructions. However, if replacement-instruction is supplied and not nil, then before the replay, replace the nth instruction (from the most recent, as shown by commands) with

replacement-instruction.

If this command “fails”, then the restore command will revert the state-stack to its value present before the replay instruction was executed.

11.68 ACL2-PC::RESTORE

ACL2-PC::RESTORE (meta) remove the effect of an UNDO command

     Example and General Form:
     restore

Restore removes the effect of an undo command. This always works as expected if restore is invoked immediately after undo, without intervening instructions. However, other commands may also interact with restore, notably “sequencing” commands such as do-all, do-strict, protect, and more generally, sequence.

Note: Another way to control the saving of proof-checker state is with the save command; see the documentation for save.

The restore command always “succeeds”; it returns (mv nil t state).

11.69 ACL2-PC::RETAIN

ACL2-PC::RETAIN (atomic macro) drop all but the indicated top-level hypotheses

     Example:
     (RETAIN 2 3) -- keep the second and third hypotheses, and drop
                     the rest
     General Form:
     (retain &rest args)

Drop all top-level hypotheses except those with the indicated indices.

There must be at least one argument, and all must be in range (i.e. integers between one and the number of top-level hypotheses, inclusive).

11.70 ACL2-PC::RETRIEVE

ACL2-PC::RETRIEVE (macro) re-enter the proof-checker

     Examples:
     (retrieve associativity-of-permutationp)
     retrieve
     General Form:
     (retrieve &optional name)

Must be used from outside the interactive proof-checker loop. If name is supplied and not nil, this causes re-entry to the interactive proof-checker loop in the state at which save was last executed for the indicated name. (See documentation for save.) If name is nil or is not supplied, then the user is queried regarding which proof-checker state to re-enter. The query is omitted, however, if there only one proof-checker state is present that was saved with save, in which case that is the one that is used. See also unsave.

11.71 ACL2-PC::REWRITE

ACL2-PC::REWRITE (primitive) apply a rewrite rule

     Examples:
     (rewrite reverse-reverse)
        -- apply the rewrite rule `reverse-reverse'
     (rewrite (:rewrite reverse-reverse))
        -- same as above
     (rewrite 2)
        -- apply the second rewrite rule, as displayed by show-rewrites
     rewrite
        -- apply the first rewrite rule, as displayed by show-rewrites
     (rewrite transitivity-of-< ((y 7)))
        -- apply the rewrite rule transitivity-of-< with the substitution
           that associates 7 to the ``free variable'' y
     General Form:
     (rewrite &optional rule-id substitution)

Replace the current subterm with a new term by applying a rewrite rule. If rule-id is a positive integer n, then the nth rewrite rule as displayed by show-rewrites is the one that is applied. If rule-id is nil or is not supplied, then it is treated as the number 1. Otherwise, rule-id should be either a rune of or name of a rewrite rule. If a name is supplied, then any rule of that name may be used. More explanation of all of these points follows below.

Consider first the following example. Suppose that the current subterm is (reverse (reverse y)) and that there is a rewrite rule called reverse-reverse of the form

     (implies (true-listp x)
              (equal (reverse (reverse x)) x)) .

Then the instruction (rewrite reverse-reverse) would cause the current subterm to be replaced by y and would create a new goal with conclusion (true-listp y). An exception is that if the top-level hypotheses imply (true-listp y) using only “trivial reasoning” (more on this below), then no new goal is created.

A rather important point is that if the rule-id argument is a number or is not supplied, then the system will store an instruction of the form (rewrite name ...), where name is the name of a rewrite rule; this is in order to make it easier to replay instructions when there have been changes to the history. Actually, instead of the name (whether the name is supplied or calculated), the system stores the rune if there is any chance of ambiguity. (Formally, “ambiguity” here means that the rune being applied is of the form (:rewrite name . index), where index is not nil.)

Speaking in general, then, a rewrite instruction works as follows:

First, a rewrite rule is selected according to the arguments of the rewrite instruction. The selection is made as explained above under “General Form” above. The “disambiguating rare arguments” will rarely be of interest to the user; as explained just above, the stored instruction always contains the name of the rewrite rule, so if there is more than one rule of that name then the system creates and stores these extra arguments in order to make the resulting instruction unambiguous, i.e., so that only one rewrite rule applies. For what it’s worth, they correspond respectively to the fields of a rewrite rule record named lhs, rhs, hyps, and equiv.

Next, the left-hand side of the rule is matched with the current subterm, i.e., a substitution unifysubst is found such that if one instantiates the left-hand side of the rule with unify-subst, then one obtains the current subterm. If this matching fails, then the instruction fails.

Now an attempt is made to relieve the hypotheses, in much the same sense as the theorem prover relieves hypotheses except that there is no call to the rewriter. Essentially, this means that the substitution unify-subst is applied to the hypotheses and the system then checks whether all hypotheses are “clearly” true in the current context. If there are variables in the hypotheses of the rewrite rule that do not occur in the left-hand side of the conclusion even after the user-supplied substitution (default: nil) is applied, then a weak attempt is made to extend that substitution so that even those hypotheses can be relieved. However, if even one hypothesis remains unrelieved, then no automatic extension of the substitution is made, and in fact hypotheses that contain even one uninstantiated variable will remain unrelieved.

Finally, the instruction is applied as follows. The current subterm is replaced by applying the final substitution, i.e., the extension of unify-subst by the user-supplied substitution which may in turn be extended by the system (as explained above) in order to relieve all hypotheses, to the right-hand side of the selected rewrite rule. And, one new subgoal is created for each unrelieved hypothesis of the rule, whose top-level hypotheses are the governors and top-level hypotheses of the current goal and whose conclusion and current subterm are the instance, by that same final substitution, of that unrelieved hypothesis.

Note: The substitution argument should be a list whose elements have the form (variable term), where term may contain abbreviations.

11.72 ACL2-PC::RUN-INSTR-ON-GOAL

ACL2-PC::RUN-INSTR-ON-GOAL (macro) auxiliary toxae THEN See documentation for then.

11.73 ACL2-PC::RUN-INSTR-ON-NEW-GOALS

ACL2-PC::RUN-INSTR-ON-NEW-GOALS (macro) auxiliary to then

See documentation for then.

11.74 ACL2-PC::S

ACL2-PC::S (primitive) simplify the current subterm

     Examples:
     S  -- simplify the current subterm
     (S :backchain-limit 2 :normalize t :expand (append x z))
        -- simplify the current subterm, but during the rewriting
           process first ``normalize'' it by pushing IFs to the
           top-level, and also force the term (append x z) to be
           expanded during the rewriting process
     General Form:
     (s &key rewrite normalize backchain-limit repeat in-theory hands-off
             expand)

Simplify the current subterm according to the keyword parameters supplied. First if-normalization is applied (unless the normalize argument is nil), i.e., each subterm of the form (f ... (if test

x y) ...) is replaced by the term (if test (f ... x ...) (f ... y ...)) except, of course,

when f is if and the indicated if subterm is in the second or third argument position. Then rewriting is applied (unless the rewrite argument is nil). Finally this pair of actions is repeated — until the rewriting step causes no change in the term. A description of each parameter follows.

     :rewrite -- default t

When non-nil, instructs the system to use ACL2’s rewriter (or, something close to it) during simplification.

     :normalize -- default t

When non-nil, instructs the system to use if-normalization (as described above) during simplification.

     :backchain-limit -- default 0

Sets the number of recursive calls to the rewriter that are allowed for backchaining. Even with the default of 0, some reasoning is allowed (technically speaking, type-set reasoning is allowed) in the relieving of hypotheses.

     :repeat -- default 0

Sets the number of times the current term is to be rewritten. If this value is t, then the default is used (as specified by the constant *default-s-repeat-limit*).

     :in-theory, :hands-off, :expand

These have their usual meaning; see Section 8.43 [HINTS], page 319.

Note: if conditional rewrite rules are used that cause case splits because of the use of force, then appropriate new subgoals will be created, i.e., with the same current subterm (and address) but with each new (forced) hypothesis being negated and then used to create a corresponding new subgoal. In that case, the current goal will have all such new hypotheses added to the list of top-level hypotheses.

11.75 ACL2-PC::S-PROP

ACL2-PC::S-PROP (atomic macro) simplify propositionally

     Example:
     s-prop
     General Form:
     (s-prop &rest names)

Simplify, using the default settings for s (which include if-normalization and rewriting without real backchaining), but with respect to a theory in which only basic functions and rules (the ones in *s-prop-theory*), together with the names (or parenthesized names) in the &rest argument names, are enabled.

See also the documentation for s.

11.76 ACL2-PC::SAVE

ACL2-PC::SAVE (macro) save the proof-checker state (state-stack)

     Example:
     (save lemma3-attempt
     General Form:
     (save &optional name do-it-flg)

Saves the current proof-checker state by “associating” it with the given name. Submit (retrieve name) to Lisp to get back to this proof-checker state. If verify was originally supplied with an event name, then the argument can be omitted in favor of that name as the default.

Note that if a save has already been done with the indicated name (or the default event name), then the user will be queried regarding whether to go ahead with the save — except, if do-it-flg is supplied and not nil, then there will be no query and the save will be effected.

See also the documentation for retrieve and unsave.

11.77 ACL2-PC::SEQUENCE

ACL2-PC::SEQUENCE (meta) run the given list of instructions according to a multitude of options

     Example:
     (sequence (induct p prove) t)

See also the definitions of commands do-all, do-strict, protect, and succeed.

     General Form:
     (sequence instruction-list
               &optional
               strict-flg protect-flg success-expr no-prompt-flg)

Each instruction in the list instruction-list is run, and the instruction “succeeds” if every instruction in instruction-list “succeeds”. However, it might “succeed” even if some instructions in the list “fail”; more generally, the various arguments control a number of aspects of the running of the instructions. All this is explained in the paragraphs below. First we embark on a general discussion of the instruction interpreter, including the notions of “succeed” and “fail”.

Note: The arguments are not evaluated, except (in a sense) for success-expr, as described below.

Each primitive and meta instruction can be thought of as returning an error triple (in the standard ACL2 sense), say (erp val state). An instruction (primitive or meta) “succeeds” if erp is nil and val is not nil; otherwise it “fails”. (When we use the words “succeed” or “fail” in this technical sense, we’ll always include them in double quotes.) If an instruction “fails,” we say that that the failure is “soft” if erp is nil; otherwise the failure is “hard”. The sequence command gives the user control over how to treat “success” and “failure” when sequencing instructions, though we have created a number of handy macro commands for this purpose, notably do-all, do-strict

and protect.

Here is precisely what happens when a sequence instruction is run. The instruction interpreter is run on the instructions supplied in the argument instruction-list (in order). The interpreter halts the first time there is a hard “failure.” except that if strict-flg is supplied and not nil, then the interpreter halts the first time there is any “failure.” The error triple (erp val state) returned by the sequence instruction is the triple returned by the last instruction executed (or, the triple (nil t state) if instruction-list is nil), except for the following provision. If successexpr is supplied and not nil, then it is evaluated with the state global variables erp and val (in ACL2 package) bound to the corresponding components of the error triple returned (as described above). At least two values should be returned, and the first two of these will be substituted for erp and val in the triple finally returned by sequence. For example, if success-expr is (mv erp val), then no change will be made to the error triple, and if instead it is (mv nil t), then the sequence instruction will “succeed”.

That concludes the description of the error triple returned by a sequence instruction, but it remains to explain the effects of the arguments protect-flg and no-prompt-flg.

If protect-flg is supplied and not nil and if also the instruction “fails” (i.e., the error component of the triple is not nil or the value component is nil), then the state is reverted so that the proofchecker’s state (including the behavior of restore) is set back to what it was before the sequence instruction was executed. Otherwise, unless no-restore-flg is set, the state is changed so that the restore command will now undo the effect of this sequence instruction (even if there were nested calls to sequence).

Finally, as each instruction in instruction-list is executed, the prompt and that instruction will be printed, unless the global state variable print-prompt-and-instr-flg is unbound or nil and the parameter no-prompt-flg is supplied and not nil.

11.78 ACL2-PC::SHOW-ABBREVIATIONS

ACL2-PC::SHOW-ABBREVIATIONS (macro) display the current abbreviations

     Examples:
     (show-abbreviations v w)
        -- assuming that v and w currently abbreviate terms,
           then this instruction displays them together with
           the terms they abbreviate
     show-abbreviations
        -- display all abbreviations

See also add-abbreviation and remove-abbreviations. In particular, the documentation for add-abbreviation contains a general discussion of abbreviations.

     General Form:
     (show-abbreviations &rest vars)

Display each argument in vars together with the term it abbreviates (if any). If there are no arguments, i.e. the instruction is simply show-abbreviations, then display all abbreviations together with the terms they abbreviate.

If the term abbreviated by a variable, say v, contains a proper subterm that is also abbreviate by (another) variable, then both the unabbreviated term and the abbreviated term (but not using (?

v) to abbreviate the term) are displayed with together with v.

11.79 ACL2-PC::SHOW-REWRITES

ACL2-PC::SHOW-REWRITES (macro) display the applicable rewrite rules

     Example:
     show-rewrites

     General Form:
     (show-rewrites &optional rule-id enabled-only-flg)

Display rewrite rules whose left-hand side matches the current subterm. This command is useful in conjunction with rewrite. If rule-id is supplied and is a name (non-nil symbol) or a rune, then only the corresponding rewrite rule(s) will be displayed, while if rule-id is a positive integer n, then only the nth rule that would be in the list is displayed. In each case, the display will point out when a rule is currently disabled (in the interactive environment), except that if enabled-only-flg is supplied and not nil, then disabled rules will not be displayed at all. Finally, the free variables of any rule (those occurring in the rule that do not occur in the left-hand side of its conclusion) will be displayed. See also the documentation for rewrite.

11.80 ACL2-PC::SKIP

ACL2-PC::SKIP (macro) “succeed” without doing anything

     Example and General Form:
     skip

Make no change in the state-stack, but “succeed”. Same as (sequence nil).

11.81 ACL2-PC::SL

ACL2-PC::SL (atomic macro) simplify with lemmas

     Examples:
     sl
     (sl 3)
     General Form:
     (sl &optional backchain-limit)

Simplify, but with all function definitions disabled (see Section 16.5 [FUNCTION-THEORY], page 781 in the top-level ACL2 loop), except for a few basic functions (the ones in *s-prop-theory*). If backchain-limit is supplied and not nil, then it should be a nonnegative integer;

see (help s).

11.82 ACL2-PC::SPLIT

ACL2-PC::SPLIT (atomic macro) split the current goal into cases

     Example:
     split

For example, if the current goal has one hypothesis (or x y) and a conclusion of (and a b), then split will create four new goals:

     one with hypothesis X and conclusion A
     one with hypothesis X and conclusion B
     one with hypothesis Y and conclusion A
     one with hypothesis Y and conclusion B.
     General Form:
     SPLIT

Replace the current goal by subgoals whose conjunction is equivalent (primarily by propositional reasoning) to the original goal, where each such goal cannot be similarly split.

Note: The new goals will all have their hypotheses promoted; in particular, no conclusion will have a top function symbol of implies. Also note that split will fail if there is exactly one new goal created and it is the same as the existing current goal.

The way split really works is to call the ACL2 theorem prover with only simplification (and preprocessing) turned on, and with only a few built-in functions (especially, propositional ones) enabled, namely, the ones in the list *s-prop-theory*. However, because the prover is called, type-set reasoning can be used to eliminate some cases. For example, if (true-listp x) is in the hypotheses, then probably (true-listp (cdr x)) will be reduced to t.

11.83 ACL2-PC::SR

ACL2-PC::SR (macro) same as SHOW-REWRITES

     Example:
     sr

     General Form:
     (sr &optional rule-id)

See the documentation for show-rewrites, as sr and show-rewrites are identical.

11.84 ACL2-PC::SUCCEED

ACL2-PC::SUCCEED (macro) run the given instructions, and “succeed”

     Example:
     (succeed induct p prove)
     General Form:
     (succeed &rest instruction-list)

Run the indicated instructions until there is a hard “failure”, and “succeed”. (See the documentation for sequence for an explanation of “success” and “failure”.)

11.85 ACL2-PC::TH

ACL2-PC::TH (macro) print the top-level hypotheses and the current subterm

     Examples:
     th               -- print all (top-level) hypotheses and the current
                         subterm
     (th (1 3) (2 4)) -- print hypotheses 1 and 3 and governors 2 and 4,
                         and the current subterm
     (th (1 3) t)     -- print hypotheses 1 and 3 and all governors, and
                         the current subterm
     General Form:
     (th &optional hyps-indices govs-indices)

Print hypotheses and the current subterm. The printing of hypotheses (and perhaps governors) are controlled as in the hyps command; see its documentation.

Historical note: The name th is adapted from the Gypsy Verification Environment, where th abbreviates the command theorem, which says to print information on the current goal.

11.86 ACL2-PC::THEN

ACL2-PC::THEN (macro) apply one instruction to current goal and another to new subgoals

     Example:
     (then induct prove)
     General Form:
     (then first-instruction &optional completion must-succeed-flg)

Run first-instruction, and then run completion (another instruction) on each subgoal created by first-instruction. If must-succeed-flg is supplied and not nil, then immediately remove the effects of each invocation of completion that “fails”.

11.87 ACL2-PC::TOP

ACL2-PC::TOP (atomic macro) move to the top of the goal

     Example and General Form:
     top

For example, if the conclusion is (= x (* (- y) z)) and the current subterm is y, then after executing top, the current subterm will be the same as the conclusion, i.e., (= x (* (- y) z)).

Top is the same as (up n), where n is the number of times one needs to execute up in order to get to the top of the conclusion. The top command fails if one is already at the top of the conclusion.

See also up, dive, nx, and bk.

11.88 ACL2-PC::TYPE-ALIST

ACL2-PC::TYPE-ALIST (macro) display the type-alist from the current context

     Example and General Form:
     type-alist

Display the current assumptions as a type-alist. Note that this display includes the result of forward chaining.

11.89 ACL2-PC::UNDO

ACL2-PC::UNDO (meta) undo some instructions

     Examples:
     (undo 7)
     undo
     General Forms:
     (undo n) -- Undo the last n instructions.  The argument n should be
                 a positive integer.
     undo     -- Same as (undo 1).

Note: To remove the effect of an undo command, use restore. See the documentation for details.

Note: If the argument n is greater than the total number of interactive instructions in the current session, then (undo n) will simply take you back to the start of the session.

The undo meta command always “succeeds”; it returns (mv nil t state) unless its optional argument is supplied and of the wrong type (i.e. not a positive integer) or there are no instructions to undo.

11.90 ACL2-PC::UNSAVE

ACL2-PC::UNSAVE (macro) remove a proof-checker state

     Example:
     (unsave assoc-of-append)
     General Form:
     (unsave &optional name)

Eliminates the association of a proof-checker state with name, if name is supplied and not nil. The name may be nil or not supplied, in which case it defaults to the event name supplied with the original call to verify (if there is one — otherwise, the instruction “fails” and there is no change). The ACL2 function unsave may also be executed outside the interactive loop, with the same syntax.

See also documentation for save and retrieve.

11.91 ACL2-PC::UP

ACL2-PC::UP (primitive) move to the parent (or some ancestor) of the current subterm

     Examples:  if the conclusion is (= x (* (- y) z)) and the
                current subterm is y, then we have:
     up or (up 1) -- the current subterm becomes (- y)
     (up 2)       -- the current subterm becomes (* (- y) z)
     (up 3)       -- the current subterm becomes the entire conclusion
     (up 4)       -- no change; can't go up that many levels
     General Form:
     (up &optional n)

Move up n levels in the conclusion from the current subterm, where n is a positive integer. If n is not supplied or is nil, then move up 1 level, i.e., treat the instruction as (up 1).

See also dive, top, nx, and bk.

11.92 ACL2-PC::USE

ACL2-PC::USE (atomic macro) use a lemma instance

     Example:
     (USE true-listp-append
          (:instance assoc-of-append (x a) (y b) (z c)))
     -- Add two top-level hypotheses, one the lemma called
        true-listp-append, and the other an instance of the lemma called
        assoc-of-append by the substitution in which x is assigned a, y

        is assigned b, and z is assigned c.
     General Form:
     (use &rest args)

Add the given lemma instances to the list of top-level hypotheses. See Section 8.43 [HINTS], page 319 for the syntax of :use hints in defthm, which is essentially the same as the syntax here (see the example above).

This command calls the prove command, and hence should only be used at the top of the conclusion.

11.93 ACL2-PC::X

ACL2-PC::X (atomic macro) expand and (maybe) simplify function call at the current subterm

     Examples:
     x --  expand and simplify.

For example, if the current subterm is (append a b), then after x the current subterm will probably be (cons (car a) (append (cdr a) b)) if (consp a) and (true-listp a) are among the top-level hypotheses and governors. If there are no top-level hypotheses and governors, then after x the current subterm will probably be:

     (if (true-listp x)
         (if x
             (cons (car x) (append (cdr x) y))
           y)
       (apply 'binary-append (list x y))).
     General Form:
     (X &key
        rewrite normalize backchain-limit in-theory hands-off expand)

Expand the function call at the current subterm, and simplify using the same conventions as with the s command (see documentation for s).

Unlike s, it is permitted to set both :rewrite and :normalize to nil, which will result in no simplification; see x-dumb.

Note (obscure): On rare occasions the current address may be affected by the use of x. For example, suppose we have the definition

     (defun g (x) (if (consp x) x 3))

and then we enter the proof-checker with

     (verify (if (integerp x) (equal (g x) 3) t)) .

Then after invoking the instruction (dive 2 1), so that the current subterm is (g x), followed by the instruction x, we would expect the conclusion to be (if (integerp x) (equal 3 3) t). However, the system actually replaces (equal 3 3) with t (because we use the ACL2 term-forming primitives), and hence the conclusion is actually (if (integerp x) (equal 3 3) t). Therefore, the current address is put at (2) rather than (2 1). In such cases, a warning “NOTE” will be printed to the terminal.

The other primitive commands to which the above “truncation” note applies are equiv, rewrite, and s.

11.94 ACL2-PC::X-DUMB

ACL2-PC::X-DUMB (atomic macro) expand function call at the current subterm, without simplifying

     Example:
     x-dumb:  expand without simplification.
     General Form:
     (x-dumb &optional new-goals-flg keep-all-guards-flg)
Same as (expand t new-goals-flg keep-all-guards-flg). See documentation for expand.

See also x, which allows simplification.

11.95 DEFINE-PC-HELP

DEFINE-PC-HELP define a macro command whose purpose is to print something

     Example:
     (define-pc-help pp ()
       (if (goals t)
           (io? proof-checker nil state
                (fms0 "~|~y0~|"
                      (list (cons #0
                                  (fetch-term (conc t)
                                              (current-addr t))))))
         (print-all-goals-proved-message state)))
     General Form:
     (define-pc-help name args &rest body)

This defines a macro command named name, as explained further below. The body should (after removing optional declarations) have multiplicity 1 and state-out t, i.e. it should return a single value of state. Typically, it will just print something.

What (define-pc-help name args &rest body) really does is to create a call of define-pc-

macro that defines name to take arguments args, to have the declarations indicated by all but the last form in body, and to have a body that (via pprogn) first executes the form in the last element of body and then returns a call to the command skip (which will return (mv nil t state)).

11.96 INSTRUCTIONS

INSTRUCTIONS instructions to the proof checker

     Example:
     :instructions (induct prove promote (dive 1) x
                           (dive 2) = top (drop 2) prove)

See Section 6.15 [DEFTHM], page 176 for the role of :instructions in place of :hints (HINTS^). As illustrated by the example above, the value associated with :instructions is a list of proofchecker (PROOF-CHECKER^) commands. At the moment the best way to understand the idea of the interactive proof-checker (see Chapter 11 [PROOF-CHECKER], page 553 and see Section 11.101 [VERIFY], page 615) is probably to read the first 11 pages of CLI Technical Report 19, which describes the corresponding facility for Nqthm.

When inside the interactive loop (i.e., after executing verify (VERIFY^)), use help (HELP^) to get a list of legal instructions and (help instr) to get help for the instruction instr.

11.97 MACRO-COMMAND

MACRO-COMMAND compound command for the proof-checker

The proof-checker (see Chapter 11 [PROOF-CHECKER], page 553) allows the user to supply interactive commands. Compound commands, called macro commands, may be defined; these expand into zero or more other commands. Some of these are “atomic” macro commands; these are viewed as a single command step when completed successfully.

More documentation (DOCUMENTATION^) will be written on the proof-checker (PROOF-CHECKER^). For now, we simply point out that there are lots of examples of the use of define-

pc-macro and define-pc-atomic-macro in the ACL2 source file "proof-checker-b.lisp". The

former is used to create macro commands, which can be submitted to the interactive loop (see Section 11.101 [VERIFY], page 615) and will “expand” into zero or more commands. The latter is similar, except that the undoing mechanism (see Section 11.89 [ACL2-PC::UNDO], page 609) understands atomic macro commands to represent single interactive commands. Also see Section 11.12 [ACL2-PC::COMM], page 565 and see Section 11.13 [ACL2-PC::COMMANDS], page 566 for a discussion of the display of interactive commands.

Also see Section 11.99 [TOGGLE-PC-MACRO], page 614 for how to change a macro command to an atomic macro command, and vice versa.

11.98 RETRIEVE

RETRIEVE re-enter a (specified) proof-checker (PROOF-CHECKER^) state

     Examples:
     (retrieve associativity-of-permutationp)
     retrieve
     General Form:
     (retrieve &optional name)

See Section 11.70 [ACL2-PC::RETRIEVE], page 597, or use (help retrieve) inside the interactive proof-checker (PROOF-CHECKER^) loop. Also see Section 11.100 [UNSAVE], page 615.

11.99 TOGGLE-PC-MACRO

TOGGLE-PC-MACRO change an ordinary macro command to an atomic macro, or vice-versa

     Example:
     (toggle-pc-macro pro)

Change pro from an atomic macro command to an ordinary one (or vice-versa, if pro happens to be an ordinary macro command)

     General Form:
     (toggle-pc-macro name &optional new-tp)

If name is an atomic macro command then this turns it into an ordinary one, and vice-versa. However, if new-tp is supplied and not nil, then it should be the new type, or else there is no change.

11.100 UNSAVE

UNSAVE remove a proof-checker (PROOF-CHECKER^) state

     Example:
     (unsave assoc-of-append)
     General Form:
     (unsave name)

Eliminates the association of a proof-checker (PROOF-CHECKER^) state with name. See Section 11.100 [UNSAVE], page 615 or see Section 11.90 [ACL2-PC::UNSAVE], page 609. Also see Section 11.76 [ACL2-PC::SAVE], page 602 and see Section 11.98 [RETRIEVE], page 614.

11.101 VERIFY

VERIFY enter the interactive proof checker For proof-checker command summaries, see Chapter 11 [PROOF-CHECKER], page 553.

     Examples:

(VERIFY (implies (and (true-listp x) (true-listp y))
              (equal (append (append x y) z)
                     (append x (append y z)))))
-- Attempt to prove the given term interactively.
(VERIFY (p x)
:event-name p-always-holds
:rule-classes (:rewrite :generalize)
:instructions ((rewrite p-always-holds-lemma)
               change-goal))
-- Attempt to prove (p x), where the intention is to call the
resulting DEFTHM event by the name p-always-holds, with
rule-classes as indicated.  The two indicated instructions
will be run immediately to start the proof.
(VERIFY)
-- Re-enter the proof-checker in the state at which is was last
left.
General Form:
(VERIFY &OPTIONAL raw-term
&KEY
event-name
rule-classes
instructions)

Verify is the function used for entering the proof-checker (PROOF-CHECKER^)’s interactive loop.

12 PROOF-TREE

PROOF-TREE proof tree displays

A view of ACL2 proofs may be obtained by way of “proof tree displays.” Environments such as emacs may be customized to provide window-based versions of proof tree displays. (See for example documentation of the emacs function start-proof-tree (START-PROOF-TREE^), co-written with Michael K. Smith, that the implementors are happy to make available.) Proof tree displays may be turned on with the command :start-proof-tree (START-PROOF-TREE^) and may be turned off with the command :start-proof-tree (START-PROOF-TREE^); see Section 12.4 [START-PROOF-TREE], page 626 and see Section 12.5 [STOP-PROOF-TREE], page 626.

* CHECKPOINT-FORCED-GOALS:: Cause forcing goals to be checkpointed in proof trees

* PROOF-TREE-DETAILS:: proof tree details not covered elsewhere

* PROOF-TREE-EXAMPLES:: proof tree example

* START-PROOF-TREE:: start displaying proof trees during proofs

* STOP-PROOF-TREE:: stop displaying proof trees during proofs

Here is an example of a proof tree display, with comments. Lines marked with “c” are considered “checkpoints,” i.e., goals whose scrutiny may be of particular value.

     ( DEFTHM PLUS-TREE-DEL ...)    ;currently proving PLUS-TREE-DEL
        1 Goal preprocess   ;"Goal" creates 1 subgoal by preprocessing
        2 |  Goal' simp     ;"Goal'" creates 2 subgoals by simplification
     c  0 |  |  Subgoal 2 PUSH *1   ;"Subgoal 2" pushes "*1" for INDUCT
     ++++++++++++++++++++++++++++++ ;first pass thru waterfall completed
     c  6 *1 INDUCT                 ;Proof by induction of "*1" has
          |  <5 more subgoals>      ; created 6 top-level subgoals.  At
                                    ; this point, one of those 6 has been
                                    ; proved, and 5 remain to be proved.
                                    ; We are currently working on the
                                    ; first of those 5 remaining goals.

See Section 12.3 [PROOF-TREE-EXAMPLES], page 620 for many examples that contain proof tree displays. But first, we summarize the kinds of lines that may appear in a proof tree display. The simplest form of a proof tree display is a header showing the current event, followed by list of lines, each having one of the following forms.

         n <goal> <process> ...

Says that the indicated goal created n subgoals using the indicated process. Here “...” refers to possible additional information.

     c   n <goal> <process> ...

As above, but calls attention to the fact that this goal is a “checkpoint” in the sense that it may be of particular interest. Some displays may overwrite “c” with “>” to indicate the current checkpoint being shown in the proof transcript.

          |  <goal> ...
          |  |  <k subgoals>

Indicates that the goal just above this line, which is pointed to by the rightmost vertical bar (“|”), has k subgoals, none of which have yet been processed.

          |  <goal> ...
          |  |  <k more subgoals>

As above, except that some subgoals have already been processed.

     ++++++++++++++++++++++++++++++

Separates successive passes through the “waterfall”. Thus, this “fencepost” mark indicates the start of a new proof by induction or of a new forcing round.

See Section 12.3 [PROOF-TREE-EXAMPLES], page 620 for detailed examples. To learn how to turn off proof tree displays or to turn them back on again, see Section 12.5 [STOP-PROOF-TREE], page 626 and see Section 12.4 [START-PROOF-TREE], page 626, respectively. See Section 12.1 [CHECKPOINT-FORCED-GOALS], page 618 to learn how to mark goals as checkpoints that force (FORCE^) the creation of goals in forcing rounds. Finally, see Section 12.2 [PROOF-TREE-DETAILS], page 619 for some points not covered elsewhere.

12.1 CHECKPOINT-FORCED-GOALS

CHECKPOINT-FORCED-GOALS Cause forcing goals to be checkpointed in proof trees

     Example forms:
     (checkpoint-forced-goals t)

     (checkpoint-forced-goals nil)

Also see Chapter 12 [PROOF-TREE], page 617.

By default, goals are not marked as checkpoints by a proof tree display (as described in the documentation for proof-tree (PROOF-TREE^)) merely because they force (FORCE^) some hypotheses, thus possibly contributing to a forcing round. However, some users may want such behavior, which will occur once the command (checkpoint-forced-goals) t) has been executed. To return to the default behavior, use the command (checkpoint-forced-goals nil).

12.2 PROOF-TREE-DETAILS

PROOF-TREE-DETAILS proof tree details not covered elsewhere

See Chapter 12 [PROOF-TREE], page 617 for an introduction to proof trees, and for a list of related topics. Here we present some details not covered elsewhere.

1. When proof tree display is enabled (because the command :stop-proof-tree (STOP-PROOF-TREE^) has not been executed, or has been superseded by a later :start-proof-tree (START-PROOF-TREE^) command), then time summaries will include the time for proof tree display. This time includes the time spent computing with proof trees, such as the pruning process described briefly above. Even when proof trees are not displayed, such as when their display is turned off in the middle of a proof, this time will be printed if it is not 0.

2. When a goal is given a :bye in a proof (see Section 8.43 [HINTS], page 319), it is treated for the purpose of proof tree display just as though it had been proved.

3. Several state (STATE^) global variables affect proof tree display. (@ proof-tree-indent) is initially the string "| ": it is the string that is laid down the appropriate number of times

to effect indentation. (@ proof-tree-buffer-width) is initially the value of (fmt-soft-right-

margin state), and is used to prevent printing of the annotation “(force (FORCE^)d ...)” in any greater column than this value. However, (assign proof-tree-buffer-width nil) to avoid any such suppression. Finally, (@ checkpoint-processors) is a list of processors from the constant list *preprocess-clause-ledge*, together with :induct. You may remove elements of (@ checkpoint-processors) to limit which processes are considered checkpoints.

4. When :otf-flg (OTF-FLG^) is not set to t in a proof, and the prover then decides to revert to the original goal and prove it by induction, the proof tree display will reflect this fact as shown here:

     c  0 |  |  Subgoal 2 PUSH (reverting)

5. Proof-tree (PROOF-TREE^) display is turned off during calls of certify-book (CERTIFY-BOOK^).

6. The usual failure (FAILURE^) message is printed as part of the prooftree display when a proof has failed.

12.3 PROOF-TREE-EXAMPLES

PROOF-TREE-EXAMPLES proof tree example

See Chapter 12 [PROOF-TREE], page 617 for an introduction to proof trees, and for a list of related topics. Here we present a detailed example followed by a shorter example that illustrates proof by induction.

Consider the guard (GUARD^) proof for the definition of a function cancel_equal_plus; the body of this definition is of no importance here. The first proof tree display is:

     ( DEFUN CANCEL_EQUAL_PLUS ...)
       18 Goal preprocess
          |  <18 subgoals>

This is to be read as follows.

At this stage of the proof we have encountered the top-level goal, named "Goal", which generated 18 subgoals using the “preprocess” process. We have not yet begun to work on those subgoals.

The corresponding message from the ordinary prover output is:

By case analysis we reduce the conjecture to the following 18 conjectures.

Note that the field just before the name of the goal ("Goal"), which here contains the number 18, indicates the number of cases (children) created by the goal using the indicated process. This number will remain unchanged as long as this goal is displayed.

The next proof tree display is:

     ( DEFUN CANCEL_EQUAL_PLUS ...)
       18 Goal preprocess
        1 |  Subgoal 18 simp
          |  |  <1 subgoal>
          |  <17 more subgoals>

which indicates that at this point, the prover has used the simplification (“simp”) process on Subgoal 18 to create one subgoal (“<1 subgoal>”). The vertical bar (“|”) below “Subgoal 18”, accompanied by the line below it, signifies that there are 17 siblings of Subgoal 18 that remain to be processed.

The next proof tree displayed is:

     ( DEFUN CANCEL_EQUAL_PLUS ...)
       18 Goal preprocess
        1 |  Subgoal 18 simp
     c  2 |  |  Subgoal 18' ELIM
          |  |  |  <2 subgoals>
          |  <17 more subgoals>

Let us focus on the fourth line of this display:

     c  2 |  |  Subgoal 18' ELIM

The “c” field marks this goal as a “checkpoint”, i.e., a goal worthy of careful scrutiny. In fact, any goal that creates children by a process other than “preprocess” or “simp” is marked as a checkpoint. In this case, the destructor-elimination (“ELIM (ELIM^)”) process has been used to create subgoals of this goal. The indentation shows that this goal, Subgoal 18’, is a child of Subgoal 18. The number “2” indicates that 2 subgoals have been created (by ELIM (ELIM^)). Note that this information is consistent with the line just below it, which says “<2 subgoals>”.

Finally, the last line of this proof tree display,

          |  <17 more subgoals>

is connected by vertical bars (“|”) up to the string "Subgoal 18", which suggests that there are 17 immediate subgoals of Goal remaining to process after Subgoal 18. Note that this line is indented one level from the second line, which is the line for the goal named "Goal". The display is intended to suggest that the subgoals of Goal that remain to be proved consist of Subgoal 18 together with 17 more subgoals.

The next proof tree display differs from the previous one only in that now, Subgoal 18’ has only one more subgoal to be processed.

     ( DEFUN CANCEL_EQUAL_PLUS ...)
       18 Goal preprocess
        1 |  Subgoal 18 simp
     c  2 |  |  Subgoal 18' ELIM
          |  |  |  <1 more subgoal>
          |  <17 more subgoals>

Note that the word “more” in “<1 more subgoal>” tells us that there was originally more than one subgoal of Subgoal 18. In fact that information already follows from the line above, which (as previously explained) says that Subgoal 18’ originally created 2 subgoals.

The next proof tree display occurs when the prover completes the proof of that “1 more subgoal” referred to above.

     ( DEFUN CANCEL_EQUAL_PLUS ...)
       18 Goal preprocess
          |  <17 more subgoals>

Then, Subgoal 17 is processed and creates one subgoal, by simplification:

     ( DEFUN CANCEL_EQUAL_PLUS ...)
       18 Goal preprocess
        1 |  Subgoal 17 simp
          |  |  <1 subgoal>
          |  <16 more subgoals>

... and so on.

Later in the proof one might find the following successive proof tree displays.

     ( DEFUN CANCEL_EQUAL_PLUS ...)
       18 Goal preprocess

  |  <9 more subgoals>
( DEFUN CANCEL_EQUAL_PLUS ...)
18 Goal preprocess
0 |  Subgoal 9 simp (FORCED)
  |  <8 more subgoals>

These displays tell us that Subgoal 9 simplified to t (note that the “0” shows clearly that no subgoals were created), but that some rule’s hypotheses were force (FORCE^)d. Although this goal is not checkpointed (i.e., no “c” appears on the left margin), one can cause such goals to be checkpointed; see Section 12.1 [CHECKPOINT-FORCED-GOALS], page 618.

In fact, the proof tree displayed at the end of the “main proof” (the 0-th forcing round) is as follows.

( DEFUN CANCEL_EQUAL_PLUS ...)
18 Goal preprocess
0 |  Subgoal 9 simp (FORCED)
0 |  Subgoal 8 simp (FORCED)
0 |  Subgoal 7 simp (FORCED)
0 |  Subgoal 6 simp (FORCED)
0 |  Subgoal 4 simp (FORCED)
0 |  Subgoal 3 simp (FORCED)

This is followed by the following proof tree display at the start of the forcing round.

18 Goal preprocess
0 |  Subgoal 9 simp (FORCED [1]Subgoal 4)
0 |  Subgoal 8 simp (FORCED [1]Subgoal 6)
0 |  Subgoal 7 simp (FORCED [1]Subgoal 1)
0 |  Subgoal 6 simp (FORCED [1]Subgoal 3)
0 |  Subgoal 4 simp (FORCED [1]Subgoal 5)
0 |  Subgoal 3 simp (FORCED [1]Subgoal 2)
++++++++++++++++++++++++++++++
6 [1]Goal FORCING-ROUND
2 |  [1]Subgoal 6 preprocess
  |  |  <2 subgoals>
  |  <5 more subgoals>

This display shows which goals to “blame” for the existence of each goal in the forcing round. For example, Subgoal 9 is to blame for the creation of [1]Subgoal 4.

Actually, there is no real goal named "[1]Goal". However, the line

6 [1]Goal FORCING-ROUND

appears in the proof tree display to suggest a “parent” of the six top-level goals in that forcing round. As usual, the numeric field before the goal name contains the original number of children of that (virtual, in this case) goal — in this case, 6.

In our example proof, Subgoal 6 eventually gets proved, without doing any further forcing. At that point, the proof tree display looks as follows.

( DEFUN CANCEL_EQUAL_PLUS ...)
18 Goal preprocess
0 |  Subgoal 9 simp (FORCED [1]Subgoal 4)
0 |  Subgoal 7 simp (FORCED [1]Subgoal 1)
0 |  Subgoal 6 simp (FORCED [1]Subgoal 3)
0 |  Subgoal 4 simp (FORCED [1]Subgoal 5)
0 |  Subgoal 3 simp (FORCED [1]Subgoal 2)
++++++++++++++++++++++++++++++
6 [1]Goal FORCING-ROUND
  |  <5 more subgoals>

Notice that the line for Subgoal 8,

0 |  Subgoal 8 simp (FORCED [1]Subgoal 6)

no longer appears. That is because the goal [1]Subgoal 6 has been proved, along with all its children; and hence, the proof of Subgoal 8 no longer depends on any further reasoning.

The final two proof tree displays in our example are as follows.

( DEFUN CANCEL_EQUAL_PLUS ...)
18 Goal preprocess
0 |  Subgoal 7 simp (FORCED [1]Subgoal 1)
++++++++++++++++++++++++++++++
6 [1]Goal FORCING-ROUND
2 |  [1]Subgoal 1 preprocess
1 |  |  [1]Subgoal 1.1 preprocess
1 |  |  |  [1]Subgoal 1.1' simp
c  3 |  |  |  |  [1]Subgoal 1.1'' ELIM
  |  |  |  |  |  <1 more subgoal>
( DEFUN CANCEL_EQUAL_PLUS ...)

     <<PROOF TREE IS EMPTY>>

The explanation for the empty proof tree is simple: once [1]Subgoal 1.1.1 was proved, nothing further remained to be proved. In fact, the much sought-after “Q.E.D.” appeared shortly after the final proof tree was displayed.

Let us conclude with a final, brief example that illustrates proof by induction. Partway through the proof one might come across the following proof tree display.

     ( DEFTHM PLUS-TREE-DEL ...)
        1 Goal preprocess
        2 |  Goal' simp
     c  0 |  |  Subgoal 2 PUSH *1
          |  |  <1 more subgoal>

This display says that in the attempt to prove a theorem called plus-tree-del, preprocessing created the only child Goal’ from Goal, and Goal’ simplified to two subgoals. Subgoal 2 is immediately pushed for proof by induction, under the name “*1”. In fact if Subgoal 1 simplifies to t, then we see the following successive proof tree displays after the one shown above.

     ( DEFTHM PLUS-TREE-DEL ...)
        1 Goal preprocess
        2 |  Goal' simp
     c  0 |  |  Subgoal 2 PUSH *1
     ( DEFTHM PLUS-TREE-DEL ...)
        1 Goal preprocess
        2 |  Goal' simp
     c  0 |  |  Subgoal 2 PUSH *1
     ++++++++++++++++++++++++++++++
     c  6 *1 INDUCT
          |  <5 more subgoals>

The separator “+++++...” says that we are beginning another trip through the waterfall. In fact this trip is for a proof by induction (as opposed to a forcing round), as indicated by the word “INDUCT”. Apparently *1.6 was proved immediately, because it was not even displayed; a goal is only displayed when there is some work left to do either on it or on some goal that it brought (perhaps indirectly) into existence.

Once a proof by induction is completed, the “PUSH” line that refers to that proof is eliminated (“pruned”). So for example, when the present proof by induction is completed, the line

     c  0 |  |  Subgoal 2 PUSH *1

is eliminated, which in fact causes the lines above it to be eliminated (since they no longer refer to unproved children). Hence, at that point one might expect to see:

     ( DEFTHM PLUS-TREE-DEL ...)
     <<PROOF TREE IS EMPTY>>

However, if the proof by induction of *1 necessitates further proofs by induction or a forcing round, then this “pruning” will not yet be done.

12.4 START-PROOF-TREE

START-PROOF-TREE start displaying proof trees during proofs

Also see Chapter 12 [PROOF-TREE], page 617 and see Section 12.5 [STOP-PROOF-TREE], page 626. Note that :start-proof-tree works by removing 'proof-tree (PROOF-TREE^) from the inhibit-output-lst; see Section 9.13 [SET-INHIBIT-OUTPUT-LST], page 424.

Proof tree displays are explained in the documentation for proof-tree (PROOF-TREE^). :startproof-tree causes proof tree display to be turned on, once it has been turned off by :stop-proof-tree (STOP-PROOF-TREE^).

Do not attempt to invoke start-proof-tree during an interrupt in the middle of a proof.

12.5 STOP-PROOF-TREE

STOP-PROOF-TREE stop displaying proof trees during proofs

Also see Chapter 12 [PROOF-TREE], page 617 and see Section 12.4 [START-PROOF-TREE], page 626. Note that :stop-proof-tree works by adding 'proof-tree (PROOF-TREE^) to the inhibit-output-lst; see Section 9.13 [SET-INHIBIT-OUTPUT-LST], page 424.

Proof tree displays are explained in the documentation for proof-tree (PROOF-TREE^). :Stopproof-tree causes proof tree display to be turned off.

It is permissible to submit the form (stop-proof-tree) during a break. Thus, you can actually turn off proof tree display in the middle of a proof by interrupting ACL2 and submitting the form

(stop-proof-tree) in raw Lisp.

628 ACL2 Version 1.9

13 Pages Written Especially for the Tours

Pages Written Especially for the Tours Pages Written Especially for the Tours

The ACL2 Home Page is generated from ACL2’s online documentation strings. (How else could we achieve the total integration of ACL2’s online documentation with the home page?) This page is just an artifact of the structure of our documentation strings: each string must belong to a “major section” of the documentation database. This page is not structured to be used by a person browsing via the Web. It contains, in an arbitrary order, the pages written specificially for the Web user.

Furthermore, browsing the pages below via the ACL2 :DOC command or via TexInfo is often unsatisfying because those browsers do not support gif files and the notion of going “back” to a node just visited. If you wish to look at the pages below, we strongly recommend that you do so via a HTML-based Web browser. Indeed, you should simply visit ACL2’s Home Page and take one of the Tours.

* A Flying Tour of ACL2:: A Flying Tour of ACL2

* A Sketch of How the Rewriter Works:: A Sketch of How the Rewriter Works

* A Tiny Warning Sign:: A Tiny Warning Sign

* A Trivial Proof:: A Trivial Proof

* A Typical State:: A Typical State

* A Walking Tour of ACL2:: A Walking Tour of ACL2

* ACL2 Characters:: ACL2 Characters

* ACL2 Conses or Ordered Pairs:: ACL2 Conses or Ordered Pairs

* ACL2 Strings:: ACL2 Strings

* ACL2 Symbols:: ACL2 Symbols

* ACL2 System Architecture:: ACL2 System Architecture

* ACL2 as an Interactive Theorem Prover:: ACL2 as an Interactive Theorem Prover

* ACL2 as an Interactive Theorem Prover (continued):: ACL2 as an Interactive Theorem Prover (continued)

* ACL2 is an Untyped Language:: ACL2 is an Untyped Language

* About Models:: About Models

* About Types:: About Types

* About the ACL2 Home Page:: About the ACL2 Home Page

* About the Admission of Recursive Definitions:: About the Admission of Recursive Definitions

* About the Prompt:: About the Prompt

* An Example Common Lisp Function Definition:: An Example Common Lisp Function Definition

* An Example of ACL2 in Use:: An Example of ACL2 in Use

* Analyzing Common Lisp Models:: Analyzing Common Lisp Models

* Common Lisp:: Common Lisp

* Common Lisp as a Modeling Language:: Common Lisp as a Modeling Language

* Conversion:: Conversion to Uppercase

* Corroborating Models:: Corroborating Models

* Evaluating App on Sample Input:: Evaluating App on Sample Input * Flawed Induction Candidates in App Example:: Flawed Induction Candidates in App Example

* Functions for Manipulating these Objects:: Functions for Manipulating these Objects

* Guards:: Guards

* Guessing the Type of a Newly Admitted Function:: Guessing the Type of a Newly Admitted Function

* Guiding the ACL2 Theorem Prover:: Guiding the ACL2 Theorem Prover

* Hey Wait! Is ACL2 Typed or Untyped(Q):: Hey Wait! Is ACL2 Typed or Untyped?

* How Long Does It Take to Become an Effective User(Q):: How Long Does It Take to Become an Effective User?

* How To Find Out about ACL2 Functions:: How To Find Out about ACL2 Functions

* How To Find Out about ACL2 Functions (continued):: How To Find Out about ACL2 Functions (continued)

* Modeling in ACL2:: Modeling in ACL2

* Models in Engineering:: Models in Engineering

* Models of Computer Hardware and Software:: Models of Computer Hardware and Software

* Name the Formula Above:: Name the Formula Above

* Numbers in ACL2:: Numbers in ACL2

* On the Naming of Subgoals:: On the Naming of Subgoals

* Other Requirements:: Other Requirements

* Overview of the Expansion of ENDP in the Base Case:: Overview of the Expansion of ENDP in the Base Case * Overview of the Expansion of ENDP in the Induction Step:: Overview of the Expansion of ENDP in the Induction Step

* Overview of the Final Simplification in the Base Case:: Overview of the Final Simplification in the Base Case * Overview of the Proof of a Trivial Consequence:: Overview of the Proof of a Trivial Consequence

* Overview of the Simplification of the Base Case to T:: Overview of the Simplification of the Base Case to T

* Overview of the Simplification of the Induction Conclusion:: Overview of the Simplification of the Induction Conclusion

* Overview of the Simplification of the Induction Step to T:: Overview of the Simplification of the Induction Step to T

* Perhaps:: Perhaps

* Popping out of an Inductive Proof:: Popping out of an Inductive Proof

* Proving Theorems about Models:: Proving Theorems about Models

* Revisiting the Admission of App:: Revisiting the Admission of App

* Rewrite Rules are Generated from DEFTHM Events:: Rewrite Rules are Generated from DEFTHM Events

* Running Models:: Running Models

* STATE is the Only Variable in Top-Level Forms:: STATE is the Only Variable in Top-Level Forms

* Subsumption of Induction Candidates in App Example:: Subsumption of Induction Candidates in App Example * Suggested Inductions in the Associativity of App Example:: Suggested Inductions in the Associativity of App Example

* Symbolic Execution of Models:: Symbolic Execution of Models

* The Admission of App:: The Admission of App

* The Associativity of App:: The Associativity of App

* The Base Case in the App Example:: The Base Case in the App Example

* The End of the Flying Tour:: The End of the Flying Tour

* The End of the Proof of the Associativity of App:: The End of the Proof of the Associativity of App

* The End of the Walking Tour:: The End of the Walking Tour

* The Event Summary:: The Event Summary * The Expansion of ENDP in the Induction Step (Step 0):: The Expansion of ENDP in the Induction Step (Step 0)

* The Expansion of ENDP in the Induction Step (Step 1):: The Expansion of ENDP in the Induction Step (Step 1)

* The Expansion of ENDP in the Induction Step (Step 2):: The Expansion of ENDP in the Induction Step (Step 2)

* The Falling Body Model:: The Falling Body Model

* The Final Simplification in the Base Case (Step 0):: the Final Simplification in the Base Case (Step 0)

* The Final Simplification in the Base Case (Step 1):: the Final Simplification in the Base Case (Step 1)

* The Final Simplification in the Base Case (Step 2):: the Final Simplification in the Base Case (Step 2)

* The Final Simplification in the Base Case (Step 3):: the Final Simplification in the Base Case (Step 3)

* The First Application of the Associativity Rule:: The First Application of the Associativity Rule

* The Induction Scheme Selected for the App Example:: The Induction Scheme Selected for the App Example * The Induction Step in the App Example:: The Induction Step in the App Example

* The Instantiation of the Induction Scheme:: The Instantiation of the Induction Scheme

* The Justification of the Induction Scheme:: The Justification of the Induction Scheme

* The Proof of the Associativity of App:: The Proof of the Associativity of App

* The Q.E.D. Message:: The Q.E.D. Message

* The Rules used in the Associativity of App Proof:: The Rules used in the Associativity of App Proof

* The Simplification of the Induction Conclusion (Step 0):: the Simplification of the Induction Conclusion (Step 0)

* The Simplification of the Induction Conclusion (Step 1):: the Simplification of the Induction Conclusion (Step 1)

* The Simplification of the Induction Conclusion (Step 10):: the Simplification of the Induction Conclusion (Step 10)

* The Simplification of the Induction Conclusion (Step 11):: the Simplification of the Induction Conclusion (Step 11)

* The Simplification of the Induction Conclusion (Step 12):: the Simplification of the Induction Conclusion (Step 12)

* The Simplification of the Induction Conclusion (Step 2):: the Simplification of the Induction Conclusion (Step 2)

* The Simplification of the Induction Conclusion (Step 3):: the Simplification of the Induction Conclusion (Step 3)

* The Simplification of the Induction Conclusion (Step 4):: the Simplification of the Induction Conclusion (Step 4)

* The Simplification of the Induction Conclusion (Step 5):: the Simplification of the Induction Conclusion (Step 5)

* The Simplification of the Induction Conclusion (Step 6):: the Simplification of the Induction Conclusion (Step 6)

* The Simplification of the Induction Conclusion (Step 7):: the Simplification of the Induction Conclusion (Step 7)

* The Simplification of the Induction Conclusion (Step 8):: the Simplification of the Induction Conclusion (Step 8)

* The Simplification of the Induction Conclusion (Step 9):: the Simplification of the Induction Conclusion (Step 9)

* The Summary of the Proof of the Trivial Consequence:: The Summary of the Proof of the Trivial Consequence

* The Theorem that App is Associative:: The Theorem that App is Associative * The Time Taken to do the Associativity of App Proof:: The Time Taken to do the Associativity of App Proof

* The Tours:: The Tours

* The WARNING about the Trivial Consequence:: The WARNING about the Trivial Consequence

* Undocumented Topic:: Undocumented Topic

* Using the Associativity of App to Prove a Trivial Consequence:: Using the Associativity of App to Prove a Trivial Consequence

* What Is ACL2(Q):: What Is ACL2?

* What is Required of the User(Q):: What is Required of the User?

* What is a Mathematical Logic(Q):: What is a Mathematical Logic?

* What is a Mechanical Theorem Prover(Q):: What is a Mechanical Theorem Prover?

* What is a Mechanical Theorem Prover(Q) (continued):: What is a Mechanical Theorem Prover? (continued)

* You Must Think about the Use of a Formula as a Rule:: You Must Think about the Use of a Formula as a Rule

Generally, the topics listed above will not be of use to the ACL2 user.

13.1 A Flying Tour of ACL2

A Flying Tour of ACL2 A Flying Tour of ACL2

On this tour you will learn a little about what ACL2 is for rather than how ACL2 works. At the bottom of the “page” (which may extend beyond the end of your screen) there is a small “flying tour” icon. Click on it to go to the next page of the tour.

The tour visits the following topics sequentially.

The Flight Plan

* This Documentation (About the ACL2 Home Page^)

* What is ACL2? (What Is ACL2(Q)^)

* Mathematical Logic (What is a Mathematical Logic(Q)^)

* Mechanical Theorem Proving (What is a Mechanical Theorem Prover(Q)^)

* Mathematical Models in General (About Models^)

* Mathematical Models of Computing Machines (Models of Computer Hardware and Software^)

Formalizing Models (A Typical State^) Running Models (Running Models^) Symbolic Execution of Models (Symbolic Execution of Models^) Proving Theorems about Models (Proving Theorems about Models^)

* Requirements of ACL2 The User’s Skills (What is Required of the User(Q)^) Training (How Long Does It Take to Become an Effective User(Q)^) Host System (Other Requirements^)

We intend the tour to take about 10 minutes of your time. Some pages on the tour contain pointers to other documents. You need not follow these pointers to stay on the tour.

Flying Tour: see Section 13.17 [About the ACL2 Home Page], page 641

13.2 A Sketch of How the Rewriter Works

A Sketch of How the Rewriter Works A Sketch of How the Rewriter Works

Below we show the first target term, extracted from the current conjecture. Below it we show the associativity rule.

The variables of the rewrite rule are instantiated so that the left-hand side of the rule matches the target:

          variable          term from target
            a                     x1
            b                     x2
            c                     (app x3 x4)

Then the target is replaced by the instantiated right-hand side of the rule.

Sometimes rules have hypotheses. To make a long story short, if the rule has hypotheses, then after matching the left-hand side, the rewriter instantiates the hypotheses and rewrites them recursively. This is called backchaining. If they all rewrite to true, then the target is replaced as above.

For more details on how the ACL2 rewriter works, see Boyer and Moore’s book A Computational Logic, Academic Press, 1979.

13.3 A Tiny Warning Sign

A Tiny Warning Sign A Tiny Warning Sign

This warning sign, which usually appears as “”, indicates that the link it marks takes you into ACL2’s online documentation.

The documentation is a vast graph of documented topics intended to help the user of ACL2 rather than the potential user. If you are exploring ACL2’s home page to learn about the system, perhaps you should go back rather than follow the link marked with this sign. But you are welcome to explore the online documentation as well. Good luck.

13.4 A Trivial Proof

A Trivial Proof A Trivial Proof

13.5 A Typical State

A Typical State A Typical State

Observe that the states in typical models talk about

booleans integers vectors records caches bits symbols arrays stacks files characters strings sequences tables directories

These objects are discrete rather than continuous; furthermore they are built incrementally or inductively by repeatedly using primitive operations to put together smaller peices.

The functions we need to manipulate these objects do things like concatenate, reverse, sort, search, count, etc.

Flying Tour: see Section 13.29 [Functions for Manipulating these Objects], page 650

13.6 A Walking Tour of ACL2

A Walking Tour of ACL2 A Walking Tour of ACL2

On this tour you will learn a little more about the ACL2 logic, the theorem prover, and the user interface.

This time we will stick with really simple things, such as the associativity of list concatenation.

We assume you have taken the Flying Tour but that you did not necessarily follow all the “off-tour” links. So this tour may revisit some pages you’ve seen. Just click on the Walking Tour icon at the bottom of each page.

On this tour you will see many more links marked <>. We would like to discourage you from following these links right now. However we encourage you to note them. Basically, the <> sign here illustrates the documentation and introduces you to its main entry points. Once you have started to use ACL2 you can take the Walking Tour again but pursue more of the indicated links.

Walking Tour: see Section 13.23 [Common Lisp], page 646

13.7 ACL2 Characters

ACL2 Characters ACL2 Characters

ACL2 accepts 256 distinct characters, which are the characters obtained by applying the function code-char (CODE-CHAR^) <> to each integer from 0 to 255. Among these, Common Lisp designates certain ones as *standard-characters*, namely those of the form (code-char n) where n is from 33 to 126, together with #\Newline and #\Space. The actual standard characters may be viewed by evaluating the constant expression *standard-chars*.

The standard character constants are written by writing a hash mark followed by a backslash (#\) followed by the character.

The function characterp (CHARACTERP^) <> recognizes characters. For more details, See Section 10.83 [CHARACTERS], page 463 <>.

13.8 ACL2 Conses or Ordered Pairs

ACL2 Conses or Ordered Pairs ACL2 Conses or Ordered Pairs

The function cons (CONS^) <> creates an ordered pair. Car (CAR^) <> and cdr (CDR^) <> return the first and second components, respectively, of an ordered pair. The function consp (CONSP^) <> recognizes ordered pairs.

Ordered pairs are used to represent lists and trees. See any Common Lisp documentation for a discussion of how list constants are written and for the many list processing functions available. Also, see Chapter 10 [PROGRAMMING], page 429 <> where we list all the ACL2 primitive functions.

Here are some examples of list constants to suggest their syntax.

     '(a . b)                ; a pair whose car is 'a and cdr is 'b
     '(a . nil)              ; a pair whose car is 'a and cdr is nil
     '(a)                    ; another way to write the same thing
     '(a b)                  ; a pair whose car is 'a and cdr is '(b)
     '(a b c)                ; a pair whose car is 'a and cdr is '(b c)
                             ;  i.e., a list of three symbols, a, b, and c.
     '((a . 1) (b . 2))      ; a list of two pairs

It is useful to distinguish “proper” conses from “improper” ones, the former being those cons trees whose right-most branch terminates with nil. A “true list” (see Section 10.250 [TRUE-LISTP], page 542 <>) is either nil or a proper cons. (A b c . 7) is an improper cons and hence not a true list.

13.9 ACL2 Strings

ACL2 Strings ACL2 Strings

Strings of ACL2 characters (ACL2 Characters^) are written as sequences of characters delimited by “double quotation marks” ("). To put such a character in a string, escape it by preceding it with a backslash.

The function stringp (STRINGP^) <> recognizes strings and char (CHAR^) <> will fetch the nth character of a string. There are many other primitives for handling strings, such as string< (STRING<^) <> for comparing two strings lexicographically. We suggest you See Chapter 10 [PROGRAMMING], page 429 <> where we list all of the primitive ACL2 functions. Alternatively, see any Common Lisp language documentation.

13.10 ACL2 Symbols

ACL2 Symbols ACL2 Symbols Common Lisp’s symbols are a data type representing words. They are frequently regarded as atomic objects in the sense that they are not frequently broken down into their constituents. Often the only important properties of symbols is that they are not numbers, characters, strings, or lists and that two symbols are not equal if they look different (!). Examples of symbols include PLUS and SMITH::ABC. All function and variable names in ACL2 are symbols. When symbols are used as constants they must be quoted, as in 'PLUS.

The symbol T is commonly used as the Boolean “true.” The symbol NIL is commonly used both as the Boolean “false” and as the “empty list.” Despite sometimes being called the “empty list” NIL is a symbol not an “empty cons.” Unlike other symbols, T and NIL may be used as constants without quoting them.

Usually, symbols are written as sequences of alphanumeric characters other than those denoting numbers. Thus, A12, +1A and 1+ are symbols but +12 is a number. Roughly speaking, when symbols are read lower case characters are converted to upper case, so we frequently do not distinguish ABC from Abc or abc. See Section 13.25 [Conversion], page 647 for information about case conversion when symbols are read. However, any character can be used in a symbol, but some characters must be “escaped” to allow the Lisp reader to parse the sequence as a symbol. For example, |Abc| is a symbol whose first character is capitalized and whose remaining characters are in lower case. |An odd duck| is a symbol containing two #\Space characters. See any Common Lisp documentation for the syntactic rules for symbols.

Technically, a symbol is a special kind of pair consisting of a package name (which is a string) and a symbol name (which is also a string). (See Section 10.243 [SYMBOL-PACKAGE-NAME], page 540 <> and see Section 10.242 [SYMBOL-NAME], page 540 <>.) The symbol SMITH::ABC is said to be in package "SMITH" and to have the symbol name "ABC". The symbol ABC in package "SMITH" is generally not equal to the symbol ABC in package "JONES". However, it is possible to “import” symbols from one package into another one, but in ACL2 this can only be done when the package is created. (See Section 6.11 [DEFPKG], page 173 <>.) If the current-package (CURRENT-PACKAGE^) <> is "SMITH" then SMITH::ABC may be more briefly written as just ABC. Intern (INTERN^) <> “creates” a symbol of a given name in a given package.

13.11 ACL2 System Architecture

ACL2 System Architecture ACL2 System Architecture

The user interacts with the theorem prover by giving it definitions, theorems and advice (e.g., “use this lemma.”), often in the form of books books (BOOKS^) <>.

The theorem prover uses the rules in the library of books the user has selected. The theorem prover prints its proof attempts to the user. When a theorem is proved it is converted to a rule under the control of the user’s rule-classes (RULE-CLASSES^) <>. The informed user can make ACL2 do amazing things. Walking Tour: see Section 13.55 [Rewrite Rules are Generated from DEFTHM Events], page 664

13.12 ACL2 as an Interactive Theorem Prover

ACL2 as an Interactive Theorem Prover ACL2 as an Interactive Theorem Prover The ACL2 theorem prover finds proofs in the ACL2 logic. It can be automatic. But most often the user must help it. The user usually guides ACL2 by suggesting that it first prove key lemmas. Lemmas are just theorems used in the proofs of other theorems. See Section 13.13 [ACL2 as an Interactive Theorem Prover (continued)], page 638 to continue.

13.13 ACL2 as an Interactive Theorem Prover (continued)

ACL2 as an Interactive Theorem Prover (continued) ACL2 as an Interactive Theorem Prover (continued) Theorems, lemmas, definitions, and advice of various sorts can be stored in books (BOOKS^) <>. When a theorem or definition is stored in a book, the user can specify how it should be used in the future. When viewed this way, theorems and definitions are thought of as rules. The ACL2 theorem prover is rule driven. The rules are obtained from books. See Section 13.11 [ACL2 System Architecture], page 637 to continue.

Walking Tour: see Section 13.11 [ACL2 System Architecture], page 637

13.14 ACL2 is an Untyped Language

ACL2 is an Untyped Language ACL2 is an Untyped Language

The example

ACL2 !>(app ’(a b c) 27)

     (A B C . 27)

illustrates the fact that ACL2’s logic is untyped (see Section 13.16 [About Types], page 640 for a brief discussion of the typed versus untyped nature of the logic).

The definition of app makes no restriction of the arguments to lists. The definition says that if the first argument satisfies endp (ENDP^) <> then return the second argument. In this example, when app has recursed three times down the cdr of its first argument, '(a b c), it reaches the final nil, which satisfies endp, and so 27 is returned. It is naturally consed into the emerging list as the function returns from successive recursive calls (since cons does not require its arguments to be lists, either). The result is an “improper” list, (a b c . 27).

You can think of (app x y) as building a binary tree by replacing the right-most tip of the tree x with the tree y.

13.15 About Models

About Models About Models

ACL2 is used to construct mathematical models of computer hardware and software (i.e., “digital systems”).

A mathematical model is a set of mathematical formulas used to predict the behavior of some artifact.

The use of mathematical models allows faster and cheaper delivery of better systems.

Models need not be complete or perfectly accurate to be useful to the trained engineer.

See Section 13.38 [Models in Engineering], page 655 for more discussion of these assertions in an engineering context.

Flying Tour: see Section 13.39 [Models of Computer Hardware and Software], page 656

13.16 About Types

About Types About Types

The universe of ACL2 objects includes objects of many different types. For example, t is a “symbol” and 3 is an “integer.” Roughly speaking the objects of ACL2 can be partitioned into the following types:

Numbers (Numbers in ACL2^) 3, -22/7, #c(3 5/2) Characters (ACL2 Characters^) #\A, #\a, #\Space Strings (ACL2 Strings^) "This is a string." Symbols (ACL2 Symbols^) 'abc, 'smith::abc Conses (or Ordered Pairs) (ACL2 Conses or Ordered Pairs^) '((a . 1) (b . 2))

When proving theorems it is important to know the types of object returned by a term. ACL2 uses a complicated heuristic algorithm, called type-set (TYPE-SET^) <>, to determine what types of objects a term may produce. The user can more or less program the type-set algorithm by proving type-prescription (TYPE-PRESCRIPTION^) <> rules.

ACL2 is an “untyped” logic in the sense that the syntax is not typed: It is legal to apply a function symbol of n arguments to any n terms, regardless of the types of the argument terms. Thus, it is permitted to write such odd expressions as (+ t 3) which sums the symbol t and the integer 3. Common Lisp does not prohibit such expressions. We like untyped languages because they are simple to describe, though proving theorems about them can be awkward because, unless one is careful in the way one defines or states things, unusual cases (like (+ t 3)) can arise.

To make theorem proving easier in ACL2, the axioms actually define a value for such terms. The value of (+ t 3) is 3; under the ACL2 axioms, non-numeric arguments to + are treated as though they were 0.

You might immediately wonder about our claim that ACL2 is Common Lisp, since (+ t 3) is “an error” (and will sometimes even “signal an error”) in Common Lisp. It is to handle this problem that ACL2 has guards. We will discuss guards later in the Walking Tour. However, many new users simply ignore the issue of guards entirely.

You should now return to the Walking Tour (Revisiting the Admission of App^).

13.17 About the ACL2 Home Page

About the ACL2 Home Page About the ACL2 Home Page

The ACL2 Home Page is integrated into the ACL2 online documentation. Over 1.5 megabytes of text is available here.

The vast majority of the text is user-level documentation. For example, to find out about rewrite (REWRITE^) <> rules you could click on the word “rewrite (REWRITE^) <>.” But before you do that remember that you must then use your browser’s back commands to come back here.

The tiny warning signs <> mark pointers that lead out of the introductory-level material and into the user documentation. If you are taking the Flying Tour, we advise you to avoid following such pointers the first time; it is easy to get lost in the full documentation unless you are pursuing the answer to a specific question. If you do wander down these other paths, remember you can back out to a page containing the Flying Tour icon to resume the tour.

At the end of the tour you will have a chance to return to The Flight Plan (A Flying Tour of ACL2^) where you can revisit the main stops of the Flying Tour and explore the alternative paths more fully.

Finally, every page contains two icons at the bottom. The ACL2 icon leads you back to the ACL2 Home Page. The Index icon allows you to browse an alphabetical listing of all the topics in ACL2’s online documentation.

Flying Tour: see Section 13.104 [What Is ACL2(Q)], page 687

13.18 About the Admission of Recursive Definitions

About the Admission of Recursive Definitions About the Admission of Recursive Definitions

You can’t just add any formula as an axiom or definition and expect the logic to stay sound! The purported “definition” of APP must have several properties to be admitted to the logic as a new axiom

The key property a recursive definition must have is that the recursion terminate. This, along with some syntactic criteria, insures us that there exists a function satisfying the definition.

Termination must be proved before the definition is admitted. This is done in general by finding a measure of the arguments of the function and a well-founded relation such that the arguments “get smaller” every time a recursive branch is taken.

For app the measure is the “size” of the first argument, x, as determined by the primitive function acl2-count (ACL2-COUNT^) <>. The well-founded relation used in this example is e0-ordinalp (E0-ORDINALP^) <>, which is the standard ordering on the ordinals less than “epsilon naught.” These particular choices for app were made “automatically” by ACL2. But they are in fact determined by various “default” settings. The user of ACL2 can change the defaults or specify a “hint” to the defun (DEFUN^) <> command to specify the measure and relation.

You should now return to the Walking Tour (Revisiting the Admission of App^).

13.19 About the Prompt

About the Prompt About the Prompt

The string “ACL2 !>” is the ACL2 prompt.

The prompt tells the user that an ACL2 command (COMMAND^) <>is expected. In addition, the prompt tells us a little about the current state of the ACL2 command interpreter. We explain the prompt briefly below. But first we talk about the command interpreter.

An ACL2 command is generally a Lisp expression to be evaluated. There are some unusual commands (such as :q (Q^) <> for quitting ACL2) which cause other behavior. But most commands are read, evaluated, and then have their results printed. Thus, we call the command interpreter a “read-eval-print loop.” The ACL2 command interpreter is named LD (LD^) <> (after Lisp’s “load”).

A command like (defun app (x y) ...) causes ACL2 to evaluate the defun (DEFUN^) <> function on app, (x y) and .... When that command is evaluated it prints some information to the terminal explaining the processing of the proposed definition. It returns the symbol APP as its value, which is printed by the command interpreter. (Actually, defun is not a function but a macro (DEF-MACRO^) which expands to a form that involves state (STATE^) <>, a necessary precondition to printing output to the terminal and to “changing” the set of axioms. But we do not discuss this further here.)

The defun command is an example of a special kind of command called an “event.” Events (EVENTS^) <> are those commands that change the “logical world” by adding such things as axioms or theorems to ACL2’s data base. See Section 8.100 [WORLD], page 399 <>. But not every command is an event command.

A command like (app ’(1 2 3) ’(4 5 6 7)) is an example of a non-event. It is processed the same general way: the function app is applied to the indicated arguments and the result is printed. The function app does not print anything and does not change the “world.”

A third kind of command are those that display information about the current logical world or that “backup” to previous versions of the world. Such commands are called “history (HISTORY^)” <> commands.

What does the ACL2 prompt tell us about the read-eval-print loop? The prompt “ACL2 !>” tells us that the command will be read with current-package (CURRENT-PACKAGE^) <> set to "ACL2", that guard checking (see Section 9.12 [SET-GUARD-CHECKING], page 423 <>) is on (“!”), and that we are at the top-level (there is only one “>”). For more about the prompt, see Section 8.19 [DEFAULT-PRINT-PROMPT], page 274 <>.

You should now return to the Walking Tour (Revisiting the Admission of App^).

13.20 An Example Common Lisp Function Definition

An Example Common Lisp Function Definition An Example Common Lisp Function Definition

Consider the binary trees x and y below.

In Lisp, x is written as the list '(A B) or, equivalently, as '(A B . NIL). Similarly, y may be written '(C D E). Suppose we wish to replace the right-most tip of x by the entire tree y. This is denoted (app x y), where app stands for “append”.

We can define app with:

(defun app (x y) ; Concatenate x and y. (declare (type (satisfies true-listp) x)); We expect x to end in NIL. (cond ((endp x) y) ; If x is empty, return y. (t (cons (car x) ; Else, copy first node

(app (cdr x) y))))) ; and recur into next.

If you defined this function in some Common Lisp, then to run app on the x and y above you could then type

     (app '(A B) '(C D E))

and Common Lisp will print the result (A B C D E).

Walking Tour: see Section 13.21 [An Example of ACL2 in Use], page 644

13.21 An Example of ACL2 in Use

An Example of ACL2 in Use An Example of ACL2 in Use

To introduce you to ACL2 we will consider the app function discussed in the Common Lisp (Common Lisp^) page, except we will omit for the moment the declare form, which in ACL2 is called a guard. We will deal with guards later.

Here is the definition again

(defun app (x y)

(cond ((endp x) y)

(t (cons (car x)

(app (cdr x) y)))))

The next few stops along the Walking Tour will show you

* how to use the ACL2 documentation,

* what happens when the above definition is submitted to ACL2,

* what happens when you evaluate calls of app,

* what one simple theorem about app looks like,

* how ACL2 proves the theorem, and

* how that theorem can be used in another proof.

Along the way we will talk about the definitional principle, types, the ACL2 read-eval-print loop, and how the theorem prover works. When we complete this part of the tour we will introduce the notion of guards and revisit several of the topics above in that context. Walking Tour: see Section 13.35 [How To Find Out about ACL2 Functions], page 654

13.22 Analyzing Common Lisp Models

Analyzing Common Lisp Models Analyzing Common Lisp Models To analyze a model you must be able to reason about the operations and relations involved. Perhaps, for example, some aspect of the model depends upon the fact that the concatenation operation is associative. In any Common Lisp you can confirm that

     (app '(A B) (app '(C D) '(E F)))

and

     (app (app '(A B) '(C D)) '(E F)))

both evaluate to the same thing, (A B C D E F). But what distinguishes ACL2 (the logic) from applicative Common Lisp (the language) is that in ACL2 you can prove that the concatenation function app is associative when its arguments are true-lists, whereas in Common Lisp all you can do is test that proposition. That is, in ACL2 it makes sense to say that the following formula is a “theorem.”

     Theorem Associativity of App
     (implies (and (true-listp a)
                   (true-listp b))
              (equal (app (app a b) c)
                     (app a (app b c))))

Theorems about the properties of models are proved by symbolically manipulating the operations and relations involved. If the concatenation of sequences is involved in your model, then you may well need the theorem above in order to that your model has some particular property.

13.23 Common Lisp

Common Lisp Common Lisp

The logic of ACL2 is based on Common Lisp.

Common Lisp is the standard list processing programming language. It is documented in: Guy L. Steele, Common Lisp The Language, Digital Press, 12 Crosby Drive, Bedford, MA 01730, 1990.

ACL2 formalizes only a subset of Common Lisp. It includes such familiar Lisp functions as cons, car and cdr for creating and manipulating list structures, various arithmetic primitives such as +, *, expt and <=, and intern and symbol-name for creating and manipulating symbols. Control primitives include cond, case and if, as well as function call, including recursion. New functions are defined with defun and macros with defmacro. See Chapter 10 [PROGRAMMING], page 429 <> for a list of the Common Lisp primitives supported by ACL2.

ACL2 is a very small subset of full Common Lisp. ACL2 does not include the Common Lisp Object System (CLOS), higher order functions, circular structures, and other aspects of Common Lisp that are non-applicative. Roughly speaking, a language is applicative if it follows the rules of function application. For example, f(x) must be equal to f(x), which means, among other things, that the value of f must not be affected by “global variables” and the object x must not change over time.

See Section 13.20 [An Example Common Lisp Function Definition], page 643 for a simple example of Common Lisp.

Walking Tour: see Section 13.20 [An Example Common Lisp Function Definition], page 643

13.24 Common Lisp as a Modeling Language

Common Lisp as a Modeling Language Common Lisp as a Modeling Language In ACL2 we have adopted Common Lisp as the basis of our modeling language. If you have already read our brief note on Common Lisp and recall the example of app, please proceed. Otherwise see Section 13.23 [Common Lisp], page 646 for an exceedingly brief introduction to Common Lisp and then come back here.

In Common Lisp it is very easy to write systems of formulas that manipulate discrete, inductively constructed data objects. In building a model you might need to formalize the notion of sequences and define such operations as concatenation, length, whether one is a permutation of the other, etc. It is easy to do this in Common Lisp. Furthermore, if you have a Common Lisp “theory of sequences” you can run the operations and relations you define. That is, you can execute the functions on concrete data to see what results your formulas produce.

If you define the function app as shown above and then type

     (app '(A B) '(C D E))

in any Common Lisp, the answer will be computed and will be (A B C D E).

The executable nature of Common Lisp and thus of ACL2 is very handy when producing models.

But executability is not enough for a modeling language because the purpose of models is to permit analysis.

See Section 13.22 [Analyzing Common Lisp Models], page 645 to continue.

13.25 Conversion

Conversion Conversion to Uppercase

When symbols are read by Common Lisp they are converted to upper case. Note carefully that this remark applies to the characters in symbols. The characters in strings are not converted upper case.

To type a symbol containing lower case characters you can enclose the symbol in vertical bars, as in |AbC| or you can put a “backslash” before each lower case character you wish to preserve, as in A\bC. |AbC| and A\bC are two different ways of writing the same symbol (just like 4/2 and 1/2 are two different ways of writing the same rational). The symbol has three characters in its name, the middle one of which is a lower case b.

13.26 Corroborating Models

Corroborating Models Corroborating Models

After producing a model, it must be corroborated against reality. The Falling Body Model has been corroborated by a vast number of experiments in which the time and distance were measured and compared according to the formula. In general all models must be corroborated by experiment.

The Falling Body Model can be derived from deeper models, namely Newton’s laws of motion and the assertion that, over the limited distances concerned, graviation exerts a constant acceleration on the object. When the model in question can be derived from other models, it is the other models that are being corroborated by our experiments.

Because nature is not formal, we cannot prove that our models of it are correct. All we can do is test our models against nature’s behavior.

Such testing often exposes restrictions on the applicability of our models. For example, the Falling Body Model is inaccurate if air resistance is significant. Thus, we learn not to use that model to predict how long it takes a feather to fall from a 200 foot tower in the earth’s atmosphere.

In addition, attempts at corroboration might reveal that the model is actually incorrect. Careful measurements might expose the fact that the gravitational force increases as the body falls closer to earth. Very careful measurements might reveal relativistic effects. Technically, the familiar Falling Body Model is just wrong, even under excessive restrictions such as “in a perfect vacuum” and “over small distances.” But it is an incredibly useful model nonetheless.

There are several morals here.

Models need not be complete to be useful.

Models need not be perfectly accurate to be useful.

The user of a model must understand its limitations.

Flying Tour: see Section 13.39 [Models of Computer Hardware and Software], page 656

13.27 Evaluating App on Sample Input

Evaluating App on Sample Input Evaluating App on Sample Input

ACL2 !>(app nil ’(x y z))

(X Y Z)

ACL2 !>(app ’(1 2 3) ’(4 5 6 7))

(1 2 3 4 5 6 7)
ACL2 !>(app ’(a b c d e f g) ’(x y z)) ; see Section 13.25 [Conversion], page 647 for an explanation
(A B C D E F G X Y Z)

ACL2 !>(app (app ’(1 2) ’(3 4)) ’(5 6))

(1 2 3 4 5 6)

ACL2 !>(app ’(1 2) (app ’(3 4) ’(5 6)))

(1 2 3 4 5 6)

ACL2!>(let ((a ’(1 2))

(b ’(3 4)) (c ’(5 6))) (equal (app (app a b) c)

(app a (app b c))))

T

As we can see from these examples, ACL2 functions can be executed more or less as Common Lisp.

The last three examples suggest an interesting property of app.

Walking Tour: see Section 13.62 [The Associativity of App], page 668

13.28 Flawed Induction Candidates in App Example

Flawed Induction Candidates in App Example Flawed Induction Candidates in App Example

Induction on a is unflawed: every occurrence of a in the conjecture

     (equal (app (app a b) c)
            (app a (app b c)))

is in a position being recursively decomposed! Now look at the occurrences of b. The first (shown in bold below) is in a position that is held constant in the recursion of (app a b). It would be “bad” to induct on b here.

     (equal (app (app a b) c)
            (app a (app b c)))

13.29 Functions for Manipulating these Objects

Functions for Manipulating these Objects Functions for Manipulating these Objects Consider a typical “stack” of control frames. Suppose the model required that we express the idea of “the most recent frame whose return program counter points into MAIN.” The natural expression of this notion involves function application – “fetch the return-pc of this frame” case analysis – “if the pc is MAIN, then ...” iteration or recursion – “pop this frame off and repeat.” The designers of ACL2 have taken the position that a programming language is the natural language in which to define such notions, provided the language has a mathematical foundation so that models can be analyzed and properties derived logically. is the language supported by ACL2. See Section 13.23 [Common Lisp], page 646 for an optional and very brief introduction to Common Lisp. Flying Tour: see Section 13.37 [Modeling in ACL2], page 655

13.30 Guards

Guards Guards

Common Lisp functions are partial; they are not defined for all possible inputs. But ACL2 functions are total. Roughly speaking, the logical function of a given name in ACL2 is a completion of the Common Lisp function of the same name obtained by adding some arbitrary but “natural” values on arguments outside the “intended domain” of the Common Lisp function.

ACL2 requires that every ACL2 function symbol have a “guard,” which may be thought of as a predicate on the formals of the function describing the intended domain. The guard on the primitive function car (CAR^) <>, for example, is (or (consp x) (equal x nil)), which requires the argument to be either an ordered pair or nil. We will discuss later how to specify a guard for a defined function; when one is not specified, the guard is t which is just to say all arguments are allowed.

But guards are entirely extra-logical: they are not involved in the axioms defining functions. If you put a guard on a defined function, the defining axiom added to the logic defines the function on all arguments, not just on the guarded domain.

So what is the purpose of guards?

The key to the utility of guards is that we provide a mechanism, called “guard verification,” for checking that all the guards in a formula are true. That is,(i-am-here)

Functions in ACL2 may restrict their arguments. These restrictions take the form of formulas about the formal parameters. These formulas are called “guards.” The Common Lisp primitives such as car (CAR^) <> and endp (ENDP^) <> have guards. ACL2 permits you to specify restrictions on the arguments to the functions you define. To do so you use the xargs (XARGS^) <> declaration (see Section 10.94 [DECLARE], page 469 <>) for defun (DEFUN^) <>.

Logically speaking, guards are irrelevant. (i-am-here)

13.31 Guessing the Type of a Newly Admitted Function

Guessing the Type of a Newly Admitted Function Guessing the Type of a Newly Admitted Function When a function is admitted to the logic, ACL2 tries to “guess” what type of object it returns. This guess is codified as a term that expresses a property of the value of the function. For app the term is

     (OR (CONSP (APP X Y))
         (EQUAL (APP X Y) Y))

which says that app returns either a cons or its second argument. This formula is added to ACL2’s rule base as a type-prescription (TYPE-PRESCRIPTION^) <> rule. Later we will discuss how rules are used by the ACL2 theorem prover. The point here is just that when you add a definition, the data base of rules is updated, not just by the addition of the definitional axiom, but by several new rules.

You should now return to the Walking Tour (Revisiting the Admission of App^).

13.32 Guiding the ACL2 Theorem Prover

Guiding the ACL2 Theorem Prover Guiding the ACL2 Theorem Prover

Now that you have seen the theorem prover in action you might be curious as to how you guide it.

The idea is that the user submits conjectures and advice and reads the proof attempts as they are produced.

Most of the time, the conjectures submitted are lemmas to be used in the proofs of other theorems.

Walking Tour: see Section 13.13 [ACL2 as an Interactive Theorem Prover (continued)], page 638

13.33 Hey Wait! Is ACL2 Typed or Untyped(Q)

Hey Wait! Is ACL2 Typed or Untyped(Q) Hey Wait! Is ACL2 Typed or Untyped?

The example

ACL2 !>(app 7 27)

     ACL2 Error in TOP-LEVEL:  The guard for the function symbol ENDP, which
     is (OR (CONSP X) (EQUAL X NIL)), is violated by the arguments in the
     call (ENDP 7).

illustrates the fact that while ACL2 is an untyped language the ACL2 evaluator can be configured so as to check “types” at runtime. We should not say “types” here but “guards.” See Section 13.102 [Undocumented Topic], page 686 for a discussion of guards.

The guard on endp (ENDP^) <> requires its argument to be a true list. Since 7 is not a true list, and since ACL2 is checking guards in this example, an error is signaled by ACL2. How do you know ACL2 is checking guards? Because the prompt tells us (see Section 13.19 [About the Prompt], page 642) with its “!”.

13.34 How Long Does It Take to Become an Effective User(Q)

How Long Does It Take to Become an Effective User(Q) How Long Does It Take to Become an Effective User?

The training time depends primarily on the background of the user.

We expect that a user who

* has a bachelor’s degree in computer science or mathematics,

* has some experience with formal methods,

* has had some exposure to Lisp programming and is comfortable with the Lisp notation,

* is familiar with and has unlimited access to a Common Lisp host processor, operating system, and text editor (we use Sun workstations running Unix and GNU Emacs),

* is willing to read and study the ACL2 documentation, and

* is given the opportunity to start with “toy” projects before being expected to tackle the company’s Grand Challenge,

will probably take several months to become an effective ACL2 user.

Flying Tour: see Section 13.43 [Other Requirements], page 658

13.35 How To Find Out about ACL2 Functions

How To Find Out about ACL2 Functions How To Find Out about ACL2 Functions

Most ACL2 primitives are documented. Here is the definition of app again, with the documented topics highlighted. <> All of the links below lead into the ACL2 online documentation, 1.5 megabytes of hyperlinked text. So follow these links around, but remember to come back here!

     (defun (DEFUN^) app (x y)
       (cond (COND^) ((endp (ENDP^) x) y)
             (t (cons (CONS^) (car (CAR^) x)
                      (app (cdr (CDR^) x) y)))))

By following the link on endp (ENDP^) <> we see that it is a Common Lisp function and is defined to be the same as atom (ATOM^) <>, which recognizes non-conses. But endp has a guard. Since we are ignorning guards for now, we’ll ignore the guard issue on endp.

So this definition reads “to app x and y: if x is an atom, return y; otherwise, app (cdr x) and y and then cons (car x) onto that.”

Walking Tour: see Section 13.36 [How To Find Out about ACL2 Functions (continued)], page 654

13.36 How To Find Out about ACL2 Functions (continued)

How To Find Out about ACL2 Functions (continued) How To Find Out about ACL2 Functions (continued)

You can always use the Index <> to find the documentation of functions. Try it. Click on the Index icon below. Then use the Find command of your browser to find “endp” in that document and follow the link. But remember to come back here.

The ACL2 documentation is also available via Emacs’ TexInfo, allowing you to explore the hyperlinked documentation in the comfort of a text editor that can also interact with ACL2.

In addition, some runtime images of ACL2 (the so-called “large image”) have the hyperlinked text as a large ACL2 data structure that can be explored with ACL2’s :doc command. If you have ACL2 running, try the command :doc endp. If that doesn’t work, you are running the “small image.”

Another way to find out about ACL2 functions, if you have an ACL2 image available, is to use the command :args (ARGS^) <> which prints the formals, type, and guard of a function symbol. Of course, the ACL2 documentation can also be printed out as 700 page book. See the ACL2 Home Page to download the Postscript. Now let’s continue with app. Walking Tour: see Section 13.61 [The Admission of App], page 667

13.37 Modeling in ACL2

Modeling in ACL2 Modeling in ACL2 Below we define mc(s,n) to be the function that single-steps n times from a given starting state, s. In Common Lisp, “mc(s,n)” is written (mc s n).

(defun mc (s n) ; To step s n times: (if (zp n) ; If n is 0

          s  ;    then return s

(mc (single-step s) (- n 1)))) ; else step single-step(s)

                                                           n-1 times.

This is an example of a formal model in ACL2. Flying Tour: see Section 13.56 [Running Models], page 665

13.38 Models in Engineering

Models in Engineering Models in Engineering Frequently, engineers use mathematical models. Use of such models frequently lead to better designs, faster completion of acceptable products, and reduced overall cost, because models allow the trained user to study the design before it is built and analyze its properties. Usually, testing and analyzing a model is cheaper and faster than fabricating and refabricating the product. See Section 13.71 [The Falling Body Model], page 673 to continue.

13.39 Models of Computer Hardware and Software

Models of Computer Hardware and Software Models of Computer Hardware and Software Computing machines, whether hardware or software or some combintation, are frequently modeled as “state machines.” To so model a computing machine we must represent its states as objects in our mathematical framework. Transitions are functions or relations on state objects. In what language shall we define these objects, functions, and relations? The mathematical languages we were taught in high school algebra, geometry, trignometry, and calculus are inappropriate for modeling digital systems. They primarily let us talk about numbers and continuous functions. To see what kind of expressive power we need, take a closer look at what a typical state contains.

Flying Tour: see Section 13.5 [A Typical State], page 634

13.40 Name the Formula Above

Name the Formula Above Name the Formula Above

When the theorem prover explicitly assigns a name, like *1, to a formula, it has decided to prove the formula by induction.

13.41 Numbers in ACL2

Numbers in ACL2 Numbers in ACL2

The numbers in ACL2 can be partitioned into the following subtypes:

Rationals Integers Positive integers 3 Zero 0 Negative Integers -3 Non-Integral Rationals Positive Non-Integral Rationals 19/3 Negative Non-Integral Rationals -22/7 Complex Rational Numbers #c(3 5/2) ; = 3+(5/2)i

Signed integer constants are usually written (as illustrated above) as sequences of decimal digits, possibly preceded by + or -. Decimal points are not allowed. Integers may be written in binary, as in #b1011 (= 23) and #b-111 (= -7). Octal may also be used, #o-777 = -511. Non-integral rationals are written as a signed decimal integer and an unsigned decimal integer, separated by a slash. Complex rationals are written as #c(rpart ipart) where rpart and ipart are rationals.

Of course, 4/2 = 2/1 = 2 (i.e., not every rational written with a slash is a non-integer). Similarly, #c(4/2 0) = #c(2 0) = 2.

The common arithmetic functions and relations are denoted by +, -, *, /, =, <, <=, > and >=. However there are many others, e.g., floor, ceiling, and lognot. We suggest you see Chapter 10 [PROGRAMMING], page 429 <> where we list all of the primitive ACL2 functions. Alternatively, see any Common Lisp language documentation.

The primitive predicates for recognizing numbers are illustrated below. The following ACL2 function will classify an object, x, according to its numeric subtype, or else return ’NaN (not a number). We show it this way just to illustrate programming in ACL2.

      (defun classify-number (x)
        (cond ((rationalp x)
               (cond ((integerp x)
                      (cond ((< 0 x) 'positive-integer)
                            ((= 0 x) 'zero)
                            (t 'negative-integer)))
                     ((< 0 x) 'positive-non-integral-rational)
                     (t 'negative-non-integral-rational)))
              ((complex-rationalp x) 'complex-rational)
              (t 'NaN)))

13.42 On the Naming of Subgoals

On the Naming of Subgoals On the Naming of Subgoals

Subgoal *1/2 is the induction step from the scheme, obtained by instantiating the scheme with our conjecture.

We number the cases “backward”, so this is case “2” of the proof of “*1”. We number them backward so you can look at a subgoal number and get an estimate for how close you are to the end.

13.43 Other Requirements

Other Requirements Other Requirements

ACL2 is distributed on the Web without fee.

There is a License agreement, which is available via the ACL2 Home Page link below.

ACL2 currently runs on the Unix, Linux, and Macintosh operating systems. It can be built in any of the following Common Lisps:

* Allegro,

* GCL (Gnu Common Lisp) [or, AKCL],

* Lispworks,

* Lucid, and

* MCL (Macintosh Common Lisp). We recommend running ACL2 with at least 16MB of memory and prefer significantly more (e.g., 64MB). Flying Tour: see Section 13.64 [The End of the Flying Tour], page 669

13.44 Overview of the Expansion of ENDP in the Base Case

Overview of the Expansion of ENDP in the Base Case Overview of the Expansion of ENDP in the Base Case Subgoal *1/1 is the Base Case of our induction. It simplifies to Subgoal *1/1' by expanding the ENDP term in the hypothesis, just as we saw in the earlier proof of Subgoal *1/2.

13.45 Overview of the Expansion of ENDP in the Induction Step

Overview of the Expansion of ENDP in the Induction Step Overview of the Expansion of ENDP in the Induction Step In this message the system is saying that Subgoal *1/2 has been rewritten to the Subgoal *1/2', by expanding the definition of endp. This is an example of simplification, one of the main proof techniques used by the theorem prover. See Section 13.68 [The Expansion of ENDP in the Induction Step (Step 0)], page 672 if you would like to step through the simplification of Subgoal *1/2.

13.46 Overview of the Final Simplification in the Base Case

Overview of the Final Simplification in the Base Case Overview of the Final Simplification in the Base Case

The But is our signal that the goal is proved.

See Section 13.72 [The Final Simplification in the Base Case (Step 0)], page 674 to step through the proof. It is very simple.

13.47 Overview of the Proof of a Trivial Consequence

Overview of the Proof of a Trivial Consequence Overview of the Proof of a Trivial Consequence

ACL2 !>(defthm trivial-consequence

(equal (app (app (app (app x1 x2) (app x3 x4)) (app x5 x6)) x7) (app x1 (app (app x2 x3) (app (app x4 x5) (app x6 x7))))))

ACL2 Warning (The WARNING about the Trivial Consequence^) [Subsume] in ( DEFTHM TRIVIAL-CONSEQUENCE ...):  The previously
added rule ASSOCIATIVITY-OF-APP subsumes the newly proposed :REWRITE
rule TRIVIAL-CONSEQUENCE, in the sense that the old rule rewrites a
more general target.  Because the new rule will be tried first, it
may nonetheless find application.
By the simple :rewrite rule ASSOCIATIVITY-OF-APP (The First Application of the Associativity Rule^) we reduce the conjecture
to
Goal'
(EQUAL (APP X1
            (APP X2
                 (APP X3 (APP X4 (APP X5 (APP X6 X7))))))
       (APP X1
            (APP X2
                 (APP X3 (APP X4 (APP X5 (APP X6 X7))))))).
But we reduce the conjecture to T, by primitive type reasoning.
Q.E.D.
Summary
Form:  ( DEFTHM TRIVIAL-CONSEQUENCE ...)
Rules: ((:REWRITE ASSOCIATIVITY-OF-APP)
        (:FAKE-RUNE-FOR-TYPE-SET NIL))
Warnings:  Subsume (The Summary of the Proof of the Trivial Consequence^)
Time:  0.20 seconds (prove: 0.02, print: 0.00, other: 0.18)
 TRIVIAL-CONSEQUENCE

You might explore the links before moving on.

Walking Tour: see Section 13.66 [The End of the Walking Tour], page 670

13.48 Overview of the Simplification of the Base Case to T

Overview of the Simplification of the Base Case to T Overview of the Simplification of the Base Case to T

     Subgoal *1/1 (Overview of the Expansion of ENDP in the Base Case^)
     (IMPLIES (ENDP A)
              (EQUAL (APP (APP A B) C)
                     (APP A (APP B C)))).
     By the simple :definition ENDP we reduce the conjecture to
     Subgoal *1/1'
     (IMPLIES (NOT (CONSP A))
              (EQUAL (APP (APP A B) C)
                     (APP A (APP B C)))).
     But (Overview of the Final Simplification in the Base Case^) simplification reduces this to T, using the :definition APP and
     primitive type reasoning.

Walking Tour: see Section 13.65 [The End of the Proof of the Associativity of App], page 670

13.49 Overview of the Simplification of the Induction Conclusion

Overview of the Simplification of the Induction Conclusion Overview of the Simplification of the Induction Conclusion

In this message the system is saying that Subgoal *1/2' has been rewritten T using the rules noted. The word “But” at the beginning of the sentence is a signal that the goal has been proved.

See Section 13.84 [The Simplification of the Induction Conclusion (Step 0)], page 678 to step through the proof of Subgoal *1/2'.

13.50 Overview of the Simplification of the Induction Step to T

Overview of the Simplification of the Induction Step to T Overview of the Simplification of the Induction Step to T

     Subgoal *1/2 (On the Naming of Subgoals^)
     (IMPLIES (AND (NOT (ENDP A))
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (APP (APP A B) C)
                     (APP A (APP B C)))).
     By the simple :definition ENDP (Overview of the Expansion of ENDP in the Induction Step^) we reduce the conjecture to
     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (APP (APP A B) C)
                     (APP A (APP B C)))).
     But (Overview of the Simplification of the Induction Conclusion^) simplification reduces this to T, using the :definition APP, the
     :rewrite rules CDR-CONS and CAR-CONS and primitive type reasoning.

Walking Tour: see Section 13.48 [Overview of the Simplification of the Base Case to T], page 661

13.51 Perhaps

Perhaps Perhaps

The theorem prover’s proof is printed in real time. At the time it prints “Perhaps” it does not know the proof will succeed.

13.52 Popping out of an Inductive Proof

Popping out of an Inductive Proof Popping out of an Inductive Proof

Recall that our induction scheme (see Section 13.81 [The Proof of the Associativity of App], page 677 to revisit it) had two cases, the induction step (Subgoal *1/2) and the base case (Subgoal *1/1). Both have been proved!

13.53 Proving Theorems about Models

Proving Theorems about Models Proving Theorems about Models

But ACL2 is a logic. We can prove theorems about the model.

Theorem. MC ’mult is a multiplier

     (implies (and (natp x)
                   (natp y))
              (equal (lookup 'z (mc (s 'mult x y) (mclk x)))
                     (* x y))).

This theorem says that a certain program running on the mc machine will correctly multiply any two natural numbers.

It is a statement about an infinite number of test cases!

We know it is true about the model because we proved it.

Flying Tour: see Section 13.105 [What is Required of the User(Q)], page 687

13.54 Revisiting the Admission of App

Revisiting the Admission of App Revisiting the Admission of App

Here is the definition of app again with certain parts highlighted. If you are taking the Walking Tour, please read the text carefully and click on each of the links below, except those marked <>. Then come back here.

     ACL2 !> (About the Prompt^)(defun app (x y)

(cond ((endp x) y)

(t (cons (car x) (app (cdr x) y)))))

     The admission (About the Admission of Recursive Definitions^) of APP is trivial, using the
     relation E0-ORD-< (E0-ORD-<^) <> (which is known to be well-founded on
     the domain recognized by E0-ORDINALP (E0-ORDINALP^) <>) and the measure
     (ACL2-COUNT (ACL2-COUNT^) <> X).  We observe (Guessing the Type of a Newly Admitted Function^) that the
     type (About Types^) of APP is described by the theorem (OR

(CONSP (APP X Y)) (EQUAL (APP X Y) Y)).  We used primitive type
reasoning.
Summary (The Event Summary^)
Form:  ( DEFUN APP ...)
Rules: ((:FAKE-RUNE-FOR-TYPE-SET NIL))
Warnings:  None
Time:  0.03 seconds (prove: 0.00, print: 0.00, other: 0.03)
 APP

Walking Tour: see Section 13.27 [Evaluating App on Sample Input], page 649

13.55 Rewrite Rules are Generated from DEFTHM Events

Rewrite Rules are Generated from DEFTHM Events Rewrite Rules are Generated from DEFTHM Events

By reading the documentation of defthm (DEFTHM^) <> (and especially of its :rule-classes (RULE-CLASSES^) <> argument) you would learn that when we submitted the command

(defthm associativity-of-app

(equal (app (app a b) c) (app a (app b c))))

we not only command the system to prove that app is an associative function but

* we commanded it to use that fact as a rewrite rule.

That means that every time the system encounters a term of the form

(app (app x y) z)

it will replace it with

(app x (app y z))!

Walking Tour: see Section 13.109 [You Must Think about the Use of a Formula as a Rule], page 689

13.56 Running Models

Running Models Running Models Suppose the machine being modeled is some kind of arithmetic unit. Suppose the model can be initialized so as to multiply x times y and leave the answer in z. Then if we initialize s to multiply with x=5 and y=7 and run the machine long enough, we can read the answer 35 in the final state. Because ACL2 is a programming language, our model can be run or executed. If you defined the model in ACL2 and then typed

     > (lookup 'z (mc (s 'mult 5 7) 29))

then ACL2 would compute 35. You can emulate or test the model of your machine. This is obvious because ACL2 is Common Lisp; and Common Lisp is a programming language. Flying Tour: see Section 13.60 [Symbolic Execution of Models], page 667

13.57 STATE is the Only Variable in Top-Level Forms

STATE is the Only Variable in Top-Level Forms STATE is the Only Variable in Top-Level Forms

ACL2!>(equal (app (app a b) c)

(app a (app b c))))

     ACL2 Error in TOP-LEVEL:  STATE is the only variable we permit to occur
     freely in expressions to be evaluated, but C, B and A occur freely
     in (EQUAL (APP (APP A B) C) (APP A (APP B C))).  Embed symbols in (@
     *) to access their global values.

This cryptic message means: you can’t evaluate terms containing unbound or free variables like a, b and c above. Actually, one free variable is permitted in top-level forms: the variable state (STATE^) <>, which denotes the current ACL2 state and which is given very special treatment in this applicative programming language. We do not discuss state here.

ACL2 provides a way for you to use state to save values of computations at the top-level and refer to them later. See assign (ASSIGN^) <> and @ (@^) <>.

13.58 Subsumption of Induction Candidates in App Example

Subsumption of Induction Candidates in App Example Subsumption of Induction Candidates in App Example After collecting induction suggestions from these three terms

     (app a b)
     (app b c)
     (app a (app b c))

the system notices that the first and last suggest the same decomposition of a. So we are left with two ideas about how to induct: Decompose a as we would to unwind (app a b). Decompose b as we would to unwind (app b c).

13.59 Suggested Inductions in the Associativity of App Example

Suggested Inductions in the Associativity of App Example Suggested Inductions in the Associativity of App Example To find a plausible induction argument, the system studies the recursions exhibited by the terms in the conjecture. Roughly speaking, a call of a recursive function “suggests” an induction if the argument position decomposed in recursion is occupied by a variable. In this conjecture, three terms suggest inductions:

     (app a b)

     (app b c)
     (app a (app b c))

The variable recursively decomposed is indicated in bold.

13.60 Symbolic Execution of Models

Symbolic Execution of Models Symbolic Execution of Models But ACL2 is more than a programming language. Initialize x to 5 and let y be any legal value. Because ACL2 is a mathematical language, we can simplify the expression

     (lookup 'z (mc (s 'mult 5 y) 29))

and get (+ y y y y y). This is symbolic execution because not all of the parameters are known. Flying Tour: see Section 13.53 [Proving Theorems about Models], page 663

13.61 The Admission of App

The Admission of App The Admission of App Here is what it looks like to submit the definition of app to ACL2:

ACL2 !>(defun app (x y) (cond ((endp x) y)

(t (cons (car x)

(app (cdr x) y)))))

     The admission of APP is trivial, using the relation E0-ORD-< (which
     is known to be well-founded on the domain recognized by E0-ORDINALP)
     and the measure (ACL2-COUNT X).  We observe that the type of APP is
     described by the theorem (OR (CONSP (APP X Y)) (EQUAL (APP X Y) Y)).
     We used primitive type reasoning.

     Summary
     Form:  ( DEFUN APP ...)
     Rules: ((:FAKE-RUNE-FOR-TYPE-SET NIL))
     Warnings:  None
     Time:  0.03 seconds (prove: 0.00, print: 0.00, other: 0.03)
      APP

The text between the lines above is one interaction with the ACL2 command loop.

Above you see the user’s input and how the system responds. This little example shows you what the syntax looks like and is a very typical successful interaction with the definitional principle.

Let’s look at it a little more closely.

Walking Tour: see Section 13.54 [Revisiting the Admission of App], page 663

13.62 The Associativity of App

The Associativity of App The Associativity of App

ACL2!>(let ((a ’(1 2))

(b ’(3 4)) (c ’(5 6))) (equal (app (app a b) c)

(app a (app b c))))

     T

Observe that, for the particular a, b, and c above, (app (app a b) c) returns the same thing as (app a (app b c)). Perhaps app is associative. Of course, to be associative means that the above property must hold for all values of a, b, and c, not just the ones tested above.

Wouldn’t it be cool if you could type

ACL2!>(equal (app (app a b) c)

(app a (app b c))))

and have ACL2 compute the value T? Well, you can’t! If you try it, you’ll get an error message! The message says we can’t evaluate that form because it contains free variables, i.e., variables not given values. See Section 13.57 [STATE is the Only Variable in Top-Level Forms], page 665 to see the message. We cannot evaluate a form on an infinite number of cases. But we can prove that a form is a theorem and hence know that it will always evaluate to true. Walking Tour: see Section 13.98 [The Theorem that App is Associative], page 684

13.63 The Base Case in the App Example

The Base Case in the App Example The Base Case in the App Example This formula is the Base Case. It consists of two parts, a test identifying the non-inductive case and the conjecture to prove.

     (IMPLIES (ENDP A)  ; Test

(:P A B C)) ; Conjecture

When we prove this we can assume

* A is empty and we have to prove the conjecture for A.

13.64 The End of the Flying Tour

The End of the Flying Tour The End of the Flying Tour This completes the Flying Tour. You may wish now to go back and revisit selected nodes of the Flying Tour so that you can explore some of the branches not on the Tour. You can do so via The Flight Plan (A Flying Tour of ACL2^). These branches mainly provide some background and motivational material, rather than details of ACL2.

If you would like to learn more about ACL2 itself, we recommend that you now take the walking Tour. You may do so by clicking on the Walking Tour icon below.

Thanks.

Matt Kaufmann and J Moore

Walking Tour: see Section 13.6 [A Walking Tour of ACL2], page 634

13.65 The End of the Proof of the Associativity of App

The End of the Proof of the Associativity of App The End of the Proof of the Associativity of App

     That completes (Popping out of an Inductive Proof^) the proof of *1.
     Q.E.D. (The Q.E.D. Message^)
     Summary
     Form:  ( DEFTHM ASSOCIATIVITY-OF-APP ...)
     Rules (The Rules used in the Associativity of App Proof^): ((:REWRITE CDR-CONS)
             (:REWRITE CAR-CONS)
             (:DEFINITION NOT)
             (:DEFINITION ENDP)
             (:FAKE-RUNE-FOR-TYPE-SET NIL)
             (:DEFINITION APP))
     Warnings:  None
     Time:  0.27 seconds (prove: 0.10 (The Time Taken to do the Associativity of App Proof^), print: 0.05, other: 0.12)
      ASSOCIATIVITY-OF-APP

Walking Tour: see Section 13.32 [Guiding the ACL2 Theorem Prover], page 652

13.66 The End of the Walking Tour

The End of the Walking Tour The End of the Walking Tour

This completes the Walking Tour.

We intend to document many other parts of the system this way, but we just haven’t gotten around to it.

If you feel like reading more, see Section 1.5 [TUTORIAL-EXAMPLES], page 31 in the documentation. There you will find several challenging but simple applications. At the conclusion of the examples is a simple challenge to try.

We hope you enjoy ACL2. We do.

Matt Kaufmann and J Strother Moore

13.67 The Event Summary

The Event Summary The Event Summary

At the conclusion of most events (see Section 13.19 [About the Prompt], page 642 for a brief discussion of events or see Chapter 6 [EVENTS], page 161 <>), ACL2 prints a summary. The summary for app is:

     Summary
     Form:  ( DEFUN APP ...)
     Rules: ((:FAKE-RUNE-FOR-TYPE-SET NIL))
     Warnings:  None
     Time:  0.03 seconds (prove: 0.00, print: 0.00, other: 0.03)
      APP

The “rules” listed are those used in function admission or proof summarized. What is actually listed are “runes” (see Section 16.10 [RUNE], page 784) <>) which are list-structured unique names for rules in the ACL2 data base or “world (WORLD^)” <>. Using theories (THEORIES^) <> you can “enable” and “disable” rules so as to make them available (or not) to the ACL2 theorem prover.

The “warnings” mentioned (none are listed for app) remind the reader whether the event provoked any warnings. The warnings themselves would have been printed earlier in the processing and this part of the summary just names the earlier warnings printed.

The “time” indicates how much processing time was used and is divided into three parts: the time devoted to proof, to printing, and to syntactic checks, pre-processing and data base updates. Despite the fact that ACL2 is an applicative language it is possible to measure time with ACL2 programs. The state (STATE^) <> contains a clock. The times are printed in decimal notation but are actually counted in integral units.

The final APP is the value of the defun command and was printed by the read-eval-print loop. The fact that it is indented one space is a subtle reminder that the command actually returned an “error triple”, consisting of a flag indicating (in this case) that no error occurred, a value (in this case the symbol APP), and the final state (STATE^) <>). See Section 8.53 [LD-POST-EVAL-PRINT], page 332 <> for some details. If you really want to follow that link, however, you might see Section 9.7 [LD], page 416 <> first.

You should now return to the Walking Tour (Revisiting the Admission of App^).

13.68 The Expansion of ENDP in the Induction Step (Step 0)

The Expansion of ENDP in the Induction Step (Step 0) The Expansion of ENDP in the Induction Step (Step 0)

     Subgoal *1/2
     (IMPLIES (AND (NOT ( (The Expansion of ENDP in the Induction Step (Step 1)^)ENDP A))
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (APP (APP A B) C)
                     (APP A (APP B C)))).

Click on the link above (the open parenthesis before ENDP) to replace (ENDP A) by its definition.

13.69 The Expansion of ENDP in the Induction Step (Step 1)

The Expansion of ENDP in the Induction Step (Step 1) The Expansion of ENDP in the Induction Step (Step 1)

     Subgoal *1/2
     (IMPLIES (AND ( (The Expansion of ENDP in the Induction Step (Step 2)^)NOT (NOT (CONSP A)))
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (APP (APP A B) C)
                     (APP A (APP B C)))).

The bold text is the instantiated definition of ENDP.

Now click on the link above to simplify (NOT (NOT (CONSP A)))

13.70 The Expansion of ENDP in the Induction Step (Step 2)

The Expansion of ENDP in the Induction Step (Step 2) The Expansion of ENDP in the Induction Step (Step 2)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (APP (APP A B) C)
                     (APP A (APP B C)))).

Note that this is Subgoal *1/2'.

You may see Section 13.50 [Overview of the Simplification of the Induction Step to T], page 662 to return to the main proof.

13.71 The Falling Body Model

The Falling Body Model The Falling Body Model

One particularly famous and very simple model is the equation of a falling body: the distance d an object falls is proportional to the square of the time t. If the time is measured in seconds and the distance in feet, the equation relating these two is

            2
     d = 16t

This equation is a model of falling objects. It can be used to predict how long it takes a cannonball to fall from the top of a 200 foot tower (3.5 seconds). This might be important if your product is designed to drop cannonballs on moving targets.

See Section 13.26 [Corroborating Models], page 648 to continue

13.72 The Final Simplification in the Base Case (Step 0)

The Final Simplification in the Base Case (Step 0) the Final Simplification in the Base Case (Step 0)

     Subgoal *1/1'
     (IMPLIES (NOT (CONSP A))
              (EQUAL (APP ( (The Final Simplification in the Base Case (Step 1)^)APP A B) C)
                     (APP A (APP B C)))).

Click on the link above to replace (APP A B) by its definition. Note that the hypothesis (NOT (CONSP A)) allows us to simplify the IF in APP to its false branch this time.

13.73 The Final Simplification in the Base Case (Step 1)

The Final Simplification in the Base Case (Step 1) the Final Simplification in the Base Case (Step 1)

     Subgoal *1/1'
     (IMPLIES (NOT (CONSP A))
              (EQUAL (APP B C)
                     ( (The Final Simplification in the Base Case (Step 2)^)APP A (APP B C)))).

Click on the link above to expand the definition of APP. Again, we come out through the false branch because of the hypothesis.

13.74 The Final Simplification in the Base Case (Step 2)

The Final Simplification in the Base Case (Step 2) the Final Simplification in the Base Case (Step 2)

     Subgoal *1/1'
     (IMPLIES (NOT (CONSP A))
              ( (The Final Simplification in the Base Case (Step 3)^)EQUAL (APP B C)

(APP B C))).

Click on the link above to use the Axiom (EQUAL x x) = t

13.75 The Final Simplification in the Base Case (Step 3)

The Final Simplification in the Base Case (Step 3) the Final Simplification in the Base Case (Step 3)

     Subgoal *1/1'
     (IMPLIES (NOT (CONSP A))
              T)

Now that its conclusion is identically T the IMPLIES will simplify to T (not shown) and we are done

with Subgoal *1/1'.

You may see Section 13.48 [Overview of the Simplification of the Base Case to T], page 661 to return to the main proof.

13.76 The First Application of the Associativity Rule

The First Application of the Associativity Rule The First Application of the Associativity Rule

So here we see our associativity rule being used!

The rewriter sweeps the conjecture in a leftmost innermost fashion, applying rewrite rules as it goes.

The associativity rule is used many times in this sweep. The first “target” is highlighted below. Click on it to see what happens:

Current Conjecture:

     (equal (app (app (app (app x1 x2) (app x3 x4)) (A Sketch of How the Rewriter Works^) (app x5 x6)) x7)
            (app x1 (app (app x2 x3) (app (app x4 x5) (app x6 x7)))))

13.77 The Induction Scheme Selected for the App Example

The Induction Scheme Selected for the App Example The Induction Scheme Selected for the App Example

     (AND
        (IMPLIES (AND (NOT (ENDP A))         ; Induction Step: test
                      (:P (CDR A) B C))      ;  and induction hypothesis
                 (:P A B C))                 ;  implies induction conclusion.
        (IMPLIES (ENDP A) (:P A B C)))       ; Base Case

The formula beginning with this parenthesis is the induction scheme suggested by (APP A B) applied to (P A B C). It is a conjunction (AND (AND^) <>) of two formulas. The first is the induction step and the second is the base case.

13.78 The Induction Step in the App Example

The Induction Step in the App Example The Induction Step in the App Example This formula is the Induction Step. It basically consists of three parts, a test identifying the inductive case, an induction hypothesis and an induction conclusion.

     (IMPLIES (AND (NOT (ENDP A))  ; Test

(:P (CDR A) B C)) ; Induction Hypothesis (:P A B C)) ; Induction Conclusion

When we prove this we can assume

* A is not empty, and that

* the associativity conjecture holds for a “smaller” version of A, namely, (CDR A).

Under those hypotheses we have to prove the associativity conjecture for A itself.

13.79 The Instantiation of the Induction Scheme

The Instantiation of the Induction Scheme The Instantiation of the Induction Scheme The induction scheme just shown is just an abbreviation for our real goal. To obtain our actual goals we have to replace the schema :P by the associativity conjecture (instantiated as shown in the scheme). This produces two actual goals, the induction step and the base case.

13.80 The Justification of the Induction Scheme

The Justification of the Induction Scheme The Justification of the Induction Scheme

This paragraph explains why the induction selected is legal. The explanation is basically the same as the explanation for why the recursion in (APP A B) terminates.

13.81 The Proof of the Associativity of App

The Proof of the Associativity of App The Proof of the Associativity of App

Here is the theorem prover’s output when it processes the defthm command for the associativity of app. We have highlighted text for which we offer some explanation, and broken the presentation into several pages. Just follow the Walking Tour after exploring the explanations.

ACL2!>(defthm associativity-of-app

(equal (app (app a b) c) (app a (app b c))))

Name the formula above *1 (Name the Formula Above^).
Perhaps (Perhaps^) we can prove *1 by induction.  Three induction schemes are
suggested (Suggested Inductions in the Associativity of App Example^) by this conjecture.  Subsumption (Subsumption of Induction Candidates in App Example^) reduces that number to two.
However, one of these is flawed (Flawed Induction Candidates in App Example^) and so we are left with one viable
candidate.
We will induct according to a scheme suggested by (APP A B).  If we
let  (:P A B C) denote *1 above then the induction scheme we'll use
is
( (The Induction Scheme Selected for the App Example^)AND
   ( (The Induction Step in the App Example^)IMPLIES (AND (NOT (ENDP A))
                 (:P (CDR A) B C))
            (:P A B C))
   ( (The Base Case in the App Example^)IMPLIES (ENDP A) (:P A B C))).
This induction is justified (The Justification of the Induction Scheme^) by the same argument used to admit APP,
namely, the measure (ACL2-COUNT A) is decreasing according to the relation
E0-ORD-< (which is known to be well-founded on the domain recognized
by E0-ORDINALP).  When applied (The Instantiation of the Induction Scheme^) to the goal at hand the above induction
scheme produces the following two nontautological subgoals.

Walking Tour: see Section 13.50 [Overview of the Simplification of the Induction Step to T], page 662

13.82 The Q.E.D. Message

The Q.E.D. Message The Q.E.D. Message

Q.E.D. stands for “quod erat demonstrandum” which is Latin for “which was to be demonstrated” and is the signal that a proof is completely done.

13.83 The Rules used in the Associativity of App Proof

The Rules used in the Associativity of App Proof The Rules used in the Associativity of App Proof

Note that under Rules we list the runes (RUNE^) <> of all the rules used in the proof. This list says that we used the rewrite rules CAR-CONS and CDR-CONS, the definitions of the functions NOT, ENDP and APP, and primitive type reasoning (which is how we simplified the IF and EQUAL terms).

For what it is worth, IMPLIES and AND are actually macros (DEFMACRO^) <> that are expanded into IF expressions before the proof ever begins. The use of macros is not reported among the rules.

13.84 The Simplification of the Induction Conclusion (Step 0)

The Simplification of the Induction Conclusion (Step 0) the Simplification of the Induction Conclusion (Step 0)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (APP ( (The Simplification of the Induction Conclusion (Step 1)^)APP A B) C)
                     (APP A (APP B C)))).

Click on the link above to replace (APP A B) by its definition.

13.85 The Simplification of the Induction Conclusion (Step 1)

The Simplification of the Induction Conclusion (Step 1) the Simplification of the Induction Conclusion (Step 1)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (APP (IF ( (The Simplification of the Induction Conclusion (Step 2)^)CONSP A)

(CONS (CAR A) (APPEND (CDR A) B)) B)

                          C)
                     (APP A (APP B C)))).

Note that the IF expression above is the simplified body of APP. But we know the test (CONSP A) is true, by the first hypothesis. Click on the link above to replace the test by T. Actually this step and several subsequent ones are done during the simplification of the body of APP but we want to illustrate the basic principles of simplification without bothering with every detail.

13.86 The Simplification of the Induction Conclusion (Step 10)

The Simplification of the Induction Conclusion (Step 10) the Simplification of the Induction Conclusion (Step 10)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              ( (The Simplification of the Induction Conclusion (Step 11)^)EQUAL (APP (AP-

PEND (CDR A) B) C)

(APP (CDR A) (APP B C)))).

Click on the link above to use the Induction Hypothesis (which is the second of the two hypotheses above and which is identical to the rewritten conclusion).

13.87 The Simplification of the Induction Conclusion (Step 11)

The Simplification of the Induction Conclusion (Step 11) the Simplification of the Induction Conclusion (Step 11)

     Subgoal *1/2'
     ( (The Simplification of the Induction Conclusion (Step 12)^)IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              T)

Click on the link above to use the definition of IMPLIES. Since the conclusion of the implication is now identically T, the implication simplifies to T.

13.88 The Simplification of the Induction Conclusion (Step 12)

The Simplification of the Induction Conclusion (Step 12) the Simplification of the Induction Conclusion (Step 12)

     Subgoal *1/2'

T

So, indeed, Subgoal *1/2' does simplify to T!

You can see that even in an example as simple as this one, quite a lot happens in simplification.

You may see Section 13.50 [Overview of the Simplification of the Induction Step to T], page 662 to return to the main proof.

13.89 The Simplification of the Induction Conclusion (Step 2)

The Simplification of the Induction Conclusion (Step 2) the Simplification of the Induction Conclusion (Step 2)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (APP ( (The Simplification of the Induction Conclusion (Step 3)^)IF T
                              (CONS (CAR A) (APPEND (CDR A) B))
                              B)
                          C)
                     (APP A (APP B C)))).

Click on the link above to apply the Axiom (IF T x y) = x.

13.90 The Simplification of the Induction Conclusion (Step 3)

The Simplification of the Induction Conclusion (Step 3) the Simplification of the Induction Conclusion (Step 3)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL ( (The Simplification of the Induction Conclusion (Step 4)^)APP (CONS (CAR A) (AP-

PEND (CDR A) B))

                          C)
                     (APP A (APP B C)))).

Click on the link above to apply the expand the definition of APP here.

13.91 The Simplification of the Induction Conclusion (Step 4)

The Simplification of the Induction Conclusion (Step 4) the Simplification of the Induction Conclusion (Step 4)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (IF ( (The Simplification of the Induction Conclusion (Step 5)^)CONSP (CONS (CAR A) (AP-

PEND (CDR A) B)))

(CONS (CAR (CONS (CAR A) (APPEND (CDR A) B)))

(APP (CDR (CONS (CAR A) (APPEND (CDR A) B)))

C))

C)

                     (APP A (APP B C)))).

Click on the link above to apply the Axiom (CONSP (CONS x y)) = T.

13.92 The Simplification of the Induction Conclusion (Step 5)

The Simplification of the Induction Conclusion (Step 5) the Simplification of the Induction Conclusion (Step 5)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (IF T
                         (CONS ( (The Simplification of the Induction Conclusion (Step 6)^)CAR (CONS (CAR A) (APPEND (CDR A) B)))
                               (APP (CDR (CONS (CAR A) (APPEND (CDR A) B)))
                                    C))
                         C)
                     (APP A (APP B C)))).

Click on the link above to apply the Axiom (CAR (CONS x y)) = x.

13.93 The Simplification of the Induction Conclusion (Step 6)

The Simplification of the Induction Conclusion (Step 6) the Simplification of the Induction Conclusion (Step 6)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL (IF T

(CONS (CAR A)

                               (APP ( (The Simplification of the Induction Conclusion (Step 7)^)CDR (CONS (CAR A) (APPEND (CDR A) B)))
                                    C))
                         C)
                     (APP A (APP B C)))).

Click on the link above to apply the Axiom (CDR (CONS x y)) = y.

13.94 The Simplification of the Induction Conclusion (Step 7)

The Simplification of the Induction Conclusion (Step 7) the Simplification of the Induction Conclusion (Step 7)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)

                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              (EQUAL ( (The Simplification of the Induction Conclusion (Step 8)^)IF T
                         (CONS (CAR A)

(APP (APPEND (CDR A) B)

                                    C))
                         C)
                     (APP A (APP B C)))).

Click on the link above to apply the Axiom (IF T x y) = x.

13.95 The Simplification of the Induction Conclusion (Step 8)

The Simplification of the Induction Conclusion (Step 8) the Simplification of the Induction Conclusion (Step 8)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))

(EQUAL (CONS (CAR A)

(APP (APPEND (CDR A) B)

C))

                     ( (The Simplification of the Induction Conclusion (Step 9)^)APP A (APP B C)))).

Click on the link above to expand the definition of APP here. This time, we’ll do the whole expansion at once, including the simplification of the resulting IF. This is how ACL2 actually does it.

13.96 The Simplification of the Induction Conclusion (Step 9)

The Simplification of the Induction Conclusion (Step 9) the Simplification of the Induction Conclusion (Step 9)

     Subgoal *1/2'
     (IMPLIES (AND (CONSP A)
                   (EQUAL (APP (APP (CDR A) B) C)
                          (APP (CDR A) (APP B C))))
              ( (The Simplification of the Induction Conclusion (Step 10)^)EQUAL (CONS (CAR A)
                           (APP (APPEND (CDR A) B)
                                C))

(CONS (CAR A)

(APP (CDR A) (APP B C))))).

Click on the link above to apply the Axiom that (EQUAL (CONS x y) (CONS u v)) is equal to the conjunction of (EQUAL x u) and (EQUAL y v). In this case, (EQUAL x u) is trivial, (EQUAL (CAR

A) (CAR A)).

13.97 The Summary of the Proof of the Trivial Consequence

The Summary of the Proof of the Trivial Consequence The Summary of the Proof of the Trivial Consequence

Note that at the conclusion of the proof, the system reminds you of the earlier Warning.

It is a good idea, when the Q.E.D. flys by, to see if there were any Warnings.

13.98 The Theorem that App is Associative

The Theorem that App is Associative The Theorem that App is Associative

ACL2!>(defthm associativity-of-app

(equal (app (app a b) c) (app a (app b c))))

The formula above says app is associative. The defthm (DEFTHM^) <> command instructs ACL2 to prove the formula and to name it associativity-of-app. Actually, the defthm command also builds the formula into the data base as a rewrite (REWRITE^) <> rule, but we won’t go into that just yet.

What we will consider is how the ACL2 theorem prover proves this formula.

If you proceed you will find the actual output of ACL2 in response to the command above. Some of the text is highlighted for the purposes of the tour. ACL2 does not highlight its output.

You will note that we sometimes highlight a single open parenthesis. This is our way of drawing your attention to the subformula that begins with that parenthesis. By clicking on the parenthesis you will get an explanation of the subformula or its processing.

Walking Tour: see Section 13.81 [The Proof of the Associativity of App], page 677

13.99 The Time Taken to do the Associativity of App Proof

The Time Taken to do the Associativity of App Proof The Time Taken to do the Associativity of App Proof The time it took us to explain this proof may leave the impression that the proof is complicated. In a way, it is. But it happens quickly. The time taken to do this proof is about 1/10 second. The rest of the time (about 2/10 seconds) is spent in pre- and post-processing. Basically, this proof flashes across your screen before you can read it; you see the Q.E.D. and don’t bother to scroll back to read it. You have more important things to do than read successful proofs.

13.100 The Tours

The Tours The Tours ACL2 is a very large, multipurpose system. You can use it as a programming language, a specification language, a modeling language, a formal mathematical logic, or a semi-automatic theorem prover, just to name its most common uses. This home page includes all of ACL2’s online documentation, which is quite extensive. To help ease your introduction to ACL2, we have built two tours through this documentation. Newcomers to ACL2 should first take the “Flying Tour.” Then, if you want to know more, take the “Walking Tour.” To start a tour, click on the appropriate icon below. Flying Tour: see Section 13.1 [A Flying Tour of ACL2], page 632 Walking Tour: see Section 13.6 [A Walking Tour of ACL2], page 634 For readers using Web browsers: This “page” actually contains many other pages of our documentation, organized alphabetically and separated by many blank lines. Be careful when using the scroll bar!

For readers using our :DOC or our TexInfo format in Emacs: The tours will probably be unsatisfying because we use gif files and assume you can navigate “back.”

13.101 The WARNING about the Trivial Consequence

The WARNING about the Trivial Consequence The WARNING about the Trivial Consequence

This Warning alerts us to the fact that when treated as a rewrite rule, the new rule TRIVIAL-CONSEQUENCE, rewrites terms of the same form as a rule we have already proved, namely

ASSOCIATIVITY-OF-APP.

When you see this warning you should think about your rules!

In the current case, it would be a good idea not to make TRIVIAL-CONSEQUENCE a rule at all. We could do this with :rule-classes (RULE-CLASSES^) <> nil.

ACL2 proceeds to try to prove the theorem, even though it printed some warnings. The basic assumption in ACL2 is that the user understands what he or she is doing but may need a little reminding just to manage a complicated set of facts.

13.102 Undocumented Topic

Undocumented Topic Undocumented Topic

This topic has not yet been documented. Sorry

13.103 Using the Associativity of App to Prove a Trivial Consequence

Using the Associativity of App to Prove a Trivial Consequence Using the Associativity of App to Prove a Trivial Consequence If we have proved the associativity-of-app rule, then the following theorem is trivial:

     (defthm trivial-consequence
       (equal (app (app (app (app x1 x2) (app x3 x4)) (app x5 x6)) x7)
              (app x1 (app (app x2 x3) (app (app x4 x5) (app x6 x7))))))

Below we show the proof Walking Tour: see Section 13.47 [Overview of the Proof of a Trivial Consequence], page 660

13.104 What Is ACL2(Q)

What Is ACL2(Q) What Is ACL2? ACL2 is a mathematical logic together with a mechanical theorem prover to help you reason in the logic. The logic is just a subset of applicative Common Lisp (Common Lisp^). The theorem prover is an “industrial strength” version of the Boyer-Moore theorem prover, Nqthm. Models of all kinds of computing systems can be built in ACL2, just as in Nqthm, even though the formal logic is Lisp. Once you’ve built an ACL2 model of a system, you can run it. You can also use ACL2 to prove theorems about the model. Flying Tour: see Section 13.106 [What is a Mathematical Logic(Q)], page 688

13.105 What is Required of the User(Q)

What is Required of the User(Q) What is Required of the User? It is not easy to build ACL2 models of complex systems. To do so, the user must understand * the system being modeled, and

* ACL2, at least as a programming language. It is not easy to get ACL2 to prove hard theorems. To do so, the user must understand

* the model,

* ACL2 as a mathematical logic, and

* be able to construct a proof (in interaction with ACL2). ACL2 will help construct the proof but its primary role is to prevent logical mistakes. The creative burden – the mathematical insight into why the model has the desired property – is the user’s responsibility. Flying Tour: see Section 13.34 [How Long Does It Take to Become an Effective User(Q)], page 653

13.106 What is a Mathematical Logic(Q)

What is a Mathematical Logic(Q) What is a Mathematical Logic? A mathematical logic is a formal system of formulas (axioms) and rules for deriving other formulas, called theorems. A proof is a derivation of a theorem. To see a concrete proof tree, see Section 13.4 [A Trivial Proof], page 634. Why should you care? The neat thing about Theorems is that they are “true.” More precisely, if all the axioms are valid and the rules are validity preserving, then anything derived from the axioms via the rules is valid. So, if you want to determine if some formula is true, prove it. Flying Tour: see Section 13.107 [What is a Mechanical Theorem Prover(Q)], page 688

13.107 What is a Mechanical Theorem Prover(Q)

What is a Mechanical Theorem Prover(Q) What is a Mechanical Theorem Prover? A mechanical theorem prover is a computer program that finds proofs of theorems. The ideal mechanical theorem prover is automatic: you give it a formula and it gives you a proof of that formula or tells you there is no proof. Unfortunately, automatic theorem provers can be built only for very simple logics (e.g., propositional calculus) and even then practical considerations (e.g., how many centuries you are willing to wait) limit the problems they can solve. Flying Tour: see Section 13.108 [What is a Mechanical Theorem Prover(Q) (continued)], page 689

13.108 What is a Mechanical Theorem Prover(Q) (continued)

What is a Mechanical Theorem Prover(Q) (continued) What is a Mechanical Theorem Prover? (continued) To get around this, mechanical theorem provers often require help from the user. See Section 13.12 [ACL2 as an Interactive Theorem Prover], page 638 to continue downward. Flying Tour: see Section 13.15 [About Models], page 639

13.109 You Must Think about the Use of a Formula as a Rule

You Must Think about the Use of a Formula as a Rule You Must Think about the Use of a Formula as a Rule This is good and bad. The good news is that you can program ACL2’s simplifier. The bad news is that when you command ACL2 to prove a theorem you must give some thought to how that theorem is to be used as a rule!

For example, if you engaged in the mathematically trivial act of proving the associativity rule again, but with the equality reversed, you would have programmed ACL2’s rewriter to loop forever.

You can avoid adding any rule by using the command:

     (defthm associativity-of-app
       (equal (app (app a b) c)
              (app a (app b c)))

:rule-classes nil)

Walking Tour: see Section 13.103 [Using the Associativity of App to Prove a Trivial Consequence], page 686

14 RELEASE-NOTES

RELEASE-NOTES pointers to what has changed

* NOTE1:: Acl2 Version 1.1 Notes

* NOTE2:: Acl2 Version 1.2 Notes

* NOTE3:: Acl2 Version 1.3 Notes

* NOTE4:: Acl2 Version 1.4 Notes

* NOTE5:: Acl2 Version 1.5 Notes

* NOTE6:: Acl2 Version 1.6 Notes

* NOTE7:: ACL2 Version 1.7 (released October 1994) Notes

* NOTE8:: ACL2 Version 1.8 (May, 1995) Notes

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

* NOTE9:: ACL2 Version 1.9 (Fall, 1996) Notes

This section of the online documentation (DOCUMENTATION^) contains notes on the changes that distinguish successive released versions of ACL2.

The current version of ACL2 is the value of the constant *acl2-version*.

14.1 NOTE1

NOTE1 Acl2 Version 1.1 Notes

The new features are extensively documented. The relevant topics are:

Related topics other than immediate subtopics:

* BOOKS:: files of ACL2 event forms

* GUARD:: restricting the domain of a function

* MORE:: your response to :doc (DOC^) or :more-doc (MORE-DOC^)’s “(cont'd)”

* REDUNDANT-EVENTS:: allowing a name to be introduced “twice”

It is especially important to read all of of the documentation (DOCUMENTATION^) for books (BOOKS^) before trying to use books. However, the new :more (MORE^) keyword command is so handy for reading long documentation (DOCUMENTATION^) strings that we recommend you start with :doc (DOC^) more if reading at the terminal. Some documentation has been written for guard (GUARD^)s which you might find interesting.

14.2 NOTE2

NOTE2 Acl2 Version 1.2 Notes

Hacker mode has been eliminated and programming (PROGRAMMING^) mode has been added. Programming (PROGRAMMING^) mode is unsound but does syntax checking and permits redefinitions of names. See :doc (DOC^) load-mode and :doc (DOC^) g-mode.

The arguments to ld (LD^) have changed. Ld (LD^) is now much more sophisticated. See Section 9.7 [LD], page 416.

For those occasions on which you wish to look at a large list structure that you are afraid to print, try (walkabout x state), where x is an Acl2 expression that evaluates to the structure in question. I am afraid there is no documentation (DOCUMENTATION^) yet, but it is similar in spirit to the Interlisp structure editor. You are standing on an object and commands move you around in it. E.g., 1 moves you to its first element, 2 to its second, etc.; 0 moves you up to its parent; nx and bk move you to its next sibling and previous sibling; pp prettyprints it; q (Q^) exits returning nil; = (=^) exits returning the thing you’re standing on; (= symb) assigns the thing you’re standing on to the state (STATE^) global variable symb.

Several new hints (HINTS^) have been implemented, including :by and :do-not. The old :donot-generalize has been scrapped in favor of such new hints (HINTS^) as :do-not(generalize elim). :By lets you say “this goal is subsumed by” a given lemma instance. The :by hint also lets you say “this goal can’t be proved yet but skip it and see how the rest of the proof goes.” See Section 8.43 [HINTS], page 319.

14.3 NOTE3

NOTE3 Acl2 Version 1.3 Notes

Programming (PROGRAMMING^) mode has been eliminated. Instead, all functions have a “color” which indicates what can be done with the function. For example, :red functions can be executed but have no axioms describing them. Thus, :red functions can be introduced after passing a simple syntactic check and they can be redefined without undoing. But nothing of consequence can be proved about them. At the other extreme are :gold functions which can be executed and which also have passed both the termination and the guard (GUARD^) verification proofs. The color of a function can be specified with the new xargs (XARGS^) keyword, :color, which, if omitted defaults to the global setting of ld-color. Ld-color replaces load-mode. Setting ld-color to :red causes behavior similar to the old :g-mode. Setting ld-color to :gold causes behavior similar to the old :v-mode. It is possible to prototype your system in :red and then convert :red functions to :blue individually by calling verify-termination (VERIFY-TERMINATION^) on them. They can then be converted to :gold with verify-guards (VERIFY-GUARDS^). This allows us to undertake to verify the termination and guard (GUARD^)s of system functions. See :doc (DOC^) color for an introduction to the use of colors.

Type prescription rules have been added. Recall that in Nqthm, some rewrite (REWRITE^) rules were actually stored as “type-prescription (TYPE-PRESCRIPTION^)s.” Such rules allow the user to inform Nqthm’s primitive type mechanism as to the kinds of shells returned by a function. Earlier versions of Acl2 did not have an analogous kind of rule because Acl2’s type mechanism is complicated by guard (GUARD^)s. Version 1.3 supports type-prescription (TYPE-PRESCRIPTION^) rules. See Section 15.15 [TYPE-PRESCRIPTION], page 766.

Three more new rule-classes (RULE-CLASSES^) implement congruence-based rewriting. It is possible to identify a binary relation as an equivalence relation (see Section 15.6 [EQUIVALENCE], page 738), to show that one equivalence relation refines another (see Section 15.13 [REFINEMENT], page 763) and to show that a given equivalence relation is maintained when rewriting a given function call, e.g., (fn ...xk...), by maintaining another equivalence relation while rewriting the kth argument (see Section 15.3 [CONGRUENCE], page 733). If r has been shown to be an equivalence (EQUIVALENCE^) relation and then (implies hyps (r (foo x) (bar x))) is proved as a :rewrite (REWRITE^) rule, then instances of (foo x) will be replaced by corresponding instances of (bar x) provided the instance occurs in a slot where the maintainence of r-equivalence is known to be sufficient and hyps can be established as usual.

In Version 1.2, rule-classes (RULE-CLASSES^) were simple keywords, e.g., :rewrite (REWRITE^) or :elim (ELIM^). In Version 1.3, rule-classes (RULE-CLASSES^) have been elaborated to allow you to specify how the theorem ought to be used as a rule. That is, the new rule-classes (RULE-CLASSES^) allows you to separate the mathematical statement of the formula from its interpretation as a rule. See Chapter 15 [RULE-CLASSES], page 723.

Rules used to be named by symbols, e.g., car (CAR^) and car-cons were the names of rules. Unfortunately, this was ambiguous because there are three rules associated with function symbols: the symbolic definition, the executable counterpart, and the type-prescription (TYPE-PRESCRIPTION^); many different rules might be associated with theorems, depending on the rule classes. In Version 1.3 rules are named by “rune (RUNE^)s” (which is just short hand for

“rule names”). Example rune (RUNE^)s are (:definition car), (:executable-counterpart

car), and (:type-prescription car . 1). Every rule added by an event has a different name and you can enable (ENABLE^) and disable (DISABLE^) them independently. See Section 16.10 [RUNE], page 784 and see Chapter 16 [THEORIES], page 775.

The identity function force (FORCE^), of one argument, has been added and given a special interpretation by the functions responsible for establishing hypotheses in backchaining: When the system fails to establish some hypothesis of the form (force term), it simply assumes it is true and goes on, delaying until later the establishment of term. In particular, pushes a new subgoal to prove term in the current context. When that subgoal is attacked, all of the resources of the theorem prover, not just rewriting, are brought to bear. Thus, for example, if you wish to prove the rule

(implies (good-statep s) (equal (exec s n) s')) and it is your expectation that every time

exec appears its first argument is a good-statep then you might write the rule as (implies (force (good-statep s)) (equal (exec s n) s')). This rule is essentially an unconditional rewrite of (exec s n) to s' that spawns the new goal (good-statep s). See Section 8.37 [FORCE], page 297. Because you can now specify independently how a theorem is used as a rule, you need not write the force (FORCE^) in the actual theorem proved. See Chapter 15 [RULE-CLASSES], page 723.

Version 1.3 supports a facility similar to Nqthm’s break-lemma (BREAK-LEMMA^). See Chapter 4 [BREAK-REWRITE], page 119. You can install “monitor (MONITOR^)s” on rune (RUNE^)s that will cause interactive breaks under certain conditions.

Acl2 also provides “wormhole (WORMHOLE^)s” which allow you to write functions that cause interaction with the user but which do not require that you have access to state (STATE^). See Section 8.101 [WORMHOLE], page 401.

The rewriter now automatically backchains to stronger recognizers. There is no user hook to this feature but it may simplify some proofs with which older versions of Acl2 had trouble. For example, if the rewriter is trying to prove (rationalp (foo a b c)) it is now smart enough to try lemmas

that match with (integerp (foo a b c)).

14.4 NOTE4

NOTE4 Acl2 Version 1.4 Notes

Once again ld (LD^) only takes one required argument, as the bind-flg has been deleted.

Three commands have been added in the spirit of :pe (PE^). :Pe! (PE!^) is similar to :pe (PE^) but it prints all events (EVENTS^) with the given name, rather than just the most recent. The command :pf (PF^) prints the corollary formula corresponding to a name or rune (RUNE^). The command :pl (PL^) (print lemmas) prints rules whose top function symbol is the given name. See Section 7.8 [PE!], page 222, see Section 7.9 [PF], page 223, and see Section 7.10 [PL], page 223.

Book naming conventions have been changed somewhat. The once-required .lisp extension is now prohibited! Directories are supported, including a notion of “connected book directory”. See Section 3.3 [BOOK-NAME], page 99. Also, the second argument of certify-book (CERTIFY-BOOK^) is now optional, defaulting to 0.

Compilation (COMPILATION^) is now supported inside the Acl2 loop. See Section 9.5 [COMP], page 415 and see Section 6.27 [SET-COMPILE-FNS], page 197.

The default color is now part of the Acl2 world (WORLD^); see :doc (DOC^) default-color. Ld-color is no longer an ld (LD^) special. Instead, colors are events (EVENTS^); see the documentation for red, pink, blue, and gold.

A table (TABLE^) exists for controlling whether Acl2 prints comments when it force (FORCE^)s hypotheses of rules; see :doc (DOC^) force-table. Also, it is now possible to turn off the forcing of assumptions by disabling the definition of force (FORCE^); see Section 8.37 [FORCE], page 297.

The event defconstant is no longer supported, but a very similar event, defconst (DEFCONST^), has been provided in its place. See Section 6.5 [DEFCONST], page 166.

The event for defining congruence (CONGRUENCE^) relations is now defcong (DEFCONG^) (formerly, defcon).

Patterns are now allowed in :expand hints (HINTS^). See the documentation for :expand inside the documentation for hints (HINTS^).

We have improved the way we report rules used by the simplifier. All rune (RUNE^)s of the same type are reported together in the running commentary associated with each goal, so that for example, executable counterparts are listed separately from definitions, and rewrite rules are listed separately from linear (LINEAR^) rules. The preprocessor now mentions “simple” rules; see Section 8.81 [SIMPLE], page 364.

The mechanism for printing warning messages for new rewrite rules, related to subsumption, now avoids worrying about nonrecursive function symbols when those symbols are disable (DIS-ABLE^)d. These messages have also been eliminated for the case where the old rule is a :definition (DEFINITION^) rule.

Backquote has been modified so that it can usually provide predictable results when used on the left side of a rewrite rule.

Time statistics are now printed even when an event fails.

The Acl2 trace package has been modified so that it prints using the values of the Lisp globals

*print-level* and *print-length* (respectively).

Table (TABLE^) has been modified so that the :clear option lets you replace the entire table (TABLE^) with one that satisfies the val and key guards (if any); see Section 6.36 [TABLE], page 204.

We have relaxed the translation rules for :measure hints (HINTS^) to defun (DEFUN^), so that the the same rules apply to these terms that apply to terms in defthm (DEFTHM^) events (EVENTS^). In particular, in :measure hints (HINTS^) mv (MV^) is treated just like list (LIST^), and state (STATE^) receives no special handling.

The loop-stopper (LOOP-STOPPER^) test has been relaxed. The old test required that every new argument be strictly less than the corresponding old argument in a certain term-order (TERM-ORDER^). The new test uses a lexicographic order on term lists instead. For example, consider the following rewrite rule.

       (equal
        (variable-update var1
                         val1 (variable-update var2 val2 vs))
        (variable-update var2
                         val2 (variable-update var1 val1 vs)))

This rule is permutative. Now imagine that we want to apply this rule to the term

       (variable-update u y (variable-update u x vs)).

Since the actual corresponding to both var1 and var2 is u, which is not strictly less than itself in the term-order (TERM-ORDER^), this rule would fail to be applied in this situation when using the old test. However, since the pair (u x) is lexicographically less than the pair (u y) with respect to our term-order (TERM-ORDER^), the rule is in fact applied using our new test.

Messages about events (EVENTS^) now contain a space after certain left parentheses, in order to assist emacs users. For example, the event

       (defthm abc (equal (+ (len x) 0) (len x)))

leads to a summary containing the line

       Form:  ( DEFTHM ABC ...)

and hence, if you search backwards for “(defthm abc”, you won’t stop at this message. More tautology checking is done during a proof; in fact, no goal printed to the screen, except for the results of applying :use and :by hints (HINTS^) or the top-level goals from an induction proof, are known to Acl2 to be tautologies. The ld-query-control-alist (LD-QUERY-CONTROL-ALIST^) may now be used to suppress printing of queries; see Section 8.57 [LD-QUERY-CONTROL-ALIST], page 335. Warning messages are printed with short summary strings, for example the string “Use” in the following message.

       Acl2 Warning [Use] in DEFTHM:  It is unusual to :USE an enabled
       :REWRITE or :DEFINITION rule, so you may want to consider
       disabling FOO.

At the end of the event, just before the time is printed, all such summary strings are printed out. The keyword command :u has been introduced as an abbreviation for :ubt (UBT^) :max (MAX^). Printing of query messages is suppressed by :u. The keyword :cheat is no longer supported by any event form. Some irrelevant formals are detected; see Section 10.136 [IRRELEVANT-FORMALS], page 495. A bug in the application of metafunctions was fixed: now if the output of a metafunction is equal to its input, the application of the metafunction is deemed unsuccessful and the next metafunction is tried. An example has been added to the documentation for equivalence (EQUIVALENCE^) to suggest how to make use of equivalence (EQUIVALENCE^) relations in rewriting. The following Common Lisp functions have been added to Acl2: alpha-char-p (ALPHA-CHAR-

P^), upper-case-p (UPPER-CASE-P^), lower-case-p (LOWER-CASE-P^), char-upcase

(CHAR-UPCASE^), char-downcase (CHAR-DOWNCASE^), string-downcase (STRING-DOWNCASE^),

string-upcase (STRING-UPCASE^), and digit-charp-p.

A documentation section called proof-checker (PROOF-CHECKER^) has been added for the interactive facility, whose documentation has been slightly improved. See in particular the documentation for proof-checker (PROOF-CHECKER^), verify (VERIFY^), and macro-command (MACRO-COMMAND^).

A number of events (EVENTS^) that had been inadvertently disallowed in books (BOOKS^) are now permitted in books (BOOKS^). These are: defcong (DEFCONG^), defcor, defequiv (DEFEQUIV^), defrefinement (DEFREFINEMENT^), defstub (DEFSTUB^), and verifytermination (VERIFY-TERMINATION^).

14.5 NOTE5

NOTE5 Acl2 Version 1.5 Notes

Acl2 now allows “complex rationals,” which are complex numbers whose real parts are rationals and whose imaginary parts are non-zero rationals. See Section 10.87 [COMPLEX], page 466.

A new way of handling force (FORCE^)d hypotheses has been implemented. Rather than cause a case split at the time the force (FORCE^) occurs, we complete the main proof and then embark on one or more “forcing rounds” in which we try to prove the force (FORCE^)d hypotheses. See Section 8.38 [FORCING-ROUND], page 299. To allow us to compare the new handling of force (FORCE^) with the old, Version 1.5 implements both and uses a flag in state (STATE^) to determine which method should be used. Do (assign old-style-forcing t) if you want force (FORCE^) to be handled as it was in Version 1.4. However, we expect to eliminate the old-style forcing eventually because we think the new style is more effective. To see the difference between the two approaches to forcing, try proving the associativity of append (APPEND^) under both settings of old-style-forcing. To get the new behavior invoke:

     (thm (implies (and (true-listp a) (true-listp b))
                   (equal (append (append a b) c)
                          (append a (append b c)))))

Then (assign old-style-forcing t) and invoke the thm command (COMMAND^) above again.

A new :cases hints (HINTS^) allows proof by cases. See Section 8.43 [HINTS], page 319.

Include-book (INCLUDE-BOOK^) and encapsulate (ENCAPSULATE^) now restore the acl2defaults-table (ACL2-DEFAULTS-TABLE^) when they complete. See Section 6.20 [INCLUDE-BOOK], page 189 and see Section 6.18 [ENCAPSULATE], page 185.

The guard (GUARD^)s on many Acl2 primitives defined in axioms.lisp have been weakened to permit them to be used in accordance with lisp custom and tradition.

It is possible to attach heuristic filters to :rewrite (REWRITE^) rules to limit their applicability. See Section 8.86 [SYNTAXP], page 374.

A tutorial has been added; see Chapter 1 [ACL2-TUTORIAL], page 3.

Events (EVENTS^) now print the Summary paragraph listing rune (RUNE^)s used, time, etc., whether they succeed or fail. The format of the “failure (FAILURE^) banner” has been changed but still has multiple asterisks in it. Thm also prints a Summary, whether it succeeds or fails; but thm is not an event.

A new event form skip-proofs (SKIP-PROOFS^) has been added; see Section 9.14 [SKIP-PROOFS], page 425.

A user-specific customization facility has been added in the form of a book that is automatically included, if it exists on the current directory. See Section 8.4 [ACL2-CUSTOMIZATION], page 239.

A facility for conditional metalemmas has been implemented; see Section 15.12 [META], page 758.

The acceptable values for ld-skip-proofsp (LD-SKIP-PROOFSP^) have changed. In the old version (Version 1.4), a value of t meant that proofs and local (LOCAL^) events (EVENTS^) are to be skipped. In Version 1.5, a value of t means proofs (but not local (LOCAL^) events (EVENTS^)) are to be skipped. A value of 'include-book (INCLUDE-BOOK^) means proofs and local (LOCAL^) events (EVENTS^) are to be skipped. There are two other, more obscure, acceptable values. See Section 8.59 [LD-SKIP-PROOFSP], page 339.

In order to turn off the forcing of assumptions, one should now disable (DISABLE^) the :executable-counterpart (EXECUTABLE-COUNTERPART^) of force (FORCE^) (rather than the :definition (DEFINITION^) of force (FORCE^), as in the previous release); see Section 8.37 [FORCE], page 297.

The macros enable-forcing (ENABLE-FORCING^) and disable-forcing (DISABLE-FORCING^) make it convenient to enable (ENABLE^) or disable (DISABLE^) forcing. See Section 8.28 [ENABLE-FORCING], page 289 and see Section 8.23 [DISABLE-FORCING], page 281.

The new commands :pr (PR^) and :pr! (PR!^) print the rules created by an event or command. See Section 7.11 [PR], page 224 and see Section 7.12 [PR!], page 224.

The new history (HISTORY^) command (COMMAND^)s :puff (PUFF^) and :puff* (PUFF*^) will replace a compound command (COMMAND^) such as an encapsulate (ENCAPSULATE^) or include-book (INCLUDE-BOOK^) by the sequence of events (EVENTS^) in it. That is, they “puff (PUFF^) up” or “lift” the subevents of a command (COMMAND^) to the command (COM-MAND^) level, eliminating the formerly superior command (COMMAND^) and lengthening the history (HISTORY^). This is useful if you want to “partially undo” an encapsulate (ENCAP-SULATE^) or book or other compound command (COMMAND^) so you can experiment. See Section 7.13 [PUFF], page 225 and see Section 7.14 [PUFF*], page 228.

Theory expressions now are allowed to use the free variable world (WORLD^) and prohibited from using the free variable state (STATE^). See Chapter 16 [THEORIES], page 775, although it is essentially the same as before except it mentions world (WORLD^) instead of state (STATE^). See Section 8.100 [WORLD], page 399 for a discussion of the Acl2 logical world (WORLD^). Allowing in-theory (IN-THEORY^) events (EVENTS^) to be state-sensitive violated an important invariant about how books (BOOKS^) behaved.

Table (TABLE^) keys and values now are allowed to use the free variable world (WORLD^) and prohibited from using the free variable state (STATE^). See the note above about theory expressions for some explanation.

The macro for minus, - (-^), used to expand (- x 3) to (+ x -3) and now expands it to (+ -3 x) instead. The old macro, if used in the left-hand sides of rewrite rules, produced inapplicable rules because the constant occurs in the second argument of the + (+^), but potential target terms generally had the constant in the first argument position because of the effect of commutativity-

of-+.

A new class of rule, :linear-alias (LINEAR-ALIAS^) rules, allows one to implement the nqthm package and similar hacks in which a disable (DISABLE^)d function is to be known equivalent to an arithmetic function. See Section 15.11 [LINEAR-ALIAS], page 753.

A new class of rule, :built-in-clause rules, allows one to extend the set of clauses proved silently by defun (DEFUN^) during measure and guard (GUARD^) processing. See Section 15.1 [BUILT-IN-CLAUSES], page 727.

The new command pcb! (PCB!^) is like pcb (PCB^) but sketches the command (COMMAND^) and then prints its subsidiary events (EVENTS^) in full. See Section 7.5 [PCB!], page 221.

:Rewrite (REWRITE^) class rules may now specify the :loop-stopper (LOOP-STOPPER^) field. See Chapter 15 [RULE-CLASSES], page 723 and see Section 8.64 [LOOP-STOPPER], page 347.

The rules for how loop-stopper (LOOP-STOPPER^)s control permutative rewrite rules have been changed. One effect of this change is that now when the built-in commutativity rules for + (+^) are used, the terms a and (- a) are permuted into adjacency. For example, (+ a b (- a)) is now normalized by the commutativity rules to (+ a (- a) b); in Version 1.4, b was considered syntactically smaller than (- a) and so (+ a b (- a)) is considered to be in normal form. Now it is possible to arrange for unary functions be be considered “invisible” when they are used in certain contexts. By default, unary-- (UNARY–^) is considered invisible when its application appears in the argument list of binary-+ (BINARY-+^). See Section 8.64 [LOOP-STOPPER], page 347 and see Section 6.30 [SET-INVISIBLE-FNS-ALIST], page 199.

Extensive documentation has been provided on the topic of Acl2’s “term ordering.” See Section 8.88 [TERM-ORDER], page 379.

Calls of ld (LD^) now default ld-error-action (LD-ERROR-ACTION^) to :return rather than to the current setting.

The command (COMMAND^) descriptor :x has been introduced and is synonymous with :max (MAX^), the most recently executed command (COMMAND^). History (HISTORY^) command (COMMAND^)s such as :pbt (PBT^) print a :x beside the most recent command (COMMAND^), simply to indicate that it is the most recent one.

The command (COMMAND^) descriptor :x-23 is synonymous with (:x -23). More generally, every symbol in the keyword package whose first character is #\x and whose remaining characters (CHARACTERS^) parse as a negative integer is appropriately understood. This allows :pbt (PBT^) :x-10 where :pbt (PBT^) (:max -10) or :pbt (PBT^) (:here -10) were previously used. The old forms are still legal.

The order of the arguments to defcong (DEFCONG^) has been changed.

The simplifier now reports the use of unspecified built-in type information about the primitives with the phrase “primitive type reasoning.” This phrase may sometimes occur in situations where “propositional calculus” was formerly credited with the proof.

The function pairlis (PAIRLIS^) has been replaced in the code by a new function pairlis$ (PAIRLIS$^), because Common Lisp does not adequately specify its pairlis (PAIRLIS^) function.

Some new Common Lisp functions have been added, including logtest (LOGTEST^), logcount (LOGCOUNT^), integer-length (INTEGER-LENGTH^), make-list (MAKE-LIST^), removeduplicates (REMOVE-DUPLICATES^), string (STRING^), and concatenate (CONCATE-NATE^). The source file /slocal/src/acl2/axioms.lisp is the ultimate reference regarding Common Lisp functions in Acl2.

The functions defuns (DEFUNS^) and theory-invariant (THEORY-INVARIANT^) have been documented. See Section 8.22 [DEFUNS], page 280 and see Section 6.38 [THEORY-INVARIANT], page 208.

A few symbols have been added to the list *acl2-exports*.

A new key has been implemented for the acl2-defaults-table (ACL2-DEFAULTS-TABLE^), :irrelevant-formals-ok. See Section 6.31 [SET-IRRELEVANT-FORMALS-OK], page 200.

The connected book directory, cbd (CBD^), must be nonempty and begin and end with a slash. It is set (and displayed) automatically upon your first entry to lp (LP^). You may change the setting with set-cbd (SET-CBD^). See Section 3.4 [CBD], page 102.

:oops (OOPS^) will undo the last :ubt (UBT^). See Section 7.1 [OOPS], page 215.

Documentation has been written about the ordinals. See Section 8.26 [E0-ORDINALP], page 283 and see Section 8.25 [E0-ORD-<], page 282.

The color events (EVENTS^) — (red), (pink), (blue), and (gold) — may no longer be enclosed inside calls of local (LOCAL^), for soundness reasons. In fact, neither may any event that sets the acl2defaults-table (ACL2-DEFAULTS-TABLE^). See Section 8.27 [EMBEDDED-EVENT-FORM], page 286.

See Section 8.52 [LD-KEYWORD-ALIASES], page 331 for an example of how to change the exit keyword from :q (Q^) to something else.

The attempt to install a monitor (MONITOR^) on :rewrite (REWRITE^) rules stored as simple abbreviations now causes an error because the application of abbreviations is not tracked.

A new message is sometimes printed by the theorem prover, indicating that a given simplification is “specious” because the subgoals it produces include the input goal. In Version 1.4 this was detected but not reported, causing behavior some users found bizarre. See Section 8.82 [SPECIOUS-SIMPLIFICATION], page 365.

:Definition (DEFINITION^) rules are no longer always required to specify the :clique and :controller-alist fields; those fields can be defaulted to system-determined values in many common instances. See Section 15.4 [DEFINITION], page 735.

A warning is printed if a macro form with keyword arguments is given duplicate keyword values. Execute (thm t :doc nil :doc "ignored") and read the warning printed.

A new restriction has been placed on encapsulate (ENCAPSULATE^). Non-local (LOCAL^) recursive definitions inside the encapsulate (ENCAPSULATE^) may not use, in their tests and recursive calls, the constrained functions introduced by the encapsulate (ENCAPSULATE^). See Section 8.84 [SUBVERSIVE-INDUCTIONS], page 371.

The events (EVENTS^) defequiv (DEFEQUIV^), defcong (DEFCONG^), defrefinement (DE-FREFINEMENT^), and defevaluator (DEFEVALUATOR^) have been reimplemented so that they are just macros that expand into appropriate defthm (DEFTHM^) or encapsulate (EN-CAPSULATE^) events (EVENTS^); they are no longer primitive events (EVENTS^). See the documentation (DOCUMENTATION^) of each affected event.

The defcor event, which was a shorthand for a defthm (DEFTHM^) that established a corollary (COROLLARY^) of a named, previously proved event, has been eliminated because its implementation relied on a technique we have decided to ban from our code. If you want the effect of a defcor in Version 1.5 you must submit the corresponding defthm (DEFTHM^) with a :by hint naming the previously proved event.

Error reporting has been improved for inappropriate in-theory (IN-THEORY^) hints (HINTS^) and events (EVENTS^), and for syntax errors in rule classes, and for non-existent filename arguments to ld (LD^).

Technical Note: We now maintain the Third Invariant on type-alists, as described in the Essay on the Invariants on Type-alists, and Canonicality. This change will affect some proofs, for example, by causing a to rewrite more quickly to c when (equiv a b) and (equiv b c) are both known and c is the canonical representative of the three.

14.6 NOTE6

NOTE6 Acl2 Version 1.6 Notes

A new key has been implemented for the acl2-defaults-table (ACL2-DEFAULTS-TABLE^), :ignore-ok. See Section 6.28 [SET-IGNORE-OK], page 198.

It is now legal to have color events (EVENTS^), such as (red), in the portcullis (PORTCULLIS^) of a book. More generally, it is legal to set the acl2-defaults-table (ACL2-DEFAULTS-TABLE^) in the portcullis (PORTCULLIS^) of a book. For example, if you execute :red and then certify a book, the event (red) will show up in the portcullis (PORTCULLIS^) of that book, and hence the definitions in that book will all be red (except when overridden by appropriate declarations or events (EVENTS^)). When that book is included, then as always, its portcullis (PORTCULLIS^) must first be “raised,” and that will cause the default color to become red before the events (EVENTS^) in the book are executed. As always, the value of acl2-defaults-table (ACL2-DEFAULTS-TABLE^) immediately after execution of an include-book (INCLUDE-BOOK^), certify-book (CERTIFY-BOOK^), or encapsulate (ENCAPSULATE^) form will be the same as it was immediately before execution (and hence, so will the default color). See Section 3.10 [PORTCULLIS], page 113 and, for more about books, see Chapter 3 [BOOKS], page 93.

A theory ground-zero (GROUND-ZERO^) has been defined to contain exactly those rules that are enable (ENABLE^)d when Acl2 starts up. See Section 16.6 [GROUND-ZERO], page 782.

The function nth (NTH^) is now enable (ENABLE^)d, correcting an oversight from Version 1.5.

Customization files no longer need to meet the syntactic restrictions put on books (BOOKS^); rather, they can contain arbitrary Acl2 forms. See Section 8.4 [ACL2-CUSTOMIZATION], page 239.

Structured directory names and structured file names are supported; see especially the documentation for pathname (PATHNAME^), book-name (BOOK-NAME^), and cbd (CBD^).

Acl2 now works with some Common Lisp implementations other than akcl, including Lucid, Allegro, and MCL.

A facility has been added for displaying proof trees, especially using emacs; see Chapter 12 [PROOF-TREE], page 617.

There is a considerable amount of new documentation (DOCUMENTATION^), in particular for the printing functions fmt (FMT^), fmt1 (FMT1^), and fms (FMS^), and for the notion of Acl2 term (see Section 8.87 [TERM], page 376).

It is possible to introduce new well-founded relations, to specify which relation should be used by defun (DEFUN^), and to set a default relation. See Section 15.17 [WELL-FOUNDED-RELATION], page 769.

It is possible to make functions suggest new inductions. See Section 15.9 [INDUCTION], page 746.

It is possible to change how Acl2 expresses type-set (TYPE-SET^) information; in particular, this affects what clauses are proved when force (FORCE^)d assumptions are generated. See Section 15.16 [TYPE-SET-INVERTER], page 768.

A new restriction has been added to defpkg (DEFPKG^), having to do with undoing. If you undo a defpkg (DEFPKG^) and define the same package name again, the imports list must be identical to the previous imports or else an explanatory error will occur. See Section 8.70 [PACKAGE-REINCARNATION-IMPORT-RESTRICTIONS], page 354.

Theory-invariant (THEORY-INVARIANT^) and set-irrelevant-formals-ok (SET-IRRELEVANT-

FORMALS-OK^) are now embedded event forms.

The command :good-bye (GOOD-BYE^) may now be used to quit entirely out of Lisp, thus losing your work forever. This command works in akcl but may not work in every Common Lisp.

A theory ground-zero (GROUND-ZERO^) has been added that contains exactly the enable (EN-ABLE^)d rules in the startup (STARTUP^) theory. See Section 16.6 [GROUND-ZERO], page 782.

Define-pc-macro and define-pc-atomic-macro now automatically define :red functions. (It

used to be necessary, in general, to change color to :red before invoking these.)

For a proof of the well-foundedness of e0-ord-< (E0-ORD-<^) on the e0-ordinalps, see Section 8.73 [PROOF-OF-WELL-FOUNDEDNESS], page 355.

Free variables are now handled properly for hypotheses of :type-prescription (TYPE-PRESCRIPTION^) rules.

When the system is loaded or saved, state (STATE^) is now bound to *the-live-state*.

Certify-book (CERTIFY-BOOK^) has been modified so that when it compiles a file, it loads that object file.

Defstub (DEFSTUB^) has been modified so that it works when the color is hot (:red or :pink).

Several basic, but not particularly commonly used, events (EVENTS^) have been added or changed. The obscure axiom symbol-name-intern has been modified. The definition of firstn has been changed. Butlast (BUTLAST^) is now defined. The definition of integer-length (INTEGER-LENGTH^) has been modified. The left-hand side of the rewrite rule rational-implies2 has

been changed from (* (numerator x) (/ (denominator x))) to (* (/ (denominator x))

(numerator x)), in order to respect the fact that unary-/ (UNARY-/^) is invisible with respect to binary-* (BINARY-*^). See Section 8.64 [LOOP-STOPPER], page 347.

The ‘preprocess’ process in the waterfall (see Section 8.43 [HINTS], page 319 for a discussion of the :do-not hint) has been changed so that it works to avoid case-splitting. The ‘simplify’ process refuses to force (see Section 8.37 [FORCE], page 297) when there are if (IF^) terms, including and (AND^) and or (OR^) terms, in the goal being simplified.

The function apply is no longer introduced automatically by translation of user input to internal form when functions are called on inappropriate explicit values, e.g., (car 3).

The choice of which variable to use as the measured variable in a recursive definition has been very slightly changed.

14.7 NOTE7

NOTE7 ACL2 Version 1.7 (released October 1994) Notes

Include-book (INCLUDE-BOOK^) now takes (optionally) an additional keyword argument, indicating whether a compiled file is to be loaded. The default behavior is unchanged, except that a warning is printed when a compiled file is not loaded. See Section 6.20 [INCLUDE-BOOK], page 189.

A markup (MARKUP^) language for documentation (DOCUMENTATION^) strings has been implemented, and many of the source files have been marked up using this language (thanks largely to the efforts of Laura Lawless). See Section 5.8 [MARKUP], page 148. Moreover, there are translators that we have used to provide versions of the ACL2 documentation (DOCUMENTATION^) in info (for use in emacs), html (for Mosaic), and tex (for hardcopy) formats.

A new event defdoc (DEFDOC^) has been implemented. It is like deflabel (DEFLABEL^), but allows redefinition of doc (DOC^) strings and has other advantages. See Section 6.6 [DEFDOC], page 167.

We used to ignore corollaries when collecting up the axioms introduced about constrained functions. That bug has been fixed. We thank John Cowles for bringing this bug to our attention.

The macro defstub (DEFSTUB^) now allows a :doc (DOC^) keyword argument, so that documentation (DOCUMENTATION^) may be attached to the name being introduced.

A new command nqthm-to-acl2 (NQTHM-TO-ACL2^) has been added to help Nqthm users to make the transition to ACL2. See Section 5.12 [NQTHM-TO-ACL2], page 156, which also includes a complete listing of the relevant tables.

Many function names, especially of the form “foo-lst”, have been changed in order to support the following convention, for any “foo”:

(foo-listp lst) represents the notion (for x in lst always foop x).

A complete list of these changes may be found at the end of this note. All of them except symbolp-listp and list-of-symbolp-listp have the string “-lst” in their names. Note also that keyword-listp has been renamed keyword-value-listp (KEYWORD-VALUE-LISTP^).

Accumulated persistence has been implemented. It is not connected to :brr (BRR^) or rule monitoring. See Section 8.1 [ACCUMULATED-PERSISTENCE], page 235.

:Trigger-terms has been added for :linear (LINEAR^) rule classes, so you can hang a linear (LINEAR^) rule under any addend you want. See Section 15.10 [LINEAR], page 749, which has been improved and expanded.

ACL2 now accepts 256 characters (CHARACTERS^) and includes the Common Lisp functions code-char (CODE-CHAR^) and char-code (CHAR-CODE^). However, ACL2 controls the lisp reader so that #\c may only be used when c is a single standard character or one of Newline, Space, Page, Rubout, Tab. If you want to enter other characters (CHARACTERS^) use code-

char (CODE-CHAR^), e.g., (coerce (list (code-char 7) (code-char 240) #a) 'string).

See Section 10.83 [CHARACTERS], page 463. Note: our current handling of characters (CHAR-ACTERS^) makes the set of theorems different under Macintosh Common Lisp (MCL) than under other Common Lisps. We hope to rectify this situation before the final release of ACL2.

A new table (TABLE^), macro-aliases-table (MACRO-ALIASES-TABLE^), has been implemented, that associates macro names with function names. So for example, since append (AP-PEND^) is associated with binary-append (BINARY-APPEND^), the form (disable append) it is interpreted as though it were (disable binary-append). See Section 6.23 [MACRO-ALIASES-TABLE], page 192, see Section 6.1 [ADD-MACRO-ALIAS], page 162 and see Section 6.26 [REMOVE-MACRO-ALIAS], page 196.

The implementation of conditional metalemmas has been modified so that the metafunction is applied before the hypothesis metafunction is applied. See Section 15.12 [META], page 758.

The Common Lisp functions acons (ACONS^) and endp (ENDP^) have been defined in the ACL2 logic.

We have added the symbol declare (DECLARE^) to the list *acl2-exports*, and hence to the

package "ACL2-USER".

A new hint, :restrict, has been implemented. See Section 8.43 [HINTS], page 319.

It used to be that if :ubt (UBT^) were given a number that is greater than the largest current command (COMMAND^) number, it treated that number the same as :max (MAX^). Now, an error is caused.

The table (TABLE^) :force-table has been eliminated.

A command :disabledp (DISABLEDP^) (and macro disabledp (DISABLEDP^)) has been added; see Section 8.24 [DISABLEDP], page 281.

Compilation (COMPILATION^) via :set-compile-fns (SET-COMPILE-FNS^) is now suppressed during include-book (INCLUDE-BOOK^). In fact, whenever the state (STATE^) global variable ld-skip-proofsp (LD-SKIP-PROOFSP^) has value 'include-book (INCLUDE-BOOK^).

Here are some less important changes, additions, and so on.

Unlike previous releases, we have not proved all the theorems in axioms.lisp; instead we have simply assumed them. We have deferred such proofs because we anticipate a fairly major changed in Version 1.8 in how we deal with guard (GUARD^)s.

We used to (accidentally) prohibit the “redefinition” of a table (TABLE^) as a function. That is no longer the case.

The check for whether a corollary (COROLLARY^) follows tautologically has been sped up, at the cost of making the check less “smart” in the following sense: no longer do we expand primitive functions such as implies (IMPLIES^) before checking this propositional implication.

The command (COMMAND^) ubt! (UBT!^) has been modified so that it never causes or reports an error. See Section 7.17 [UBT!], page 230.

ACL2 now works in Harlequin Lispworks.

The user can now specify the :trigger-terms for :linear (LINEAR^) rules. See Section 15.10 [LINEAR], page 749.

The name of the system is now “ACL2”; no longer is it “Acl2”.

The raw lisp counterpart of theory-invariant (THEORY-INVARIANT^) is now defined to be a no-op as is consistent with the idea that it is just a call of table (TABLE^).

A bug was fixed that caused proof-checker (PROOF-CHECKER^) instructions (INSTRUC-TIONS^) to be executed when ld-skip-proofsp (LD-SKIP-PROOFSP^) was t.

The function rassoc (RASSOC^) has been added, along with a corresponding function used in its

guard (GUARD^), r-eqlable-alistp.

The in-theory (IN-THEORY^) event and hint now print a warning not only when certain “primitive” :definition (DEFINITION^) rules are disable (DISABLE^)d, but also when certain “primitive” :executable-counterpart (EXECUTABLE-COUNTERPART^) rules are disable (DIS-ABLE^)d.

The modified version of trace provided by ACL2, for use in raw Lisp, has been modified so that the lisp special variable *trace-alist* is consulted. This alist associates, using eq (EQ^), values with their print representations. For example, initially *trace-alist* is a one-element list containing

the pair (cons state '|*the-live-state*|).

The system now prints an observation when a form is skipped because the default color is :red or :pink. (Technically: when-cool has been modified.)

Additional protection exists when you submit a form to raw Common Lisp that should only be submitted inside the ACL2 read-eval-print loop.

Here is a complete list of the changes in function names described near the top of this note, roughly of the form

foo-lst --> foo-listp

meaning: the name “foo-lst” has been changed to “foo-listp.”

symbolp-listp    --> symbol-listp
list-of-symbolp-listp  --> symbol-list-listp
                       {for consistency with change to symbol-listp}
rational-lst     --> rational-listp
                     {which in fact was already defined as well}
integer-lst      --> integer-listp
character-lst    --> character-listp
stringp-lst      --> string-listp
32-bit-integer-lst   --> 32-bit-integer-listp
typed-io-lst     --> typed-io-listp
open-channel-lst --> open-channel-listp
readable-files-lst   --> readable-files-listp
written-file-lst --> written-file-listp
read-file-lst    --> read-file-listp
writeable-file-lst   --> writable-file-listp
                     {note change in spelling of ``writable''}
writeable-file-lst1  --> writable-file-listp1
pseudo-termp-lst     --> pseudo-term-listp
hot-termp-lst --> hot-term-listp {by analogy with pseudo-term-listp}
weak-termp-lst   --> weak-term-listp
weak-termp-lst-lst   --> weak-termp-list-listp
ts-builder-case-lstp -> ts-builder-case-listp
quotep-lst       --> quote-listp
termp-lst        --> term-listp
instr-lst        --> instr-listp
spliced-instr-lst    --> spliced-instr-listp

     rewrite-fncallp-lst  --> rewrite-fncallp-listp
     every-occurrence-equiv-hittablep1-lst -->
                 every-occurrence-equiv-hittablep1-listp
     some-occurrence-equiv-hittablep1-lst  -->
                 some-occurrence-equiv-hittablep1-listp
                 {by analogy with the preceding, even though it's a
                  ``some'' instead of ``all'' predicate]
     almost-quotep1-lst   --> almost-quotep1-listp
     ffnnames-subsetp-lst --> ffnnames-subsetp-listp
     boolean-lstp     --> boolean-listp
     subst-expr1-lst-okp  --> subst-expr1-ok-listp

14.8 NOTE8

NOTE8 ACL2 Version 1.8 (May, 1995) Notes

See Section 14.9 [NOTE8-UPDATE], page 719 for yet more recent changes.

Guard (GUARD^)s have been eliminated from the ACL2 logic. A summary is contained in this brief note. Also see Section 8.20 [DEFUN-MODE], page 275 and see Section 9.12 [SET-GUARD-CHECKING], page 423.

Guard (GUARD^)s may be included in defuns (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 (CAR^), logically default unexpected arguments to convenient values. Thus, (+ 'abc 3) is 3 and (car 'abc) is nil. See Chapter 10 [PROGRAMMING], page 429, and see the documentation (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 guard (GUARD^)s have not been verified. In versions before 1.8, such functions were interpreted by ACL2.

Colors have been eliminated. Two “defun-mode (DEFUN-MODE^)s” are supported, :program (PROGRAM^) and :logic (LOGIC^). Roughly speaking, :program (PROGRAM^) does what :red used to do, namely, allow you to prototype functions for execution without any proof burdens. :Logic (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 (DEFAULT-DEFUN-MODE^) is comparable to the old default color. The system comes up in :logic (LOGIC^) mode. To change the global defunmode (DEFUN-MODE^), type :program (PROGRAM^) or :logic (LOGIC^) at the top-level. To specify the defun-mode (DEFUN-MODE^) of a defun (DEFUN^) locally use

     (declare (xargs :mode mode)).

The prompt (PROMPT^) has changed. The initial prompt (PROMPT^), indicating :logic (LOGIC^) mode, is

     ACL2 !>

If you change to :program (PROGRAM^) mode the prompt (PROMPT^) becomes

     ACL2 p!>

Guard (GUARD^)s 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 (GUARD^) is specified, as with xargs (XARGS^) :guard (GUARD^), then it is “verified” at defun-time (unless you also specify xargs (XARGS^) :verify-guards nil). Guard (GUARD^) verification means what it always has: the input guard (GUARD^) is shown to imply the guard (GUARD^)s on all subroutines in the body. If the guard (GUARD^)s of a function are verified, then a call of the function on inputs satisfying the guard (GUARD^) can be computed directly by Common Lisp. Thus, verifying the guard (GUARD^)s 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 guard (GUARD^)s either as a specification device or only use them when execution efficiency is extremely important.

Given the presence of guard (GUARD^)s in the system, two issues are unavoidable. Are guard (GUARD^)s verified as part of the defun (DEFUN^) process? And are guard (GUARD^)s checked when terms are evaluated? We answer both of those questions below.

Roughly speaking, in its initial state (STATE^) the system will try to verify the guard (GUARD^)s of a defun (DEFUN^) if a :guard (GUARD^) is supplied in the xargs (XARGS^) and will not try otherwise. However, guard (GUARD^) verification in defun (DEFUN^) can be inhibited “locally” by supplying the xargs (XARGS^) :verify-guards (VERIFY-GUARDS^) nil. “Global” inhibition can be obtained via the :set-verify-guards-eagerness (SET-VERIFY-GUARDS-EAGERNESS^). If you do not use the :guard (GUARD^) xargs (XARGS^), you will not need to think about guard (GUARD^) verification.

We now turn to the evaluation of expressions. Even if your functions contain no guard (GUARD^)s, the primitive functions do and hence you have the choice: when you submit an expression for evaluation do you mean for guard (GUARD^)s 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 (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 (GUARD^) checking on,” by which we mean that guard (GUARD^)s 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 (PROMPT^).

     ACL2 !>

means guard (GUARD^) checking is on and

     ACL2 >

means guard (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 guard (GUARD^)s are checked at runtime is independent of whether you are operating in :program (PROGRAM^) mode or :logic (LOGIC^) mode and whether theorems are being proved or not. (Although it must be added that functions defined in :program (PROGRAM^) mode cannot help but check their guard (GUARD^)s because no logical definition exists.)

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

     (verify-guards name).

If a theorem’s guard (GUARD^)s 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 (VERIFY-GUARDS^): implies (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 guard (GUARD^)s on a theorem if implies (IMPLIES^) is used to state the hypotheses. Use if (IF^) instead. In a future version of ACL2, implies (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 (GUARD-EXAMPLE^).

We have removed the capability to do “old-style-forcing” as existed before Version 1.5. See Section 14.5 [NOTE5], page 698.

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 guard (GUARD^)s verified. So for example, the type prescription rune (RUNE^) for binary-append (BINARY-APPEND^) is now

     (:type-prescription binary-append)

while in Versions 1.7 and earlier, there were two such rune (RUNE^)s:

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

Nqthm-style forcing on linear (LINEAR^) arithmetic assumptions is no longer executed when forcing is disable (DISABLE^)d.

Functional instantiation now benefits from a trick also used in Nqthm: once a constraint (CON-STRAINT^) generated by a :functional-instance lemma instance (see Section 8.61 [LEMMA-INSTANCE], page 342) has been proved on behalf of a successful event, it will not have to be re-proved on behalf of a later event.

1+ (1+^) and 1- (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 (DOCUMENTATION^) section file-reading-example (FILE-READING-EXAMPLE^) illustrates how to process forms in a file.

A new proof-checker (PROOF-CHECKER^) command forwardchain has been added; see Section 11.30 [ACL2-PC::FORWARDCHAIN], page 577.

It is now possible to use quantifiers. See Section 6.17 [DEFUN-SK], page 182 and see Section 6.3 [DEFCHOOSE], page 163.

There is a new event set-inhibit-warnings (SET-INHIBIT-WARNINGS^), which allows the user to turn off warnings of various types. see Section 6.29 [SET-INHIBIT-WARNINGS], page 198.

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

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

The documentation (DOCUMENTATION^) has been substantially improved. A new section “Programming” contains documentation (DOCUMENTATION^) of many useful functions provided by ACL2; see Chapter 10 [PROGRAMMING], page 429. Also, the documentation (DOCUMENTA-TION^) has been “marked up” extensively. Thus in particular, users of Mosaic will find many links in the documentation (DOCUMENTATION^).

The symbols force (FORCE^), mv-nth (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 Section 8.67 [NAME], page 352.

We have changed the list of imports from the Common Lisp package to ACL2, i.e., the list *commonlisp-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 (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 (POSITION^) (for the test eql (EQL^)), as well as corresponding versions position-equal (POSITION-EQUAL^) and position-eq (POSITION-EQ^) that use tests equal (EQUAL^) and eq (EQ^), respectively. See Section 10.188 [POSITION], page 518, see Section 10.190 [POSITION-EQUAL], page 519, and see Section 10.189 [POSITION-EQ], page 518.

The defthm (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 (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 (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 (PROOF-CHECKER^) commands claim and = (=^) has been replaced by :none.

A bug in the handling of hints (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 (PSEUDO-TERMP^) and pseudo-term-listp. The notion of pseudo-termp (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 (IO^) level, we have improved performance somewhat by suitable declarations and proclamations. These include technical modifications to the macros mv (MV^) and mv-let (MV-LET^), and introduction of a macro the-mv analogous to the macro the (THE^) but for forms returning multiple values.

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

A bug in the proof-checker (PROOF-CHECKER^) equiv command was fixed.

The function intersectp has been deleted, because it was essentially duplicated by the function intersectp-equal (INTERSECTP-EQUAL^).

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

The function repeat has been eliminated; use make-list (MAKE-LIST^) instead.

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

A new primitive function, mv-nth (MV-NTH^), has been introduced. Mv-nth (MV-NTH^) is equivalent to nth (NTH^) and is used in place of nth (NTH^) in the translation of mv-let (MV-LET^) expressions. This allows the user to control the simplification of mv-let (MV-LET^) expressions without affecting how nth (NTH^) is treated. In that spirit, the rewriter has been modified so that certain mv-nth (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 (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 (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 (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 (SKIP-PROOFS^) now prints a warning message when it is encountered in the context of an encapsulate (ENCAPSULATE^) event or a book. See Section 9.14 [SKIP-PROOFS], page 425.

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

14.9 NOTE8-UPDATE

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

ACL2 can now use Ordered Binary Decision Diagram technology. See Chapter 2 [BDD], page 71. There is also a proof-checker (PROOF-CHECKER^) bdd command.

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

The ld (LD^) special (see Section 9.7 [LD], page 416) ld-pre-eval-print (LD-PRE-EVAL-PRINT^) may now be used to turn off printing of input forms during processing of encapsulate (ENCAPSULATE^) and certify-book (CERTIFY-BOOK^) forms, by setting it to the value

:never, i.e., (set-ld-pre-eval-print :never state). See Section 8.55 [LD-PRE-EVAL-

PRINT], page 334.

The TUTORIAL documentation section has, with much help from Bill Young, been substantially improved to a bona fide introduction, and has been renamed acl2-tutorial (ACL2-TUTORIAL^).

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 (SET-INHIBIT-OUTPUT-LST^) has been defined. This should be used when setting the state (STATE^) global inhibit-output-lst; see Section 9.13 [SET-INHIBIT-OUTPUT-LST], page 424 and see Chapter 12 [PROOF-TREE], page 617.

The test for redundancy in definitions includes the guard (GUARD^) and type declarations. See Section 8.78 [REDUNDANT-EVENTS], page 361.

See Section 8.39 [GENERALIZED-BOOLEANS], page 302 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 Section 9.5 [COMP], page 415) correctly handles non-standard characters.

A bug in digit-char-p (DIGIT-CHAR-P^) has been fixed, so that the “default” is nil rather than 0.

True-listp (TRUE-LISTP^) now tests the final cdr (CDR^) against nil using eq (EQ^) instead of equal (EQUAL^), for improved efficiency. The logical meaning is, however, unchanged.

Put-assoc-equal (PUT-ASSOC-EQUAL^) has been added to the logic (it used to have :defunmode (DEFUN-MODE^) :program (PROGRAM^), and has been documented.

14.10 NOTE9

NOTE9 ACL2 Version 1.9 (Fall, 1996) Notes

By default, when the system is started it is illegal to use the variable STATE (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 Section 6.33 [SET-STATE-OK], page 201

Set-state-ok is an event that affects the ACL2 defaults table (see Section 9.2 [ACL2-DEFAULTS-TABLE], page 410). 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 PRE-VENT 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 Section 8.40 [GOAL-SPEC], page 304) 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 Section 15.1 [BUILT-IN-CLAUSES], page 727

Wormholes can now be used in :logic mode functions. See Section 8.101 [WORMHOLE], page 401

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 Section 8.13 [COMPUTED-HINTS], page 263 and the extraordinarily long example in see Section 8.91 [USING-COMPUTED-HINTS], page 386.

Hide terms may be rewritten with :rewrite rules about hide. See Section 8.42 [HIDE], page 317, 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.

722 ACL2 Version 1.9

15 RULE-CLASSES

RULE-CLASSES adding rules to the data base

     General Form:
     a true list of rule class objects as defined below
     Special Cases:
     a symbol abbreviating a single rule class object

ACL2 provides users with the ability to create a number of different kinds of rules, including (conditional) rewrite rules but also including others. Don’t be put off by the long description to follow; usually, you’ll probably want to use rewrite rules. More on this below.

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 (!)
       :LOOP-STOPPER alist        ; provided :class = :REWRITE
       :PATTERN term              ; provided :class = :INDUCTION (!)
       :CONDITION term            ; provided :class = :INDUCTION
       :SCHEME term               ; provided :class = :INDUCTION (!)
       :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 data base. 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 (DOCUMENTATION^) facilities do not permit us to use keywords below).

* BUILT-IN-CLAUSES:: to build a clause into the simplifier and measure and guard generating * 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

* GENERALIZE:: make a rule to restrict generalizations

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

* LINEAR:: make some arithmetic inequality rules

* LINEAR-ALIAS:: make a rule to extend the applicability of linear arithmetic

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

* 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

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 (TYPE-PRESCRIPTION^) and :forward-chaining (FORWARD-

CHAINING^) rules for “type-theoretic” rules, especially ones whose top-level function symbol is a common one like true-listp (TRUE-LISTP^) or consp (CONSP^); see Section 15.15 [TYPE-PRESCRIPTION], page 766 and see Section 15.7 [FORWARD-CHAINING], page 744. 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 (REWRITE^) rule.

:Rule-classes is an optional keyword argument of the defthm (DEFTHM^) (and defaxiom (DE-FAXIOM^)) 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 (DEFTHM^) (or defaxiom (DEFAXIOM^)) event,

it is 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 (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 (CAR^) is one of the rule class keyword tokens listed above, e.g., :rewrite (REWRITE^), :elim (ELIM^), etc., and whose cdr (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 (COROLLARY^) — its value, term, must be a term. If omitted, this field defaults to thm. The :corollary (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 (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 wellformed, its (defaulted) :corollary (COROLLARY^), term, must follow from thm. Unless term is trivially implied by 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 (HINTS^), :instructions (INSTRUCTIONS^), and :otf-flg (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 Section 9.16 [TRANS], page 427.

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

:Type-set (TYPE-SET^) — this field may be supplied only if the :class is :typeset-inverter (TYPE-SET-INVERTER^). When provided, the value must be a typeset, an integer in a certain range. If not provided, an attempt is made to compute it from the corollary. See Section 15.16 [TYPE-SET-INVERTER], page 768.

:Typed-term — this field may be supplied only if the :class is :type-prescription

(TYPE-PRESCRIPTION^). When provided, the value is the term for which the :corollary (COROLLARY^) is a type-prescription lemma. If no :typed-term is provided in a :type-prescription (TYPE-PRESCRIPTION^) rule class object, we try to compute heuristically an acceptable term. See Section 15.15 [TYPE-PRESCRIPTION], page 766.

:Trigger-terms — this field may be supplied only if the :class is :forward-chaining

(FORWARD-CHAINING^) or :linear (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 Section 15.7 [FORWARD-CHAINING], page 744 or see Section 15.10 [LINEAR], page 749.

:Trigger-fns — this field must (and may only) be supplied if the :class is :meta (META^). Its value must be a list of function symbols. Terms with these symbols trigger the application of the rule. See Section 15.12 [META], page 758.

:Clique and :controller-alist — these two fields must (and may only) be supplied if the :class is :definition (DEFINITION^). Suppose the :corollary (COROL-

LARY^) 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.

:loop-stopper (LOOP-STOPPER^) — this field may only be supplied if the class is :rewrite (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 Section 8.64 [LOOP-STOPPER], page 347. 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 (COROLLARY^) formula.

:pattern, :condition, :scheme — the first and last of these fields must (and may only) be supplied if the class is :induction (INDUCTION^). :Condition is optional but may only be supplied if the class is :induction (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 Section 15.9 [INDUCTION], page 746.

Once thm has been proved (in the case of defthm (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 (RUNE^) (:class name . x), where x is nil if there is only one class and otherwise x is i. Then, from the :corollary (COROLLARY^) of that object, generate one or more rules, each of which has the name (:class name . x). See the :doc (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 (COROL-LARY^) determines more than one rule. This in fact only occurs for :rewrite (REWRITE^), :linear (LINEAR^), and :forward-chaining (FORWARD-CHAINING^) class rules and only then if the :corollary (COROLLARY^) is essentially a conjunction. (See the documentation for rewrite (REWRITE^), linear (LINEAR^), or forward-chaining (FORWARD-CHAINING^) for details.)

15.1 BUILT-IN-CLAUSES

BUILT-IN-CLAUSES to build a clause into the simplifier and measure and guard generating

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. 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 (IMPLIES^) and and (AND^) structure of the :corollary (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.

For example, the following :corollary (COROLLARY^) (regardless of the definition of 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))))

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 (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 (CDR^) after testing consp (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 (CDR^) recursion after a consp (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 (CDR^) recursion is ok after a negative atom (ATOM^) test (which, by the definition of atom (ATOM^), is the same as a consp (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.

15.2 COMPOUND-RECOGNIZER

COMPOUND-RECOGNIZER make a rule used by the typing mechanism

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. An example :corollary (COROLLARY^) formula from which a :compound-recognizer rule might be built is:

     Example:
     (implies (alistp x)         When (alistp x) is assumed true,
              (true-listp x))    add the additional hypothesis that x
                                 is of primitive type true-listp.
     General Forms:
     (implies (fn x) concl)
     (implies (not (fn x)) concl)
     (and (implies (fn x) concl1)
          (implies (not (fn x)) concl2))
     (iff (fn x) concl)
     (equal (fn x) concl)

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 third 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, the last two general forms above being equivalent. We explain how such rules are used by considering the individual forms.

Consider a rule of the first form, (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. 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.

The second general form addresses itself to 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 consp (CONSP^)s — 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 (CONSP^).

The third general form addresses itself 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 a rule of the third form is

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

Finally, rules of the fourth class address the case where fn recognizes all and only the objects whose type is described. In this case, 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 (fn x) will not be recognized as a compound recognizer once it has been expanded.

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 or fourth forms. Proving a rule of the first form followed by one of the second only leaves the second fact in the data base.

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

If you prove multiple compound recognizer rules 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 interpretions 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 know and then forget 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 (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 (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 (FORWARD-CHAINING^) rules instead of :compound-

recognizer rules.

15.3 CONGRUENCE

CONGRUENCE the relations to maintain while simplifying arguments

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. An example :corollary (COROLLARY^) formula from which a :congruence rule might be built is:

     Example:
     (implies (set-equal x y)
              (iff (memb e x) (memb e y))).

Also see Section 6.4 [DEFCONG], page 165 and see Section 15.6 [EQUIVALENCE], page 738.

     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 equiv2equivalence of fn-expressions can be maintained if, while rewriting the kth argument position, equiv1-equivalence is maintained. See Section 15.6 [EQUIVALENCE], page 738 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

(DEFTHM^) of rule-class :congruence that attempts to establish that equiv2 is maintained by maintaining equiv1 in fn’s kth argument. The defcong (DEFCONG^) macro automatically generates the general formula shown above. See Section 6.4 [DEFCONG], page 165.

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 (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 (IF^) (but not, for example, as an argument to cons (CONS^)), we can rewrite its second argument maintaining set-equality. For example, a rule stating the commutativity of append (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 Section 15.13 [REFINEMENT], page 763.

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 (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 (REWRITE^) rules for one are unexpectedly preventing the application of the desired rule, you can disable the rule that introduced the unwanted inside equivalence.

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

15.4 DEFINITION

DEFINITION make a rule that acts like a function definition

     Example:
     (implies (true-listp x)
              (equal (len x)
                     (if (null x)
                         0
                         (if (null (cdr x))
                             1
                             (len (cddr x))))))
     General Form:
     (implies hyp (equiv (fn a1 ... an) body))

where equiv is an equivalence relation and fn is a function symbol other than if (IF^), hide (HIDE^) or force (FORCE^). 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 (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 (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). If the :clique contains more than one function, the user must supply the :controlleralist 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.

The definitional principle, defun (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 (DEFUN^)’d to be body. Note that defun (DEFUN^) (or defuns (DEFUNS^) or mutual-recursion (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 (DEFUN^) adds the

:definition rule (equal (fn x y) body). Thus, (fn a b) will not be expanded unless (g a b)

can be established.

15.5 ELIM

ELIM make a destructor elimination rule See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. An example :corollary (COROLLARY^) formula from which an :elim rule might be built is:

     Example:
     (implies (consp x)                      when (car v) or (cdr v) appears
              (equal (cons (car x) (cdr x))  in a conjecture, and v is a
                     x))                     variable, consider replacing v by
                                             (cons a b), for two new variables
                                             a and b.
     General Form:
     (implies hyp (equal lhs x))

where 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. If it then finds an instance of some destructor term (fn v1 ... vn) in the conjecture, where the instance for x is some variable symbol, vi, it 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, generalizes all the instantiated destructor terms in the conjecture to new variables and then replaces vi in the conjecture by the generalized instantiated lhs.

At the moment, the best description of how ACL2 :elim rules are used may be found in the discussion of “ELIM Rules,” pp 247 of A Computational Logic Handbook.

15.6 EQUIVALENCE

EQUIVALENCE mark a relation as an equivalence relation

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. An example :corollary (COROLLARY^) formula from which a :equivalence rule might be built is as follows. (We assume that r-equal has been defined.)

     Example:
     (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))).

Also see Section 6.7 [DEFEQUIV], page 168.

     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 2place function symbols can be treated as equivalence relations. See Section 15.3 [CONGRUENCE], page 733 and see Section 15.13 [REFINEMENT], page 763 for closely related concepts.

The macro form (defequiv equiv) is an abbreviation for a defthm (DEFTHM^) of rule-class :equivalence that establishes that equiv is an equivalence relation. It generates the formula shown above. See Section 6.7 [DEFEQUIV], page 168.

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 (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 (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 (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 Section 15.3 [CONGRUENCE], page 733 for details about :congruence (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 (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 (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 Section 15.13 [REFINEMENT], page 763.

The system initially has knowledge of two equivalence relations, equality, denoted by the symbol equal (EQUAL^), and propositional equivalence, denoted by iff (IFF^). Equal (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 (CONGRUENCE^) lemmas that show where equiv can be used to maintain known relations,

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

(5) develop the theory of conditional :rewrite (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 (CONS^) and member (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 (x y) t))
(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 ==-symmetric (== x x))
(defthm ==-reflexive (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))

15.7 FORWARD-CHAINING

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

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. An example :corollary (COROLLARY^) formula from which a :forward-chaining rule might be built is:

Example:
(implies (and (p x) (r x))        when (p a) appears in a formula to be

              (q (f x)))               simplified, try to establish (r a) and
                                       if successful, add (q (f a)) to the
                                       known assumptions

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

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

Forward chaining rules are generated from the corollary term as follows. If that term has the form (implies hyp concl), then the let (LET^) expressions in concl (formally, lambda expressions) are expanded away, and the result 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 (IMPLIES^), we process it as we process the conclusion in the first case.

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 (LET^)-expression, or a not (NOT^)-expression, and every variable symbol in the conclusion of the theorem either occurs in the hypotheses or occurs in the trigger.

:Forward-chaining rules are used by the simplifier before it begins to rewrite the literals of the 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 hypotheses we only use type reasoning, evaluation of ground terms, and presence among our known assumptions. We do not use rewriting. If all hypotheses are relieved, we add the instantiated conclusion to our known assumptions.

15.8 GENERALIZE

GENERALIZE make a rule to restrict generalizations See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. An example :corollary (COROLLARY^) formula from which a :generalize rule might be built is:

     Example:
     any theorem
     General Form:
     any theorem

To use such 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.

At the moment, the best description of how ACL2 :generalize rules are used may be found in the discussion of “Generalize Rules,” pp 248 of A Computational Logic Handbook.

15.9 INDUCTION

INDUCTION make a rule that suggests a certain induction

     Example:
     (:induction :corollary t  ; the theorem proved is irrelevant!
                 :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 (APPEND^) (actually binary-append (BINARY-APPEND^), but we’ll ignore the distinction here) decomposes its first argument by successive cdr (CDR^)s 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 (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 insure 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 (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 (DEFTHM^).

Technically we are “overloading” defthm (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 (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. 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 (CONSP^) argument two cdr (CDR^)s 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 (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 (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.

15.10 LINEAR

LINEAR make some arithmetic inequality rules

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. An example :corollary (COROLLARY^) formula from which a :linear rule might be built is:

     Example:
     (implies (and (eqlablep e)           if inequality reasoning begins to

                   (true-listp x))        consider how (length (member a b))
              (>= (length x)              compares to any other term, add to
                  (length (member e x)))) set of known inequalities the fact
                                          that it is no larger than (length b),
                                          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 (COROLLARY^) formula. To create the rules, we first flatten the and (AND^) and implies (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 a linear arithmetic decision procedure during rewriting. We describe the procedure very roughly here. Fundamental to the procedure is the notion of a linear polynomial inequality. A “linear polynomial” is a sum of terms, each of which is the product of a rational constant and an “unknown.” The “unknown” is permitted to be 1 simply to allow a term in the sum to be constant. Thus, an example linear polynomial is 3*x + 7*a + 2; here x and a are the (interesting) unknowns. In our case, the unknowns need not be variable symbols. For example, (length x) might be used as an unknown in a linear polynomial. Thus, another linear polynomial is 3*(length x) + 7*a. A “linear polynomial inequality” is an inequality (either < (<^) or <= (<=^)) relation between two linear polynomials. Certain linear polynomial inequalities can be combined by cross-multiplication and addition to permit the deduction of a third linear inequality polynomial with fewer unknowns. If this deduced inequality is manifestly false, a contradiction has been deduced from the assumed inequalities.

For example, suppose we have three assumptions:

     p1:  3*x + 7*a <  4
     p2:          3 <  2*x
     p3:          0 <= a.

By cross-multiplying and adding the first two (that is, multiplying p1 by 2, p2 by 3 and adding the respective sides), we deduce the intermediate result

     p4:  6*x + 14*a + 9 < 8 + 6*x

which, after cancellation, is

     p4:        14*a + 1 <  0.

If we then cross-multiply and add p3 to p4, we get

     p5:               1 <= 0,

a contradiction. Thus, we have proved that p1 and p2 imply the negation of p3.

All of the unknowns of a polynomial must be eliminated by cancellation in order to produce a constant inequality. We can choose to eliminate the unknowns in any order. We eliminate them in term-order, largest unknowns first. (See Section 8.88 [TERM-ORDER], page 379.) Now suppose that this procedure does not produce a contradiction but instead yields a set of nontrivial inequalities. A contradiction might still be deduced if we could add to the set some additional inequalities allowing additional cancellation. That is where :linear lemmas come in. When the set of inequalities has stabilized under cross-multiplication and addition and no contradiction is produced, we search the data base of :linear rules for rules about the unknowns that are candidates for cancellation (i.e., are the largest unknowns in their respective inequalities).

If the trigger term of some :linear rule can be instantiated to yield a candidate for cancellation, we so instantiate that rule, attempt to relieve the hypotheses with general-purpose rewriting, and, if successful, convert the concluding inequality into a polynomial inequality and add it to the set. This may let cancellation continue. See the discussion of “Linear Arithmetic Rules” pp 242 of A Computational Logic Handbook for more details.

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.

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 largest unknown in some inequality in the set of assumed inequalities, 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 this inequality will not be used until that term is eliminated by cancellation with some other inequality. It is generally best to specify as a trigger term one of the “maximal” terms of the polynomial, as described below.

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 numeric constant, is in all cases 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 (LET^) and non-if (IF^) expression,

(b) the term contains enough variables so that when they are instantiated and the hypotheses are relieved then all the variables in concl are instantiated, and (c) any instantiation of the term is always at least as “large” (see Section 8.88 [TERM-ORDER], page 379 for a description of the order used) as the corresponding instantiations of any other addend in concl.

15.11 LINEAR-ALIAS

LINEAR-ALIAS make a rule to extend the applicability of linear arithmetic

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. An example :corollary (COROLLARY^) formula from which a :linear-alias rule might be built is as follows. (Of course, the functions fix, plus, diff, and lessp would have to be defined first.)

     Example:
     (and (equal (fix (plus x y)) (plus x y))
          (equal (fix (diff x y)) (diff x y))
          (equal (fix (fix x)) (fix x))
          (equal (lessp x y) (< (fix x) (fix y)))
          (equal (plus x y) (+ (fix x) (fix y)))
          (implies (not (lessp x y))
                   (equal (diff x y) (- (fix x) (fix y)))))

:linear-alias rules are essentially a hack to allow the creation of the "NQTHM" package. We will be surprised if the casual user of ACL2 ever finds a use for them. They are not documented very thoroughly.

     General Forms:
     (equal lhs rhs)
     (implies hyps (equal lhs rhs))

where every variable that occurs in the rule must occur in the lhs. As for :rewrite (REWRITE^) rules, we strip the conjuncts out of the :corollary (COROLLARY^) formula and generate one :linear-alias rule for each. Thus, it is possible to package together a complete set of :linearalias rules under a single name.

When linear arithmetic is applied to a term that is not “linearizable,” i.e., a term that does not start with < (<^), + (+^), or - (-^), it attempts to transduce the term to a linearizable one by applying all known :linear-alias rules as rewrite rules. This transduction is performed by the simple rewrite function rewrite-with-linear-aliases. Like the standard ACL2 rewriter, the linear alias rewriter applies linear alias rules exhaustively in the sense that if a rule applies then the rhs of the rule is recursively rewritten. Unlike :rewrite (REWRITE^) rules, :linear-alias rules are applied from outside in (!) and hypotheses are not relieved but merely collected.

For example, rewriting (lessp (diff (plus a b) c) (diff u v)) with the rules generated from the conjunction above produces

     (< (+ (+ (fix a) (fix b))
           (- (fix c)))
        (+ (fix u) (- (fix v))))

under the hypothesis that (not (lessp (plus a b) c)) and (not (lessp u v)). (Actually, the + (+^) and - (-^) operators shown above are really calls of binary-+ (BINARY-+^) and unary-- (UNARY–^).)

Think of :linear-alias rules as transforming a term from one theory to another, generating hypotheses in the first theory. Call the initial theory “nqthm” and the final one “acl2.” One should strive to create a set of rules that transform from the nqthm to the acl2 theory while only generating hypotheses in the first theory. The restriction is motivated by the desire not to surprise the nqthm user by suddently introducing conditions that are not phrased in the nqthm theory. The purpose of the nqthm package is to emulate nqthm, so it simply represents a failure if acl2 suddenly produces a case split, say, in which some non-nqthm term appears, such as (rationalp (plus a b)). To this end, we offer some advice below. However, it is especially helpful to study how the outside-in rewrite strategy uses the rules above to achieve this goal.

For example,

       (lessp (plus a b) (diff u v))

first steps to

       (< (fix (plus a b)) (fix (diff u v))),

unconditionally. But plus and diff don’t need fix (FIX^)ing:

       (< (plus a b) (diff u v)).

Rewriting further finishes with

       (< (+ (fix a) (fix b)) (+ (fix u) (- (fix v)))).

Observe that had we rewritten inside-out the sequence would have been:

       (lessp (+ (fix a) (fix b)) (+ (fix u) (- (fix v))))

and then

       (< (fix (+ (fix a) (fix b))) (fix  (+ (fix u) (- (fix v))))).

Note that we now need to know that + (+^) doesn’t need fix (FIX^)ing if its arguments have been. But that is a more complicated rule than the simple one that plus doesn’t need fix (FIX^)ing. Perhaps a different set of rules would work well for inside-out rewriting, but I just used the ones that first leapt to mind. It is interesting to note that linearization proceeds outside in too.

Here then is the advice. Rules should either transform nqthm terms to nqthm terms, e.g., (fix (plus x y)) to (plus x y), or should transform nqthm terms to acl2 terms, e.g., (lessp x y) to (< (fix x) (fix y)). When the rhs introduces an acl2 function symbol, the symbol should be outside of all nqthm terms in the rhs. Hypotheses should be expressed in the nqthm theory. No rule should rewrite an acl2 function symbol. If the transformation involves “fixers” then each operator should have two rules about it. The first, like (plus x y) = (+ (fix x) (fix y)), explains the nqthm function in terms of an acl2 function with fixed arguments. The second, like (fix (plus x y)) = (plus x y) eliminates the interior fixes generated by the first rule. These conventions mean that the rewriter, by going from outside in, always sees nqthm terms and instantiates the hypotheses of rules with nqthm terms. To violate these conventions might produce a set of rules that would cause a non-nqthm hypothesis to be generated.

Finally, observe that the rules probably will introduce a “fixer”, which is the function fix (FIX^) in the NQTHM package. The fixer tends to settle around the nonlinear leaves of the resultant linearizable term. It is important to have a :type-prescription (TYPE-PRESCRIPTION^) rule establishing that the fixer produces a rational.

When a :linear (LINEAR^) arithmetic rule is proved its conclusion is linearized to obtain the relevant polynomials. :linear-alias rules may kick in there; thus, a conclusion of the form

(not (lessp (length str) (strpos pat str))) may be a legal :linear (LINEAR^) rule. Note
however that its linearization is (not (< (fix (length str)) (fix (strpos pat str)))). The

maximal term of this rule is (fix (strpos pat str)). However, we do not want to store such a linear rule under fix (FIX^) because that would result in all of the Nqthm proveall’s linear rules being stored under the same symbol. We therefore note when the maximal term does not actually occur in the conclusion, is of the form (fix term), for some unary function fix (FIX^), and term does occur in the conclusion. In that case, we call fix (FIX^) a “fixer” and we store a t under the property 'linear-alias-fixerp. We then store the rule with the maximal term term instead of (fix term). Later, when we are adding lemmas to the linear pot, we note that if we seek linear lemmas about (fix term), where fix (FIX^) is a fixer, we look for lemmas both stored under the function symbol of term and stored under the function symbol fix (FIX^). In all cases, the maximal term of the rule contains as its top-most function symbol the symbol under which the rule is stored. Thus, if we seek lemmas about (fix (strpos pat str)) we will go to the property list of strpos and there find rules about (strpos pat str). We will instantiate their conclusions and linearize them, producing polynomials about (fix (strpos pat str)). This raises a subtle point. It could be that there is more than one fixer used in connection with strpos. Thus, some lemmas could linearize to polynomials about (rat (strpos pat str)). Therefore, when we create the linear rule with (strpos pat str) as its (fixed) maximal term, we store in the :fixer field of the rule the symbol fix (FIX^) to indicate that the linearization of this conclusion will (probably) produce (fix (strpos pat str)) terms. When looking for lemmas about (fix (strpos pat str)) we actually look for lemmas about strpos that have :fixer fix (FIX^).

Here is an extended example of the use of linear aliasing. First, we define some nqthm-level functions:

     (defun fix (x) (if (and (integerp x) (>= x 0)) x 0))
     (defun lessp (x y) (< (fix x) (fix y)))
     (defun plus (x y) (+ (fix x) (fix y)))
     (defun diff (x y) (fix (- (fix x) (fix y))))

Note that (fix x) gets a :type-prescription (TYPE-PRESCRIPTION^) rule that it is a nonnegative integer.

Now we prove a :linear-alias rule, actually a package of the six rules above.

     (defthm nqthm-linear-arithmetic
       (and (equal (fix (plus x y)) (plus x y))
            (equal (fix (diff x y)) (diff x y))
            (equal (fix (fix x)) (fix x))
            (equal (lessp x y) (< (fix x) (fix y)))
            (equal (plus x y) (+ (fix x) (fix y)))
            (implies (not (lessp x y))
                     (equal (diff x y) (- (fix x) (fix y)))))
       :rule-classes :linear-alias)

To mimic Nqthm behavior, we need a :rewrite (REWRITE^) rule to dispatch the cases generated by the case split caused by linearizing diff-expressions. This is not, strictly speaking, part of linear aliasing.

     (defthm diff-0 (implies (lessp x y) (equal (diff x y) 0)))

Now we disable the nqthm-level functions. Henceforth, we do not expect to see ACL2-level functions in proofs about these concepts.

     (in-theory (disable fix lessp plus diff))

Note that we can now prove such facts as

     (thm (implies (and (lessp a b) (lessp b c)) (lessp a c)))
     (thm (implies (lessp a (diff b c)) (lessp a b)))

and that the proofs appeal to linear arithmetic!

We can add new aliases (although they get new names). Note that we have to (a) define the function, (b) prove the :linear-alias rule — probably enabling nqthm-level functions to do it, and (c) disable the new function so it survives rewriting and is around for linearization to de-alias.

     (defun add1 (x) (+ (fix x) 1))                       ; (a)
     (defthm add1-linear                                  ; (b) - see below
       (and (equal (add1 x) (+ (fix x) 1))
            (equal (fix (add1 x)) (add1 x)))
       :rule-classes :linear-alias
       :hints (("Goal" :in-theory (enable fix))))
     (in-theory (disable add1))                           ; (c)
     (thm (lessp x (add1 x)))

Observe that in (b) we prove two rules about add1: the one that relates it to + (+^) and the one that removes the fix (FIX^)es inserted by the first rule.

Next we illustrate the use of :linear (LINEAR^) lemmas in the context of linear aliasing. Consider the function:

     (defun strpos (pat str)
     ; Find the position of pat in str.
       (cond ((atom str) 0)
             ((equal pat (car str)) 0)
             (t (add1 (strpos pat (cdr str))))))
     (defun strlen (str)
       (cond ((atom str) 0)
             (t (add1 (strlen (cdr str))))))

We can prove and store the following :linear (LINEAR^) lemma about strpos.

     (defthm strpos-length
       (not (lessp (strlen str) (strpos pat str)))
       :rule-classes :linear)

This event is interesting for two reasons. The proof illustrates linear aliasing. But the fact that this event is stored as a :linear (LINEAR^) lemma — even though the conclusion is not about < (<^) — also illustrates linear aliasing. In fact, this lemma is stored under (strpos pat str) with

:fixer fix (FIX^).

We can illustrate the storage and retrieval of the lemma directly by proving:

     (thm (not (< (fix (strlen str)) (fix (strpos pat str)))))

But more commonly we will be interested in proofs that reach out for facts about strpos (implicitly fix (FIX^)ing them for us) as in:

     (thm (implies (lessp (strlen str) mx)
                   (lessp (strpos pat str) mx))).

This ends the extended example of linear aliasing lemmas.

15.12 META

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

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. Meta rules extend the ACL2 simplifier with hand-written code to transform certain terms to equivalent ones. To add a meta rule, the :corollary (COROL-LARY^) formula must establish that the hand-written “metafunction” preserves the meaning of the transformed term.

Example :corollary (COROLLARY^) formulas from which :meta rules might be built are:

     Examples:
     (equal (ev x a)                 ; Modify the rewriter to use fn to
            (ev (fn x) a))           ; transform terms.  The :trigger-fns
                                     ; of the :meta rule-class specify

                                     ; the top-most function symbols of
                                     ; those x that are candidates for
                                     ; this transformation.
     (implies (and (pseudo-termp x)  ; As above, but this illustrates
                   (alistp a))       ; that without loss of generality we
              (equal (ev x a)        ; may restrict x to be shaped like a
                     (ev (fn x) a))) ; term and a to be an alist.
     (implies (and (pseudo-termp x)  ; As above (with or without the
                   (alistp a)        ; hypotheses on x and a) with the
                   (ev (hyp-fn x) a)); additional restriction that the
              (equal (ev x a)        ; meaning of (hyp-fn x) is true in
                     (ev (fn x) a))) ; the current context.  That is, the
                                     ; applicability of the transforma-
                                     ; tion may be dependent upon some
                                     ; computed hypotheses.

A non-nil list of function symbols must be supplied as the value of the :trigger-fns field in a :meta rule class object.

     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
              (equiv (ev x a)
                     (ev (fn x) a)))

where equiv is a known equivalence (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. Both fn and hyp-fn should take a single argument. If fn and/or hyp-fn are guard (GUARD^)ed, their guard (GUARD^)s should be (implied by) pseudo-termp (PSEUDO-TERMP^). See Section 8.74 [PSEUDO-TERMP], page 358. We say the theorem above is a “metatheorem” or “metalemma” and fn is a “metafunction”, and hyp-fn is a “hypothesis metafunction”.

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 (PSEUDO-TERMP^) hypothesis is omitted, x may be any object. Even with the pseudo-termp (PSEUDO-TERMP^) hypothesis, x may merely “look like a term” but use nonfunction 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 (PSEUDO-TERMP^) and alistp (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 Section 6.37 [TERM-TABLE], page 208 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 (EQUAL^) and 'binary-append (BINARY-APPEND^) occur as function symbols, then ev is generally specified to handle equal (EQUAL^) and binary-append (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 (DEFEVALUATOR^), though this is not strictly necessary. See Section 6.8 [DEFEVALUATOR], page 169 for details.

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 constraint (CONSTRAINT^)s on ev. Hence, the metatheorem holds for ev* in place of ev, by functional instantiation. We can then carry out the proof of the equivalence (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 (PSEUDO-TERMP^) and alistp (ALISTP^) hypotheses by appealing to the facts that term1 is a term and a is an alist by construction.

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 (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 (PSEUDO-TERMP^) hypothesis. (Pseudo-termp x) checks that x has the shape of a term. Roughly speaking, it insures that x is a symbol, a quoted constant, or a true list consisting of a lambda expression or symbol followed by some pseudoterms. Among the properties of terms not checked by pseudo-termp (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 Section 8.74 [PSEUDO-TERMP], page 358.

There are two possible roles for pseudo-termp (PSEUDO-TERMP^) in the development of a metatheorem: it may be used as the guard (GUARD^) of the metafunction and/or hypothesis metafunction and it may be used as a hypothesis of the metatheorem. Generally speaking, the pseudo-termp (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 (PSEUDO-TERMP^) guard (GUARD^)? A pseudo-termp (PSEUDO-TERMP^) guard (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 (PSEUDO-TERMP^) guard (GUARD^) and exploit the guard (GUARD^) when possible in coding the body of the function (see Section 8.41.4 [GUARDS-AND-EVALUATION], page 310, especially the section on efficiency issues), (b) verify the guard (GUARD^)s of the metafunction (see Section 6.39 [VERIFY-GUARDS], page 210), and (c) compile the metafunction (see Section 9.5 [COMP], page 415). When these three steps have been taken the simplifier can evaluate (fn 'term1) by running the compiled “primary code” (see Section 8.41.4 [GUARDS-AND-EVALUATION], page 310) for fn directly in Common Lisp.

Before discussing efficiency issues further, let us review the for a moment the general case in which we wish to evaluate (fn `obj) for some :logic (LOGIC^) function. We must first ask whether the guard (GUARD^)s of fn have been verified. If not, we must evaluate fn by executing its logic definition. This effectively checks the guard (GUARD^)s of every subroutine and so can be slow. If, on the other hand, the guard (GUARD^)s of fn have been verified, then we can run the primary code for fn, provided 'obj satisfies the guard (GUARD^) of fn. So we must next evaluate the guard (GUARD^) of fn on 'obj. If the guard (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 (GUARD^) is (implied by) pseudo-termp (PSEUDO-TERMP^) and that it has been verified. Furthermore, we know without checking that the guard (GUARD^) is met (because term1 is a term and hence 'term1 is a pseudo-termp (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. Guard verification is also recommended.

15.13 REFINEMENT

REFINEMENT record that one equivalence relation refines another

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. An example :corollary (COROLLARY^) formula from which a :refinement rule might be built is:

     Example:
     (implies (bag-equal x y) (set-equal y x)).

Also see Section 6.12 [DEFREFINEMENT], page 174.

     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 (REWRITE^) rules may be used while trying to maintain equiv2. See Section 15.6 [EQUIVALENCE], page 738 for a general discussion of the issues.

The macro form (defrefinement equiv1 equiv2) is an abbreviation for a defthm (DEFTHM^) of rule-class :refinement that establishes that equiv1 is a refinement of equiv2. See Section 6.12 [DEFREFINEMENT], page 174.

Suppose we have the :rewrite (REWRITE^) rule

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

which states that append (APPEND^) is commutative modulo bag-equality. Suppose further we have established that bag-equality refines set-equality. Then when we are simplifying append (AP-PEND^) expressions while maintaining set-equality we use append (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 (REWRITE^) rules can be disabled.

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

15.14 REWRITE

REWRITE make some :rewrite rules (possibly conditional ones)

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. Example :corollary (COROLLARY^) formulas from which :rewrite rules might be built are:

     Example:
     (equal (+ x y) (+ y x))            replace (+ a b) by (+ b a) provided
                                        certain heuristics approve the
                                        permutation.
     (implies (true-listp x)            replace (append a nil) by a, if
              (equal (append x nil) x)) (true-listp a) rewrites to t
     (implies                           replace (member a (append b c)) by
         (and (eqlablep e)              (member a (append c b)) in contexts
              (true-listp x)            in which propositional equivalence
              (true-listp y))           is sufficient, provided (eqlablep a)
         (iff (member e (append x y))   (true-listp b) and (true-listp c)
              (member e (append y x)))) rewrite to t and the permutative
                                        heuristics approve
     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 (COROLLARY^) formula. To create the rules, we first translate the formula (expanding all macros; also see Section 9.16 [TRANS], page 427). Next, we eliminate all lambdas; one may think of this step as simply substituting away every let (LET^), let* (LET*^), and mv-let (MV-LET^) in the formula. We then flatten the and (AND^) and implies (IMPLIES^) structure of the formula, transforming it into 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 (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 (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 (EQUIVALENCE^) relation. See Section 15.6 [EQUIVA-LENCE], page 738 for a general discussion of the introduction of new equivalence (EQUIVA-LENCE^) relations.

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 (LET^)-expression, a lambda application, or an if (IF^)-expression.

A :rewrite rule is used when any instance of the lhs occurs in a context in which the equivalence (EQUIVALENCE^) relation is operative. 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 Section 8.64 [LOOP-STOPPER], page 347), the target is replaced by the instantiated rhs, which is then recursively rewritten.

At the moment, the best description of how ACL2 :rewrite rules are used may be found in the discussion of “Replacement Rules” pp 234 of A Computational Logic Handbook.

15.15 TYPE-PRESCRIPTION

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

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. Some example :corollary (COROLLARY^) formulas from which :type-prescription rules might be built are:

     Examples:
     (implies                           (nth n lst) is of type characterp
      (and (character-listp lst)        provided the two hypotheses can
           (< n (length lst)))          be established by type reasoning
      (characterp (nth n lst))).
     (implies                           (demodulize a lst 'value ans) is
      (and (atom a)                     either a nonnegative integer or
           (true-listp lst)             of the same type as ans, provided
           (member-equal a lst))        the hyps can be established by type
      (or (and                          reasoning
            (integerp
             (demodulize a lst 'value ans))
            (>= (demodulize a lst 'value ans) 0))
          (equal (demodulize a lst 'value ans) ans))).

To specify the term whose type (see Section 8.90 [TYPE-SET], page 383) is described by the rule, provide that term as the value of the :typed-term field of the rule class object.

     General Form:
     (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 Section 15.2 [COMPOUND-RECOGNIZER], page 730.

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! Of course, if some hypothesis is to be forced, it is so treated; see Section 8.37 [FORCE], page 297. 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.

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 (length 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 (length 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 (mystatep s) has type t in this context. Thus, either my-statep should be disabled (see Section 16.2 [DISABLE], page 779) 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 (DEFUN^). (The trivial rule, saying fn has unknown type, is not stored, but defun (DEFUN^) still allocates the rune and the corollary of this rune is known to be t.)

15.16 TYPE-SET-INVERTER

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

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas.

     Example Rule Class:
     (:type-set-inverter
       :corollary (equal (and (counting-number x) (not (equal x 0)))
                         (and (integerp x) (< x 0)))
       :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 (TYPE-SET^) (see Section 8.90 [TYPE-SET], page 383) and old-expr is the term containing x as a free variable that ACL2 currently uses to recognize type-set (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 (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 Section 8.90 [TYPE-SET], page 383). 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 (TYPE-SET^) and an error is caused because lhs has the incorrect form, you should manually specify both :type-set (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 (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*.

15.17 WELL-FOUNDED-RELATION

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

See Chapter 15 [RULE-CLASSES], page 723 for a general discussion of rule classes and how they are used to build rules from formulas. An example :corollary (COROLLARY^) formula from which a :well-founded-relation rule might be built is as follows. (Of course, the functions pairp, lex2p, and ordinate would have to be defined first.)

     Example:
     (and (implies (pairp x) (e0-ordinalp (ordinate x)))
          (implies (and (pairp x)
                        (pairp y)
                        (lex2p x y))
                   (e0-ord-< (ordinate x) (ordinate y))))

The above example 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) (E0-ORDINALP (fn x)))      ; Property 1
          (IMPLIES (AND (mp x)                       ; Property 2
                        (mp y)
                        (rel x y))
                   (E0-ORD-< (fn x) (fn y)))),

or

     (AND (E0-ORDINALP (fn x))                       ; Property 1
          (IMPLIES (rel x y)                         ; Property 2
                   (E0-ORD-< (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 insures 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.

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 Section 8.26 [E0-ORDINALP], page 283.) 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 e0-ord-< (E0-ORD-<^). (See Section 8.25 [E0-ORD-<], page 282.) 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 insured 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 (DEFUN^)? There are two ways. First, an xargs (XARGS^) keyword to the defun (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 (ACL2-DEFAULTS-TABLE^) by executing the event

     (set-default-well-founded-relation rel).

When a defun (DEFUN^) event does not explicitly specify the relation in its xargs (XARGS^) the default relation is used. When ACL2 is initialized, the default relation is e0-ord-< (E0-ORD-<^). Finally, though it is probably obvious, we now show that defun-goal-1 and defun-goal-2 are sufficient to insure 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 e0-ord-<
                      :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

     (e0-ordinalp (fn (m x)))                        ; *1

and

     (implies (test x)                               ; *2
              (e0-ord-< (fn (m (step x))) (fn (m x)))).

But *1 can be proved by instantiating property-1 to get

     (implies (mp (m x)) (e0-ordinalp (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)))
              (e0-ord-< (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))
              (e0-ord-< (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.

774 ACL2 Version 1.9

16 THEORIES

THEORIES sets of rune (RUNE^)s to enable/disable in concert

     Example: '((:definition app)
                (:executable-counterpart app)
                rv
                (rv)
                assoc-of-app)

See:

* CURRENT-THEORY:: currently enable (ENABLE^)d rules as of logical name

* DISABLE:: deletes names from current theory

* ENABLE:: adds names to current theory

* EXECUTABLE-COUNTERPART-THEORY:: executable counterpart rules as of logical name * FUNCTION-THEORY:: function symbol rules as of logical name

* GROUND-ZERO:: enable (ENABLE^)d rules in the startup (STARTUP^) theory

* INCOMPATIBLE:: declaring that two rules should not both be enable (ENABLE^)d

* INTERSECTION-THEORIES:: intersect two theories (THEORIES^)

* RULE-NAMES:: How rules are named.

* RUNE:: a rule name

* SET-DIFFERENCE-THEORIES:: difference of two theories (THEORIES^)

* THEORY:: retrieve named theory

* THEORY-FUNCTIONS:: functions for obtaining or producing theories (THEORIES^)

* UNION-THEORIES:: union two theories (THEORIES^)

* UNIVERSAL-THEORY:: all rules as of logical name

Related topics other than immediate subtopics:

* DEFTHEORY:: define a theory (to enable (ENABLE^) or disable (DISABLE^) a set of rules)

A theory is a list of “runic designators” as described below. Each runic designator denotes a set of “runes” (see Section 16.10 [RUNE], page 784) and by unioning together the runes denoted by each member of a theory we define the set of runes corresponding to a theory. Theories are used to control which rules are “enable (ENABLE^)d,” i.e., available for automatic application by the theorem prover. There is always a “current” theory. A rule is enable (ENABLE^)d precisely if its rune (RUNE^) is an element of the set of rune (RUNE^)s corresponding to the current theory. At the top-level, the current theory is the theory selected by the most recent in-theory (IN-THEORY^) event, extended with the rule names introduced since then. Inside the theorem prover, the :in-theory (IN-THEORY^) hint (see Section 8.43 [HINTS], page 319) can be used to select a particular theory as current during the proof attempt for a particular goal.

Theories are generally constructed by “theory expressions.” Formally, a theory expression is any term, containing at most the single free variable world (WORLD^), that when evaluated with world (WORLD^) bound to the current ACL2 world (see Section 8.100 [WORLD], page 399) produces a theory. ACL2 provides various functions for the convenient construction and manipulation of theories. These are called “theory functions” (see Section 16.13 [THEORY-FUNCTIONS], page 787). For example, the theory function union-theories (UNION-THEORIES^) takes two theories and produces their union. The theory function universal-theory (UNIVERSAL-THEORY^) returns the theory containing all known rule names as of the introduction of a given logical name. But a theory expression can contain constants, e.g.,

     '(assoc (assoc) (:rewrite car-cons) car-cdr-elim)

and user-defined functions. The only important criterion is that a theory expression mention no variable freely except world (WORLD^) and evaluate to a theory.

More often than not, theory expressions typed by the user do not mention the variable world (WORLD^). This is because user-typed theory expressions are generally composed of applications of ACL2’s theory functions. These “functions” are actually macros that expand into terms in which world (WORLD^) is used freely and appropriately. Thus, the technical definition of “theory expression” should not mislead you into thinking that interestng theory expressions must mention world (WORLD^); they probably do and you just didn’t know it!

One aspect of this arrangement is that theory expressions cannot generally be evaluated at the toplevel of ACL2, because world (WORLD^) is not bound. To see the value of a theory expression, expr, at the top-level, type

     ACL2 !>(LET ((WORLD (W STATE))) expr).

However, because the built-in theories are quite long, you may be sorry you printed the value of a theory expression!

A theory is a true list of runic designators and to each theory there corresponds a set of rune (RUNE^)s, obtained by unioning together the sets of rune (RUNE^)s denoted by each runic designator. For example, the theory constant

        '(assoc (assoc) (:rewrite car-cons) car-cdr-elim)

corresponds to the set of rune (RUNE^)s

   {(:definition assoc)
    (:executable-counterpart assoc)
    (:rewrite car-cons)
    (:rewrite car-cdr-elim)
    (:elim car-cdr-elim)} .

Observe that the theory contains four elements but its runic correspondent contains five. That is because some designators denote sets of several rune (RUNE^)s. If the above theory were selected as current then the five rules named in its runic counterpart would be enable (ENABLE^)d and all other rules would be disable (DISABLE^)d.

We now precisely define the runic designators and the set of rune (RUNE^)s denoted by each.

o A rune is a runic designator and denotes the singleton set containing that rune.

o If symb is a function symbol introduced with a defun (DEFUN^) (or defuns (DE-FUNS^)) event, then symb is a runic designator and denotes the singleton set containing

the rune (:definition symb).

o If symb is a function symbol introduced with a defun (DEFUN^) (or defuns (DE-FUNS^)) event, then (symb) is a runic designator and denotes the singleton set con-

taining the rune (:executable-counterpart symb).

o If symb is the name of a defthm (DEFTHM^) (or defaxiom (DEFAXIOM^)) event that introduced at least one rule, then symb is a runic designator and denotes the set of the names of all rules introduced by the named event.

o If str is the string naming some defpkg (DEFPKG^) event and symb is the symbol returned by (intern str "ACL2"), then symb is a runic designator and denotes the singleton set containing (:rewrite symb), which is the name of the rule stating the conditions under which the symbol-package-name (SYMBOL-PACKAGE-NAME^) of

(intern x str) is str.

o If symb is the name of a deftheory (DEFTHEORY^) event, then symb is a runic designator and denotes the runic theory corresponding to symb.

These conventions attempt to implement the Nqthm-1992 treatment of theories. For example, including a function name, e.g., assoc (ASSOC^), in the current theory enable (ENABLE^)s that function but does not enable (ENABLE^) the executable counterpart. Similarly, including (assoc) enable (ENABLE^)s the executable counterpart (Nqthm’s *1*assoc) but not the symbolic definition. And including the name of a proved lemma enable (ENABLE^)s all of the rules added by the event. These conventions are entirely consistent with Nqthm usage. Of course, in ACL2 one can include explicitly the rune (RUNE^)s naming the rules in question and so can avoid entirely the use of non-runic elements in theories.

Because a rune (RUNE^) is a runic designator denoting the set containing that rune (RUNE^), a list of rune (RUNE^)s is a theory and denotes itself. We call such theories “runic theories.” To every theory there corresponds a runic theory obtained by unioning together the sets denoted by each designator in the theory. When a theory is selected as “current” it is actually its runic correspondent that is effectively used. That is, a rune (RUNE^) is enable (ENABLE^)d iff it is a member of the runic correspondent of the current theory. The value of a theory defined with deftheory (DEFTHEORY^) is the runic correspondent of the theory computed by the defining theory expression. The theory manipulation functions, e.g., union-theories (UNION-THEORIES^), actually convert their theory arguments to their runic correspondents before performing the required set operation. The manipulation functions always return runic theories. Thus, it is sometimes convenient to think of (non-runic) theories as merely abbreviations for their runic correspondents, abbreviations which are “expanded” at the first opportunity by theory manipulation functions and the “theory consumer” functions such as in-theory (IN-THEORY^) and deftheory (DEFTHE-ORY^).

16.1 CURRENT-THEORY

CURRENT-THEORY currently enable (ENABLE^)d rules as of logical name

     Examples:
     (current-theory :here)
     (current-theory 'lemma3)

See Section 8.63 [LOGICAL-NAME], page 346.

     General Form:
     (current-theory logical-name)

Returns the current theory as it existed immediately after the introduction of logical-name (LOGICAL-NAME^) provided it is evaluated in an environment in which the variable symbol WORLD is bound to the current ACL2 logical world, (w state). Thus,

     ACL2 !>(current-theory :here)

will cause an (unbound variable) error while

     ACL2 !>(let ((world (w state))) (current-theory :here))

will return the current theory in world.

See Chapter 16 [THEORIES], page 775 and see Section 8.63 [LOGICAL-NAME], page 346 for a discussion of theories in general and why the commonly used “theory functions” such as currenttheory are really macros that expand into terms involving the variable world.

The theory returned by current-theory is in fact the theory selected by the in-theory (IN-THEORY^) event most recently preceding logical name, extended by the rules introduced up through logical-name (LOGICAL-NAME^).

You may experience a fencepost problem in deciding which logical name to use. Deflabel (DE-FLABEL^) can always be used to mark unambiguously for future reference a particular point in the development of your theory. The order of events (EVENTS^) in the vicinity of an encapsulate (ENCAPSULATE^) is confusing. See Section 6.18 [ENCAPSULATE], page 185.

This “function” is actually a macro that expands to a term mentioning the single free variable world (WORLD^). When theory expressions are evaluated by in-theory (IN-THEORY^) or the :in-theory (IN-THEORY^) hint, world (WORLD^) is bound to the current ACL2 world (WORLD^).

16.2 DISABLE

DISABLE deletes names from current theory

     Example:
     (disable fact (fact) associativity-of-app)
     General Form:
     (disable name1 name2 ... namek)

where each namei is a runic designator; see Chapter 16 [THEORIES], page 775. The result is the theory that contains all the names in the current theory except those listed. Note that this is merely a function that returns a theory. The result is generally a very long list of rune (RUNE^)s and you will probably regret printing it.

The standard way to “disable” a fixed set of names, is:

     (in-theory (disable name1 name2 ... namek)) ; globally
     :in-theory (disable name1 name2 ... namek)  ; locally

Note that all the names are implicitly quoted. If you wish to disable a computed list of names,

lst, use the theory expression (set-difference-theories (current-theory :here) lst).

16.3 ENABLE

ENABLE adds names to current theory

     Example:
     (enable fact (fact) associativity-of-app)
     General Form:
     (enable name1 name2 ... namek)

where each namei is a runic designator; see Chapter 16 [THEORIES], page 775. The result is the theory that contains all the names in the current theory plus those listed. Note that this is merely a function that returns a theory. The result is generally a very long list of rune (RUNE^)s and you will probably regret printing it.

The standard way to “enable” a fixed set of names, is

     (in-theory (enable name1 name2 ... namek)) ; globally
     :in-theory (enable name1 name2 ... namek)  ; locally

Note that all the names are implicitly quoted. If you wish to enable a computed list of names, lst,

use the theory expression (union-theories (current-theory :here) lst).

16.4 EXECUTABLE-COUNTERPART-THEORY

EXECUTABLE-COUNTERPART-THEORY executable counterpart rules as of logical name

     Examples:
     (executable-counterpart-theory :here)
     (executable-counterpart-theory 'lemma3)

See Section 8.63 [LOGICAL-NAME], page 346.

     General Form:
     (executable-counterpart-theory logical-name)

Returns the theory containing all the :executable-counterpart (EXECUTABLE-COUNTERPART^) rune (RUNE^)s, whether enable (ENABLE^)d or not, that existed immediately after logicalname (LOGICAL-NAME^) was introduced. See the documentation for theories (THEORIES^), logical-name (LOGICAL-NAME^), executable-counterpart (EXECUTABLE-COUNTERPART^) and function-theory (FUNCTION-THEORY^).

You may experience a fencepost problem in deciding which logical name to use. Deflabel (DE-FLABEL^) can always be used to mark unambiguously for future reference a particular point in the development of your theory. The order of events (EVENTS^) in the vicinity of an encapsulate (ENCAPSULATE^) is confusing. See Section 6.18 [ENCAPSULATE], page 185.

This “function” is actually a macro that expands to a term mentioning the single free variable world (WORLD^). When theory expressions are evaluated by in-theory (IN-THEORY^) or the :in-theory (IN-THEORY^) hint, world (WORLD^) is bound to the current ACL2 world (WORLD^).

16.5 FUNCTION-THEORY

FUNCTION-THEORY function symbol rules as of logical name

     Examples:
     (function-theory :here)
     (function-theory 'lemma3)

See Section 8.63 [LOGICAL-NAME], page 346.

     General Form:
     (function-theory logical-name)

Returns the theory containing all the :definition (DEFINITION^) rune (RUNE^)s, whether enable (ENABLE^)d or not, that existed immediately after logical-name (LOGICAL-NAME^) was introduced. See the documentation for theories (THEORIES^), logical-name (LOGICAL-NAME^) and executable-counterpart-theory (EXECUTABLE-COUNTERPART-THEORY^).

You may experience a fencepost problem in deciding which logical name to use. Deflabel (DE-FLABEL^) can always be used to mark unambiguously for future reference a particular point in the development of your theory. The order of events (EVENTS^) in the vicinity of an encapsulate (ENCAPSULATE^) is confusing. See Section 6.18 [ENCAPSULATE], page 185.

This “function” is actually a macro that expands to a term mentioning the single free variable world (WORLD^). When theory expressions are evaluated by in-theory (IN-THEORY^) or the :in-theory (IN-THEORY^) hint, world (WORLD^) is bound to the current ACL2 world (WORLD^).

16.6 GROUND-ZERO

GROUND-ZERO enable (ENABLE^)d rules in the startup (STARTUP^) theory

ACL2 concludes its initialization (boot-strapping) procedure by defining the theory groundzero; see Chapter 16 [THEORIES], page 775. In fact, this theory is just the theory defined by (current-theory :here) at the conclusion of initialization; see Section 16.1 [CURRENT-THEORY], page 778.

Note that by executing the event

     (in-theory (current-theory 'ground-zero))

you can restore the current theory to its value at the time you started up ACL2.

16.7 INCOMPATIBLE

INCOMPATIBLE declaring that two rules should not both be enable (ENABLE^)d

     Example:
     (theory-invariant (incompatible (:rewrite left-to-right)
                                     (:rewrite right-to-left)))
     General Form:
     (incompatible rune1 rune2)

where rune1 and rune2 are two specific rune (RUNE^)s. The arguments are not evaluated. Invariant is just a macro that expands into a term that checks that theory (THEORY^) does not contain both rune (RUNE^)s. See Section 6.38 [THEORY-INVARIANT], page 208.

16.8 INTERSECTION-THEORIES

INTERSECTION-THEORIES intersect two theories (THEORIES^)

     Example:
     (intersection-theories (current-theory :here)
                            (theory 'arith-patch))
     General Form:
     (intersection-theories th1 th2)

where th1 and th2 are theories (see Chapter 16 [THEORIES], page 775). To each of the arguments there corresponds a runic theory. This function returns the intersection of those two runic theories (THEORIES^), represented as a list and ordered chronologically.

This “function” is actually a macro that expands to a term mentioning the single free variable world (WORLD^). When theory expressions are evaluated by in-theory (IN-THEORY^) or the :in-theory (IN-THEORY^) hint, world (WORLD^) is bound to the current ACL2 world (WORLD^).

16.9 RULE-NAMES

RULE-NAMES How rules are named.

     Examples:
     (:rewrite assoc-of-app)
     (:linear delta-aref . 2)
     (:definition length)
     (:executable-counterpart length)

See Section 16.10 [RUNE], page 784.

16.10 RUNE

RUNE a rule name

     Examples:
     (:rewrite assoc-of-app)
     (:linear delta-aref . 2)
     (:definition length)
     (:executable-counterpart length)

Background: The theorem prover is driven from a data base of rules. The most common rules are :rewrite (REWRITE^) rules, which cause the simplifier to replace one term with another. Events (EVENTS^) introduce rules into the data base. For example, a defun (DEFUN^) event may introduce as many as four rules: one for symbolically replacing a function call by its instantiated body, one for evaluating the function on constants, and two for determining the type of a call of the function (one of which is deduced before guard (GUARD^) verification and the other of which is deduced after guard (GUARD^) verification). Defthm (DEFTHM^) may introduce several rules, one for each of the rule classes specified.

Every rule in the system has a name. Each name is a structured object called a “rune,” which is short for “rule name”. Runes are always of the form (:token symbol . x), where :token is some keyword symbol indicating what kind of rule is named, symbol is the event name that created the rule (and is called the “base symbol” of the rune), and x is either nil or a natural number that makes the rule name unique.

For example, an event of the form

     (defthm name thm
       :rule-classes ((:REWRITE :COROLLARY term1)
                      (:REWRITE :COROLLARY term2)
                      (:ELIM    :COROLLARY term3)))

creates three rules, each with a unique rune. The runes are

     (:REWRITE name . 1), (:REWRITE name . 2), and (:ELIM name).

The function corollary (COROLLARY^) will return the corollary (COROLLARY^) term associated with a given rune in a given world (WORLD^). Example:

     (corollary '(:TYPE-PRESCRIPTION DIGIT-TO-CHAR) (w state))

However, the preferred way to see the corollary term associated with a rune or a name is to use :pf; see Section 7.9 [PF], page 223.

The defun (DEFUN^) event creates as many as four rules. (:definition fn) is the rune given to the equality axiom defining the function, fn. (:executable-counterpart fn) is the rune given to the rule for computing fn on known arguments. A type prescription rule may be created under the name (:type-prescription fn), and an induction (INDUCTION^) rule may be created under

the name (:induction fn).

Runes may be individually enable (ENABLE^)d and disable (DISABLE^)d, according to whether they are included in the current theory. See Chapter 16 [THEORIES], page 775. Thus, it is permitted to disable (DISABLE^) (:elim name), say, while enabling the other rules derived from name.

Similarly, (:definition fn) may be disable (DISABLE^)d while (:executable-counterpart

fn) and the type prescriptions for fn are enable (ENABLE^)d.

Associated with most runes is the formula justifying the rule named. This is called the “corollary (COROLLARY^) formula” of the rune and may be obtained via the function corollary (COROL-LARY^), which takes as its argument a rune and a property list world (WORLD^). Also see Section 7.9 [PF], page 223. The corollary (COROLLARY^) formula for (:rewrite name . 1) after the defthm (DEFTHM^) event above is term1. The corollary formulas for (:definition fn) and (:executable-counterpart fn) are always identical: the defining axiom. Some runes, e.g., (:definition car), do not have corollary formulas. Corollary (COROLLARY^) returns nil on such runes. In any case, the corollary formula of a rune, when it is non-nil, is a theorem and may be used in the :use and :by hints (HINTS^).

Note: The system has many built in rules that, for regularity, ought to have names but don’t because they can never be disable (DISABLE^)d. One such rule is that implemented by the linear arithmetic package. Because many of our subroutines are required by their calling conventions to return the justifying rune, we have invented the notion of “fake runes.” Fake runes always have the base symbol nil, use a keyword token that includes the phrase “fake-rune”, and are always enable (ENABLE^)d. For example, (:fake-rune-for-linear nil) is a fake rune. Occasionally the system will print a fake rune where a rune is expected. For example, when the linear arithmetic fake rune is reported among the rules used in a proof, it is an indication that the linear arithmetic package was used. However, fake runes are not allowed in theories (THEORIES^), they cannot be enable (ENABLE^)d or disable (DISABLE^)d, and they do not have associated corollary (COROLLARY^) formulas. In short, despite the fact that the user may sometimes see fake runes printed, they should never be typed.

16.11 SET-DIFFERENCE-THEORIES

SET-DIFFERENCE-THEORIES difference of two theories (THEORIES^)

     Example:
     (set-difference-theories (current-theory :here)
                              '(fact (fact)))
     General Form:
     (set-difference-theories th1 th2)

where th1 and th2 are theories (THEORIES^) (see Chapter 16 [THEORIES], page 775). To each of the arguments there corresponds a runic theory. This function returns the set-difference of those two runic theories (THEORIES^), represented as a list and ordered chronologically. That is, a rune (RUNE^) is in the result iff it is in the first runic theory but not in the second.

The standard way to “disable” a theory, lst, is: (in-theory (set-difference-theories
(current-theory :here) lst)).

This “function” is actually a macro that expands to a term mentioning the single free variable world (WORLD^). When theory expressions are evaluated by in-theory (IN-THEORY^) or the :in-theory (IN-THEORY^) hint, world (WORLD^) is bound to the current ACL2 world (WORLD^).

16.12 THEORY

THEORY retrieve named theory

     Example:
     (theory 'my-theory)
     General Form:
     (theory name)

where name is the name of a previously executed deftheory (DEFTHEORY^) event. Returns the named theory. See Chapter 16 [THEORIES], page 775.

This “function” is actually a macro that expands to a term mentioning the single free variable world (WORLD^). When theory expressions are evaluated by in-theory (IN-THEORY^) or the :in-theory (IN-THEORY^) hint, world (WORLD^) is bound to the current ACL2 world (WORLD^).

16.13 THEORY-FUNCTIONS

THEORY-FUNCTIONS functions for obtaining or producing theories (THEORIES^)

     Example Calls of Theory Functions:
     (universal-theory :here)
     (union-theories th1 th2)
     (set-difference-theories th1 th2)

The theory functions are documented individually:

Related topics other than immediate subtopics:

* CURRENT-THEORY:: currently enable (ENABLE^)d rules as of logical name

* DISABLE:: deletes names from current theory

* ENABLE:: adds names to current theory

* EXECUTABLE-COUNTERPART-THEORY:: executable counterpart rules as of logical name * FUNCTION-THEORY:: function symbol rules as of logical name

* INTERSECTION-THEORIES:: intersect two theories (THEORIES^)

* SET-DIFFERENCE-THEORIES:: difference of two theories (THEORIES^)

* THEORY:: retrieve named theory

* UNION-THEORIES:: union two theories (THEORIES^)

* UNIVERSAL-THEORY:: all rules as of logical name

The functions (actually, macros) mentioned above are convenient ways to produce theories (THEO-RIES^). (See Chapter 16 [THEORIES], page 775.) Some, like universal-theory (UNIVERSAL-THEORY^), take a logical name (see Section 8.63 [LOGICAL-NAME], page 346) as an argument and return the relevant theory as of the time that name was introduced. Others, like uniontheories (UNION-THEORIES^), take two theories (THEORIES^) and produce a new one. See Section 8.78 [REDUNDANT-EVENTS], page 361 for a caution about the use of logical names in theory expressions.

Theory expressions are generally composed of applications of theory functions. Formally, theory expressions are expressions that involve, at most, the free variable world (WORLD^) and that when evaluated with world (WORLD^) bound to the current ACL2 world (see Section 8.100 [WORLD], page 399) return theories (THEORIES^). The “theory functions” are actually macros that expand into forms that involve the free variable world (WORLD^). Thus, for example (universal-

theory :here) actually expands to (universal-theory-fn :here world) and when that form

is evaluated with world (WORLD^) bound to the current ACL2 world (WORLD^), universaltheory-fn scans the ACL2 property lists and computes the current universal theory. Because the theory functions all implicitly use world (WORLD^), the variable does not generally appear in anything the user types.

16.14 UNION-THEORIES

UNION-THEORIES union two theories (THEORIES^)

     Example:
     (union-theories (current-theory 'lemma3)
                     (theory 'arith-patch))
     General Form:
     (union-theories th1 th2)

where th1 and th2 are theories (see Chapter 16 [THEORIES], page 775). To each of the arguments there corresponds a runic theory. This function returns the union of those two runic theories (THEORIES^), represented as a list and ordered chronologically.

This “function” is actually a macro that expands to a term mentioning the single free variable world (WORLD^). When theory expressions are evaluated by in-theory (IN-THEORY^) or the :in-theory (IN-THEORY^) hint, world (WORLD^) is bound to the current ACL2 world (WORLD^).

16.15 UNIVERSAL-THEORY

UNIVERSAL-THEORY all rules as of logical name

     Examples:
     (universal-theory :here)
     (universal-theory 'lemma3)

See Section 8.63 [LOGICAL-NAME], page 346.

     General Form:
     (universal-theory logical-name)

Returns the theory consisting of all the rune (RUNE^)s that existed immediately after logicalname (LOGICAL-NAME^) was introduced. See Chapter 16 [THEORIES], page 775 and see Section 8.63 [LOGICAL-NAME], page 346. The theory includes logical-name (LOGICAL-NAME^) itself (if there is a rule by that name). (Note that since some events (EVENTS^) do not introduce rules (e.g., defmacro (DEFMACRO^), defconst (DEFCONST^) or defthm (DEFTHM^) with :rule-classes (RULE-CLASSES^) nil), the universal-theory does not necessarily include a rune (RUNE^) for every event name.) The universal-theory is very long and you will probably regret printing it.

You may experience a fencepost problem in deciding which logical-name (LOGICAL-NAME^) to use. Deflabel (DEFLABEL^) can always be used to mark unambiguously for future reference a particular point in the development of your theory. This is convenient because deflabel (DEFLA-BEL^) does not introduce any rules and hence it doesn’t matter if you count it as being in the interval or not. The order of events (EVENTS^) in the vicinity of an encapsulate (ENCAPSU-LATE^) is confusing. See Section 6.18 [ENCAPSULATE], page 185.

This “function” is actually a macro that expands to a term mentioning the single free variable world (WORLD^). When theory expressions are evaluated by in-theory (IN-THEORY^) or the :in-theory (IN-THEORY^) hint, world (WORLD^) is bound to the current ACL2 world (WORLD^).

790 ACL2 Version 1.9

Index 791

Index

*

* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 *STANDARD-CI* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 *STANDARD-CO* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436 *STANDARD-OI* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436 *TERMINAL-MARKUP-TABLE* . . . . . . . . . . . . . . . . 140

-

- . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437

/

/ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438 /= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439

=

= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440

@

@ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409

+

+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437

>

> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 >= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441

<

< . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440 <= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440

1

1- . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439 1+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439

A

A Flying Tour of ACL2 . . . . . . . . . . . . . . . . . . . . . . . . . . . 632 A Sketch of How the Rewriter Works . . . . . . . . . . . . . 633 A Tiny Warning Sign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633 A Trivial Proof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634 A Typical State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634 A Walking Tour of ACL2 . . . . . . . . . . . . . . . . . . . . . . . . . 634 About Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639 About the ACL2 Home Page. . . . . . . . . . . . . . . . . . . . . . 641 About the Admission of Recursive Definitions . . . . . 641 About the Prompt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642 About Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640 ABS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 ACCUMULATED-PERSISTENCE . . . . . . . . . . . . . . . 235 ACKNOWLEDGEMENTS . . . . . . . . . . . . . . . . . . . . . . . 237 ACL2 as an Interactive Theorem Prover . . . . . . . . . . 638 ACL2 as an Interactive Theorem Prover (continued)

792 ACL2 Version 1.9

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638 ACL2 Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 635 ACL2 Conses or Ordered Pairs. . . . . . . . . . . . . . . . . . . . 635 ACL2 is an Untyped Language. . . . . . . . . . . . . . . . . . . . 639 ACL2 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636 ACL2 Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636 ACL2 System Architecture. . . . . . . . . . . . . . . . . . . . . . . . 637 ACL2-COMPLEX-RATIONALP. . . . . . . . . . . . . . . . . . 442 ACL2-COUNT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 ACL2-CUSTOMIZATION . . . . . . . . . . . . . . . . . . . . . . . . 239 ACL2-DEFAULTS-TABLE . . . . . . . . . . . . . . . . . . . . . . . 410 ACL2-NUMBERP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 ACL2-PC::= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 ACL2-PC::ACL2-WRAP . . . . . . . . . . . . . . . . . . . . . . . . . 559 ACL2-PC::ADD-ABBREVIATION . . . . . . . . . . . . . . . 559 ACL2-PC::BASH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 ACL2-PC::BDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 ACL2-PC::BK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 ACL2-PC::BOOKMARK . . . . . . . . . . . . . . . . . . . . . . . . . 562 ACL2-PC::CASESPLIT . . . . . . . . . . . . . . . . . . . . . . . . . . 562 ACL2-PC::CG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563 ACL2-PC::CHANGE-GOAL . . . . . . . . . . . . . . . . . . . . . . 564 ACL2-PC::CLAIM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564 ACL2-PC::COMM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565 ACL2-PC::COMMANDS . . . . . . . . . . . . . . . . . . . . . . . . . 566 ACL2-PC::COMMENT . . . . . . . . . . . . . . . . . . . . . . . . . . . 567 ACL2-PC::CONTRADICT . . . . . . . . . . . . . . . . . . . . . . . 567 ACL2-PC::CONTRAPOSE . . . . . . . . . . . . . . . . . . . . . . . 568 ACL2-PC::DEMOTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568 ACL2-PC::DIVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569 ACL2-PC::DO-ALL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570 ACL2-PC::DO-ALL-NO-PROMPT . . . . . . . . . . . . . . . 570 ACL2-PC::DO-STRICT . . . . . . . . . . . . . . . . . . . . . . . . . . 571 ACL2-PC::DROP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571 ACL2-PC::DV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572 ACL2-PC::ELIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573 ACL2-PC::EQUIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573 ACL2-PC::EX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574 ACL2-PC::EXIT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574 ACL2-PC::EXPAND. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575 ACL2-PC::FAIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 576 ACL2-PC::FORWARDCHAIN . . . . . . . . . . . . . . . . . . . . 577 ACL2-PC::FREE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578 ACL2-PC::GENERALIZE . . . . . . . . . . . . . . . . . . . . . . . . 578 ACL2-PC::GOALS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 579 ACL2-PC::HELP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 579 ACL2-PC::HELP! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 580 ACL2-PC::HELP-LONG. . . . . . . . . . . . . . . . . . . . . . . . . . 580 ACL2-PC::HYPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581 ACL2-PC::ILLEGAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 582 ACL2-PC::IN-THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . 582 ACL2-PC::INDUCT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583 ACL2-PC::LISP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583 ACL2-PC::MORE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584 ACL2-PC::MORE!. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584 ACL2-PC::NEGATE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585 ACL2-PC::NIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585 ACL2-PC::NOISE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586 ACL2-PC::NX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586 ACL2-PC::ORELSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586 ACL2-PC::P. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587 ACL2-PC::P-TOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587 ACL2-PC::PP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 588 ACL2-PC::PRINT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 588 ACL2-PC::PRINT-ALL-GOALS . . . . . . . . . . . . . . . . . . 589 ACL2-PC::PRINT-MAIN . . . . . . . . . . . . . . . . . . . . . . . . . 589 ACL2-PC::PRO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589 ACL2-PC::PROMOTE . . . . . . . . . . . . . . . . . . . . . . . . . . . 590 ACL2-PC::PROTECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590 ACL2-PC::PROVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591 ACL2-PC::PUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591 ACL2-PC::QUIET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592 ACL2-PC::R. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592 ACL2-PC::REDUCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593 ACL2-PC::REDUCE-BY-INDUCTION . . . . . . . . . . . 593 ACL2-PC::REMOVE-ABBREVIATIONS . . . . . . . . . 594 ACL2-PC::REPEAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595 ACL2-PC::REPEAT-REC . . . . . . . . . . . . . . . . . . . . . . . . 595 ACL2-PC::REPLAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595 ACL2-PC::RESTORE . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596 ACL2-PC::RETAIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596 ACL2-PC::RETRIEVE . . . . . . . . . . . . . . . . . . . . . . . . . . . 597 ACL2-PC::REWRITE . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597 ACL2-PC::RUN-INSTR-ON-GOAL . . . . . . . . . . . . . . . 599 ACL2-PC::RUN-INSTR-ON-NEW-GOALS . . . . . . . 600 ACL2-PC::S . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600 ACL2-PC::S-PROP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601 ACL2-PC::SAVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602 ACL2-PC::SEQUENCE. . . . . . . . . . . . . . . . . . . . . . . . . . . 602 ACL2-PC::SHOW-ABBREVIATIONS . . . . . . . . . . . . 604 ACL2-PC::SHOW-REWRITES . . . . . . . . . . . . . . . . . . . 604 ACL2-PC::SKIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605 ACL2-PC::SL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605 ACL2-PC::SPLIT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606 ACL2-PC::SR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606 ACL2-PC::SUCCEED . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607 ACL2-PC::TH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607 ACL2-PC::THEN. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 ACL2-PC::TOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 ACL2-PC::TYPE-ALIST . . . . . . . . . . . . . . . . . . . . . . . . . 608 ACL2-PC::UNDO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 609 ACL2-PC::UNSAVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 609 ACL2-PC::UP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610 ACL2-PC::USE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610 ACL2-PC::X. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 611 ACL2-PC::X-DUMB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612 ACL2-TUTORIAL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 ACL2-USER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 ACONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 ADD-MACRO-ALIAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 ADD-TO-SET-EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 ALISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 ALPHA-CHAR-P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 An Example Common Lisp Function Definition … 643 An Example of ACL2 in Use . . . . . . . . . . . . . . . . . . . . . . 644 Analyzing Common Lisp Models . . . . . . . . . . . . . . . . . . 645 AND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 APPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 APROPOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 AREF1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 AREF2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 ARGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 ARRAY1P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 ARRAY2P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 ARRAYS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 ASET1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 ASET2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 ASH. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 ASSIGN. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414 ASSOC. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 ASSOC-EQ. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 ASSOC-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 ASSOC-KEYWORD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 ASSOC-STRING-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . 447 ATOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447 ATOM-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447

B

BDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 BDD-ALGORITHM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 BDD-INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 BIBLIOGRAPHY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 BINARY-* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 BINARY-+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 BINARY-APPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 BOOK-CONTENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 BOOK-EXAMPLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 BOOK-NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 BOOKS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 BOOLEANP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 BREAK-LEMMA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 BREAK-REWRITE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 BREAKS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 BRR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 BRR-COMMANDS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 BRR@ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 BUILT-IN-CLAUSES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727 BUTLAST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449

C

CAAAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 CAAADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 CAAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 CAADAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 CAADDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 CAADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 CAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 CADAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 CADADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 CADAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 CADDAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 CADDDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 CADDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 CADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453 CAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453 CASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453 CASE-MATCH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 CBD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 CDAAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456 CDAADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456 CDAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456 CDADAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 CDADDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 CDADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 CDAR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 CDDAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 CDDADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 CDDAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 CDDDAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 CDDDDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 CDDDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 CDDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 CDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 CEILING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 CERTIFICATE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 CERTIFY-BOOK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 CERTIFY-BOOK! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 CHAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 CHAR-CODE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 CHAR-DOWNCASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 CHAR-EQUAL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 CHAR-UPCASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 CHAR> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462 CHAR>=. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 CHAR< . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462 CHAR<=. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462 CHARACTER-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 CHARACTERP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 CHARACTERS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 CHECK-SUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 CHECKPOINT-FORCED-GOALS. . . . . . . . . . . . . . . . 618 CLAUSE-IDENTIFIER. . . . . . . . . . . . . . . . . . . . . . . . . . . 260 CODE-CHAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465 COERCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465 COMMAND. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 COMMAND-DESCRIPTOR. . . . . . . . . . . . . . . . . . . . . . 261 Common Lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 646 Common Lisp as a Modeling Language. . . . . . . . . . . . 646 COMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 COMPILATION. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 COMPLEX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 COMPLEX-RATIONALP . . . . . . . . . . . . . . . . . . . . . . . . 467 COMPOUND-RECOGNIZER . . . . . . . . . . . . . . . . . . . . 730 COMPRESS1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 COMPRESS2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 COMPUTED-HINTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 CONCATENATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467 COND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468 CONGRUENCE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733 CONJUGATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468 CONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468 CONSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469 CONSTRAINT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647 COPYRIGHT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 COROLLARY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 Corroborating Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . 648 CURRENT-PACKAGE. . . . . . . . . . . . . . . . . . . . . . . . . . . 272 CURRENT-THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . 778

D

DECLARE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469 DEFAULT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 DEFAULT-DEFUN-MODE . . . . . . . . . . . . . . . . . . . . . . . 273 DEFAULT-PRINT-PROMPT. . . . . . . . . . . . . . . . . . . . . 274 DEFAXIOM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 DEFCHOOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 DEFCONG. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 DEFCONST. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 DEFDOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 DEFEQUIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 DEFEVALUATOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 DEFINE-PC-HELP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612 DEFINITION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735 DEFLABEL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 DEFMACRO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 DEFPKG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 DEFREFINEMENT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 DEFSTUB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 DEFTHEORY. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 DEFTHM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 DEFUN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 DEFUN-MODE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 DEFUN-MODE-CAVEAT . . . . . . . . . . . . . . . . . . . . . . . . 278 DEFUN-SK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 DEFUNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 DENOMINATOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470 DIGIT-CHAR-P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470 DIGIT-TO-CHAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 DIMENSIONS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 DISABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 779 DISABLE-FORCING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 DISABLEDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 DOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 DOC! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 DOC-STRING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 DOCS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 DOCUMENTATION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

E

E0-ORD-< . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 E0-ORDINALP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 EIGHTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 ELIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 737 EMBEDDED-EVENT-FORM . . . . . . . . . . . . . . . . . . . . 286 ENABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 780 ENABLE-FORCING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 ENCAPSULATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 ENDP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 ENTER-BOOT-STRAP-MODE . . . . . . . . . . . . . . . . . . 289 EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 EQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472 EQLABLE-ALISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472 EQLABLE-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 EQLABLEP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 EQUIVALENCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 738 ER-PROGN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 ESCAPE-TO-COMMON-LISP . . . . . . . . . . . . . . . . . . . 290 Evaluating App on Sample Input . . . . . . . . . . . . . . . . . 649 EVENP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 EVENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 EVISCERATE-HIDE-TERMS . . . . . . . . . . . . . . . . . . . . 290 EXECUTABLE-COUNTERPART . . . . . . . . . . . . . . . . 291 EXECUTABLE-COUNTERPART-THEORY . . . . . 780 EXISTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 EXIT-BOOT-STRAP-MODE . . . . . . . . . . . . . . . . . . . . . 292 EXPLODE-NONNEGATIVE-INTEGER. . . . . . . . . . 474 EXPT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474

F

FAILED-FORCING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 FAILURE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 FIFTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475 FILE-READING-EXAMPLE . . . . . . . . . . . . . . . . . . . . . . 59 FIND-RULES-OF-RUNE . . . . . . . . . . . . . . . . . . . . . . . . . 296 FIRST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475 FIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475 FIX-TRUE-LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476 Flawed Induction Candidates in App Example …. 649 FLOOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476 FMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476 FMT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478 FMT1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486 FORALL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 FORCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 FORCING-ROUND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 FORWARD-CHAINING . . . . . . . . . . . . . . . . . . . . . . . . . . 744 FOURTH. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487 FULL-BOOK-NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 FUNCTION-THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . 781 Functions for Manipulating these Objects . . . . . . . . . 650

G

GENERALIZE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 GENERALIZED-BOOLEANS . . . . . . . . . . . . . . . . . . . . 302 GOAL-SPEC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 GOOD-BYE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416 GROUND-ZERO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 782 GUARD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 GUARD-EXAMPLE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 GUARD-INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . 306 GUARD-MISCELLANY . . . . . . . . . . . . . . . . . . . . . . . . . . 307 GUARD-QUICK-REFERENCE . . . . . . . . . . . . . . . . . . 308 Guards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651 GUARDS-AND-EVALUATION. . . . . . . . . . . . . . . . . . . 310 GUARDS-FOR-SPECIFICATION . . . . . . . . . . . . . . . . 316 Guessing the Type of a Newly Admitted Function

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651 Guiding the ACL2 Theorem Prover . . . . . . . . . . . . . . . 652

H

HEADER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 HELP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 Hey Wait! Is ACL2 Typed or Untyped(Q) . . . . . . . . 652 HIDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 HINTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 HISTORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 How Long Does It Take to Become an Effective

User(Q). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653 How To Find Out about ACL2 Functions . . . . . . . . . 654 How To Find Out about ACL2 Functions (continued)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654

I

I-AM-HERE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 IDENTITY. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487 IF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 IF* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 IFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 IFIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 ILLEGAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 IMAGPART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 IMMEDIATE-FORCE-MODEP . . . . . . . . . . . . . . . . . . 327 IMPLIES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 IMPROPER-CONSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 IN-PACKAGE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 IN-THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 INCLUDE-BOOK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 INCOMPATIBLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 782 INDUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746 INSTRUCTIONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 613 INT= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 INTEGER-LENGTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 INTEGER-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 INTEGERP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 INTERN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491 INTERN-IN-PACKAGE-OF-SYMBOL . . . . . . . . . . . 491 INTERSECTION-THEORIES . . . . . . . . . . . . . . . . . . . . 783 INTERSECTP-EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493 INTERSECTP-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . 493 INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 INVISIBLE-FNS-ALIST . . . . . . . . . . . . . . . . . . . . . . . . . . 328 IO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493 IRRELEVANT-FORMALS . . . . . . . . . . . . . . . . . . . . . . . 495

K

KEEP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 KEYWORD-COMMANDS . . . . . . . . . . . . . . . . . . . . . . . 328 KEYWORD-VALUE-LISTP . . . . . . . . . . . . . . . . . . . . . . 497 KEYWORDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497

L

LAST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498 LD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416 LD-ERROR-ACTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329 LD-ERROR-TRIPLES. . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 LD-EVISC-TUPLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 LD-KEYWORD-ALIASES. . . . . . . . . . . . . . . . . . . . . . . . 331 LD-POST-EVAL-PRINT . . . . . . . . . . . . . . . . . . . . . . . . . 332 LD-PRE-EVAL-FILTER. . . . . . . . . . . . . . . . . . . . . . . . . . 333 LD-PRE-EVAL-PRINT. . . . . . . . . . . . . . . . . . . . . . . . . . . 334 LD-PROMPT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 LD-QUERY-CONTROL-ALIST . . . . . . . . . . . . . . . . . . 335 LD-REDEFINITION-ACTION . . . . . . . . . . . . . . . . . . . 336 LD-SKIP-PROOFSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 LD-VERBOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342 LEMMA-INSTANCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342 LENGTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498 LET. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498 LET* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501 LINEAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 749 LINEAR-ALIAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 753 LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501 LIST* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501 LISTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502 LOCAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 LOCAL-INCOMPATIBILITY . . . . . . . . . . . . . . . . . . . . 344 LOGAND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502 LOGANDC1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502 LOGANDC2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503 LOGBITP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503 LOGCOUNT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503 LOGEQV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503 LOGIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 LOGICAL-NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346 LOGIOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 LOGNAND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 LOGNOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 LOGNOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505 LOGORC1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505 LOGORC2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505 LOGTEST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 LOGXOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 LOOP-STOPPER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 LOWER-CASE-P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 LP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350

M

MACRO-ALIASES-TABLE . . . . . . . . . . . . . . . . . . . . . . . 192 MACRO-ARGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 MACRO-COMMAND . . . . . . . . . . . . . . . . . . . . . . . . . . . . 614 MAKE-CHARACTER-LIST . . . . . . . . . . . . . . . . . . . . . . 506 MAKE-LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507 MARKUP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 MAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507 MAXIMUM-LENGTH. . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 MEMBER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507 MEMBER-EQ. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508 MEMBER-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508 META . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758 MIN. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508 MINUSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 MISCELLANEOUS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 MOD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 Modeling in ACL2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655 Models in Engineering . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655 Models of Computer Hardware and Software . . . . . . 656 MONITOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 MONITORED-RUNES . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 MORE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 MORE!. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 MORE-DOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 MUTUAL-RECURSION. . . . . . . . . . . . . . . . . . . . . . . . . . 194 MUTUAL-RECURSION-PROOF-EXAMPLE. . . . . . 66 MV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510 MV-LET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510 MV-NTH. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513

N

NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 Name the Formula Above . . . . . . . . . . . . . . . . . . . . . . . . . 657 NFIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 NINTH. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 NO-DUPLICATESP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514 NO-DUPLICATESP-EQUAL . . . . . . . . . . . . . . . . . . . . . 514 NONNEGATIVE-INTEGER-QUOTIENT . . . . . . . . 514 NOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 NOTE1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691 NOTE2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692 NOTE3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692 NOTE4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694 NOTE5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698 NOTE6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704 NOTE7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706 NOTE8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711 NOTE8-UPDATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 719 NOTE9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720 NQTHM-TO-ACL2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 NTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 NTHCDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 NULL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516 Numbers in ACL2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 657 NUMERATOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516

O

OBDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 ODDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516 OK-IF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 On the Naming of Subgoals . . . . . . . . . . . . . . . . . . . . . . . 658 OOPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 OR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 OTF-FLG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 OTHER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 Other Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658 Overview of the Expansion of ENDP in the Base Case

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 659 Overview of the Expansion of ENDP in the Induction

Step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 659 Overview of the Final Simplification in the Base Case

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 659 Overview of the Proof of a Trivial Consequence … 660 Overview of the Simplification of the Base Case to T

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 661 Overview of the Simplification of the Induction

Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 661 Overview of the Simplification of the Induction Step to T . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662

P

PACKAGE-REINCARNATION-IMPORT-

RESTRICTIONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 Pages Written Especially for the Tours . . . . . . . . . . . . 629 PAIRLIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 PAIRLIS$ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 PATHNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 PBT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 PC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 PCB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 PCB! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 PCS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 PE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 PE! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 Perhaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662 PF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 PL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 PLUSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518 Popping out of an Inductive Proof . . . . . . . . . . . . . . . . 662 PORTCULLIS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 POSITION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518 POSITION-EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518 POSITION-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 PPROGN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 PR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 PR! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 PRINT-DOC-START-COLUMN . . . . . . . . . . . . . . . . . . 354 PROGN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 PROGRAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 PROGRAMMING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429 PROMPT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 PROOF-CHECKER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553 PROOF-OF-WELL-FOUNDEDNESS . . . . . . . . . . . . . 355 PROOF-TREE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617 PROOF-TREE-DETAILS . . . . . . . . . . . . . . . . . . . . . . . . 619 PROOF-TREE-EXAMPLES. . . . . . . . . . . . . . . . . . . . . . 620 PROOFS-CO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 PROPER-CONSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 PROPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 Proving Theorems about Models . . . . . . . . . . . . . . . . . . 663 PSEUDO-TERMP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 PUFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 PUFF* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 PUT-ASSOC-EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 PUT-ASSOC-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521

Q

Q . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421

R

RASSOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 RATIONAL-LISTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522 RATIONALP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522 REALPART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522 REBUILD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 REDEF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 REDEF!. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 REDEFINED-NAMES. . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 REDEFINING-PROGRAMS . . . . . . . . . . . . . . . . . . . . . 523 REDUNDANT-EVENTS . . . . . . . . . . . . . . . . . . . . . . . . . 361 REFINEMENT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 763 RELEASE-NOTES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691 REM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 525 REMOVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526 REMOVE-DUPLICATES. . . . . . . . . . . . . . . . . . . . . . . . . 526 REMOVE-DUPLICATES-EQUAL . . . . . . . . . . . . . . . . 527 REMOVE-MACRO-ALIAS . . . . . . . . . . . . . . . . . . . . . . . 196 RESET-LD-SPECIALS . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 REST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527 RETRIEVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 614 REVAPPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527 REVERSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 Revisiting the Admission of App . . . . . . . . . . . . . . . . . . 663 REWRITE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 764 Rewrite Rules are Generated from DEFTHM Events

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664 RFIX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 ROUND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 RULE-CLASSES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 723 RULE-NAMES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783 RUNE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 784 Running Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 665

S

SAVING-AND-RESTORING . . . . . . . . . . . . . . . . . . . . . 363 SECOND. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529 SET-CBD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 SET-COMPILE-FNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 SET-DIFFERENCE-EQUAL . . . . . . . . . . . . . . . . . . . . . 529 SET-DIFFERENCE-THEORIES . . . . . . . . . . . . . . . . . 786 SET-GUARD-CHECKING . . . . . . . . . . . . . . . . . . . . . . . 423 SET-IGNORE-OK. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 SET-INHIBIT-OUTPUT-LST . . . . . . . . . . . . . . . . . . . . 424 SET-INHIBIT-WARNINGS. . . . . . . . . . . . . . . . . . . . . . . 198 SET-INVISIBLE-FNS-ALIST . . . . . . . . . . . . . . . . . . . . . 199 SET-IRRELEVANT-FORMALS-OK . . . . . . . . . . . . . . 200 SET-MEASURE-FUNCTION . . . . . . . . . . . . . . . . . . . . 201 SET-STATE-OK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 SET-VERIFY-GUARDS-EAGERNESS . . . . . . . . . . . 202 SET-WELL-FOUNDED-RELATION . . . . . . . . . . . . . 203 SEVENTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530 SHOW-BDD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 SIGNATURE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 SIGNUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530 SIMPLE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 SIXTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530 SKIP-PROOFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425 SLOW-ARRAY-WARNING . . . . . . . . . . . . . . . . . . . . . . 255 SOLUTION-TO-SIMPLE-EXAMPLE. . . . . . . . . . . . . . 32 SPECIOUS-SIMPLIFICATION . . . . . . . . . . . . . . . . . . . 365 STANDARD-CHAR-LISTP. . . . . . . . . . . . . . . . . . . . . . . 531 STANDARD-CHAR-P. . . . . . . . . . . . . . . . . . . . . . . . . . . . 531 STANDARD-CO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531 STANDARD-OI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532 START-PROOF-TREE . . . . . . . . . . . . . . . . . . . . . . . . . . . 626 STARTUP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 STATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 STATE is the Only Variable in Top-Level Forms . . 665 STOP-PROOF-TREE . . . . . . . . . . . . . . . . . . . . . . . . . . . . 626 STRING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532 STRING-ALISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532 STRING-APPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533 STRING-DOWNCASE . . . . . . . . . . . . . . . . . . . . . . . . . . . 533 STRING-EQUAL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 STRING-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 STRING-UPCASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 STRING> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535 STRING>= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536 STRING< . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 STRING<= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535 STRINGP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536 STRIP-CARS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536 STRIP-CDRS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537 SUBLIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537 SUBSEQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537 SUBSETP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538 SUBSETP-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538 SUBST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538 Subsumption of Induction Candidates in App Example

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666 SUBVERSIVE-INDUCTIONS . . . . . . . . . . . . . . . . . . . . 371 Suggested Inductions in the Associativity of App

Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666 SYMBOL-< . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 SYMBOL-ALISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 SYMBOL-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 SYMBOL-NAME. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 SYMBOL-PACKAGE-NAME. . . . . . . . . . . . . . . . . . . . . 540 Symbolic Execution of Models . . . . . . . . . . . . . . . . . . . . 667 SYMBOLP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 SYNTAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374 SYNTAXP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374

T

TABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 TAKE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 TENTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 TERM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376 TERM-ORDER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 TERM-TABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 THE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 The Admission of App . . . . . . . . . . . . . . . . . . . . . . . . . . . . 667 The Associativity of App . . . . . . . . . . . . . . . . . . . . . . . . . 668 The Base Case in the App Example . . . . . . . . . . . . . . . 669 The End of the Flying Tour. . . . . . . . . . . . . . . . . . . . . . . 669 The End of the Proof of the Associativity of App . . 670 The End of the Walking Tour . . . . . . . . . . . . . . . . . . . . . 670 The Event Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671 The Expansion of ENDP in the Induction Step (Step

0). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 672 The Expansion of ENDP in the Induction Step (Step

1). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 672 The Expansion of ENDP in the Induction Step (Step

2). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673 The Falling Body Model . . . . . . . . . . . . . . . . . . . . . . . . . . 673 The Final Simplification in the Base Case (Step 0)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674 The Final Simplification in the Base Case (Step 1)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674 The Final Simplification in the Base Case (Step 2)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674 The Final Simplification in the Base Case (Step 3)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674 The First Application of the Associativity Rule … 675 The Induction Scheme Selected for the App Example

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675 The Induction Step in the App Example . . . . . . . . . . 676 The Instantiation of the Induction Scheme . . . . . . . . 676 The Justification of the Induction Scheme . . . . . . . . . 677 The Proof of the Associativity of App . . . . . . . . . . . . . 677 The Q.E.D. Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678 The Rules used in the Associativity of App Proof . . 678 The Simplification of the Induction Conclusion (Step 0)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678 The Simplification of the Induction Conclusion (Step 1)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679 The Simplification of the Induction Conclusion (Step

10). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679 The Simplification of the Induction Conclusion (Step

11). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679 The Simplification of the Induction Conclusion (Step

12). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680 The Simplification of the Induction Conclusion (Step 2)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680 The Simplification of the Induction Conclusion (Step 3)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681 The Simplification of the Induction Conclusion (Step 4)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681 The Simplification of the Induction Conclusion (Step 5)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681 The Simplification of the Induction Conclusion (Step 6)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682 The Simplification of the Induction Conclusion (Step 7)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682 The Simplification of the Induction Conclusion (Step 8)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 683 The Simplification of the Induction Conclusion (Step 9)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 683 The Summary of the Proof of the Trivial Consequence

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684 The Theorem that App is Associative . . . . . . . . . . . . . 684 The Time Taken to do the Associativity of App Proof

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 685 The Tours . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 685 The WARNING about the Trivial Consequence … 686 THEORIES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775 THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 786 THEORY-FUNCTIONS . . . . . . . . . . . . . . . . . . . . . . . . . . 787 THEORY-INVARIANT. . . . . . . . . . . . . . . . . . . . . . . . . . . 208 THIRD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 THM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426 TIDBITS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 TIPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 TOGGLE-PC-MACRO . . . . . . . . . . . . . . . . . . . . . . . . . . . 614 TRANS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 TRANS1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 TRUE-LIST-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 TRUE-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 TRUNCATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543 TTREE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 TUTORIAL-EXAMPLES. . . . . . . . . . . . . . . . . . . . . . . . . . 31 TUTORIAL1-TOWERS-OF-HANOI . . . . . . . . . . . . . . . 33 TUTORIAL2-EIGHTS-PROBLEM . . . . . . . . . . . . . . . . 38 TUTORIAL3-PHONEBOOK-EXAMPLE . . . . . . . . . . 41 TUTORIAL4-DEFUN-SK-EXAMPLE . . . . . . . . . . . . . 57 TUTORIAL5-MISCELLANEOUS-EXAMPLES …. 59 TYPE-PRESCRIPTION. . . . . . . . . . . . . . . . . . . . . . . . . . 766 TYPE-SET. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 TYPE-SET-INVERTER . . . . . . . . . . . . . . . . . . . . . . . . . . 768 TYPE-SPEC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543

U

U . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 UBT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 UBT!. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 UNARY– . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545 UNARY-/ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545 UNCERTIFIED-BOOKS . . . . . . . . . . . . . . . . . . . . . . . . . 116 Undocumented Topic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686 UNION-EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 UNION-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 UNION-THEORIES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788 UNIVERSAL-THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . 788 UNMONITOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 UNSAVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615 UPDATE-NTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 UPPER-CASE-P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547 Using the Associativity of App to Prove a Trivial

Consequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686 USING-COMPUTED-HINTS . . . . . . . . . . . . . . . . . . . . . 386 USING-COMPUTED-HINTS-1 . . . . . . . . . . . . . . . . . . . 386 USING-COMPUTED-HINTS-2 . . . . . . . . . . . . . . . . . . . 388 USING-COMPUTED-HINTS-3 . . . . . . . . . . . . . . . . . . . 390 USING-COMPUTED-HINTS-4 . . . . . . . . . . . . . . . . . . . 392 USING-COMPUTED-HINTS-5 . . . . . . . . . . . . . . . . . . . 395 USING-COMPUTED-HINTS-6 . . . . . . . . . . . . . . . . . . . 396

V

VERIFY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615 VERIFY-GUARDS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 VERIFY-TERMINATION . . . . . . . . . . . . . . . . . . . . . . . . 212 VERSION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397

W

WELL-FOUNDED-RELATION. . . . . . . . . . . . . . . . . . . 769 What is a Mathematical Logic(Q). . . . . . . . . . . . . . . . . 688 What is a Mechanical Theorem Prover(Q) . . . . . . . . 688 What is a Mechanical Theorem Prover(Q) (continued)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689 What Is ACL2(Q) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 687 What is Required of the User(Q). . . . . . . . . . . . . . . . . . 687 WHY-BRR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 WORLD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 WORMHOLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401

X

XARGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406

Y

You Must Think about the Use of a Formula as a Rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689

Z

ZERO-TEST-IDIOMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547 ZEROP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551 ZIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551 ZP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552

802 ACL2 Version 1.9

Table of Contents

1 ACL2-TUTORIAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.1 INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 STARTUP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.3 TIDBITS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 1.4 TIPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 1.5 TUTORIAL-EXAMPLES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

1.5.1 SOLUTION-TO-SIMPLE-EXAMPLE . . . . . . . . . . . . . . . . . . 32 1.5.2 TUTORIAL1-TOWERS-OF-HANOI . . . . . . . . . . . . . . . . . . . 33 1.5.3 TUTORIAL2-EIGHTS-PROBLEM . . . . . . . . . . . . . . . . . . . . 38 1.5.4 TUTORIAL3-PHONEBOOK-EXAMPLE . . . . . . . . . . . . . . 41 1.5.5 TUTORIAL4-DEFUN-SK-EXAMPLE . . . . . . . . . . . . . . . . . 57 1.5.6 TUTORIAL5-MISCELLANEOUS-EXAMPLES. . . . . . . . . 59

1.5.6.1 FILE-READING-EXAMPLE . . . . . . . . . . . . . . . . . 59 1.5.6.2 GUARD-EXAMPLE . . . . . . . . . . . . . . . . . . . . . . . . . 60 1.5.6.3 MUTUAL-RECURSION-PROOF-EXAMPLE. . 66

2 BDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

2.1 BDD-ALGORITHM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 2.2 BDD-INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 2.3 IF* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 2.4 SHOW-BDD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

3 BOOKS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

3.1 BOOK-CONTENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 3.2 BOOK-EXAMPLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 3.3 BOOK-NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 3.4 CBD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 3.5 CERTIFICATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 3.6 CERTIFY-BOOK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 3.7 FULL-BOOK-NAME. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 3.8 KEEP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 3.9 PATHNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 3.10 PORTCULLIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 3.11 SET-CBD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 3.12 UNCERTIFIED-BOOKS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

4 BREAK-REWRITE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

4.1 BREAK-LEMMA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 4.2 BRR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 4.3 BRR-COMMANDS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 4.4 BRR@ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 4.5 MONITOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 4.6 MONITORED-RUNES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 4.7 OK-IF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 4.8 UNMONITOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

5 DOCUMENTATION . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

5.1 *TERMINAL-MARKUP-TABLE* . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 5.2 ARGS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 5.3 DOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 5.4 DOC! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 5.5 DOC-STRING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 5.6 DOCS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 5.7 HELP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 5.8 MARKUP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 5.9 MORE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 5.10 MORE! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 5.11 MORE-DOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 5.12 NQTHM-TO-ACL2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156

6 EVENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161

6.1 ADD-MACRO-ALIAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 6.2 DEFAXIOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 6.3 DEFCHOOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 6.4 DEFCONG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 6.5 DEFCONST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 6.6 DEFDOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 6.7 DEFEQUIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 6.8 DEFEVALUATOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 6.9 DEFLABEL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 6.10 DEFMACRO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 6.11 DEFPKG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 6.12 DEFREFINEMENT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 6.13 DEFSTUB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 6.14 DEFTHEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 6.15 DEFTHM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 6.16 DEFUN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 6.17 DEFUN-SK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 6.17.1 EXISTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 6.17.2 FORALL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185

6.18 ENCAPSULATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 6.19 IN-THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 6.20 INCLUDE-BOOK. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 6.21 LOCAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 6.22 LOGIC. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 6.23 MACRO-ALIASES-TABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 6.24 MUTUAL-RECURSION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 6.25 PROGRAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 6.26 REMOVE-MACRO-ALIAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 6.27 SET-COMPILE-FNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 6.28 SET-IGNORE-OK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 6.29 SET-INHIBIT-WARNINGS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 6.30 SET-INVISIBLE-FNS-ALIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 6.31 SET-IRRELEVANT-FORMALS-OK . . . . . . . . . . . . . . . . . . . . . . . . . 200 6.32 SET-MEASURE-FUNCTION. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 6.33 SET-STATE-OK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 6.34 SET-VERIFY-GUARDS-EAGERNESS . . . . . . . . . . . . . . . . . . . . . . . 202 6.35 SET-WELL-FOUNDED-RELATION . . . . . . . . . . . . . . . . . . . . . . . . . 203 6.36 TABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 6.37 TERM-TABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 6.38 THEORY-INVARIANT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 6.39 VERIFY-GUARDS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 6.40 VERIFY-TERMINATION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212

7 HISTORY. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215

7.1 OOPS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 7.2 PBT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 7.3 PC. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 7.4 PCB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 7.5 PCB!. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 7.6 PCS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 7.7 PE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 7.8 PE! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 7.9 PF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 7.10 PL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 7.11 PR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 7.12 PR! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 7.13 PUFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 7.14 PUFF*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 7.15 U . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 7.16 UBT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 7.17 UBT! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230

8 MISCELLANEOUS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233

8.1 ACCUMULATED-PERSISTENCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 8.2 ACKNOWLEDGEMENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 8.3 ACL2-COUNT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 8.4 ACL2-CUSTOMIZATION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 8.5 APROPOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 8.6 ARRAYS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241

8.6.1 AREF1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 8.6.2 AREF2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 8.6.3 ARRAY1P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 8.6.4 ARRAY2P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 8.6.5 ASET1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 8.6.6 ASET2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 8.6.7 COMPRESS1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 8.6.8 COMPRESS2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 8.6.9 DEFAULT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 8.6.10 DIMENSIONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 8.6.11 HEADER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 8.6.12 MAXIMUM-LENGTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 8.6.13 SLOW-ARRAY-WARNING . . . . . . . . . . . . . . . . . . . . . . . . . 255

8.7 BIBLIOGRAPHY. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 8.8 BREAKS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 8.9 CHECK-SUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 8.10 CLAUSE-IDENTIFIER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 8.11 COMMAND. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 8.12 COMMAND-DESCRIPTOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 8.13 COMPUTED-HINTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 8.14 CONSTRAINT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 8.15 COPYRIGHT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 8.16 COROLLARY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 8.17 CURRENT-PACKAGE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 8.18 DEFAULT-DEFUN-MODE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 8.19 DEFAULT-PRINT-PROMPT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 8.20 DEFUN-MODE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 8.21 DEFUN-MODE-CAVEAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 8.22 DEFUNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 8.23 DISABLE-FORCING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 8.24 DISABLEDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 8.25 E0-ORD-<. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 8.26 E0-ORDINALP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 8.27 EMBEDDED-EVENT-FORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 8.28 ENABLE-FORCING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 8.29 ENTER-BOOT-STRAP-MODE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 8.30 ESCAPE-TO-COMMON-LISP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 8.31 EVISCERATE-HIDE-TERMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 8.32 EXECUTABLE-COUNTERPART . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 8.33 EXIT-BOOT-STRAP-MODE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292 8.34 FAILED-FORCING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 8.35 FAILURE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 8.36 FIND-RULES-OF-RUNE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 8.37 FORCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 8.38 FORCING-ROUND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 8.39 GENERALIZED-BOOLEANS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 8.40 GOAL-SPEC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 8.41 GUARD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305

8.41.1 GUARD-INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . 306 8.41.2 GUARD-MISCELLANY . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 8.41.3 GUARD-QUICK-REFERENCE . . . . . . . . . . . . . . . . . . . . . 308 8.41.4 GUARDS-AND-EVALUATION . . . . . . . . . . . . . . . . . . . . . 310 8.41.5 GUARDS-FOR-SPECIFICATION . . . . . . . . . . . . . . . . . . . 316

8.42 HIDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 8.43 HINTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 8.44 I-AM-HERE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 8.45 IMMEDIATE-FORCE-MODEP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 8.46 IN-PACKAGE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 8.47 INVISIBLE-FNS-ALIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 8.48 KEYWORD-COMMANDS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 8.49 LD-ERROR-ACTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329 8.50 LD-ERROR-TRIPLES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 8.51 LD-EVISC-TUPLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 8.52 LD-KEYWORD-ALIASES. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 8.53 LD-POST-EVAL-PRINT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 8.54 LD-PRE-EVAL-FILTER. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 8.55 LD-PRE-EVAL-PRINT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 8.56 LD-PROMPT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 8.57 LD-QUERY-CONTROL-ALIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335 8.58 LD-REDEFINITION-ACTION. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 8.59 LD-SKIP-PROOFSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 8.60 LD-VERBOSE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342 8.61 LEMMA-INSTANCE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342 8.62 LOCAL-INCOMPATIBILITY. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344 8.63 LOGICAL-NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346 8.64 LOOP-STOPPER. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 8.65 LP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 8.66 MACRO-ARGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 8.67 NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 8.68 OBDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 8.69 OTF-FLG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 8.70 PACKAGE-REINCARNATION-IMPORT-RESTRICTIONS … 354 8.71 PRINT-DOC-START-COLUMN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 8.72 PROMPT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 8.73 PROOF-OF-WELL-FOUNDEDNESS . . . . . . . . . . . . . . . . . . . . . . . . 355 8.74 PSEUDO-TERMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 8.75 REDEF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 8.76 REDEF! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 8.77 REDEFINED-NAMES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 8.78 REDUNDANT-EVENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361 8.79 SAVING-AND-RESTORING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 8.80 SIGNATURE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 8.81 SIMPLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 8.82 SPECIOUS-SIMPLIFICATION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 8.83 STATE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 8.84 SUBVERSIVE-INDUCTIONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 8.85 SYNTAX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374 8.86 SYNTAXP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374 8.87 TERM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376 8.88 TERM-ORDER. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 8.89 TTREE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 8.90 TYPE-SET. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 8.91 USING-COMPUTED-HINTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 8.92 USING-COMPUTED-HINTS-1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 8.93 USING-COMPUTED-HINTS-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 8.94 USING-COMPUTED-HINTS-3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 8.95 USING-COMPUTED-HINTS-4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 8.96 USING-COMPUTED-HINTS-5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 8.97 USING-COMPUTED-HINTS-6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 8.98 VERSION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 8.99 WHY-BRR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 8.100 WORLD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 8.101 WORMHOLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401 8.102 XARGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406

9 OTHER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409

9.1 @ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 9.2 ACL2-DEFAULTS-TABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 9.3 ASSIGN. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414 9.4 CERTIFY-BOOK! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 9.5 COMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 9.6 GOOD-BYE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416 9.7 LD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416 9.8 PROPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 9.9 Q . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 9.10 REBUILD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 9.11 RESET-LD-SPECIALS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 9.12 SET-GUARD-CHECKING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423 9.13 SET-INHIBIT-OUTPUT-LST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424 9.14 SKIP-PROOFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425 9.15 THM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426 9.16 TRANS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 9.17 TRANS1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427

10 PROGRAMMING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429

10.1 * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 10.2 *STANDARD-CI* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 10.3 *STANDARD-CO*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436 10.4 *STANDARD-OI* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436 10.5 + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437 10.6 - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437 10.7 / . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438 10.8 /= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439 10.9 1+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439 10.10 1-. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439 10.11 < . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440 10.12 <=. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440 10.13 = . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440 10.14 > . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 10.15 >=. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 10.16 ABS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 10.17 ACL2-COMPLEX-RATIONALP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 10.18 ACL2-NUMBERP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 10.19 ACL2-USER. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 10.20 ACONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 10.21 ADD-TO-SET-EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 10.22 ALISTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 10.23 ALPHA-CHAR-P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 10.24 AND. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 10.25 APPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 10.26 ASH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 10.27 ASSOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 10.28 ASSOC-EQ. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 10.29 ASSOC-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 10.30 ASSOC-KEYWORD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 10.31 ASSOC-STRING-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447 10.32 ATOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447 10.33 ATOM-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447 10.34 BINARY-* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 10.35 BINARY-+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 10.36 BINARY-APPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 10.37 BOOLEANP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 10.38 BUTLAST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 10.39 CAAAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 10.40 CAAADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 10.41 CAAAR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 10.42 CAADAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 10.43 CAADDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 10.44 CAADR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 10.45 CAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 10.46 CADAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 10.47 CADADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 10.48 CADAR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 10.49 CADDAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 10.50 CADDDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 10.51 CADDR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 10.52 CADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453 10.53 CAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453 10.54 CASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453 10.55 CASE-MATCH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 10.56 CDAAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456 10.57 CDAADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456 10.58 CDAAR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456 10.59 CDADAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 10.60 CDADDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 10.61 CDADR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 10.62 CDAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 10.63 CDDAAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 10.64 CDDADR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 10.65 CDDAR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 10.66 CDDDAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 10.67 CDDDDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 10.68 CDDDR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 10.69 CDDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 10.70 CDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 10.71 CEILING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 10.72 CHAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 10.73 CHAR-CODE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 10.74 CHAR-DOWNCASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 10.75 CHAR-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 10.76 CHAR-UPCASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 10.77 CHAR< . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462 10.78 CHAR<= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462 10.79 CHAR> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462 10.80 CHAR>= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 10.81 CHARACTER-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 10.82 CHARACTERP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 10.83 CHARACTERS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 10.84 CODE-CHAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465 10.85 COERCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465 10.86 COMPILATION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 10.87 COMPLEX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 10.88 COMPLEX-RATIONALP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467 10.89 CONCATENATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467 10.90 COND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468 10.91 CONJUGATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468 10.92 CONS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468 10.93 CONSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469 10.94 DECLARE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469 10.95 DENOMINATOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470 10.96 DIGIT-CHAR-P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470 10.97 DIGIT-TO-CHAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 10.98 EIGHTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 10.99 ENDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 10.100 EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 10.101 EQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472 10.102 EQLABLE-ALISTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472 10.103 EQLABLE-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 10.104 EQLABLEP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 10.105 EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 10.106 ER-PROGN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 10.107 EVENP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 10.108 EXPLODE-NONNEGATIVE-INTEGER . . . . . . . . . . . . . . . . . . . 474 10.109 EXPT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 10.110 FIFTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475 10.111 FIRST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475 10.112 FIX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475 10.113 FIX-TRUE-LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476 10.114 FLOOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476 10.115 FMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476 10.116 FMT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478 10.117 FMT1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486 10.118 FOURTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487 10.119 IDENTITY. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487 10.120 IF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 10.121 IFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 10.122 IFIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 10.123 ILLEGAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 10.124 IMAGPART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 10.125 IMPLIES. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 10.126 IMPROPER-CONSP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 10.127 INT= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 10.128 INTEGER-LENGTH. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 10.129 INTEGER-LISTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 10.130 INTEGERP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 10.131 INTERN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491 10.132 INTERN-IN-PACKAGE-OF-SYMBOL . . . . . . . . . . . . . . . . . . . . . 491 10.133 INTERSECTP-EQ. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493 10.134 INTERSECTP-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493 10.135 IO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493 10.136 IRRELEVANT-FORMALS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495 10.137 KEYWORD-VALUE-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497 10.138 KEYWORDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497 10.139 LAST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498 10.140 LENGTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498 10.141 LET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498 10.142 LET* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501 10.143 LIST. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501 10.144 LIST*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501 10.145 LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502 10.146 LOGAND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502 10.147 LOGANDC1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502 10.148 LOGANDC2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503 10.149 LOGBITP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503 10.150 LOGCOUNT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503 10.151 LOGEQV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503 10.152 LOGIOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 10.153 LOGNAND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 10.154 LOGNOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 10.155 LOGNOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505 10.156 LOGORC1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505 10.157 LOGORC2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505 10.158 LOGTEST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 10.159 LOGXOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 10.160 LOWER-CASE-P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 10.161 MAKE-CHARACTER-LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 10.162 MAKE-LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507 10.163 MAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507 10.164 MEMBER. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507 10.165 MEMBER-EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508 10.166 MEMBER-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508 10.167 MIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508 10.168 MINUSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 10.169 MOD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 10.170 MV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510 10.171 MV-LET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510 10.172 MV-NTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 10.173 NFIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 10.174 NINTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 10.175 NO-DUPLICATESP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514 10.176 NO-DUPLICATESP-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514 10.177 NONNEGATIVE-INTEGER-QUOTIENT . . . . . . . . . . . . . . . . . . 514 10.178 NOT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 10.179 NTH. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 10.180 NTHCDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 10.181 NULL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516 10.182 NUMERATOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516 10.183 ODDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516 10.184 OR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 10.185 PAIRLIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 10.186 PAIRLIS$ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 10.187 PLUSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518 10.188 POSITION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518 10.189 POSITION-EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518 10.190 POSITION-EQUAL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 10.191 PPROGN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 10.192 PROGN. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 10.193 PROOFS-CO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 10.194 PROPER-CONSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 10.195 PUT-ASSOC-EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 10.196 PUT-ASSOC-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 10.197 RASSOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 10.198 RATIONAL-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522 10.199 RATIONALP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522 10.200 REALPART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522 10.201 REDEFINING-PROGRAMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523 10.202 REM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 525 10.203 REMOVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526 10.204 REMOVE-DUPLICATES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526 10.205 REMOVE-DUPLICATES-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . 527 10.206 REST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527 10.207 REVAPPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527 10.208 REVERSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 10.209 RFIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 10.210 ROUND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 10.211 SECOND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529 10.212 SET-DIFFERENCE-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529 10.213 SEVENTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530 10.214 SIGNUM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530 10.215 SIXTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530 10.216 STANDARD-CHAR-LISTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531 10.217 STANDARD-CHAR-P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531 10.218 STANDARD-CO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531 10.219 STANDARD-OI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532 10.220 STRING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532 10.221 STRING-ALISTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532 10.222 STRING-APPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533 10.223 STRING-DOWNCASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533 10.224 STRING-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 10.225 STRING-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 10.226 STRING-UPCASE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 10.227 STRING< . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 10.228 STRING<= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535 10.229 STRING> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535 10.230 STRING>= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536 10.231 STRINGP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536 10.232 STRIP-CARS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536 10.233 STRIP-CDRS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537 10.234 SUBLIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537 10.235 SUBSEQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537 10.236 SUBSETP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538 10.237 SUBSETP-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538 10.238 SUBST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538 10.239 SYMBOL-< . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 10.240 SYMBOL-ALISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 10.241 SYMBOL-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 10.242 SYMBOL-NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 10.243 SYMBOL-PACKAGE-NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 10.244 SYMBOLP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 10.245 TAKE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 10.246 TENTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 10.247 THE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 10.248 THIRD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 10.249 TRUE-LIST-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 10.250 TRUE-LISTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 10.251 TRUNCATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543 10.252 TYPE-SPEC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543 10.253 UNARY–. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545 10.254 UNARY-/ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545 10.255 UNION-EQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 10.256 UNION-EQUAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 10.257 UPDATE-NTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 10.258 UPPER-CASE-P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547 10.259 ZERO-TEST-IDIOMS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547 10.260 ZEROP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551 10.261 ZIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551 10.262 ZP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552

11 PROOF-CHECKER . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553

11.1 ACL2-PC::=. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 11.2 ACL2-PC::ACL2-WRAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559 11.3 ACL2-PC::ADD-ABBREVIATION . . . . . . . . . . . . . . . . . . . . . . . . . . . 559 11.4 ACL2-PC::BASH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 11.5 ACL2-PC::BDD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 11.6 ACL2-PC::BK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 11.7 ACL2-PC::BOOKMARK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 562 11.8 ACL2-PC::CASESPLIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 562 11.9 ACL2-PC::CG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563 11.10 ACL2-PC::CHANGE-GOAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564 11.11 ACL2-PC::CLAIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564 11.12 ACL2-PC::COMM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565 11.13 ACL2-PC::COMMANDS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 11.14 ACL2-PC::COMMENT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567 11.15 ACL2-PC::CONTRADICT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567 11.16 ACL2-PC::CONTRAPOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568 11.17 ACL2-PC::DEMOTE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568 11.18 ACL2-PC::DIVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569 11.19 ACL2-PC::DO-ALL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570 11.20 ACL2-PC::DO-ALL-NO-PROMPT . . . . . . . . . . . . . . . . . . . . . . . . . . 570 11.21 ACL2-PC::DO-STRICT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571 11.22 ACL2-PC::DROP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571 11.23 ACL2-PC::DV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572 11.24 ACL2-PC::ELIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573 11.25 ACL2-PC::EQUIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573 11.26 ACL2-PC::EX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574 11.27 ACL2-PC::EXIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574 11.28 ACL2-PC::EXPAND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575 11.29 ACL2-PC::FAIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 576 11.30 ACL2-PC::FORWARDCHAIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 577 11.31 ACL2-PC::FREE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578 11.32 ACL2-PC::GENERALIZE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578 11.33 ACL2-PC::GOALS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 579 11.34 ACL2-PC::HELP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 579 11.35 ACL2-PC::HELP! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 580 11.36 ACL2-PC::HELP-LONG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 580 11.37 ACL2-PC::HYPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581 11.38 ACL2-PC::ILLEGAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 582 11.39 ACL2-PC::IN-THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 582 11.40 ACL2-PC::INDUCT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583 11.41 ACL2-PC::LISP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583 11.42 ACL2-PC::MORE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584 11.43 ACL2-PC::MORE! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584 11.44 ACL2-PC::NEGATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585 11.45 ACL2-PC::NIL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585 11.46 ACL2-PC::NOISE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586 11.47 ACL2-PC::NX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586 11.48 ACL2-PC::ORELSE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586 11.49 ACL2-PC::P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587 11.50 ACL2-PC::P-TOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587 11.51 ACL2-PC::PP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 588 11.52 ACL2-PC::PRINT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 588 11.53 ACL2-PC::PRINT-ALL-GOALS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589 11.54 ACL2-PC::PRINT-MAIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589 11.55 ACL2-PC::PRO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589 11.56 ACL2-PC::PROMOTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590 11.57 ACL2-PC::PROTECT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590 11.58 ACL2-PC::PROVE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591 11.59 ACL2-PC::PUT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591 11.60 ACL2-PC::QUIET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592 11.61 ACL2-PC::R. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592 11.62 ACL2-PC::REDUCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593 11.63 ACL2-PC::REDUCE-BY-INDUCTION . . . . . . . . . . . . . . . . . . . . . . 593 11.64 ACL2-PC::REMOVE-ABBREVIATIONS . . . . . . . . . . . . . . . . . . . . 594 11.65 ACL2-PC::REPEAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595 11.66 ACL2-PC::REPEAT-REC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595 11.67 ACL2-PC::REPLAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595 11.68 ACL2-PC::RESTORE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596 11.69 ACL2-PC::RETAIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596 11.70 ACL2-PC::RETRIEVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597 11.71 ACL2-PC::REWRITE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597 11.72 ACL2-PC::RUN-INSTR-ON-GOAL . . . . . . . . . . . . . . . . . . . . . . . . . 599 11.73 ACL2-PC::RUN-INSTR-ON-NEW-GOALS . . . . . . . . . . . . . . . . . . 600 11.74 ACL2-PC::S . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600 11.75 ACL2-PC::S-PROP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601 11.76 ACL2-PC::SAVE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602 11.77 ACL2-PC::SEQUENCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602 11.78 ACL2-PC::SHOW-ABBREVIATIONS . . . . . . . . . . . . . . . . . . . . . . . 604 11.79 ACL2-PC::SHOW-REWRITES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604 11.80 ACL2-PC::SKIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605 11.81 ACL2-PC::SL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605 11.82 ACL2-PC::SPLIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606 11.83 ACL2-PC::SR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606 11.84 ACL2-PC::SUCCEED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607 11.85 ACL2-PC::TH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607 11.86 ACL2-PC::THEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 11.87 ACL2-PC::TOP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 11.88 ACL2-PC::TYPE-ALIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 11.89 ACL2-PC::UNDO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 609 11.90 ACL2-PC::UNSAVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 609 11.91 ACL2-PC::UP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610 11.92 ACL2-PC::USE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610 11.93 ACL2-PC::X. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 611 11.94 ACL2-PC::X-DUMB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612 11.95 DEFINE-PC-HELP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612 11.96 INSTRUCTIONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 613 11.97 MACRO-COMMAND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 614 11.98 RETRIEVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 614 11.99 TOGGLE-PC-MACRO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 614 11.100 UNSAVE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615 11.101 VERIFY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615

12 PROOF-TREE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617

12.1 CHECKPOINT-FORCED-GOALS . . . . . . . . . . . . . . . . . . . . . . . . . . . 618 12.2 PROOF-TREE-DETAILS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 619 12.3 PROOF-TREE-EXAMPLES. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620 12.4 START-PROOF-TREE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 626 12.5 STOP-PROOF-TREE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 626

13 Pages Written Especially for the Tours . . . . . . . . 629

13.1 A Flying Tour of ACL2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 632 13.2 A Sketch of How the Rewriter Works . . . . . . . . . . . . . . . . . . . . . . . . . 633 13.3 A Tiny Warning Sign. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633 13.4 A Trivial Proof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634 13.5 A Typical State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634 13.6 A Walking Tour of ACL2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634 13.7 ACL2 Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 635 13.8 ACL2 Conses or Ordered Pairs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 635 13.9 ACL2 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636 13.10 ACL2 Symbols. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636 13.11 ACL2 System Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 637 13.12 ACL2 as an Interactive Theorem Prover . . . . . . . . . . . . . . . . . . . . . 638 13.13 ACL2 as an Interactive Theorem Prover (continued) . . . . . . . . . . 638 13.14 ACL2 is an Untyped Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639 13.15 About Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639 13.16 About Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640 13.17 About the ACL2 Home Page. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641 13.18 About the Admission of Recursive Definitions . . . . . . . . . . . . . . . . 641 13.19 About the Prompt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642 13.20 An Example Common Lisp Function Definition. . . . . . . . . . . . . . . 643 13.21 An Example of ACL2 in Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644 13.22 Analyzing Common Lisp Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645 13.23 Common Lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 646 13.24 Common Lisp as a Modeling Language . . . . . . . . . . . . . . . . . . . . . . 646 13.25 Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647 13.26 Corroborating Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 648 13.27 Evaluating App on Sample Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649 13.28 Flawed Induction Candidates in App Example . . . . . . . . . . . . . . . 649 13.29 Functions for Manipulating these Objects . . . . . . . . . . . . . . . . . . . . 650 13.30 Guards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651 13.31 Guessing the Type of a Newly Admitted Function . . . . . . . . . . . . 651 13.32 Guiding the ACL2 Theorem Prover. . . . . . . . . . . . . . . . . . . . . . . . . . 652 13.33 Hey Wait! Is ACL2 Typed or Untyped(Q) . . . . . . . . . . . . . . . . . . . 652 13.34 How Long Does It Take to Become an Effective User(Q) . . . . . . 653 13.35 How To Find Out about ACL2 Functions . . . . . . . . . . . . . . . . . . . . 654 13.36 How To Find Out about ACL2 Functions (continued) . . . . . . . . . 654 13.37 Modeling in ACL2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655 13.38 Models in Engineering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655 13.39 Models of Computer Hardware and Software . . . . . . . . . . . . . . . . . 656 13.40 Name the Formula Above. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 657 13.41 Numbers in ACL2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 657 13.42 On the Naming of Subgoals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658 13.43 Other Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658 13.44 Overview of the Expansion of ENDP in the Base Case . . . . . . . . 659 13.45 Overview of the Expansion of ENDP in the Induction Step …. 659 13.46 Overview of the Final Simplification in the Base Case . . . . . . . . . 659 13.47 Overview of the Proof of a Trivial Consequence . . . . . . . . . . . . . . 660 13.48 Overview of the Simplification of the Base Case to T . . . . . . . . . 661 13.49 Overview of the Simplification of the Induction Conclusion …. 661 13.50 Overview of the Simplification of the Induction Step to T . . . . . 662 13.51 Perhaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662 13.52 Popping out of an Inductive Proof. . . . . . . . . . . . . . . . . . . . . . . . . . . 662 13.53 Proving Theorems about Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663 13.54 Revisiting the Admission of App . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663 13.55 Rewrite Rules are Generated from DEFTHM Events. . . . . . . . . . 664 13.56 Running Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 665 13.57 STATE is the Only Variable in Top-Level Forms. . . . . . . . . . . . . . 665 13.58 Subsumption of Induction Candidates in App Example . . . . . . . 666 13.59 Suggested Inductions in the Associativity of App Example …. 666 13.60 Symbolic Execution of Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 667 13.61 The Admission of App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 667 13.62 The Associativity of App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 668 13.63 The Base Case in the App Example . . . . . . . . . . . . . . . . . . . . . . . . . 669 13.64 The End of the Flying Tour. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 669 13.65 The End of the Proof of the Associativity of App . . . . . . . . . . . . . 670 13.66 The End of the Walking Tour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 670 13.67 The Event Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671 13.68 The Expansion of ENDP in the Induction Step (Step 0). . . . . . . 672 13.69 The Expansion of ENDP in the Induction Step (Step 1). . . . . . . 672 13.70 The Expansion of ENDP in the Induction Step (Step 2). . . . . . . 673 13.71 The Falling Body Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673 13.72 The Final Simplification in the Base Case (Step 0). . . . . . . . . . . . 674 13.73 The Final Simplification in the Base Case (Step 1). . . . . . . . . . . . 674 13.74 The Final Simplification in the Base Case (Step 2). . . . . . . . . . . . 674 13.75 The Final Simplification in the Base Case (Step 3). . . . . . . . . . . . 674 13.76 The First Application of the Associativity Rule. . . . . . . . . . . . . . . 675 13.77 The Induction Scheme Selected for the App Example . . . . . . . . . 675 13.78 The Induction Step in the App Example . . . . . . . . . . . . . . . . . . . . . 676 13.79 The Instantiation of the Induction Scheme . . . . . . . . . . . . . . . . . . . 676 13.80 The Justification of the Induction Scheme. . . . . . . . . . . . . . . . . . . . 677 13.81 The Proof of the Associativity of App . . . . . . . . . . . . . . . . . . . . . . . 677 13.82 The Q.E.D. Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678 13.83 The Rules used in the Associativity of App Proof. . . . . . . . . . . . . 678 13.84 The Simplification of the Induction Conclusion (Step 0) . . . . . . . 678 13.85 The Simplification of the Induction Conclusion (Step 1) . . . . . . . 679 13.86 The Simplification of the Induction Conclusion (Step 10) . . . . . . 679 13.87 The Simplification of the Induction Conclusion (Step 11) . . . . . . 679 13.88 The Simplification of the Induction Conclusion (Step 12) . . . . . . 680 13.89 The Simplification of the Induction Conclusion (Step 2) . . . . . . . 680 13.90 The Simplification of the Induction Conclusion (Step 3) . . . . . . . 681 13.91 The Simplification of the Induction Conclusion (Step 4) . . . . . . . 681 13.92 The Simplification of the Induction Conclusion (Step 5) . . . . . . . 681 13.93 The Simplification of the Induction Conclusion (Step 6) . . . . . . . 682 13.94 The Simplification of the Induction Conclusion (Step 7) . . . . . . . 682 13.95 The Simplification of the Induction Conclusion (Step 8) . . . . . . . 683 13.96 The Simplification of the Induction Conclusion (Step 9) . . . . . . . 683 13.97 The Summary of the Proof of the Trivial Consequence . . . . . . . . 684 13.98 The Theorem that App is Associative . . . . . . . . . . . . . . . . . . . . . . . 684 13.99 The Time Taken to do the Associativity of App Proof . . . . . . . . 685 13.100 The Tours . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 685 13.101 The WARNING about the Trivial Consequence . . . . . . . . . . . . . 686 13.102 Undocumented Topic. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686 13.103 Using the Associativity of App to Prove a Trivial Consequence

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686 13.104 What Is ACL2(Q) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 687 13.105 What is Required of the User(Q) . . . . . . . . . . . . . . . . . . . . . . . . . . . 687 13.106 What is a Mathematical Logic(Q) . . . . . . . . . . . . . . . . . . . . . . . . . . 688 13.107 What is a Mechanical Theorem Prover(Q) . . . . . . . . . . . . . . . . . . 688 13.108 What is a Mechanical Theorem Prover(Q) (continued) . . . . . . . 689 13.109 You Must Think about the Use of a Formula as a Rule . . . . . . 689

14 RELEASE-NOTES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691

14.1 NOTE1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691 14.2 NOTE2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692 14.3 NOTE3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692 14.4 NOTE4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694 14.5 NOTE5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698 14.6 NOTE6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704 14.7 NOTE7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706 14.8 NOTE8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711 14.9 NOTE8-UPDATE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 719 14.10 NOTE9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720

15 RULE-CLASSES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 723

15.1 BUILT-IN-CLAUSES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727 15.2 COMPOUND-RECOGNIZER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 730 15.3 CONGRUENCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733 15.4 DEFINITION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735 15.5 ELIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 737 15.6 EQUIVALENCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 738 15.7 FORWARD-CHAINING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 744 15.8 GENERALIZE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 15.9 INDUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746 15.10 LINEAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 749 15.11 LINEAR-ALIAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 753 15.12 META . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758 15.13 REFINEMENT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 763 15.14 REWRITE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 764 15.15 TYPE-PRESCRIPTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 766 15.16 TYPE-SET-INVERTER. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 768 15.17 WELL-FOUNDED-RELATION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769

16 THEORIES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775

16.1 CURRENT-THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 778 16.2 DISABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 779 16.3 ENABLE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 780 16.4 EXECUTABLE-COUNTERPART-THEORY. . . . . . . . . . . . . . . . . . 780 16.5 FUNCTION-THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781 16.6 GROUND-ZERO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 782 16.7 INCOMPATIBLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 782 16.8 INTERSECTION-THEORIES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783 16.9 RULE-NAMES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783 16.10 RUNE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 784 16.11 SET-DIFFERENCE-THEORIES. . . . . . . . . . . . . . . . . . . . . . . . . . . . 786 16.12 THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 786 16.13 THEORY-FUNCTIONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787 16.14 UNION-THEORIES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788 16.15 UNIVERSAL-THEORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791

xx ACL2 Version 1.9